diff --git a/.github/workflows/cs-comparison.yml b/.github/workflows/cs-comparison.yml index f66589076..8b7883fb6 100644 --- a/.github/workflows/cs-comparison.yml +++ b/.github/workflows/cs-comparison.yml @@ -25,9 +25,7 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - # Run the comparison using the test classpath - - name: Build and run CS Comparison + - name: Build and run CS comparison run: | chmod +x ./mvnw - ./mvnw -B test-compile -DskipTests - ./mvnw -B exec:java -DskipTests -Dexec.mainClass=com.imsweb.staging.cs.CsIntegrationTest -Dexec.classpathScope=test + ./mvnw -B -Pcs-comparison verify diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index c3d002456..b99e60496 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -44,6 +44,13 @@ jobs: chmod +x ./mvnw ./mvnw -B verify + - name: Upload JaCoCo report + if: always() + uses: actions/upload-artifact@v4 + with: + name: jacoco-report + path: target/site/jacoco/ + - name: SonarCloud Analysis if: github.actor != 'dependabot[bot]' env: diff --git a/.gitignore b/.gitignore index a5edded5c..8b2a01285 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ HELP.md target/ !**/src/main/**/target/ !**/src/test/**/target/ +node_modules/ ### STS ### .apt_generated @@ -30,4 +31,5 @@ build/ ### VS Code ### .vscode/ - +package-lock.json +package.json diff --git a/pom.xml b/pom.xml index ece3c9ebb..fc0cd4b56 100644 --- a/pom.xml +++ b/pom.xml @@ -156,7 +156,7 @@ org.jacoco jacoco-maven-plugin - 0.8.12 + 0.8.15 prepare-agent @@ -171,6 +171,32 @@ report + + check + verify + + check + + + + + BUNDLE + + + LINE + COVEREDRATIO + 0.95 + + + BRANCH + COVEREDRATIO + 0.89 + + + + + + @@ -241,6 +267,64 @@ + + cs-comparison + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.6.1 + + + add-cs-comparison-test-source + generate-test-sources + + add-test-source + + + + src/cs-comparison/java + + + + + add-cs-comparison-test-resource + generate-test-resources + + add-test-resource + + + + + src/cs-comparison/resources + + + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.6.3 + + + run-cs-comparison + integration-test + + java + + + com.imsweb.staging.cs.CsComparisonRunner + test + + + + + + + release diff --git a/src/test/java/com/imsweb/staging/cs/CsIntegrationTest.java b/src/cs-comparison/java/com/imsweb/staging/cs/CsComparisonRunner.java similarity index 52% rename from src/test/java/com/imsweb/staging/cs/CsIntegrationTest.java rename to src/cs-comparison/java/com/imsweb/staging/cs/CsComparisonRunner.java index 988c7bc2e..809dc5fef 100644 --- a/src/test/java/com/imsweb/staging/cs/CsIntegrationTest.java +++ b/src/cs-comparison/java/com/imsweb/staging/cs/CsComparisonRunner.java @@ -3,6 +3,12 @@ */ package com.imsweb.staging.cs; +import static com.imsweb.staging.StagingTest.getAlgorithmPath; + +import com.imsweb.staging.ExternalStagingFileDataProvider; +import com.imsweb.staging.Staging; +import com.imsweb.staging.cs.IntegrationUtils.IntegrationResult; +import com.imsweb.staging.util.Stopwatch; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -15,21 +21,12 @@ import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.zip.GZIPInputStream; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.imsweb.staging.ExternalStagingFileDataProvider; -import com.imsweb.staging.Staging; -import com.imsweb.staging.cs.IntegrationUtils.IntegrationResult; -import com.imsweb.staging.util.Stopwatch; +public class CsComparisonRunner { -import static com.imsweb.staging.StagingTest.getAlgorithmPath; - -@SuppressWarnings("java:S2187") -public class CsIntegrationTest { - - private static final Logger _LOG = LoggerFactory.getLogger(CsIntegrationTest.class); + private static final Logger _LOG = LoggerFactory.getLogger(CsComparisonRunner.class); // set this to null to process all, or a list of schema filename to process private static final List _SCHEMA_FILES = Collections.emptyList(); @@ -43,8 +40,17 @@ private static void execute() throws IOException, InterruptedException, URISynta // only do schema selection test if running all schemas if (_SCHEMA_FILES.isEmpty()) { - IntegrationUtils.processSchemaSelection(staging, "cs_schema_identification.txt.gz", - new GZIPInputStream(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResourceAsStream("cs/integration/schema_selection/cs_schema_identification.txt.gz")))); + IntegrationUtils.processSchemaSelection( + staging, + "cs_schema_identification.txt.gz", + new GZIPInputStream( + Objects.requireNonNull( + Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream("cs/integration/schema_selection/cs_schema_identification.txt.gz") + ) + ) + ); _LOG.info("-----------------------------------------------"); } @@ -55,8 +61,18 @@ private static void execute() throws IOException, InterruptedException, URISynta // NOTE: some of these files are REALLY large; so they are not included in the project for now; all files larger than 2MB (40 of them) are not // part of the repository and can be found at \\omni\btp\csb\Staging\CS List schemaFiles; - try (BufferedReader buffer = new BufferedReader( - new InputStreamReader(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResourceAsStream("cs/integration/schemas/index.txt")), StandardCharsets.UTF_8))) { + try ( + BufferedReader buffer = new BufferedReader( + new InputStreamReader( + Objects.requireNonNull( + Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream("cs/integration/schemas/index.txt") + ), + StandardCharsets.UTF_8 + ) + ) + ) { schemaFiles = buffer.lines().toList(); } @@ -67,8 +83,17 @@ private static void execute() throws IOException, InterruptedException, URISynta for (String schemaFile : schemaFiles) { if (_SCHEMA_FILES.isEmpty() || _SCHEMA_FILES.contains(schemaFile)) { totalFiles += 1; - IntegrationResult result = IntegrationUtils.processSchema(staging, schemaFile, - new GZIPInputStream(Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResourceAsStream("cs/integration/schemas/" + schemaFile)))); + IntegrationResult result = IntegrationUtils.processSchema( + staging, + schemaFile, + new GZIPInputStream( + Objects.requireNonNull( + Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream("cs/integration/schemas/" + schemaFile) + ) + ) + ); totalCases += result.getNumCases(); totalFailures += result.getNumFailures(); } @@ -76,11 +101,27 @@ private static void execute() throws IOException, InterruptedException, URISynta stopwatch.stop(); - String perMs = String.format("%.3f", ((float)stopwatch.elapsed(TimeUnit.MILLISECONDS) / totalCases)); + String perMs = String.format("%.3f", (float) stopwatch.elapsed(TimeUnit.MILLISECONDS) / totalCases); _LOG.info(""); - _LOG.info("Completed {} cases ({} files) in {} ({}ms/case).", NumberFormat.getNumberInstance(Locale.US).format(totalCases), totalFiles, stopwatch, perMs); - if (totalFailures > 0) - _LOG.error("There were {} failing cases.", NumberFormat.getNumberInstance(Locale.US).format(totalFailures)); + _LOG.info( + "Completed {} cases ({} files) in {} ({}ms/case).", + NumberFormat.getNumberInstance(Locale.US).format(totalCases), + totalFiles, + stopwatch, + perMs + ); + if (totalFailures > 0) _LOG.error( + "There were {} failing cases.", + NumberFormat.getNumberInstance(Locale.US).format(totalFailures) + ); + failIfNecessary(totalFailures); } + static void failIfNecessary(long totalFailures) { + if (totalFailures > 0) throw new IllegalStateException( + "CS comparison failed with " + + NumberFormat.getNumberInstance(Locale.US).format(totalFailures) + + " failing cases." + ); + } } diff --git a/src/cs-comparison/java/com/imsweb/staging/cs/CsComparisonRunnerTest.java b/src/cs-comparison/java/com/imsweb/staging/cs/CsComparisonRunnerTest.java new file mode 100644 index 000000000..3bd0e66e5 --- /dev/null +++ b/src/cs-comparison/java/com/imsweb/staging/cs/CsComparisonRunnerTest.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2026 Information Management Services, Inc. + */ +package com.imsweb.staging.cs; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class CsComparisonRunnerTest { + + @Test + void testNoFailures() { + assertDoesNotThrow(() -> CsComparisonRunner.failIfNecessary(0)); + } + + @Test + void testFailures() { + IllegalStateException exception = assertThrows(IllegalStateException.class, () -> + CsComparisonRunner.failIfNecessary(1234) + ); + assertEquals("CS comparison failed with 1,234 failing cases.", exception.getMessage()); + } +} diff --git a/src/test/resources/cs/integration/schema_selection/cs_schema_identification.txt.gz b/src/cs-comparison/resources/cs/integration/schema_selection/cs_schema_identification.txt.gz similarity index 100% rename from src/test/resources/cs/integration/schema_selection/cs_schema_identification.txt.gz rename to src/cs-comparison/resources/cs/integration/schema_selection/cs_schema_identification.txt.gz diff --git a/src/test/resources/cs/integration/schemas/adnexa_uterine_other.gz b/src/cs-comparison/resources/cs/integration/schemas/adnexa_uterine_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/adnexa_uterine_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/adnexa_uterine_other.gz diff --git a/src/test/resources/cs/integration/schemas/adrenal_gland.gz b/src/cs-comparison/resources/cs/integration/schemas/adrenal_gland.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/adrenal_gland.gz rename to src/cs-comparison/resources/cs/integration/schemas/adrenal_gland.gz diff --git a/src/test/resources/cs/integration/schemas/ampulla_vater.gz b/src/cs-comparison/resources/cs/integration/schemas/ampulla_vater.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/ampulla_vater.gz rename to src/cs-comparison/resources/cs/integration/schemas/ampulla_vater.gz diff --git a/src/test/resources/cs/integration/schemas/anus.gz b/src/cs-comparison/resources/cs/integration/schemas/anus.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/anus.gz rename to src/cs-comparison/resources/cs/integration/schemas/anus.gz diff --git a/src/test/resources/cs/integration/schemas/bile_ducts_distal.gz b/src/cs-comparison/resources/cs/integration/schemas/bile_ducts_distal.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/bile_ducts_distal.gz rename to src/cs-comparison/resources/cs/integration/schemas/bile_ducts_distal.gz diff --git a/src/test/resources/cs/integration/schemas/bile_ducts_perihilar.gz b/src/cs-comparison/resources/cs/integration/schemas/bile_ducts_perihilar.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/bile_ducts_perihilar.gz rename to src/cs-comparison/resources/cs/integration/schemas/bile_ducts_perihilar.gz diff --git a/src/test/resources/cs/integration/schemas/biliary_other.gz b/src/cs-comparison/resources/cs/integration/schemas/biliary_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/biliary_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/biliary_other.gz diff --git a/src/test/resources/cs/integration/schemas/brain.gz b/src/cs-comparison/resources/cs/integration/schemas/brain.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/brain.gz rename to src/cs-comparison/resources/cs/integration/schemas/brain.gz diff --git a/src/test/resources/cs/integration/schemas/buccal_mucosa.gz b/src/cs-comparison/resources/cs/integration/schemas/buccal_mucosa.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/buccal_mucosa.gz rename to src/cs-comparison/resources/cs/integration/schemas/buccal_mucosa.gz diff --git a/src/test/resources/cs/integration/schemas/cervix.gz b/src/cs-comparison/resources/cs/integration/schemas/cervix.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/cervix.gz rename to src/cs-comparison/resources/cs/integration/schemas/cervix.gz diff --git a/src/test/resources/cs/integration/schemas/cns_other.gz b/src/cs-comparison/resources/cs/integration/schemas/cns_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/cns_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/cns_other.gz diff --git a/src/test/resources/cs/integration/schemas/conjunctiva.gz b/src/cs-comparison/resources/cs/integration/schemas/conjunctiva.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/conjunctiva.gz rename to src/cs-comparison/resources/cs/integration/schemas/conjunctiva.gz diff --git a/src/test/resources/cs/integration/schemas/corpus_adenosarcoma.gz b/src/cs-comparison/resources/cs/integration/schemas/corpus_adenosarcoma.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/corpus_adenosarcoma.gz rename to src/cs-comparison/resources/cs/integration/schemas/corpus_adenosarcoma.gz diff --git a/src/test/resources/cs/integration/schemas/cystic_duct.gz b/src/cs-comparison/resources/cs/integration/schemas/cystic_duct.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/cystic_duct.gz rename to src/cs-comparison/resources/cs/integration/schemas/cystic_duct.gz diff --git a/src/test/resources/cs/integration/schemas/digestive_other.gz b/src/cs-comparison/resources/cs/integration/schemas/digestive_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/digestive_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/digestive_other.gz diff --git a/src/test/resources/cs/integration/schemas/endocrine_other.gz b/src/cs-comparison/resources/cs/integration/schemas/endocrine_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/endocrine_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/endocrine_other.gz diff --git a/src/test/resources/cs/integration/schemas/epiglottis_anterior.gz b/src/cs-comparison/resources/cs/integration/schemas/epiglottis_anterior.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/epiglottis_anterior.gz rename to src/cs-comparison/resources/cs/integration/schemas/epiglottis_anterior.gz diff --git a/src/test/resources/cs/integration/schemas/eye_other.gz b/src/cs-comparison/resources/cs/integration/schemas/eye_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/eye_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/eye_other.gz diff --git a/src/test/resources/cs/integration/schemas/fallopian_tube.gz b/src/cs-comparison/resources/cs/integration/schemas/fallopian_tube.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/fallopian_tube.gz rename to src/cs-comparison/resources/cs/integration/schemas/fallopian_tube.gz diff --git a/src/test/resources/cs/integration/schemas/floor_mouth.gz b/src/cs-comparison/resources/cs/integration/schemas/floor_mouth.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/floor_mouth.gz rename to src/cs-comparison/resources/cs/integration/schemas/floor_mouth.gz diff --git a/src/test/resources/cs/integration/schemas/gallbladder.gz b/src/cs-comparison/resources/cs/integration/schemas/gallbladder.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gallbladder.gz rename to src/cs-comparison/resources/cs/integration/schemas/gallbladder.gz diff --git a/src/test/resources/cs/integration/schemas/genital_female_other.gz b/src/cs-comparison/resources/cs/integration/schemas/genital_female_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/genital_female_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/genital_female_other.gz diff --git a/src/test/resources/cs/integration/schemas/genital_male_other.gz b/src/cs-comparison/resources/cs/integration/schemas/genital_male_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/genital_male_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/genital_male_other.gz diff --git a/src/test/resources/cs/integration/schemas/gist_appendix.gz b/src/cs-comparison/resources/cs/integration/schemas/gist_appendix.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gist_appendix.gz rename to src/cs-comparison/resources/cs/integration/schemas/gist_appendix.gz diff --git a/src/test/resources/cs/integration/schemas/gist_colon.gz b/src/cs-comparison/resources/cs/integration/schemas/gist_colon.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gist_colon.gz rename to src/cs-comparison/resources/cs/integration/schemas/gist_colon.gz diff --git a/src/test/resources/cs/integration/schemas/gist_esophagus.gz b/src/cs-comparison/resources/cs/integration/schemas/gist_esophagus.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gist_esophagus.gz rename to src/cs-comparison/resources/cs/integration/schemas/gist_esophagus.gz diff --git a/src/test/resources/cs/integration/schemas/gist_peritoneum.gz b/src/cs-comparison/resources/cs/integration/schemas/gist_peritoneum.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gist_peritoneum.gz rename to src/cs-comparison/resources/cs/integration/schemas/gist_peritoneum.gz diff --git a/src/test/resources/cs/integration/schemas/gist_rectum.gz b/src/cs-comparison/resources/cs/integration/schemas/gist_rectum.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gist_rectum.gz rename to src/cs-comparison/resources/cs/integration/schemas/gist_rectum.gz diff --git a/src/test/resources/cs/integration/schemas/gist_small_intestine.gz b/src/cs-comparison/resources/cs/integration/schemas/gist_small_intestine.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gist_small_intestine.gz rename to src/cs-comparison/resources/cs/integration/schemas/gist_small_intestine.gz diff --git a/src/test/resources/cs/integration/schemas/gist_stomach.gz b/src/cs-comparison/resources/cs/integration/schemas/gist_stomach.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gist_stomach.gz rename to src/cs-comparison/resources/cs/integration/schemas/gist_stomach.gz diff --git a/src/test/resources/cs/integration/schemas/gum_lower.gz b/src/cs-comparison/resources/cs/integration/schemas/gum_lower.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gum_lower.gz rename to src/cs-comparison/resources/cs/integration/schemas/gum_lower.gz diff --git a/src/test/resources/cs/integration/schemas/gum_other.gz b/src/cs-comparison/resources/cs/integration/schemas/gum_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gum_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/gum_other.gz diff --git a/src/test/resources/cs/integration/schemas/gum_upper.gz b/src/cs-comparison/resources/cs/integration/schemas/gum_upper.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/gum_upper.gz rename to src/cs-comparison/resources/cs/integration/schemas/gum_upper.gz diff --git a/src/test/resources/cs/integration/schemas/heart_mediastinum.gz b/src/cs-comparison/resources/cs/integration/schemas/heart_mediastinum.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/heart_mediastinum.gz rename to src/cs-comparison/resources/cs/integration/schemas/heart_mediastinum.gz diff --git a/src/test/resources/cs/integration/schemas/hypopharynx.gz b/src/cs-comparison/resources/cs/integration/schemas/hypopharynx.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/hypopharynx.gz rename to src/cs-comparison/resources/cs/integration/schemas/hypopharynx.gz diff --git a/src/test/resources/cs/integration/schemas/ill_defined_other.gz b/src/cs-comparison/resources/cs/integration/schemas/ill_defined_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/ill_defined_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/ill_defined_other.gz diff --git a/src/test/resources/cs/integration/schemas/index.txt b/src/cs-comparison/resources/cs/integration/schemas/index.txt similarity index 100% rename from src/test/resources/cs/integration/schemas/index.txt rename to src/cs-comparison/resources/cs/integration/schemas/index.txt diff --git a/src/test/resources/cs/integration/schemas/intracranial_gland.gz b/src/cs-comparison/resources/cs/integration/schemas/intracranial_gland.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/intracranial_gland.gz rename to src/cs-comparison/resources/cs/integration/schemas/intracranial_gland.gz diff --git a/src/test/resources/cs/integration/schemas/kaposi_sarcoma.gz b/src/cs-comparison/resources/cs/integration/schemas/kaposi_sarcoma.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/kaposi_sarcoma.gz rename to src/cs-comparison/resources/cs/integration/schemas/kaposi_sarcoma.gz diff --git a/src/test/resources/cs/integration/schemas/kidney_parenchyma.gz b/src/cs-comparison/resources/cs/integration/schemas/kidney_parenchyma.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/kidney_parenchyma.gz rename to src/cs-comparison/resources/cs/integration/schemas/kidney_parenchyma.gz diff --git a/src/test/resources/cs/integration/schemas/kidney_renal_pelvis.gz b/src/cs-comparison/resources/cs/integration/schemas/kidney_renal_pelvis.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/kidney_renal_pelvis.gz rename to src/cs-comparison/resources/cs/integration/schemas/kidney_renal_pelvis.gz diff --git a/src/test/resources/cs/integration/schemas/lacrimal_gland.gz b/src/cs-comparison/resources/cs/integration/schemas/lacrimal_gland.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/lacrimal_gland.gz rename to src/cs-comparison/resources/cs/integration/schemas/lacrimal_gland.gz diff --git a/src/test/resources/cs/integration/schemas/lacrimal_sac.gz b/src/cs-comparison/resources/cs/integration/schemas/lacrimal_sac.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/lacrimal_sac.gz rename to src/cs-comparison/resources/cs/integration/schemas/lacrimal_sac.gz diff --git a/src/test/resources/cs/integration/schemas/larynx_glottic.gz b/src/cs-comparison/resources/cs/integration/schemas/larynx_glottic.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/larynx_glottic.gz rename to src/cs-comparison/resources/cs/integration/schemas/larynx_glottic.gz diff --git a/src/test/resources/cs/integration/schemas/larynx_other.gz b/src/cs-comparison/resources/cs/integration/schemas/larynx_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/larynx_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/larynx_other.gz diff --git a/src/test/resources/cs/integration/schemas/larynx_subglottic.gz b/src/cs-comparison/resources/cs/integration/schemas/larynx_subglottic.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/larynx_subglottic.gz rename to src/cs-comparison/resources/cs/integration/schemas/larynx_subglottic.gz diff --git a/src/test/resources/cs/integration/schemas/larynx_supraglottic.gz b/src/cs-comparison/resources/cs/integration/schemas/larynx_supraglottic.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/larynx_supraglottic.gz rename to src/cs-comparison/resources/cs/integration/schemas/larynx_supraglottic.gz diff --git a/src/test/resources/cs/integration/schemas/lip_lower.gz b/src/cs-comparison/resources/cs/integration/schemas/lip_lower.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/lip_lower.gz rename to src/cs-comparison/resources/cs/integration/schemas/lip_lower.gz diff --git a/src/test/resources/cs/integration/schemas/lip_other.gz b/src/cs-comparison/resources/cs/integration/schemas/lip_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/lip_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/lip_other.gz diff --git a/src/test/resources/cs/integration/schemas/lip_upper.gz b/src/cs-comparison/resources/cs/integration/schemas/lip_upper.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/lip_upper.gz rename to src/cs-comparison/resources/cs/integration/schemas/lip_upper.gz diff --git a/src/test/resources/cs/integration/schemas/liver.gz b/src/cs-comparison/resources/cs/integration/schemas/liver.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/liver.gz rename to src/cs-comparison/resources/cs/integration/schemas/liver.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_buccal_mucosa.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_buccal_mucosa.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_buccal_mucosa.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_buccal_mucosa.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_epiglottis_anterior.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_epiglottis_anterior.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_epiglottis_anterior.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_epiglottis_anterior.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_eye_other.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_eye_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_eye_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_eye_other.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_floor_mouth.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_floor_mouth.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_floor_mouth.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_floor_mouth.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_gum_lower.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_gum_lower.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_gum_lower.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_gum_lower.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_gum_other.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_gum_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_gum_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_gum_other.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_gum_upper.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_gum_upper.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_gum_upper.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_gum_upper.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_hypopharynx.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_hypopharynx.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_hypopharynx.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_hypopharynx.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_iris.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_iris.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_iris.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_iris.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_larynx_glottic.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_larynx_glottic.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_larynx_glottic.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_larynx_glottic.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_larynx_other.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_larynx_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_larynx_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_larynx_other.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_larynx_subglottic.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_larynx_subglottic.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_larynx_subglottic.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_larynx_subglottic.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_larynx_supraglottic.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_larynx_supraglottic.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_larynx_supraglottic.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_larynx_supraglottic.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_lip_lower.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_lip_lower.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_lip_lower.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_lip_lower.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_lip_other.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_lip_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_lip_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_lip_other.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_lip_upper.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_lip_upper.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_lip_upper.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_lip_upper.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_mouth_other.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_mouth_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_mouth_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_mouth_other.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_nasal_cavity.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_nasal_cavity.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_nasal_cavity.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_nasal_cavity.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_nasopharynx.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_nasopharynx.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_nasopharynx.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_nasopharynx.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_oropharynx.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_oropharynx.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_oropharynx.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_oropharynx.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_palate_hard.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_palate_hard.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_palate_hard.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_palate_hard.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_palate_soft.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_palate_soft.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_palate_soft.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_palate_soft.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_pharynx_other.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_pharynx_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_pharynx_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_pharynx_other.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_sinus_ethmoid.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_sinus_ethmoid.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_sinus_ethmoid.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_sinus_ethmoid.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_sinus_maxillary.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_sinus_maxillary.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_sinus_maxillary.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_sinus_maxillary.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_sinus_other.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_sinus_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_sinus_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_sinus_other.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_tongue_anterior.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_tongue_anterior.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_tongue_anterior.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_tongue_anterior.gz diff --git a/src/test/resources/cs/integration/schemas/melanoma_tongue_base.gz b/src/cs-comparison/resources/cs/integration/schemas/melanoma_tongue_base.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/melanoma_tongue_base.gz rename to src/cs-comparison/resources/cs/integration/schemas/melanoma_tongue_base.gz diff --git a/src/test/resources/cs/integration/schemas/middle_ear.gz b/src/cs-comparison/resources/cs/integration/schemas/middle_ear.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/middle_ear.gz rename to src/cs-comparison/resources/cs/integration/schemas/middle_ear.gz diff --git a/src/test/resources/cs/integration/schemas/mouth_other.gz b/src/cs-comparison/resources/cs/integration/schemas/mouth_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/mouth_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/mouth_other.gz diff --git a/src/test/resources/cs/integration/schemas/mycosis_fungoides.gz b/src/cs-comparison/resources/cs/integration/schemas/mycosis_fungoides.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/mycosis_fungoides.gz rename to src/cs-comparison/resources/cs/integration/schemas/mycosis_fungoides.gz diff --git a/src/test/resources/cs/integration/schemas/myeloma_plasma_cell_disorder.gz b/src/cs-comparison/resources/cs/integration/schemas/myeloma_plasma_cell_disorder.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/myeloma_plasma_cell_disorder.gz rename to src/cs-comparison/resources/cs/integration/schemas/myeloma_plasma_cell_disorder.gz diff --git a/src/test/resources/cs/integration/schemas/nasal_cavity.gz b/src/cs-comparison/resources/cs/integration/schemas/nasal_cavity.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/nasal_cavity.gz rename to src/cs-comparison/resources/cs/integration/schemas/nasal_cavity.gz diff --git a/src/test/resources/cs/integration/schemas/nasopharynx.gz b/src/cs-comparison/resources/cs/integration/schemas/nasopharynx.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/nasopharynx.gz rename to src/cs-comparison/resources/cs/integration/schemas/nasopharynx.gz diff --git a/src/test/resources/cs/integration/schemas/net_ampulla.gz b/src/cs-comparison/resources/cs/integration/schemas/net_ampulla.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/net_ampulla.gz rename to src/cs-comparison/resources/cs/integration/schemas/net_ampulla.gz diff --git a/src/test/resources/cs/integration/schemas/net_small_intestine.gz b/src/cs-comparison/resources/cs/integration/schemas/net_small_intestine.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/net_small_intestine.gz rename to src/cs-comparison/resources/cs/integration/schemas/net_small_intestine.gz diff --git a/src/test/resources/cs/integration/schemas/orbit.gz b/src/cs-comparison/resources/cs/integration/schemas/orbit.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/orbit.gz rename to src/cs-comparison/resources/cs/integration/schemas/orbit.gz diff --git a/src/test/resources/cs/integration/schemas/ovary.gz b/src/cs-comparison/resources/cs/integration/schemas/ovary.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/ovary.gz rename to src/cs-comparison/resources/cs/integration/schemas/ovary.gz diff --git a/src/test/resources/cs/integration/schemas/palate_hard.gz b/src/cs-comparison/resources/cs/integration/schemas/palate_hard.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/palate_hard.gz rename to src/cs-comparison/resources/cs/integration/schemas/palate_hard.gz diff --git a/src/test/resources/cs/integration/schemas/palate_soft.gz b/src/cs-comparison/resources/cs/integration/schemas/palate_soft.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/palate_soft.gz rename to src/cs-comparison/resources/cs/integration/schemas/palate_soft.gz diff --git a/src/test/resources/cs/integration/schemas/pancreas_body_tail.gz b/src/cs-comparison/resources/cs/integration/schemas/pancreas_body_tail.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/pancreas_body_tail.gz rename to src/cs-comparison/resources/cs/integration/schemas/pancreas_body_tail.gz diff --git a/src/test/resources/cs/integration/schemas/pancreas_head.gz b/src/cs-comparison/resources/cs/integration/schemas/pancreas_head.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/pancreas_head.gz rename to src/cs-comparison/resources/cs/integration/schemas/pancreas_head.gz diff --git a/src/test/resources/cs/integration/schemas/pancreas_other.gz b/src/cs-comparison/resources/cs/integration/schemas/pancreas_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/pancreas_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/pancreas_other.gz diff --git a/src/test/resources/cs/integration/schemas/parotid_gland.gz b/src/cs-comparison/resources/cs/integration/schemas/parotid_gland.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/parotid_gland.gz rename to src/cs-comparison/resources/cs/integration/schemas/parotid_gland.gz diff --git a/src/test/resources/cs/integration/schemas/penis.gz b/src/cs-comparison/resources/cs/integration/schemas/penis.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/penis.gz rename to src/cs-comparison/resources/cs/integration/schemas/penis.gz diff --git a/src/test/resources/cs/integration/schemas/peritoneum.gz b/src/cs-comparison/resources/cs/integration/schemas/peritoneum.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/peritoneum.gz rename to src/cs-comparison/resources/cs/integration/schemas/peritoneum.gz diff --git a/src/test/resources/cs/integration/schemas/pharyngeal_tonsil.gz b/src/cs-comparison/resources/cs/integration/schemas/pharyngeal_tonsil.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/pharyngeal_tonsil.gz rename to src/cs-comparison/resources/cs/integration/schemas/pharyngeal_tonsil.gz diff --git a/src/test/resources/cs/integration/schemas/pharynx_other.gz b/src/cs-comparison/resources/cs/integration/schemas/pharynx_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/pharynx_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/pharynx_other.gz diff --git a/src/test/resources/cs/integration/schemas/placenta.gz b/src/cs-comparison/resources/cs/integration/schemas/placenta.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/placenta.gz rename to src/cs-comparison/resources/cs/integration/schemas/placenta.gz diff --git a/src/test/resources/cs/integration/schemas/respiratory_other.gz b/src/cs-comparison/resources/cs/integration/schemas/respiratory_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/respiratory_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/respiratory_other.gz diff --git a/src/test/resources/cs/integration/schemas/retroperitoneum.gz b/src/cs-comparison/resources/cs/integration/schemas/retroperitoneum.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/retroperitoneum.gz rename to src/cs-comparison/resources/cs/integration/schemas/retroperitoneum.gz diff --git a/src/test/resources/cs/integration/schemas/salivary_gland_other.gz b/src/cs-comparison/resources/cs/integration/schemas/salivary_gland_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/salivary_gland_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/salivary_gland_other.gz diff --git a/src/test/resources/cs/integration/schemas/sinus_ethmoid.gz b/src/cs-comparison/resources/cs/integration/schemas/sinus_ethmoid.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/sinus_ethmoid.gz rename to src/cs-comparison/resources/cs/integration/schemas/sinus_ethmoid.gz diff --git a/src/test/resources/cs/integration/schemas/sinus_maxillary.gz b/src/cs-comparison/resources/cs/integration/schemas/sinus_maxillary.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/sinus_maxillary.gz rename to src/cs-comparison/resources/cs/integration/schemas/sinus_maxillary.gz diff --git a/src/test/resources/cs/integration/schemas/sinus_other.gz b/src/cs-comparison/resources/cs/integration/schemas/sinus_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/sinus_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/sinus_other.gz diff --git a/src/test/resources/cs/integration/schemas/submandibular_gland.gz b/src/cs-comparison/resources/cs/integration/schemas/submandibular_gland.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/submandibular_gland.gz rename to src/cs-comparison/resources/cs/integration/schemas/submandibular_gland.gz diff --git a/src/test/resources/cs/integration/schemas/tongue_anterior.gz b/src/cs-comparison/resources/cs/integration/schemas/tongue_anterior.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/tongue_anterior.gz rename to src/cs-comparison/resources/cs/integration/schemas/tongue_anterior.gz diff --git a/src/test/resources/cs/integration/schemas/tongue_base.gz b/src/cs-comparison/resources/cs/integration/schemas/tongue_base.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/tongue_base.gz rename to src/cs-comparison/resources/cs/integration/schemas/tongue_base.gz diff --git a/src/test/resources/cs/integration/schemas/trachea.gz b/src/cs-comparison/resources/cs/integration/schemas/trachea.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/trachea.gz rename to src/cs-comparison/resources/cs/integration/schemas/trachea.gz diff --git a/src/test/resources/cs/integration/schemas/urethra.gz b/src/cs-comparison/resources/cs/integration/schemas/urethra.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/urethra.gz rename to src/cs-comparison/resources/cs/integration/schemas/urethra.gz diff --git a/src/test/resources/cs/integration/schemas/urinary_other.gz b/src/cs-comparison/resources/cs/integration/schemas/urinary_other.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/urinary_other.gz rename to src/cs-comparison/resources/cs/integration/schemas/urinary_other.gz diff --git a/src/test/resources/cs/integration/schemas/vagina.gz b/src/cs-comparison/resources/cs/integration/schemas/vagina.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/vagina.gz rename to src/cs-comparison/resources/cs/integration/schemas/vagina.gz diff --git a/src/test/resources/cs/integration/schemas/vulva.gz b/src/cs-comparison/resources/cs/integration/schemas/vulva.gz similarity index 100% rename from src/test/resources/cs/integration/schemas/vulva.gz rename to src/cs-comparison/resources/cs/integration/schemas/vulva.gz diff --git a/src/test/java/com/imsweb/staging/AlgorithmStagingDataTest.java b/src/test/java/com/imsweb/staging/AlgorithmStagingDataTest.java new file mode 100644 index 000000000..2851bd4c6 --- /dev/null +++ b/src/test/java/com/imsweb/staging/AlgorithmStagingDataTest.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2026 Information Management Services, Inc. + */ +package com.imsweb.staging; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.ValueSource; + +import com.imsweb.staging.cs.CsStagingData; +import com.imsweb.staging.cs.CsStagingData.CsInput; +import com.imsweb.staging.cs.CsStagingData.CsOutput; +import com.imsweb.staging.cs.CsStagingData.CsStagingInputBuilder; +import com.imsweb.staging.eod.EodStagingData; +import com.imsweb.staging.eod.EodStagingData.EodInput; +import com.imsweb.staging.eod.EodStagingData.EodOutput; +import com.imsweb.staging.eod.EodStagingData.EodStagingInputBuilder; +import com.imsweb.staging.tnm.TnmStagingData; +import com.imsweb.staging.tnm.TnmStagingData.TnmInput; +import com.imsweb.staging.tnm.TnmStagingData.TnmOutput; +import com.imsweb.staging.tnm.TnmStagingData.TnmStagingInputBuilder; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class AlgorithmStagingDataTest { + + private static final String SITE = "C509"; + private static final String HISTOLOGY = "8000"; + + @Test + void testCsConstructors() { + CsStagingData empty = new CsStagingData(); + CsStagingData siteAndHistology = new CsStagingData(SITE, HISTOLOGY); + CsStagingData withSsf25 = new CsStagingData(SITE, HISTOLOGY, "025"); + + assertAll( + () -> assertTrue(empty.getInput().isEmpty()), + () -> assertSiteAndHistology(siteAndHistology), + () -> assertSiteAndHistology(withSsf25), + () -> assertEquals("025", withSsf25.getSsf(25))); + } + + @Test + void testTnmConstructors() { + TnmStagingData empty = new TnmStagingData(); + TnmStagingData siteAndHistology = new TnmStagingData(SITE, HISTOLOGY); + TnmStagingData withSsf25 = new TnmStagingData(SITE, HISTOLOGY, "025"); + + assertAll( + () -> assertTrue(empty.getInput().isEmpty()), + () -> assertSiteAndHistology(siteAndHistology), + () -> assertSiteAndHistology(withSsf25), + () -> assertEquals("025", withSsf25.getSsf(25))); + } + + @Test + void testEodConstructors() { + EodStagingData empty = new EodStagingData(); + EodStagingData siteAndHistology = new EodStagingData(SITE, HISTOLOGY); + EodStagingData withFirstDiscriminator = new EodStagingData(SITE, HISTOLOGY, "A"); + EodStagingData withBothDiscriminators = new EodStagingData(SITE, HISTOLOGY, "A", "B"); + + assertAll( + () -> assertTrue(empty.getInput().isEmpty()), + () -> assertSiteAndHistology(siteAndHistology), + () -> assertSiteAndHistology(withFirstDiscriminator), + () -> assertEquals("A", withFirstDiscriminator.getInput(EodInput.DISCRIMINATOR_1)), + () -> assertSiteAndHistology(withBothDiscriminators), + () -> assertEquals("A", withBothDiscriminators.getInput(EodInput.DISCRIMINATOR_1)), + () -> assertEquals("B", withBothDiscriminators.getInput(EodInput.DISCRIMINATOR_2))); + } + + @ParameterizedTest + @EnumSource(CsInput.class) + void testCsTypedInputAccess(CsInput key) { + CsStagingData data = new CsStagingData(); + + data.setInput(key, "value"); + + assertAll( + () -> assertEquals("value", data.getInput(key)), + () -> assertEquals("value", data.getInput(key.toString()))); + } + + @ParameterizedTest + @EnumSource(TnmInput.class) + void testTnmTypedInputAccess(TnmInput key) { + TnmStagingData data = new TnmStagingData(); + + data.setInput(key, "value"); + + assertAll( + () -> assertEquals("value", data.getInput(key)), + () -> assertEquals("value", data.getInput(key.toString()))); + } + + @ParameterizedTest + @EnumSource(EodInput.class) + void testEodTypedInputAccess(EodInput key) { + EodStagingData data = new EodStagingData(); + + data.setInput(key, "value"); + + assertAll( + () -> assertEquals("value", data.getInput(key)), + () -> assertEquals("value", data.getInput(key.toString()))); + } + + @ParameterizedTest + @EnumSource(CsOutput.class) + void testCsTypedOutputAccess(CsOutput key) { + CsStagingData data = new CsStagingData(); + data.getOutput().put(key.toString(), "value"); + + assertEquals("value", data.getOutput(key)); + } + + @ParameterizedTest + @EnumSource(TnmOutput.class) + void testTnmTypedOutputAccess(TnmOutput key) { + TnmStagingData data = new TnmStagingData(); + data.getOutput().put(key.toString(), "value"); + + assertEquals("value", data.getOutput(key)); + } + + @ParameterizedTest + @EnumSource(EodOutput.class) + void testEodTypedOutputAccess(EodOutput key) { + EodStagingData data = new EodStagingData(); + data.getOutput().put(key.toString(), "value"); + + assertEquals("value", data.getOutput(key)); + } + + @ParameterizedTest + @ValueSource(ints = {1, 25}) + void testCsSsfBoundaries(int index) { + CsStagingData data = new CsStagingData(); + + assertValidSsf(index, data::setSsf, data::getSsf); + } + + @ParameterizedTest + @ValueSource(ints = {1, 25}) + void testTnmSsfBoundaries(int index) { + TnmStagingData data = new TnmStagingData(); + + assertValidSsf(index, data::setSsf, data::getSsf); + } + + @ParameterizedTest + @ValueSource(ints = {-1, 0, 26, Integer.MAX_VALUE}) + void testCsRejectsInvalidSsfIndexes(int index) { + CsStagingData data = new CsStagingData(); + + assertInvalidSsf(index, data::setSsf, data::getSsf); + } + + @ParameterizedTest + @ValueSource(ints = {-1, 0, 26, Integer.MAX_VALUE}) + void testTnmRejectsInvalidSsfIndexes(int index) { + TnmStagingData data = new TnmStagingData(); + + assertInvalidSsf(index, data::setSsf, data::getSsf); + } + + @Test + void testCsBuilder() { + CsStagingData data = new CsStagingInputBuilder() + .withInput(CsInput.BEHAVIOR, "3") + .withSsf(1, "001") + .withSsf(25, "025") + .build(); + + assertAll( + () -> assertEquals("3", data.getInput(CsInput.BEHAVIOR)), + () -> assertEquals("001", data.getSsf(1)), + () -> assertEquals("025", data.getSsf(25))); + } + + @Test + void testTnmBuilder() { + TnmStagingData data = new TnmStagingInputBuilder() + .withInput(TnmInput.BEHAVIOR, "3") + .withSsf(1, "001") + .withSsf(25, "025") + .build(); + + assertAll( + () -> assertEquals("3", data.getInput(TnmInput.BEHAVIOR)), + () -> assertEquals("001", data.getSsf(1)), + () -> assertEquals("025", data.getSsf(25))); + } + + @Test + void testEodDiscriminatorBuilder() { + EodStagingData data = new EodStagingInputBuilder() + .withDisciminator1("A") + .withDisciminator2("B") + .withInput(EodInput.BEHAVIOR, "3") + .build(); + + assertAll( + () -> assertEquals("A", data.getInput(EodInput.DISCRIMINATOR_1)), + () -> assertEquals("B", data.getInput(EodInput.DISCRIMINATOR_2)), + () -> assertEquals("3", data.getInput(EodInput.BEHAVIOR))); + } + + private static void assertSiteAndHistology(com.imsweb.staging.entities.StagingData data) { + assertAll( + () -> assertEquals(SITE, data.getInput("site")), + () -> assertEquals(HISTOLOGY, data.getInput("hist"))); + } + + private static void assertValidSsf(int index, BiConsumer setter, Function getter) { + setter.accept(index, "value"); + + assertEquals("value", getter.apply(index)); + } + + private static void assertInvalidSsf(int index, BiConsumer setter, Function getter) { + assertAll( + () -> assertThrows(IllegalStateException.class, () -> setter.accept(index, "value")), + () -> assertThrows(IllegalStateException.class, () -> getter.apply(index))); + } +} diff --git a/src/test/java/com/imsweb/staging/ExternalStagingFileDataProviderTest.java b/src/test/java/com/imsweb/staging/ExternalStagingFileDataProviderTest.java index b2ee6fcdc..f9efa2140 100644 --- a/src/test/java/com/imsweb/staging/ExternalStagingFileDataProviderTest.java +++ b/src/test/java/com/imsweb/staging/ExternalStagingFileDataProviderTest.java @@ -1,23 +1,31 @@ package com.imsweb.staging; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; - +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; - class ExternalStagingFileDataProviderTest extends FileDataProviderTest { private static Staging _STAGING; @BeforeAll static void setup() throws IOException { - try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("external_algorithm.zip")) { + try ( + InputStream is = Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream("external_algorithm.zip") + ) { _STAGING = Staging.getInstance(is); } } @@ -62,8 +70,87 @@ void testConstructorWithString() throws IOException { void testInvalidPathThrowsException() { Path invalidPath = Paths.get("src/test/resources/missing.zip"); assertThatThrownBy(() -> new ExternalStagingFileDataProvider(invalidPath)) - .isInstanceOf(IOException.class) - .hasMessageContaining("missing.zip"); + .isInstanceOf(IOException.class) + .hasMessageContaining("missing.zip"); + } + + @Test + void testGlossaryFromInMemoryZip() throws IOException { + ExternalStagingFileDataProvider provider = provider( + "tables/site.json", + tableJson("site", "TESTING", "1.0"), + "glossary/cortex.json", + "{\"name\":\"Cortex\",\"definition\":\"Outer tissue\",\"alternate_names\":[\"Cortical\"]}" + ); + + assertThat(provider.getAlgorithm()).isEqualTo("testing"); + assertThat(provider.getGlossaryTerms()).containsExactly("Cortex"); + assertThat(provider.getGlossaryDefinition("Cortex").getDefinition()).isEqualTo("Outer tissue"); + assertThat(provider.getGlossaryDefinition("missing")).isNull(); + assertThat(provider.getGlossaryMatches("The cortex is present")).extracting("term").containsExactly("Cortex"); + assertThat(provider.getGlossaryMatches("Cortexlike")).isEmpty(); + } + + @Test + void testMalformedJsonIsRejected() throws IOException { + byte[] zip = zip("tables/broken.json", "{not-json"); + + assertThatThrownBy(() -> new ExternalStagingFileDataProvider(new ByteArrayInputStream(zip))).isInstanceOf( + IOException.class + ); } -} \ No newline at end of file + @Test + void testArchiveRequiresAlgorithmData() throws IOException { + byte[] zip = zip("notes/readme.txt", "ignored", "glossary/term.json", "{\"name\":\"Term\"}"); + + assertThatThrownBy(() -> new ExternalStagingFileDataProvider(new ByteArrayInputStream(zip))) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Error initializing provider; only a single algorithm should be included in file"); + } + + @Test + void testInconsistentAlgorithmsAndVersionsAreRejected() throws IOException { + byte[] algorithms = zip( + "tables/one.json", + tableJson("one", "FIRST", "1.0"), + "tables/two.json", + tableJson("two", "SECOND", "1.0") + ); + assertThatThrownBy(() -> new ExternalStagingFileDataProvider(new ByteArrayInputStream(algorithms))) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Error initializing provider; only a single algorithm should be included in file"); + + byte[] versions = zip( + "tables/one.json", + tableJson("one", "TEST", "1.0"), + "tables/two.json", + tableJson("two", "TEST", "2.0") + ); + assertThatThrownBy(() -> new ExternalStagingFileDataProvider(new ByteArrayInputStream(versions))) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Error initializing provider; only a single version should be included in file"); + } + + private static ExternalStagingFileDataProvider provider(String... entries) throws IOException { + return new ExternalStagingFileDataProvider(new ByteArrayInputStream(zip(entries))); + } + + private static byte[] zip(String... entries) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (ZipOutputStream zip = new ZipOutputStream(bytes)) { + for (int i = 0; i < entries.length; i += 2) { + zip.putNextEntry(new ZipEntry(entries[i])); + zip.write(entries[i + 1].getBytes(StandardCharsets.UTF_8)); + zip.closeEntry(); + } + } + return bytes.toByteArray(); + } + + private static String tableJson(String id, String algorithm, String version) { + return """ + {"id":"%s","algorithm":"%s","version":"%s","definition":[{"key":"value","type":"INPUT"}],"rows":[["1"]]} + """.formatted(id, algorithm, version); + } +} diff --git a/src/test/java/com/imsweb/staging/StagingDataProviderTest.java b/src/test/java/com/imsweb/staging/StagingDataProviderTest.java index 5fecac409..ea40f3e1c 100644 --- a/src/test/java/com/imsweb/staging/StagingDataProviderTest.java +++ b/src/test/java/com/imsweb/staging/StagingDataProviderTest.java @@ -1,23 +1,24 @@ package com.imsweb.staging; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.imsweb.staging.entities.ColumnDefinition.ColumnType; +import com.imsweb.staging.entities.Range; +import com.imsweb.staging.entities.impl.StagingColumnDefinition; +import com.imsweb.staging.entities.impl.StagingSchema; +import com.imsweb.staging.entities.impl.StagingTable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; - +import java.util.Set; import org.junit.jupiter.api.Test; -import com.imsweb.staging.entities.ColumnDefinition.ColumnType; -import com.imsweb.staging.entities.Range; -import com.imsweb.staging.entities.impl.StagingColumnDefinition; -import com.imsweb.staging.entities.impl.StagingTable; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - class StagingDataProviderTest { @Test @@ -138,7 +139,9 @@ void testSplitValues() { void testTableRowParsing() { StagingTable table = new StagingTable(); table.setId("test_table"); - table.setColumnDefinitions(Collections.singletonList(new StagingColumnDefinition("key1", "Input 1", ColumnType.INPUT))); + table.setColumnDefinitions( + Collections.singletonList(new StagingColumnDefinition("key1", "Input 1", ColumnType.INPUT)) + ); table.setRawRows(new ArrayList<>()); table.getRawRows().add(Collections.singletonList(",1,2,3")); table.getRawRows().add(Collections.singletonList("1,2,3,")); @@ -152,6 +155,107 @@ void testTableRowParsing() { assertEquals(4, table.getTableRows().get(1).getInputs().get("key1").size()); } + @Test + void testInMemoryProviderContract() { + InMemoryDataProvider provider = new InMemoryDataProvider("Test Algorithm", "1.2.3"); + + assertEquals("Test Algorithm", provider.getAlgorithm()); + assertEquals("1.2.3", provider.getVersion()); + assertTrue(provider.getTableIds().isEmpty()); + assertTrue(provider.getSchemaIds().isEmpty()); + assertNull(provider.getTable("missing")); + assertNull(provider.getSchema("missing")); + + StagingSchema schema = new StagingSchema("present"); + schema.setSchemaSelectionTable("selection"); + provider.addSchema(schema); + assertEquals(Set.of("present"), provider.getSchemaIds()); + assertEquals(schema, provider.getSchema("present")); + } + + @Test + void testInMemoryGlossaryIsUnsupported() { + InMemoryDataProvider provider = new InMemoryDataProvider("test", "1.0"); + + assertGlossaryUnsupported(provider::getGlossaryTerms); + assertGlossaryUnsupported(() -> provider.getGlossaryDefinition("term")); + assertGlossaryUnsupported(() -> provider.getGlossaryMatches("text")); + } + + private static void assertGlossaryUnsupported(Runnable operation) { + IllegalStateException exception = assertThrows(IllegalStateException.class, operation::run); + assertEquals("Glossary not supported in this provider", exception.getMessage()); + } + + @Test + void testValidValuesForMissingTable() { + StagingDataProvider provider = new InMemoryDataProvider("test", "1.0"); + + assertEquals(Collections.emptySet(), provider.getValidSites()); + } + + @Test + void testValidValuesRequireExactlyOneInputDefinition() { + InMemoryDataProvider noInputs = new InMemoryDataProvider("test", "1.0"); + noInputs.addTable( + table( + StagingDataProvider.PRIMARY_SITE_TABLE, + new StagingColumnDefinition("result", "Result", ColumnType.ENDPOINT) + ) + ); + + RuntimeException noInputException = assertThrows(RuntimeException.class, noInputs::getValidSites); + assertInvalidInputDefinition(noInputException); + + InMemoryDataProvider multipleInputs = new InMemoryDataProvider("test", "1.0"); + multipleInputs.addTable( + table( + StagingDataProvider.PRIMARY_SITE_TABLE, + new StagingColumnDefinition("site", "Site", ColumnType.INPUT), + new StagingColumnDefinition("other", "Other", ColumnType.INPUT) + ) + ); + + RuntimeException multipleInputException = assertThrows(RuntimeException.class, multipleInputs::getValidSites); + assertInvalidInputDefinition(multipleInputException); + } + + private static void assertInvalidInputDefinition(RuntimeException exception) { + assertTrue(exception.getCause() instanceof IllegalStateException); + assertEquals( + "Table 'primary_site' must have one and only one INPUT column.", + exception.getCause().getMessage() + ); + } + + @Test + void testValidValuesExpandRangesWithZeroPadding() { + InMemoryDataProvider provider = new InMemoryDataProvider("test", "1.0"); + StagingTable table = table( + StagingDataProvider.PRIMARY_SITE_TABLE, + new StagingColumnDefinition("site", "Site", ColumnType.INPUT) + ); + table.setRawRows( + Arrays.asList( + Collections.singletonList("001"), + Collections.singletonList("003-005"), + Collections.singletonList("010") + ) + ); + provider.addTable(table); + + assertEquals(Set.of("001", "003", "004", "005", "010"), provider.getValidSites()); + assertTrue(provider.isValidSite("004")); + assertFalse(provider.isValidSite("4")); + } + + private static StagingTable table(String id, StagingColumnDefinition... definitions) { + StagingTable table = new StagingTable(id); + table.setColumnDefinitions(Arrays.asList(definitions)); + table.setRawRows(Collections.emptyList()); + return table; + } + @Test void testPadStart() { assertNull(StagingDataProvider.padStart(null, 1, '0')); @@ -174,4 +278,4 @@ void testIsNumeric() { assertFalse(StagingDataProvider.isNumeric("1.1.1")); assertFalse(StagingDataProvider.isNumeric("NAN")); } -} \ No newline at end of file +} diff --git a/src/test/java/com/imsweb/staging/StagingInputsOutputsTest.java b/src/test/java/com/imsweb/staging/StagingInputsOutputsTest.java new file mode 100644 index 000000000..5aba1cf5f --- /dev/null +++ b/src/test/java/com/imsweb/staging/StagingInputsOutputsTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2026 Information Management Services, Inc. + */ +package com.imsweb.staging; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.imsweb.staging.entities.ColumnDefinition.ColumnType; +import com.imsweb.staging.entities.impl.StagingColumnDefinition; +import com.imsweb.staging.entities.impl.StagingMapping; +import com.imsweb.staging.entities.impl.StagingSchema; +import com.imsweb.staging.entities.impl.StagingSchemaOutput; +import com.imsweb.staging.entities.impl.StagingTable; +import com.imsweb.staging.entities.impl.StagingTablePath; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class StagingInputsOutputsTest { + + private InMemoryDataProvider _provider; + private Staging _staging; + private StagingTablePath _mainPath; + private StagingMapping _mapping; + + @BeforeEach + void setUp() { + _provider = new InMemoryDataProvider("test", "1.0"); + _provider.addTable( + table( + "selection", + List.of( + new StagingColumnDefinition("selector", "Selector", ColumnType.INPUT), + new StagingColumnDefinition(Staging.CTX_YEAR_CURRENT, "Current year", ColumnType.INPUT) + ), + List.of("*", "*") + ) + ); + _provider.addTable( + table( + "inclusion", + Collections.singletonList(new StagingColumnDefinition("include_flag", "Include", ColumnType.INPUT)), + Collections.singletonList("Y") + ) + ); + _provider.addTable( + table( + "exclusion", + Collections.singletonList(new StagingColumnDefinition("exclude_flag", "Exclude", ColumnType.INPUT)), + Collections.singletonList("Y") + ) + ); + _provider.addTable( + table( + "main", + List.of( + new StagingColumnDefinition("raw_input", "Raw input", ColumnType.INPUT), + new StagingColumnDefinition(Staging.CTX_ALGORITHM_VERSION, "Algorithm version", ColumnType.INPUT), + new StagingColumnDefinition(Staging.CTX_YEAR_CURRENT, "Current year", ColumnType.INPUT), + new StagingColumnDefinition("raw_output", "Raw output", ColumnType.ENDPOINT) + ), + List.of("*", "*", "*", "VALUE:result") + ) + ); + + _mainPath = new StagingTablePath("main"); + _mainPath.addInputMapping("case_input", "raw_input"); + _mainPath.addOutputMapping("raw_output", "mapped_output"); + + _mapping = new StagingMapping("conditional", Collections.singletonList(_mainPath)); + _mapping.setInclusionTables(Collections.singletonList(new StagingTablePath("inclusion"))); + _mapping.setExclusionTables(Collections.singletonList(new StagingTablePath("exclusion"))); + + _staging = Staging.getInstance(_provider); + } + + @Test + void getsMappedTablePathInputsAndOutputs() { + assertThat(_staging.getInputs(_mainPath)).containsExactly("case_input"); + assertThat(_staging.getInputs(_mainPath, new HashSet<>(Set.of("case_input")))).isEmpty(); + assertThat(_staging.getInputs((StagingTablePath) null)).isEmpty(); + + assertThat(_staging.getOutputs(_mainPath)).containsExactly("mapped_output"); + } + + @Test + void getsMappingInputsAndOutputsWithExclusionsAndContext() { + Map included = Map.of("include_flag", "Y", "exclude_flag", "N"); + Map notIncluded = Map.of("include_flag", "N", "exclude_flag", "N"); + Map excluded = Map.of("include_flag", "Y", "exclude_flag", "Y"); + + assertThat(_staging.getInputs(_mapping)).containsExactlyInAnyOrder( + "include_flag", + "exclude_flag", + "case_input" + ); + assertThat(_staging.getInputs(_mapping, included, new HashSet<>())).containsExactlyInAnyOrder( + "include_flag", + "exclude_flag", + "case_input" + ); + assertThat(_staging.getInputs(_mapping, notIncluded, new HashSet<>())).containsExactlyInAnyOrder( + "include_flag", + "exclude_flag" + ); + assertThat(_staging.getInputs(_mapping, excluded, new HashSet<>(Set.of("include_flag")))).containsExactly( + "exclude_flag" + ); + + assertThat(_staging.getOutputs(_mapping)).containsExactly("mapped_output"); + assertThat(_staging.getOutputs(_mapping, included)).containsExactly("mapped_output"); + assertThat(_staging.getOutputs(_mapping, notIncluded)).isEmpty(); + assertThat(_staging.getOutputs(_mapping, excluded)).isEmpty(); + } + + @Test + void getsSchemaInputsAndExplicitOrInferredOutputs() { + Map excluded = Map.of("include_flag", "Y", "exclude_flag", "Y"); + + StagingSchema inferred = schema("inferred", _mapping); + _provider.addSchema(inferred); + inferred.setOutputMap(null); + + assertThat(_staging.getInputs(inferred)).containsExactlyInAnyOrder( + "selector", + "include_flag", + "exclude_flag", + "case_input" + ); + assertThat(_staging.getInputs(inferred, excluded)).containsExactlyInAnyOrder( + "selector", + "include_flag", + "exclude_flag" + ); + assertThat(_staging.getOutputs(inferred)).containsExactly("mapped_output"); + assertThat(_staging.getOutputs(inferred, excluded)).isEmpty(); + + StagingSchema explicit = schema("explicit", _mapping); + explicit.setOutputs( + Arrays.asList( + new StagingSchemaOutput("declared_one", "Declared one"), + new StagingSchemaOutput("declared_two", "Declared two") + ) + ); + _provider.addSchema(explicit); + + assertThat(_staging.getOutputs(explicit)).containsExactlyInAnyOrder("declared_one", "declared_two"); + assertThat(_staging.getOutputs(explicit, excluded)).containsExactlyInAnyOrder("declared_one", "declared_two"); + } + + private StagingSchema schema(String id, StagingMapping mapping) { + StagingSchema schema = new StagingSchema(id); + schema.setSchemaSelectionTable("selection"); + schema.setMappings(Collections.singletonList(mapping)); + return schema; + } + + private StagingTable table(String id, List definitions, List row) { + StagingTable table = new StagingTable(id); + table.setColumnDefinitions(definitions); + table.setRawRows(Collections.singletonList(row)); + return table; + } +} diff --git a/src/test/java/com/imsweb/staging/engine/DecisionEngineTest.java b/src/test/java/com/imsweb/staging/engine/DecisionEngineTest.java index dbb270861..64506300b 100644 --- a/src/test/java/com/imsweb/staging/engine/DecisionEngineTest.java +++ b/src/test/java/com/imsweb/staging/engine/DecisionEngineTest.java @@ -4,18 +4,15 @@ */ package com.imsweb.staging.engine; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import static com.imsweb.staging.engine.DecisionEngine.BLANK_OUTPUT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.imsweb.staging.InMemoryDataProvider; import com.imsweb.staging.entities.ColumnDefinition.ColumnType; @@ -38,16 +35,17 @@ import com.imsweb.staging.entities.impl.StagingSchemaOutput; import com.imsweb.staging.entities.impl.StagingTable; import com.imsweb.staging.entities.impl.StagingTablePath; - -import static com.imsweb.staging.engine.DecisionEngine.BLANK_OUTPUT; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * Test class for DecisionEngine @@ -242,7 +240,9 @@ static void init() { schema.addInput("c"); schema.addInitialContext("d", "HARD-CODE"); StagingMapping mapping = new StagingMapping("m1"); - mapping.setTablePaths(Arrays.asList(new StagingTablePath("table_sample_first"), new StagingTablePath("table_sample_second"))); + mapping.setTablePaths( + Arrays.asList(new StagingTablePath("table_sample_first"), new StagingTablePath("table_sample_second")) + ); schema.addMapping(mapping); provider.addSchema(schema); @@ -256,7 +256,9 @@ static void init() { schema.addInput("a"); schema.addInput("b"); schema.addInput("c"); - schema.addMapping(new StagingMapping("m1", Collections.singletonList(new StagingTablePath("table_multiple_inputs")))); + schema.addMapping( + new StagingMapping("m1", Collections.singletonList(new StagingTablePath("table_multiple_inputs"))) + ); provider.addSchema(schema); schema = new StagingSchema("starting_recursion"); @@ -404,8 +406,8 @@ void testMatchTable() { input.put("size", "003"); assertThat(DecisionEngine.matchTable(matchTable, input)) - .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) - .containsExactly(tuple(EndpointType.JUMP, "some_crazy_table", "size_result")); + .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) + .containsExactly(tuple(EndpointType.JUMP, "some_crazy_table", "size_result")); input.put("size", "014"); List results = DecisionEngine.matchTable(matchTable, input); @@ -416,8 +418,8 @@ void testMatchTable() { input.put("size", "086"); assertThat(DecisionEngine.matchTable(matchTable, input)) - .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) - .containsExactly(tuple(EndpointType.ERROR, "Get that huge stuff out of here!", "size_result")); + .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) + .containsExactly(tuple(EndpointType.ERROR, "Get that huge stuff out of here!", "size_result")); // try with a value not in the table input.put("size", "021"); @@ -497,30 +499,30 @@ void testMatchOnSpecificKeys() { // specify to only match on key1, there should be a match to the first line assertThat(DecisionEngine.matchTable(matchTable, input, new HashSet<>(Collections.singletonList("key1")))) - .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) - .containsExactly(tuple(EndpointType.MATCH, "LINE1", "result")); + .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) + .containsExactly(tuple(EndpointType.MATCH, "LINE1", "result")); // add key2 to the input map and there should be a match input.put("key2", "7"); assertThat(DecisionEngine.matchTable(matchTable, input)) - .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) - .containsExactly(tuple(EndpointType.MATCH, "LINE2", "result")); + .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) + .containsExactly(tuple(EndpointType.MATCH, "LINE2", "result")); // if searching on key1 only, even though key2 was supplied should still match to first line assertThat(DecisionEngine.matchTable(matchTable, input, new HashSet<>(Collections.singletonList("key1")))) - .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) - .containsExactly(tuple(EndpointType.MATCH, "LINE1", "result")); + .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) + .containsExactly(tuple(EndpointType.MATCH, "LINE1", "result")); // supply an empty set of keys (the same meaning as not passing any keys assertThat(DecisionEngine.matchTable(matchTable, input, new HashSet<>())) - .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) - .containsExactly(tuple(EndpointType.MATCH, "LINE1", "result")); + .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) + .containsExactly(tuple(EndpointType.MATCH, "LINE1", "result")); // supply an invalid key. I think this should find nothing, but for the moment finds a match to the first row since none of the cells were // compared to. It is the same as matching to a table with no INPUTS which would currently find a match to the first row. assertThat(DecisionEngine.matchTable(matchTable, input, new HashSet<>(Collections.singletonList("bad_key")))) - .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) - .containsExactly(tuple(EndpointType.MATCH, "LINE1", "result")); + .extracting(Endpoint::getType, Endpoint::getValue, Endpoint::getResultKey) + .containsExactly(tuple(EndpointType.MATCH, "LINE1", "result")); } @Test @@ -537,6 +539,10 @@ void testMatchTableWithNoRows() { input.put("a", ""); List endpoints = DecisionEngine.matchTable(tableMissing, input); assertNull(endpoints); + + // A malformed table with no parsed row collection also has no match. + ((StagingTable) tableMissing).setTableRows(null); + assertNull(DecisionEngine.matchTable(tableMissing, input)); } @Test @@ -584,7 +590,9 @@ void testValueKeyReferences() { schema.setSchemaSelectionTable("table_selection"); schema.addInput("a"); schema.addInput("b"); - schema.addMapping(new StagingMapping("m1", Collections.singletonList(new StagingTablePath("table_key_references")))); + schema.addMapping( + new StagingMapping("m1", Collections.singletonList(new StagingTablePath("table_key_references"))) + ); provider.addSchema(schema); DecisionEngine engine = new DecisionEngine(provider); @@ -809,7 +817,7 @@ void testMissingParameters() { void testParameterLookupValidation() { Map input = new HashMap<>(); input.put("a", "3"); - input.put("b", "31"); // value is not in lookup table + input.put("b", "31"); // value is not in lookup table Result result = _ENGINE.process("starting_sample", input); @@ -836,7 +844,7 @@ void testParameterLookupValidation() { void testSingleTableProcess() { Map input = new HashMap<>(); input.put("a", "7"); - input.put("b", "03"); // should map to "hemeretic" without using second table + input.put("b", "03"); // should map to "hemeretic" without using second table input.put("e", "X"); Result result = _ENGINE.process("starting_sample", input); @@ -917,7 +925,10 @@ void testProcessError() { result = _ENGINE.process("starting_sample", input); assertEquals(1, result.getErrors().size()); assertEquals(2, result.getPath().size()); - assertEquals("Matching resulted in an error in table 'table_sample_first' for column 'result' (8,99)", result.getErrors().getFirst().getMessage()); + assertEquals( + "Matching resulted in an error in table 'table_sample_first' for column 'result' (8,99)", + result.getErrors().getFirst().getMessage() + ); assertNull(result.getErrors().getFirst().getKey()); assertEquals("table_sample_first", result.getErrors().getFirst().getTable()); assertEquals(Collections.singletonList("result"), result.getErrors().getFirst().getColumns()); @@ -933,6 +944,7 @@ void testProcessWithNullValues() { table.addRawRow("1", "VALUE:FOUND1"); table.addRawRow("2", "VALUE"); table.addRawRow("3", "VALUE:"); + table.addRawRow("4", "ERROR"); table.addRawRow("*", "MATCH"); provider.addTable(table); @@ -942,7 +954,9 @@ void testProcessWithNullValues() { inputKey.setDefault("0"); schema.addInput(inputKey); schema.addInitialContext("result", "0"); - schema.addMapping(new StagingMapping("m1", Collections.singletonList(new StagingTablePath("table_null_values")))); + StagingTablePath nullValuePath = new StagingTablePath("table_null_values"); + nullValuePath.addOutputMapping("other", "mapped"); + schema.addMapping(new StagingMapping("m1", Collections.singletonList(nullValuePath))); provider.addSchema(schema); DecisionEngine engine = new DecisionEngine(provider); @@ -952,6 +966,12 @@ void testProcessWithNullValues() { assertFalse(result.hasErrors()); assertEquals("0", input.get("result")); + input.clear(); + input.put("a", null); + result = engine.process("starting_null_values", input); + assertFalse(result.hasErrors()); + assertEquals("0", input.get("result")); + input.clear(); input.put("a", "1"); result = engine.process("starting_null_values", input); @@ -969,6 +989,20 @@ void testProcessWithNullValues() { result = engine.process("starting_null_values", input); assertFalse(result.hasErrors()); assertEquals("", input.get("result")); + + input.clear(); + input.put("a", "4"); + result = engine.process("starting_null_values", input); + assertThat(result.getErrors()) + .extracting(Error::getType, Error::getMessage, Error::getTable, Error::getColumns) + .containsExactly( + tuple( + Error.Type.STAGING_ERROR, + "Matching resulted in an error in table 'table_null_values' for column 'result' (4)", + "table_null_values", + Collections.singletonList("result") + ) + ); } @Test @@ -1028,7 +1062,12 @@ void testStopIsNotOverwrittenByLaterJump() { StagingSchema schema = new StagingSchema("stop_then_jump"); schema.setSchemaSelectionTable("table_stop_then_jump"); schema.addInput("input"); - schema.addMapping(new StagingMapping("m1", Arrays.asList(new StagingTablePath("table_stop_then_jump"), new StagingTablePath("table_after_stop")))); + schema.addMapping( + new StagingMapping( + "m1", + Arrays.asList(new StagingTablePath("table_stop_then_jump"), new StagingTablePath("table_after_stop")) + ) + ); provider.addSchema(schema); Map context = new HashMap<>(); @@ -1393,6 +1432,10 @@ void testMappedInclusionsAndExclusionsAndMissingTables() { context.put("source", "B"); assertTrue(engine.isMappingInvolved(exclusion, context)); + context.clear(); + assertFalse(engine.isMappingInvolved(inclusion, context)); + assertTrue(engine.isMappingInvolved(exclusion, context)); + assertThrows(IllegalStateException.class, () -> engine.isMappingInvolved(inclusion, null)); StagingSchema schema = new StagingSchema("schema"); assertThrows(IllegalStateException.class, () -> engine.getInvolvedMappings(schema, null)); @@ -1406,12 +1449,20 @@ void testMappedInclusionsAndExclusionsAndMissingTables() { @Test void testMissingSchemaAndTableReferences() { InMemoryDataProvider provider = new InMemoryDataProvider("Test", "1.0"); + StagingTable table = new StagingTable("null_output_key"); + table.addColumnDefinition(null, ColumnType.ENDPOINT); + provider.addTable(table); DecisionEngine engine = new DecisionEngine(provider); assertThrows(IllegalStateException.class, () -> engine.process("missing", new HashMap<>())); assertThrows(IllegalStateException.class, () -> engine.getInvolvedTables("missing")); assertTrue(engine.getInputs(new StagingTablePath("missing")).isEmpty()); assertTrue(engine.getOutputs(new StagingTablePath("missing")).isEmpty()); + assertTrue(engine.getInputs((StagingTablePath) null).isEmpty()); + assertTrue(engine.getOutputs((StagingTablePath) null).isEmpty()); + assertTrue(engine.getInputs(new StagingMapping("empty"), new HashSet<>()).isEmpty()); + assertTrue(engine.getOutputs(new StagingMapping("empty")).isEmpty()); + assertTrue(engine.getOutputs(new StagingTablePath("null_output_key")).isEmpty()); StagingTablePath path = new StagingTablePath("starting_table"); Result result = new Result(new HashMap<>()); @@ -1445,7 +1496,10 @@ void testSchemaInputs() { assertEquals(asSet("a", "b", "c"), _ENGINE.getInputs(provider.getSchema("starting_inclusions"))); assertEquals(asSet("a"), _ENGINE.getInputs(provider.getSchema("starting_recursion"))); assertEquals(asSet("a", "b", "c"), _ENGINE.getInputs(provider.getSchema("starting_multiple_endpoints"))); - assertEquals(asSet("b", "not_in_input_list"), _ENGINE.getInputs(provider.getSchema("starting_inclusions_extra_inputs"))); + assertEquals( + asSet("b", "not_in_input_list"), + _ENGINE.getInputs(provider.getSchema("starting_inclusions_extra_inputs")) + ); assertEquals(asSet("main_input"), _ENGINE.getInputs(provider.getSchema("starting_intermediate_values"))); } @@ -1457,9 +1511,18 @@ void testGetSchemaOutputs() { assertEquals(asSet("result", "shared_result"), _ENGINE.getOutputs(provider.getSchema("starting_sample"))); assertEquals(asSet("result", "special"), _ENGINE.getOutputs(provider.getSchema("starting_inclusions"))); assertEquals(asSet("result"), _ENGINE.getOutputs(provider.getSchema("starting_recursion"))); - assertEquals(asSet("result", "r1", "r2", "r3"), _ENGINE.getOutputs(provider.getSchema("starting_multiple_endpoints"))); - assertEquals(asSet("mapped_result"), _ENGINE.getOutputs(provider.getSchema("starting_inclusions_extra_inputs"))); - assertEquals(asSet("intermediate_output", "final_output"), _ENGINE.getOutputs(provider.getSchema("starting_intermediate_values"))); + assertEquals( + asSet("result", "r1", "r2", "r3"), + _ENGINE.getOutputs(provider.getSchema("starting_multiple_endpoints")) + ); + assertEquals( + asSet("mapped_result"), + _ENGINE.getOutputs(provider.getSchema("starting_inclusions_extra_inputs")) + ); + assertEquals( + asSet("intermediate_output", "final_output"), + _ENGINE.getOutputs(provider.getSchema("starting_intermediate_values")) + ); } @Test @@ -1617,6 +1680,15 @@ void testDefaultInputValidation() { schema.addInput(input); provider.addSchema(schema); + schema = new StagingSchema("invalid_required_continue"); + schema.setSchemaSelectionTable("valid_inputs"); + schema.setOnInvalidInput(Schema.StagingInputErrorHandler.CONTINUE); + input = new StagingSchemaInput("input", "input", "valid_inputs"); + input.setDefault("X"); + input.setUsedForStaging(true); + schema.addInput(input); + provider.addSchema(schema); + schema = new StagingSchema("invalid_non_required_default"); schema.setSchemaSelectionTable("valid_inputs"); schema.setOnInvalidInput(Schema.StagingInputErrorHandler.FAIL_WHEN_USED_FOR_STAGING); @@ -1650,6 +1722,10 @@ void testDefaultInputValidation() { assertEquals(Type.FAILED_INPUT, result.getType()); assertEquals(Error.Type.INVALID_REQUIRED_INPUT, result.getErrors().getFirst().getType()); + result = engine.process("invalid_required_continue", new HashMap<>()); + assertEquals(Type.STAGED, result.getType()); + assertEquals(Error.Type.INVALID_REQUIRED_INPUT, result.getErrors().getFirst().getType()); + result = engine.process("invalid_non_required_default", new HashMap<>()); assertEquals(Type.STAGED, result.getType()); assertEquals(Error.Type.INVALID_NON_REQUIRED_INPUT, result.getErrors().getFirst().getType()); @@ -1660,6 +1736,27 @@ void testDefaultInputValidation() { assertEquals("X", result.getContext().get("input")); } + @Test + void testDefaultTableMatchWithoutRequestedValue() { + InMemoryDataProvider provider = new InMemoryDataProvider("Test", "1.0"); + StagingTable table = new StagingTable("malformed_default"); + table.addColumnDefinition("selector", ColumnType.INPUT); + table.addColumnDefinition("other", ColumnType.ENDPOINT); + table.addRawRow("*", "VALUE:fallback"); + provider.addTable(table); + + StagingSchemaInput input = new StagingSchemaInput("requested"); + input.setDefaultTable("malformed_default"); + Result result = new Result(new HashMap<>()); + + assertEquals("", new DecisionEngine(provider).getDefault(input, result.getContext(), result)); + assertThat(result.getErrors()) + .extracting(Error::getType, Error::getKey, Error::getMessage) + .containsExactly( + tuple(Error.Type.MATCH_NOT_FOUND, "requested", "Default table malformed_default did not find a match") + ); + } + @Test void testProcessingReferenceErrorsAndMappingInitialContext() { InMemoryDataProvider provider = new InMemoryDataProvider("Test", "1.0"); @@ -1817,6 +1914,7 @@ void testMappingInputsWithReferenceInTable() { table.addRawRow("001", "VALUE:000"); table.addRawRow("002", "VALUE:{{input1}}"); provider.addTable(table); + table.setExtraInput(new HashSet<>(Arrays.asList("input1", "unmapped", "output1"))); StagingSchema schema = new StagingSchema("sample_outputs"); schema.setSchemaSelectionTable("table_selection"); @@ -1832,7 +1930,17 @@ void testMappingInputsWithReferenceInTable() { DecisionEngine engine = new DecisionEngine(provider); - assertEquals(new HashSet<>(Collections.singletonList("remapped1")), engine.getInputs(schema.getMappings().getFirst().getTablePaths().getFirst())); + assertEquals( + new HashSet<>(Arrays.asList("remapped1", "unmapped")), + engine.getInputs(schema.getMappings().getFirst().getTablePaths().getFirst()) + ); + + StagingTable sharedKeyTable = new StagingTable("shared_input_output"); + sharedKeyTable.addColumnDefinition("shared", ColumnType.INPUT); + sharedKeyTable.addColumnDefinition("shared", ColumnType.ENDPOINT); + provider.addTable(sharedKeyTable); + + assertEquals(Collections.singleton("shared"), engine.getInputs(new StagingTablePath("shared_input_output"))); } @Test @@ -1891,7 +1999,12 @@ void testDefaultTable() { // first, verify getInvolvedTables is working with default tables Set tables = engine.getInvolvedTables("test_default_table"); - assertThat(tables).containsExactlyInAnyOrder("table_input1", "table_input2", "table_input2_default", "table_mapping"); + assertThat(tables).containsExactlyInAnyOrder( + "table_input1", + "table_input2", + "table_input2_default", + "table_mapping" + ); // test a case where the default_table make a successful lookup Map context = new HashMap<>(); @@ -1928,7 +2041,11 @@ void testDefaultTable() { assertFalse(result1.hasErrors()); // test a case where the default_table did not exist - schema.getInputs().stream().filter(i -> i.getDefaultTable() != null).forEach(i -> i.setDefaultTable("does_not_exist")); + schema + .getInputs() + .stream() + .filter(i -> i.getDefaultTable() != null) + .forEach(i -> i.setDefaultTable("does_not_exist")); context = new HashMap<>(); context.put("input1", "000"); result = engine.process("test_default_table", context); @@ -1947,7 +2064,11 @@ void testDefaultTable() { assertEquals("Default table does not exist: does_not_exist", result1.getErrors().getFirst().getMessage()); // test a case where the default table did not find a match - schema.getInputs().stream().filter(i -> i.getDefaultTable() != null).forEach(i -> i.setDefaultTable("table_input2_default")); + schema + .getInputs() + .stream() + .filter(i -> i.getDefaultTable() != null) + .forEach(i -> i.setDefaultTable("table_input2_default")); provider.getTable("table_input2_default").setRawRows(new ArrayList<>()); provider.initTable(provider.getTable("table_input2_default")); context = new HashMap<>(); @@ -1956,7 +2077,10 @@ void testDefaultTable() { assertEquals(Type.STAGED, result.getType()); assertEquals(1, result.getErrors().size()); assertEquals("input2", result.getErrors().getFirst().getKey()); - assertEquals("Default table table_input2_default did not find a match", result.getErrors().getFirst().getMessage()); + assertEquals( + "Default table table_input2_default did not find a match", + result.getErrors().getFirst().getMessage() + ); // check same case with getDefault method context = new HashMap<>(); @@ -1965,7 +2089,9 @@ void testDefaultTable() { assertEquals("", engine.getDefault(input2, context, result1)); assertEquals(1, result1.getErrors().size()); assertEquals("input2", result.getErrors().getFirst().getKey()); - assertEquals("Default table table_input2_default did not find a match", result.getErrors().getFirst().getMessage()); + assertEquals( + "Default table table_input2_default did not find a match", + result.getErrors().getFirst().getMessage() + ); } - } diff --git a/src/test/java/com/imsweb/staging/entities/SchemaLookupTest.java b/src/test/java/com/imsweb/staging/entities/SchemaLookupTest.java index eaba0a5b2..b35032588 100644 --- a/src/test/java/com/imsweb/staging/entities/SchemaLookupTest.java +++ b/src/test/java/com/imsweb/staging/entities/SchemaLookupTest.java @@ -1,13 +1,17 @@ package com.imsweb.staging.entities; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.util.HashSet; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; - import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - class SchemaLookupTest { @Test @@ -25,4 +29,96 @@ void testConstructorMissingValues() { assertEquals(new SchemaLookup("C629", "9100").getKeys(), Stream.of("site", "hist").collect(Collectors.toSet())); } -} \ No newline at end of file + @Test + void testSiteAndHistologyMutation() { + SchemaLookup lookup = new SchemaLookup("C629", "9100"); + + lookup.setSite("C509"); + lookup.setHistology("8000"); + + assertEquals("C509", lookup.getSite()); + assertEquals("C509", lookup.getInput(StagingData.PRIMARY_SITE_KEY)); + assertEquals("8000", lookup.getHistology()); + assertEquals("8000", lookup.getInput(StagingData.HISTOLOGY_KEY)); + } + + @Test + void testEqualsAndHashCode() { + SchemaLookup lookup1 = new SchemaLookup("C629", "9100"); + SchemaLookup lookup2 = new SchemaLookup("C629", "9100"); + SchemaLookup lookup3 = new SchemaLookup("C629", "9100"); + + assertEquals(lookup1, lookup1); + assertEquals(lookup1, lookup2); + assertEquals(lookup2, lookup1); + assertEquals(lookup2, lookup3); + assertEquals(lookup1, lookup3); + assertEquals(lookup1.hashCode(), lookup2.hashCode()); + } + + @Test + void testNotEquals() { + SchemaLookup lookup = new SchemaLookup("C629", "9100"); + + assertNotEquals(null, lookup); + assertNotEquals("C629", lookup); + assertNotEquals(lookup, new TestSchemaLookup("C629", "9100")); + assertNotEquals(new SchemaLookup("C509", "9100"), lookup); + assertNotEquals(new SchemaLookup("C629", "8000"), lookup); + } + + @Test + void testClearInputs() { + TestSchemaLookup lookup = new TestSchemaLookup("C629", "9100"); + lookup.setInput("allowed", "value"); + + lookup.clear(); + + assertTrue(lookup.getInputs().isEmpty()); + } + + @Test + void testAllowedKeys() { + SchemaLookup unrestrictedLookup = new SchemaLookup(); + unrestrictedLookup.setInput("anything", "value"); + assertEquals("value", unrestrictedLookup.getInput("anything")); + + TestSchemaLookup restrictedLookup = new TestSchemaLookup(); + restrictedLookup.setInput("allowed", "value"); + assertEquals("value", restrictedLookup.getInput("allowed")); + assertThrows(IllegalStateException.class, () -> restrictedLookup.setInput("disallowed", "value")); + } + + @Test + void testDiscriminator() { + SchemaLookup lookup = new SchemaLookup("C629", "9100"); + assertFalse(lookup.hasDiscriminator()); + + lookup.setInput("discriminator", null); + assertFalse(lookup.hasDiscriminator()); + + lookup.setInput("discriminator", ""); + assertFalse(lookup.hasDiscriminator()); + + lookup.setInput("discriminator", "001"); + assertTrue(lookup.hasDiscriminator()); + } + + private static class TestSchemaLookup extends SchemaLookup { + + TestSchemaLookup() {} + + TestSchemaLookup(String site, String histology) { + super(site, histology); + } + + @Override + public Set getAllowedKeys() { + return Set.of(StagingData.PRIMARY_SITE_KEY, StagingData.HISTOLOGY_KEY, "allowed"); + } + + void clear() { + clearInputs(); + } + } +}