From e7091e448b0b1eef053f894bbed4aef4907d764f Mon Sep 17 00:00:00 2001 From: Martin Kellogg Date: Fri, 26 Jul 2024 09:04:45 -0400 Subject: [PATCH] QoL improvement: typecheck just one test (#335) (on unix only, because I don't know how to write a bat script) --- DEVELOPERS.md | 6 +++++- build.gradle | 14 +++++++++++++- typecheck_one_test.sh | 28 ++++++++++++++++++++++++++++ typecheck_test_outputs.sh | 24 ++++++++---------------- 4 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 typecheck_one_test.sh diff --git a/DEVELOPERS.md b/DEVELOPERS.md index c58ece91..85171c93 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -25,7 +25,11 @@ if the test input is in a package, there must be a corresponding file structure here. * the expected test output. It is stored in `src/test/resources/$testname/expected`. It must be an independently-compilable Java program; our CI system checks this requirement -by running the `./gradlew expectedTestOutputsMustCompile` command. +by running the `./gradlew expectedTestOutputsMustCompile` command. Since this command takes +some time to complete, you can use `./gradlew checkExpectedOutputCompilesFor -PtestName="x"` +to run check that some specific test "x" compiles ("x" should be the all-lower-case name of +the test, since this script uses the test name to find the right "expected" directory). Note +that the `checkExpectedOutputCompilesFor` Gradle task only works on Unix systems. You can run all of the tests via `./gradlew test`. When debugging a specific test, I usually use a command like this one (replacing `MethodRef2Test` with the diff --git a/build.gradle b/build.gradle index 1c7108ae..6d389d91 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,6 @@ task requireJavadoc(type: JavaExec) { } task expectedTestOutputsMustCompile(type: Exec) { - // TODO: should this task run in CI, or as part of the regular tests? if (System.getProperty('os.name').toLowerCase().startsWith('windows')) { commandLine "cmd", "/c", "typecheck_test_outputs.bat" } else { @@ -60,6 +59,19 @@ task expectedTestOutputsMustCompile(type: Exec) { } } +// run via e.g.: ./gradlew checkExpectedOutputCompilesFor -PtestName="onefilesimple" +task checkExpectedOutputCompilesFor(type: Exec) { + if (project.hasProperty("testName")) { + workingDir("src/test/resources") + if (System.getProperty('os.name').toLowerCase().startsWith('windows')) { + // TODO: fix this + print "checkExpectedOutputCompilesFor is not supported on Windows" + } else { + commandLine "sh", "../../../typecheck_one_test.sh", project.property("testName") + } + } +} + tasks.compileJava { // uncomment for testing // options.errorprone.enabled = false diff --git a/typecheck_one_test.sh b/typecheck_one_test.sh new file mode 100644 index 00000000..019ea2bd --- /dev/null +++ b/typecheck_one_test.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +## This script runs javac on a single expected test output. If the test output +## is compilable, it exits with code 0. If not, it exits with code 1. In all other +# cases (e.g., if a cd command fails), it exits with code 2. It includes +## logic for skipping test cases that don't need to compile, etc. It should be +## run in the directory src/test/resources. + +testcase=$1 + +if [ "${testcase}" = "shared" ]; then exit 0; fi +# https://bugs.openjdk.org/browse/JDK-8319461 wasn't actually fixed (this test is based on that bug) +if [ "${testcase}" = "superinterfaceextends" ]; then exit 0; fi +# incomplete handling of method references: https://github.com/njit-jerse/specimin/issues/291 +# this test exists to check that no crash occurs, not that Specimin produces the correct output +if [ "${testcase}" = "methodref2" ]; then exit 0; fi +cd "${testcase}/expected/" || exit 2 +# javac relies on word splitting +# shellcheck disable=SC2046 +javac -classpath "../../shared/checker-qual-3.42.0.jar" $(find . -name "*.java") \ + || { echo "Running javac on ${testcase}/expected issues one or more errors, which are printed above."; \ + find . -name "*.class" -exec rm {} \; ; exit 1; } + +# clean up +find . -name "*.class" -exec rm {} \; + +cd ../.. || exit 2 +exit 0 \ No newline at end of file diff --git a/typecheck_test_outputs.sh b/typecheck_test_outputs.sh index a76958d5..410cdea2 100755 --- a/typecheck_test_outputs.sh +++ b/typecheck_test_outputs.sh @@ -1,7 +1,7 @@ #!/bin/sh # This script runs javac on all of the expected test outputs under src/test/resources. -# It returns 2 if any of them fail to compile, 1 if there are any malformed test directories, +# It returns 1 if any of them fail to compile, 2 if there are any malformed test directories, # and 0 if all of them do compile. # # It is desirable that all of the expected test outputs compile, because Specimin @@ -11,26 +11,18 @@ returnval=0 cd src/test/resources || exit 1 for testcase in * ; do - if [ "${testcase}" = "shared" ]; then continue; fi - # https://bugs.openjdk.org/browse/JDK-8319461 wasn't actually fixed (this test is based on that bug) - if [ "${testcase}" = "superinterfaceextends" ]; then continue; fi - # incomplete handling of method references: https://github.com/njit-jerse/specimin/issues/291 - # this test exists to check that no crash occurs, not that Specimin produces the correct output - if [ "${testcase}" = "methodref2" ]; then continue; fi - cd "${testcase}/expected/" || exit 1 - # javac relies on word splitting - # shellcheck disable=SC2046 - javac -classpath "../../shared/checker-qual-3.42.0.jar" $(find . -name "*.java") \ - || { echo "Running javac on ${testcase}/expected issues one or more errors, which are printed above."; returnval=2; } - cd ../.. || exit 1 + sh ../../../typecheck_one_test.sh "${testcase}" + # update overall return value + test_retval=$? + if [ ! "${test_retval}" = 0 ]; then + returnval=1 + fi done if [ "${returnval}" = 0 ]; then echo "All expected test outputs compiled successfully." -elif [ "${returnval}" = 2 ]; then +elif [ "${returnval}" = 1 ]; then echo "Some expected test outputs do not compile successfully. See the above error output for details." fi -find . -name "*.class" -exec rm {} \; - exit ${returnval}