Skip to content

Commit 97be33d

Browse files
committed
test: assert the repeating reference check instead of documenting its absence
Both example tests existed partly to record that the check never ran, and forced it to execute with an invalid single-value cardinality to show what it would do. They now exercise the list path directly.
1 parent b7ec6cd commit 97be33d

2 files changed

Lines changed: 64 additions & 51 deletions

File tree

‎examples/python-r4-us-core/test_profile_provenance.py‎

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@
1111
conformant type the generation did not emit is reported as an error. The
1212
TypeScript generator behaves the same way.
1313
14-
The check still never runs, though: `target` is `1..*`, and the helper reads
15-
`reference` from the list itself rather than from each entry. The TypeScript
16-
generator has the same hole, so this mirrors
14+
`target` is `1..*`, so the element holds a list of References; the check reads
15+
every entry. Mirrors
1716
`examples/typescript-r4-us-core/profile-us-core-provenance.test.ts`.
1817
"""
1918

2019
from pathlib import Path
21-
from typing import Any, cast
2220

2321
import pytest
2422
from fhir_types.hl7_fhir_r4_core.base import Reference
25-
from fhir_types.hl7_fhir_r4_core.provenance import Provenance, ProvenanceAgent
23+
from fhir_types.hl7_fhir_r4_core.provenance import ProvenanceAgent
2624
from fhir_types.hl7_fhir_us_core.profiles.provenance_uscore_provenance import (
2725
UscoreProvenanceProfile,
2826
)
@@ -63,41 +61,49 @@ def test_the_generated_validation_lists_the_member_resource_types() -> None:
6361
assert '"DomainResource"' not in GENERATED_SOURCE
6462

6563

66-
@pytest.mark.parametrize("reference", ["Patient/pt-1", "Practitioner/pr-1", "NotAResource/x"])
67-
def test_a_target_in_a_list_reports_no_error(reference: str) -> None:
68-
# `target` is an array, so the emitted check cannot fail for any input — not
69-
# even a reference to something that is not a FHIR resource at all.
64+
def test_an_allowed_target_passes() -> None:
7065
profile = UscoreProvenanceProfile.create(
71-
target=[Reference(reference=reference)],
66+
target=[Reference(reference="Patient/pt-1")],
7267
recorded=RECORDED,
7368
agent=_agent(),
7469
)
7570

7671
assert profile.validate()["errors"] == []
7772

7873

79-
def _single_target(reference: str) -> Provenance:
80-
# An invalid cardinality, used only to make the check execute.
81-
resource: dict[str, Any] = {
82-
"resourceType": "Provenance",
83-
"recorded": RECORDED,
84-
"agent": _agent(),
85-
"target": {"reference": reference},
86-
}
87-
return cast(Provenance, resource)
88-
89-
90-
def test_the_check_accepts_an_allowed_resource_once_it_executes() -> None:
91-
profile = UscoreProvenanceProfile(_single_target("Patient/pt-1"))
74+
@pytest.mark.parametrize("reference", ["Practitioner/pr-1", "NotAResource/x"])
75+
def test_a_target_outside_the_allowed_set_is_reported(reference: str) -> None:
76+
profile = UscoreProvenanceProfile.create(
77+
target=[Reference(reference=reference)],
78+
recorded=RECORDED,
79+
agent=_agent(),
80+
)
9281

93-
assert profile.validate()["errors"] == []
82+
reported = reference.split("/")[0]
83+
assert profile.validate()["errors"] == [
84+
f"UscoreProvenanceProfile: field 'target' references '{reported}' but only {ALLOWED} are allowed"
85+
]
9486

9587

96-
def test_the_check_rejects_a_type_outside_the_generated_closure_once_it_executes() -> None:
97-
# Not "is this a FHIR resource" — the allowed set is this generation's
98-
# closure, so a conformant Practitioner reference is reported here too.
99-
profile = UscoreProvenanceProfile(_single_target("NotAResource/x"))
88+
def test_every_entry_of_the_list_is_checked() -> None:
89+
profile = UscoreProvenanceProfile.create(
90+
target=[Reference(reference="Patient/pt-1"), Reference(reference="NotAResource/x")],
91+
recorded=RECORDED,
92+
agent=_agent(),
93+
)
10094

10195
assert profile.validate()["errors"] == [
10296
f"UscoreProvenanceProfile: field 'target' references 'NotAResource' but only {ALLOWED} are allowed"
10397
]
98+
99+
100+
def test_a_repeated_offending_type_is_reported_once() -> None:
101+
# One error per offending type, so a long list does not bury the rest of
102+
# validate()'s output.
103+
profile = UscoreProvenanceProfile.create(
104+
target=[Reference(reference="NotAResource/x"), Reference(reference="NotAResource/y")],
105+
recorded=RECORDED,
106+
agent=_agent(),
107+
)
108+
109+
assert len(profile.validate()["errors"]) == 1

‎examples/typescript-r4-us-core/profile-us-core-provenance.test.ts‎

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
* resources, so the emitted check lists the instantiable types a reference can
88
* actually have — the abstract Resource and DomainResource are left out.
99
*
10-
* The check still never runs, though: `target` is `1..*`, and the helper reads
11-
* `.reference` from the array itself rather than from each entry.
10+
* `target` is `1..*`, so the element holds a list of References; the check reads
11+
* every entry.
1212
*/
1313

1414
import { describe, expect, test } from "bun:test";
1515
import { readFileSync } from "node:fs";
16-
import type { Provenance } from "./fhir-types/hl7-fhir-r4-core/Provenance";
1716
import { USCoreProvenanceProfile } from "./fhir-types/hl7-fhir-us-core/profiles/Provenance_USCoreProvenance";
1817

1918
const generatedSource = readFileSync(
@@ -38,38 +37,46 @@ describe("demo: record provenance for a resource", () => {
3837
});
3938
});
4039

41-
describe("the generated reference check on target never runs", () => {
40+
describe("the generated reference check on target", () => {
4241
test("the generated validation lists the member resource types", () => {
4342
expect(generatedSource).toContain(
4443
'validateReference(res, profileName, "target", ["Bundle","CodeSystem","Observation","OperationOutcome","Patient","Provenance"])',
4544
);
4645
});
4746

48-
// `target` is an array, so the emitted check cannot fail for any input —
49-
// not even a reference to something that is not a FHIR resource at all.
50-
test.each(["Patient/pt-1", "Organization/org-1", "NotAResource/x"])(
51-
"a target referencing %s reports no error",
52-
(reference) => {
53-
const profile = USCoreProvenanceProfile.create({ ...baseArgs, target: [{ reference }] });
47+
test("an allowed target passes", () => {
48+
const profile = USCoreProvenanceProfile.create({ ...baseArgs, target: [{ reference: "Patient/pt-1" }] });
5449

55-
expect(profile.validate().errors).toEqual([]);
56-
},
57-
);
50+
expect(profile.validate().errors).toEqual([]);
51+
});
5852

59-
// Reaching the same check with a single value instead of an array (an
60-
// invalid cardinality, used here only to make the check execute) shows what
61-
// it does when it runs: an allowed resource passes, a type that is not a
62-
// resource does not.
63-
const singleTarget = (reference: string) =>
64-
({ resourceType: "Provenance", ...baseArgs, target: { reference } }) as unknown as Provenance;
53+
test.each(["Organization/org-1", "NotAResource/x"])("a target referencing %s is reported", (reference) => {
54+
const profile = USCoreProvenanceProfile.create({ ...baseArgs, target: [{ reference }] });
6555

66-
test("the check accepts an allowed resource once it executes", () => {
67-
expect(new USCoreProvenanceProfile(singleTarget("Patient/pt-1")).validate().errors).toEqual([]);
56+
expect(profile.validate().errors).toEqual([
57+
`USCoreProvenance: field 'target' references '${reference.split("/")[0]}' but only Bundle, CodeSystem, Observation, OperationOutcome, Patient, Provenance are allowed`,
58+
]);
6859
});
6960

70-
test("the check rejects a type that is not a resource once it executes", () => {
71-
expect(new USCoreProvenanceProfile(singleTarget("NotAResource/x")).validate().errors).toEqual([
61+
test("every entry of the list is checked, not just the first", () => {
62+
const profile = USCoreProvenanceProfile.create({
63+
...baseArgs,
64+
target: [{ reference: "Patient/pt-1" }, { reference: "NotAResource/x" }],
65+
});
66+
67+
expect(profile.validate().errors).toEqual([
7268
"USCoreProvenance: field 'target' references 'NotAResource' but only Bundle, CodeSystem, Observation, OperationOutcome, Patient, Provenance are allowed",
7369
]);
7470
});
71+
72+
// One error per offending type, so a list of many wrong references of the
73+
// same type does not bury the rest of validate()'s output.
74+
test("a repeated offending type is reported once", () => {
75+
const profile = USCoreProvenanceProfile.create({
76+
...baseArgs,
77+
target: [{ reference: "NotAResource/x" }, { reference: "NotAResource/y" }],
78+
});
79+
80+
expect(profile.validate().errors).toHaveLength(1);
81+
});
7582
});

0 commit comments

Comments
 (0)