diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 6db6daed42..5787f9dd1f 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -21,6 +21,12 @@ Further documentation can be found in: `make -C $DAIKONDIR/java javadoc` It is also available at . +## Version 5.9.1 (???, 2026) + +* Daikon and its tools now reject a malformed command-line option. +* `daikon.diff.Diff` no longer accepts the `-u` and `-z` options, which had + no effect. + ## Version 5.9.0 (September 1, 2026) * All Daikon tools now work with Java 8-26. diff --git a/doc/daikon.texinfo b/doc/daikon.texinfo index 2c7d2f72e6..63824ae74e 100644 --- a/doc/daikon.texinfo +++ b/doc/daikon.texinfo @@ -6749,9 +6749,6 @@ invariants must be justified. Does not print ``uninteresting'' invariants Display the tree of all invariants. Includes invariants that are the same in @var{file1} and @var{file2}, and unjustified invariants. -@item -u -Include ``uninteresting'' invariants in the tree of differing invariants. - @item -y @itemx --ignore_unjustified Include (statistically) unjustified invariants. diff --git a/java/Makefile b/java/Makefile index ce436e5d69..886b00683b 100644 --- a/java/Makefile +++ b/java/Makefile @@ -181,7 +181,7 @@ JAVADOC_COMMAND := ${JAVADOC} -cp ${DAIKON_CLASSPATH} JAVAC_COMMAND := ${JAVAC} -cp ${DAIKON_CLASSPATH} -Xlint -J-Xmx7g ${JAVAC_ARGS} JAVA_COMMAND := ${JAVA} -cp ${DAIKON_CLASSPATH} -DOCLETPATH := ${DAIKONDIR}/java:$(wildcard ${DAIKONDIR}/java/lib/bcel-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/plume-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/reflection-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/hashmap-util-*.jar):${DAIKONDIR}/java/lib/daikon-plumelib.jar +DOCLETPATH := ${DAIKONDIR}/java:$(wildcard ${DAIKONDIR}/java/lib/java-getopt-*.jar):$(wildcard ${DAIKONDIR}/java/lib/bcel-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/plume-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/reflection-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/hashmap-util-*.jar):${DAIKONDIR}/java/lib/daikon-plumelib.jar DOCLET_FLAGS := LINKOFFLINE := https://docs.oracle.com/javase/8/docs/api/ diff --git a/java/daikon/Daikon.java b/java/daikon/Daikon.java index 1e7c1e1b73..aaa2b3f3d6 100644 --- a/java/daikon/Daikon.java +++ b/java/daikon/Daikon.java @@ -1022,7 +1022,6 @@ static FileOptions read_options(String[] args, String usage) { LongOpt[] longopts = new LongOpt[] { // Control output - new LongOpt(help_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(no_text_output_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(format_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(show_progress_SWITCH, LongOpt.NO_ARGUMENT, null, 0), @@ -1055,7 +1054,7 @@ static FileOptions read_options(String[] args, String usage) { new LongOpt(disc_reason_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(mem_stat_SWITCH, LongOpt.NO_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.Daikon", args, "ho:", longopts); + DaikonGetopt g = new DaikonGetopt(args, "o:", longopts, usage); int c; while ((c = g.getopt()) != -1) { @@ -1065,10 +1064,7 @@ static FileOptions read_options(String[] args, String usage) { String option_name = longopts[g.getLongind()].getName(); // Control output - if (help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (no_text_output_SWITCH.equals(option_name)) { + if (no_text_output_SWITCH.equals(option_name)) { no_text_output = true; } else if (format_SWITCH.equals(option_name)) { String format_name = getOptarg(g); @@ -1367,12 +1363,9 @@ else if (ppt_regexp_SWITCH.equals(option_name)) { } else if (mem_stat_SWITCH.equals(option_name)) { use_mem_monitor = true; } else { - throw new Daikon.UserError("Unknown option " + option_name + " on command line"); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); case 'o': String inv_filename = getOptarg(g); @@ -1391,11 +1384,6 @@ else if (ppt_regexp_SWITCH.equals(option_name)) { } break; // - case '?': - // break; // getopt() already printed an error - System.out.println(usage); - throw new Daikon.NormalTermination(); - // default: throw new Daikon.BugInDaikon("getopt() returned " + c); } diff --git a/java/daikon/DaikonGetopt.java b/java/daikon/DaikonGetopt.java new file mode 100644 index 0000000000..26bf668530 --- /dev/null +++ b/java/daikon/DaikonGetopt.java @@ -0,0 +1,125 @@ +package daikon; + +import static daikon.tools.nullness.NullnessUtil.castNonNull; + +import gnu.getopt.Getopt; +import gnu.getopt.LongOpt; +import org.plumelib.util.ArraysPlume; + +/** + * A command-line option processor that throws a {@link Daikon.UserError} that describes a bad + * command-line option, instead of printing a message and returning {@code '?'} or {@code ':'}. It + * also handles {@code -h} and {@code --help}: it prints the usage message and throws {@link + * Daikon.NormalTermination}. + */ +public class DaikonGetopt extends Getopt { + + /** + * The name passed to {@link Getopt}, which uses it only in messages that DaikonGetopt suppresses. + */ + private static final String PROGNAME = "DaikonGetopt"; + + /** The usage message printed for {@code -h} and {@code --help}. */ + private final String usage; + + /** + * Creates a command-line option processor that recognizes short and long options, plus {@code -h} + * and {@code --help}, which print the usage message and throw {@link Daikon.NormalTermination}. + * + * @param argv the command-line arguments + * @param optstring the short options, in the format of {@link Getopt}; must not contain {@code h} + * @param longopts the long options; must not contain {@code help} + * @param usage the usage message to print for {@code -h} and {@code --help} + */ + public DaikonGetopt(String[] argv, String optstring, LongOpt[] longopts, String usage) { + super( + PROGNAME, + argv, + optstring + "h", + ArraysPlume.append( + longopts, new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 'h'))); + this.usage = usage; + opterr = false; + } + + /** + * Like {@link Getopt#getopt()}, but never returns {@code '?'}, {@code ':'}, or {@code 'h'}. + * Getopt returns {@code ':'} for a missing argument if the optstring starts with {@code ':'}. + * + * @return the next option, as described in {@link Getopt#getopt()} + * @throws Daikon.UserError if the next option is unrecognized, ambiguous, or malformed + * @throws Daikon.NormalTermination after printing the usage message, if the next option is {@code + * -h} or {@code --help} + */ + @Override + public int getopt() { + int c = super.getopt(); + if (c == '?' || c == ':') { + throw new Daikon.UserError(badOptionMessage() + "; run with -h for usage"); + } + if (c == 'h') { + System.out.println(usage); + throw new Daikon.NormalTermination(); + } + return c; + } + + /** + * Returns a description of the bad command-line option that {@link Getopt#getopt()} just + * rejected. + * + * @return a description of the bad command-line option + */ + private String badOptionMessage() { + // For every bad long option, Getopt clears nextchar and advances optind past the option. A + // bad short option has no such guarantee, because it may be followed by other short options in + // the same argument, as in "-xh". + if ("".equals(nextchar) && argv[optind - 1].startsWith("--")) { + return longOptionMessage(argv[optind - 1]); + } + char c = (char) optopt; + if (c == ':' || optstring.indexOf(c) == -1) { + return "Unrecognized command-line option -" + c; + } else { + return "Command-line option -" + c + " requires an argument"; + } + } + + /** + * Returns a description of a bad long command-line option. Uses {@code longind}, which Getopt + * sets to the index of the long option that matched the argument, or to -1 if none matched. + * + * @param arg the bad command-line argument, which starts with "--" + * @return a description of the bad command-line option + */ + private String longOptionMessage(String arg) { + int equalsPos = arg.indexOf('='); + String name = (equalsPos == -1) ? arg.substring(2) : arg.substring(2, equalsPos); + // Getopt treats an empty name, as in "--=foo", as a prefix of every long option. + if (name.isEmpty()) { + return "Unrecognized command-line option " + arg; + } + if (longind == -1) { + return "Unrecognized command-line option --" + name; + } + // Every constructor passes long options to Getopt. + LongOpt[] longopts = castNonNull(long_options); + LongOpt match = longopts[longind]; + // For an inexact match, Getopt sets longind to the first long option that has the given + // prefix. The match is ambiguous if a later long option also has the prefix. + if (!match.getName().equals(name)) { + for (int i = longind + 1; i < longopts.length; i++) { + if (longopts[i].getName().startsWith(name)) { + return "Ambiguous command-line option --" + name; + } + } + } + if (equalsPos != -1 && match.getHasArg() == LongOpt.NO_ARGUMENT) { + return "Command-line option --" + match.getName() + " does not take an argument"; + } else if (equalsPos == -1 && match.getHasArg() == LongOpt.REQUIRED_ARGUMENT) { + return "Command-line option --" + match.getName() + " requires an argument"; + } else { + throw new Daikon.BugInDaikon("Getopt rejected " + arg + " for no known reason"); + } + } +} diff --git a/java/daikon/MergeInvariants.java b/java/daikon/MergeInvariants.java index bc2009da5d..8a814a80fb 100644 --- a/java/daikon/MergeInvariants.java +++ b/java/daikon/MergeInvariants.java @@ -5,7 +5,6 @@ import daikon.split.PptSplitter; import daikon.suppress.NIS; -import gnu.getopt.Getopt; import gnu.getopt.LongOpt; import java.io.File; import java.io.FileNotFoundException; @@ -97,14 +96,13 @@ public static void mainHelper(String[] args) LongOpt[] longopts = new LongOpt[] { - new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.config_option_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.MergeInvariants", args, "ho:", longopts); + DaikonGetopt g = new DaikonGetopt(args, "o:", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { @@ -112,10 +110,7 @@ public static void mainHelper(String[] args) // long option case 0: String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (Daikon.config_option_SWITCH.equals(option_name)) { + if (Daikon.config_option_SWITCH.equals(option_name)) { String item = Daikon.getOptarg(g); daikon.config.Configuration.getInstance().apply(item); break; @@ -133,14 +128,10 @@ public static void mainHelper(String[] args) "Error parsing track argument '" + Daikon.getOptarg(g) + "' - " + error); } } else { - throw new Daikon.UserError("Unknown long option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); - case 'o': String output_inv_filename = Daikon.getOptarg(g); @@ -160,12 +151,8 @@ public static void mainHelper(String[] args) } break; - case '?': - break; // getopt() already printed an error - default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/java/daikon/PrintInvariants.java b/java/daikon/PrintInvariants.java index f7bc9121c3..57f483661d 100644 --- a/java/daikon/PrintInvariants.java +++ b/java/daikon/PrintInvariants.java @@ -24,7 +24,6 @@ import daikon.split.PptSplitter; import daikon.suppress.NIS; import daikon.suppress.NISuppressionSet; -import gnu.getopt.Getopt; import gnu.getopt.LongOpt; import java.io.BufferedWriter; import java.io.File; @@ -329,7 +328,6 @@ public static void mainHelper(String[] args) LongOpt[] longopts = new LongOpt[] { - new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.format_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.suppress_redundant_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.output_num_samples_SWITCH, LongOpt.NO_ARGUMENT, null, 0), @@ -344,17 +342,14 @@ public static void mainHelper(String[] args) new LongOpt( PrintInvariants.print_csharp_metadata_SWITCH, LongOpt.OPTIONAL_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.PrintInvariants", args, "h", longopts); + DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { case 0: // got a long option String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (Daikon.ppt_regexp_SWITCH.equals(option_name)) { + if (Daikon.ppt_regexp_SWITCH.equals(option_name)) { if (ppt_regexp != null) { throw new Error( "multiple --" @@ -430,17 +425,11 @@ public static void mainHelper(String[] args) } else if (Daikon.wrap_xml_SWITCH.equals(option_name)) { wrap_xml = true; } else { - throw new RuntimeException("Unknown long option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); - case '?': - break; // getopt() already printed an error default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/java/daikon/UnionInvariants.java b/java/daikon/UnionInvariants.java index ea34b0f075..c07e19d7ce 100644 --- a/java/daikon/UnionInvariants.java +++ b/java/daikon/UnionInvariants.java @@ -1,6 +1,5 @@ package daikon; -import gnu.getopt.Getopt; import gnu.getopt.LongOpt; import java.io.File; import org.plumelib.util.FilesPlume; @@ -52,25 +51,19 @@ public static void mainHelper(String[] args) throws Exception { new LongOpt[] { new LongOpt(Daikon.suppress_redundant_SWITCH, LongOpt.NO_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.UnionInvariants", args, "ho:", longopts); + DaikonGetopt g = new DaikonGetopt(args, "o:", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { case 0: // got a long option String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (Daikon.suppress_redundant_SWITCH.equals(option_name)) { + if (Daikon.suppress_redundant_SWITCH.equals(option_name)) { Daikon.suppress_redundant_invariants_with_simplify = true; } else { - throw new Daikon.UserError("Unknown option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); case 'o': String inv_filename = Daikon.getOptarg(g); @@ -90,11 +83,8 @@ public static void mainHelper(String[] args) throws Exception { } break; // - case '?': - break; // getopt() already printed an error default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/java/daikon/diff/Diff.java b/java/daikon/diff/Diff.java index 0019d1e935..324406bafb 100644 --- a/java/daikon/diff/Diff.java +++ b/java/daikon/diff/Diff.java @@ -4,13 +4,13 @@ import static java.util.logging.Level.INFO; import daikon.Daikon; +import daikon.DaikonGetopt; import daikon.FileIO; import daikon.Ppt; import daikon.PptConditional; import daikon.PptMap; import daikon.PptTopLevel; import daikon.inv.Invariant; -import gnu.getopt.Getopt; import gnu.getopt.LongOpt; import java.io.File; import java.io.FileNotFoundException; @@ -68,13 +68,19 @@ public final class Diff { " For a list of flags, see the Daikon manual, which appears in the ", " Daikon distribution and also at http://plse.cs.washington.edu/daikon/."); - /** The long command line options. */ - private static final String HELP_SWITCH = "help"; - + /** The long command-line option that specifies the comparator to sort the first set of invs. */ private static final String INV_SORT_COMPARATOR1_SWITCH = "invSortComparator1"; + + /** The long command-line option that specifies the comparator to sort the second set of invs. */ private static final String INV_SORT_COMPARATOR2_SWITCH = "invSortComparator2"; + + /** The long command-line option that specifies the comparator to pair up invs. */ private static final String INV_PAIR_COMPARATOR_SWITCH = "invPairComparator"; + + /** The long command-line option that is a synonym for -y. */ private static final String IGNORE_UNJUSTIFIED_SWITCH = "ignore_unjustified"; + + /** The long command-line option that ignores numbered exit points. */ private static final String IGNORE_NUMBERED_EXITS_SWITCH = "ignore_exitNN"; /** Determine which ppts should be paired together in the tree. */ @@ -193,7 +199,6 @@ public static void mainHelper(final String[] args) LongOpt[] longOpts = new LongOpt[] { - new LongOpt(HELP_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(INV_SORT_COMPARATOR1_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(INV_SORT_COMPARATOR2_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(INV_PAIR_COMPARATOR_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), @@ -201,20 +206,14 @@ public static void mainHelper(final String[] args) new LongOpt(IGNORE_NUMBERED_EXITS_SWITCH, LongOpt.NO_ARGUMENT, null, 0), }; - Getopt g = - new Getopt( - "daikon.diff.Diff", args, - "Hhyduastmxno:jzpevl", longOpts); + DaikonGetopt g = new DaikonGetopt(args, "Hydastmxno:jpevl", longOpts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { case 0: // got a long option String optionName = longOpts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(optionName)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (INV_SORT_COMPARATOR1_SWITCH.equals(optionName)) { + if (INV_SORT_COMPARATOR1_SWITCH.equals(optionName)) { if (invSortComparator1Classname != null) { throw new Error( "multiple --" @@ -252,12 +251,9 @@ public static void mainHelper(final String[] args) ignoreNumberedExits = true; break; } else { - throw new RuntimeException("Unknown long option received: " + optionName); + throw new Daikon.BugInDaikon("Unhandled long option " + optionName); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); case 'H': PrintAllVisitor.HUMAN_OUTPUT = true; break; @@ -318,13 +314,8 @@ public static void mainHelper(final String[] args) case 'l': logging = true; break; - case '?': - // getopt() already printed an error - System.out.println(usage); - throw new Daikon.UserError("Bad argument"); default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } @@ -422,8 +413,7 @@ public static void mainHelper(final String[] args) v1.printAll(); return; } else { - System.out.println(usage); - throw new Daikon.NormalTermination(); + throw new Daikon.UserError("No invariant files specified; run with -h for usage"); } if (logging) { diff --git a/java/daikon/test/AllTestsSuite.java b/java/daikon/test/AllTestsSuite.java index 7d74e7e7ac..9a817b266f 100644 --- a/java/daikon/test/AllTestsSuite.java +++ b/java/daikon/test/AllTestsSuite.java @@ -7,6 +7,7 @@ @RunWith(Suite.class) @Suite.SuiteClasses({ daikon.chicory.RuntimeTest.class, + daikon.test.BadOptionTest.class, daikon.test.TestClassOrInterfaceTypeDecorateVisitor.class, daikon.test.TestAst.class, daikon.test.config.ConfigurationTest.class, diff --git a/java/daikon/test/BadOptionTest.java b/java/daikon/test/BadOptionTest.java new file mode 100644 index 0000000000..0f50ea31e2 --- /dev/null +++ b/java/daikon/test/BadOptionTest.java @@ -0,0 +1,176 @@ +package daikon.test; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import daikon.Daikon; +import daikon.DaikonGetopt; +import daikon.PrintInvariants; +import daikon.UnionInvariants; +import daikon.tools.DtraceDiff; +import gnu.getopt.LongOpt; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import org.junit.Test; +import org.junit.function.ThrowingRunnable; + +/** + * Tests that Daikon tools reject bad command-line options with a UserError. + * + *

