Skip to content

Commit

Permalink
Set up some content test scaffolding (#497)
Browse files Browse the repository at this point in the history
  • Loading branch information
JPercival authored Dec 1, 2023
1 parent 8c4092a commit 630b521
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 114 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"java.configuration.updateBuildConfiguration": "automatic",
"cSpell.words": [
"acceleratorkit",
"ANCM",
"Careand",
"pagecontent",
"plandefinition",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.opencds.cqf.tooling.acceleratorkit;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;

import java.io.IOException;
import java.nio.file.Files;

import org.hl7.fhir.r4.model.CodeSystem;
import org.testng.annotations.Test;

public class ANCMiniContentTest extends BaseContentTest {

public ANCMiniContentTest() {
super(new Spreadsheet(){{
path = "acceleratorkit/ANC Test Cases-mini.xlsx";
dataDictionarySheets = "ANC.A. Registration,ANC.B5 Quick check,ANC.End End";
scope = "ANCM";
}});
}

@Test
public void validateContentCount() {
assertFalse(profilesPath().toFile().exists());
assertEquals(cqlPath().toFile().listFiles().length, 4);
assertFalse(examplesPath().toFile().exists());
assertFalse(extensionsPath().toFile().exists());
assertFalse(resourcesPath().toFile().exists());
assertFalse(testsPath().toFile().exists());
assertEquals(vocabularyPath().toFile().listFiles().length, 1);
}

@Test
public void validateCQLContent() throws IOException {
assertTrue(cqlPath().resolve("ANCMConcepts.cql").toFile().exists());
assertTrue(cqlPath().resolve("ANCMContactDataElements.cql").toFile().exists());
assertTrue(cqlPath().resolve("ANCMDataElements.cql").toFile().exists());

var cqlLines = Files.readAllLines(cqlPath().resolve("ANCMConcepts.cql"));
assertEquals(cqlLines.get(6), "codesystem \"RxNorm\": 'http://www.nlm.nih.gov/research/umls/rxnorm'");
}

@Test
public void validateCodeSystem() {
var codeSystem = resourceAtPath(
CodeSystem.class,
vocabularyPath().resolve("codesystem/codesystem-activity-codes.json"));
assertEquals(codeSystem.getTitle(), "ANCM Activity Codes");
}

@Test
public void exampleIssue628() throws IOException {
// Link the github issue here
// Description of the issue (e.g. "The CQL was missing a comment at line 235")
// var cqlLines = Files.readAllLines(cqlPath().resolve("FhirHelpers.cql"));
// assertEquals(cqlLines.get(20), "// @fluentFunction");
}


@Test
public void validateElm() {
// TODO: Helpers to compile CQL to ELM and validate
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package org.opencds.cqf.tooling.acceleratorkit;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Objects;

import org.hl7.fhir.instance.model.api.IBaseResource;
import org.testng.annotations.BeforeClass;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.parser.IParser;

/**
* This class scaffolds the test setup for the AcceleratorKitProcessor.
* Extend this class to create a test for a specific accelerator kit
* spreadsheet.
*/
public abstract class BaseContentTest {
private static final String resourcesPath = "src/test/resources";
private static final String tempPath = "target/test-output";

private final Spreadsheet spreadsheet;
private final FhirContext fhirContext;

private Path outputPath;
private Processor processor;

protected BaseContentTest(Spreadsheet spreadsheet) {
this(spreadsheet, FhirVersionEnum.R4);
}

protected BaseContentTest(Spreadsheet spreadsheet, FhirVersionEnum fhirVersion) {
Objects.requireNonNull(spreadsheet, "spreadsheet is required");
Objects.requireNonNull(spreadsheet.path, "spreadsheet path is required");
Objects.requireNonNull(spreadsheet.dataDictionarySheets, "data dictionary sheets are required");
Objects.requireNonNull(spreadsheet.scope, "scope is required");

Objects.requireNonNull(fhirVersion, "fhir version is required");

this.fhirContext = FhirContext.forCached(fhirVersion);
this.spreadsheet = spreadsheet;
}

@BeforeClass
protected void init() throws IOException {
outputPath = Files.createTempDirectory(Path.of(tempPath), "content-test-").toAbsolutePath();
processor = new Processor();
processor.execute(args());
}

protected String command() {
return "-ProcessAcceleratorKit";
}

/**
* Add new fields to this class to support additional command line arguments.
*/
protected static class Spreadsheet {
String path;
String dataDictionarySheets;
String encoding;
String scope;
String dataElementPages;
String testCases;
}

protected String[] params() {
return new String[] {
"-s", scope(),
"-pts", spreadsheetPath().toAbsolutePath().toString(),
"-dep", dataDictionarySheets(),
"-op", outputPath().toAbsolutePath().toString(),
"-e", encoding(),
"-tc", testCases()};
};

protected String[] args() {

var params = params();
if (params.length % 2 != 0) {
throw new RuntimeException("Invalid number of command line arguments. Each argument must have a value");
}

var args = new ArrayList<String>();
args.add(command());

// get only the key-value pairs where the value is set,
// create command line arguments (key=value) from them
for (int i = 0; i < params.length; i += 2) {
if (params[i + 1] != null) {
args.add(params[i] + "=" + params[i + 1]);
}
}

return args.toArray(String[]::new);
}

// Input params accessors

protected String testCases() {
return spreadsheet.testCases;
}

protected String encoding() {
return spreadsheet.encoding;
}

protected String scope() {
return spreadsheet.scope;
}

protected Path spreadsheetPath() {
return Path.of(resourcesPath, spreadsheet.path);
}

protected String dataDictionarySheets() {
return spreadsheet.dataDictionarySheets;
}

// FHIR context accessors
protected FhirContext fhirContext() {
return fhirContext;
}

// Directory accessors

protected Path outputPath() {
return outputPath;
}

protected Path inputPath() {
return outputPath().resolve("input");
}

protected Path profilesPath() {
return inputPath().resolve("profiles");
}

protected Path cqlPath() {
return inputPath().resolve("cql");
}

protected Path examplesPath() {
return inputPath().resolve("examples");
}

protected Path extensionsPath() {
return inputPath().resolve("extensions");
}

protected Path resourcesPath() {
return inputPath().resolve("resources");
}

protected Path testsPath() {
return inputPath().resolve("tests");
}

protected Path vocabularyPath() {
return inputPath().resolve("vocabulary");
}

// Resource helpers

protected <T extends IBaseResource> T resourceAtPath(Class<T> resourceClass, Path resourcePath) {
Objects.requireNonNull(resourcePath, "resourcePath is required");
Objects.requireNonNull(resourceClass, "resourceClass is required");

var file = resourcePath.toFile();
if (!file.exists()) {
throw new RuntimeException("Resource file does not exist: " + resourcePath);
}

IParser parser = null;
if (file.getName().endsWith(".json")) {
parser = fhirContext().newJsonParser();
} else if (file.getName().endsWith(".xml")) {
parser = fhirContext().newXmlParser();
} else {
throw new RuntimeException("Unsupported resource file type: " + resourcePath);
}

try {
return parser.parseResource(resourceClass, new BufferedReader(new FileReader(file)));
} catch (Exception e) {
throw new RuntimeException("Error parsing resource file: " + resourcePath, e);
}
}
}

This file was deleted.

0 comments on commit 630b521

Please sign in to comment.