Path: blob/master/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java
40971 views
/*1* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/222324/*25* @test26* @bug 826757427* @summary check stylesheet names against HtmlStyle28* @modules jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.markup29* jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.resources:open30*/3132import java.io.BufferedWriter;33import java.io.IOException;34import java.io.InputStream;35import java.io.PrintWriter;36import java.net.URL;37import java.nio.file.Files;38import java.nio.file.Path;39import java.util.Arrays;40import java.util.Set;41import java.util.TreeSet;42import java.util.regex.Matcher;43import java.util.regex.Pattern;44import java.util.stream.Collectors;4546import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;4748/**49* This test compares the set of CSS class names defined in HtmlStyle50* and other files (such as search.js) against the set of CSS class names51* defined in the main stylesheet.css provided by the doclet.52*53* The goal is to detect "unexpected" discrepancies between the two sets.54* "Expected" discrepancies are taken into account, but may indicate a55* need to resolve the discrepancy.56*57* The test does not take into direct account the recent introduction of58* CSS constructs like section {@code [class$="-details"]}59*/60public class CheckStylesheetClasses {61public static void main(String... args) throws Exception {62CheckStylesheetClasses c = new CheckStylesheetClasses();63c.run();64}6566int errors = 0;6768void run() throws Exception {69Set<String> htmlStyleNames = getHtmlStyleNames();70Set<String> styleSheetNames = getStylesheetNames();7172System.err.println("found " + htmlStyleNames.size() + " names in HtmlStyle");73System.err.println("found " + styleSheetNames.size() + " names in stylesheet");7475// Write the lists to external files for the benefit of external diff tools:76// for example, to compare against the CSS class names used in generated documentation.77// To find the classes used in a directory containing HTML files, use something like78// find $DIRECTORY -name \*.html | \79// xargs grep -o 'class="[^"]*"' | \80// sed -e 's/^[^"]*"//' -e 's/".*$//' | \81// while read line ; do for w in $line ; do echo $w ; done ; done | \82// sort -u8384try (BufferedWriter out = Files.newBufferedWriter(Path.of("htmlStyleNames.txt"));85PrintWriter pw = new PrintWriter(out)) {86htmlStyleNames.forEach(pw::println);87}8889try (BufferedWriter out = Files.newBufferedWriter(Path.of("styleSheetNames.txt"));90PrintWriter pw = new PrintWriter(out)) {91styleSheetNames.forEach(pw::println);92}9394// Remove names from htmlStyleNames if they are valid names generated by the doclet,95// even if they do not by default require a style to be defined in the stylesheet.96// In general, names in these lists are worthy of attention to see if they *should*97// be defined in the stylesheet, especially when the names exist in a family of98// related items: related by name or by function.99100// the page names are provided to override a style on a specific page;101// only some are used in the stylesheet102htmlStyleNames.removeIf(s -> s.endsWith("-page") && !styleSheetNames.contains(s));103104// descriptions; class-description is used;105// surprisingly? module-description and package-description are not106htmlStyleNames.removeIf(s -> s.endsWith("-description") && !styleSheetNames.contains(s));107108// help page109htmlStyleNames.removeIf(s -> s.startsWith("help-") && !styleSheetNames.contains(s));110111// summary and details tables; styles for these may be present in the stylesheet112// using constructs like these:113// .summary section[class$="-summary"], .details section[class$="-details"],114htmlStyleNames.removeIf(s -> s.endsWith("-details"));115htmlStyleNames.removeIf(s -> s.endsWith("-summary") && !styleSheetNames.contains(s));116117// signature classes118removeAll(htmlStyleNames, "annotations", "element-name", "extends-implements",119"modifiers", "permits", "return-type");120121// misc: these are defined in HtmlStyle, and used by the doclet122removeAll(htmlStyleNames, "col-plain", "details-table", "external-link",123"hierarchy", "index", "package-uses", "packages", "permits-note",124"serialized-package-container", "source-container");125126// Remove names from styleSheetNames if they are false positives,127// or used by other code (i.e. not HtmlStyle),128// or if they are unused and therefore candidates to be deleted.129130// false positives: file extensions and URL components131removeAll(styleSheetNames, "css", "png", "w3");132133// for doc-comment authors; maybe worthy of inclusion in HtmlStyle, just to be documented134removeAll(styleSheetNames, "borderless", "plain", "striped");135136// used in search.js; may be worth documenting in HtmlStyle137removeAll(styleSheetNames, "result-highlight", "result-item",138"search-tag-desc-result", "search-tag-holder-result",139"ui-autocomplete", "ui-autocomplete-category",140"watermark");141142// very JDK specific143styleSheetNames.remove("module-graph");144145// apparently unused146// "tab" is commented implying it is in the header/footer, but147// (a) it is a poorly chosen name148// (b) it does not seem to be used in make/Docs.gmk or anywhere else149removeAll(styleSheetNames, "all-classes-container", "all-packages-container",150"bottom-nav", "clear", "constant-values-container", "deprecated-content",151"footer", "hidden", "override-specify-label", "serialized-class-details",152"tab", "table-sub-heading-color");153154boolean ok = check(htmlStyleNames, "HtmlStyle", styleSheetNames, "stylesheet")155& check(styleSheetNames, "stylesheet", htmlStyleNames, "HtmlStyle");156157if (!ok) {158throw new Exception("differences found");159}160161if (errors > 0) {162throw new Exception(errors + " errors found");163}164}165166boolean check(Set<String> s1, String l1, Set<String> s2, String l2) {167boolean equal = true;168for (String s : s1) {169if (!s2.contains(s)) {170System.err.println("In " + l1 + " but not " + l2 + ": " + s);171equal = false;172}173}174return equal;175}176177/**178* Remove all the names from the set, giving a message for any that were not found.179*/180void removeAll(Set<String> set, String... names) {181for (String name : names) {182if (!set.remove(name)) {183error("name not found in set: " + name);184}185}186}187188void error(String message) {189System.err.println("error: " + message);190errors++;191}192193Set<String> getHtmlStyleNames() {194return Arrays.stream(HtmlStyle.values())195.map(HtmlStyle::cssName)196.collect(Collectors.toCollection(TreeSet::new));197}198199Set<String> getStylesheetNames() throws IOException {200Set<String> names = new TreeSet<>();201String stylesheet = "/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css";202URL url = HtmlStyle.class.getResource(stylesheet);203readStylesheet(url, names);204return names;205}206207private void readStylesheet(URL resource, Set<String> names) throws IOException {208try (InputStream in = resource.openStream()) {209if (in == null) {210throw new AssertionError("Cannot find or access resource " + resource);211}212String s = new String(in.readAllBytes());213Pattern p = Pattern.compile("(?i)(\\s|([a-z][a-z0-9-]*))\\.(?<name>[a-z0-9-]+)\\b");214Matcher m = p.matcher(s);215while (m.find()) {216names.add(m.group("name"));217}218}219}220}221222