Path: blob/master/test/langtools/jdk/javadoc/tool/TestScriptInComment.java
40957 views
/*1* Copyright (c) 2016, 2020, 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*/2223/**24* @test25* @bug 8138725 822676526* @summary test --allow-script-in-comments27* @modules jdk.javadoc/jdk.javadoc.internal.tool28*/2930import java.io.File;31import java.io.FileWriter;32import java.io.IOException;33import java.io.PrintStream;34import java.io.PrintWriter;35import java.io.StringWriter;36import java.util.ArrayList;37import java.util.Arrays;38import java.util.Collections;39import java.util.List;40import java.util.regex.Matcher;41import java.util.regex.Pattern;4243/**44* Combo-style test, exercising combinations of different HTML fragments that may contain45* JavaScript, different places to place those fragments, and whether or not to allow the use46* of JavaScript.47*/48public class TestScriptInComment {49public static void main(String... args) throws Exception {50new TestScriptInComment().run();51}5253/**54* Representative samples of different fragments of HTML that may contain JavaScript.55* To facilitate checking the output manually in a browser, the text "#ALERT" will be56* replaced by a JavaScript call of "alert(msg)", using a message string that is specific57* to the test case.58*/59enum Comment {60LC("<script>#ALERT</script>", true), // script tag in Lower Case61UC("<SCRIPT>#ALERT</script>", true), // script tag in Upper Case62WS("< script >#ALERT</script>", false, "-Xdoclint:none"), // script tag with invalid white space63SP("""64<script src="file"> #ALERT </script>""", true), // script tag with an attribute65ON("<a onclick='#ALERT'>x</a>", true), // event handler attribute66OME("<img alt='1' onmouseenter='#ALERT'>", true), // onmouseenter event handler attribute67OML("<img alt='1' onmouseleave='#ALERT'>", true), // onmouseleave event handler attribute68OFI("<a href='#' onfocusin='#ALERT'>x</a>", true), // onfocusin event handler attribute69OBE("<a onbogusevent='#ALERT'>x</a>", true), // bogus/future event handler attribute70URI("<a href='javascript:#ALERT'>x</a>", true); // javascript URI7172/**73* Creates an HTML fragment to be injected into a template.74* @param text the HTML fragment to put into a doc comment or option.75* @param hasScript whether or not this fragment does contain legal JavaScript76* @param opts any additional options to be specified when javadoc is run77*/78Comment(String text, boolean hasScript, String... opts) {79this.text = text;80this.hasScript = hasScript;81this.opts = Arrays.asList(opts);82}8384final String text;85final boolean hasScript;86final List<String> opts;87};8889/**90* Representative samples of positions in which javadoc may find JavaScript.91* Each template contains a series of strings, which are written to files or inferred as options.92* The first source file implies a corresponding output file which should not be written93* if the comment contains JavaScript and JavaScript is not allowed.94*/95enum Template {96OVR("<html><body> overview #COMMENT </body></html>", "package p; public class C { }"),97PKGINFO("#COMMENT package p;", "package p; public class C { }"),98PKGHTML("<html><body>#COMMENT package p;</body></html>", "package p; public class C { }"),99CLS("package p; #COMMENT public class C { }"),100CON("package p; public class C { #COMMENT public C() { } }"),101FLD("package p; public class C { #COMMENT public int f; }"),102MTH("package p; public class C { #COMMENT public void m() { } }"),103TOP("-top", "lorem #COMMENT ipsum", "package p; public class C { }"),104HDR("-header", "lorem #COMMENT ipsum", "package p; public class C { }"),105BTM("-bottom", "lorem #COMMENT ipsum", "package p; public class C { }"),106DTTL("-doctitle", "lorem #COMMENT ipsum", "package p; public class C { }"),107PHDR("-packagesheader", "lorem #COMMENT ipsum", "package p; public class C { }");108109Template(String... args) {110opts = new ArrayList<String>();111sources = new ArrayList<String>();112int i = 0;113while (args[i].startsWith("-")) {114// all options being tested have a single argument that follow the option115opts.add(args[i++]);116opts.add(args[i++]);117}118while(i < args.length) {119sources.add(args[i++]);120}121}122123// groups: 1 <html> or not; 2: package name; 3: class name124private final Pattern pat =125Pattern.compile("(?i)(<html>)?.*?(?:package ([a-z]+);.*?(?:class ([a-z]+).*)?)?");126127/**128* Infer the file in which to write the given source.129* @param dir the base source directory130* @param src the source text131* @return the file in which the source should be written132*/133File getSrcFile(File srcDir, String src) {134String f;135Matcher m = pat.matcher(src);136if (!m.matches())137throw new Error("match failed");138if (m.group(3) != null) {139f = m.group(2) + "/" + m.group(3) + ".java";140} else if (m.group(2) != null) {141f = m.group(2) + "/" + (m.group(1) == null ? "package-info.java" : "package.html");142} else {143f = "overview.html";144}145return new File(srcDir, f);146}147148/**149* Get the options to give to javadoc.150* @param srcDir the srcDir to use -overview is needed151* @return152*/153List<String> getOpts(File srcDir) {154if (!opts.isEmpty()) {155return opts;156} else if (sources.get(0).contains("overview")) {157return Arrays.asList("-overview", getSrcFile(srcDir, sources.get(0)).getPath());158} else {159return Collections.emptyList();160}161}162163/**164* Gets the output file corresponding to the first source file.165* This file should not be written if the comment contains JavaScript and JavaScripot is166* not allowed.167* @param dir the base output directory168* @return the output file169*/170File getOutFile(File outDir) {171String f;172Matcher m = pat.matcher(sources.get(0));173if (!m.matches())174throw new Error("match failed");175if (m.group(3) != null) {176f = m.group(2) + "/" + m.group(3) + ".html";177} else if (m.group(2) != null) {178f = m.group(2) + "/package-summary.html";179} else {180f = "overview-summary.html";181}182return new File(outDir, f);183}184185final List<String> opts;186final List<String> sources;187};188189enum Option {190OFF(null),191ON("--allow-script-in-comments");192193Option(String text) {194this.text = text;195}196197final String text;198};199200private PrintStream out = System.err;201202public void run() throws Exception {203int count = 0;204for (Template template: Template.values()) {205for (Comment comment: Comment.values()) {206for (Option option: Option.values()) {207if (test(template, comment, option)) {208count++;209}210}211}212}213214out.println(count + " test cases run");215if (errors > 0) {216throw new Exception(errors + " errors occurred");217}218}219220boolean test(Template template, Comment comment, Option option) throws IOException {221if (option == Option.ON && !comment.hasScript) {222// skip --allowScriptInComments if comment does not contain JavaScript223return false;224}225226String test = template + "-" + comment + "-" + option;227out.println("Test: " + test);228229File dir = new File(test);230dir.mkdirs();231File srcDir = new File(dir, "src");232File outDir = new File(dir, "out");233234String alert = "alert(\"" + test + "\");";235for (String src: template.sources) {236writeFile(template.getSrcFile(srcDir, src),237src.replace("#COMMENT",238"/** " + comment.text.replace("#ALERT", alert) + " **/"));239}240241List<String> opts = new ArrayList<String>();242opts.add("-sourcepath");243opts.add(srcDir.getPath());244opts.add("-d");245opts.add(outDir.getPath());246if (option.text != null)247opts.add(option.text);248for (String opt: template.getOpts(srcDir)) {249opts.add(opt.replace("#COMMENT", comment.text.replace("#ALERT", alert)));250}251opts.addAll(comment.opts);252opts.add("-noindex"); // index not required; save time/space writing files253opts.add("p");254255StringWriter sw = new StringWriter();256PrintWriter pw = new PrintWriter(sw);257int rc = javadoc(opts, pw);258pw.close();259String log = sw.toString();260writeFile(new File(dir, "log.txt"), log);261262out.println("opts: " + opts);263out.println(" rc: " + rc);264out.println(" log:");265out.println(log);266267String ERROR = "Use --allow-script-in-comment";268File outFile = template.getOutFile(outDir);269270boolean expectErrors = comment.hasScript && (option == Option.OFF);271272if (expectErrors) {273check(rc != 0, "unexpected exit code: " + rc);274check(log.contains(ERROR), "expected error message not found");275check(!outFile.exists(), "output file found unexpectedly");276} else {277check(rc == 0, "unexpected exit code: " + rc);278check(!log.contains(ERROR), "error message found");279check(outFile.exists(), "output file not found");280}281282out.println();283return true;284}285286int javadoc(List<String> opts, PrintWriter pw) {287return jdk.javadoc.internal.tool.Main.execute(opts.toArray(new String[opts.size()]), pw);288}289290File writeFile(File f, String text) throws IOException {291f.getParentFile().mkdirs();292FileWriter fw = new FileWriter(f);293try {294fw.write(text);295} finally {296fw.close();297}298return f;299}300301void check(boolean cond, String errMessage) {302if (!cond) {303error(errMessage);304}305}306307void error(String message) {308out.println("Error: " + message);309errors++;310}311312int errors = 0;313}314315316317