Path: blob/master/test/jdk/tools/launcher/HelpFlagsTest.java
41145 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"jaccesswalker", // gui, don't test, win only50"jconsole", // gui, don't test51"servertool", // none. Shell, don't test.52"javaw", // don't test, win only53// These shall have a help message that resembles that of54// MIT's tools. Thus -?, -h and --help are supported, but not55// mentioned in the help text.56"kinit",57"klist",58"ktab",59// Oracle proprietary tools without help message.60"javacpl",61"jmc",62"jweblauncher",63"jcontrol",64"ssvagent"65};6667// Lists which tools support which flags.68private static class ToolHelpSpec {69String toolname;7071// How the flags supposed to be supported are handled.72//73// These flags are supported, i.e.,74// * the tool accepts the flag75// * the tool prints a help message if the flag is specified76// * this help message lists the flag77// * the tool exits with exit code '0'.78boolean supportsQuestionMark;79boolean supportsH;80boolean supportsHelp;8182// One tool returns with exit code != '0'.83int exitcodeOfHelp;8485// How legacy -help is handled.86//87// Tools that so far support -help should still do so, but88// not print documentation about it. Tools that do not89// support -help should not do so in future.90//91// The tools accepts legacy -help. -help should not be92// documented in the usage message.93boolean supportsLegacyHelp;9495// Java itself documents -help. -help prints to stderr,96// while --help prints to stdout. Leave as is.97boolean documentsLegacyHelp;9899// The exit code of the tool if an invalid argument is passed to it.100// An exit code != 0 would be expected, but not all tools handle it101// that way.102int exitcodeOfWrongFlag;103104ToolHelpSpec(String n, int q, int h, int hp, int ex1, int l, int dl, int ex2) {105toolname = n;106supportsQuestionMark = ( q == 1 ? true : false );107supportsH = ( h == 1 ? true : false );108supportsHelp = ( hp == 1 ? true : false );109exitcodeOfHelp = ex1;110111supportsLegacyHelp = ( l == 1 ? true : false );112documentsLegacyHelp = ( dl == 1 ? true : false );113exitcodeOfWrongFlag = ex2;114}115}116117static ToolHelpSpec[] jdkTools = {118// name -? -h --help exitcode -help -help exitcode119// of help docu of wrong120// mented flag121new ToolHelpSpec("jabswitch", 0, 0, 0, 0, 0, 0, 0), // /?, prints help message anyways, win only122new ToolHelpSpec("jar", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help123new ToolHelpSpec("jarsigner", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.124new ToolHelpSpec("java", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help125new ToolHelpSpec("javac", 1, 0, 1, 0, 1, 1, 2), // -?, --help -help, Documents -help, -h is already taken for "native header output directory".126new ToolHelpSpec("javadoc", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help127new ToolHelpSpec("javap", 1, 1, 1, 0, 1, 1, 2), // -?, -h, --help -help, Documents -help128new ToolHelpSpec("javaw", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help, win only129new ToolHelpSpec("jcmd", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.130new ToolHelpSpec("jdb", 1, 1, 1, 0, 1, 1, 0), // -?, -h, --help -help, Documents -help131new ToolHelpSpec("jdeprscan", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help132new ToolHelpSpec("jdeps", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented.133new ToolHelpSpec("jfr", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help134new ToolHelpSpec("jhsdb", 0, 0, 0, 0, 0, 0, 0), // none, prints help message anyways.135new ToolHelpSpec("jimage", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help136new ToolHelpSpec("jinfo", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help137new ToolHelpSpec("jjs", 0, 1, 1, 100, 0, 0, 100), // -h, --help, return code 100138new ToolHelpSpec("jlink", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help139new ToolHelpSpec("jmap", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.140new ToolHelpSpec("jmod", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented.141new ToolHelpSpec("jps", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help142new ToolHelpSpec("jrunscript", 1, 1, 1, 0, 1, 1, 7), // -?, -h, --help -help, Documents -help143new ToolHelpSpec("jshell", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.144new ToolHelpSpec("jstack", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help145new ToolHelpSpec("jstat", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help146new ToolHelpSpec("jstatd", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help147new ToolHelpSpec("keytool", 1, 1, 1, 0, 1, 0, 1), // none, prints help message anyways.148new ToolHelpSpec("rmiregistry", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways.149new ToolHelpSpec("serialver", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways.150new ToolHelpSpec("jpackage", 0, 1, 1, 0, 0, 1, 1), // -h, --help,151};152153// Returns corresponding object from jdkTools array.154static ToolHelpSpec getToolHelpSpec(String tool) {155for (ToolHelpSpec x : jdkTools) {156if (tool.toLowerCase().equals(x.toolname) ||157tool.toLowerCase().equals(x.toolname + ".exe"))158return x;159}160return null;161}162163// Check whether 'flag' appears in 'line' as a word of itself. It must not164// be a substring of a word, as then similar flags might be matched.165// E.g.: --help matches in the documentation of --help-extra.166// This works only with english locale, as some tools have translated167// usage messages.168static boolean findFlagInLine(String line, String flag) {169if (line.contains(flag) &&170!line.contains("nknown") && // Some tools say 'Unknown option "<flag>"',171!line.contains("invalid flag") && // 'invalid flag: <flag>'172!line.contains("invalid option") && // or 'invalid option: <flag>'. Skip that.173!line.contains("FileNotFoundException: -help") && // Special case for idlj.174!line.contains("-h requires an argument") && // Special case for javac.175!line.contains("port argument,")) { // Special case for rmiregistry.176// There might be several appearances of 'flag' in177// 'line'. (-h as substring of --help).178int flagLen = flag.length();179int lineLen = line.length();180for (int i = line.indexOf(flag); i >= 0; i = line.indexOf(flag, i+1)) {181// There should be a space before 'flag' in 'line', or it's right at the beginning.182if (i > 0 &&183line.charAt(i-1) != ' ' &&184line.charAt(i-1) != '[' && // jarsigner185line.charAt(i-1) != '|' && // jstatd186line.charAt(i-1) != '\t') { // jjs187continue;188}189// There should be a space or comma after 'flag' in 'line', or it's just at the end.190int posAfter = i + flagLen;191if (posAfter < lineLen &&192line.charAt(posAfter) != ' ' &&193line.charAt(posAfter) != ',' &&194line.charAt(posAfter) != '[' && // jar195line.charAt(posAfter) != ']' && // jarsigner196line.charAt(posAfter) != ')' && // jfr197line.charAt(posAfter) != '|' && // jstatd198line.charAt(posAfter) != ':' && // jps199line.charAt(posAfter) != '"') { // keytool200continue;201}202return true;203}204}205return false;206}207208static TestResult runToolWithFlag(File f, String flag) {209String x = f.getAbsolutePath();210TestResult tr = doExec(x, flag);211System.out.println("Testing " + f.getName());212System.out.println("#> " + x + " " + flag);213tr.testOutput.forEach(System.out::println);214System.out.println("#> echo $?");215System.out.println(tr.exitValue);216217return tr;218}219220// Checks whether tool supports flag 'flag' and documents it221// in the help message.222static String testTool(File f, String flag, int exitcode) {223String result = "";224TestResult tr = runToolWithFlag(f, flag);225226// Check that the tool accepted the flag.227if (exitcode == 0 && !tr.isOK()) {228System.out.println("failed");229result = "failed: " + f.getName() + " " + flag + " has exit code " + tr.exitValue + ".\n";230}231232// Check there is a help message listing the flag.233boolean foundFlag = false;234for (String y : tr.testOutput) {235if (!foundFlag && findFlagInLine(y, flag)) { // javac236foundFlag = true;237System.out.println("Found documentation of '" + flag + "': '" + y.trim() +"'");238}239}240if (!foundFlag) {241result += "failed: " + f.getName() + " does not document " +242flag + " in help message.\n";243}244245if (!result.isEmpty())246System.out.println(result);247248return result;249}250251// Test the tool supports legacy option -help, but does252// not document it.253static String testLegacyFlag(File f, int exitcode) {254String result = "";255TestResult tr = runToolWithFlag(f, "-help");256257// Check that the tool accepted the flag.258if (exitcode == 0 && !tr.isOK()) {259System.out.println("failed");260result = "failed: " + f.getName() + " -help has exit code " + tr.exitValue + ".\n";261}262263// Check there is _no_ documentation of -help.264boolean foundFlag = false;265for (String y : tr.testOutput) {266if (!foundFlag && findFlagInLine(y, "-help")) { // javac267foundFlag = true;268System.out.println("Found documentation of '-help': '" + y.trim() +"'");269}270}271if (foundFlag) {272result += "failed: " + f.getName() + " does document -help " +273"in help message. This legacy flag should not be documented.\n";274}275276if (!result.isEmpty())277System.out.println(result);278279return result;280}281282// Test that the tool exits with the exit code expected for283// invalid flags. In general, one would expect this to be != 0,284// but currently a row of tools exit with 0 in this case.285// The output should not ask to get help with flag '-help'.286static String testInvalidFlag(File f, String flag, int exitcode, boolean documentsLegacyHelp) {287String result = "";288TestResult tr = runToolWithFlag(f, flag);289290// Check that the tool did exit with the expected return code.291if (!((exitcode == tr.exitValue) ||292// Windows reports -1 where unix reports 255.293(tr.exitValue < 0 && exitcode == tr.exitValue + 256))) {294System.out.println("failed");295result = "failed: " + f.getName() + " " + flag + " should not be " +296"accepted. But it has exit code " + tr.exitValue + ".\n";297}298299if (!documentsLegacyHelp) {300// Check there is _no_ documentation of -help.301boolean foundFlag = false;302for (String y : tr.testOutput) {303if (!foundFlag && findFlagInLine(y, "-help")) { // javac304foundFlag = true;305System.out.println("Found documentation of '-help': '" + y.trim() +"'");306}307}308if (foundFlag) {309result += "failed: " + f.getName() + " does document -help " +310"in error message. This legacy flag should not be documented.\n";311}312}313314if (!result.isEmpty())315System.out.println(result);316317return result;318}319320public static void main(String[] args) {321String errorMessage = "";322323// The test analyses the help messages printed. It assumes englisch324// help messages. Thus it only works with english locale.325if (!isEnglishLocale()) { return; }326327for (File f : new File(JAVA_BIN).listFiles(new ToolFilter(TOOLS_NOT_TO_TEST))) {328String toolName = f.getName();329330ToolHelpSpec tool = getToolHelpSpec(toolName);331if (tool == null) {332errorMessage += "Tool " + toolName + " not covered by this test. " +333"Add specification to jdkTools array!\n";334continue;335}336337// Test for help flags to be supported.338if (tool.supportsQuestionMark == true) {339errorMessage += testTool(f, "-?", tool.exitcodeOfHelp);340} else {341System.out.println("Skip " + tool.toolname + ". It does not support -?.");342}343if (tool.supportsH == true) {344errorMessage += testTool(f, "-h", tool.exitcodeOfHelp);345} else {346System.out.println("Skip " + tool.toolname + ". It does not support -h.");347}348if (tool.supportsHelp == true) {349errorMessage += testTool(f, "--help", tool.exitcodeOfHelp);350} else {351System.out.println("Skip " + tool.toolname + ". It does not support --help.");352}353354// Check that the return code listing in jdkTools[] is355// correct for an invalid flag.356errorMessage += testInvalidFlag(f, "-asdfxgr", tool.exitcodeOfWrongFlag, tool.documentsLegacyHelp);357358// Test for legacy -help flag.359if (!tool.documentsLegacyHelp) {360if (tool.supportsLegacyHelp == true) {361errorMessage += testLegacyFlag(f, tool.exitcodeOfHelp);362} else {363errorMessage += testInvalidFlag(f, "-help", tool.exitcodeOfWrongFlag, false);364}365}366}367368if (errorMessage.isEmpty()) {369System.out.println("All help string tests: PASS");370} else {371throw new AssertionError("HelpFlagsTest failed:\n" + errorMessage);372}373}374}375376377