Path: blob/master/test/jdk/tools/launcher/HelpFlagsTest.java
66643 views
/*1* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2018, 2020 SAP SE. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324/**25* @test26* @summary Validate and test -?, -h and --help flags. All tools in the jdk27* should take the same flags to display the help message. These28* flags should be documented in the printed help message. The29* tool should quit without error code after displaying the30* help message (if there is no other problem with the command31* line).32* Also check that tools that used to accept -help still do33* so. Test that tools that never accepted -help don't do so34* in future. I.e., check that the tool returns with the same35* return code as called with an invalid flag, and does not36* print anything containing '-help' in that case.37* @compile HelpFlagsTest.java38* @run main HelpFlagsTest39*/4041import java.io.File;4243public class HelpFlagsTest extends TestHelper {4445// Tools that should not be tested because a usage message is pointless.46static final String[] TOOLS_NOT_TO_TEST = {47"appletviewer", // deprecated, don't test48"jaccessinspector", // gui, don't test, win only49"jaccessinspector-32", // gui, don't test, win-32 only50"jaccesswalker", // gui, don't test, win only51"jaccesswalker-32", // gui, don't test, win-32 only52"jconsole", // gui, don't test53"servertool", // none. Shell, don't test.54"javaw", // don't test, win only55// These shall have a help message that resembles that of56// MIT's tools. Thus -?, -h and --help are supported, but not57// mentioned in the help text.58"kinit",59"klist",60"ktab",61// Oracle proprietary tools without help message.62"javacpl",63"jmc",64"jweblauncher",65"jcontrol",66"ssvagent"67};6869// Lists which tools support which flags.70private static class ToolHelpSpec {71String toolname;7273// How the flags supposed to be supported are handled.74//75// These flags are supported, i.e.,76// * the tool accepts the flag77// * the tool prints a help message if the flag is specified78// * this help message lists the flag79// * the tool exits with exit code '0'.80boolean supportsQuestionMark;81boolean supportsH;82boolean supportsHelp;8384// One tool returns with exit code != '0'.85int exitcodeOfHelp;8687// How legacy -help is handled.88//89// Tools that so far support -help should still do so, but90// not print documentation about it. Tools that do not91// support -help should not do so in future.92//93// The tools accepts legacy -help. -help should not be94// documented in the usage message.95boolean supportsLegacyHelp;9697// Java itself documents -help. -help prints to stderr,98// while --help prints to stdout. Leave as is.99boolean documentsLegacyHelp;100101// The exit code of the tool if an invalid argument is passed to it.102// An exit code != 0 would be expected, but not all tools handle it103// that way.104int exitcodeOfWrongFlag;105106ToolHelpSpec(String n, int q, int h, int hp, int ex1, int l, int dl, int ex2) {107toolname = n;108supportsQuestionMark = ( q == 1 ? true : false );109supportsH = ( h == 1 ? true : false );110supportsHelp = ( hp == 1 ? true : false );111exitcodeOfHelp = ex1;112113supportsLegacyHelp = ( l == 1 ? true : false );114documentsLegacyHelp = ( dl == 1 ? true : false );115exitcodeOfWrongFlag = ex2;116}117}118119static ToolHelpSpec[] jdkTools = {120// name -? -h --help exitcode -help -help exitcode121// of help docu of wrong122// mented flag123new ToolHelpSpec("jabswitch", 0, 0, 0, 0, 0, 0, 0), // /?, prints help message anyways, win only124new ToolHelpSpec("jar", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help125new ToolHelpSpec("jarsigner", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.126new ToolHelpSpec("java", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help127new ToolHelpSpec("javac", 1, 0, 1, 0, 1, 1, 2), // -?, --help -help, Documents -help, -h is already taken for "native header output directory".128new ToolHelpSpec("javadoc", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help129new ToolHelpSpec("javap", 1, 1, 1, 0, 1, 1, 2), // -?, -h, --help -help, Documents -help130new ToolHelpSpec("javaw", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help, win only131new ToolHelpSpec("jcmd", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.132new ToolHelpSpec("jdb", 1, 1, 1, 0, 1, 1, 0), // -?, -h, --help -help, Documents -help133new ToolHelpSpec("jdeprscan", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help134new ToolHelpSpec("jdeps", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented.135new ToolHelpSpec("jfr", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help136new ToolHelpSpec("jhsdb", 0, 0, 0, 0, 0, 0, 0), // none, prints help message anyways.137new ToolHelpSpec("jimage", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help138new ToolHelpSpec("jinfo", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help139new ToolHelpSpec("jjs", 0, 1, 1, 100, 0, 0, 100), // -h, --help, return code 100140new ToolHelpSpec("jlink", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help141new ToolHelpSpec("jmap", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.142new ToolHelpSpec("jmod", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented.143new ToolHelpSpec("jps", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help144new ToolHelpSpec("jrunscript", 1, 1, 1, 0, 1, 1, 7), // -?, -h, --help -help, Documents -help145new ToolHelpSpec("jshell", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.146new ToolHelpSpec("jstack", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help147new ToolHelpSpec("jstat", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help148new ToolHelpSpec("jstatd", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help149new ToolHelpSpec("keytool", 1, 1, 1, 0, 1, 0, 1), // none, prints help message anyways.150new ToolHelpSpec("rmiregistry", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways.151new ToolHelpSpec("serialver", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways.152new ToolHelpSpec("jpackage", 0, 1, 1, 0, 0, 1, 1), // -h, --help,153};154155// Returns corresponding object from jdkTools array.156static ToolHelpSpec getToolHelpSpec(String tool) {157for (ToolHelpSpec x : jdkTools) {158if (tool.toLowerCase().equals(x.toolname) ||159tool.toLowerCase().equals(x.toolname + ".exe"))160return x;161}162return null;163}164165// Check whether 'flag' appears in 'line' as a word of itself. It must not166// be a substring of a word, as then similar flags might be matched.167// E.g.: --help matches in the documentation of --help-extra.168// This works only with english locale, as some tools have translated169// usage messages.170static boolean findFlagInLine(String line, String flag) {171if (line.contains(flag) &&172!line.contains("nknown") && // Some tools say 'Unknown option "<flag>"',173!line.contains("invalid flag") && // 'invalid flag: <flag>'174!line.contains("invalid option") && // or 'invalid option: <flag>'. Skip that.175!line.contains("FileNotFoundException: -help") && // Special case for idlj.176!line.contains("-h requires an argument") && // Special case for javac.177!line.contains("port argument,")) { // Special case for rmiregistry.178// There might be several appearances of 'flag' in179// 'line'. (-h as substring of --help).180int flagLen = flag.length();181int lineLen = line.length();182for (int i = line.indexOf(flag); i >= 0; i = line.indexOf(flag, i+1)) {183// There should be a space before 'flag' in 'line', or it's right at the beginning.184if (i > 0 &&185line.charAt(i-1) != ' ' &&186line.charAt(i-1) != '[' && // jarsigner187line.charAt(i-1) != '|' && // jstatd188line.charAt(i-1) != '\t') { // jjs189continue;190}191// There should be a space or comma after 'flag' in 'line', or it's just at the end.192int posAfter = i + flagLen;193if (posAfter < lineLen &&194line.charAt(posAfter) != ' ' &&195line.charAt(posAfter) != ',' &&196line.charAt(posAfter) != '[' && // jar197line.charAt(posAfter) != ']' && // jarsigner198line.charAt(posAfter) != ')' && // jfr199line.charAt(posAfter) != '|' && // jstatd200line.charAt(posAfter) != ':' && // jps201line.charAt(posAfter) != '"') { // keytool202continue;203}204return true;205}206}207return false;208}209210static TestResult runToolWithFlag(File f, String flag) {211String x = f.getAbsolutePath();212TestResult tr = doExec(x, flag);213System.out.println("Testing " + f.getName());214System.out.println("#> " + x + " " + flag);215tr.testOutput.forEach(System.out::println);216System.out.println("#> echo $?");217System.out.println(tr.exitValue);218219return tr;220}221222// Checks whether tool supports flag 'flag' and documents it223// in the help message.224static String testTool(File f, String flag, int exitcode) {225String result = "";226TestResult tr = runToolWithFlag(f, flag);227228// Check that the tool accepted the flag.229if (exitcode == 0 && !tr.isOK()) {230System.out.println("failed");231result = "failed: " + f.getName() + " " + flag + " has exit code " + tr.exitValue + ".\n";232}233234// Check there is a help message listing the flag.235boolean foundFlag = false;236for (String y : tr.testOutput) {237if (!foundFlag && findFlagInLine(y, flag)) { // javac238foundFlag = true;239System.out.println("Found documentation of '" + flag + "': '" + y.trim() +"'");240}241}242if (!foundFlag) {243result += "failed: " + f.getName() + " does not document " +244flag + " in help message.\n";245}246247if (!result.isEmpty())248System.out.println(result);249250return result;251}252253// Test the tool supports legacy option -help, but does254// not document it.255static String testLegacyFlag(File f, int exitcode) {256String result = "";257TestResult tr = runToolWithFlag(f, "-help");258259// Check that the tool accepted the flag.260if (exitcode == 0 && !tr.isOK()) {261System.out.println("failed");262result = "failed: " + f.getName() + " -help has exit code " + tr.exitValue + ".\n";263}264265// Check there is _no_ documentation of -help.266boolean foundFlag = false;267for (String y : tr.testOutput) {268if (!foundFlag && findFlagInLine(y, "-help")) { // javac269foundFlag = true;270System.out.println("Found documentation of '-help': '" + y.trim() +"'");271}272}273if (foundFlag) {274result += "failed: " + f.getName() + " does document -help " +275"in help message. This legacy flag should not be documented.\n";276}277278if (!result.isEmpty())279System.out.println(result);280281return result;282}283284// Test that the tool exits with the exit code expected for285// invalid flags. In general, one would expect this to be != 0,286// but currently a row of tools exit with 0 in this case.287// The output should not ask to get help with flag '-help'.288static String testInvalidFlag(File f, String flag, int exitcode, boolean documentsLegacyHelp) {289String result = "";290TestResult tr = runToolWithFlag(f, flag);291292// Check that the tool did exit with the expected return code.293if (!((exitcode == tr.exitValue) ||294// Windows reports -1 where unix reports 255.295(tr.exitValue < 0 && exitcode == tr.exitValue + 256))) {296System.out.println("failed");297result = "failed: " + f.getName() + " " + flag + " should not be " +298"accepted. But it has exit code " + tr.exitValue + ".\n";299}300301if (!documentsLegacyHelp) {302// Check there is _no_ documentation of -help.303boolean foundFlag = false;304for (String y : tr.testOutput) {305if (!foundFlag && findFlagInLine(y, "-help")) { // javac306foundFlag = true;307System.out.println("Found documentation of '-help': '" + y.trim() +"'");308}309}310if (foundFlag) {311result += "failed: " + f.getName() + " does document -help " +312"in error message. This legacy flag should not be documented.\n";313}314}315316if (!result.isEmpty())317System.out.println(result);318319return result;320}321322public static void main(String[] args) {323String errorMessage = "";324325// The test analyses the help messages printed. It assumes englisch326// help messages. Thus it only works with english locale.327if (!isEnglishLocale()) { return; }328329for (File f : new File(JAVA_BIN).listFiles(new ToolFilter(TOOLS_NOT_TO_TEST))) {330String toolName = f.getName();331332ToolHelpSpec tool = getToolHelpSpec(toolName);333if (tool == null) {334errorMessage += "Tool " + toolName + " not covered by this test. " +335"Add specification to jdkTools array!\n";336continue;337}338339// Test for help flags to be supported.340if (tool.supportsQuestionMark == true) {341errorMessage += testTool(f, "-?", tool.exitcodeOfHelp);342} else {343System.out.println("Skip " + tool.toolname + ". It does not support -?.");344}345if (tool.supportsH == true) {346errorMessage += testTool(f, "-h", tool.exitcodeOfHelp);347} else {348System.out.println("Skip " + tool.toolname + ". It does not support -h.");349}350if (tool.supportsHelp == true) {351errorMessage += testTool(f, "--help", tool.exitcodeOfHelp);352} else {353System.out.println("Skip " + tool.toolname + ". It does not support --help.");354}355356// Check that the return code listing in jdkTools[] is357// correct for an invalid flag.358errorMessage += testInvalidFlag(f, "-asdfxgr", tool.exitcodeOfWrongFlag, tool.documentsLegacyHelp);359360// Test for legacy -help flag.361if (!tool.documentsLegacyHelp) {362if (tool.supportsLegacyHelp == true) {363errorMessage += testLegacyFlag(f, tool.exitcodeOfHelp);364} else {365errorMessage += testInvalidFlag(f, "-help", tool.exitcodeOfWrongFlag, false);366}367}368}369370if (errorMessage.isEmpty()) {371System.out.println("All help string tests: PASS");372} else {373throw new AssertionError("HelpFlagsTest failed:\n" + errorMessage);374}375}376}377378379