diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2572b94..8c47878 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,10 @@ jobs: matrix: distribution: [ 'temurin' ] java: [ '21' ] - name: Java ${{ matrix.Java }} Build + # Run the unit tests against both the original validation engine and the new + # list-of-successes engine, in parallel. + grammarParseEngine: [ 'false', 'true' ] + name: Java ${{ matrix.java }} Build (grammar engine ${{ matrix.grammarParseEngine }}) steps: - name: Check out Git repository uses: actions/checkout@v7 @@ -46,10 +49,11 @@ jobs: mkdir -p ./build docker compose --project-directory ./systemd-build up --build ./generate-changelog > build/CHANGELOG - ./gradlew test buildPlugin + ./gradlew test buildPlugin -Dsystemd.unit.grammarParseEngine=${{ matrix.grammarParseEngine }} ./gradlew --stop - name: Publish Unit Test Results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: + check_name: "Unit Test Results (grammar engine ${{ matrix.grammarParseEngine }})" junit_files: build/test-results/**/*.xml diff --git a/build.gradle.kts b/build.gradle.kts index b43f36c..46ed417 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -144,6 +144,10 @@ tasks { test { testLogging.showExceptions = true testLogging.setExceptionFormat("full") + // Forward the grammar-engine switch to the forked test JVM so the suite can be run twice: + // ./gradlew test (original validation engine) + // ./gradlew test -Dsystemd.unit.grammarParseEngine=true (new list-of-successes engine) + systemProperty("systemd.unit.grammarParseEngine", System.getProperty("systemd.unit.grammarParseEngine", "false")) } } diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/GrammarOptionValue.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/GrammarOptionValue.kt index 33375ed..a8567bf 100644 --- a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/GrammarOptionValue.kt +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/GrammarOptionValue.kt @@ -37,7 +37,7 @@ open class GrammarOptionValue( override fun generateProblemDescriptors(property: UnitFilePropertyType, holder: ProblemsHolder) { val value = property.valueText ?: return - if (ExperimentalSettings.getInstance(property.project).state.useGrammarParseEngine) { + if (FORCE_PARSE_ENGINE || ExperimentalSettings.getInstance(property.project).state.useGrammarParseEngine) { generateProblemDescriptorsViaParse(property, value, holder) return } @@ -173,5 +173,15 @@ open class GrammarOptionValue( companion object { private val LOG = Logger.getInstance(SemanticDataRepository::class.java) + + /** + * Forces the new list-of-successes engine for validation regardless of the per-project setting, + * used to run the whole unit-test suite against it (CI runs the suite twice: once without and + * once with -Dsystemd.unit.grammarParseEngine=true). Only the validation engine is forced; the + * cosmetic annotators stay on the user flag, so problem counts are unchanged and only exact + * error spans/messages can differ between engines. + */ + @JvmField + val FORCE_PARSE_ENGINE: Boolean = java.lang.Boolean.getBoolean("systemd.unit.grammarParseEngine") } } diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/InvalidValueInspectionForCGroupSocketBind.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/InvalidValueInspectionForCGroupSocketBind.kt index 0701beb..042f530 100644 --- a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/InvalidValueInspectionForCGroupSocketBind.kt +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/InvalidValueInspectionForCGroupSocketBind.kt @@ -2,6 +2,7 @@ package net.sjrx.intellij.plugins.systemdunitfiles.inspections import junit.framework.TestCase import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.GrammarOptionValue class InvalidValueInspectionForCGroupSocketBindOptionValue : AbstractUnitFileTest() { @@ -133,7 +134,9 @@ class InvalidValueInspectionForCGroupSocketBindOptionValue : AbstractUnitFileTes assertSize(1, highlights) val info = highlights[0] assertStringContains("SocketBindAllow's value does not match the expected format.", info!!.description) - TestCase.assertEquals("::tcp", info.text) + // The two engines localize this differently: the original highlights from after "ipv6"; the + // list-of-successes engine consumes "ipv6:" before getting stuck, so it highlights from there. + TestCase.assertEquals(if (GrammarOptionValue.FORCE_PARSE_ENGINE) ":tcp" else "::tcp", info.text) } fun testWeakWarningWhenInvalidPortRangeSpecified() { @@ -154,6 +157,8 @@ class InvalidValueInspectionForCGroupSocketBindOptionValue : AbstractUnitFileTes assertSize(1, highlights) val info = highlights[0] assertStringContains("SocketBindAllow's value is correctly formatted but seems invalid.", info!!.description) - TestCase.assertEquals("-", info.text) + // The original engine gives up at the first "-"; the list-of-successes engine parses the whole + // range form and points at the out-of-range port "-21485". + TestCase.assertEquals(if (GrammarOptionValue.FORCE_PARSE_ENGINE) "-21485" else "-", info.text) } }