These tests do not call {@code Daikon.mainHelper}, because it resets Daikon's global state, + * which other tests in the same JVM depend on. + */ +public class BadOptionTest { + + /** The long options used by {@link #parse}. DaikonGetopt adds {@code --help}. */ + private static final LongOpt[] longopts = + new LongOpt[] { + new LongOpt("config", LongOpt.REQUIRED_ARGUMENT, null, 0), + new LongOpt("config_option", LongOpt.REQUIRED_ARGUMENT, null, 0), + new LongOpt("debug", LongOpt.REQUIRED_ARGUMENT, null, 'd'), + new LongOpt("verbose", LongOpt.NO_ARGUMENT, null, 'v'), + }; + + /** The suffix of every description of a bad command-line option. */ + private static final String USAGE_HINT = "; run with -h for usage"; + + /** + * Parses the given command-line arguments, which must contain a bad option, and returns the + * resulting error message, without its suffix that suggests running with -h. + * + * @param optstring the short options, in the format of Getopt + * @param args command-line arguments + * @return the message of the UserError for the bad option, without {@link #USAGE_HINT} + */ + private static String parseWith(String optstring, String... args) { + DaikonGetopt g = new DaikonGetopt(args, optstring, longopts, "usage"); + Daikon.UserError e = assertThrows(Daikon.UserError.class, () -> consumeAll(g)); + String message = String.valueOf(e.getMessage()); + assertTrue(message, message.endsWith(USAGE_HINT)); + return message.substring(0, message.length() - USAGE_HINT.length()); + } + + /** + * Parses the given command-line arguments, which must contain a bad option, and returns the + * resulting error message, without its suffix that suggests running with -h. + * + * @param args command-line arguments + * @return the message of the UserError for the bad option, without {@link #USAGE_HINT} + */ + private static String parse(String... args) { + return parseWith("vo:", args); + } + + /** + * Calls {@code getopt()} until all command-line arguments have been processed. + * + * @param g the command-line parser + */ + private static void consumeAll(DaikonGetopt g) { + while (g.getopt() != -1) {} + } + + /** Tests an unrecognized long option. */ + @Test + public void testUnrecognizedLongOption() { + assertEquals("Unrecognized command-line option --bogus", parse("--bogus")); + assertEquals("Unrecognized command-line option --bogus", parse("--bogus=3")); + assertEquals("Unrecognized command-line option --=3", parse("--=3")); + assertEquals("Unrecognized command-line option --bogus", parse("-v", "--bogus", "file")); + } + + /** Tests an unrecognized short option, alone and combined with a valid one. */ + @Test + public void testUnrecognizedShortOption() { + assertEquals("Unrecognized command-line option -x", parse("-x")); + assertEquals("Unrecognized command-line option -x", parse("-xv")); + assertEquals("Unrecognized command-line option -x", parse("-vx")); + assertEquals("Unrecognized command-line option -:", parse("-:")); + } + + /** Tests an unrecognized short option when there are no short options. */ + @Test + public void testNoShortOptions() { + for (String arg : new String[] {"- ", "-x", "-:"}) { + assertEquals("Unrecognized command-line option " + arg, parseWith("", arg)); + } + } + + /** Tests an ambiguous abbreviation of a long option. */ + @Test + public void testAmbiguousLongOption() { + assertEquals("Ambiguous command-line option --conf", parse("--conf=x")); + assertEquals("Ambiguous command-line option --conf", parse("--conf")); + } + + /** Tests options that are missing their required argument. */ + @Test + public void testMissingArgument() { + assertEquals("Command-line option --config requires an argument", parse("--config")); + assertEquals("Command-line option --debug requires an argument", parse("--deb")); + assertEquals("Command-line option -o requires an argument", parse("-o")); + assertEquals("Command-line option -o requires an argument", parse("-vo")); + } + + /** Tests options that are missing their required argument, when the optstring starts with ':'. */ + @Test + public void testMissingArgumentLeadingColon() { + assertEquals("Command-line option -o requires an argument", parseWith(":o:", "-o")); + assertEquals("Command-line option --config requires an argument", parseWith(":o:", "--config")); + } + + /** Tests long options that are given an argument they do not take. */ + @Test + public void testUnexpectedArgument() { + assertEquals("Command-line option --help does not take an argument", parse("--help=x")); + assertEquals("Command-line option --verbose does not take an argument", parse("--verb=x")); + } + + /** + * Asserts that running {@code mainCall} throws a UserError with the given message. + * + * @param description a description of the bad option + * @param mainCall a call to a tool's {@code mainHelper} method + */ + private static void assertBadOption(String description, ThrowingRunnable mainCall) { + Daikon.UserError e = assertThrows(Daikon.UserError.class, mainCall); + assertEquals(description + USAGE_HINT, String.valueOf(e.getMessage())); + } + + /** Tests an unrecognized long option in a tool. */ + @Test + public void testPrintInvariantsUnrecognizedOption() { + assertBadOption( + "Unrecognized command-line option --bogus", + () -> PrintInvariants.mainHelper(new String[] {"--bogus", "foo.inv.gz"})); + } + + /** Tests that tools accept the {@code --help} option that their usage messages document. */ + @Test + public void testHelpOption() { + assertPrintsUsage(() -> DtraceDiff.mainHelper(new String[] {"--help"})); + assertPrintsUsage(() -> UnionInvariants.mainHelper(new String[] {"--help"})); + } + + /** + * Asserts that the given code prints a usage message to standard output and throws {@link + * Daikon.NormalTermination}. Captures the usage message so that it does not clutter the test + * output. + * + * @param code the code to run + */ + private static void assertPrintsUsage(ThrowingRunnable code) { + PrintStream oldOut = System.out; + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bytes, true, UTF_8)); + try { + assertThrows(Daikon.NormalTermination.class, code); + } finally { + System.setOut(oldOut); + } + assertNotEquals("", bytes.toString(UTF_8).trim()); + } +} diff --git a/java/daikon/test/SampleTester.java b/java/daikon/test/SampleTester.java index 40919edb6b..ee6c5eda2e 100644 --- a/java/daikon/test/SampleTester.java +++ b/java/daikon/test/SampleTester.java @@ -8,6 +8,7 @@ import static org.junit.Assert.fail; import daikon.Daikon; +import daikon.DaikonGetopt; import daikon.Debug; import daikon.FileIO; import daikon.Global; @@ -18,7 +19,6 @@ import daikon.ValueTuple; import daikon.VarInfo; import daikon.inv.Invariant; -import gnu.getopt.Getopt; import gnu.getopt.LongOpt; import java.io.File; import java.io.IOException; @@ -78,8 +78,29 @@ public class SampleTester { " Specify a class, varinfos, and ppt to debug track.", " Format is class@ppt"); - @SuppressWarnings("JUnitMethodInvoked") // main() runs the tests without JUnit + /** + * Runs the sample tests. + * + * @param args command-line arguments + * @throws IOException if there is trouble reading a file + */ public static void main(String[] args) throws IOException { + try { + mainHelper(args); + } catch (Daikon.DaikonTerminationException e) { + Daikon.handleDaikonTerminationException(e); + } + } + + /** + * Does the work of {@link #main}, but throws an exception rather than calling {@code + * System.exit}. + * + * @param args command-line arguments + * @throws IOException if there is trouble reading a file + */ + @SuppressWarnings("JUnitMethodInvoked") // mainHelper() runs the tests without JUnit + public static void mainHelper(String[] args) throws IOException { LongOpt[] longopts = new LongOpt[] { @@ -89,7 +110,7 @@ public static void main(String[] args) throws IOException { new LongOpt(Daikon.track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.test.SampleTester", args, "h:", longopts); + DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { @@ -97,11 +118,7 @@ public static void main(String[] args) throws IOException { // long option case 0: String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - - } else if (Daikon.config_option_SWITCH.equals(option_name)) { + if (Daikon.config_option_SWITCH.equals(option_name)) { String item = Daikon.getOptarg(g); daikon.config.Configuration.getInstance().apply(item); break; @@ -119,20 +136,12 @@ public static void main(String[] args) throws IOException { "Error parsing track argument '" + Daikon.getOptarg(g) + "' - " + error); } } else { - throw new RuntimeException("Unknown long option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); - - case '?': - break; // getopt() already printed an error - default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/java/daikon/test/split/SplitterFactoryTestUpdater.java b/java/daikon/test/split/SplitterFactoryTestUpdater.java index 0c806f6071..5391293804 100644 --- a/java/daikon/test/split/SplitterFactoryTestUpdater.java +++ b/java/daikon/test/split/SplitterFactoryTestUpdater.java @@ -247,24 +247,36 @@ private static String getTestClassText() { " \" -s Save (do not delete) the splitter java files in the temp directory\","); ps.println(" \" -h Display this usage message\");"); ps.println(); + ps.println(" /**"); + ps.println(" * Processes command-line options."); + ps.println(" *"); + ps.println(" * @param args command-line arguments"); + ps.println(" */"); ps.println(" public static void main(String[] args) {"); + ps.println(" try {"); + ps.println(" mainHelper(args);"); + ps.println(" } catch (Daikon.DaikonTerminationException e) {"); + ps.println(" Daikon.handleDaikonTerminationException(e);"); + ps.println(" }"); + ps.println(" }"); + ps.println(); + ps.println(" /**"); ps.println( - " Getopt g = new Getopt(\"daikon.test.split.SplitterFactoryTest\", args, \"hs\");"); + " * Does the work of {@link #main}, but throws an exception rather than calling {@code"); + ps.println(" * System.exit}."); + ps.println(" *"); + ps.println(" * @param args command-line arguments"); + ps.println(" */"); + ps.println(" public static void mainHelper(String[] args) {"); + ps.println(" DaikonGetopt g = new DaikonGetopt(args, \"s\", new LongOpt[0], usage);"); ps.println(" int c;"); ps.println(" while ((c = g.getopt()) != -1) {"); ps.println(" switch (c) {"); ps.println(" case 's':"); ps.println(" saveFiles = true;"); ps.println(" break;"); - ps.println(" case 'h':"); - ps.println(" System.out.println(usage);"); - ps.println(" System.exit(1);"); - ps.println(" break;"); - ps.println(" case '?':"); - ps.println(" break;"); ps.println(" default:"); - ps.println(" System.out.println(\"getopt() returned \" + c);"); - ps.println(" break;"); + ps.println(" throw new Daikon.BugInDaikon(\"getopt() returned \" + c);"); ps.println(" }"); ps.println(" }"); ps.println(" }"); diff --git a/java/daikon/tools/DtraceDiff.java b/java/daikon/tools/DtraceDiff.java index 7d158ccc29..0fe001621e 100644 --- a/java/daikon/tools/DtraceDiff.java +++ b/java/daikon/tools/DtraceDiff.java @@ -6,6 +6,7 @@ import static daikon.tools.nullness.NullnessUtil.*; import daikon.Daikon; +import daikon.DaikonGetopt; import daikon.FileIO; import daikon.Global; import daikon.PptMap; @@ -124,7 +125,7 @@ public static void mainHelper(final String[] args) { new LongOpt(Daikon.config_option_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.tools.DtraceDiff", args, "h:", longopts); + DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { @@ -132,10 +133,7 @@ public static void mainHelper(final String[] args) { // long option case 0: String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (Daikon.ppt_regexp_SWITCH.equals(option_name)) { + if (Daikon.ppt_regexp_SWITCH.equals(option_name)) { if (Daikon.ppt_regexp != null) { throw new Error( "multiple --" @@ -224,20 +222,11 @@ public static void mainHelper(final String[] args) { Configuration.getInstance().apply(item); break; } else { - throw new RuntimeException("Unknown long option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } - // short options - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); - - case '?': - break; // getopt() already printed an error - default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/java/daikon/tools/ExtractConsequent.java b/java/daikon/tools/ExtractConsequent.java index f2ecf3caf3..d4f94d9f49 100644 --- a/java/daikon/tools/ExtractConsequent.java +++ b/java/daikon/tools/ExtractConsequent.java @@ -5,6 +5,7 @@ import static java.util.logging.Level.INFO; import daikon.Daikon; +import daikon.DaikonGetopt; import daikon.FileIO; import daikon.Global; import daikon.Ppt; @@ -118,17 +119,14 @@ public static void mainHelper(final String[] args) throws IOException { new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.ExtractConsequent", args, "h", longopts); + DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { case 0: // got a long option String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (Daikon.suppress_redundant_SWITCH.equals(option_name)) { + if (Daikon.suppress_redundant_SWITCH.equals(option_name)) { Daikon.suppress_redundant_invariants_with_simplify = true; } else if (Daikon.config_option_SWITCH.equals(option_name)) { String item = Daikon.getOptarg(g); @@ -139,17 +137,11 @@ public static void mainHelper(final String[] args) throws IOException { } else if (Daikon.debug_SWITCH.equals(option_name)) { daikon.LogHelper.setLevel(Daikon.getOptarg(g), FINE); } else { - throw new RuntimeException("Unknown long option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); - case '?': - break; // getopt() already printed an error default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } // The index of the first non-option argument -- the name of the file diff --git a/java/daikon/tools/InvariantChecker.java b/java/daikon/tools/InvariantChecker.java index 70a3c804d1..3f8c7c56b7 100644 --- a/java/daikon/tools/InvariantChecker.java +++ b/java/daikon/tools/InvariantChecker.java @@ -4,6 +4,7 @@ import static java.util.logging.Level.INFO; import daikon.Daikon; +import daikon.DaikonGetopt; import daikon.Debug; import daikon.FileIO; import daikon.Global; @@ -135,20 +136,16 @@ public static void mainHelper(final String[] args) new LongOpt(verbose_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), - new LongOpt(Daikon.ppt_regexp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.tools.InvariantChecker", args, "h", longopts); + DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { case 0: // got a long option String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (conf_SWITCH.equals(option_name)) { + if (conf_SWITCH.equals(option_name)) { doConf = true; } else if (filter_SWITCH.equals(option_name)) { doFilter = true; @@ -179,17 +176,11 @@ public static void mainHelper(final String[] args) "Error parsing track argument '" + Daikon.getOptarg(g) + "' - " + error); } } else { - throw new RuntimeException("Unknown long option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); - case '?': - break; // getopt() already printed an error default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/java/daikon/tools/compare/LogicalCompare.java b/java/daikon/tools/compare/LogicalCompare.java index bbbc6df993..371d26ea25 100644 --- a/java/daikon/tools/compare/LogicalCompare.java +++ b/java/daikon/tools/compare/LogicalCompare.java @@ -5,6 +5,7 @@ import static java.util.logging.Level.INFO; import daikon.Daikon; +import daikon.DaikonGetopt; import daikon.FileIO; import daikon.Global; import daikon.PptMap; @@ -658,7 +659,6 @@ public static void mainHelper(final String[] args) new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt("filters", LongOpt.REQUIRED_ARGUMENT, null, 0), - new LongOpt("help", LongOpt.NO_ARGUMENT, null, 0), new LongOpt("minimize-classes", LongOpt.NO_ARGUMENT, null, 0), new LongOpt("no-post-after-pre-failure", LongOpt.NO_ARGUMENT, null, 0), new LongOpt("post-after-pre-failure", LongOpt.NO_ARGUMENT, null, 0), @@ -675,7 +675,7 @@ public static void mainHelper(final String[] args) extra_assumptions = new LinkedHashMap<>(); - Getopt g = new Getopt("daikon.tools.compare.LogicalCompare", args, "h", longopts); + DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage); int c; boolean user_filters = false; while ((c = g.getopt()) != -1) { @@ -683,10 +683,7 @@ public static void mainHelper(final String[] args) case 0: // got a long option String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (option_name.equals("config-file")) { + if (option_name.equals("config-file")) { String config_file = Daikon.getOptarg(g); try (InputStream stream = new FileInputStream(config_file)) { Configuration.getInstance().apply(stream); @@ -727,15 +724,11 @@ public static void mainHelper(final String[] args) } else if (option_name.equals("minimize-classes")) { opt_minimize_classes = true; } else { - throw new Error(); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); - case '?': - // getopt() already printed an error - throw new Daikon.UserError("Bad argument"); + default: + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/java/daikon/tools/jtb/Annotate.java b/java/daikon/tools/jtb/Annotate.java index 9635cc5912..b76c70ef97 100644 --- a/java/daikon/tools/jtb/Annotate.java +++ b/java/daikon/tools/jtb/Annotate.java @@ -24,8 +24,7 @@ * *

The first argument is a Daikon {@code .inv} file -- a serialized file of Invariant objects. * All subsequent arguments are {@code Foo.java} files that are rewritten into {@code - * Foo.java-jmlannotated} versions; alternately, use the {@code -r} flag to process every {@code - * .java} file under the current directory. + * Foo.java-jmlannotated} versions. */ public class Annotate { @@ -88,11 +87,10 @@ private Annotate() { private static String usage = StringsPlume.joinLines( "Usage: java daikon.tools.Annotate FILE.inv FILE.java ...", - " -h Display this usage message", - " -i Insert invariants not supported by ESC with \"!\" instead of \"@\";", - " by default these \"inexpressible\" invariants are simply omitted", - " -r Use all .java files under the current directory as arguments", - " -s Use // comments rather than /* comments", + " -h, --help Display this usage message", + " -i Insert invariants not supported by ESC with \"!\" instead of \"@\";", + " by default these \"inexpressible\" invariants are simply omitted", + " -s Use // comments rather than /* comments", " --format name Insert specifications in the given format: DBC, ESC, JML, Java", " --wrap_xml Wrap each annotation and auxiliary information in XML tags", " --max_invariants_pp N", @@ -132,7 +130,6 @@ public static void mainHelper(final String[] args) throws Exception { Daikon.output_format = OutputFormat.ESCJAVA; LongOpt[] longopts = new LongOpt[] { - new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.format_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), @@ -140,7 +137,7 @@ public static void mainHelper(final String[] args) throws Exception { new LongOpt(max_invariants_pp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(no_reflection_SWITCH, LongOpt.NO_ARGUMENT, null, 0) }; - Getopt g = new Getopt("daikon.tools.jtb.Annotate", args, "hs", longopts); + DaikonGetopt g = new DaikonGetopt(args, "is", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { @@ -148,10 +145,7 @@ public static void mainHelper(final String[] args) throws Exception { // got a long option String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (no_reflection_SWITCH.equals(option_name)) { + if (no_reflection_SWITCH.equals(option_name)) { useReflection = false; } else if (max_invariants_pp_SWITCH.equals(option_name)) { try { @@ -181,12 +175,9 @@ public static void mainHelper(final String[] args) throws Exception { setLightweight = true; } } else { - throw new Daikon.UserError("Unknown long option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); case 'i': insert_inexpressible = true; break; @@ -200,11 +191,8 @@ public static void mainHelper(final String[] args) throws Exception { case 's': slashslash = true; break; - case '?': - break; // getopt() already printed an error default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/java/daikon/tools/jtb/CreateSpinfo.java b/java/daikon/tools/jtb/CreateSpinfo.java index 56f1b154e2..76d4b23b05 100644 --- a/java/daikon/tools/jtb/CreateSpinfo.java +++ b/java/daikon/tools/jtb/CreateSpinfo.java @@ -83,40 +83,30 @@ public static void mainHelper(final String[] args) throws IOException { daikon.LogHelper.setupLogs(INFO); LongOpt[] longopts = new LongOpt[] { - new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), }; - Getopt g = new Getopt("daikon.tools.jtb.CreateSpinfo", args, "ho:", longopts); + DaikonGetopt g = new DaikonGetopt(args, "o:", longopts, usage); int c; while ((c = g.getopt()) != -1) { switch (c) { case 0: // got a long option String option_name = longopts[g.getLongind()].getName(); - if (Daikon.help_SWITCH.equals(option_name)) { - System.out.println(usage); - throw new Daikon.NormalTermination(); - } else if (Daikon.debugAll_SWITCH.equals(option_name)) { + if (Daikon.debugAll_SWITCH.equals(option_name)) { Global.debugAll = true; } else if (Daikon.debug_SWITCH.equals(option_name)) { daikon.LogHelper.setLevel(Daikon.getOptarg(g), FINE); } else { - throw new RuntimeException("Unknown long option received: " + option_name); + throw new Daikon.BugInDaikon("Unhandled long option " + option_name); } break; case 'o': outputfilename = Daikon.getOptarg(g); break; - case 'h': - System.out.println(usage); - throw new Daikon.NormalTermination(); - case '?': - break; // getopt() already printed an error default: - System.out.println("getopt() returned " + c); - break; + throw new Daikon.BugInDaikon("getopt() returned " + c); } } diff --git a/tests/diff-tests/Makefile.common b/tests/diff-tests/Makefile.common index 7a22461dfd..014605b8b4 100644 --- a/tests/diff-tests/Makefile.common +++ b/tests/diff-tests/Makefile.common @@ -20,10 +20,10 @@ INV_FILES := $(PROGRAM)-1.inv.gz $(PROGRAM)-2.inv.gz # An output file must satisfy the pattern program%.txt, where the % is # the options passed to Diff ## Must reinstate -a and -ap and -p in V3 as soon as possible. -MDE 6/10/2003 -# OUTPUT := $(PROGRAM).txt $(PROGRAM)-u.txt $(PROGRAM)-a.txt $(PROGRAM)-p.txt \ +# OUTPUT := $(PROGRAM).txt $(PROGRAM)-a.txt $(PROGRAM)-p.txt \ # $(PROGRAM)-e.txt $(PROGRAM)-ap.txt $(PROGRAM)-t.txt \ # $(PROGRAM)-jt.txt -OUTPUT := $(PROGRAM).txt $(PROGRAM)-u.txt \ +OUTPUT := $(PROGRAM).txt \ $(PROGRAM)-e.txt $(PROGRAM)-t.txt \ $(PROGRAM)-jt.txt # Must be handled differently than OUTPUT, because map files are diff --git a/tests/diff-tests/StackAr/StackAr-u.txt.goal b/tests/diff-tests/StackAr/StackAr-u.txt.goal deleted file mode 100644 index f3164de375..0000000000 --- a/tests/diff-tests/StackAr/StackAr-u.txt.goal +++ /dev/null @@ -1,105 +0,0 @@ -(I)V:::ENTER> - = 0 {0+}, capacity >= 2 {1-}> (UInt,DJU) - (U!Int,DUU) -(I)V:::EXIT> - (Bin,MJ) - (Bin,MJ) - = -1 {0.8136-}, this.topOfStack >= -1 {0.8333-}> (U!Int,SUU) - (UInt,SJU) - (U!Int,DUU) - (U!Int,SUU) - (UInt,SJU) - (UInt,MJ) - - = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ) - (U!Int,DJU) - (U!Int,DUU) - (UInt,MJ) - - = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ) - (U!Int,DJU) - (U!Int,DJU) - (U!Int,DUU) - (UInt,MJ) - - (Bin,MJ) - = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ) - (U!Int,DJJ) - (U!Int,DUU) - - (Bin,MJ) - = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ) - (UInt,MJ) - (U!Int,DJJ) - (U!Int,DJJ) - (U!Int,DUU) - - (Bin,JM) - = -1 {0+}, this.topOfStack >= 9223372036854775807 {1-}> (U!Int,DJU) - (U!Int,UM) - (U!Int,DUU) - (UInt,JM) - (UInt,JM) - (UInt,DJU) - - (Bin,JM) - (Bin,JM) - (Bin,JM) - (Bin,JM) - (Bin,JM) - = -1 {0+}, null> (U!Int,JM) - = -1 {0.8205-}, this.topOfStack >= 9223372036854775807 {1-}> (U!Int,DUU) - (UInt,DJU) - (U!Int,UM) - (U!Int,UM) - (U!Int,UM) - (U!Int,DUU) - (UInt,DJU) - (UInt,JM) - (UInt,JM) - (UInt,DJU) - (UInt,DJU) - - = 9223372036854775807 {1-}, this.topOfStack >= 9223372036854775807 {1-}> (U!Int,SUU) - (U!Int,SUU) - - = 9223372036854775807 {1-}, this.topOfStack >= 9223372036854775807 {1-}> (U!Int,SUU) - (U!Int,SUU) - - = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ) - (U!Int,DJJ) - (U!Int,DUU) - - = -1 {0+}, orig(this.topOfStack) >= -1 {0+}> (U!Int,SJJ) - (U!Int,DUU) - (U!Int,DJJ) - (U!Int,DJJ) - (U!Int,DUU) - - = -1 {0+}, this.topOfStack >= 0 {0+}> (UInt,DJJ) - (U!Int,DJJ) - (U!Int,DUU) - - (Bin,MJ) - (Bin,MJ) - (Bin,MJ) - (Bin,MJ) - = -1 {0+}, this.topOfStack >= 0 {0+}> (UInt,DJJ) - (UInt,MJ) - (U!Int,DJJ) - (U!Int,DJJ) - (U!Int,DUU) - - = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ) - (U!Int,DJU) - (U!Int,DUU) - - (Bin,MJ) - (Bin,MJ) - (Bin,MJ) - = -1 {0+}, orig(this.topOfStack) >= -1 {0+}> (U!Int,SJJ) - = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ) - (U!Int,DUU) - (U!Int,DJU) - (U!Int,DJU) - (U!Int,DUU) diff --git a/tests/diff-tests/schedule2/schedule2-u.txt.goal b/tests/diff-tests/schedule2/schedule2-u.txt.goal deleted file mode 100644 index ef71a1c0d9..0000000000 --- a/tests/diff-tests/schedule2/schedule2-u.txt.goal +++ /dev/null @@ -1,77 +0,0 @@ -getopt() returned 117 - - <::next_pid >= 0 {0-}, ::next_pid >= 0 {1+}> (Una,SUJ) - - <::next_pid >= 0 {0-}, ::next_pid >= 0 {1+}> (Una,SUJ) - - = 0 {1+}, prio >= -1 {1+}> (Una,DJJ) - - (return is a pointer) {1+}> (Nul,MJ) - (prio >= -1) {1+}> (Nul,MJ) - (prio >= 0) {1+}> (Nul,MJ) - (prio != 0) {0.9999+}> (Nul,MJ) - = 0 {1+}, prio >= -1 {1+}> (Una,DJJ) - (Una,DJJ) - - <*prio >= -1 {1+}, *prio >= -2 {0-}> (Una,DJU) - <*command != 0 {1+}, null> (Una,JM) - - (*prio >= -1) {1+}> (Nul,MJ) - (orig(*prio) >= -1) {1+}> (Nul,MJ) - <(return == 1) ==> (*prio != 0) {1+}, null> (Nul,JM) - (*command == 0) {1+}> (Bin,MJ) - <(*prio == 0) ==> (orig(*prio) == 0) {1+}, null> (Bin,JM) - <*prio >= -1 {1+}, *prio >= -2 {0-}> (Una,DJU) - <*command != 0 {1+}, null> (Una,JM) - - <::next_pid >= 0 {0.4444-}, ::next_pid >= 0 {1+}> (Una,SUJ) - - <::next_pid >= 0 {0.4444-}, ::next_pid >= 0 {1+}> (Una,SUJ) - - = 0.0 {1+}, ratio >= -1.0 {0.0721-}> (Una,DJU) - - = 0.0 {1+}, ratio >= -1.0 {0.0721-}> (Una,DJU) - (Una,DJJ) - - (Una,JM) - - = orig(::next_pid) {1+}> (Bin,MJ) - <::next_pid - orig(::next_pid) - 1 == 0 {1+}, null> (Bin,JM) - (orig(::next_pid) == 0) {1+}> (Bin,MJ) - <::next_pid >= 1 {1+}, ::next_pid >= 0 {0.3333-}> (Una,DJU) - (Una,DUJ) - (Una,JM) - (Una,DJJ) - - = 0 {1+}, prio >= -1 {1+}> (Una,DJJ) - - (return is a pointer) {1+}> (Nul,MJ) - (prio >= -1) {1+}> (Nul,MJ) - (prio >= 0) {1+}> (Nul,MJ) - (prio != 0) {0.9999+}> (Nul,MJ) - = 0 {1+}, prio >= -1 {1+}> (Una,DJJ) - (Una,DJJ) - - = -1 {1+}, prio >= -2 {0-}> (Una,DJU) - (Una,JM) - (Una,JM) - - = -1 {1+}, prio >= -2 {0-}> (Una,DJU) - (Una,JM) - (Una,JM) - (Una,JM) - (Una,JM) - - (Una,SUJ) - - (Una,SUJ) - (Una,DJJ) - - <::next_pid >= 0 {1+}, ::next_pid >= 0 {0.7779-}> (Una,SJU) - (Una,SUJ) - (Una,JM) - - <::next_pid >= 0 {1+}, ::next_pid >= 0 {0.7779-}> (Una,SJU) - (Una,SUJ) - (Una,JM) - (Una,DJJ)