openEHR logo

openEHR Platform Conformance Test Schedule

Issuer: openEHR Specification Program

Release: CNF development

Status: DEVELOPMENT

Revision: [latest_issue]

Date: [latest_issue_date]

Keywords: conformance, test

openEHR components
© 2017 - 2024 The openEHR Foundation

The openEHR Foundation is an independent, non-profit foundation, facilitating the sharing of health records by consumers and clinicians via open specifications, clinical models and open platform implementations.

Licence

image Creative Commons Attribution-NoDerivs 3.0 Unported. https://creativecommons.org/licenses/by-nd/3.0/

Support

Issues: Problem Reports
Web: specifications.openEHR.org

Acknowledgements

This specification was developed and is maintained by the openEHR Specifications Editorial Committee (SEC).

Principal Authors

  • Thomas Beale, Ars Semantica, UK; openEHR International Board

  • Pablo Pazos Gutierrez, CaboLabs, Uruguay

  • Wladislaw Wagner, vitagroup AG, Germany

Trademarks

  • 'openEHR' is a trademark of the openEHR Foundation

1. Preface

1.1. Purpose

This document specifies the openEHR Platform Conformance test schedule, which may be used to determine the conformance of openEHR platform products to openEHR plaform-related specifications. The audience of this document includes:

  • Software development organisations developing healthcare information systems;

  • Customer (i.e. procuring) organisations.

Useful references for reading this document include:

1.3. Status

This specification is in the DEVELOPMENT state. The development version of this document can be found at https://specifications.openehr.org/releases/CNF/development/platform_test_schedule.html.

Known omissions or questions are indicated in the text with a 'to be determined' paragraph, as follows:

TBD: (example To Be Determined paragraph)

1.4. Feedback

Feedback may be provided on the openEHR Conformance forum.

Issues may be raised on the specifications Problem Report tracker.

To see changes made due to previously reported issues, see the CNF component Change Request tracker.

2. Glossary of Terms and Acronyms

The following terms and acronyms are used in this document.

Term Meaning

AOM

Archetype Object Model (model of constraints).

API

Application Programmer Interface.

CDS

Clinical Decision Support.

REST

Representational state transfer, a type of web service. REST-compliant Web services allow requesting systems to access and manipulate
textual representations of Web resources using a uniform and predefined set of stateless operations.

RM

openEHR Reference Model

SUT

System under test.

3. Overview

3.1. Scope

As described in the openEHR Conformance Guide, the following aspects of a System Under Test (SUT) are tested to determine conformance to published specifications:

Test aspect How assessed Methodology

API conformance

Conformance of the implemented APIs to the published APIs, in a concrete API technology

Regression of test client running API call-in test cases against reference results

Data Validation conformance

Conformance of platform’s validation of data against semantic models (archetypes etc)

Regression of test client committing variable data sets against reference validity

The main part of this specification is divided into sections according to the three test aspects shown above. Specific methods related to each aspect are described in the sub-sections below.

Specific applications are also outside the scope of this specification, however, it is assumed that in order for solutions to be testable, a minimal generic viewing tool is provided to enable viewing of data and other testable events.

3.2. API Conformance Test Design

API conformance is assessed by running tests on the SUT API, and determining deviations from expected results. As described in Section 4.2 of the openEHR Conformance Guide, the test cases defined here are based on the openEHR Platform Abstract Service Model API operations. Each such operation is a testable capability of a system that relates to a business function. For example, SM operations for an EHR service include create_EHR, update_EHR, and so on. For any such operation, there may be multiple test cases, each of which is individually identified. For each test case, there may be multiple data sets. A 'test' is therefore the execution of a particular test case with a particular data set.

Each test case is documented in the form shown in the following sub-section.

3.2.1. Test Case <SERVICE_COMPONENT>.<operation>-<test-specific id>

Description

<test case description>

Pre-conditions

<conditions required of the SUT prior to test case execution>

Post-conditions

<conditions true of the SUT subsequent to test case execution>

Flow

<steps required to execute the test>

In most automated test frameworks, pre-conditions, setup, actions, post-conditions, and cleanup steps can be directly implemented.

Note
The supported RM version(s) by the SUT should be stated in the Conformance Statement, because this will determine some variations on the data sets used for testing. The minimum required version is RM 1.0.2.

3.3. Data Validation Conformance Test Design

Data validation conformance is defined in terms of test cases with multiple data sets. These test cases are documented in the same basic way as described above, along with multiple data sets, typically shown in tabulated form. They are described in Section 14.

4. Test Suite: DEFINITION Service / I_DEFINITION_ADL2 and I_DEFINITION_ADL14 Interfaces

4.1. Normative Reference

Items under this validation suite conceptually use these abstract interfaces defined in the openEHR Platform Service Model:

These are concretely realised in implementation technology specfic APIs, such as the Definitions REST API.

This test suite uses artefacts defined by the following specifications:

TODO: add ref to dependency diagram in SM/Platform service model.

4.2. Test Environment

The server under test should support:

  1. OPTs 1.4 or 2, but OPT 1.4 if more frequent since modeling tools supporting this were around for a long time. Could also support ADL, 1.4 or 2;

  2. validation of OPTs and archetypes uploaded to it, or even provide a service to do so before uploading (useful while developing);

  3. different versions of the same OPTs and archetypes.

The following should be taken into account when testing any given product:

  1. The server under test should support the full cycle of OPT management, including: validation, loading, versioning, retrieving, delete or deactivation (data for this OPT is loaded but no new data should be accepted for it). For the delete, the internal behavior should be defined: 1. if data was committed referencing an OPT, can it be physically deleted? or should be logically deleted? 2. if there is no data, can the OPT be deleted physically? Logical delete might work as the deactivation mentioned above.

  2. The test cases are the same for OPT 1.4/2, but tests should be written separately and different datasets should be created for 1.4 and 2.

  3. Different implementations might use specific formats for the template IDs, when testing each server, the template IDs should be adapted to prevent failures for wrong format on the template ID. This is due to openEHR not yet defining a format for the template IDs in the specifications.

4.3. OPT 1.4/2 Test cases

4.3.1. Service Model operation: I_DEFINITION_ADL14.validate_opt()

Service Model reference: I_DEFINITION_ADL14.validate_opt()

4.3.1.1. Test Data Sets
  • minimal valid OPT (each containing each entry type);

  • maximal valid OPT (all types in the RM);

  • invalid OPT (empty file);

  • invalid OPT (empty template_id);

  • invalid OPT (removed mandatory elements);

  • invalid OPT (added multiple elements that had an upper bound of 1)

4.3.1.2. Test Case I_DEFINITION_ADL14.validate_opt-valid_opt

Description

Validate valid OPTs

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None (validation should not change the state of the system).

Flow

  1. For each valid OPT in the data set, invoke the OPT validation service

  2. The result should be positive and the server should return should be related to “OPT is valid”.

Test runners

Note
some servers might not have a way to just validate the OPT, and validation might be part of the OPT upload functionality. In that case, the validation should upload and validate the OPT, and in the cases of valid OPTs, the OPT should be deleted afterwards, so the system state doesn’t change. For invalid OPTs, the upload should fail.
4.3.1.3. Test Case I_DEFINITION_ADL14.validate_opt-invalid_opt

Description

Validate invalid OPTs

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None (validation should not change the state of the system).

Flow

  1. For each invalid OPT in the data set, invoke the OPT validation service

  2. The result should be negative related to the “OPT is invalid”, would be useful if the server also returns where the problems are in the OPT

Test runners

Implementation note: when a step says “for each X, invoke service Y”, means that the test should run completely for each X, that is, the pre-conditions and post-conditions apply to the run for X. So if we have:

Test set: a, b, c

Test case:

  • ensure pre-conditions

  • verify post-conditions

  • flow

    1. for each X in data set, run service Y

    2. verify result

The run should be:

  • ensure pre-conditions

  • invoke Y(a)

  • verify result

  • verify post-conditions

  • ensure pre-conditions

  • invoke Y(b)

  • verify result

  • verify post-conditions

  • ensure pre-conditions

  • invoke Y(c)

  • verify result

  • verify post-conditions

4.3.2. Service Model operation: I_DEFINITION_ADL14.upload_opt()

Service Model reference: I_DEFINITION_ADL14.upload_opt()

4.3.2.1. Data set
  • minimal valid OPT (each with one type of entry, cover all entries)

  • minimal valid OPT, two versions

  • maximal valid OPT (all types in the RM)

  • invalid OPT (empty file)

  • invalid OPT (empty template_id)

  • invalid OPT (removed mandatory elements)

  • invalid OPT (added multiple elements that had an upper bound of 1)

4.3.2.2. Test Case I_DEFINITION_ADL14.upload_opt-valid_opt

Description

upload valid OPTs

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

A new OPT with the given template_id is loaded into the server.

NOTE: the server should be able to retrieve the template by `template_id` or retrieve if an OPT exists or not by `template_id`.

Flow

  1. For each valid OPT in the data set, invoke the OPT upload service

  2. The result should be positive, the server accepted the OPT and it is stored as it was uploaded

Test runners

4.3.2.3. Test Case I_DEFINITION_ADL14.upload_opt-invalid_opt

Description

upload invalid OPTs

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

No OPTs should be loaded on the system.

Flow

  1. For each invalid OPT in the data set, invoke the OPT upload service

  2. The result should be negative, the server rejected the OPT because it was invalid, and would be useful if the result contains where the errors are in the uploaded OPT.

Test runners

4.3.2.4. Test Case I_DEFINITION_ADL14.upload_opt-valid_opt_twice_conflict
Note
since there is no formal versioning mechanism for templates 1.4 (OPT 2 might use the archetype id format for the template id that also includes a version number, but this is not widely used), the OPT upload service needs to handle a version parameter, for instance this is the solution on the openEHR REST API. If the version information is not available when uploading OPTs, then uploading an OPT with the same template_id twice will make the second upload fail (conflict).

An alternative solution for the version parameter is to add the version number to the other_details of the OPT, or directly into the template_id.

Description

Upload valid OPT twice with conflict

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

A new OPT with the given template_id is loaded into the server, and there will be only one OPT loaded.

Note
the server should be able to retrieve the template by template_id, or retrieve if an OPT exists or not by template_id.

Flow

  1. For each valid OPT in the data set, invoke the OPT upload service

  2. The result should be positive (the server accepted the OPT)

  3. Invoke the upload service with the same OPT as in 1.

  4. The result should be negative (the server rejected the OPT)

Test runners

4.3.2.5. Test Case I_DEFINITION_ADL14.upload_opt-valid_opt_twice_no_conflict
Note
considering the note on the previous flow, for this flow the version parameter is provided, and both service invocations contain a different version value.

Description

upload valid OPT twice with conflict

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

Two new OPTs with the given template_id and different versions are loaded into the server.

Note
the server should be able to retrieve the templates by template_id and version, or retrieve if an OPT exists or not by template_id and version. Given only the template_id, the server will return just the latest version.

Flow

  1. For each valid OPT in the data set, invoke the OPT upload service, including the version parameter = 1

  2. The result should be positive (the server accepted the OPT)

  3. Invoke the upload service with the same OPT as in 1., including the version parameter = 2

  4. The result should be positive (the server accepted the OPT)

Test runners

4.3.3. Service Model operation: I_DEFINITION_ADL14.get_opt()

Service Model reference: I_DEFINITION_ADL14.get_opt()

Note
the flows of this test case will include flows from the Upload OPT test case, in order to have something to retrieve.
4.3.3.1. Data sets
  • minimal valid OPT (covering all entry types)

  • minimal valid OPT, two versions

  • maximal valid OPT (all types in the RM)

4.3.3.2. Test Case I_DEFINITION_ADL14.get_opt-retrieve_single

Description

Retrieve a single OPT

Pre-conditions

All valid OPTs should be loaded into the system, only the single versioned ones.

Post-conditions

None (retrieve should not change the state of the system).

Flow

  1. Invoke the retrieve OPT service with existing template_ids

  2. For each template_id, the correct OPT will be returned

    NOTE: to check point 2, the retrieved OPT should be exactly the same as the uploaded one.

Test runners

4.3.3.3. Test Case I_DEFINITION_ADL14.get_opt-retrieve_fail

Description

Empty server OPT retrieve fail test

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

None

Flow

  1. Invoke the retrieve OPT service with a random template_id

  2. The service should return an error related to the non existence of the requested OPT

Test runners

4.3.3.4. Test Case I_DEFINITION_ADL14.get_opt-retrieve_latest_version

Description

retrieve last version of versioned OPT

Pre-conditions

OPTs with more than one version should be loaded.

Post-conditions

None

Flow

  1. Invoke the retrieve OPT service with existing template_ids

  2. For each template_id, the correct OPT will be returned, and will be the last version

    NOTE: to be sure the last version was returned, a small modification to the OPT could be done.

Test runners

4.3.3.5. Test Case I_DEFINITION_ADL14.get_opt-retrieve_specific_version

Description

retrieve a specific version (not last) of versioned OPT

Pre-conditions

OPTs with more than one version should be loaded.

Post-conditions

None

Flow

  1. Invoke the retrieve OPT service with existing template_ids and a version parameter value that is not the last

  2. For each template_id, the correct OPT will be returned, and will be the requested version

    NOTE: to be sure the last version was returned, a small modification to the OPT could be done.

Test runners

4.3.4. Service Model operation: I_DEFINITION_ADL14.get_opts()

Service Model reference: I_DEFINITION_ADL14.get_opts()

4.3.4.1. Data sets
  • minimal valid OPT (covering each type of entry);

  • minimal valid OPT, two versions;

  • maximal valid OPT (all types in the RM).

4.3.4.2. Test Case I_DEFINITION_ADL14.get_opts-retrieve_all

Description

retrieve all loaded OPTs

Pre-conditions

All valid OPTs should be loaded.

Post-conditions

None

Flow

  1. Invoke the retrieve OPTs service

  2. All the loaded OPTs should be returned, if there are versions of any OPTs, only the last version is retrieved

Test runners

4.3.4.3. Test Case I_DEFINITION_ADL14.get_opts-retrieve_all_no_opts

Description

retrieve all loaded OPTs when none is loaded

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

None

Flow

  1. Invoke the retrieve OPTs service

  2. The service should return an empty set and should not fail.

Test runners

4.3.5. Service Model operation: I_DEFINITION_ADL14.delete_opt()

Service Model reference: I_DEFINITION_ADL14.delete_opt()

Note
the OPT delete can only happen if there is no associated data with the OPT, or if there exists a newer revision (minor version of the same OPT) in the server under test. For all these tests, there is not data committed to the server, so the delete can happen.

Implementation recommendations: the delete could be logical, so the OPT exists in the server but is not available, and there could be a service to retrieve deleted OPTs. Those can be undeleted or physically deleted (this can’t be undone), and only users with admin permissions should be able to physically delete OPTs.

4.3.5.1. Data sets
  • minimal valid OPT

  • minimal valid OPT, two versions

  • maximal valid OPT (all types in the RM)

4.3.5.2. Test Case I_DEFINITION_ADL14.delete_opt-delete_existing

Description

delete existing OPTs

Pre-conditions

All valid OPTs should be loaded into the system.

Post-conditions

None

Flow

  1. For each existing template_id, invoke the delete OPT service

  2. Verify the OPT is not longer available via the retrieve OPTs service

    NOTE: for step 1, exclude versioned OPT, the result should be the same: the OPT is not available.

Test runners

4.3.5.3. Test Case I_DEFINITION_ADL14.delete_opt-delete_latest_version

Description

delete last version of a versioned OPT

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

None

Flow

  1. Include flow: upload valid OPTs

  2. Invoke the delete OPT service for all existing template_ids

  3. Include flow: retrieve all loaded OPTs when none is loaded

    NOTE: for step 1, include only versioned OPT.
    NOTE: for versioned OPTs, when no version parameter is present when invoking the delete OPT service, all the versions of the OPT will be deleted.

Test runners

4.3.5.4. Test Case I_DEFINITION_ADL14.delete_opt-delete_specific_version

Description

delete specific version of a versioned OPT

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

None

Flow

  1. Include flow: upload valid OPTs

  2. Invoke the delete OPT service for an existing template_id and version of the OPT, version should not be the last

  3. Include flow: retrieve all loaded OPTs

  4. The OPT set retrieved on step 3 should contain the deleted OPT, since the latest version was not deleted

  5. Include flow: delete existing OPTs

    NOTE: for step 1, include only versioned OPT.

Test runners

4.3.5.5. Test Case I_DEFINITION_ADL14.delete_opt-delete_non_existing

Description

delete a non existing OPT

Pre-conditions

No OPTs should be loaded on the system.

Post-conditions

None

Flow

  1. Include flow: upload valid OPTs

  2. Invoke the delete OPT service with a non existing template_id

  3. The server will return an error related to the OPT not existing in the server

  4. Include flow: delete existing OPTs

Test runners

5. Test Suite: DEFINITION Service / I_DEFINITION_QUERY Interface

5.1. Normative Reference

Items under this validation suite conceptually use these abstract interfaces defined in the Platform Service Model:

  • I_DEFINITION_QUERY

These are concretely realised in implementation technology specfic APIs, such as the Definitions REST API.

This test suite uses artefacts defined by the following specifications:

5.2. Test Environment

The server under test should support:

TBD

5.3. Test Data Sets

TBD

5.4. Test cases

5.4.1. Service Model operation: I_DEFINITION_QUERY.has_query()

Service Model reference: I_DEFINITION_QUERY.has_query()

5.4.1.1. Test Case I_DEFINITION_QUERY.has_query-xxx

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

5.4.2. Service Model operation: I_DEFINITION_QUERY.valid_query()

Service Model reference: I_DEFINITION_QUERY.valid_query()

5.4.2.1. Test Case I_DEFINITION_QUERY.valid_query-valid

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

5.4.2.2. Test Case I_DEFINITION_QUERY.valid_query-invalid

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

5.4.2.3. Test Case I_DEFINITION_QUERY.valid_query-bad_formalism

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

5.4.3. Service Model operation: I_DEFINITION_QUERY.list_queries()

Service Model reference: I_DEFINITION_QUERY.list_queries()

5.4.3.1. Test Case I_DEFINITION_QUERY.list_queries-empty

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

5.4.3.2. Test Case I_DEFINITION_QUERY.list_queries-non_empty

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

5.4.3.3. Test Case I_DEFINITION_QUERY.list_queries-select_items

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

6. Test Suite: EHR_SERVICE

6.1. Normative Reference

Items in this validation suite conceptually use the following abstract interfaces from the Abstract Platform Service Model, EHR component.

  • I_EHR_SERVICE

  • I_EHR

  • I_EHR_STATUS

These are concretely realised in implementation technology specfic APIs, such as the EHR REST API.

This test suite uses artefacts defined by the following information model specifications:

6.2. Test Environment

The server under test should support:

  1. at least the OPT 1.4 format, and optionally OPT 2.

  2. at least the XML representation of COMPOSITIONs for committing data, which may be validated by the openEHR XSDs.

6.3. Test Data Sets

These are the data set classes:

  1. VALID:

    1. not providing an EHR_STATUS (empty input, the server creates the default structures and data)

    2. providing a valid EHR_STATUS

  2. INVALID:

    1. providing invalid EHR_STATUS

Valid data sets when the EHR_STATUS is provided and internal strucrures are valid (data set class 1.a):

No. is_queryable is_modifiable subject other_details ehr_id

1

true

true

provided

not provided

not provided

2

true

false

provided

not provided

not provided

3

false

true

provided

not provided

not provided

4

false

false

provided

not provided

not provided

5

true

true

provided

provided

not provided

6

true

false

provided

provided

not provided

7

false

true

provided

provided

not provided

8

false

false

provided

provided

not provided

9

true

true

provided

not provided

provided

10

true

false

provided

not provided

provided

11

false

true

provided

not provided

provided

12

false

false

provided

not provided

provided

13

true

true

provided

provided

provided

14

true

false

provided

provided

provided

15

false

true

provided

provided

provided

16

false

false

provided

provided

provided

Any other data set is invalid, for instance providing EHR_STATUS with:

  1. missing is_queryable, is_modifiable

  2. empty is_queryable, `_is_modifiable

  3. missing or empty subject_id

  4. invalid subject_id

  5. invalid other_details

Notes:

  1. When the ehr_id is not present, it is expected that it is assigned by the server.

  2. The server should set the EHR.system_id value to a known value (defined by the server’s configuration).

  3. The default values that should be assigned by the server for is_modifiable and is_queryable are 'true', and for the subject it defaults to an instance of PARTY_SELF.

  4. There are no cases to check if the provided ehr_id is valid, since in the openEHR Platform Service Model the parameters are typed to UUID, any other format will be an invalid call.

  5. The validity of an EHR_STATUS can be checked in its JSON form by validating against the JSON schemas.

6.4. Test Cases

6.4.1. Service Model operation: I_EHR_SERVICE.has_ehr()

Service Model reference: I_EHR_SERVICE.has_ehr()

6.4.1.1. Test Case I_EHR_SERVICE.has_ehr-existing_ehr_id

Description

Check has EHR with existing EHR

Pre-conditions

An EHR should exist in the system with a known ehr_id

Post-conditions

None

Flow

  1. Invoke has EHR service with the known ehr_id

  2. The result should be positive, e.g. "the EHR with <ehr_id> exists"

Test runners

6.4.1.2. Test Case I_EHR_SERVICE.has_ehr-existing_subject_id

Description

Check has EHR with existing EHR by subject_id

Pre-conditions

An EHR should exist in the system with a known subject_id.

Post-conditions

None

Flow

  1. Invoke has EHR service with the known subject_id

  2. The result should be positive, e.g. "the EHR with <subject_id> exists"

Test runners

Note
subject_id refers to the PARTY_REF class instance containing the identifier of a patient represented by PARTY_SELF in the openEHR Reference Model.
6.4.1.3. Test Case I_EHR_SERVICE.has_ehr-non_existing_ehr_id

Description

Check has EHR with non existing EHR

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None

Flow

  1. Invoke has EHR service with a random ehr_id.

  2. The result should be negative, e.g. "the EHR with <ehr_id> does not exist"

Test runners

6.4.1.4. Test Case I_EHR_SERVICE.has_ehr-non_existing_subject_id

Description

Check has EHR with non existing EHR by subject_id

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None

Flow

  1. Invoke has EHR service with a random subject_id

  2. The result should be negative, e.g. "the EHR for <subject_id> does not exist"

Test runners

6.4.2. Service Model operation: I_EHR_SERVICE.create_ehr()

Service Model reference: I_EHR_SERVICE.create_ehr()

6.4.2.1. Test Case I_EHR_SERVICE.create_ehr-main

Description

Create new EHR

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

A new EHR will exist in the system and be consistent with the data sets used.

Flow

  1. Invoke the create EHR service

    1. for each item in the VALID data set classes

    2. when the ehr_id is provided, should be unique for each invocation of the service

  2. The server should answer with a positive response associated to the successful EHR creation

Test runners

6.4.2.2. Test Case I_EHR_SERVICE.create_ehr-same_ehr_twice

Description

Attempt to create same EHR twice

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

A new EHR will exist in the system, the first one created, and be consistent with the data sets used.

Flow

  1. Invoke the create EHR service

    1. for each VALID data set not providing ehr_id

    2. for each VALID data set providing ehr_id

  2. The server should answer with a positive response associated to the successful EHR creation

  3. Invoke the create EHR service

    1. with the same ehr_id of the EHR created in 1.1. (should be read from the response)

    2. with the same ehr_id of the EHR created in 1.2. (should be read from the test data sets)

  4. The server should answer with a negative response, related to the existence of an EHR with the provided ehr_id, because ehr_id values should be unique

Test runners

6.4.2.3. Test Case I_EHR_SERVICE.create_ehr-two_ehrs_same_patient

Description

Create two EHRs for the same patient

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

A new EHR will exist in the system.

Flow

  1. Invoke the create EHR service

    1. for each VALID data set with a provided subject and not providing ehr_id

  2. The server should answer with a positive response associated to the successful EHR creation

  3. Invoke the create EHR service

    1. with the same data set used in 1.1

  4. The server should answer with a negative response, related with the EHR already existing for the provided subject

Test runners

6.4.3. Service Model operation: I_EHR_SERVICE.get_ehr()

Service Model reference: I_EHR_SERVICE.get_ehr()

6.4.3.1. Test Case I_EHR_SERVICE.get_ehr-existing_ehr_by_ehr_id

Description

Get existing EHR

Pre-conditions

An EHR should exist in the system with a known ehr_id.

Post-conditions

None.

Flow

  1. Invoke get EHR service with the known ehr_id

  2. The result should be positive and retrieve the EHR

Test runners

6.4.3.2. Test Case I_EHR_SERVICE.get_ehr-existing_ehr_by_subject_id

Description

Get existing EHR by subject_id

Pre-conditions

An EHR should exist in the system with a known subject_id.

Post-conditions

None.

Flow

  1. Invoke get EHR service with the known subject_id

  2. The result should be positive and retrieve the EHR

Test runners

6.4.3.3. Test Case I_EHR_SERVICE.get_ehr-get_ehr_by_invalid_ehr_id

Description

Get non existing EHR

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None.

Flow

  1. Invoke get EHR service by a random ehr_id

  2. The result should be negative, e.g. "EHR with <ehr_id> does not exist"

Test runners

6.4.3.4. Test Case I_EHR_SERVICE.get_ehr-get_ehr_by_invalid_subject_id

Description

Get non existing EHR by subject_id

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None.

Flow

  1. Invoke get EHR service by a random subject_id

  2. The result should be negative, e.g. "EHR for <subject_id> does not exist"

Test runners

6.5. EHR_STATUS Test Cases

6.5.1. Service Model operation: I_EHR_STATUS.get_ehr_status()

Service Model reference: I_EHR_STATUS.get_ehr_status()

6.5.1.1. Test Case I_EHR_STATUS.get_ehr_status-get_by_ehr_id

Description

Get status of an existing EHR

Pre-conditions

An EHR with known ehr_id should exist.

Post-conditions

None.

Flow

  1. Invoke the get EHR_STATUS service by the existing ehr_id

  2. The result should be positive and retrieve a correspondent EHR_STATUS.

    1. The EHR_STATUS internal information should match the rules in which the EHR was created (see test flow Create EHR)

    2. Those rules should be verified: a. has or not a subject_id, b. has correct value for is_modifiable, c. has correct value for is_queryable.

Test runners

6.5.1.2. Test Case I_EHR_STATUS.get_ehr_status-bad_ehr

Description

Get status of a non-existing EHR

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None.

Flow

  1. Invoke the get EHR_STATUS service by a random ehr_id

  2. The result should be negative and the result should include an error e.g. "EHR with <ehr_id> doesn’t exist".

Test runners

6.5.2. Service Model operation: I_EHR_STATUS.set_ehr_queryable()

Service Model reference: I_EHR_STATUS.set_ehr_queryable()

6.5.2.1. Test Case I_EHR_STATUS.set_ehr_queryable-existing_ehr

Description

Set EHR queryable of an existing EHR

Pre-conditions

An EHR with known ehr_id should exist.

Post-conditions

EHR_STATUS.is_queryable, for the EHR with known ehr_id, should be true.

Flow

  1. For the existing EHR, invoke the set EHR queryable service

  2. The result should be positive and the corresponding EHR_STATUS.is_queryable should be true

Test runners

6.5.2.2. Test Case I_EHR_STATUS.set_ehr_queryable-bad_ehr

Description

Set EHR queryable of non existing EHR

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None

Flow

  1. Invoke the set EHR queryable service by a random ehr_id

  2. The result should be negative and the result should include an error e.g. "EHR with <ehr_id> doesn’t exist".

Test runners

6.5.3. Service Model operation: I_EHR_STATUS.set_ehr_modifiable()

Service Model reference: I_EHR_STATUS.set_ehr_modifiable()

6.5.3.1. Test Case I_EHR_STATUS.set_ehr_modifiable-existing_ehr

Description

Set EHR modifiable of an existing EHR

Pre-conditions

An EHR with known ehr_id should exist.

Post-conditions

EHR_STATUS.is_modifiable, for the EHR with known ehr_id, should be true.

Flow

  1. For the existing EHR, invoke the set EHR modifiable service

  2. The result should be positive and the corresponding EHR_STATUS.is_modifiable should be true

Test runners

6.5.3.2. Test Case I_EHR_STATUS.set_ehr_modifiable-bad_ehr

Description

Set EHR modifiable of non-existing EHR

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None

Flow

  1. Invoke the set EHR modifiable service by a random ehr_id

  2. The result should be negative and the result should include an error e.g. "EHR with <ehr_id> doesn’t exist".

Test runners

6.5.4. Service Model operation: I_EHR_STATUS.clear_ehr_queryable()

Service Model reference: I_EHR_STATUS.clear_ehr_queryable()

6.5.4.1. Test Case I_EHR_STATUS.clear_ehr_queryable-existing_ehr

Description

Clear EHR queryable of an existing EHR

Pre-conditions

An EHR with known ehr_id should exist.

Post-conditions

EHR_STATUS.is_queryable, for the EHR with known ehr_id, should be false.

Flow

  1. For the existing EHR, invoke the clear EHR queryable service

  2. The result should be positive and the corresponding EHR_STATUS.is_queryable should be false

Test runners

6.5.4.2. Test Case I_EHR_STATUS.clear_ehr_queryable-bad_ehr

Description

Clear EHR queryable of non-existing EHR

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None

Flow

  1. Invoke the clear EHR queryable service by a random ehr_id

  2. The result should be negative and the result should include an error e.g. "EHR with <ehr_id> doesn’t exist".

Test runners

6.5.5. Service Model operation: I_EHR_STATUS.clear_ehr_modifiable()

Service Model reference: I_EHR_STATUS.clear_ehr_modifiable()

6.5.5.1. Test Case I_EHR_STATUS.clear_ehr_modifiable-existing_ehr

Description

Clear EHR modifiable of an existing EHR

Pre-conditions

An EHR with known ehr_id should exist.

Post-conditions

EHR_STATUS.is_modifiable, for the EHR with known ehr_id, should be false

Flow

  1. For the existing EHR, invoke the clear EHR modifiable service

  2. The result should be positive and the corresponding EHR_STATUS.is_modifiable should be false

Test runners

6.5.5.2. Test Case I_EHR_STATUS.clear_ehr_modifiable-bad_ehr

Description

Clear EHR modifiable of non existing EHR

Pre-conditions

The server should be empty (no EHRs, no commits, no OPTs).

Post-conditions

None

Flow

  1. Invoke the clear EHR modifiable service by a random ehr_id

  2. The result should be negative and the result should include an error e.g. "EHR with <ehr_id> doesn’t exist".

Test runners

7. Test Suite: EHR_SERVICE / I_COMPOSITION Interface

7.1. Normative Reference

Items in this validation suite conceptually use the following abstract interfaces from the Abstract Platform Service Model, EHR/COMPOSITION component.

  • I_EHR_COMPOSITION

These are concretely realised in implementation technology specfic APIs, such as the EHR REST API.

This test suite uses artefacts defined by the following information model specifications:

7.2. Dependencies

This test suite depends on other test suites:

7.3. Test Environment

  1. The server under test should support at least OPTs, 1.4 or 2, but OPT 1.4 if more frequent since modeling tools supporting this were around for a long time. Could also support ADL, 1.4 or 2.

  2. The server should support at least one of the XML or JSON representations of COMPOSITIONs for committing data, and integrate the corresponding schemas (XML or JSON) to validate data syntactically (before validating against an OPT).

7.4. Test Cases

7.4.1. Service Model operation: I_EHR_COMPOSITION.has_composition()

Service Model reference: I_EHR_COMPOSITION.has_composition()

7.4.1.1. Test Case I_EHR_COMPOSITION.has_composition

Description

Has existing COMPOSITION

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has a CONTRIBUTION

  3. The CONTRIBUTION contains a VERSION with known uid.

Post-conditions

None

Flow

  1. Invoke the has COMPOSITION service for the ehr_id and VERSION.uid

  2. The result must be TRUE

Test runners

7.4.1.2. Test Case I_EHR_COMPOSITION.has_composition-bad_composition

Description

Has COMPOSITION, COMPOSITION doesn’t exist

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has no CONTRIBUTIONs

Post-conditions

None

Flow

  1. Invoke the has COMPOSITION service for ehr_id, and a random VERSION.uid

  2. The result must be FALSE

Test runners

7.4.1.3. Test Case I_EHR_COMPOSITION.has_composition-bad_ehr

Description

Has COMPOSITION on non-existent EHR

Pre-conditions

  1. There are no EHRs on the server

Post-conditions

None

Flow

  1. Invoke the has COMPOSITION service with a random ehr_id

  2. The service should return an error related to the non existence of the EHR

Test runners

7.4.2. Get COMPOSITION latest

Implementation consideration:

When a COMPOSITION is retrieved from a service, it will comply with a specific format. There could be a variant for each test to retrieve the COMPOSITION in any of the supported openEHR formats, and the syntactic validation of those retrieved formats should be done by using the corresponding schemas (XML, JSON, etc). That would be the minimal validation for conformance testing. Though it would be ideal to have semantic validation of the retrieved COMPOSITIONs to ensure conformance, which is achieved by validating against the corresponding OPT in the testing layer.

7.4.2.1. Test Case I_EHR_COMPOSITION.get_composition_latest

Description

Get existing COMPOSITION latest

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has a VERSIONED_COMPOSITION with known uid

  3. The VERSIONED_COMPOSITION has two VERSIONs

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION latest service for the ehr_id and VERSIONED_COMPOSITION uid

  2. The result must return the COMPOSITION contents, and should be the latest version

  3. The retrieved format should contain all the exact same data as the format used when committing the COMPOSITION (content check)

Test runners

7.4.2.2. Test Case I_EHR_COMPOSITION.get_composition_latest-bad_composition

Description

Get COMPOSITION latest, COMPOSITION doesn’t exist

Pre-conditions

  1. An EHR with known ehr_id exists and has no CONTRIBUTIONs

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION latest service for ehr_uid, and a random VERSIONED_COMPOSITION uid

  2. The result must be empty, with an error “the COMPOSITION uid doesn’t exist in the EHR ehr_uid”

Test runners

7.4.2.3. Test Case I_EHR_COMPOSITION.get_composition_latest-bad_ehr

Description

Get COMPOSITION latest on non-existent EHR

Pre-conditions

  1. There are no EHRs on the server

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION latest service with a random ehr_id, and a random VERSIONED_COMPOSITION uid

  2. The service should return an error related to the non existence of the EHR

Test runners

7.4.3. Get COMPOSITION at time

7.4.3.1. Test Case I_EHR_COMPOSITION.get_composition_at_time

Description

Get existing COMPOSITION at time

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has one or more VERSIONED_COMPOSITIONs with known uids

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at time service for the ehr_id, VERSIONED_COMPOSITION.uid and current time

  2. The result must return the COMPOSITION contents of the existing COMPOSITION at given time

  3. The retrieved format should contain all the exact same data as the format used when committing the COMPOSITION (content check)

    NOTE: When requesting a `COMPOSITION` at time using the current time, the last version of the matching composition, if it exists, should be retrieved.

Test runners

7.4.3.2. Test Case I_EHR_COMPOSITION.get_composition_at_time-no_time_arg

Description

Get existing COMPOSITION at time, without a given time

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has one or more VERSIONED_COMPOSITIONs with known uids

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at time service for the ehr_id, VERSIONED_COMPOSITION uid and no time

  2. The result must return the COMPOSITION contents of the existing COMPOSITION, and should be the latest VERSION of the COMPOSITION

  3. The retrieved format should contain all the exact same data as the format used when committing the COMPOSITION (content check)

    NOTE: Test this using `COMPOSITIONs` with one version and multiple versions, to be sure the retrieved one is the latest; +
    The previous tests for "`get COMPOSITION latest`" could be used to compare results.

Test runners

7.4.3.3. Test Case I_EHR_COMPOSITION.get_composition_at_time-bad_composition

Description

Get COMPOSITION at time, COMPOSITION doesn’t exist

Pre-conditions

  1. An EHR with known ehr_id exists and has no CONTRIBUTIONs

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at time service for ehr_uid, and a random VERSIONED_COMPOSITION.uid and current time

  2. The result must be empty, with an error related to “the COMPOSITION uid doesn’t exist in the EHR ehr_uid”

Test runners

7.4.3.4. Test Case I_EHR_COMPOSITION.get_composition_at_time-bad_ehr

Description

Get COMPOSITION at time on non-existent EHR

Pre-conditions

  1. There are no EHRs on the server

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at time service with a random ehr_id, random VERSIONED_OBJECT.uid and current time

  2. The service should return an error indicating non-existence of the EHR

Test runners

7.4.3.5. Test Case I_EHR_COMPOSITION.get_composition_at_times

Description

Get existing COMPOSITION at time, cover different times

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR should have one VERSIONED_COMPOSITION with a know uid

  3. The VERSIONED_COMPOSITION should have two VERSIONs (the EHR has two CONTRIBUTIONs for the same COMPOSITION)

  4. CONTRIBUTIONs were done at times t0 and t1 with t0 < t1

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at time service for the ehr_id, VERSIONED_COMPOSITION uid and a time < t0

  2. The result must be negative and return an error related to the COMPOSITION not existing at that time

  3. Invoke the get COMPOSITION at time service for the ehr_id, VERSIONED_COMPOSITION uid and a time > t0 and < t1

  4. The result must return the COMPOSITION contents of the COMPOSITION committed in t0

  5. The retrieved format should contain all the exact same data as the format used when committing the COMPOSITION (content check)

  6. Invoke the get COMPOSITION at time service for the ehr_id, VERSIONED_COMPOSITION uid and a time > t1

  7. The result must return the COMPOSITION contents of the COMPOSITION committed in t1

  8. The retrieved format should contain all the exact same data as the format used when committing the COMPOSITION (content check)

Test runners

7.4.4. Get COMPOSITION at version

7.4.4.1. Test Case I_EHR_COMPOSITION.get_composition_version

Description

Get existing COMPOSITION at version

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has one VERSION with known version id

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at version service for the ehr_id, VERSION version id

  2. The result must return the COMPOSITION contents of the existing VERSION

  3. The retrieved format should contain all the exact same data as the format used when committing the COMPOSITION (content check)

Test runners

7.4.4.2. Test Case I_EHR_COMPOSITION.get_composition_version-bad_version

Description

Get COMPOSITION at version, VERSION doesn’t exist

Pre-conditions

  1. An EHR with known ehr_id exists and doesn’t have any commits

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at version service for the ehr_id, and a random version id

  2. The result must be negative and return an error related to the non-existent COMPOSITION with the version id

Test runners

7.4.4.3. Test Case I_EHR_COMPOSITION.get_composition_version-bad_ehr

Description

Get COMPOSITION at version, EHR doesn’t exist

Pre-conditions

  1. The system doesn’t have any EHRs

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at version service a random ehr_id and random version id

  2. The result must be negative and return an error related to the non-existent EHR.

Test runners

7.4.4.4. Test Case I_EHR_COMPOSITION.get_composition_versions

Description

Get COMPOSITION at version, cover different versions

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR should have one VERSIONED_COMPOSITION with a known uid

  3. The VERSIONED_COMPOSITION should have two VERSIONs (the EHR has two CONTRIBUTIONs for the same COMPOSITION)

  4. Both VERSIONs have ids: v1 and v2

Post-conditions

None

Flow

  1. Invoke the get COMPOSITION at version service, for the ehr_id and VERSION version id v1

  2. The result must be positive and retrieve the COMPOSITION, that should match the COMPOSITION created with version id v1. (content check).

  3. Invoke the get COMPOSITION at version service, for the ehr_id and VERSION version id v2

  4. The result must be positive and retrieve the COMPOSITION, that should match the COMPOSITION created with version id v2 (content check).

Test runners

7.4.5. Get VERSIONED COMPOSITION

7.4.5.1. Test Case I_EHR_COMPOSITION.get_versioned_composition

Description

Get existing VERSIONED_COMPOSITION

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has one VERSIONED_COMPOSITION with known uid

Post-conditions

None

Flow

  1. Invoke the get VERSIONED_COMPOSITION service for the ehr_id and VERSIONED_COMPOSITION uid

  2. The result must return a valid VERSIONED_COMPOSITION object, referencing the VERSION it contains

Test runners

Note
To consider different cases, try with VERSIONED_COMPOSITION that contain just one VERSION or many VERSIONs
Note
For that, the valid test cases for Create COMPOSITION could be used to comply with the preconditions of this test flow
7.4.5.2. Test Case I_EHR_COMPOSITION.get_versioned_composition-non_existent

Description

Get non-existent VERSIONED_COMPOSITION

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR doesn’t have any commits

Post-conditions

None

Flow

  1. Invoke the get VERSIONED_COMPOSITION service for the ehr_id and a random VERSIONED_COMPOSITION uid

  2. The result must be negative and return an error related to the non-existence of the VERSIONED_COMPOSITION

Test runners

7.4.5.3. Test Case I_EHR_COMPOSITION.get_versioned_composition-bad_ehr

Description

Get VERSIONED_COMPOSITION, EHR doesn’t exist

Pre-conditions

  1. The system doesn’t have any EHRs

Post-conditions

None

Flow

  1. Invoke the get VERSIONED_COMPOSITION service for a random ehr_id and a random VERSIONED_COMPOSITION uid

  2. The result must be negative and return an error related to the non-existence of the EHR

Test runners

7.4.6. Create COMPOSITION

Service Model reference: I_EHR_COMPOSITION.create_composition()

7.4.6.1. Test Case I_EHR_COMPOSITION.create_composition-event

Description

Create new event COMPOSITION

Pre-conditions

  1. The OPT, associated with the event COMPOSITION that will be created, should exist on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

A new event COMPOSITION exists in the EHR.

Flow

  1. Invoke the create COMPOSITION service with a valid event COMPOSITION, compliant with the existing OPT, and with the known ehr_id

  2. The result should be positive, return information about the new COMPOSITION added to the EHR, and the version number should be 1

Test runners

7.4.6.2. Test Case I_EHR_COMPOSITION.create_composition-persistent

Description

Create new persistent COMPOSITION

Pre-conditions

  1. The OPT, associated with the persistent COMPOSITION that will be created, should exist on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

A new persistent COMPOSITION exists in the EHR.

Flow

  1. Invoke the create COMPOSITION service with a valid persistent COMPOSITION, compliant with the existing OPT, and the known ehr_id

  2. The result should be positive, and return information about the new COMPOSITION added to the EHR, and the version number should be 1

Test runners

7.4.6.3. Test Case I_EHR_COMPOSITION.create_composition-same_opt_twice

Description

Create persistent COMPOSITION for the same OPT twice

Pre-conditions

  1. The OPT, associated with the persistent COMPOSITION that will be created, should exist on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

A new persistent COMPOSITION exists in the EHR.

Flow

  1. Invoke the create COMPOSITION service with a valid persistent COMPOSITION, compliant with the existing OPT, and with the known ehr_id

  2. The result should be positive, and return information about the new COMPOSITION added to the EHR, and the version number should be 1

  3. Invoke the create COMPOSITION service with a valid persistent COMPOSITION and the same ehr_id as in 1., the COMPOSITION should comply with the same persistent OPT as the COMPOSITION in 1

  4. The result should be negative, returning an error related to trying to create a persistent COMPOSITION for the same persistent OPT that already has a first version

Test runners

Notes:

  1. Current criteria is: only one ‘create’ operation is allowed for persistent COMPOSITIONs, the next operations over an existing persistent COMPOSITION should be ‘modifications’.

  2. This is under debate in the openEHR SEC since some implementations permit 'persistent' COMPOSIITONS to have more than one instance in the same EHR and some others not. This is due to the lack of information in the openEHR specifications. There is also a discussion to define other types of categories for COMPOSITIONs to allow different behaviors.

7.4.6.4. Test Case I_EHR_COMPOSITION.create_composition-invalid_event

Description

Create new invalid event COMPOSITION

Pre-conditions

  1. The OPT, associated with the event COMPOSITION that will be created, should exist on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

None

Flow

  1. Invoke the create COMPOSITION service with an invalid event COMPOSITION and the known ehr_id

  2. The result should be negative, and return information about the errors in the provided COMPOSITION

Test runners

7.4.6.5. Test Case I_EHR_COMPOSITION.create_composition-invalid_persistent

Description

Create new invalid persistent COMPOSITION

Pre-conditions

  1. The OPT, associated with the persistent COMPOSITION that will be created, should exist on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

None

Flow

  1. Invoke the create COMPOSITION service with an invalid persistent COMPOSITION and the known ehr_id

  2. The result should be negative, and return information about the errors in the provided COMPOSITION

Test runners

7.4.6.6. Test Case I_EHR_COMPOSITION.create_composition-event_bad_opt

Description

Create new event COMPOSITION, referenced OPT doesn’t exist

Pre-conditions

  1. The OPT, referenced by the COMPOSITION to commit, doesn’t exist on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

None

Flow

  1. Invoke the create COMPOSITION service with a valid event COMPOSITION and the known ehr_id

    1. The COMPOSITION should reference an OPT that doesn’t exist on the server

  2. The result should be negative, and return information about the non-existent OPT

Test runners

7.4.6.7. Test Case I_EHR_COMPOSITION.create_composition-event_bad_ehr

Description

Create new event COMPOSITION, EHR doesn’t exist

Pre-conditions

  1. The OPT, referenced by the COMPOSITION to commit, exists on the server

  2. The server doesn’t have any EHRs

Post-conditions

None

Flow

  1. Invoke the create COMPOSITION service with a valid event COMPOSITION and a random ehr_id

  2. The result should be negative, and return information about the non-existent EHR

Test runners

7.4.7. Update COMPOSITION

The update COMPOSITION service needs the VERSION.preceding_version_uid attribute to be set, so the server knows which existing VERSION of the COMPOSITION will be associated with the newly committed COMPOSITION. The Service Model spec is not clear about where that attribute is defined. By taking into account the Reference Model, the COMPOSITION doesn’t contain that value but the VERSION does. For the COMPOSITION update service the preceding_version_uid should be a parameter or the definition in the SM should mention this.

Service Model reference: I_EHR_COMPOSITION.update_composition()

7.4.7.1. Test Case I_EHR_COMPOSITION.update_composition-event

Description

Update an existing event COMPOSITION

Pre-conditions

  1. The OPT referenced by the COMPOSITIONs to commit exists on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

  1. A new VERSIONED_OBJECT exists on the server

  2. The VERSIONED_OBJECT has two VERSIONs of COMPOSITION

  3. One VERSION.commit_audit.change_type is CREATE, the other one is MODIFY

Flow

  1. Invoke the create COMPOSITION service with a valid event COMPOSITION and the existing ehr_id

    1. The COMPOSITION reference the existing OPT

  2. The result should be positive and a new COMPOSITION should exist in the EHR

  3. Invoke the update COMPOSITION service with a valid event COMPOSITION to the existing ehr_id and preceding_version_uid should be the version uid from the COMPOSITION created in 1

    1. This COMPOSITION has the same OPT as the COMPOSITION created in 1

  4. The result should be positive and a new version of the existing COMPOSITION should exist in the EHR

Test runners

7.4.7.2. Test Case I_EHR_COMPOSITION.update_composition-persistent

Description

Update an existing persistent COMPOSITION

Pre-conditions

  1. The OPT referenced by the COMPOSITIONs to commit exists on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

  1. The server should contain one VERSIONED_OBJECT

  2. The VERSIONED_OBJECT should have two VERSIONs of COMPOSITION

  3. The COMPOSITIONs should comply with the existing OPT

Flow

  1. Invoke the create COMPOSITION service with a valid persistent COMPOSITION and the existing ehr_id

    1. The OPT referenced by this COMPOSITION exists on the server

  2. The result should be positive and a new COMPOSITION should exist in the EHR

  3. Invoke the update COMPOSITION service with a valid persistent COMPOSITION, to the existing ehr_id

    1. that has the same template as the COMPOSITION created in 1.,

    2. preceding_version_uid should be the VERSION.uid from the COMPOSITION created in 1

  4. The result should be positive and a new version of the existing COMPOSITION should exist in the EHR

Test runners

7.4.7.3. Test Case I_EHR_COMPOSITION.update_composition-non_existent

Description

Update a non-existing COMPOSITION

Pre-conditions

  1. The OPT referenced by the COMPOSITIONs to commit exists on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

None

Flow

  1. Invoke the update COMPOSITION service with a valid event COMPOSITION, the existing ehr_id and preceding_version_uid should be a random value

    1. The COMPOSITION should comply with the existing OPT

  2. The result should be negative and return an error related to the non-existence of the preceding_version_id

Test runners

7.4.7.4. Test Case I_EHR_COMPOSITION.update_composition-wrong_template

Description

Update an existing COMPOSITION, referencing a different template

Pre-conditions

  1. The OPTs, referenced by the COMPOSITIONs to commit, exist on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

  1. The server has a new VERSIONED_OBJECT

  2. The VERSIONED_OBJECT has one version of a COMPOSITION

Flow

  1. Invoke the create COMPOSITION service with a valid event COMPOSITION and the existing ehr_id

    1. The OPT referenced by this COMPOSITION exists on the server

  2. The result should be positive and a new COMPOSITION should exist in the EHR

  3. Invoke the update COMPOSITION service with a valid event COMPOSITION, to the existing ehr_id and preceding_version_uid should be the version uid from the COMPOSITION created in 1

    1. The COMPOSITION references a different template than the one referenced by the COMPOSITION created in 1.

    2. The OPT referenced by this COMPOSITION exists on the server

  4. The result should be negative and return an error related to the template_id mismatch

Test runners

7.4.8. Delete COMPOSITION

Service Model reference: I_EHR_COMPOSITION.delete_composition()

7.4.8.1. Test Case I_EHR_COMPOSITION.delete_composition-event

Description

Delete event COMPOSITION

Pre-conditions

  1. The OPT referenced by the COMPOSITIONs to commit exists on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

  1. The server has one VERSIONED_OBJECT

  2. The VERSIONED_OBJECT contains two versions of COMPOSITION

  3. The second VERSION.lifecycle_state value is the code `openehr::523

deleted

`

Flow

  1. Invoke the create COMPOSITION service with a valid event COMPOSITION and the existing ehr_id

    1. The COMPOSITION complies with the existing OPT

  2. The result should be positive and a new COMPOSITION should exist in the EHR

  3. Invoke the delete COMPOSITION service with the existing ehr_id and preceding_version_uid should be the version id of the COMPOSITION created in 1

  4. The result should be positive, and the COMPOSITION should be deleted

Test runners

Note
The common implementation of the delete operation is two create a new VERSION of the COMPOSITION that has VERSION.commit_audit.change_type = openehr::523|deleted|, and VERSION.lifecycle_state = openehr::523|deleted|. So the delete operation is not a physical delete but a logical delete. Some implementations might add the option of a physical deleted. This test case considers the postcondition to be a logical delete, which behaves like an update operation in which a new VERSION of an existing COMPOSITION is created.
7.4.8.2. Test Case I_EHR_COMPOSITION.delete_composition-persistent

Description

Delete persistent COMPOSITION

Pre-conditions

  1. The OPT referenced by the COMPOSITIONs to commit exists on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

  1. The server has one VERSIONED_OBJECT

  2. The VERSIONED_OBJECT contains two versions of COMPOSITION

  3. The second VERSION.lifecycle_state value is the code `openehr::523

deleted

`

Flow

  1. Invoke the create COMPOSITION service with a valid persistent COMPOSITION and the existing ehr_id

    1. The COMPOSITION complies with the existing OPT

  2. The result should be positive and a new COMPOSITION should exist in the EHR

  3. Invoke the delete COMPOSITION service with the existing ehr_id and preceding_version_uid should be the version id of the COMPOSITION created in 1

  4. The result should be positive, and the COMPOSITION should be deleted

Test runners

7.4.8.3. Test Case I_EHR_COMPOSITION.delete_composition-non_existent

Description

Delete persistent COMPOSITION

Pre-conditions

  1. The OPT referenced by the COMPOSITIONs to commit exists on the server

  2. An EHR with known ehr_id should exist

  3. The EHR should have no commits

Post-conditions

None

Flow

  1. Invoke the delete COMPOSITION service with the existing ehr_id and a random preceding_version_uid

  2. The result should be negative and return an error related to the non-existent COMPOSITION

Test runners

8. Test Suite: EHR_SERVICE / I_CONTRIBUTION Interface

8.1. Normative Reference

Items under this validation suite conceptually use these abstract interfaces from the Abstract Platform Service Model, EHR/EHR_CONTRIBUTION component.

8.2. Dependencies

This test suite depends on other test suites:

8.3. Test Environment

  1. The server under test should support at least OPTs, 1.4 or 2, but OPT 1.4 if more frequent since modeling tools supporting this were around for a long time. Could also support ADL, 1.4 or 2.

  2. The server should support at least one of the XML or JSON representations of CONTRIBUTIONs for committing data, and integrate the corresponding schemas (XML or JSON) to validate data syntactically (before validating against an OPT).

8.4. Test Data Sets

8.4.1. General CONTRIBUTION Commit Data Sets

  1. CONTRIBUTIONs with single valid VERSION<COMPOSITION> (minimal, one for each entry type)

  2. CONTRIBUTIONs with multiple valid VERSION<COMPOSITION> (reuse the minimal ^)

  3. CONTRIBUTION with single valid VERSION<COMPOSITION> with maximal data sets

  4. Empty CONTRIBUTION (no VERSIONs)

  5. CONTRIBUTIONs with invalid VERSION<COMPOSITION>

    1. Invalid data

    2. Wrong change_type

    3. Wrong lifecycle

  6. CONTRIBUTIONs with multiple VERSION<COMPOSITION>, with mixed valid and invalid ones

Note
these cases do not consider which RM type is contained in the VERSIONs, it could be COMPOSITION, FOLDER, EHR_STATUS, etc.

8.4.2. COMPOSITION CONTRIBUTION Commit Data Sets

Since there are many combinations of data that could be used for testing the Commit CONTRIBUTION service, we decided to create three main kinds of CONTRIBUTIONs that should be tested:

  1. Valid

    1. minimal COMPOSITIONs with one type of ENTRY (one ENTRY each, all ENTRYs covered)

    2. maximal COMPOSITION (all data types, all ENTRY types, and SECTIONs)

    3. a persistent COMPOSITION (e.g. problem list, medication list, immunization list, …)

    4. time series COMPOSITION (observation with many events, e.g. CPR compressions intervals)

    5. COMPOSITION with alternative types (e.g. lab result DV_COUNT, DV_QUANTITY and DV_CODED_TEXT)

    6. COMPOSITION with DV_CODED_TEXT instance on nodes declared as DV_TEXT in the OPT

    7. COMPOSITION with empty ELEMENT.value and not empty ELEMENT.null_flavour

  2. Invalid

    1. Invalid COMPOSITIONs (e.g. mandatory items not present, wrong types, extra items not declared in OPT, invalid values)

    2. Referenced OPT not loaded (this has to do more with the state of the system than to invalid data)

  3. Change type combinations (these are the minimal required, all supported change types can be found in the openEHR Terminology)

    1. VERSION.commit_audit.change_type = creation

    2. VERSION.commit_audit.change_type = modification

    3. VERSION.commit_audit.change_type = delete

Note
there could be many combinations of flows to use the different Change Types mentioned above. The minimal required by this specification it that the server is capable of this flow: 1. creation 2. modification (one or many times) 3. deleted
8.4.2.1. Data Set Considerations

change_type

Each VERSION in a CONTRIBUTION has an AUDIT_DETAILS which contains a change_type attribute. The value on that attribute determines the internal behavior for processing each VERSION, and each VERSION in the same CONTRIBUTION could have a different change_type. The most used change types are:

  1. creation: the VERSION represents the first version of a COMPOSITION.

  2. amendment: the VERSION represents a new version of an existing COMPOSITION, with the purpose of adding data.

  3. modification: the VERSION represents a new version of an existing COMPOSITION, with the purpose of changing data, maybe to fix an error.

  4. deleted:the VERSION represents a new version of an existing COMPOSITION, with the purpose of deleting it.

Internally, amendment and modification might be processed in the exact same way, because the difference is semantic not functional.

lifecycle_state

Each VERSION in a CONTRIBUTION contains an lifecycle_state attribute, which value gives semantics about the contents of the VERSION. The values could be:

  1. incomplete: the COMPOSITION was committed incomplete and should be completed (reviewed, validated, amended) later.

  2. complete: the COMPOSITION was complete at the moment it was committed.

  3. deleted: the COMPOSITION was committed for deletion.

These codes are defined in the openEHR Terminology.

lifecycle state machine

8.4.2.2. Combinations of data sets

These combinations can be tested by doing a single commit. The same combinations with flows of multiple commits could lead to different results.

One commit (no previous commits were done), single version cases:

Note
All change types but creation should fail on the first commit, since other change types need a previous commit. Last one could fail because the first commit can’t be change_type = deleted or because the lifecycle_state = |complete| can’t be with change_type = deleted.
change_type lifecycle_state* composition category composition validity** expected

creation

complete

event

valid

accepted

amendment

complete

event

valid

rejected

modification

complete

event

valid

rejected

deleted

complete

event

valid

rejected

creation

complete

persistent

valid

accepted

amendment

complete

persistent

valid

rejected

modification

complete

persistent

valid

rejected

deleted

complete

persistent

valid

rejected

creation

deleted

event

valid

rejected

amendment

deleted

event

valid

rejected

modification

deleted

event

valid

rejected

deleted

deleted

event

valid

rejected

Note
the incomplete cases should be equal to the complete, because the flag is just adding semantics about the content, not setting how the content should be processed.
Note
the invalid cases will make the accepted cases on the previous table to be rejected because the content in the COMPOSITION is not valid.

One commit (no previous commits were done), multiple versions cases:

Note
the tables below represent one VERSION in the committed CONTRIBUTION.
  1. Creating two valid, complete event COMPOSITIONs in one commit should be accepted.

    change_type+ lifecycle_state++ composition category composition validity

    creation

    complete

    event

    valid

    creation

    complete

    event

    valid

    This CONTRIBUTION should be accepted.

  2. Creating two valid, complete persistent COMPOSITIONs in one commit should be accepted.

    Note
    depending on the server implementation, some servers might not accept the second COMPOSITION if both COMPOSITIONs reference the same persistent OPT. So this test case considers both COMPOSITIONs reference different persistent OPTs.
    change_type+ lifecycle_state++ composition category composition validity

    creation

    complete

    persistent

    valid

    creation

    complete

    persistent

    valid

    This CONTRIBUTION should be accepted.

  3. Creating two valid, complete and mixed category COMPOSITIONs in one commit should be accepted.

    change_type+ lifecycle_state++ composition category composition validity

    creation

    complete

    event

    valid

    creation

    complete

    persistent

    valid

    This CONTRIBUTION should be accepted.

  4. If any COMPOSITION is invalid in a CONTRIBUTION, the whole commit should fail. It doesn’t matter if it is complete or incomplete, event or persistent (just showing some of the combinations below).

    change_type+ lifecycle_state++ composition category composition validity

    creation

    complete

    event

    valid

    creation

    complete

    event

    invalid

    change_type+ lifecycle_state++ composition category composition validity

    creation

    complete

    persistent

    valid

    creation

    complete

    persistent

    invalid

    change_type+ lifecycle_state++ composition category composition validity

    creation

    complete

    event

    valid

    creation

    complete

    persistent

    invalid

    change_type+ lifecycle_state++ composition category composition validity

    creation

    complete

    event

    invalid

    creation

    complete

    persistent

    valid

    These CONTRIBUTIONs should be REJECTED.

Note
(+) for other change types than creation, the first commit will be rejected, so not included in the table those cases but should be tested.
Note
(++) the incomplete cases should be equal to the complete, because the flag is just adding semantics about the content, not setting how the content should be processed.

8.4.3. EHR_STATUS CONTRIBUTION Commit Data Sets

8.4.3.1. Combinations for data sets

The following accepted and rejected apply under any of these scenarios:

  1. The server has an EHR with the default EHR_STATUS (the EHR was created without providing an EHR_STATUS).

  2. The server has an EHR created by providing an EHR_STATUS.

  3. The server has an EHR with modifications already done to its EHR_STATUS (consecutive modifications).

Reject Cases:

  1. CONTRIBUTIONs with VERSION, where VERSION.commit_audit.change_type IN [creation, deleted] should be rejected, because the default EHR_STATUS was already created in the EHR, and the EHR_STATUS can’t be deleted once created.

  2. CONTRIBUTIONs with VERSION, where VERSION.lifecycle_state = incomplete should be rejected, because the incomplete state doesn’t apply to EHR_STATUS. Though there is an open issue related to this: https://specifications.openehr.org/jira/browse/SPECPR-368

  3. Any other case with an invalid EHR_STATUS in VERSION should also be rejected.

Accepted Cases:

  1. CONTRIBUTIONs with VERSION where VERSION.commit_audit.change_type IN [modification, amendment] and valid EHR_STATUS, should be accepted. This inscludes the following combinations for EHR_STATUS:

is_modifiable is_queryable subject.external_ref

true

true

HIER_OBJECT_ID

true

true

GENERIC_ID

true

true

NULL

true

false

HIER_OBJECT_ID

true

false

GENERIC_ID

true

false

NULL

false

true

HIER_OBJECT_ID

false

true

GENERIC_ID

false

true

NULL

false

true

HIER_OBJECT_ID

false

true

GENERIC_ID

false

true

NULL

false

false

HIER_OBJECT_ID

false

false

GENERIC_ID

false

false

NULL

Note
Since EHR_STATUS is LOCATABLE, is should have an archetype_id assigned. It is recommended to test the combination described above, combined with different values for EHR_STATUS.archetype_id.

8.4.4. FOLDER CONTRIBUTION Commit Data Sets

All the datasets are specified at the EHR.directory level, since that is the current level of operation of the openEHR REST API for FOLDERs to create, update or delete.

8.4.4.1. Data Set Combinations

Valid payload should include these cases:

  1. minimal directory

  2. directory with items

  3. directry with subfolders

  4. directory with items and subfolders

  5. directory with items and subfolders with items

Sample structure of FOLDERs with items:

Folders with items

Table of data combinations:

change_type lifecycle_state payload expected

creation

complete / incomplete

valid

accepted

amendment / modification

complete / incomplete

valid

accepted

deleted

deleted

valid

accepted

Any invalid payload should be rejected.

8.5. Test Cases

8.5.1. Service Model operation: I_EHR_CONTRIBUTION.commit_contribution()

Service Model reference: I_EHR_CONTRIBUTION.commit_contribution()

8.5.1.1. Test Case I_EHR_CONTRIBUTION.commit_contribution-valid_composition

Description

Successfully commit CONTRIBUTION of COMPOSITION

Pre-conditions

  1. An EHR with known ehr_id exists

  2. OPTs for each valid cases are loaded on the server

Post-conditions

  1. The EHR with ehr_id should have a new CONTRIBUTION

  2. The ID(s) of the created VERSION(s) are correct

    1. the version ID matches the change_type executed (creation = 1, modification/amendment = 2, 3, …)

    2. ID(s) can be used to retrieve a VERSION<COMPOSITION>)

Flow

  1. Invoke commit CONTRIBUTION service with the existing ehr_id and valid data sets

    1. The COMPOSITIONs reference existing OPTs on the server

  2. The result should be positive and retrieve the id of the CONTRIBUTION just created

Test runners

8.5.1.2. Test Case I_EHR_CONTRIBUTION.commit_contribution-invalid_composition

Description

Commit CONTRIBUTION with invalid COMPOSITION

Pre-conditions

  1. An EHR with known ehr_id exists

  2. OPTs for each valid cases are loaded on the server

Post-conditions

None

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the invalid VERSION<COMPOSITION>

    1. The COMPOSITIONs reference existing OPTs on the server

  2. The result should be negative and provide info about the errors with the data committed

Test runners

8.5.1.3. Test Case I_EHR_CONTRIBUTION.commit_contribution-empty

Description

Commit CONTRIBUTION with no content.

Pre-conditions

  1. An EHR with known ehr_id exists

Post-conditions

None

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and no data in the CONTRIBUTION

  2. The result should be negative and retrieve an error indicating the empty list of VERSION<COMPOSITION> in the CONTRIBUTION

Test runners

8.5.1.4. Test Case I_EHR_CONTRIBUTION.commit_contribution-valid_invalid_compositions

Description

Commit CONTRIBUTION with mixed valid and invalid COMPOSITIONs.

Pre-conditions

  1. An EHR with known ehr_id exists

  2. OPTs for each valid cases are loaded on the server

Post-conditions

None

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and multiple VERSION<COMPOSITION>

    1. Some VERSIONs are valid, some aree invalid

    2. The COMPOSITIONs reference existing OPTs on the server

  2. The result should be negative and retrieve an error related invalid VERSION<COMPOSITION>

Test runners

Note
the whole commit should behave like a transaction and fail, no CONTRIBUTIONs or VERSIONs should be created on the server.
8.5.1.5. Test Case I_EHR_CONTRIBUTION.commit_contribution-event_composition

Description

Commit CONTRIBUTION with event COMPOSITION.

Pre-conditions

  1. An EHR with known ehr_id exists

  2. OPTs for each valid cases are loaded on the server

Post-conditions

  1. There should be two VERSIONs of the same COMPOSITION in the EHR with ehr_id

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION has category = event

    2. The COMPOSITION reference existing an OPT on the server

  2. The result should be positive, returning the created CONTRIBUTION with the ID of the created VERSION<COMPOSITION>

  3. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION should have the same template_id as the one used in 1.

    2. The VERSION change_type = modification and preceding_version_uid = version id returned in 2.

  4. The result should be positive and the returned version id should reflect it’s a new version of an existing COMPOSITION created in 1. (has the same OBJECT_VERSION_ID with version number = 2)

Test runners

8.5.1.6. Test Case I_EHR_CONTRIBUTION.commit_contribution-persistent_composition

Description

Commit CONTRIBUTION with persistent COMPOSITIONs.

Pre-conditions

  1. An EHR with known ehr_id exists

  2. OPTs for each valid case are loaded on the server

Post-conditions

  1. There should be two VERSIONs of the same COMPOSITION in the EHR with ehr_id

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION.category = persistent

    2. The COMPOSITION references an existing OPT on the server

  2. The result should be positive, returning the version id for the created VERSION

  3. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION should have the same template_id as the one used in 1.

    2. The VERSION.change_type = modification

    3. The VERSION.preceding_version_uid = version id returned in 2.,

  4. The result should be positive and the returned version id should reflect it is a new version of an existing COMPOSITION created in 1. (has the same OBJECT_VERSION_ID with version number = 2)

Test runners

8.5.1.7. Test Case I_EHR_CONTRIBUTION.commit_contribution-delete

Description

Commit CONTRIBUTION deleting a COMPOSITION.

Pre-conditions

  1. An EHR with known ehr_id exists

  2. OPTs for each valid case are loaded on the server

Post-conditions

  1. Two VERSIONs of the same COMPOSITION should exist in the EHR with ehr_id

  2. The VERSIONED_OBJECT should be logically deleted NOTE: the effect of a VERSIONED_OBJECT being deleted might vary in different implementations. This needs further specification at the openEHR Service Model

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION references an existing OPT on the server

  2. The result should be positive, returning the version id for the created VERSION

  3. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION should reference the same template_id as the one used in 1.

    2. The VERSION.change_type = deleted

    3. The VERSION.preceding_version_uid = version id returned in 2.

  4. The result should be positive and the returned version id should reflect it is a new version of an existing COMPOSITION created in 1. (has the same OBJECT_VERSION_ID with version number = 2, which should be deleted)

Test runners

8.5.1.8. Test Case I_EHR_CONTRIBUTION.commit_contribution-two_commits_second_invalid

Description

Commit two CONTRIBUTIONa on same COMPOSITION with second containing invalid content.

Pre-conditions

  1. An EHR with known ehr_id exists

  2. OPTs for each valid case are loaded on the server

Post-conditions

  1. There will be just one VERSION in the EHR with ehr_id

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION references an existing OPT on the server

  2. The result should be positive, returning the version id for the created VERSION

  3. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION references the same template_id as the one used in 1.

    2. The VERSION has change_type = modification

    3. The VERSION has preceding_version_uid = version id returned in 2.

    4. The COMPOSITION is one of the invalid data sets

  4. The result should be negative, and retrieve some info about the errors found on the data committed

Test runners

8.5.1.9. Test Case I_EHR_CONTRIBUTION.commit_contribution-two_commits_second_creation

Description

Commit two CONTRIBUTIONa on same COMPOSITION with second having change_type = creation

Pre-conditions

  1. An EHR with known ehr_id exists

  2. OPTs for each valid case are loaded on the server

Post-conditions

  1. There will be just one VERSION in the EHR with ehr_id

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION references an existing OPT on the server

  2. The result should be positive, returning the version id for the created VERSION

  3. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION references the same template_id as the one used in 1.

    2. The VERSION.change_type = creation

    3. The VERSION.preceding_version_uid = version id returned in 2.

  4. The result should be negative, and retrieve some info about the wrong change type (see notes)

Test runners

Note
Validity criterion: only one 'create' operation is allowed for persistent COMPOSITIONs, the next operations over an existing persistent COMPOSITION should be modification.
8.5.1.10. Test Case I_EHR_CONTRIBUTION.commit_contribution-non_exiting_opt

Description

Commit CONTRIBUTION with COMPOSITION referencing a non existing OPT

Pre-conditions

  1. An EHR with known ehr_id exists

  2. There are no OPTs loaded on the server

Post-conditions

None

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and a valid VERSION<COMPOSITION>

    1. The COMPOSITION references a random OPT template_id

  2. The result should be negative and retrieve an error indicating the missing OPT

Test runners

8.5.1.11. Test Case I_EHR_CONTRIBUTION.commit_contribution-minimal_ehr_status

Description

Commit CONTRIBUTION containing minimal EHR_STATUS

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR contains a default EHR_STATUS

Post-conditions

  1. The EHR should have a new CONTRIBUTION

  2. The EHR should have a new VERSION for the EHR_STATUS

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the valid data sets (see section B.3.)

    1. For EHR_STATUS CONTRIBUTIONs, the change_type is always modification or amendment

  2. The result should be positive and retrieve the id of the CONTRIBUTION just created

  3. Verify expected CONTRIBUTION uids and CONTRIBUTION count for the EHR with ehr_id

Test runners

8.5.1.12. Test Case I_EHR_CONTRIBUTION.commit_contribution-full_ehr_status
Note
this case is the same as previous but the precondition 2. is different.

Description

Commit CONTRIBUTION containing full EHR_STATUS

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR contains a full EHR_STATUS (all the optional information is set, i.e. subject.external_ref etc)

Post-conditions

  1. The EHR should have a new CONTRIBUTION

  2. The EHR should have a new VERSION for the EHR_STATUS

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the valid data sets (see above)

    1. Use change_type = modification or amendment

  2. The result should be positive and retrieve the id of the CONTRIBUTION just created

  3. Verify expected CONTRIBUTION uids and CONTRIBUTION count for the EHR with ehr_id

Test runners

8.5.1.13. Test Case I_EHR_CONTRIBUTION.commit_contribution-ehr_status_invalid_change_type

Description

Commit CONTRIBUTION containing EHR_STATUS with invalid change type

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has the default EHR_STATUS

Post-conditions

None

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the valid data sets (see above)

    1. Use change_type = create and delete

  2. The result should be negative and retrieve an error indicating the EHR_STATUS already existing for the EHR

Test runners

8.5.1.14. Test Case I_EHR_CONTRIBUTION.commit_contribution-invalid_ehr_status

Description

Commit CONTRIBUTION containing invalid EHR_STATUS

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has the default EHR_STATUS

Post-conditions

None

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the invalid data sets (see above)

    1. Use change_type = modification

  2. The result should be negative and retrieve an error indicating the invalid EHR_STATUS

8.5.1.15. Test Case I_EHR_CONTRIBUTION.commit_contribution-valid_directory

Description

Commit CONTRIBUTION containing valid FOLDER

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR doesn’t have a directory (root FOLDER)

Post-conditions

  1. The EHR with ehr_id should have a new CONTRIBUTION and a directory

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the valid data sets (see above) and change_type = creation

  2. The result should be positive and retrieve the id of the CONTRIBUTION just created

Test runners

8.5.1.16. Test Case I_EHR_CONTRIBUTION.commit_contribution-fail_create_existing_directory

Description

Commit CONTRIBUTION attempting to create an EHR directory that already exists

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has a directory (root FOLDER)

Post-conditions

None

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the valid data sets (see above) and change_type = creation

  2. The result should be negative, and retrieve an error indicating the wrong change_type because the root FOLDER already exists

Test runners

8.5.1.17. Test Case I_EHR_CONTRIBUTION.commit_contribution-fail_modify_non_existing_directory

Description

Commit CONTRIBUTION attempting to modify an EHR directory that doesn’t exist

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has no directory (root FOLDER)

Post-conditions

None

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the valid data sets

    1. Use change_type = modification

    2. Use a random preceding_version_uid

  2. The result should be negative since, and retrieve an error indicating the wrong change_type, because it’s trying to modify something that doesn’t exist

Test runners

8.5.1.18. Test Case I_EHR_CONTRIBUTION.commit_contribution-update_existing_directory

Description

Commit CONTRIBUTION updating an EHR directory

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has a directory (root FOLDER)

Post-conditions

  1. The EHR should have a new CONTRIBUTION and a new VERSION for the root FOLDER

Flow

  1. Invoke commit CONTRIBUTION service with an existing ehr_id and the valid data sets with change_type = modification or amendment

  2. The result should be positive and retrieve the id of the CONTRIBUTION just created

Test runners

8.5.2. Service Model operation: I_EHR_CONTRIBUTION.list_contributions()

Service Model reference: I_EHR_CONTRIBUTION.list_contributions()

Note
CONTRIBUTIONs can contain COMPOSITION, EHR_STATUS or FOLDER, or any mix of those. Each flow below applies to a specific type, except when 'ANY' is mentioned, in which case the flow applies to any of those three types.
8.5.2.1. Test Case I_EHR_CONTRIBUTION.list_contributions-post_commit

Description

List CONTRIBUTIONs following successful commit

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR as a CONTRIBUTION with known uid

  3. The CONTRIBUTION contains a VERSION<COMPOSITION>

Post-conditions

  1. The EHR should have a new CONTRIBUTION and a new VERSION for the root FOLDER

Flow

  1. Invoke list CONTRIBUTIONs service with the existing ehr_id

  2. The result should be positive and retrieve a list of CONTRIBUTIONs with one item

  3. The CONTRIBUTION should contain a VERSION<COMPOSITION>

Test runners

8.5.2.2. Test Case I_EHR_CONTRIBUTION.list_contributions-empty

Description

List CONTRIBUTIONs of existing EHR with no CONTRIBUTIONS

Pre-conditions

  1. An EHR with known ehr_id should exist

  2. The EHR has no CONTRIBUTIONs

Post-conditions

None

Flow

  1. Invoke get CONTRIBUTIONs service by the existing ehr_id

  2. The result should be positive and retrieve an empty list

Test runners

8.5.2.3. Test Case I_EHR_CONTRIBUTION.list_contributions-non_existing_ehr

Description

List CONTRIBUTIONs of non-existing EHR (ANY)

Pre-conditions

  1. There are no EHRs on the server

Post-conditions

None

Flow

  1. Invoke list CONTRIBUTIONs service with a random ehr_id

  2. The result should be negative and retrieve an error indicating "EHR with `ehr_id doesn’t exist"`

Test runners

8.5.2.4. Test Case I_EHR_CONTRIBUTION.list_contributions-ehr_containing_ehr_status

Description

List CONTRIBUTIONs post commit of CONTRIBUTION containing EHR_STATUS

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has a CONTRIBUTION with known uid

  3. The CONTRIBUTION contains a VERSION<EHR_STATUS>

Post-conditions

None

Flow

  1. Invoke list CONTRIBUTIONs service by the existing ehr_id

  2. The result should be positive and retrieve a list of CONTRIBUTIONs with one item

  3. The CONTRIBUTION should contain an EHR_STATUS

Test runners

8.5.2.5. Test Case I_EHR_CONTRIBUTION.list_contributions-ehr_containing_directory

Description

List CONTRIBUTIONs post commit of CONTRIBUTION containing a directory

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has a CONTRIBUTION with known uid

  3. The CONTRIBUTION contains a VERSION<FOLDER>

Post-conditions

None

Flow

  1. Invoke get CONTRIBUTIONs service by the existing ehr_id

  2. The result should be positive and retrieve a list of CONTRIBUTIONs with one item

  3. The CONTRIBUTION should contain a FOLDER

Test runners

8.5.3. Service Model operation: I_EHR_CONTRIBUTION.has_contribution()

Service Model reference: I_EHR_CONTRIBUTION.has_contribution()

8.5.3.1. Test Case I_EHR_CONTRIBUTION.has_contribution-existing

Description

Test presence of CONTRIBUTIONs post commit of CONTRIBUTION

Pre-conditions

  1. An EHR should exist in the system with a known ehr_id

  2. The EHR has a CONTRIBUTION with known uid

Post-conditions

None

Flow

  1. Invoke has CONTRIBUTION service with the known ehr_id and CONTRIBUTION uid

  2. The result should be true

Test runners

8.5.3.2. Test Case I_EHR_CONTRIBUTION.has_contribution-empty_ehr

Description

Test presence of CONTRIBUTIONs on empty EHR

Pre-conditions

  1. An EHR should exists in the system with a known ehr_id

  2. The EHR doesn’t have any CONTRIBUTIONs

Post-conditions

None

Flow

  1. Invoke has CONTRIBUTION service with the known ehr_id and a random CONTRIBUTION uid

  2. The result should be false

Test runners

8.5.3.3. Test Case I_EHR_CONTRIBUTION.has_contribution-bad_ehr

Description

Test presence of CONTRIBUTIONs on non-existent EHR

Pre-conditions

  1. There are no EHRs on the server

Post-conditions

None

Flow

  1. Invoke has CONTRIBUTION service with a random ehr_id and a random CONTRIBUTION uid

  2. The result should be negative, and retrieve an error indicating "the EHR with ehr_id doesn’t exist"

Test runners

8.5.3.4. Test Case I_EHR_CONTRIBUTION.has_contribution-bad_contribution

Description

Test presence of CONTRIBUTION that doesn’t exist

Pre-conditions

  1. An EHR should exist on the server with a known ehr_id

  2. The EHR has CONTRIBUTIONs

Post-conditions

None

Flow

  1. Invoke has CONTRIBUTION service with the known ehr_id and a random, not existing CONTRIBUTION uid

  2. The result should be false

Test runners

8.5.4. Service Model operation: I_EHR_CONTRIBUTION.get_contribution()

Service Model reference: I_EHR_CONTRIBUTION.get_contribution()

8.5.4.1. Test Case I_EHR_CONTRIBUTION.get_contribution-existing

Description

Test get CONTRIBUTION from EHR with existing CONTRIBUTION

Pre-conditions

  1. An EHR should exist in the system with a known ehr_id

  2. The EHR has a CONTRIBUTION with known uid

Post-conditions

None

Flow

  1. Invoke has CONTRIBUTION service with the known ehr_id and CONTRIBUTION uid

  2. The result should be the existing CONTRIBUTION

Test runners

8.5.4.2. Test Case I_EHR_CONTRIBUTION.get_contribution-empty_ehr

Description

Test get CONTRIBUTION from empty EHR

Pre-conditions

  1. An EHR should exists in the system with a known ehr_id

  2. The EHR doesn’t have any CONTRIBUTIONs

Post-conditions

None

Flow

  1. Invoke has CONTRIBUTION service with the known ehr_id and a random CONTRIBUTION uid

  2. The result should be negative and retrieve an error indicating the non-existing CONTRIBUTION

Test runners

8.5.4.3. Test Case I_EHR_CONTRIBUTION.get_contribution-bad_ehr

Description

Test get CONTRIBUTION from non-existing EHR

Pre-conditions

  1. There are no EHRs on the server

Post-conditions

None

Flow

  1. Invoke has CONTRIBUTION service with a random ehr_id and a random CONTRIBUTION uid

  2. The result should be negative, and retrieve an error indicating "the EHR with ehd_id doesn’t exist"

Test runners

8.5.4.4. Test Case I_EHR_CONTRIBUTION.get_contribution-bad_contribution

Description

Test get CONTRIBUTION from EHR with non-existing CONTRIBUTION

Pre-conditions

  1. An EHR should exist on the server with a known ehr_id

  2. The EHR has CONTRIBUTIONs

Post-conditions

None

Flow

  1. Invoke has CONTRIBUTION service with the known ehr_id and a random, non-existing CONTRIBUTION uid

  2. The result should be negative and retrieve an error indicating the non-existing CONTRIBUTION

Test runners

9. Test Suite: EHR_SERVICE / I_DIRECTORY Interface

9.1. Normative Reference

Items in this validation suite conceptually use the following abstract interfaces from the Abstract Platform Service Model, EHR/DIRECTORY component.

  • I_EHR_DIRECTORY

These are concretely realised in implementation technology specfic APIs, such as the EHR REST API.

This test suite uses artefacts defined by the following information model specifications:

9.2. Dependencies

This test suite depends on other test suites:

9.3. Test Environment

TBD

9.4. Test Data Sets

For the creation and modification of the EHR.directory structure it is important to explore the hierarchical nature of the FOLDER structures and consider the edge cases for EHR.directory.

9.4.1. Tests of EHR.directory

  1. FOLDER

  2. FOLDER with items

  3. FOLDER with subfolders

  4. FOLDER with subfolders and items on all the folders

  5. FOLDER with n levels of subfolders and items (to detect any implementation limitations)

9.4.2. Tests of Reference FOLDER structure

Note
the following image is provided for reference. The items in the FOLDER are references to VERSIONED_OBJECTs that may contain COMPOSITION, EHR_STATUS and FOLDER. This documentation focuses on testing COMPOSITION as content in the FOLDERs. Discourse discussion.
high level ehr structure
Figure 1. Folder structures in the EHR

9.5. Test Cases

9.5.1. Service Model operation: I_EHR_DIRECTORY.has_directory()

Service Model reference: I_EHR_DIRECTORY.has_directory()

9.5.1.1. Test Case I_EHR_DIRECTORY.has_directory-empty_ehr

Description

Test has_directory on empty EHR

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the has_directory service for the ehr_id

  2. The result must be false

Test runners

9.5.1.2. Test Case I_EHR_DIRECTORY.has_directory-ehr_with_directory

Description

Test has_directory on EHR containing a directory

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has a directory

Post-conditions

None

Flow

  1. Invoke the has_directory service for the ehr_id

  2. The result must be true

Test runners

9.5.1.3. Test Case I_EHR_DIRECTORY.has_directory-bad_ehr

Description

Test has_directory on non-existent EHR

Pre-conditions

  1. There are no EHRs on the server

Post-conditions

None

Flow

  1. Invoke the has_directory service for a random non-existent ehr_id

  2. An error should be returned, indicating that the EHR that doesn’t exist

Test runners

9.5.2. Service Model operation: I_EHR_DIRECTORY.has_path()

Service Model reference: I_EHR_DIRECTORY.has_path()

9.5.2.1. Test Case I_EHR_DIRECTORY.has_path-empty_ehr

Description

Test has_path on empty EHR

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the has path service for the ehr_id with a random FOLDER path

  2. The result must be false

Test runners

9.5.2.2. Test Case I_EHR_DIRECTORY.has_path-ehr_root_directory

Description

Test has_path on EHR with just root directory

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR and has an empty directory (no subfolders or items)

Post-conditions

None

Flow

  1. Invoke the has path service for the ehr_id and an existing path $path from the data set

  2. The result must be $result from the data set

Data set

$path $result

'/'

true

random()

false

Note
'/' represents the string slash, which is the default name for the root FOLDER at EHR.directory, random() represents any randomly generated path that doesn’t exist.

Test runners

9.5.2.3. Test Case I_EHR_DIRECTORY.has_path-folder_structure

Description

Test has_path on EHR with folder structure

Pre-conditions

  1. An EHR with known ehr_id exists

  2. The EHR has a directory with an internal structure (described below)

Post-conditions

None

Flow

  1. Invoke the has path service for the ehr_id and the path $path from the data set

  2. The result must be $result from the data set

Data set

Assuming the following structure in EHR.directory:

/
    +--- emergency
    |        |
    |        +--- episode-x
    |        |      |
    |        |      +--- summary-composition-x
    |        |
    |        +--- episode-y
    |               |
    |               +--- summary-composition-y
    |
    +--- hospitalization
             |
             +--- summary-composition-z
Note
these are the names of the FOLDERs and COMPOSITIONs in EHR.directory.
$path $result

'/'

true

'/emergency'

true

'/emergency/episode-x'

true

'/emergency/episode-x/summary-composition-x'

true

'/emergency/episode-y'

true

'/emergency/episode-y/summary-composition-y'

true

'/hospitalization'

true

'/hospitalization/summary-composition-z'

true

'/' + random()

false

'/emergency/' + random()

false

'/emergency/episode-x/' + random()

false

random()

false

Note
the table mixes cases that exist with cases of paths which part exists and parts doesn’t exist. The final one is a random path.

Test runners

9.5.2.4. Test Case I_EHR_DIRECTORY.has_path-bad_ehr

Description

Test has_path on non-existent EHR

Pre-conditions

  1. The server is empty

Post-conditions

None

Flow

  1. Invoke the has path service for a random ehr_id and path

  2. The service should return an error, indicating that the EHR doesn’t exist

Test runners

9.5.3. Service Model operation: I_EHR_DIRECTORY.create_directory()

Service Model reference: I_EHR_DIRECTORY.create_directory()

9.5.3.1. Test Case I_EHR_DIRECTORY.create_directory-empty_ehr

Description

Test create_directory on empty EHR

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR doesn’t have a directory

Post-conditions

  1. The EHR ehr_id should have a directory

Flow

  1. Invoke the create directory service with the existing ehr_id and a valid FOLDER structure

    1. Use any of the data sets described on the previous tests and the reference directory structure

  2. The service should return a positive result indicating the directory created for the EHR

Test runners

9.5.3.2. Test Case I_EHR_DIRECTORY.create_directory-ehr_with_directory

Description

Test create_directory on EHR with directory

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR has a directory

Post-conditions

None

Flow

  1. Invoke the create directory service with the existing ehr_id and a valid FOLDER structure

    1. Use any of the data sets described on the previous tests and the reference directory structure

  2. The service should return an error, indicating that the EHR directory already exists

Test runners

9.5.3.3. Test Case I_EHR_DIRECTORY.create_directory-bad_ehr

Description

Test create_directory on non-existent EHR

Pre-conditions

  1. The server should be empty

Post-conditions

None

Flow

  1. Invoke the create directory service for a random ehr_id

  2. The service should return an error, indicating that the EHR that doesn’t exist

Test runners

9.5.4. Service Model operation: I_EHR_DIRECTORY.get_directory()

Service Model reference: I_EHR_DIRECTORY.get_directory()

9.5.4.1. Test Case I_EHR_DIRECTORY.get_directory-empty_ehr

Description

Test get_directory on empty EHR

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the get directory service for the ehr_id

  2. The service should return an empty structure

    NOTE: in a REST API implementation, the result could be an error status instead of an empty structure.

Test runners

9.5.4.2. Test Case I_EHR_DIRECTORY.get_directory-ehr_root_directory

Description

Test get_directory on EHR with a root directory

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR has a single empty FOLDER in its directory

Post-conditions

None

Flow

  1. Invoke the get directory service for the ehr_id

  2. The service should return the structure of the EHR.directory: an empty FOLDER

Test runners

9.5.4.3. Test Case I_EHR_DIRECTORY.get_directory-directory_with_structure

Description

Test get_directory on EHR with a directory containing sub-structure

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR has a directory with a sub-structure (use the data sets from the previous tests and the reference directory structure)

Post-conditions

None

Flow

  1. Invoke the get directory service for the ehr_id

  2. The service should return the full structure of the EHR directory

Test runners

9.5.4.4. Test Case I_EHR_DIRECTORY.get_directory-bad_ehr

Description

Test get_directory on non-existent EHR

Pre-conditions

  1. The server is empty

Post-conditions

None

Flow

  1. Invoke the get directory service for a random ehr_id

  2. The service should return an error related with the non-existent EHR

Test runners

9.5.5. Service Model operation: I_EHR_DIRECTORY.get_directory_at_time()

Service Model reference: I_EHR_DIRECTORY.get_directory_at_time()

9.5.5.1. Test Case I_EHR_DIRECTORY.get_directory_at_time-empty_ehr

Description

Test get_directory_at_time on empty EHR

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the get directory at time service for the ehr_id and current time

  2. The service should return an empty structure

    NOTE: considering a REST API implementation, the result could be an error status instead of an empty structure.

Test runners

9.5.5.2. Test Case I_EHR_DIRECTORY.get_directory_at_time-empty_ehr_empty_time

Description

Test get_directory_at_time on empty EHR with empty time

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the get directory at time service for the ehr_id and empty time

  2. The service should return an empty structure

    NOTE: considering a REST API implementation, the result could be an error status instead of an empty structure.

Test runners

9.5.5.3. Test Case I_EHR_DIRECTORY.get_directory_at_time-ehr_with_directory

Description

Test get_directory_at_time on empty EHR with directory

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR has a directory with one version (use any of the valid datasets from the previous tests)

Post-conditions

None

Flow

  1. Invoke the get directory at time service for the ehr_id and current time

  2. The service should return the current directory

Test runners

9.5.5.4. Test Case I_EHR_DIRECTORY.get_directory_at_time-ehr_with_directory_empty_time

Description

Test get_directory_at_time on EHR with directory with empty time

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR has a directory with one version (use any of the valid datasets from the previous tests)

Post-conditions

None

Flow

  1. Invoke the get directory at time service for the ehr_id and empty time

  2. The service should return the current directory

Test runners

9.5.5.5. Test Case I_EHR_DIRECTORY.get_directory_at_time-ehr_with_directory_versions

Description

Test get_directory_at_time on EHR with directory containing multiple versions

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR has a directory with two versions (use any of the valid datasets from the previous tests, add small changes to differentiate the versions)

Post-conditions

None

Flow

  1. Invoke the get directory at time service for the ehr_id and a time before EHR.time_created

  2. The service should return an empty structure

  3. Invoke the get directory at time service for the ehr_id and a time after the first EHR.directory version was created and before the second EHR.directory version was created

  4. The service should return the first version of EHR.drectory

  5. Invoke the get directory at time service for the ehr_id and current time

  6. The service should return the second version of EHR.directory

Test runners

9.5.5.6. Test Case I_EHR_DIRECTORY.get_directory_at_time-ehr_with_directory_versions_empty_time

Description

Test get_directory_at_time on EHR with directory containing multiple versions with empty time

Pre-conditions

  1. An EHR with ehr_id exists

  2. The EHR has a directory with two versions (use any of the valid datasets from the previous tests, add small changes to differentiate the versions)

Post-conditions

None

Flow

  1. Invoke the get directory at time service for the ehr_id and empty time

  2. The service should return the current latest directory

Test runners

9.5.5.7. Test Case I_EHR_DIRECTORY.get_directory_at_time-bad_ehr

Description

Test get_directory_at_time on non-existent EHR

Pre-conditions

  1. The server is empty

Post-conditions

None

Flow

  1. Invoke the get directory at time service for a random ehr_id and current time

  2. The service should return an error indicating non-existent EHR

Test runners

9.5.5.8. Test Case I_EHR_DIRECTORY.get_directory_at_time-multiple_versions_first

Description

Test get_directory_at_time on EHR with directory with multiple versions first version

Pre-conditions

  1. An EHR with ehr_id and has directory with two versions

Post-conditions

None

Flow

  1. Invoke the get directory at time service for the ehr_id and a time AFTER the first version of the directory was created, but BEFORE the second version was created (update)

  2. The service should return the first version of the directory

Test runners

9.5.6. Service Model operation: I_EHR_DIRECTORY.update_directory()

Service Model reference: I_EHR_DIRECTORY.update_directory()

9.5.6.1. Test Case I_EHR_DIRECTORY.update_directory-ehr_with_directory

Description

Test update_directory on EHR with directory

Pre-conditions

  1. An EHR with ehr_id exists on the server

  2. The EHR has a directory

Post-conditions

  1. The EHR with ehr_id has an updated directory structure

Flow

  1. Invoke the update directory service for the ehr_id

    1. Use any of the valid paylaods described on the previous tests

  2. The service should return a positive result related with the updated directory

Test runners

9.5.6.2. Test Case I_EHR_DIRECTORY.update_directory-empty_ehr

Description

Test update_directory on empty EHR

Pre-conditions

  1. An EHR with ehr_id exists on the server

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the update directory service for the ehr_id

    1. Use any of the valid paylaods described on the previous tests

  2. The service should return an error indicating that the non existent directory to update

Test runners

9.5.6.3. Test Case I_EHR_DIRECTORY.update_directory-bad_ehr

Description

Test update_directory on non-existent EHR

Pre-conditions

  1. The server is empty

Post-conditions

None

Flow

  1. Invoke the update directory service for random ehr_id

    1. Any valid payload will suffice

  2. The service should return an error indicating that the non existent ehr_id

Test runners

9.5.7. Service Model operation: I_EHR_DIRECTORY.delete_directory()

Service Model reference: I_EHR_DIRECTORY.delete_directory()

9.5.7.1. Test Case I_EHR_DIRECTORY.delete_directory-empty_ehr

Description

Test delete_directory on empty EHR

Pre-conditions

  1. An EHR with ehr_id exists on the server

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the delete directory service for the ehr_id

  2. The service should return an error indicating the non existent directory

Test runners

9.5.7.2. Test Case I_EHR_DIRECTORY.delete_directory-ehr_with_directory

Description

Test delete_directory on EHR with directory

Pre-conditions

  1. An EHR with ehr_id exists on the server

  2. The EHR has a directory

Post-conditions

  1. The EHR ehr_id doesn’t have directory

Note
the directory exists as a new deleted version (that is VERSION.lifecycle_state=deleted).

Flow

  1. Invoke the delete directory service for the ehr_id

  2. The service should return a positive result related with the deleted directory

Test runners

9.5.7.3. Test Case I_EHR_DIRECTORY.delete_directory-bad_ehr

Description

Test delete_directory on non-existent EHR

Pre-conditions

  1. The server is empty

Post-conditions

None

Flow

  1. Invoke the get directory service for a random ehr_id

  2. The service should return an error indicating that the non existent EHR

Test runners

9.5.8. Service Model operation: I_EHR_DIRECTORY.has_directory_version()

Service Model reference: I_EHR_DIRECTORY.has_directory_version()

9.5.8.1. Test Case I_EHR_DIRECTORY.has_directory_version-empty_ehr

Description

Test has_directory_version on empty EHR

Pre-conditions

  1. An EHR with known ehr_id exists on the server

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the has directory service for the ehr_id and a random version uid

  2. The service should return false

Test runners

9.5.8.2. Test Case I_EHR_DIRECTORY.has_directory_version-directory_with_two_versions

Description

Test has_directory_version on EHR that has two versions of directory

Pre-conditions

  1. An EHR with known ehr_id exists on the server

  2. The EHR has two directory versions

Post-conditions

None

Flow

  1. Invoke the has directory service for the ehr_id and the version_uid of the first version of directory

  2. The service should return true

  3. Invoke the has directory service for the ehr_id and the version_uid of the second version of directory

  4. The service should return true

Test runners

9.5.8.3. Test Case I_EHR_DIRECTORY.has_directory_version-bad_ehr

Description

Test has_directory_version on non-existent EHR

Pre-conditions

  1. The server doesn’t have EHRs

Post-conditions

None

Flow

  1. Invoke the has directory service for a random ehr_id and version uid

  2. The service should return an error related with the non-existence of the EHR

Test runners

9.5.9. Service Model operation: I_EHR_DIRECTORY.get_directory_at_version()

9.5.9.1. Test Case I_EHR_DIRECTORY.get_directory_at_version-empty_ehr

Description

Test get_directory_at_version on empty EHR

Pre-conditions

  1. An EHR with known ehr_id exists on the server

  2. The EHR doesn’t have a directory

Post-conditions

None

Flow

  1. Invoke the get directory at version service for the ehr_id and a random version uid

  2. The service should return an error indicating that the non-existence of the EHR directory version

Test runners

9.5.9.2. Test Case I_EHR_DIRECTORY.get_directory_at_version-directory_with_two_versions

Description

Test get_directory_at_version on EHR that has two versions of directory

Pre-conditions

  1. An EHR with known ehr_id exists on the server

  2. The EHR has two versions of directory

Post-conditions

None

Flow

  1. Invoke the get directory at version service for the ehr_id and the version_uid of the first version of directory

  2. The service should return the first version of the directory

  3. Invoke the get directory at version service for the ehr_id and the version_uid of the second version of directory

  4. The service should return the second version of the directory

Test runners

9.5.9.3. Test Case I_EHR_DIRECTORY.get_directory_at_version-bad_ehr

Description

Test get_directory_at_version on non-existent EHR

Pre-conditions

  1. The server doesn’t have EHRs

Post-conditions

None

Flow

  1. Invoke the get directory at version service for a random ehr_id and version uid

  2. The service should return an error related with the non existence of the EHR

Test runners

9.5.10. Service Model operation: I_EHR_DIRECTORY.get_versioned_directory()

9.5.10.1. Test Case I_EHR_DIRECTORY.get_versioned_directory-empty_ehr

Description

Test get_versioned_directory on non-existent EHR

Pre-conditions

  1. An EHR with known ehr_id exists on the server

Post-conditions

None

Flow

  1. Invoke the get versioned directory service for the ehr_id

  2. The service should return an error because the versioned directory doesn’t exist

    NOTE: depending on the implementation, a valid result could also be returning an empty result instead of an error.

Test runners

9.5.10.2. Test Case I_EHR_DIRECTORY.get_versioned_directory-directory_with_two_versions

Description

Test get_versioned_directory on EHR that has two versions of directory

Pre-conditions

  1. An EHR with known ehr_id exists on the server

  2. The EHR has two versions of directory

Post-conditions

None

Flow

  1. Invoke the get versioned directory service for the ehr_id

  2. The service should return the versioned folder and should reference the two exsinting versions

Test runners

9.5.10.3. Test Case I_EHR_DIRECTORY.get_versioned_directory-bad_ehr

Description

Test get_versioned_directory on non-existent EHR

Pre-conditions

  1. The server doesn’t have any EHRs

Post-conditions

None

Flow

  1. Invoke the get directory service for a random ehr_id

  2. The service should return an error related with the non existence of the EHR

Test runners

10. Test Suite: DEMOGRAPHIC_SERVICE

10.1. Normative Reference

Items in this validation suite conceptually use the following abstract interfaces from the Abstract Platform Service Model, DEMOGRAPHIC component.

  • I_DEMOGRAPHIC_SERVICE

These are concretely realised in implementation technology specfic APIs, such as the EHR REST API.

This test suite uses artefacts defined by the following information model specifications:

10.2. Dependencies

This test suite depends on other test suites:

10.3. Test Environment

TBD

10.4. Test Data Sets

TBD

10.5. Test Cases

10.5.1. Service Model operation: I_DEMOGRAPHIC_SERVICE.create_party()

Service Model reference: I_DEMOGRAPHIC_SERVICE.create_party()

10.5.1.1. Test Case aaaa

TBD

10.5.1.2. Test Case bbbb

TBD

10.5.2. Service Model operation: I_DEMOGRAPHIC_SERVICE.get_party()

Service Model reference: I_DEMOGRAPHIC_SERVICE.get_party()

10.5.2.1. Test Case aaaa

TBD

10.5.2.2. Test Case bbbb

TBD

10.5.3. Service Model operation: I_DEMOGRAPHIC_SERVICE.get_party_at_time()

10.5.3.1. Test Case aaaa

TBD

10.5.3.2. Test Case bbbb

TBD

10.5.4. Service Model operation: I_DEMOGRAPHIC_SERVICE.update_party()

Service Model reference: I_DEMOGRAPHIC_SERVICE.update_party()

10.5.4.1. Test Case aaaa

TBD

10.5.4.2. Test Case bbbb

TBD

10.5.5. Service Model operation: I_DEMOGRAPHIC_SERVICE.delete_party()

Service Model reference: I_DEMOGRAPHIC_SERVICE.delete_party()

10.5.5.1. Test Case aaaa

TBD

10.5.5.2. Test Case bbbb

TBD

10.5.6. Service Model operation: I_DEMOGRAPHIC_SERVICE.get_party_at_version()

10.5.6.1. Test Case aaaa

TBD

10.5.6.2. Test Case bbbb

TBD

10.5.7. Service Model operation: I_DEMOGRAPHIC_SERVICE.create_party_relationship()

10.5.7.1. Test Case aaaa

TBD

10.5.7.2. Test Case bbbb

TBD

10.5.8. Service Model operation: I_DEMOGRAPHIC_SERVICE.get_party_relationship()

10.5.8.1. Test Case aaaa

TBD

10.5.8.2. Test Case bbbb

TBD

10.5.9. Service Model operation: I_DEMOGRAPHIC_SERVICE.get_party_relationship_at_time()

10.5.9.1. Test Case aaaa

TBD

10.5.9.2. Test Case bbbb

TBD

10.5.10. Service Model operation: I_DEMOGRAPHIC_SERVICE.update_party_relationship()

10.5.10.1. Test Case aaaa

TBD

10.5.10.2. Test Case bbbb

TBD

10.5.11. Service Model operation: I_DEMOGRAPHIC_SERVICE.delete_party_relationship()

10.5.11.1. Test Case aaaa

TBD

10.5.11.2. Test Case bbbb

TBD

10.5.12. Service Model operation: I_DEMOGRAPHIC_SERVICE.get_party_relationship_at_version()

10.5.12.1. Test Case aaaa

TBD

10.5.12.2. Test Case bbbb

TBD

11. Test Suite: QUERY_SERVICE

11.1. Normative Reference

Items in this validation suite conceptually use the following abstract interfaces from the Abstract Platform Service Model, QUERY component.

  • I_QUERY_SERVICE

These are concretely realised in implementation technology specfic APIs, such as the QUERY REST API.

This test suite uses artefacts defined by the following information model specifications:

11.2. Dependencies

This test suite depends on other test suites:

11.3. Test Environment

TBD

11.4. Test Data Sets

TBD

11.5. Test Cases

11.5.1. Service Model operation: I_QUERY_SERVICE.execute_stored_query()

Service Model reference: I_QUERY_SERVICE.execute_stored_query()

11.5.1.1. Test Case I_QUERY_SERVICE.smoke_test

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

11.5.1.2. Test Case I_QUERY_SERVICE.execute_stored_query-empty_db

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

11.5.1.3. Test Case bbbb

TBD

11.5.2. Service Model operation: I_QUERY_SERVICE.execute_ad_hoc_query()

Service Model reference: I_QUERY_SERVICE.execute_ad_hoc_query()

11.5.2.1. Test Case I_QUERY_SERVICE.execute_ad_hoc_query-empty_db

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

11.5.2.2. Test Case I_QUERY_SERVICE.execute_ad_hoc_query-loaded_db

Description

xx

Pre-conditions

xx

Post-conditions

xx

Flow

xx

Test runners

12. Test Suite: ADMIN_SERVICE

12.1. Normative Reference

Items in this validation suite conceptually use the following abstract interfaces from the Abstract Platform Service Model, ADMIN component.

  • I_ADMIN_SERVICE

  • I_ADMIN_DUMP_LOAD

  • I_ADMIN_ARCHIVE

These are concretely realised in implementation technology specfic APIs, such as the {openehr_admin_rest_api}[ADMIN REST API^].

This test suite uses artefacts defined by the following information model specifications:

12.2. Dependencies

TBD

12.3. Test Environment

TBD

12.4. Test Data Sets

TBD

12.5. Test Cases

12.5.1. Service Model operation: I_ADMIN_SERVICE.list_contributions()

Service Model reference: I_ADMIN_SERVICE.list_contributions()

12.5.1.1. Test Case aaaa

TBD

12.5.1.2. Test Case bbbb

TBD

12.5.2. Service Model operation: I_ADMIN_SERVICE.contribution_count()

Service Model reference: I_ADMIN_SERVICE.contribution_count()

12.5.2.1. Test Case aaaa

TBD

12.5.2.2. Test Case bbbb

TBD

12.5.3. Service Model operation: I_ADMIN_SERVICE.versioned_composition_count()

12.5.3.1. Test Case aaaa

TBD

12.5.3.2. Test Case bbbb

TBD

12.5.4. Service Model operation: I_ADMIN_SERVICE.composition_version_count()

12.5.4.1. Test Case aaaa

TBD

12.5.4.2. Test Case bbbb

TBD

12.5.5. Service Model operation: I_ADMIN_SERVICE.physical_ehr_delete()

Service Model reference: I_ADMIN_SERVICE.physical_ehr_delete()

12.5.5.1. Test Case aaaa

TBD

12.5.5.2. Test Case bbbb

TBD

12.5.6. Service Model operation: I_ADMIN_SERVICE.physical_party_delete()

Service Model reference: I_ADMIN_SERVICE.physical_party_delete()

12.5.6.1. Test Case aaaa

TBD

12.5.6.2. Test Case bbbb

TBD

12.5.7. Service Model operation: I_ADMIN_DUMP_LOAD.export_ehrs()

Service Model reference: I_ADMIN_DUMP_LOAD.export_ehrs()

12.5.7.1. Test Case aaaa

TBD

12.5.7.2. Test Case bbbb

TBD

12.5.8. Service Model operation: I_ADMIN_ARCHIVE.archive_ehrs()

Service Model reference: I_ADMIN_ARCHIVE.archive_ehrs()

12.5.8.1. Test Case aaaa

TBD

12.5.8.2. Test Case bbbb

TBD

12.5.9. Service Model operation: I_ADMIN_ARCHIVE.archive_parties()

Service Model reference: I_ADMIN_ARCHIVE.archive_parties()

12.5.9.1. Test Case aaaa

TBD

12.5.9.2. Test Case bbbb

TBD

13. Test Suite: MESSAGE_SERVICE

13.1. Normative Reference

Items in this validation suite conceptually use the following abstract interfaces from the Abstract Platform Service Model, MESSAGE component.

  • I_EHR_EXTRACT

  • I_TDD

These are concretely realised in implementation technology specfic APIs, such as the {openehr_message_rest_api}[MESSAGE REST API^].

This test suite uses artefacts defined by the following information model specifications:

13.2. Dependencies

TBD

13.3. Test Environment

TBD

13.4. Test Data Sets

TBD

13.5. Test Cases

13.5.1. Service Model operation: I_EHR_EXTRACT.export_ehr()

Service Model reference: I_EHR_EXTRACT.export_ehr()

13.5.1.1. Test Case aaaa

TBD

13.5.1.2. Test Case bbbb

TBD

13.5.2. Service Model operation: I_EHR_EXTRACT.export_ehr_extract()

Service Model reference: I_EHR_EXTRACT.export_ehr_extract()

13.5.2.1. Test Case aaaa

TBD

13.5.2.2. Test Case bbbb

TBD

13.5.3. Service Model operation: I_EHR_EXTRACT.export_ehr()

Service Model reference: I_EHR_EXTRACT.export_ehr()

13.5.3.1. Test Case aaaa

TBD

13.5.3.2. Test Case bbbb

TBD

13.5.4. Service Model operation: I_EHR_EXTRACT.export_ehrs()

Service Model reference: I_EHR_EXTRACT.export_ehrs()

13.5.4.1. Test Case aaaa

TBD

13.5.4.2. Test Case bbbb

TBD

13.5.5. Service Model operation: I_EHR_EXTRACT.export_ehr_extracts()

Service Model reference: I_EHR_EXTRACT.export_ehr_extracts()

13.5.5.1. Test Case aaaa

TBD

13.5.5.2. Test Case bbbb

TBD

13.5.6. Service Model operation: I_TDD.import_tdd()

Service Model reference: I_TDD.import_tdd()

13.5.6.1. Test Case aaaa

TBD

13.5.6.2. Test Case bbbb

TBD

13.5.7. Service Model operation: I_TDD.import_tdds()

Service Model reference: I_TDD.import_tdds()

13.5.7.1. Test Case aaaa

TBD

13.5.7.2. Test Case bbbb

TBD

14. Data Validation Conformance

14.1. Overview

The test cases defined here are for creating archetypes expressing specific constraints over data defined by the openEHR RM. Different data instances should be generated in order to test the constraints. It’s recommended to have at least one success case, one failure case and all border cases covered. That is, for each archetype constraint specified, at least three data instances should be created.

Since there are many combinations of constraints possible in archetypes and templates, we separate them into different classes and focus on each constraint set class independently from the other sets. The sets are defined by:

  1. A top-level LOCATABLE class: COMPOSITION, EHR_STATUS, FOLDER, PARTY.

  2. Constraint sets on top-level attributes for each class.

  3. Internal LOCATABLE class: SECTION, ENTRY, HISTORY, ITEM_STRUCTURE, ITEM, DATA_VALUE.

  4. Constraint sets on internal structures and attributes (at any level in the RM hierarchy in the internal LOCATABLE class).

In this section, the following terms are used:

  • Archetypable class: any class that extends LOCATABLE.

  • Archetypable field: generic fields on archetypable classes that can be constrained in archetypes.

For testing a 'multiple attribute' cardinality, we use this set of cardinality intervals:

  • 0..*

  • 1..*

  • 3..*

  • 0..1

  • 1..1

  • 3..5

14.1.1. Implementation notes

The constraint combinations described in the cases below could be implemented in different archetypes, or in a generic archetype then defining the specific constraints at the template level. Which option to use might depend on the modeling tools used to create archetypes and templates.

We suggest to automate the archetype/template test cases generation instead of creating each constraint combination manualy.

When there is no constraint defined for an attribute, it means anything is allowed on that attribute. It is recommended to include data not defined by the archetype, but valid in the RM, when generating the data instances.

14.2. COMPOSITION Test Cases

These cases are defined to verify the constraints defined over archetypable attributes of the top-level class COMPOSITION specified in the openEHR RM, COMPOSITION package.

The constraints combinations described below could be tested in two ways:

  1. Isolation: by not constraining the COMPOSITION.content at all, or adding an open/‘any allowed’ constraint \{*} at the COMPOSITION.content in the archetype/template. This means anything, even nothing, is accepted at the COMPOSITION.content at runtime.

  2. Combination: with constraints set for COMPOSITION.content, for any CONTENT_ITEM (SECTION or ENTRY). Below there is a specification of the constraint combinations for each class accepted at COMPOSITION.content

Note
we suggest to test with both strategies.

14.2.1. Test Case CONT-COMP-content_card_any-context_any

Description: COMPOSITION content cardinality 0..*, no constraint over context

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, success)

  2. COMPOSITION with one entry (success)

  3. COMPOSITION with 3 entries (success)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

accepted

one entry

no context

accepted

three entries

no context

accepted

no entries

context without other_context

accepted

one entry

context without other_context

accepted

three entries

context without other_context

accepted

no entries

context with other_context

accepted

one entry

context with other_context

accepted

three entries

context with other_context

accepted

14.2.2. Test Case CONT-COMP-content_card_1plus-context_any

Description: COMPOSITION content cardinality 1..*, no constraint over context

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, fail)

  2. COMPOSITION with one entry (border case, success)

  3. COMPOSITION with 3 entries (success)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.content: cardinality.lower

one entry

no context

accepted

three entries

no context

accepted

no entries

context without other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context without other_context

accepted

three entries

context without other_context

accepted

no entries

context with other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context with other_context

accepted

three entries

context with other_context

accepted

14.2.3. Test Case CONT-COMP-content_card_3plus-context_any

Description: COMPOSITION content cardinality 3..*, no constraint over context

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, fail)

  2. COMPOSITION with one entry (fail)

  3. COMPOSITION with 3 entries (border case, success)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.content: cardinality.lower

one entry

no context

rejected

COMPOSITION.content: cardinality.lower

three entries

no context

accepted

no entries

context without other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context without other_context

rejected

COMPOSITION.content: cardinality.lower

three entries

context without other_context

accepted

no entries

context with other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context with other_context

rejected

COMPOSITION.content: cardinality.lower

three entries

context with other_context

accepted

14.2.4. Test Case CONT-COMP-content_card_opt-context_any

Description: COMPOSITION content cardinality 0..1, no constraint over context

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, success)

  2. COMPOSITION with one entry (border case, success)

  3. COMPOSITION with 3 entries (fail)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

accepted

one entry

no context

accepted

three entries

no context

rejected

COMPOSITION.content: cardinality.upper

no entries

context without other_context

accepted

one entry

context without other_context

accepted

three entries

context without other_context

rejected

COMPOSITION.content: cardinality.upper

no entries

context with other_context

accepted

one entry

context with other_context

accepted

three entries

context with other_context

rejected

COMPOSITION.content: cardinality.upper

14.2.5. Test Case CONT-COMP-content_card_mand-context_any

Description: COMPOSITION content cardinality 1..1, no constraint over context

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, fail)

  2. COMPOSITION with one entry (border case, success)

  3. COMPOSITION with 3 entries (fail)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.content: cardinality.lower

one entry

no context

accepted

three entries

no context

rejected

COMPOSITION.content: cardinality.upper

no entries

context without other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context without other_context

accepted

three entries

context without other_context

rejected

COMPOSITION.content: cardinality.upper

no entries

context with other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context with other_context

accepted

three entries

context with other_context

rejected

COMPOSITION.content: cardinality.upper

14.2.6. Test Case CONT-COMP-content_card_3to5-context_any

Description: COMPOSITION content cardinality 3..5, no constraint over context

COMPOSITION data sets:

  1. COMPOSITION with no entries (fail)

  2. COMPOSITION with one entry (fail)

  3. COMPOSITION with 3 entries (border case, success)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.content: cardinality.lower

one entry

no context

rejected

COMPOSITION.content: cardinality.lower

three entries

no context

accepted

no entries

context without other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context without other_context

rejected

COMPOSITION.content: cardinality.lower

three entries

context without other_context

accepted

no entries

context with other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context with other_context

rejected

COMPOSITION.content: cardinality.lower

three entries

context with other_context

accepted

14.2.7. Test Case CONT-COMP-content_card_any-context_mand

Description: COMPOSITION content cardinality 0..*, context occurrences 1..1

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, success)

  2. COMPOSITION with one entry (success)

  3. COMPOSITION with 3 entries (success)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.context occurrences.lower

one entry

no context

rejected

COMPOSITION.context occurrences.lower

three entries

no context

rejected

COMPOSITION.context occurrences.lower

no entries

context without other_context

accepted

one entry

context without other_context

accepted

three entries

context without other_context

accepted

no entries

context with other_context

accepted

one entry

context with other_context

accepted

three entries

context with other_context

accepted

14.2.8. Test Case CONT-COMP-content_card_1plus-context_mand

Description: COMPOSITION content cardinality 1..*, context occurrences 1..1

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, fail)

  2. COMPOSITION with one entry (border case, success)

  3. COMPOSITION with 3 entries (success)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.content: cardinality.lower, COMPOSITION.context occurrences.lower

one entry

no context

rejected

COMPOSITION.context occurrences.lower

three entries

no context

rejected

COMPOSITION.context occurrences.lower

no entries

context without other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context without other_context

accepted

three entries

context without other_context

accepted

no entries

context with other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context with other_context

accepted

three entries

context with other_context

accepted

14.2.9. Test Case CONT-COMP-content_card_3plus-context_mand

Description: COMPOSITION content cardinality 3..*, context occurrences 1..1

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, fail)

  2. COMPOSITION with one entry (fail)

  3. COMPOSITION with 3 entries (border case, success)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.content: cardinality.lower, COMPOSITION.context occurrences.lower

one entry

no context

rejected

COMPOSITION.content: cardinality.lower, COMPOSITION.context occurrences.lower

three entries

no context

rejected

COMPOSITION.context occurrences.lower

no entries

context without other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context without other_context

rejected

COMPOSITION.content: cardinality.lower

three entries

context without other_context

accepted

no entries

context with other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context with other_context

rejected

COMPOSITION.content: cardinality.lower

three entries

context with other_context

accepted

14.2.10. Test Case CONT-COMP-content_card_opt-context_mand

Description: COMPOSITION content cardinality 0..1, context occurrences 1..1

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, success)

  2. COMPOSITION with one entry (border case, success)

  3. COMPOSITION with 3 entries (fail)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.context occurrences.lower

one entry

no context

rejected

COMPOSITION.context occurrences.lower

three entries

no context

rejected

COMPOSITION.content: cardinality.upper, COMPOSITION.context occurrences.lower

no entries

context without other_context

accepted

one entry

context without other_context

accepted

three entries

context without other_context

rejected

COMPOSITION.content: cardinality.upper

no entries

context with other_context

accepted

one entry

context with other_context

accepted

three entries

context with other_context

rejected

COMPOSITION.content: cardinality.upper

14.2.11. Test Case CONT-COMP-content_card_mand-context_mand

Description: COMPOSITION content cardinality 1..1, context occurrences 1..1

COMPOSITION data sets:

  1. COMPOSITION with no entries (border case, fail)

  2. COMPOSITION with one entry (border case, success)

  3. COMPOSITION with 3 entries (fail)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.content: cardinality.lower, COMPOSITION.context occurrences.lower

one entry

no context

rejected

COMPOSITION.context occurrences.lower

three entries

no context

rejected

COMPOSITION.content: cardinality.upper, COMPOSITION.context occurrences.lower

no entries

context without other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context without other_context

accepted

three entries

context without other_context

rejected

COMPOSITION.content: cardinality.upper

no entries

context with other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context with other_context

accepted

three entries

context with other_context

rejected

COMPOSITION.content: cardinality.upper

14.2.12. Test Case CONT-COMP-content_card_3to5-context_mand

Description: COMPOSITION content cardinality 3..5, context occurrences 1..1

COMPOSITION data sets:

  1. COMPOSITION with no entries (fail)

  2. COMPOSITION with one entry (fail)

  3. COMPOSITION with 3 entries (border case, success)

Combine those cases with:

  1. COMPOSITION with no context

  2. COMPOSITION with context but no other_context

  3. COMPOSITION with context and other_context

All the context structures should be valid.

content context expected constraints violated

no entries

no context

rejected

COMPOSITION.content: cardinality.lower, COMPOSITION.context occurrences.lower

one entry

no context

rejected

COMPOSITION.content: cardinality.lower, COMPOSITION.context occurrences.lower

three entries

no context

rejected

COMPOSITION.context occurrences.lower

no entries

context without other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context without other_context

rejected

COMPOSITION.content: cardinality.lower

three entries

context without other_context

accepted

no entries

context with other_context

rejected

COMPOSITION.content: cardinality.lower

one entry

context with other_context

rejected

COMPOSITION.content: cardinality.lower

three entries

context with other_context

accepted

14.3. OBSERVATION Test Cases

In this section there are specifications of constraint combinations for OBSERVATION.

Each data set in this section could be combined with the test data sets for COMPOSITION.content defined in section 2.

OBSERVATION data sets:

  1. OBSERVATION with no state and no protocol

  2. OBSERVATION with no state and protocol

  3. OBSERVATION with state and no protocol

  4. OBSERVATION with state and protocol

Note
since data is mandatory by the RM we can’t have a case for an AOM constraint with no OBSERVATION data. Though any OBSERVATION committed to the SUT without data will return a validation error comming from the RM/Schema, and this should be tested.

The constraints combinations described below could be tested in two ways:

  1. Isolation: by not constraining OBSERVATION.data, OBSERVATION.state and OBSERVATION.protocol, or using the open/'any allowed' constraint \{*} for those attributes.

  2. Combination: with constraints defined at the HISTORY level (for data and state) and ITEM_STRUCTURE (for protocol).

Note
we suggest to test with both strategies.

14.3.1. Test Case CONT-OBS-state_ex_opt-protocol_ex_opt

Description: OBSERVATION state existence = 0..1, protocol existence = 0..1

data state protocol expected constraints violated

absent

absent

absent

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

absent

absent

present

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

absent

present

absent

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

absent

present

present

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

present

absent

absent

accepted

present

absent

present

accepted

present

present

absent

accepted

present

present

present

accepted

14.3.2. Test Case CONT-OBS-state_ex_opt-protocol_ex_mand

Description: OBSERVATION state existence = 0..1, protocol existence = 1..1

data state protocol expected constraints violated

absent

absent

absent

rejected

OBSERVATION.data existence.lower (RM/schema constraint), OBSERVATION.protocol existence.lower

absent

absent

present

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

absent

present

absent

rejected

OBSERVATION.data existence.lower (RM/schema constraint), OBSERVATION.protocol existence.lower

absent

present

present

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

present

absent

absent

rejected

OBSERVATION.protocol existence.lower

present

absent

present

accepted

present

present

absent

rejected

OBSERVATION.protocol existence.lower

present

present

present

accepted

14.3.3. Test Case CONT-OBS-state_ex_mand-protocol_ex_opt

Description: OBSERVATION state existence = 1..1, protocol existence = 0..1

data state protocol expected constraints violated

absent

absent

absent

rejected

OBSERVATION.data existence.lower (RM/schema constraint), OBSERVATION.state existence.lower

absent

absent

present

rejected

OBSERVATION.data existence.lower (RM/schema constraint), OBSERVATION.state existence.lower

absent

present

absent

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

absent

present

present

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

present

absent

absent

rejected

OBSERVATION.state existence.lower

present

absent

present

rejected

OBSERVATION.state existence.lower

present

present

absent

accepted

present

present

present

accepted

14.3.4. Test Case CONT-OBS-state_ex_mand-protocol_ex_mand

Description: OBSERVATION state existence = 1..1, protocol existence = 1..1

data state protocol expected constraints violated

absent

absent

absent

rejected

OBSERVATION.data existence.lower (RM/schema constraint), OBSERVATION.protocol existence.lower, OBSERVATION.state existence.lower

absent

absent

present

rejected

OBSERVATION.data existence.lower (RM/schema constraint), OBSERVATION.state existence.lower

absent

present

absent

rejected

OBSERVATION.data existence.lower (RM/schema constraint), OBSERVATION.protocol existence.lower

absent

present

present

rejected

OBSERVATION.data existence.lower (RM/schema constraint)

present

absent

absent

rejected

OBSERVATION.protocol existence.lower, OBSERVATION.state existence.lower

present

absent

present

rejected

OBSERVATION.state existence.lower

present

present

absent

rejected

OBSERVATION.protocol existence.lower

present

present

present

accepted

14.4. HISTORY Test Cases

In this section there are specifications of constraint combinations for HISTORY, specified in the openEHR Data Structures IM.

Each data set in this section could be combined with the test data sets for HISTORY defined in section 3.

HISTORY data sets:

  1. HISTORY with no events and no summary

  2. HISTORY with events and no summary

  3. HISTORY with no events and summary

  4. HISTORY with events and summary

The constraints combinations described below could be tested in two ways:

  1. Isolation: by not constraining HISTORY.events and HISTORY.summary, or using the open/'any allowed' constraint \{*} for those attributes.

  2. Combination: with constraints defined at the EVENT level (for events) and ITEM_STRUCTURE (for summary).

Note
we suggest to test with both strategies.

14.4.1. Test Case CONT-HIST-events_card_any-summary_ex_opt

Description: HISTORY events cardinality 0..*, summary existence 0..1

events summary expected constraints violated

no events

absent

accepted

one event

absent

accepted

three events

absent

accepted

no event

present

accepted

one event

present

accepted

three events

present

accepted

14.4.2. Test Case CONT-HIST-events_card_1plus-summary_ex_opt

Description: HISTORY events cardinality 1..*, summary existence 0..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.events cardinality.lower

one event

absent

accepted

three events

absent

accepted

no event

present

rejected

HISTORY.events cardinality.lower

one event

present

accepted

three events

present

accepted

14.4.3. Test Case CONT-HIST-events_card_3plus-summary_ex_opt

Description: HISTORY events cardinality 3..*, summary existence 0..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.events cardinality.lower

one event

absent

rejected

HISTORY.events cardinality.lower

three events

absent

accepted

no event

present

rejected

HISTORY.events cardinality.lower

one event

present

rejected

HISTORY.events cardinality.lower

three events

present

accepted

14.4.4. Test Case CONT-HIST-events_card_opt-summary_ex_opt

Description: HISTORY events cardinality 0..1, summary existence 0..1

events summary expected constraints violated

no events

absent

accepted

one event

absent

accepted

three events

absent

rejected

HISTORY.events cardinality.upper

no event

present

accepted

one event

present

accepted

three events

present

rejected

HISTORY.events cardinality.upper

14.4.5. Test Case CONT-HIST-events_card_mand-summary_ex_opt

Description: HISTORY events cardinality 1..1, summary existence 0..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.events cardinality.lower

one event

absent

accepted

three events

absent

rejected

HISTORY.events cardinality.upper

no event

present

rejected

HISTORY.events cardinality.lower

one event

present

accepted

three events

present

rejected

HISTORY.events cardinality.upper

14.4.6. Test Case CONT-HIST-events_card_3to5-summary_ex_opt

Description: HISTORY events cardinality 3..5, summary existence 0..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.events cardinality.lower

one event

absent

rejected

HISTORY.events cardinality.lower

three events

absent

accepted

no event

present

rejected

HISTORY.events cardinality.lower

one event

present

rejected

HISTORY.events cardinality.lower

three events

present

accepted

14.4.7. Test Case CONT-HIST-events_card_any-summary_ex_mand

Description: HISTORY events cardinality 0..*, summary existence 1..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.summary existence.lower

one event

absent

rejected

HISTORY.summary existence.lower

three events

absent

rejected

HISTORY.summary existence.lower

no event

present

accepted

one event

present

accepted

three events

present

accepted

14.4.8. Test Case CONT-HIST-events_card_1plus-summary_ex_mand

Description: HISTORY events cardinality 1..*, summary existence 1..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.events cardinality.lower, HISTORY.summary existence.lower

one event

absent

rejected

HISTORY.summary existence.lower

three events

absent

rejected

HISTORY.summary existence.lower

no event

present

rejected

HISTORY.events cardinality.lower

one event

present

accepted

three events

present

accepted

14.4.9. Test Case CONT-HIST-events_card_3plus-summary_ex_mand

Description: HISTORY events cardinality 3..*, summary existence 1..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.events cardinality.lower, HISTORY.summary existence.lower

one event

absent

rejected

HISTORY.events cardinality.lower, HISTORY.summary existence.lower

three events

absent

rejected

HISTORY.summary existence.lower

no event

present

rejected

HISTORY.events cardinality.lower

one event

present

rejected

HISTORY.events cardinality.lower

three events

present

accepted

14.4.10. Test Case CONT-HIST-events_card_opt-summary_ex_mand

Description: HISTORY events cardinality 0..1, summary existence 1..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.summary existence.lower

one event

absent

rejected

HISTORY.summary existence.lower

three events

absent

rejected

HISTORY.events cardinality.upper, HISTORY.summary existence.lower

no event

present

accepted

one event

present

accepted

three events

present

rejected

HISTORY.events cardinality.upper

14.4.11. Test Case CONT-HIST-events_card_mand-summary_ex_mand

Description: HISTORY events cardinality 1..1, summary existence 1..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.events cardinality.lower, HISTORY.summary existence.lower

one event

absent

rejected

HISTORY.summary existence.lower

three events

absent

rejected

HISTORY.events cardinality.upper, HISTORY.summary existence.lower

no event

present

rejected

HISTORY.events cardinality.lower

one event

present

accepted

three events

present

rejected

HISTORY.events cardinality.upper

14.4.12. Test Case CONT-HIST-events_card_3to5-summary_ex_mand

Description: HISTORY events cardinality 3..5, summary existence 1..1

events summary expected constraints violated

no events

absent

rejected

HISTORY.events cardinality.lower, HISTORY.summary existence.lower

one event

absent

rejected

HISTORY.events cardinality.lower, HISTORY.summary existence.lower

three events

absent

rejected

HISTORY.summary existence.lower

no event

present

rejected

HISTORY.events cardinality.lower

one event

present

rejected

HISTORY.events cardinality.lower

three events

present

accepted

14.5. EVENT Test Cases

EVENT data sets:

  1. EVENT with no state

  2. EVENT with state

Note
since data is mandatory by the RM we can’t have a case for an AOM constraint with “no EVENT.data”. Though any EVENT committed to the SUT without data will return a validation error comming from the RM/Schema, and this should be tested.

EVENT type combinations:

  1. EVENT is POINT_EVENT

  2. EVENT is INTERVAL_EVENT

Note
testing both EVENT subclasses shouldn’t affect the result of testing combinations with the rest of the constraints defined for EVENT or on container classes. It will affect only the type checking test if the wrong type of EVENT is provided. So instead of combining the expected results with the rest of the constraints, we will define separate test cases.

The constraints combinations described below could be tested in two ways:

  1. Isolation: by not constraining EVENT.data and EVENT.state, or using the open/‘any allowed’ constraint \{*} for those attributes.

  2. Combination: with constraints defined at the ITEM_STRUCTURE level (for data and state).

Note
we suggest to test with both strategies.

14.5.1. Test Case CONT-EVENT-state_ex_opt

Description: EVENT state existence 0..1

data state expected constraints violated

absent

absent

rejected

EVENT.data existence.lower (RM/schema constraint)

absent

present

rejected

EVENT.data existence.lower (RM/schema constraint)

present

absent

accepted

present

present

accepted

14.5.2. Test Case CONT-EVENT-state_ex_mand

Description: EVENT state existence 1..1

data state expected constraints violated

absent

absent

rejected

EVENT.data existence.lower (RM/schema constraint), EVENT.state existence.lower

absent

present

rejected

EVENT.data existence.lower (RM/schema constraint)

present

absent

rejected

EVENT.state existence.lower

present

present

accepted

14.5.3. Test Case CONT-EVENT-type_any

Description: EVENT is any EVENT subtype

In the AOM/TOM the constraint for the EVENT type is using the abstract class EVENT, so it allows any EVENT subclass at this position at runtime.

event expected constraints violated

POINT_EVENT

accepted

INTERVAL_EVENT

accepted

14.5.4. Test Case CONT-EVENT-type_point_event

Description: EVENT is POINT_EVENT

event expected constraints violated

POINT_EVENT

accepted

INTERVAL_EVENT

rejected

Class not allowed

14.5.5. Test Case CONT-EVENT-type_interval_event

Description: EVENT is INTERVAL_EVENT

event expected constraints violated

POINT_EVENT

rejected

Class not allowed

INTERVAL_EVENT

accepted

14.6. ITEM_STRUCTURE Test Cases

ITEM_STRUCTURE type combinations:

  1. ITEM_STRUCTURE is ITEM_TREE

  2. ITEM_STRUCTURE is ITEM_LIST

  3. ITEM_STRUCTURE is ITEM_TABLE

  4. ITEM_STRUCTURE is ITEM_SINGLE

Note
testing with any of the ITEM_STRUCTURE subclasses shouldn’t affect the result of testing combinations with the rest of the constraints defined on container classes. It will affect only the type checking test if the wrong type of ITEM_STRUCTURE is provided. So instead of combining the expected results with the rest of the constraints, we will define separate test cases.

14.6.1. Test Case CONT-ITEM_STR-type_any

Description: ITEM_STRUCTURE is any ITEM_STRUCTURE subtype

In the AOM/TOM the constraint for the ITEM_STRUCTURE type is using the abstract class ITEM_STRUCTURE, so it allows any ITEM_STRUCTURE subclass at this position at runtime.

event expected constraints violated

ITEM_TREE

accepted

ITEM_LIST

accepted

ITEM_TABLE

accepted

ITEM_SINGLE

accepted

14.6.2. Test Case CONT-ITEM_STR-type_item_tree

Description: ITEM_STRUCTURE is ITEM_TREE

event expected constraints violated

ITEM_TREE

accepted

ITEM_LIST

rejected

Class not allowed

ITEM_TABLE

rejected

Class not allowed

ITEM_SINGLE

rejected

Class not allowed

14.6.3. Test Case CONT-ITEM_STR-type_item_list

Description: ITEM_STRUCTURE is ITEM_LIST

event expected constraints violated

ITEM_TREE

rejected

Class not allowed

ITEM_LIST

accepted

ITEM_TABLE

rejected

Class not allowed

ITEM_SINGLE

rejected

Class not allowed

14.6.4. Test Case CONT-ITEM_STR-type_item_table

Description: ITEM_STRUCTURE is ITEM_TABLE

event expected constraints violated

ITEM_TREE

rejected

Class not allowed

ITEM_LIST

rejected

Class not allowed

ITEM_TABLE

accepted

ITEM_SINGLE

rejected

Class not allowed

14.6.5. Test Case CONT-ITEM_STR-type_item_single

Description: ITEM_STRUCTURE is ITEM_SINGLE

event expected constraints violated

ITEM_TREE

rejected

Class not allowed

ITEM_LIST

rejected

Class not allowed

ITEM_TABLE

rejected

Class not allowed

ITEM_SINGLE

accepted

14.7. Data Types - Basic Package

14.7.1. DV_BOOLEAN

Internally DV_BOOLEAN is constrained by C_BOOLEAN.

14.7.1.1. Test Case CONT-DV_BOOLEAN-anything_allowed
value C_BOOLEAN.true_valid C_BOOLEAN.false_valid expected constraints violated

true

true

true

accepted

false

true

true

accepted

14.7.1.2. Test Case CONT-DV_BOOLEAN-only_true_allowed
value C_BOOLEAN.true_valid C_BOOLEAN.false_valid expected constraints violated

true

true

false

accepted

false

true

false

rejected

C_BOOLEAN.false_valid

14.7.1.3. Test Case CONT-DV_BOOLEAN-only_false_allowed
value C_BOOLEAN.true_valid C_BOOLEAN.false_valid expected constraints violated

true

false

true

accepted

C_BOOLEAN.true_valid

false

false

true

accepted

14.7.2. DV_IDENTIFIER

Internally DV_IDENTIFIER attributes are constrainted by C_STRING.

Note the constraints for each attribute are all checked, so the errors are accumulated. If one validation fails for one attribute, the validation for the whole type fails.

14.7.2.1. Test Case CONT-DV_IDENTIFIER-validate_all_pattern
issuer C_STRING.pattern C_STRING.list expected constraints violated

NULL

XYZ.*

NULL

rejected

C_STRING.pattern

ABC

XYZ.*

NULL

rejected

C_STRING.pattern

XYZ

XYZ.*

NULL

accepted

assigner C_STRING.pattern C_STRING.list expected constraints violated

NULL

XYZ.*

NULL

rejected

C_STRING.pattern

ABC

XYZ.*

NULL

rejected

C_STRING.pattern

XYZ

XYZ.*

NULL

accepted

id C_STRING.pattern C_STRING.list expected constraints violated

NULL

XYZ.*

NULL

rejected

RM/Schema: this is mandatory in the RM

ABC

XYZ.*

NULL

rejected

C_STRING.pattern

XYZ

XYZ.*

NULL

accepted

type C_STRING.pattern C_STRING.list expected constraints violated

NULL

XYZ.*

NULL

rejected

C_STRING.pattern

ABC

XYZ.*

NULL

rejected

C_STRING.pattern

XYZ

XYZ.*

NULL

accepted

14.7.2.2. Test Case CONT-DV_IDENTIFIER-validate_all_list
issuer C_STRING.pattern C_STRING.list expected constraints violated

NULL

NULL

[XYZ]

rejected

C_STRING.list

ABC

NULL

[XYZ]

rejected

C_STRING.list

XYZ

NULL

[XYZ]

accepted

assigner C_STRING.pattern C_STRING.list expected constraints violated

NULL

NULL

[XYZ]

rejected

C_STRING.list

ABC

NULL

[XYZ]

rejected

C_STRING.list

XYZ

NULL

[XYZ]

accepted

id C_STRING.pattern C_STRING.list expected constraints violated

NULL

NULL

[XYZ]

rejected

RM/Schema: this is mandatory in the RM

ABC

NULL

[XYZ]

rejected

C_STRING.list

XYZ

NULL

[XYZ]

accepted

type C_STRING.pattern C_STRING.list expected constraints violated

NULL

NULL

[XYZ]

rejected

C_STRING.list

ABC

NULL

[XYZ]

rejected

C_STRING.list

XYZ

NULL

[XYZ]

accepted

14.7.3. DV_STATE

Note
this datatype is not used and not supported by modeling tools (Discourse discussion).

14.8. Data Types - text Package

14.8.1. DV_TEXT

Internally DV_TEXT can be constrained by a C_STRING. This type also allows an instance of the subclass DV_CODED_TEXT at runtime.

14.8.1.1. Test Case CONT-DV_TEXT-validate_open

In ADL this would mean the C_OBJECT for DV_TEXT matches {*}, but different Archetype Editors might model this differently, for instance LinkEHR does a DV_TEXT.value matches {'.*'} which is using the C_STRING pattern that matches anything.

value C_STRING.pattern C_STRING.list expected constraints violated

NULL

NULL

NULL

rejected

RM/Schema mandatory

ABC

NULL

NULL

accepted

XYZ

NULL

NULL

accepted

14.8.1.2. Test Case CONT-DV_TEXT-validate_open
Note
if the type is DV_CODED_TEXT at runtime, the value attribte still needs to comply with the C_STRING constraint.
value C_STRING.pattern C_STRING.list expected constraints violated

NULL

XYZ

NULL

rejected

RM/Schema mandatory

ABC

XYZ

NULL

rejected

C_STRING.pattern

XYZ

XYZ

NULL

accepted

14.8.1.3. Test Case CONT-DV_TEXT-validate_list
Note
if the type is DV_CODED_TEXT at runtime, the value attribte still needs to comply with the C_STRING constraint.
value C_STRING.pattern C_STRING.list expected constraints violated

NULL

NULL

[XYZ, OPQ]

rejected

RM/Schema mandatory

ABC

NULL

[XYZ, OPQ]

rejected

C_STRING.list

XYZ

NULL

[XYZ, OPQ]

accepted

14.8.2. DV_CODED_TEXT

Internally the DV_CODED_TEXT can be constrained by a C_CODE_PHRASE. Note that in the cases for DV_TEXT we already tested when the type is constrained by a C_STRING (when the declared type is DV_TEXT but the runtime type is DV_CODED_TEXT).

14.8.2.1. Test Case CONT-DV_CODED_TEXT-validate_open

In ADL this would mean the C_OBJECT for DV_CODED_TEXT matches {*}.

code_string terminology_id C_CODE_PHRASE.
code_list
C_CODE_PHRASE.
terminology_id
expected constraints violated

NULL

NULL

NULL

NULL

rejected

RM/Schema mandatory both code_String and terminology_id

ABC

NULL

NULL

NULL

rejected

RM/Schema mandatory terminology_id

NULL

local

NULL

NULL

rejected

RM/Schema mandatory code_string

ABC

local

NULL

NULL

accepted

82272006

SNOMED-CT

NULL

NULL

accepted

14.8.2.2. Test Case CONT-DV_CODED_TEXT-validate_local_codes
Note
having C_CODE_PHRASE.terminology_id = local and C_CODE_PHRASE.code_list = EMPTY, would be possible at the archetype level, but would be invalid at the template level, so that case is not considered here since it should be validated when the template is uploaded to the SUT.
code_string terminology_id C_CODE_PHRASE.
code_list
C_CODE_PHRASE.
terminology_id
expected constraints violated

NULL

NULL

[ABC, OPQ]

local

rejected

RM/Schema mandatory both code_String and terminology_id

ABC

NULL

[ABC, OPQ]

local

rejected

RM/Schema mandatory terminology_id

NULL

local

[ABC, OPQ]

local

rejected

RM/Schema mandatory code_string

ABC

local

[ABC, OPQ]

local

accepted

82272006

SNOMED-CT

[ABC, OPQ]

local

rejected

C_CODE_PHRASE.terminology_id

14.8.2.3. Test Case CONT-DV_CODED_TEXT-validate_ext_term

In this case the DV_CODED_TEXT is constrained by a CONSTRAINT_REF. For the CONSTRAINT_REF to be valid in the template, there shoudld be a constraint_binding entry in the template ontology for the acNNNN code of the CONSTRAINT_REF. Without that, the SUT doesn’t know which terminology_id can be used in that DV_CODED_TEXT. Note that multiple bindings are possible, so there could be more than one terminology_id for the coded text. The cases where there are no constraint_bindings are not tested here, that should be part of the OPT validation.

Note
the COSNTRAINT_REF in ADL is transformed by the Template Designer into a C_CODE_REFERENCE in OPT, which is a C_CODE_PHRASE subclass with an extra referenceSetUri attribute.
code_string terminology_id CONSTRAINT_REF.
reference
constraint_bindings expected constraints violated

NULL

NULL

ac0001

[SNOMED_CT]

rejected

RM/Schema mandatory both code_String and terminology_id

ABC

NULL

ac0001

[SNOMED_CT]

rejected

RM/Schema mandatory terminology_id

NULL

local

ac0001

[SNOMED_CT]

rejected

RM/Schema mandatory code_string

ABC

local

ac0001

[SNOMED_CT]

rejected

constraint_binding: terminology_id not found

82272006

SNOMED-CT

ac0001

[SNOMED_CT]

accepted

14.8.3. DV_PARAGRAPH

Note
this DB is not used or supported by modeling tools, see https://discourse.openehr.org/t/is-dv-paragraph-used/2187

14.9. Data Types - quantity Package

14.9.1. DV_ORDINAL

DV_ORDINAL is constrained by C_DV_ORDINAL from the openEHR AM 1.4 Archetype Profile, which contains a list of DV_ORDINAL that could be empty.

Note
in ADL it is possible to have a C_DV_ORDINAL constraint with an empty list constraint. At the OPT level this case should be invalid, since is like defining a constraint for a DV_CODED_TEXT with terminology_id local but no given codes, since all codes in a C_DV_ORDINAL have terminology_id local, at least one code in the list is required at the OPT level. This constraint is valid at the archetypel evel. See commend on 2.3.2.
14.9.1.1. Test Case CONT-DV_ORDINAL-validate_open

This case is when the ADL has DV_ORDINAL matches {*}

symbol value expected constraints violated

NULL

NULL

rejected

RM/Schema value and symbol are mandatory

NULL

1

rejected

RM/Schema symbol is mandatory

local::at0005

NULL

rejected

RM/Schema value is mandatory

local::at0005

1

accepted

local::at0005

666

accepted

14.9.1.2. Test Case CONT-DV_ORDINAL-validate_constraint
symbol value C_DV_ORDINAL.list expected constraints violated

local::at0005

1

1|[local::at0005], 2|[local::at0006]

accepted

local::at0005

666

1|[local::at0005], 2|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching value

local::at0666

1

1|[local::at0005], 2|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching symbol

14.9.2. DV_SCALE

DV_SCALE was introduced to the RM 1.1.0 (Discourse discussion), it is analogous to DV_ORDINAL with a Real value. So test cases for DV_SCALE and DV_ORDINAL are similar.

Note
if this specification is implemented on a system that supports a RM < 1.1.0, then these tests shouldn’t run against the system.
14.9.2.1. Test Case CONT-DV_SCALE-validate_open

This case is when the ADL has DV_SCALE matches {*}

symbol value expected constraints violated

NULL

NULL

rejected

RM/Schema value and symbol are mandatory

NULL

1.5

rejected

RM/Schema symbol is mandatory

local::at0005

NULL

rejected

RM/Schema value is mandatory

local::at0005

1.5

accepted

local::at0005

666

accepted

14.9.2.2. Test Case CONT-DV_SCALE-validate_constraint
Note
there is no current C_DV_SCALE constraint in the Archetype Profile, so modeling tools are not yet supporting constraints for this type. This is a [known issue](https://openehr.atlassian.net/browse/SPECPR-381). Though we can assume the constraint type will be analogous to the C_DV_ORDINAL.
symbol value C_DV_SCALE.list expected constraints violated

local::at0005

1.5

1.5|[local::at0005], 2.0|[local::at0006]

accepted

local::at0005

66.6

1.5|[local::at0005], 2.0|[local::at0006]

rejected

C_DV_SCALE.list: no matching value

local::at0666

1.5

1.5|[local::at0005], 2.0|[local::at0006]

rejected

C_DV_SCALE.list: no matching symbol

14.9.3. DV_COUNT

Internally this type is constrained by a C_INTEGER which could contain a range or a list of values.

14.9.3.1. Test Case CONT-DV_COUNT-validate_open

This case represents the DV_COUNT matching {*}, in this case the C_INTEGER is not present in the OPT.

magnitude expected constraints violated

NULL

rejected

RM/Schema magnitude is mandatory

0

accepted

1

accepted

15

accepted

30

accepted

14.9.3.2. Test Case CONT-DV_COUNT-validate_range
magnitude C_INTEGER.range C_INTEGER.list expected constraints violated

NULL

10..20

NULL

rejected

RM/Schema magnitude is mandatory

0

10..20

NULL

rejected

C_INTEGER.range

1

10..20

NULL

rejected

C_INTEGER.range

15

10..20

NULL

accepted

30

10..20

NULL

rejected

C_INTEGER.range

14.9.3.3. Test Case CONT-DV_COUNT-validate_list
Note
some modeling tools might not support the list constraint.
magnitude C_INTEGER.range C_INTEGER.list expected constraints violated

NULL

NULL

[10,15,20]

rejected

RM/Schema magnitude is mandatory

0

NULL

[10,15,20]

rejected

C_INTEGER.list

1

NULL

[10,15,20]

rejected

C_INTEGER.list

15

NULL

[10,15,20]

accepted

30

NULL

[10,15,20]

rejected

C_INTEGER.list

14.9.4. DV_QUANTITY

Internally DV_QUANTITY is constrained by a C_DV_QUANTITY, which allows to specify an optional physical property and a list of C_QUANTITY_ITEM, which can contain a mandatory units and optional interval constraints for magnitude and precision.

14.9.4.1. Test Case CONT-DV_QUANTITY-validate_open

This case represents the DV_QUANTITY matching {*}, in this case the C_DV_QUANTITY is not present in the OPT.

magnitude units expected constraints violated

NULL

NULL

rejected

RM/Schema both magnitude and untis are mandatory

NULL

cm

rejected

RM/Schema magnitude is mandatory

1.0

NULL

rejected

RM/Schema untis is mandatory

0.0

cm

accepted

1.0

cm

accepted

5.7

cm

accepted

10.0

cm

accepted

14.9.4.2. Test Case CONT-DV_QUANTITY-validate_property

The C_DV_QUANTITY is present in the OPT and has a value for property, but doesn’t have a list of C_QUANTITY_ITEM.

Note
in this case all units for the property are allowed, so the validation should look into UCUM for all the possible units of measure or that physical property (the possible values are not un the OPT).
magnitude units C_DV_QUANTITY.property C_DV_QUANTITY.list expected constraints violated

NULL

NULL

openehr::122 (length)

NULL

rejected

RM/Schema both magnitude and untis are mandatory

NULL

cm

openehr::122 (length)

NULL

rejected

RM/Schema magnitude is mandatory

1.0

NULL

openehr::122 (length)

NULL

rejected

RM/Schema untis is mandatory

0.0

mg

openehr::122 (length)

NULL

rejected

C_DV_QUANTITY.property: mg is not a length unit

0.0

cm

openehr::122 (length)

NULL

accepted

1.0

cm

openehr::122 (length)

NULL

accepted

5.7

cm

openehr::122 (length)

NULL

accepted

10.0

cm

openehr::122 (length)

NULL

accepted

14.9.4.3. Test Case CONT-DV_QUANTITY-validate_property_units
magnitude units C_DV_QUANTITY.property C_DV_QUANTITY.list expected constraints violated

NULL

NULL

openehr::122 (length)

[cm, m]

rejected

RM/Schema both magnitude and untis are mandatory

NULL

cm

openehr::122 (length)

[cm, m]

rejected

RM/Schema magnitude is mandatory

1.0

NULL

openehr::122 (length)

[cm, m]

rejected

RM/Schema untis is mandatory

0.0

mg

openehr::122 (length)

[cm, m]

rejected

C_DV_QUANTITY.property: mg is not a length unit

0.0

cm

openehr::122 (length)

[cm, m]

accepted

0.0

km

openehr::122 (length)

[cm, m]

rejected

C_DV_QUANTITY.list: km is not allowed

1.0

cm

openehr::122 (length)

[cm, m]

accepted

5.7

cm

openehr::122 (length)

[cm, m]

accepted

10.0

cm

openehr::122 (length)

[cm, m]

accepted

14.9.4.4. Test Case CONT-DV_QUANTITY-validate_property_units_mag
magnitude units C_DV_QUANTITY.property C_DV_QUANTITY.list expected constraints violated

NULL

NULL

openehr::122 (length)

[cm 5.0..10.0, m]

rejected

RM/Schema both magnitude and untis are mandatory

NULL

cm

openehr::122 (length)

[cm 5.0..10.0, m]

rejected

RM/Schema magnitude is mandatory

1.0

NULL

openehr::122 (length)

[cm 5.0..10.0, m]

rejected

RM/Schema untis is mandatory

0.0

mg

openehr::122 (length)

[cm 5.0..10.0, m]

rejected

C_DV_QUANTITY.property: mg is not a length unit

0.0

cm

openehr::122 (length)

[cm 5.0..10.0, m]

rejected

C_DV_QUANTITY.list: magnitude not in range for unit

0.0

km

openehr::122 (length)

[cm 5.0..10.0, m]

rejected

C_DV_QUANTITY.list: km is not allowed

1.0

cm

openehr::122 (length)

[cm 5.0..10.0, m]

rejected

C_DV_QUANTITY.list: magnitude not in range for unit

5.7

cm

openehr::122 (length)

[cm 5.0..10.0, m]

accepted

10.0

cm

openehr::122 (length)

[cm 5.0..10.0, m]

accepted

14.9.5. DV_PROPORTION

The DV_PROPORTION is contrained by a C_COMPLEX_OBJECT, which internally has C_REAL constraints for numerator and denominator. C_REAL defines two types of constraints: range and list of values. Though current modeling tools only allow range contraints. For the type atribute, a C_INTEGER constraint is used, which can hold list and range constraints but modeling tools only use the list.

This type has intrinsic constraints that should be semantically consistent depending on the value of the numerator, denominator, precision and type attributes. For instance, this if type = 2, the denominator value should be 100 and can’t be anything else. In te table below we express the valid combinations of attribute values.

type meaning (kind) numerator denominator precision comment

0

ratio

any

any != 0

any

1

unitary

any

1

any

2

percent

any

100

any

3

fraction

integer

integer != 0

0

presentation is num/den

4

integer fraction

integer

integer != 0

0

presentation is integral(num/den) decimal(num/den), e.g. for num=3 den=2: 1 1/2

Note
the difference between fraction and integer fraction is the presentation, the data and constraints are the same.
14.9.5.1. Test Case CONT-DV_PROPORTION-validate_open

This test case is used to check the internal rules of the DV_PROPORTION are correctly implemented by the SUT.

type meaning (kind) numerator denominator precision expected constraints violated

0

ratio

10

500

0

accepted

0

ratio

10

0

0

rejected

valid_denominator (invariant)

1

unitary

10

1

0

accepted

1

unitary

10

0

0

rejected

valid_denominator (invariant)

1

unitary

10

500

0

rejected

unitary_validity (invariant)

2

percent

10

0

0

rejected

valid_denominator (invariant)

2

percent

10

100

0

accepted

2

percent

10

500

0

rejected

percent_validity (invariant)

3

fraction

10

0

0

rejected

valid_denominator (invariant)

3

fraction

10

100

0

accepted

3

fraction

10

500

1

rejected

fraction_validity (invariant)

3

fraction

10.5

500

1

rejected

is_integral_validity (invariant)

3

fraction

10

500.5

1

rejected

is_integral_validity (invariant)

4

integer fraction

10

0

0

rejected

valid_denominator (invariant)

4

integer fraction

10

100

0

accepted

4

integer fraction

10

500

1

rejected

fraction_validity (invariant)

4

integer fraction

10.5

500

1

rejected

is_integral_validity (invariant)

4

integer fraction

10

500.5

1

rejected

is_integral_validity (invariant)

666

10

500

0

rejected

type_validity (invariant)

14.9.5.2. Test Case CONT-DV_PROPORTION-validate_ratio

The C_INTEGER constraint applies to the type attribute.

type meaning (kind) numerator denominator precision C_INTEGER.list expected constraints violated

0

ratio

10

500

0

[0]

accepted

1

unitary

10

1

0

[0]

rejected

C_INTEGER.list

2

percent

10

100

0

[0]

rejected

C_INTEGER.list

3

fraction

10

500

0

[0]

rejected

C_INTEGER.list

4

integer fraction

10

500

0

[0]

rejected

C_INTEGER.list

Note
all the fail cases related with invariants were already contemplated in 3.6.1.
14.9.5.3. Test Case CONT-DV_PROPORTION-validate_unitary

The C_INTEGER constraint applies to the type attribute.

type meaning (kind) numerator denominator precision C_INTEGER.list expected constraints violated

0

ratio

10

500

0

[1]

reejcted

C_INTEGER.list

1

unitary

10

1

0

[1]

accepted

2

percent

10

100

0

[1]

rejected

C_INTEGER.list

3

fraction

10

500

0

[1]

rejected

C_INTEGER.list

4

integer fraction

10

500

0

[1]

rejected

C_INTEGER.list

14.9.5.4. Test Case CONT-DV_PROPORTION-validate_percent

The C_INTEGER constraint applies to the type attribute.

type meaning (kind) numerator denominator precision C_INTEGER.list expected constraints violated

0

ratio

10

500

0

[2]

reejcted

C_INTEGER.list

1

unitary

10

1

0

[2]

rejected

C_INTEGER.list

2

percent

10

100

0

[2]

accepted

3

fraction

10

500

0

[2]

rejected

C_INTEGER.list

4

integer fraction

10

500

0

[2]

rejected

C_INTEGER.list

14.9.5.5. Test Case CONT-DV_PROPORTION-validate_fraction

The C_INTEGER constraint applies to the type attribute.

| type | meaning (kind) | numerator | denominator | precision | C_INTEGER.list | expected | constraints violated

0 ratio 10 500 0 [3] rejected C_INTEGER.list

1

unitary

10

1

0

[3]

rejected

C_INTEGER.list

2

percent

10

100

0

[3]

rejected

C_INTEGER.list

3

fraction

10

500

0

[3]

accepted

4

integer fraction

10

500

0

[3]

rejected

C_INTEGER.list

14.9.5.6. Test Case CONT-DV_PROPORTION-validate_integer_fraction

The C_INTEGER constraint applies to the type attribute.

type meaning (kind) numerator denominator precision C_INTEGER.list expected constraints violated

0

ratio

10

500

0

[4]

reejcted

C_INTEGER.list

1

unitary

10

1

0

[4]

rejected

C_INTEGER.list

2

percent

10

100

0

[4]

rejected

C_INTEGER.list

3

fraction

10

500

0

[4]

rejected

C_INTEGER.list

4

integer fraction

10

500

0

[4]

accepted

14.9.5.7. Test Case CONT-DV_PROPORTION-validate_any_fraction

This case is similar to the previous one, it just tests a combination of possible types for the proportion.

type meaning (kind) numerator denominator precision C_INTEGER.list expected constraints violated

0

ratio

10

500

0

[3, 4]

reejcted

C_INTEGER.list

1

unitary

10

1

0

[3, 4]

rejected

C_INTEGER.list

2

percent

10

100

0

[3, 4]

rejected

C_INTEGER.list

3

fraction

10

500

0

[3, 4]

accepted

4

integer fraction

10

500

0

[3, 4]

accepted

14.9.5.8. Test Case CONT-DV_PROPORTION-validate_ratio_range

The C_INTEGER constraint applies to the type attribute. The C_REAL constraints apply to numerator and denominator respectively.

type meaning (kind) numerator denominator precision C_INTEGER.list C_REAL.range (num) C_REAL.range (den) expected constraints violated

0

ratio

10

500

0

[0]

5..20

200..600

accepted

0

ratio

10

1

0

[0]

5..20

200..600

rejected

C_REAL.range (den)

0

ratio

30

500

0

[0]

5..20

200..600

rejected

C_REAL.range (num)

0

ratio

3

1000

0

[0]

5..20

200..600

rejected

C_REAL.range (num), C_REAL.range (den)

14.9.6. DV_INTERVAL<DV_COUNT>

14.9.6.1. Test Case CONT-DV_INTERVAL_DV_COUNT-validate_open

The DV_INTERVAL<DV_COUNT> constraint is {*}.

Note
the failure instance for this test case are related with violated interval semantics.
lower upper lower_unbounded upper_unbounded lower_included upper_included expected constraints violated

NULL

NULL

true

true

false

false

accepted

NULL

100

true

false

false

false

accepted

NULL

100

true

false

false

true

accepted

0

NULL

false

true

false

false

accepted

0

NULL

false

true

true

false

accepted

-20

-5

false

false

false

false

accepted

0

100

false

false

true

true

accepted

10

100

false

false

true

true

accepted

-50

50

false

false

true

true

accepted

NULL

NULL

true

true

true

false

rejected

lower_included_valid (invariant)

0

NULL

false

true

false

true

rejected

upper_included_valid (invariant)

200

100

false

false

true

true

rejected

limits_consistent (invariant)

14.9.6.2. Test Case CONT-DV_INTERVAL_DV_COUNT-validate_lower_upper

Lower and upper are DV_COUNT, which are constrainted internally by C_INTEGER. C_INTEGER has range and list constraints.

Note
the lower and upper limits are not constrained in terms of existence or occurrences, so both are optional.
lower upper lower_unbounded upper_unbounded lower_included upper_included C_INTEGER.range (lower) C_INTEGER.range (upper) expected constraints violated

NULL

NULL

true

true

false

false

0..100

0..100

accepted

0

NULL

false

true

true

false

0..100

0..100

accepted

NULL

100

true

false

false

true

0..100

0..100

accepted

0

100

false

false

true

true

0..100

0..100

accepted

-10

100

false

false

true

true

0..100

0..100

rejected

C_INTEGER.range (lower)

0

200

false

false

true

true

0..100

0..100

rejected

C_INTEGER.range (upper)

-10

200

false

false

true

true

0..100

0..100

rejected

C_INTEGER.range (lower), C_INTEGER.range (upper)

14.9.6.3. Test Case CONT-DV_INTERVAL_DV_COUNT-validate_lower_upper_list

Lower and upper are DV_COUNT, which are constrainted internally by C_INTEGER. C_INTEGER has range and list constraints.

Note
not all modeling tools allow a list constraint for the lower and upper attributes of the DV_INTERVAL.
lower upper lower_unbounded upper_unbounded lower_included upper_included C_INTEGER.list (lower) C_INTEGER.list (upper) expected constraints violated

NULL

NULL

true

true

false

false

[0, 5, 10, 100]

[0, 5, 10, 100]

accepted

0

NULL

false

true

true

false

[0, 5, 10, 100]

[0, 5, 10, 100]

accepted

NULL

100

true

false

false

true

[0, 5, 10, 100]

[0, 5, 10, 100]

accepted

0

100

false

false

true

true

[0, 5, 10, 100]

[0, 5, 10, 100]

accepted

-10

100

false

false

true

true

[0, 5, 10, 100]

[0, 5, 10, 100]

rejected

C_INTEGER.list (lower)

0

200

false

false

true

true

[0, 5, 10, 100]

[0, 5, 10, 100]

rejected

C_INTEGER.list (upper)

-10

200

false

false

true

true

[0, 5, 10, 100]

[0, 5, 10, 100]

rejected

C_INTEGER.list (lower), C_INTEGER.list (upper)

14.9.7. DV_INTERVAL<DV_QUANTITY>

14.9.7.1. Test Case CONT-DV_INTERVAL_DV_QUANTITY-validate_open

The DV_INTERVAL<DV_QUANTITY> constraint is {*}.

Note
the failure instance for this test case are related with violated interval semantics.
lower upper lower_unbounded upper_unbounded lower_included upper_included expected constraints violated

NULL

NULL

true

true

false

false

accepted

NULL

100 mg

true

false

false

false

accepted

NULL

100 mg

true

false

false

true

accepted

0 mg

NULL

false

true

false

false

accepted

0 mg

NULL

false

true

true

false

accepted

0 mg

100 mg

false

false

true

true

accepted

10 mg

100 mg

false

false

true

true

accepted

NULL

NULL

true

true

true

false

rejected

lower_included_valid (invariant)

0 mg

NULL

false

true

false

true

rejected

upper_included_valid (invariant)

200 mg

100 mg

false

false

true

true

rejected

limits_consistent (invariant)

14.9.7.2. Test Case CONT-DV_INTERVAL_DV_QUANTITY-validate_upper_lower

The lower and upper constraints are C_DV_QUANTITY.

Note
in all cases the C_DV_QUANTITY.property referes to temperature to keep tests as simple as possible and be able to use negative values (for other physical properties negative values don’t make sense). All temperatures will be measured in degree Celsius (Cel in UCUM).
lower upper lower_unbounded upper_unbounded lower_included upper_included C_DV_QUANTITY.list (lower) C_DV_QUANTITY.list (upper) expected constraints violated

NULL

NULL

true

true

false

false

[0..100 Cel]

[0..100 Cel]

accepted

0 Cel

NULL

false

true

true

false

[0..100 Cel]

[0..100 Cel]

accepted

NULL

100 Cel

true

false

false

true

[0..100 Cel]

[0..100 Cel]

accepted

0 Cel

100 Cel

false

false

true

true

[0..100 Cel]

[0..100 Cel]

accepted

-10 Cel

100 Cel

false

false

true

true

[0..100 Cel]

[0..100 Cel]

rejected

C_DV_QUANTITY (lower)

0 Cel

200 Cel

false

false

true

true

[0..100 Cel]

[0..100 Cel]

rejected

C_DV_QUANTITY (upper)

-10 Cel

200 Cel

false

false

true

true

[0..100 Cel]

[0..100 Cel]

rejected

C_DV_QUANTITY (lower),C_DV_QUANTITY (upper)

14.9.8. DV_INTERVAL<DV_DATE_TIME>

14.9.8.1. Test Case CONT-DV_INTERVAL_DV_DATE_TIME-validate_open

The DV_INTERVAL<DV_DATE_TIME> constraint is {*}.

lower upper lower_unbounded upper_unbounded lower_included upper_included expected constraints violated

NULL

NULL

false

false

true

true

rejected

RM/Schema: value is mandatory for lower and upper

NULL

""

false

false

true

true

rejected

RM/Schema: value is mandatory for lower. ISO8601: at least year is required for upper.

""

NULL

false

false

true

true

rejected

ISO8601: at least year is required for lower. RM/Schema: value is mandatory for upper.

2021

NULL

false

false

true

true

rejected

RM/Schema: value is mandatory for upper.

NULL

2022

false

false

true

true

rejected

RM/Schema: value is mandatory for lower.

2021

2022

false

false

true

true

accepted

2021-00

2022-01

false

false

true

true

rejected

ISO8601: month in 01..12 for lower.

2021-01

2022-01

false

false

true

true

accepted

2021-01-00

2022-01-01

false

false

true

true

rejected

ISO8601: day in 01..31 for lower.

2021-01-32

2022-01-01

false

false

true

true

rejected

ISO8601: day in 01..31 for lower.

2021-01-01

2022-01-00

false

false

true

true

rejected

ISO8601: day in 01..31 for upper.

2021-01-30

2022-01-00

false

false

true

true

rejected

ISO8601: day in 01..31 for upper.

2021-01-30

2022-01-15

false

false

true

true

accepted

2021-10-24T48

2022-01-15T10

false

false

true

true

rejected

ISO8601: hours in 00..23 for lower.

2021-10-24T21

2022-01-15T73

false

false

true

true

rejected

ISO8601: hours in 00..23 for upper.

2021-10-24T05

2022-01-15T10

false

false

true

true

accepted

2021-10-24T05:95

2022-01-15T10:45

false

false

true

true

rejected

ISO8601: minutes in 00..59 for lower.

2021-10-24T05:30

2022-01-15T10:61

false

false

true

true

rejected

ISO8601: minutes in 00..59 for upper.

2021-10-24T05:30

2022-01-15T10:45

false

false

true

true

accepted

2021-10-24T05:30:78

2022-01-15T10:45:13

false

false

true

true

rejected

ISO8601: seconds in 00..59 for lower.

2021-10-24T05:30:47

2022-01-15T10:45:69

false

false

true

true

rejected

ISO8601: seconds in 00..59 for upper.

2021-10-24T05:30:47

2022-01-15T10:45:13

false

false

true

true

accepted

2021-10-24T05:30:47.5

2022-01-15T10:45:13.6

false

false

true

true

accepted

2021-10-24T05:30:47.333

2022-01-15T10:45:13.555

false

false

true

true

accepted

2021-10-24T05:30:47.333333

2022-01-15T10:45:13.555555

false

false

true

true

accepted

2021-10-24T05:30:47Z

2022-01-15T10:45:13Z

false

false

true

true

accepted

2021-10-24T05:30:47-03:00

2022-01-15T10:45:13-03:00

false

false

true

true

accepted

14.9.8.2. Test Case CONT-DV_INTERVAL_DV_DATE_TIME-validate_lower_upper_constraint
Note
the C_DATE_TIME has invariants that define if a higher precision component is optional or prohibited, lower precision components should be optional or prohibited. In other words, if month is optional, day, hours, minutes, etc. are optional or prohibited. These invariants should be checked in an archetype editor and template editor, we consider the following tests to follow those rules without checking them, since that is related to archetype/template validation, not with data validation.
Note
if different components of each lower/upper date time expression fail the validity constraint for mandatory, the only required contraint violated to be reported is the higher precision one, since it implies the lower precision components will also fail. For instance if the hour, second and millisecond are mandatory, and the corresponding date time expression doesn’t have hour, it is accepted if the reported constraints violated is only the hour_validity, and optionally the SUT can report the minute_validity, second_validity and millisecond_validity constraints as violated too. In the data sets below we show all the constraints violated.
lower upper lower_unbounded upper_unbounded lower_included upper_included month_val. (lower) day_val. (lower) month_val. (upper) day_val. (upper) hour_val. (lower) minute_val. (lower) second_val. (lower) millisecond_val. (lower) timezone_val. (lower) hour_val. (upper) minute_val. (upper) second_val. (upper) millisecond_val. (upper) timezone_val. (upper) expected constraints violated

2021

2022

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

month_val. (lower), day_val. (lower), month_val. (upper), day_val. (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), second_val. (lower), second_val. (upper), millisecond_val. (lower), millisecond_val. (upper), timezone_val. (lower), timezone__val. (upper)

2021

2022

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

month_validity (lower), month_validity (upper), timezone_val. (lower), timezone__val. (upper)

2021

2022

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

rejected

month_validity (lower), month_validity (upper)

2021

2022

false

false

true

true

optional

optional

optional

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021

2022

false

false

true

true

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

accepted

2021

2022

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

mandatory

rejected

month_validity (lower), month_validity (upper), timezone_val. (lower), timezone__val. (upper)

2021

2022

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), month_validity (upper)

2021

2022

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021

2022

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

accepted

2021-10

2022-10

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

day_validity (lower), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), second_val. (lower), second_val. (upper), millisecond_val. (lower), millisecond_val. (upper), timezone_val. (lower), timezone__val. (upper)

2021-10

2022-10

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone_val. (upper)

2021-10

2022-10

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10

2022-10

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

mandatory

prohibited

prohibited

prohibited

mandatory

mandatory

rejected

timezone_val. (lower), timezone_val. (upper)

2021-10

2022-10

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

accepted

2021-10

2022-10

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

mandatory

rejected

month_validity (lower), month_validity (upper), timezone_val. (lower), timezone_val. (upper)

2021-10

2022-10

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), month_validity (upper)

lower upper lower_unbounded upper_unbounded lower_included upper_included month_val. (lower) day_val. (lower) month_val. (upper) day_val. (upper) hour_val. (lower) minute_val. (lower) second_val. (lower) millisecond_val. (lower) timezone_val. (lower) hour_val. (upper) minute_val. (upper) second_val. (upper) millisecond_val. (upper) timezone_val. (upper) expected constraints violated

2021-10-24

2022-10-24

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), second_val. (lower), second_val. (upper), millisecond_val. (lower), millisecond_val. (upper), timezone_val. (lower), timezone_val. (upper)

2021-10-24

2022-10-24

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

mandatory

mandatory

optional

optional

optional

mandatory

rejected

hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), timezone_val. (lower), timezone_val. (upper)

2021-10-24

2022-10-24

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

mandatory

optional

optional

optional

optional

rejected

hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper)

2021-10-24

2022-10-24

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24

2022-10-24

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24

2022-10-24

false

false

true

true

optional

optional

optional

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24

2022-10-24

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity (lower), day_validity (upper)

2021-10-24

2022-10-24

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper)

2021-10-24T22

2022-10-24T07

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

minute_val. (lower), minute_val. (upper), second_val. (lower), second_val. (upper), millisecond_val. (lower), millisecond_val. (upper), timezone_val. (lower), timezone_val. (upper)

2021-10-24T22

2022-10-24T07

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

mandatory

mandatory

optional

optional

optional

mandatory

rejected

minute_val. (lower), minute_val. (upper), timezone_val. (lower), timezone_val. (upper)

2021-10-24T22

2022-10-24T07

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

mandatory

optional

optional

optional

optional

rejected

minute_val. (lower), minute_val. (upper)

2021-10-24T22

2022-10-24T07

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24T22

2022-10-24T07

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T22

2022-10-24T07

false

false

true

true

optional

optional

optional

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24T22

2022-10-24T07

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity (lower), day_validity (upper), hour_val. (lower), hour_val. (upper)

2021-10-24T22

2022-10-24T07

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper), hour_val. (lower), hour_val. (upper)

lower upper lower_unbounded upper_unbounded lower_included upper_included month_val. (lower) day_val. (lower) month_val. (upper) day_val. (upper) hour_val. (lower) minute_val. (lower) second_val. (lower) millisecond_val. (lower) timezone_val. (lower) hour_val. (upper) minute_val. (upper) second_val. (upper) millisecond_val. (upper) timezone_val. (upper) expected constraints violated

2021-10-24T22:10

2022-10-24T07:47

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

second_val. (lower), second_val. (upper), millisecond_val. (lower), millisecond_val. (upper), timezone_val. (lower), timezone_val. (upper)

2021-10-24T22:10

2022-10-24T07:47

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

mandatory

mandatory

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone_val. (upper)

2021-10-24T22:10

2022-10-24T07:47

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

mandatory

optional

optional

optional

optional

accepted

2021-10-24T22:10

2022-10-24T07:47

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24T22:10

2022-10-24T07:47

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T22:10

2022-10-24T07:47

false

false

true

true

optional

optional

optional

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24T22:10

2022-10-24T07:47

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity (lower), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper)

2021-10-24T22:10

2022-10-24T07:47

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper)

2021-10-24T22:10:45

2022-10-24T07:47:13

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

millisecond_val. (lower), millisecond_val. (upper), timezone_val. (lower), timezone_val. (upper)

2021-10-24T22:10:45

2022-10-24T07:47:13

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

mandatory

mandatory

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone_val. (upper)

2021-10-24T22:10:45

2022-10-24T07:47:13

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

mandatory

optional

optional

optional

optional

accepted

2021-10-24T22:10:45

2022-10-24T07:47:13

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24T22:10:45

2022-10-24T07:47:13

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T22:10:45

2022-10-24T07:47:13

false

false

true

true

optional

optional

optional

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24T22:10:45

2022-10-24T07:47:13

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity (lower), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), second_val. (lower), second_val. (upper)

2021-10-24T22:10:45

2022-10-24T07:47:13

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), second_val. (lower), second_val. (upper)

lower upper lower_unbounded upper_unbounded lower_included upper_included month_val. (lower) day_val. (lower) month_val. (upper) day_val. (upper) hour_val. (lower) minute_val. (lower) second_val. (lower) millisecond_val. (lower) timezone_val. (lower) hour_val. (upper) minute_val. (upper) second_val. (upper) millisecond_val. (upper) timezone_val. (upper) expected constraints violated

2021-10-24T22:10:45.5

2022-10-24T07:47:13.666666

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

timezone_val. (lower), timezone_val. (upper)

2021-10-24T22:10:45.5

2022-10-24T07:47:13.666666

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

mandatory

mandatory

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone_val. (upper)

2021-10-24T22:10:45.5

2022-10-24T07:47:13.666666

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

mandatory

optional

optional

optional

optional

accepted

2021-10-24T22:10:45.5

2022-10-24T07:47:13.666666

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24T22:10:45.5

2022-10-24T07:47:13.666666

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T22:10:45.5

2022-10-24T07:47:13.666666

false

false

true

true

optional

optional

optional

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

rejected

timezone_val. (lower), timezone__val. (upper)

2021-10-24T22:10:45.5

2022-10-24T07:47:13.666666

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity (lower), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), seoncd_val. (lower), second_val. (upper), millisecond_val. (lower), millisecond_val. (upper)

2021-10-24T22:10:45.5

2022-10-24T07:47:13.666666

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), seoncd_val. (lower), second_val. (upper), millisecond_val. (lower), millisecond_val. (upper)

2021-10-24T22:10:45Z

2022-10-24T07:47:13Z

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

millisecond_val. (lower), millisecond_val. (upper)

2021-10-24T22:10:45Z

2022-10-24T07:47:13Z

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

mandatory

mandatory

optional

optional

optional

mandatory

accepted

2021-10-24T22:10:45Z

2022-10-24T07:47:13Z

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

mandatory

optional

optional

optional

optional

accepted

2021-10-24T22:10:45Z

2022-10-24T07:47:13Z

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

accepted

2021-10-24T22:10:45Z

2022-10-24T07:47:13Z

false

false

true

true

mandatory

optional

mandatory

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T22:10:45Z

2022-10-24T07:47:13Z

false

false

true

true

optional

optional

optional

optional

optional

optional

optional

optional

mandatory

optional

optional

optional

optional

mandatory

accepted

2021-10-24T22:10:45Z

2022-10-24T07:47:13Z

false

false

true

true

mandatory

prohibited

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity (lower), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), second_val. (lower), second_val. (upper), timezone_val. (lower), timezone_val. (upper)

2021-10-24T22:10:45Z

2022-10-24T07:47:13Z

false

false

true

true

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper), hour_val. (lower), hour_val. (upper), minute_val. (lower), minute_val. (upper), second_val. (lower), second_val. (upper), timezone_val. (lower), timezone_val. (upper)

14.9.8.3. Test Case CONT-DV_INTERVAL_DV_DATE_TIME-validate_lower_upper_range
lower upper lower_unbounded upper_unbounded lower_included upper_included C_DATE_TIME.range (lower) C_DATE_TIME.range (upper) expected constraints violated

2021

2022

false

false

true

true

2020..2030

2020..2030

accepted

2021

2022

false

false

true

true

2000..2010

2020..2030

rejected

C_DATE_TIME.range (lower)

2021

2022

false

false

true

true

2020..2030

2020..2021

rejected

C_DATE_TIME.range (upper)

2021-10

2022-11

false

false

true

true

2020-01..2030-12

2020-01..2030-12

accepted

2021-10

2022-11

false

false

true

true

2000-01..2010-12

2020-01..2030-12

rejected

C_DATE_TIME.range (lower)

2021-10

2022-11

false

false

true

true

2020-01..2030-12

2020-01..2021-12

rejected

C_DATE_TIME.range (upper)

2021-10-24

2022-11-02

false

false

true

true

2020-01-01..2030-12-31

2020-01-01..2030-12-31

accepted

2021-10-24

2022-11-02

false

false

true

true

2000-01-01..2010-12-31

2020-01-01..2030-12-31

rejected

C_DATE_TIME.range (lower)

2021-10-24

2022-11-02

false

false

true

true

2020-01-01..2030-12-31

2020-01-01..2021-12-31

rejected

C_DATE_TIME.range (upper)

2021-10-24T10

2022-11-02T19

false

false

true

true

2020-01-01T00..2030-12-31T23

2020-01-01T00..2030-12-31T23

accepted

2021-10-24T10

2022-11-02T19

false

false

true

true

2000-01-01T00..2010-12-31T23

2020-01-01T00..2030-12-31T23

rejected

C_DATE_TIME.range (lower)

2021-10-24T10

2022-11-02T19

false

false

true

true

2020-01-01T00..2030-12-31T23

2020-01-01T00..2021-12-31T23

rejected

C_DATE_TIME.range (upper)

2021-10-24T10:00

2022-11-02T19:32

false

false

true

true

2020-01-01T00:00..2030-12-31T23:59

2020-01-01T00:00..2030-12-31T23:59

accepted

2021-10-24T10:00

2022-11-02T19:32

false

false

true

true

2000-01-01T00:00..2010-12-31T23:59

2020-01-01T00:00..2030-12-31T23:59

rejected

C_DATE_TIME.range (lower)

2021-10-24T10:00

2022-11-02T19:32

false

false

true

true

2020-01-01T00:00..2030-12-31T23:59

2020-01-01T00:00..2021-12-31T23:59

rejected

C_DATE_TIME.range (upper)

2021-10-24T10:00:10

2022-11-02T19:32:40

false

false

true

true

2020-01-01T00:00:00..2030-12-31T23:59:59

2020-01-01T00:00..2030-12-31T23:59

accepted

2021-10-24T10:00:10

2022-11-02T19:32:40

false

false

true

true

2000-01-01T00:00:00..2010-12-31T23:59:59

2020-01-01T00:00..2030-12-31T23:59

rejected

C_DATE_TIME.range (lower)

2021-10-24T10:00:10

2022-11-02T19:32:40

false

false

true

true

2020-01-01T00:00:00..2030-12-31T23:59:59

2020-01-01T00:00..2021-12-31T23:59

rejected

C_DATE_TIME.range (upper)

2021-10-24T10:00:10.5

2022-11-02T19:32:40.333

false

false

true

true

2020-01-01T00:00:00.0..2030-12-31T23:59:59.999999

2020-01-01T00:00..2030-12-31T23:59

accepted

2021-10-24T10:00:10.5

2022-11-02T19:32:40.333

false

false

true

true

2000-01-01T00:00:00.0..2010-12-31T23:59:59.999999

2020-01-01T00:00..2030-12-31T23:59

rejected

C_DATE_TIME.range (lower)

2021-10-24T10:00:10.5

2022-11-02T19:32:40.333

false

false

true

true

2020-01-01T00:00:00.0..2030-12-31T23:59:59.999999

2020-01-01T00:00..2021-12-31T23:59

rejected

C_DATE_TIME.range (upper)

2021-10-24T10:00:10Z

2022-11-02T19:32:40Z

false

false

true

true

2020-01-01T00:00:00Z..2030-12-31T23:59:59Z

2020-01-01T00:00..2030-12-31T23:59

accepted

2021-10-24T10:00:10Z

2022-11-02T19:32:40Z

false

false

true

true

2000-01-01T00:00:00Z..2010-12-31T23:59:59Z

2020-01-01T00:00..2030-12-31T23:59

rejected

C_DATE_TIME.range (lower)

2021-10-24T10:00:10Z

2022-11-02T19:32:40Z

false

false

true

true

2020-01-01T00:00:00Z..2030-12-31T23:59:59Z

2020-01-01T00:00..2021-12-31T23:59

rejected

C_DATE_TIME.range (upper)

14.9.9. DV_INTERVAL<DV_DATE>

14.9.9.1. Test Case CONT-DV_INTERVAL_DV_DATE-validate_open

On this case, the own rules/invariants of the DV_INTERVAL apply to the validation.

lower upper lower_unbounded upper_unbounded lower_included upper_included expected constraints violated

NULL

NULL

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

NULL

2022

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

2021

NULL

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

2021

2022

false

false

true

true

accepted

2021-01

2022-08

false

false

true

true

accepted

2021-01-20

2022-08-11

false

false

true

true

accepted

2021

2021-10

false

false

true

true

rejected

IMO two dates with different components and common higher order components (year on this case) shouldn’t be strictly comparable, see https://discourse.openehr.org/t/issues-with-date-time-comparison-for-partial-date-time-expressions/2173

NULL

NULL

true

true

false

false

accepted

14.9.9.2. Test Case CONT-DV_INTERVAL_DV_DATE-validate_lower_upper_constraint
Note
this test case doesn’t include all the possible combinations of lower/upper data and constraints for the internal since there could be tens of possible combinations. It would be in the scope of a revision to add more combinations of an exhaustive test case.
Note
the C_DATE has invariants that define if a higher precision component is optional or prohibited, lower precision components should be optional or prohibited. In other words, if month is optional, day should be optional or prohibited. These invariants should be checked in an archetype editor and template editor, we consider the following tests to follow those rules without checking them, since that is related to archetype/template validation, not with data validation.
lower upper lower_unbounded upper_unbounded lower_included upper_included month_val. (lower) day_val. (lower) month_val. (upper) day_val. (upper) expected constraints violated

2021

2022

false

false

true

true

mandatory

mandatory

mandatory

mandatory

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper)

2021

2022

false

false

true

true

mandatory

optional

mandatory

optional

rejected

month_validity (lower), month_validity (upper)

2021

2022

false

false

true

true

optional

optional

optional

optional

accepted

2021

2022

false

false

true

true

mandatory

prohibited

mandatory

prohibited

rejected

month_validity (lower), month_validity (upper)

2021

2022

false

false

true

true

prohibited

prohibited

prohibited

prohibited

accepted

2021-10

2022-10

false

false

true

true

mandatory

mandatory

mandatory

mandatory

rejected

day_validity (lower), day_validity (upper)

2021-10

2022-10

false

false

true

true

mandatory

optional

mandatory

optional

accepted

2021-10

2022-10

false

false

true

true

optional

optional

optional

optional

accepted

2021-10

2022-10

false

false

true

true

mandatory

prohibited

mandatory

prohibited

accepted

2021-10

2022-10

false

false

true

true

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), month_validity (upper)

2021-10-24

2022-10-24

false

false

true

true

mandatory

mandatory

mandatory

mandatory

accepted

2021-10-24

2022-10-24

false

false

true

true

mandatory

optional

mandatory

optional

accepted

2021-10-24

2022-10-24

false

false

true

true

optional

optional

optional

optional

accepted

2021-10-24

2022-10-24

false

false

true

true

mandatory

prohibited

mandatory

prohibited

rejected

day_validity (lower), day_validity (upper)

2021-10-24

2022-10-24

false

false

true

true

prohibited

prohibited

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper)

2021

2022

false

false

true

true

mandatory

mandatory

mandatory

optional

rejected

month_validity (lower), day_validity (lower), month_validity (upper)

2021

2022

false

false

true

true

mandatory

mandatory

optional

optional

rejected

month_validity (lower), day_validity (lower)

2021

2022

false

false

true

true

mandatory

mandatory

mandatory

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper)

2021

2022

false

false

true

true

mandatory

mandatory

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower)

2021

2022-10

false

false

true

true

mandatory

mandatory

mandatory

mandatory

rejected

month_validity (lower), day_validity (lower), day_validity (upper)

2021

2022-10

false

false

true

true

mandatory

mandatory

mandatory

optional

rejected

month_validity (lower), day_validity (lower)

2021

2022-10

false

false

true

true

mandatory

mandatory

optional

optional

rejected

month_validity (lower), day_validity (lower)

2021

2022-10

false

false

true

true

mandatory

mandatory

mandatory

prohibited

rejected

month_validity (lower), day_validity (lower)

2021

2022-10

false

false

true

true

mandatory

mandatory

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper)

2021

2022-10-24

false

false

true

true

mandatory

mandatory

mandatory

mandatory

rejected

month_validity (lower), day_validity (lower)

2021

2022-10-24

false

false

true

true

mandatory

mandatory

mandatory

optional

rejected

month_validity (lower), day_validity (lower)

2021

2022-10-24

false

false

true

true

mandatory

mandatory

optional

optional

rejected

month_validity (lower), day_validity (lower)

2021

2022-10-24

false

false

true

true

mandatory

mandatory

mandatory

prohibited

rejected

month_validity (lower), day_validity (lower), day_validity (upper)

2021

2022-10-24

false

false

true

true

mandatory

mandatory

prohibited

prohibited

rejected

month_validity (lower), day_validity (lower), month_validity (upper), day_validity (upper)

14.9.9.3. Test Case CONT-DV_INTERVAL_DV_DATE-validate_lower_upper_range
lower upper lower_unbounded upper_unbounded lower_included upper_included C_DATE.range (lower) C_DATE.range (upper) expected constraints violated

2021

2022

false

false

true

true

1900..2030

1900..2030

accepted

2021

2022

false

false

true

true

2022..2030

1900..2030

rejected

C_DATE.range (lower)

2021

2022

false

false

true

true

1900..2030

2023..2030

rejected

C_DATE.range (upper)

2021

2022

false

false

true

true

2022..2030

2023..2030

rejected

C_DATE.range (lower), C_DATE.range (upper)

14.9.10. DV_INTERVAL<DV_TIME>

14.9.10.1. Test Case CONT-DV_INTERVAL_DV_TIME-validate_open
lower upper lower_unbounded upper_unbounded lower_included upper_included expected constraints violated

NULL

NULL

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

NULL

T11:00:00

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

T10:00:00

NULL

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

T10

T11

false

false

true

true

accepted

T10:00

T11:00

false

false

true

true

accepted

T10:00:00

T11:00:00

false

false

true

true

accepted

T10

T10:45:00

false

false

true

true

rejected

IMO two times with different components and common higher order components (hour on this case) shouldn’t be strictly comparable, see https://discourse.openehr.org/t/issues-with-date-time-comparison-for-partial-date-time-expressions/2173

NULL

NULL

true

true

false

false

accepted

14.9.10.2. Test Case CONT-DV_INTERVAL_DV_TIME-validate_lower_upper_constraint
lower upper lower_unbounded upper_unbounded lower_included upper_included minute_val. (lower) second_val. (lower) millisecond_val. (lower) timezone_val. (lower) minute_val. (upper) second_val. (upper) millisecond_val. (upper) timezone_val. (upper) expected constraints violated

T10

T11

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

minute_val. (lower), second_val. (lower), millisecond_val. (lower), timezone_val. (lower), minute_val. (upper), second_val. (upper), millisecond_val. (upper), timezone_val. (upper)

T10:00

T11:00

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

second_val. (lower), millisecond_val. (lower), timezone_val. (lower), second_val. (upper), millisecond_val. (upper), timezone_val. (upper)

T10:00:00

T11:00:00

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

millisecond_val. (lower), timezone_val. (lower), millisecond_val. (upper), timezone_val. (upper)

T10:00:00.5

T11:00:00.5

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

timezone_val. (lower) timezone_val. (upper)

T10:00:00.5Z

T11:00:00.5Z

false

false

true

true

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

accepted

TBD: combinations of other values for validity.

14.9.10.3. Test Case CONT-DV_INTERVAL_DV_TIME-validate_lower_upper_range
lower upper lower_unbounded upper_unbounded lower_included upper_included C_TIME.range (lower) C_TIME.range (upper) expected constraints violated

T10

T11

false

false

true

true

T09..T11

T10..T12

accepted

T10:00

T11:00

false

false

true

true

T09:00..T11:00

T10:00..T12:00

accepted

T10:00:00

T11:00:00

false

false

true

true

T09:00:00..T11:00:00

T10:00:00..T12:00:00

accepted

T10:00:00.5

T11:00:00.5

false

false

true

true

T09:00:00.0..T11:00:00.0

T10:00:00.0..T12:00:00.0

accepted

T10:00:00.5Z

T11:00:00.5Z

false

false

true

true

T09:00:00.0..T11:00:00.0Z

T10:00:00.0Z..T12:00:00.0Z

accepted

T10

T11

false

false

true

true

T11..T12

T11..T12

rejected

C_TIME.range (lower)

T10

T12

false

false

true

true

T10..T11

T10..T11

rejected

C_TIME.range (upper)

null

T11

true

false

false

true

T09..T11

T10..T12

rejected

C_TIME.range (lower)

T10

null

false

true

true

false

T09..T11

T10..T12

accepted

C_TIME.range (upper)

14.9.11. DV_INTERVAL<DV_DURATION>

14.9.11.1. Test Case CONT-DV_INTERVAL_DV_DURATION-validate_open
Note
this considers the lower value of the interval should have all it’s components lower or equals to the corresponding component in the upper value. This is to avoid normalization problems. For instance we could have an interval P1Y6M..P2Y which is semantically correct. But if we have values outside the normal boundaries of each component, like P1Y37M..P2Y there is a need of normalization to know if P1Y37M is really lower or equals to P2Y, which is the check ofr a valid internal. In some cases this normalization is doable, but in other cases it is not. For instance, some implementations might not know how many days in a month are, since months have a variable number of days. In the previous case, we know each year has 12 months so P1Y37M can actually be normalized to P4Y1M, but P61D can’t be strictly compared with, let’s say, P3M, since months could have 28, 29, 30 or 31 days, so without other information P61D could be lower or greater than P3M. To simplify this, some implementations might consider the measure of a month, in a duration expression, to be exactly 30 days. These considerations should be stated in the SUT Conformance Statement Document. To simplify writing the test cases for any implementation, we consider if lower is P1Y37M, the valid upper values have Y >= 1 and M >= 37, so P2Y wouldn’t be valid in this context, but P1Y37M..P1Y38M or P1Y37M..P2Y37M would be valid intervals for the test cases. One extra simplification would be to consider values are inside their normal boundaries (hours < 24, days < 31, etc.) but this won’t be encouraged but these test cases. If each component is inside it’s constrainsts it is possible to compare expressions that differ in the components like P1D3H and P10D, since comparison doesn’t require normalization and both values form a semantically valid interval.
lower upper lower_unbounded upper_unbounded lower_included upper_included expected constraints violated comment

NULL

NULL

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

NULL

PT2H

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

PT1H

NULL

false

false

true

true

rejected

IMO should fail, see https://discourse.openehr.org/t/is-dv-interval-missing-invariants/2210

PT1H

PT2H

false

false

true

true

accepted

PT1H

PT2H

false

false

true

true

accepted

P1Y7M3D

P1Y8M3D

false

false

true

true

accepted

P1M5DT3H

P10M

false

false

true

true

accepted

See Note 1.

P2M

P1M

false

false

true

true

rejected

limits_consistent (invariant)

P10M

P1M5DT3H

false

false

true

true

rejected

limits_consistent (invariant)

Notes:

  1. this case has different components in the lower and upper values, this is possible because the values don’t exceed their normal boundaries, e.g. days 31. Without this condition a normalization of the values would be needed, and in some cases the normalization is not possible without some extra constraints, for instance considering P1M is equivalent to P30D.

14.9.11.2. Test Case CONT-DV_INTERVAL_DV_DURATION-validate_constraint
Note
in the openEHR specifications only the seconds can have a fraction, but in the ISO8601 standard, the component at the lowest precision can have a fraction, for instance P0.5Y is a valid ISO 8601 duration.
lower upper lower_
unbounded
upper_
unbounded
lower_
included
upper_
included
years_
allowed
(lower)
months_
allowed
(lower)
weeks_
allowed
(lower)
days_
allowed
(lower)
hours_
allowed
(lower)
minutes_
allowed
(lower)
seconds_
allowed
(lower)
fractional_
seconds_
allowed
(lower)
years_
allowed
(upper)
months_
allowed
(upper)
weeks_
allowed
(upper)
days_
allowed
(upper)
hours_
allowed
(upper)
minutes_
allowed
(upper)
seconds_
allowed
(upper)
fractional_
seconds_
allowed
(upper)
expected constraints
violated
comment

P1Y

P2Y

false

false

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

accepted

P3W

P5W

false

false

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

accepted

P1Y

P2Y

false

false

true

true

false

true

true

true

true

true

true

true

true

true

true

true

true

true

true

true

rejected

years_allowed (lower)

P1Y

P2Y

false

false

true

true

true

true

true

true

true

true

true

true

false

true

true

true

true

true

true

true

rejected

years_allowed (upper)

P1Y1M1DT1H1M1.5S

P2Y

false

false

true

true

true

false

true

true

true

true

true

true

true

true

true

true

true

true

true

true

rejected

months_allowed (lower)

P2W

P2Y

false

false

true

true

true

true

false

true

true

true

true

true

true

true

true

true

true

true

true

true

rejected

weeks_allowed (lower)

P1Y1M1DT1H1M1.5S

P2Y

false

false

true

true

true

true

true

false

true

true

true

true

true

true

true

true

true

true

true

true

rejected

days_allowed (lower)

P1Y1M1DT1H1M1.5S

P2Y

false

false

true

true

true

true

true

true

false

true

true

true

true

true

true

true

true

true

true

true

rejected

hours_allowed (lower)

P1Y1M1DT1H1M1.5S

P2Y

false

false

true

true

true

true

true

true

true

false

true

true

true

true

true

true

true

true

true

true

rejected

minutes_allowed (lower)

P1Y1M1DT1H1M1.5S

P2Y

false

false

true

true

true

true

true

true

true

true

false

true

true

true

true

true

true

true

true

true

rejected

seconds_allowed (lower)

P1Y1M1DT1H1M1.5S

P2Y

false

false

true

true

true

true

true

true

true

true

true

false

true

true

true

true

true

true

true

true

rejected

fractional_seconds_allowed (lower)

14.9.11.3. Test Case CONT-DV_INTERVAL_DV_DURATION-validate_range
lower upper lower_unbounded upper_unbounded lower_included upper_included range.lower (lower) range.upper (lower) range.lower (upper) range.upper (upper) expected constraints violated comment

P1Y

P2Y

false

false

true

true

P1Y

P3Y

P1Y

P3Y

accepted

P1Y

P2Y

false

false

true

true

P2Y

P3Y

P1Y

P3Y

rejected

range.lower (lower)

P1Y

P2Y

false

false

true

true

P1Y

P3Y

P3Y

P4Y

rejected

range.lower (upper)

P5Y

P10Y

false

false

true

true

P2Y

P3Y

P5Y

P15Y

rejected

range.upper (lower)

P5Y

P10Y

false

false

true

true

P1Y

P9Y

P3Y

P9Y

rejected

range.upper (upper)

P5Y4M

P10Y

false

false

true

true

P1Y

P9Y

P3Y

P15Y

accepted

P5Y4M

P10Y

false

false

true

true

P6Y

P9Y

P3Y

P15Y

rejected

range.lower (lower)

P5Y4M

P10Y

false

false

true

true

P5Y4M2D

P9Y

P3Y

P15Y

rejected

range.lower (lower)

P5Y4M20D

P10Y

false

false

true

true

P1Y

P9Y

P3Y

P15Y

accepted

P5Y4M20D

P10Y

false

false

true

true

P5Y6M

P9Y

P3Y

P15Y

rejected

range.lower (lower)

14.9.12. DV_INTERVAL<DV_ORDINAL>

Note
some modeling tools don’t support representing DV_INTERVAL<DV_ORDINAL>.
14.9.12.1. Test Case CONT-DV_INTERVAL_DV_ORDINAL-validate_open

This case is when the ADL has DV_ORDINAL matches {*}

lower.symbol lower.value upper.symbol upper.value lower_unbounded upper_unbounded lower_included upper_included expected constraints violated

NULL

NULL

NULL

NULL

false

false

true

true

rejected

RM/Schema value and symbol are mandatory for lower and upper

NULL

1

NULL

5

false

false

true

true

rejected

RM/Schema symbol is mandatory for lower and upper

local::at0005

NULL

local::at0003

NULL

false

false

true

true

rejected

RM/Schema value is mandatory for lower and upper

local::at0005

1

local::at0002

5

false

false

true

true

accepted

local::at0004

666

local::at0003

777

false

false

true

true

accepted

local::at0003

777

local::at0004

666

false

false

true

true

rejected

RM invariante Interval.Limits_comparable

14.9.12.2. Test Case CONT-DV_INTERVAL_DV_ORDINAL-validate_constraint
lower.symbol lower.value upper.symbol upper.value lower_unbounded upper_unbounded lower_included upper_included lower.C_DV_ORDINAL.list upper.C_DV_ORDINAL.list expected constraints violated

local::at0005

1

local::at0002

5

false

false

true

true

1|[local::at0005], 2|[local::at0006]

5|[local::at0002], 2|[local::at0006]

accepted

local::at0004

666

local::at0003

777

false

false

true

true

8|[local::at0004], 2|[local::at0006]

9|[local::at0003], 2|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching value for lower and upper

local::at0666

1

local::at0777

2

false

false

true

true

1|[local::at0005], 2|[local::at0006]

1|[local::at0005], 2|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching symbol for lower and upper

local::at0004

666

local::at0003

777

false

false

true

true

8|[local::at0004], 2|[local::at0006]

777|[local::at0003], 2|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching value for lower

local::at0666

1

local::at0777

2

false

false

true

true

1|[local::at0005], 2|[local::at0006]

1|[local::at0005], 2|[local::at0777]

rejected

C_DV_ORDINAL.list: no matching symbol for lower

local::at0004

666

local::at0003

777

false

false

true

true

666|[local::at0004], 2|[local::at0006]

9|[local::at0003], 2|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching value for upper

local::at0005

1

local::at0777

5

false

false

true

true

1|[local::at0005], 2|[local::at0006]

1|[local::at0005], 5|[local::at0999]

rejected

C_DV_ORDINAL.list: no matching symbol for upper

14.9.13. DV_INTERVAL<DV_SCALE>

DV_SCALE was introduced to the RM 1.1.0 (Discourse discussion), it is analogous to DV_ORDINAL with a Real value. So test cases for DV_SCALE and DV_ORDINAL are similar.

Note
if this specification is implemented on a system that supports a RM < 1.1.0, then these tests shouldn’t run against the system.
Note
some modeling tools don’t support representing DV_INTERVAL<DV_SCALE>
14.9.13.1. Test Case CONT-DV_INTERVAL_DV_SCALE-validate_open

This case is when the ADL has DV_ORDINAL matches {*}

lower.symbol lower.value upper.symbol upper.value lower_unbounded upper_unbounded lower_included upper_included expected constraints violated

NULL

NULL

NULL

NULL

false

false

true

true

rejected

RM/Schema value and symbol are mandatory for lower and upper

NULL

1.5

NULL

5.3

false

false

true

true

rejected

RM/Schema symbol is mandatory for lower and upper

local::at0005

NULL

local::at0003

NULL

false

false

true

true

rejected

RM/Schema value is mandatory for lower and upper

local::at0005

1.5

local::at0002

5.3

false

false

true

true

accepted

local::at0004

666.1

local::at0003

777.1

false

false

true

true

accepted

local::at0003

777.1

local::at0004

666.1

false

false

true

true

rejected

RM invariante Interval.Limits_comparable

14.9.13.2. Test Case CONT-DV_INTERVAL_DV_SCALE-validate_constraint
lower.symbol lower.value upper.symbol upper.value lower_unbounded upper_unbounded lower_included upper_included lower.C_DV_ORDINAL.list upper.C_DV_ORDINAL.list expected constraints violated

local::at0005

1.5

local::at0002

5.3

false

false

true

true

1.5|[local::at0005], 2.4|[local::at0006]

5.3|[local::at0002], 2.4|[local::at0006]

accepted

local::at0004

666.1

local::at0003

777.1

false

false

true

true

8.9|[local::at0004], 2.4|[local::at0006]

9.7|[local::at0003], 2.4|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching value for lower and upper

local::at0666

1.5

local::at0777

2.4

false

false

true

true

1.5|[local::at0005], 2.4|[local::at0006]

1.5|[local::at0005], 2.4|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching symbol for lower and upper

local::at0004

666.1

local::at0003

777.1

false

false

true

true

8.9|[local::at0004], 2.4|[local::at0006]

777.1|[local::at0003], 2.4|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching value for lower

local::at0666

1.5

local::at0777

2.4

false

false

true

true

1.5|[local::at0005], 2.4|[local::at0006]

1.5|[local::at0005], 2.4|[local::at0777]

rejected

C_DV_ORDINAL.list: no matching symbol for lower

local::at0004

666.1

local::at0003

777.1

false

false

true

true

666.1|[local::at0004], 2.4|[local::at0006]

9.7|[local::at0003], 2.4|[local::at0006]

rejected

C_DV_ORDINAL.list: no matching value for upper

local::at0005

1.5

local::at0777

5.3

false

false

true

true

1.5|[local::at0005], 2.4|[local::at0006]

1.5|[local::at0005], 5.3|[local::at0999]

rejected

C_DV_ORDINAL.list: no matching symbol for upper

14.9.14. DV_INTERVAL<DV_PROPORTION>

Note
some modeling tools don’t support representing DV_INTERVAL<DV_PROPORTION>.
14.9.14.1. Test Case CONT-DV_INTERVAL_DV_PROPORTION-validate_open

The test data sets for lower and upper are divided into multiple tables because there are many attributes in the DV_PROPORTION.

Data set both valid ratios

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

0

ratio

10

500

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

0

ratio

20

500

0

expected constraints violated

accepted

Data set different limit types

This data set fails beacause DV_INTERVAL.Limits_consistent need both lower and upper to have the same type.

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

0

unitary

10

1

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

0

ratio

10

500

0

expected constraints violated

rejected

DV_INTERVAL.Limits_consistent (invariant)

Data set greater lower

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

0

ratio

10

500

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

0

ratio

5

500

0

expected constraints violated

rejected

DV_INTERVAL.Limits_consistent (invariant)

14.9.14.2. Test Case CONT-DV_INTERVAL_DV_PROPORTION-validate_ratio

The constraint is on the type of each limit of the interval as a C_INTEGER.list = [0], constraining the type as a ratio.

Data set valid ratios

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

0

ratio

10

500

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

0

ratio

20

500

0

expected constraints violated

accepted

Data set no ratios

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

1

unitary

10

1

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

1

unitary

20

1

0

expected constraints violated

rejected

C_INTEGER.list for lower and upper

14.9.14.3. Test Case CONT-DV_INTERVAL_DV_PROPORTION-validate_unitary

The constraint is on the type of each limit of the interval as a C_INTEGER.list = [1], constraining the type as unitary.

Data set valid unitaries

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

1

unitary

10

1

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision
1 unitary 20 1 0
expected constraints violated

accepted

Data set no unitaries

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

0

ratio

10

500

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

0

ratio

20

500

0

expected constraints violated

rejected

C_INTEGER.list for lower and upper

14.9.14.4. Test Case CONT-DV_INTERVAL_DV_PROPORTION-validate_percentage

The constraint is on the type of each limit of the interval as a C_INTEGER.list = [2], constraining the type as percentage.

Data set valid percentages

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

2

percent

10

100

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

2

percent

20

100

0

expected constraints violated

accepted

Data set no percentages

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

0

ratio

10

500

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

0

ratio

20

500

0

expected constraints violated

rejected

C_INTEGER.list for lower and upper

14.9.14.5. Test Case CONT-DV_INTERVAL_DV_PROPORTION-validate_fraction

The constraint is on the type of each limit of the interval as a C_INTEGER.list = [3], constraining the type as fraction.

Data set valid fractions

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

3

fraction

3

4

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

3

fraction

5

4

0

expected constraints violated

accepted

Data set no fractions

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

0

ratio

10

500

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

0

ratio

20

500

0

expected constraints violated

rejected

C_INTEGER.list for lower and upper

14.9.14.6. Test Case CONT-DV_INTERVAL_DV_PROPORTION-validate_integer_fraction

The constraint is on the type of each limit of the interval as a C_INTEGER.list = [3], constraining the type as fraction.

Data set valid integer fractions

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

4

integer fraction

3

4

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

4

integer fraction

5

4

0

expected constraints violated

accepted

Data set no integer fractions

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision

0

ratio

10

500

0

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision

0

ratio

20

500

0

expected constraints violated

rejected

C_INTEGER.list for lower and upper

14.9.14.7. Test Case CONT-DV_INTERVAL_DV_PROPORTION-validate_ratio_range

The constraint is on the type of each limit of the interval as a C_INTEGER.list = [0], constraining the type as a ratio. For the limits, the constraints are C_REAL using the range attribute.

Data set valid ratios

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision C_REAL.range (num) C_REAL.range (den)

0

ratio

10

500

0

0..15

100..1000

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision C_REAL.range (num) C_REAL.range (den)

0

ratio

20

500

0

0..50

100..1000

expected constraints violated

accepted

Data set ratios, invalid lower

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision C_REAL.range (num) C_REAL.range (den)

0

ratio

10

500

0

0..5

100..1000

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision C_REAL.range (num) C_REAL.range (den)

0

ratio

20

500

0

0..50

100..1000

expected constraints violated

rejected

C_REAL.range (num) for lower

Data set ratios, invalid upper

DV_INTERVAL.lower

type meaning (kind) numerator denominator precision C_REAL.range (num) C_REAL.range (den)

0

ratio

10

500

0

0..15

100..1000

DV_INTERVAL.upper

type meaning (kind) numerator denominator precision C_REAL.range (num) C_REAL.range (den)

0

ratio

20

500

0

0..10

100..1000

expected constraints violated

rejected

C_REAL.range (num) for upper

14.10. Data Types - quantity.date_time Package

Note
All test data sets for date/time/datetime expressions are represented in the ISO 8601 extended format. An openEHR CDR could choose to use the extended (with field delimiter characters) or basic format (without field delimiters) of ISO 8601, or support any of the two formats. In the test implementations it is probable that the data sets are represented as JSON or XML documents, in which the date and time expressions are always representede in the ISO 8601 extended format, but internally the SUT could store any of the two formats. If the test implementation doesn’t use JSON or XML, the date and time expression formats could use the ISO 8601 basic format.

14.10.1. DV_DURATION

Note
different duration implementations might affect the DV_DURATION related test cases. For instance, some implementations might not support days in the same duration expression that contains months, since there is no exact correspondence between the number of days and months (months could have 28, 29, 30 or 31 days). Then other implementations might simplify the month measurement to be 30 days. This also happens with some implementations that consider a day is exactly 24 hours as a simplification.> It is worth mentioning that openEHR provides means for calculating this based on averages, in DV_DURATION.magnitude(), which is implemented in terms of Iso8601_duration.to_seconds(), it uses Time_Definitions.Average_days_in_year as an approximation to the numbers of days in a year, and Time_Definitions.Average_days_in_month as an approximation to the numbers of days in a month. So to normalize an expression that is P1Y3M5D to days we would have 1 * Average_days_in_year + 3 * Average_days_in_month + 5. In case the SUT has an implementation decision to be considered, the developers should mention it in the Conformance Statement Document.

The openEHR specifications have two exceptions to the ISO 8601-1 rules:

  1. a negative sign may be used before a Duration expression, for example -P10D, meaning '10 days before [origin]', where the 'origin' is a timepoint understood as the origin for the duration;

  2. the W designator may be mixed with other designators in the duration expression.

Note those exceptions are invalid in terms of ISO 8601-1_2019, but, those are valid in terms for ISO 8601-2_2019, which defines some extensions to the ISO 8601-1 standard. From ISO 8601-2:

Expressions in the following four examples below are not valid in ISO 8601-1, but are valid as specified in this clause.

EXAMPLE 3 'P3W2D', duration of three weeks and two days, which is 23 days (equivalent to the expression 'P23D'). In ISO 8601-1, ["W"] is not permitted to occur along with any other component.
EXAMPLE 4 'P5Y10W', duration of five years and ten weeks.
...
EXAMPLE 7 '-P2M1D' is equivalent to 'P-2M-1D'.
14.10.1.1. Test Case CONT-DV_DURATION-validate_open
value expected violated constraints

NULL

rejected

DV_DURATION.value is mandatory in the RM

1Y

rejected

invalid ISO 8601-1 duration: missing duration desingator 'P'

P1Y

accepted

P1Y3M

accepted

P1W

accepted

P1Y3M4D

accepted

P1Y3M4DT2H

accepted

P1Y3M4DT2H14M

accepted

P1Y3M4DT2H14M5S

accepted

P1Y3M4DT2H14M15.5S

accepted

P1Y3M4DT2H14.5M

rejected

openEHR: fractions for minutes are not allowed

P1Y3M4DT2.5H

rejected

openEHR: fractions for hours are not allowed

P3M1W

accepted

-P2M

accepted

14.10.1.2. Test Case CONT-DV_DURATION-validate_fields

The allowed fields are defined in the C_DURATION class, which allows to constraint the DV_DURATION.value attribute.

value years_allowed months_allowed weeks_allowed days_allowed hours_allowed minutes_allowed seconds_allowed fractional_seconds_allowed expected violated constraints

P1Y

true

true

true

true

true

true

true

true

accepted

P1Y

false

true

true

true

true

true

true

true

rejected

C_DURATION.years_allowed

P1Y3M

true

true

true

true

true

true

true

true

accepted

P1Y3M

true

false

true

true

true

true

true

true

rejected

C_DURATION.months_allowed

P1Y3M15D

true

true

true

true

true

true

true

true

accepted

P1Y3M15D

true

true

true

false

true

true

true

true

rejected

C_DURATION.days_allowed

P1W

true

true

true

true

true

true

true

true

accepted

P7W

true

true

false

true

true

true

true

true

rejected

C_DURATION.weeks_allowed

P1Y3M15DT23H

true

true

true

true

true

true

true

true

accepted

P1Y3M15DT23H

true

true

true

true

false

true

true

true

rejected

C_DURATION.hours_allowed

P1Y3M15DT23H35M

true

true

true

true

true

true

true

true

accepted

P1Y3M15DT23H35M

true

true

true

true

true

false

true

true

rejected

C_DURATION.minutes_allowed

P1Y3M15DT23H35M22S

true

true

true

true

true

true

true

true

accepted

P1Y3M15DT23H35M22S

true

true

true

true

true

true

false

true

rejected

C_DURATION.seconds_allowed

P1Y3M15DT23H35M22.5S

true

true

true

true

true

true

true

true

accepted

P1Y3M15DT23H35M22.5S

true

true

true

true

true

true

true

false

rejected

C_DURATION.fractional_seconds_allowed

P1W3D

true

true

true

true

true

true

true

true

accepted

P1W3D

true

true

false

true

true

true

true

true

rejected

C_DURATION.weeks_allowed

Note
the fractional_seconds_allowed field is not so clear since the ISO8601 would allow fractions on the lowest order component, which means if the duration lowest component is minutes then it’s valid to have 5.23M. Also consider in programming languages like Java, a duration string with fractions on other fields than seconds can’t be parsed (for instance using Java CHarSequence).
14.10.1.3. Test Case CONT-DV_DURATION-validate_range

In order to compare durations, the DV_DURATION.magnitude() should be used, which will calculate the seconds in the duration based on the avg. days in year and days in month. If the SUT does calculate the magnitude() in a different way, it should be stated in the Conformance Statement Document.

value range.lower range.upper expected violated constraints

P1Y

P0Y

P50Y

accepted

P1Y

P1Y

P50Y

accepted

P1Y

P2Y

P50Y

rejected

C_DURATION.range.lower

P1M

P0M

P50M

accepted

P1M

P1M

P50M

accepted

P1M

P2M

P50M

rejected

C_DURATION.range.lower

P1D

P0D

P50D

accepted

P1D

P1D

P50D

accepted

P1D

P2D

P50D

rejected

C_DURATION.range.lower

P1Y2M

P0Y

P50Y

accepted

P1Y2M

P1Y

P50Y

accepted

P1Y2M

P2Y

P50Y

rejected

C_DURATION.range.lower

P1Y20M

P0Y

P50Y

accepted

P1Y20M

P1Y

P50Y

accepted

P1Y20M

P2Y

P50Y

accepted

P2W

P0W

P3W

accepted

P2W

P2W

P3W

accepted

P2W

P3W

P3W

rejected

C_DURATION.range.lower

P2W3D

P3W

P4W

rejected

C_DURATION.range.lower

P2W8D

P3W

P4W

accepted

P2W15D

P3W

P4W

rejected

C_DURATION.range.upper

14.10.1.4. Test Case CONT-DV_DURATION-validate_fields_range

In the AOM specification it is allowed to combine allowed and range: "Both range and the constraint pattern can be set at the same time, corresponding to the ADL constraint PWD/|P0W..P50W|. See C_DURATION class.

value years_allowed months_allowed weeks_allowed days_allowed hours_allowed minutes_allowed seconds_allowed fractional_seconds_allowed range.lower range.upper expected violated constraints

P1Y

true

true

true

true

true

true

true

true

P0Y

P50Y

accepted

P1Y

true

true

true

true

true

true

true

true

P2Y

P50Y

rejected

C_DURATION.range.lower

P1Y

false

true

true

true

true

true

true

true

P0Y

P50Y

rejected

C_DURATION.years_allowed

P1Y

false

true

true

true

true

true

true

true

P2Y

P50Y

rejected

C_DURATION.years_allowed, C_DURATION.range.lower

P1Y3M

true

true

true

true

true

true

true

true

P1Y

P50Y

accepted

P1Y3M

true

false

true

true

true

true

true

true

P1Y

P50Y

rejected

C_DURATION.months_allowed

P1Y3M

true

true

true

true

true

true

true

true

P3Y

P50Y

rejected

C_DURATION.lower

P1Y3M

true

false

true

true

true

true

true

true

P3Y

P50Y

rejected

C_DURATION.months_allowed. C_DURATION.lower

PT2M43.5S

true

true

true

true

true

true

true

false

PT1M

PT60M

rejected

C_DURATION.fractional_seconds_allowed

14.10.2. DV_TIME

DV_TIME constraints are defined by C_TIME, which specifies two types of constraints: validity kind and range. The validity kind constraints are expressed in terms of mandatory/optional/prohibited flags for each part of the time expression: minute, second, millisecond and timezone. The range constraint is an Interval<Time>, which are both openEHR Foundation Types.

Note
the Time class mentioned in the AOM 1.4 specification is actually the Iso8601_time class. This is a known bug in the specs. So in C_TIME, range being an Interval<Time> should be an Interval<Iso8601_time>.

Time expressions in openEHR are considered an absolute point in time from the start of the current day, that is T10 represents 10:00:00.000 AM in the local timezone.

14.10.2.1. Test Case CONT-DV_TIME-validate_open

This case is when DV_TIME matches {*}.

Note
the decimal mark for the seconds fraction could be , (comma) or . (period) at in-memory and storage representations of time expressions, but since in most popular exchange formats the . is preferred, and considering the implementation of these test cases will surelly use those exchange formats, we only specify test data sets which use the decimal mark .. Nevetheless, the , is totally valid at in-memory and storage levels. In the same line, basic and extended formats are allowed at in-memory and storage representations. Basic format being the time parts without any separators and the extended being the parts with separators : (colon). The extended format is also preferred by the most common exchange fornats, so only test data sets using extended format will be specified.
Note
"There is no limit on the number of decimal places for the decimal fraction. However, the number of decimal places needs to be agreed to by the communicating parties." see ISO8601 Times.
Note
the time marker T can be ommitted for the extended format in ISO8601:2019, because there is no risk of ambiguity. Since this is nor mandatory, our test data sets all include the T time marker.
Note
if no timezone information is included, the time expression is considered local time.
Note
one clarification about the seconds fraction in ISO8601 is that is not exactly an expression of milliseconds as the AOM specification implies considering the millisecond_validity field. For instance .5 represents half a second, which is indeed 500 milliseconds but .5 is not syntactically 500 ms, or .333333 represents one third of a second, and syntactically 333333 goes beyond the precision of milliseconds which is just 3 digits long. Consider .33333 is totally valid in ISO8601 for the seconds fraction (see NOTE 2).
value expected violated constraints

NULL

rejected

RM/Schema: value is mandatory

''

rejected

ISO8601: at least hours are required

T10

accepted

T48

rejected

ISO8601: hours in 0..23

T10:30

accepted

T10:95

rejected

ISO8601: minutes in 0..59

T10:30:47

accepted

T10:30:78

rejected

ISO8601: seconds in 0..59

T10:30:47.5

accepted

T10:30:47.333

accepted

T10:30:47.333333

accepted

T10:30:47Z

accepted

T10:30:78Z

rejected

ISO8601: seconds in 0..59

T10:30:47.5Z

accepted

T10:30:47.333Z

accepted

T10:30:47.333333Z

accepted

T10:30:47-03:00

accepted

T10:30:78-03:00

rejected

ISO8601: seconds in 0..59

T10:30:47.5-03:00

accepted

T10:30:47.333-03:00

accepted

T10:30:47.333333-03:00

accepted

T10.5

rejected

openEHR doesn’t allow fractional hours in partial time expressions, an openEHR exception over the ISO 8601 spec

T10:05.5

rejected

openEHR doesn’t allow fractional minutes in partial time expressions, an openEHR exception over the ISO 8601 spec

14.10.2.2. Test Case CONT-DV_TIME-validate_constraint
Note
the C_TIME has invariants that define if a lower precision component is optional or prohibited (e.g. minutes) then the higher precision components (e.g. seconds) should be optional or prohibited. In other words, if minutes is optional then seconds should be optional or prohibited. These invariants should be checked in an archetype/template editor, since that is part of archetype/template validation. Here we consider the archetypes and templates used are valid.
value minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

T10

mandatory

mandatory

mandatory

mandatory

rejected

minute_validity, second_validity, millisecond_validity, timezone_validity

T10

mandatory

mandatory

mandatory

optional

rejected

minute_validity, second_validity, millisecond_validity

T10

mandatory

mandatory

optional

optional

rejected

minute_validity, second_validity

T10

mandatory

optional

optional

optional

rejected

minute_validity

T10

optional

optional

optional

optional

accepted

T10

mandatory

mandatory

mandatory

prohibited

rejected

minute_validity, second_validity, millisecond_validity

T10

mandatory

mandatory

prohibited

prohibited

rejected

minute_validity, second_validity

T10

mandatory

prohibited

prohibited

prohibited

rejected

minute_validity

T10

prohibited

prohibited

prohibited

prohibited

accepted

value minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

T10:30

mandatory

mandatory

mandatory

mandatory

rejected

second_validity, millisecond_validity, timezone_validity

T10:30

mandatory

mandatory

mandatory

optional

rejected

second_validity, millisecond_validity

T10:30

mandatory

mandatory

optional

optional

rejected

second_validity

T10:30

mandatory

optional

optional

optional

accepted

T10:30

optional

optional

optional

optional

accepted

T10:30

mandatory

mandatory

mandatory

prohibited

rejected

second_validity, millisecond_validity

T10:30

mandatory

mandatory

prohibited

prohibited

rejected

second_validity

T10:30

mandatory

prohibited

prohibited

prohibited

accepted

T10:30

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity

value minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

T10:30:47

mandatory

mandatory

mandatory

mandatory

rejected

millisecond_validity, timezone_validity

T10:30:47

mandatory

mandatory

mandatory

optional

rejected

millisecond_validity

T10:30:47

mandatory

mandatory

optional

optional

accepted

T10:30:47

mandatory

optional

optional

optional

accepted

T10:30:47

optional

optional

optional

optional

accepted

T10:30:47

mandatory

mandatory

mandatory

prohibited

rejected

millisecond_validity

T10:30:47

mandatory

mandatory

prohibited

prohibited

accepted

T10:30:47

mandatory

prohibited

prohibited

prohibited

rejected

second_validity

T10:30:47

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity

value minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

T10:30:47.5

mandatory

mandatory

mandatory

mandatory

rejected

timezone_validity

T10:30:47.5

mandatory

mandatory

mandatory

optional

accepted

T10:30:47.5

mandatory

mandatory

optional

optional

accepted

T10:30:47.5

mandatory

optional

optional

optional

accepted

T10:30:47.5

optional

optional

optional

optional

accepted

T10:30:47.5

mandatory

mandatory

mandatory

prohibited

accepted

T10:30:47.5

mandatory

mandatory

prohibited

prohibited

rejected

millisecond_validity

T10:30:47.5

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, millisecond_validity

T10:30:47.5

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, millisecond_validity

value minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

T10:30:47Z

mandatory

mandatory

mandatory

mandatory

rejected

millisecond_validity

T10:30:47Z

mandatory

mandatory

mandatory

optional

rejected

millisecond_validity

T10:30:47Z

mandatory

mandatory

optional

optional

accepted

T10:30:47Z

mandatory

optional

optional

optional

accepted

T10:30:47Z

optional

optional

optional

optional

accepted

T10:30:47Z

mandatory

mandatory

mandatory

prohibited

rejected

millisecond_validity, timezone_validity

T10:30:47Z

mandatory

mandatory

prohibited

prohibited

rejected

timezone_validity

T10:30:47Z

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, timezone_validity

T10:30:47Z

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, timezone_validity

value minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

T10:30:47.5Z

mandatory

mandatory

mandatory

mandatory

accepted

T10:30:47.5Z

mandatory

mandatory

mandatory

optional

accepted

T10:30:47.5Z

mandatory

mandatory

optional

optional

accepted

T10:30:47.5Z

mandatory

optional

optional

optional

accepted

T10:30:47.5Z

optional

optional

optional

optional

accepted

T10:30:47.5Z

mandatory

mandatory

mandatory

prohibited

rejected

timezone_validity

T10:30:47.5Z

mandatory

mandatory

prohibited

prohibited

rejected

millisecond_validity, timezone_validity

T10:30:47.5Z

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, millisecond_validity, timezone_validity

T10:30:47.5Z

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, millisecond_validity, timezone_validity

value minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

T10:30:47.5-03:00

mandatory

mandatory

mandatory

mandatory

accepted

T10:30:47.5-03:00

mandatory

mandatory

mandatory

optional

accepted

T10:30:47.5-03:00

mandatory

mandatory

optional

optional

accepted

T10:30:47.5-03:00

mandatory

optional

optional

optional

accepted

T10:30:47.5-03:00

optional

optional

optional

optional

accepted

T10:30:47.5-03:00

mandatory

mandatory

mandatory

prohibited

rejected

timezone_validity

T10:30:47.5-03:00

mandatory

mandatory

prohibited

prohibited

rejected

millisecond_validity, timezone_validity

T10:30:47.5-03:00

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, millisecond_validity, timezone_validity

T10:30:47.5-03:00

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, millisecond_validity, timezone_validity

14.10.2.3. Test Case CONT-DV_TIME-validate_range

The C_TIME.range constraint is an Interval<Time>, which are both Foundation Types.

Note
the Time class mentioned in the AOM 1.4 specification is actually the Iso8601_time class. This is a known bug in the specs. So in C_TIME, range being an Interval<Time> should be an Interval<Iso8601_time>.
Note
there is an open issue in the comparability of two date/time/datetime expressions with different precisions but shared values for the components they contain. For instance, in ISO 8601-1_2019, the expression T23:20 is referring to a specific hour and minute, and T23 is referring to a specific hour. Then, numerically, it’s not possible to say if T23 < T23:20 or if T23 > T23:20. That is because the expressions represent different time components, which are really intervals of time, and one interval contains the oher (the 23rd hour of the day contains the minute 23:30). Though when the precisions are not the same but there are no shared components, then the expressions are comparable, for instance we can say T22 < T2320, because all the minutes and seconds in the 22nd hour of the day come before the minute 23:20. Similarly we can say T22:45 < T23, since the whole minute 22:45 comes before all minutes and seconds in the 23rd hour of the day. This issue is currently being discussed in the openEHR SEC because it changes the definition of the method is_strictly_comparable_to() for DV_DATE, DV_TIME and DV_DATE_TIME. This is commented here because this test case needs to compare time expressions to be able to check the range constraint.
Note
Besides noting that reduced precision time expressions represent an interval or range when those reduced precision time expressions are used as limits for an openEHR Interval, then it seems reasonable to interpret the whole range as the interval defined by the beginning of the lower limit and the end of the upper limit. For instance T11 represents the whole 11th hour of the day, from start to end, and T23 represents the whole 23rd hour of the day from start to end, then T11..T23 represents all hours, minutes and seconds from the start of hour 11 to the end of hour 23 (yes the end not the start!). So something that might be counterintuitive by using this interpretation is: in this notation is T23:30 would be contained in the T11..T23 interval, though it is not strictly comparable to T23.
Note
More about these considerations in the openEHR discourse.
value C_TIME.range expected violated constraints

T10

T00..T23

accepted

T10

T00:00..T23:59

accepted

T10

T00:00:00..T23:59:59

accepted

T10

T00:00:00.0..T23:59:59.999

accepted

T10

T11..T23

rejected

C_TIME.range

T10

T11:00..T23:59

rejected

C_TIME.range

T10

T11:00:00..T23:59:59

rejected

C_TIME.range

T10

T11:00:00.0..T23:59:59.999

rejected

C_TIME.range

T10

T00..T09

rejected

C_TIME.range

T10

T00:00..T09:59

rejected

C_TIME.range

T10

T00:00:00..T09:59:59

rejected

C_TIME.range

T10

T00:00:00.0..T09:59:59.999

rejected

C_TIME.range

T10

>=T00

accepted

T10

>=T00:00

accepted

T10

>=T00:00:00

accepted

T10

>=T00:00:00.0

accepted

T10

>=T11

rejected

C_TIME.range

T10

>=T11:00

rejected

C_TIME.range

T10

>=T11:00:00

rejected

C_TIME.range

T10

>=T11:00:00.0

rejected

C_TIME.range

T10

⇐T09

rejected

C_TIME.range

T10

⇐T09:59

rejected

C_TIME.range

T10

⇐T09:59:59

rejected

C_TIME.range

T10

⇐T09:59:59.999

rejected

C_TIME.range

Note
the range with the timezone included doesn’t make sense when the time value doesn’t have a timezone, since will compare a local time (without TZ) with a global time (with TZ). This case should be considered an error at the archetype level. Analogously, if the DV_TIME value has a timezome, the C_TIME.range constraints should include the timezone.
value C_TIME.range expected violated constraints

T10:30

T00..T23

accepted

T10:30

T00:00..T23:59

accepted

T10:30

T00:00:00..T23:59:59

accepted

T10:30

T00:00:00.0..T23:59:59.999

accepted

T10:30

T11..T23

rejected

C_TIME.range

T10:30

T11:00..T23:59

rejected

C_TIME.range

T10:30

T11:00:00..T23:59:59

rejected

C_TIME.range

T10:30

T11:00:00.0..T23:59:59.999

rejected

C_TIME.range

T10:30

T00..T09

rejected

C_TIME.range

T10:30

T00:00..T09:59

rejected

C_TIME.range

T10:30

T00:00:00..T09:59:59

rejected

C_TIME.range

T10:30

T00:00:00.0..T09:59:59.999

rejected

C_TIME.range

T10:30

>=T00

accepted

T10:30

>=T00:00

accepted

T10:30

>=T00:00:00

accepted

T10:30

>=T00:00:00.0

accepted

T10:30

>=T11

rejected

C_TIME.range

T10:30

>=T11:00

rejected

C_TIME.range

T10:30

>=T11:00:00

rejected

C_TIME.range

T10:30

>=T11:00:00.0

rejected

C_TIME.range

T10:30

⇐T09

rejected

C_TIME.range

T10:30

⇐T09:59

rejected

C_TIME.range

T10:30

⇐T09:59:59

rejected

C_TIME.range

T10:30

⇐T09:59:59.999

rejected

C_TIME.range

value C_TIME.range expected violated constraints

T10:30:47

T00..T23

accepted

T10:30:47

T00:00..T23:59

accepted

T10:30:47

T00:00:00..T23:59:59

accepted

T10:30:47

T00:00:00.0..T23:59:59.999

accepted

T10:30:47

T11..T23

rejected

C_TIME.range

T10:30:47

T11:00..T23:59

rejected

C_TIME.range

T10:30:47

T11:00:00..T23:59:59

rejected

C_TIME.range

T10:30:47

T11:00:00.0..T23:59:59.999

rejected

C_TIME.range

T10:30:47

T00..T09

rejected

C_TIME.range

T10:30:47

T00:00..T09:59

rejected

C_TIME.range

T10:30:47

T00:00:00..T09:59:59

rejected

C_TIME.range

T10:30:47

T00:00:00.0..T09:59:59.999

rejected

C_TIME.range

T10:30:47

>=T00

accepted

T10:30:47

>=T00:00

accepted

T10:30:47

>=T00:00:00

accepted

T10:30:47

>=T00:00:00.0

accepted

T10:30:47

>=T11

rejected

C_TIME.range

T10:30:47

>=T11:00

rejected

C_TIME.range

T10:30:47

>=T11:00:00

rejected

C_TIME.range

T10:30:47

>=T11:00:00.0

rejected

C_TIME.range

T10:30:47

⇐T09

rejected

C_TIME.range

T10:30:47

⇐T09:59

rejected

C_TIME.range

T10:30:47

⇐T09:59:59

rejected

C_TIME.range

T10:30:47

⇐T09:59:59.999

rejected

C_TIME.range

value C_TIME.range expected violated constraints

T10:30:47.5

T00..T23

accepted

T10:30:47.5

T00:00..T23:59

accepted

T10:30:47.5

T00:00:00..T23:59:59

accepted

T10:30:47.5

T00:00:00.0..T23:59:59.999

accepted

T10:30:47.5

T11..T23

rejected

C_TIME.range

T10:30:47.5

T11:00..T23:59

rejected

C_TIME.range

T10:30:47.5

T11:00:00..T23:59:59

rejected

C_TIME.range

T10:30:47.5

T11:00:00.0..T23:59:59.999

rejected

C_TIME.range

T10:30:47.5

T00..T09

rejected

C_TIME.range

T10:30:47.5

T00:00..T09:59

rejected

C_TIME.range

T10:30:47.5

T00:00:00..T09:59:59

rejected

C_TIME.range

T10:30:47.5

T00:00:00.0..T09:59:59.999

rejected

C_TIME.range

T10:30:47.5

>=T00

accepted

T10:30:47.5

>=T00:00

accepted

T10:30:47.5

>=T00:00:00

accepted

T10:30:47.5

>=T00:00:00.0

accepted

T10:30:47.5

>=T11

rejected

C_TIME.range

T10:30:47.5

>=T11:00

rejected

C_TIME.range

T10:30:47.5

>=T11:00:00

rejected

C_TIME.range

T10:30:47.5

>=T11:00:00.0

rejected

C_TIME.range

T10:30:47.5

⇐T09

rejected

C_TIME.range

T10:30:47.5

⇐T09:59

rejected

C_TIME.range

T10:30:47.5

⇐T09:59:59

rejected

C_TIME.range

T10:30:47.5

⇐T09:59:59.999

rejected

C_TIME.range

value C_TIME.range expected violated constraints

T10:30:47Z

T00Z..T23Z

accepted

T10:30:47Z

T00:00Z..T23:59Z

accepted

T10:30:47Z

T00:00:00Z..T23:59:59Z

accepted

T10:30:47Z

T00:00:00.0Z..T23:59:59.999Z

accepted

T10:30:47Z

T11Z..T23Z

rejected

C_TIME.range

T10:30:47Z

T11:00Z..T23:59Z

rejected

C_TIME.range

T10:30:47Z

T11:00:00Z..T23:59:59Z

rejected

C_TIME.range

T10:30:47Z

T11:00:00.0Z..T23:59:59.999Z

rejected

C_TIME.range

T10:30:47Z

T00Z..T09Z

rejected

C_TIME.range

T10:30:47Z

T00:00Z..T09:59Z

rejected

C_TIME.range

T10:30:47Z

T00:00:00Z..T09:59:59Z

rejected

C_TIME.range

T10:30:47Z

T00:00:00.0Z..T09:59:59.999Z

rejected

C_TIME.range

T10:30:47Z

>=T00Z

accepted

T10:30:47Z

>=T00:00Z

accepted

T10:30:47Z

>=T00:00:00Z

accepted

T10:30:47Z

>=T00:00:00.0Z

accepted

T10:30:47Z

>=T11Z

rejected

C_TIME.range

T10:30:47Z

>=T11:00Z

rejected

C_TIME.range

T10:30:47Z

>=T11:00:00Z

rejected

C_TIME.range

T10:30:47Z

>=T11:00:00.0Z

rejected

C_TIME.range

T10:30:47Z

⇐T09Z

rejected

C_TIME.range

T10:30:47Z

⇐T09:59Z

rejected

C_TIME.range

T10:30:47Z

⇐T09:59:59Z

rejected

C_TIME.range

T10:30:47Z

⇐T09:59:59.999Z

rejected

C_TIME.range

value C_TIME.range expected violated constraints

T10:30:47.5Z

T00Z..T23Z

accepted

T10:30:47.5Z

T00:00Z..T23:59Z

accepted

T10:30:47.5Z

T00:00:00Z..T23:59:59Z

accepted

T10:30:47.5Z

T00:00:00.0Z..T23:59:59.999Z

accepted

T10:30:47.5Z

T11Z..T23Z

rejected

C_TIME.range

T10:30:47.5Z

T11:00Z..T23:59Z

rejected

C_TIME.range

T10:30:47.5Z

T11:00:00Z..T23:59:59Z

rejected

C_TIME.range

T10:30:47.5Z

T11:00:00.0Z..T23:59:59.999Z

rejected

C_TIME.range

T10:30:47.5Z

T00Z..T09Z

rejected

C_TIME.range

T10:30:47.5Z

T00:00Z..T09:59Z

rejected

C_TIME.range

T10:30:47.5Z

T00:00:00Z..T09:59:59Z

rejected

C_TIME.range

T10:30:47.5Z

T00:00:00.0Z..T09:59:59.999Z

rejected

C_TIME.range

T10:30:47.5Z

>=T00Z

accepted

T10:30:47.5Z

>=T00:00Z

accepted

T10:30:47.5Z

>=T00:00:00Z

accepted

T10:30:47.5Z

>=T00:00:00.0Z

accepted

T10:30:47.5Z

>=T11Z

rejected

C_TIME.range

T10:30:47.5Z

>=T11:00Z

rejected

C_TIME.range

T10:30:47.5Z

>=T11:00:00Z

rejected

C_TIME.range

T10:30:47.5Z

>=T11:00:00.0Z

rejected

C_TIME.range

T10:30:47.5Z

⇐T09Z

rejected

C_TIME.range

T10:30:47.5Z

⇐T09:59Z

rejected

C_TIME.range

T10:30:47.5Z

⇐T09:59:59Z

rejected

C_TIME.range

T10:30:47.5Z

⇐T09:59:59.999Z

rejected

C_TIME.range

value C_TIME.range expected violated constraints

T10:30:47-03:00

T00-03:00..T23-03:00

accepted

T10:30:47-03:00

T00:00-03:00..T23:59-03:00

accepted

T10:30:47-03:00

T00:00:00-03:00..T23:59:59-03:00

accepted

T10:30:47-03:00

T00:00:00.0-03:00..T23:59:59.999-03:00

accepted

T10:30:47-03:00

T11-03:00..T23-03:00

rejected

C_TIME.range

T10:30:47-03:00

T11:00-03:00..T23:59-03:00

rejected

C_TIME.range

T10:30:47-03:00

T11:00:00-03:00..T23:59:59-03:00

rejected

C_TIME.range

T10:30:47-03:00

T11:00:00.0-03:00..T23:59:59.999-03:00

rejected

C_TIME.range

T10:30:47-03:00

T00-03:00..T09-03:00

rejected

C_TIME.range

T10:30:47-03:00

T00:00-03:00..T09:59-03:00

rejected

C_TIME.range

T10:30:47-03:00

T00:00:00-03:00..T09:59:59-03:00

rejected

C_TIME.range

T10:30:47-03:00

T00:00:00.0-03:00..T09:59:59.999-03:00

rejected

C_TIME.range

T10:30:47-03:00

>=T00-03:00

accepted

T10:30:47-03:00

>=T00:00-03:00

accepted

T10:30:47-03:00

>=T00:00:00-03:00

accepted

T10:30:47-03:00

>=T00:00:00.0-03:00

accepted

T10:30:47-03:00

>=T11-03:00

rejected

C_TIME.range

T10:30:47-03:00

>=T11:00-03:00

rejected

C_TIME.range

T10:30:47-03:00

>=T11:00:00-03:00

rejected

C_TIME.range

T10:30:47-03:00

>=T11:00:00.0-03:00

rejected

C_TIME.range

T10:30:47-03:00

⇐T09-03:00

rejected

C_TIME.range

T10:30:47-03:00

⇐T09:59-03:00

rejected

C_TIME.range

T10:30:47-03:00

⇐T09:59:59-03:00

rejected

C_TIME.range

T10:30:47-03:00

⇐T09:59:59.999-03:00

rejected

C_TIME.range

value C_TIME.range expected violated constraints

T10:30:47.5-03:00

T00-03:00..T23-03:00

accepted

T10:30:47.5-03:00

T00:00-03:00..T23:59-03:00

accepted

T10:30:47.5-03:00

T00:00:00-03:00..T23:59:59-03:00

accepted

T10:30:47.5-03:00

T00:00:00.0-03:00..T23:59:59.999-03:00

accepted

T10:30:47.5-03:00

T11-03:00..T23-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

T11:00-03:00..T23:59-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

T11:00:00-03:00..T23:59:59-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

T11:00:00.0-03:00..T23:59:59.999-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

T00-03:00..T09-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

T00:00-03:00..T09:59-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

T00:00:00-03:00..T09:59:59-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

T00:00:00.0-03:00..T09:59:59.999-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

>=T00-03:00

accepted

T10:30:47.5-03:00

>=T00:00-03:00

accepted

T10:30:47.5-03:00

>=T00:00:00-03:00

accepted

T10:30:47.5-03:00

>=T00:00:00.0-03:00

accepted

T10:30:47.5-03:00

>=T11-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

>=T11:00-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

>=T11:00:00-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

>=T11:00:00.0-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

⇐T09-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

⇐T09:59-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

⇐T09:59:59-03:00

rejected

C_TIME.range

T10:30:47.5-03:00

⇐T09:59:59.999-03:00

rejected

C_TIME.range

14.10.3. DV_DATE

DV_DATE constraints are defined by C_DATE, which specifies two types of constraints: validity kind and range. The validity kind constraints are expressed in terms of mandatory/optional/prohibited flags for each part of the date expression: day and month. The range constraint is an Interval<Date>.

NOTE 1: the basic and extended formats are allowed at in-memory and storage representations. Basic format being the time parts without any separators and the extended being the parts with separatos - (hyphen). Since most popular exchange formats use the extended format, and considering the implementation of these test cases will surelly use those exchange formats, we only specify test data sets which use the extended format.

NOTE 2: by the ISO8601 standard, only years >1582 are valid, since that was the year in which the Gregorian Calendar was put in place. For representing other years, there should be a mutual agreement between information interchange partners.

Some exceptions to ISO 8601 specs is that in openEHR date/time/duration types, which dates back to RM 1.0.2 (and maybe before that):

ISO 8601 semantics not used in openEHR include:

  • “expanded” dates, which have year numbers of greater than 4 digits, and may be negative; in openEHR, only 4-digit year numbers are assumed;

  • the YYYY-WW-DD method of expressing dates (since this is imprecise and difficult to compute with due to variable week starting dates, and not required in health);

  • partial date/times with fractional minutes or hours, e.g. hh,hhh or mm,mm; in openEHR, only fractional seconds are supported;

  • the interval syntax. Intervals of date/times are supported in openEHR, but their syntax form is defined by ADL, and is standardised across all comparable types, not just dates and times.

Following those rules, will include test data sets that break the openEHR rules, even if those are ISO 8601 valid, the SUT should mark them as invalid.

14.10.3.1. Test Case CONT-DV_DATE-validate_open
value expected violated constraints

NULL

rejected

RM/Schema: value is mandatory

''

rejected

ISO8601: at least year is required (see note below)

''

rejected

openEHR RM/AOM: at least year is required (see note below)

2021

accepted

2021-10

accepted

2021-00

rejected

ISO8601: month in 01..12

2021-13

rejected

ISO8601: month in 01..12

2021-10-24

accepted

2021-10-00

rejected

ISO8601: day in 01..31

2021-10-32

rejected

ISO8601: day in 01..31

Note
this is the author’s interpretation of a minimal valid date in the context of openEHR noting the description of C_DATE: "There is no validity flag for ‘year’, since it must always be by definition mandatory in order to have a sensible date at all.". Though the ISO 8601 standard allows partial year expressions like 198 to denoted the 80’s and 19 to denote de 1900’s.
14.10.3.2. Test Case CONT-DV_DATE-validate_constraint
Note
the C_DATE has invariants that define if a higher precision component is optional or prohibited, lower precision components should be optional or prohibited. In other words, if month is optional, day should be optional or prohibited. These invariants should be checked in an archetype editor and template editor, we consider the following tests to follow those rules without checking them, since that is related to archetype/template validation, not with data validation.
value month_validity day_validity expected violated constraints

2021

mandatory

mandatory

rejected

month_validity, day_validity

2021

mandatory

optional

rejected

month_validity

2021

optional

optional

accepted

2021

mandatory

prohibited

rejected

month_validity

2021

prohibited

prohibited

accepted

2021-10

mandatory

mandatory

rejected

day_validity

2021-10

mandatory

optional

accepted

2021-10

optional

optional

accepted

2021-10

mandatory

prohibited

accepted

2021-10

prohibited

prohibited

rejected

month_validity

2021-10-24

mandatory

mandatory

accepted

2021-10-24

mandatory

optional

accepted

2021-10-24

optional

optional

accepted

2021-10-24

mandatory

prohibited

rejected

day_validity

2021-10-24

prohibited

prohibited

rejected

month_validity, day_validity

14.10.3.3. Test Case CONT-DV_DATE-validate_range

The C_DATE.range constraint is an Interval<Date>, which are both Foundation Types.

Note
the Date class mentioned in the AOM 1.4 specification is actually the Iso8601_date class. This is a known bug in the specs.
value C_DATE.range expected violated constraints

2021

1900..2030

accepted

2021

2022..2030

rejected

C_DATE.range

2021

1900..2020

rejected

C_DATE.range

value C_DATE.range expected violated constraints

2021-10

1900-03..2030-07

accepted

2021-10

2022-03..2030-07

rejected

C_DATE.range

2021-10

1900-03..2020-07

rejected

C_DATE.range

value C_DATE.range expected violated constraints

2021-10-24

1900-03-13..2030-07-09

accepted

2021-10-24

2022-03-13..2030-07-09

rejected

C_DATE.range

2021-10-24

1900-03-13..2020-07-09

rejected

C_DATE.range

Note
the DV_DATE value and the C_DATE.range limits should be comparable, that means the value and range limits should have the same components, for instance a year-only date 2021 can’t be compared to a year+month date like 2021-10, because 2021 refers to a whole year, and 2021-10 refers to a month in that year, but it’s not possible to say if 2021 < 2021-10 or 2021 2021-10, since both are refering to different things. What we could say is 2020 < 2021, and 2021-10 < 2021-11.

14.10.4. DV_DATE_TIME

DV_DATE_TIME constraints are defined by C_DATE_TIME, which specifies two types of constraints: validity kind and range. The validity kind constraints are expressed in terms of mandatory/optional/prohibited flags for each part of the date expression: hour, minute, second, millisecond, timezone, day and month. The range constraint is an Interval<DateTime>.

14.10.4.1. Test Case CONT-DV_DATE_TIME-validate_open
value expected violated constraints

NULL

rejected

RM/Schema: value is mandatory

''

rejected

openEHR RM/AOM: at least year is required

2021

accepted

2021-10

accepted

2021-00

rejected

ISO8601: month in 01..12

2021-13

rejected

ISO8601: month in 01..12

2021-10-24

accepted

2021-10-00

rejected

ISO8601: day in 01..31

2021-10-32

rejected

ISO8601: day in 01..31

2021-10-24T10

accepted

2021-10-24T48

rejected

ISO8601: hours in 0..23

2021-10-24T10:30

accepted

2021-10-24T10:95

rejected

ISO8601: minutes in 0..59

2021-10-24T10:30:47

accepted

2021-10-24T10:30:78

rejected

ISO8601: seconds in 0..59

2021-10-24T10:30:47.5

accepted

2021-10-24T10:30:47.333

accepted

2021-10-24T10:30:47.333333

accepted

2021-10-24T10:30:47Z

accepted

2021-10-24T10:30:78Z

rejected

ISO8601: seconds in 0..59

2021-10-24T10:30:47.5Z

accepted

2021-10-24T10:30:47.333Z

accepted

2021-10-24T10:30:47.333333Z

accepted

2021-10-24T10:30:47-03:00

accepted

2021-10-24T10:30:78-03:00

rejected

ISO8601: seconds in 0..59

2021-10-24T10:30:47.5-03:00

accepted

2021-10-24T10:30:47.333-03:00

accepted

2021-10-24T10:30:47.333333-03:00

accepted

Note
to verify the date time expression used this regex, note that the rejected values don’t match the regex.
14.10.4.2. Test Case CONT-DV_DATE_TIME-validate_constraint
value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

2021

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity, millisecond_validity

2021

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity

2021

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

rejected

month_validity, day_validity, hour_validity, minute_validity

2021

mandatory

mandatory

mandatory

optional

optional

optional

optional

rejected

month_validity, day_validity, hour_validity

2021

mandatory

mandatory

optional

optional

optional

optional

optional

rejected

month_validity, day_validity

2021

mandatory

optional

optional

optional

optional

optional

optional

rejected

month_validity

2021

optional

optional

optional

optional

optional

optional

optional

accepted

2021

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity, millisecond_validity

2021

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity

2021

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity

2021

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity

2021

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity

2021

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity

2021

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

accepted

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

day_validity, hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

rejected

day_validity, hour_validity, minute_validity, second_validity, millisecond_validity

2021-10

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

rejected

day_validity, hour_validity, minute_validity, second_validity

2021-10

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

rejected

day_validity, hour_validity, minute_validity

2021-10

mandatory

mandatory

mandatory

optional

optional

optional

optional

rejected

day_validity, hour_validity

2021-10

mandatory

mandatory

optional

optional

optional

optional

optional

rejected

day_validity

2021-10

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

day_validity, hour_validity, minute_validity, second_validity, millisecond_validity

2021-10

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity, second_validity

2021-10

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity

2021-10

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity

2021-10

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity

2021-10

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

accepted

2021-10

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10-24

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

rejected

hour_validity, minute_validity, second_validity, millisecond_validity

2021-10-24

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

rejected

hour_validity, minute_validity, second_validity

2021-10-24

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

rejected

hour_validity, minute_validity

2021-10-24

mandatory

mandatory

mandatory

optional

optional

optional

optional

rejected

hour_validity

2021-10-24

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

hour_validity, minute_validity, second_validity, millisecond_validity

2021-10-24

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

hour_validity, minute_validity, second_validity

2021-10-24

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

hour_validity, minute_validity

2021-10-24

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity

2021-10-24

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

accepted

2021-10-24

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity

2021-10-24

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24T10

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10-24T10

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

rejected

minute_validity, second_validity, millisecond_validity

2021-10-24T10

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

rejected

minute_validity, second_validity

2021-10-24T10

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

rejected

minute_validity

2021-10-24T10

mandatory

mandatory

mandatory

optional

optional

optional

optional

accepted

2021-10-24T10

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24T10

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

minute_validity, second_validity, millisecond_validity

2021-10-24T10

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

minute_validity, second_validity

2021-10-24T10

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

minute_validity

2021-10-24T10

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

accepted

2021-10-24T10

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity

2021-10-24T10

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity

2021-10-24T10

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24T10:30

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

rejected

second_validity, millisecond_validity

2021-10-24T10:30

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

rejected

second_validity

2021-10-24T10:30

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

accepted

2021-10-24T10:30

mandatory

mandatory

mandatory

optional

optional

optional

optional

accepted

2021-10-24T10:30

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

second_validity, millisecond_validity

2021-10-24T10:30

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

second_validity

2021-10-24T10:30

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

accepted

2021-10-24T10:30

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity

2021-10-24T10:30

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity, minute_validity

2021-10-24T10:30

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity

2021-10-24T10:30

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24T10:30:47

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

millisecond_validity, timezone_validity

2021-10-24T10:30:47

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

rejected

millisecond_validity

2021-10-24T10:30:47

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

accepted

2021-10-24T10:30:47

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

accepted

2021-10-24T10:30:47

mandatory

mandatory

mandatory

optional

optional

optional

optional

accepted

2021-10-24T10:30:47

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

millisecond_validity

2021-10-24T10:30:47

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

accepted

2021-10-24T10:30:47

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

second_validity

2021-10-24T10:30:47

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity

2021-10-24T10:30:47

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity, minute_validity, second_validity

2021-10-24T10:30:47

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity, second_validity

2021-10-24T10:30:47

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

timezone_validity

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

accepted

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

accepted

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

accepted

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

accepted

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

millisecond_validity

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, millisecond_validity

2021-10-24T10:30:47.5

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, millisecond_validity

2021-10-24T10:30:47.5

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity, minute_validity, second_validity, millisecond_validity

2021-10-24T10:30:47.5

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity, second_validity, millisecond_validity

2021-10-24T10:30:47.5

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity, millisecond_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

accepted

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

accepted

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

accepted

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

accepted

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5Z

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5Z

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5Z

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

timezone_validity

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

millisecond_validity, timezone_validity

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30:47.5Z

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30:47.5Z

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30:47.5Z

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30:47.5Z

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

millisecond_validity

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

rejected

millisecond_validity

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

accepted

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

accepted

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

optional

optional

optional

optional

accepted

2021-10-24T10:30:47Z

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47Z

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47Z

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

millisecond_validity, timezone_validity

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

timezone_validity

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, timezone_validity

2021-10-24T10:30:47Z

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, timezone_validity

2021-10-24T10:30:47Z

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity, minute_validity, second_validity, timezone_validity

2021-10-24T10:30:47Z

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity, second_validity, timezone_validity

2021-10-24T10:30:47Z

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity, timezone_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

accepted

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

accepted

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

accepted

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

accepted

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5-03:00

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5-03:00

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

timezone_validity

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

millisecond_validity, timezone_validity

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30:47.5-03:00

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30:47.5-03:00

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

2021-10-24T10:30:47.5-03:00

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity, millisecond_validity, timezone_validity

value month_validity day_validity hour_validity minute_validity second_validity millisecond_validity timezone_validity expected violated constraints

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

rejected

millisecond_validity

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

optional

rejected

millisecond_validity

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

optional

optional

accepted

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

mandatory

optional

optional

optional

accepted

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

optional

optional

optional

optional

accepted

2021-10-24T10:30:47-03:00

mandatory

mandatory

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47-03:00

mandatory

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47-03:00

optional

optional

optional

optional

optional

optional

optional

accepted

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

rejected

millisecond_validity, timezone_validity

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

rejected

timezone_validity

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

rejected

second_validity, timezone_validity

2021-10-24T10:30:47-03:00

mandatory

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

rejected

minute_validity, second_validity, timezone_validity

2021-10-24T10:30:47-03:00

mandatory

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

hour_validity, minute_validity, second_validity, timezone_validity

2021-10-24T10:30:47-03:00

mandatory

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

day_validity, hour_validity, minute_validity, second_validity, timezone_validity

2021-10-24T10:30:47-03:00

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

prohibited

rejected

month_validity, day_validity, hour_validity, minute_validity, second_validity, timezone_validity

14.10.4.3. Test Case CONT-DV_DATE_TIME-validate_range

The C_DATE_TIME.range constraint is an Interval<Date_time>, which are both Foundation Types.

Note
the Date_time class mentioned in the AOM specification is actually the Iso8601_date_time class. This is a known bug in the specs.
value C_DATE_TIME.range expected violated constraints

2021

1900..2030

accepted

2021

2022..2030

rejected

C_DATE_TIME.range

2021

1900..2020

rejected

C_DATE_TIME.range

value C_DATE_TIME.range expected violated constraints

2021-10

1900-03..2030-07

accepted

2021-10

2022-03..2030-07

rejected

C_DATE_TIME.range

2021-10

1900-03..2020-07

rejected

C_DATE_TIME.range

value C_DATE_TIME.range expected violated constraints

2021-10-24

1900-03-13..2030-07-09

accepted

2021-10-24

2022-03-13..2030-07-09

rejected

C_DATE_TIME.range

2021-10-24

1900-03-13..2020-07-09

rejected

C_DATE_TIME.range

value C_DATE_TIME.range expected violated constraints Notes

2021-05

1900..2030

accepted

2021-05

2022..2030

rejected

C_DATE_TIME.range

2021-05

1900..2021

accepted

1900..2021 is interpreted as 1900-01-01..2021-12-31, so 2021-05 is contained in that range

2021

2020-07..2022-03

accepted

2020-07..2022-03 is interpreted as 2020-07-01..2022-03-31, and 2021 is 2021-01-01..2021-12-31, which is fully contained in the range constraint

TBD: there is an open question about strictly comparability between time expressions with different components. Is "T10" comparable to "T00:00"?

value C_DATE_TIME.range expected violated constraints

2021-10-24T10

1900-03-13T00..1900-03-13T23

accepted

2021-10-24T10

1900-03-13T00:00..1900-03-13T23:59

accepted

2021-10-24T10

1900-03-13T00:00:00..1900-03-13T23:59:59

accepted

2021-10-24T10

1900-03-13T00:00:00.0..1900-03-13T23:59:59.999

accepted

2021-10-24T10

1900-03-13T11..1900-03-13T23

rejected

C_DATE_TIME.range

2021-10-24T10

1900-03-13T11:00..1900-03-13T23:59

rejected

C_DATE_TIME.range

2021-10-24T10

1900-03-13T11:00:00..1900-03-13T23:59:59

rejected

C_DATE_TIME.range

2021-10-24T10

1900-03-13T11:00:00.0..1900-03-13T23:59:59.999

rejected

C_DATE_TIME.range

2021-10-24T10

1900-03-13T00..1900-03-13T09

rejected

C_DATE_TIME.range

2021-10-24T10

1900-03-13T00:00..1900-03-13T09:59

rejected

C_DATE_TIME.range

2021-10-24T10

1900-03-13T00:00:00..1900-03-13T09:59:59

rejected

C_DATE_TIME.range

2021-10-24T10

1900-03-13T00:00:00.0..1900-03-13T09:59:59.999

rejected

C_DATE_TIME.range

2021-10-24T10

>=1900-03-13T00

accepted

2021-10-24T10

>=1900-03-13T00:00

accepted

2021-10-24T10

>=1900-03-13T00:00:00

accepted

2021-10-24T10

>=1900-03-13T00:00:00.0

accepted

2021-10-24T10

>=1900-03-13T11

rejected

C_DATE_TIME.range

2021-10-24T10

>=1900-03-13T11:00

rejected

C_DATE_TIME.range

2021-10-24T10

>=1900-03-13T11:00:00

rejected

C_DATE_TIME.range

2021-10-24T10

>=1900-03-13T11:00:00.0

rejected

C_DATE_TIME.range

2021-10-24T10

⇐1900-03-13T09

rejected

C_DATE_TIME.range

2021-10-24T10

⇐1900-03-13T09:59

rejected

C_DATE_TIME.range

2021-10-24T10

⇐1900-03-13T09:59:59

rejected

C_DATE_TIME.range

2021-10-24T10

⇐1900-03-13T09:59:59.999

rejected

C_DATE_TIME.range

14.11. Data Types - time_specification Package

14.11.1. DV_GENERAL_TIME_SPECIFICATION

TBD: this data type might not be used or supported by modeling tools

14.11.2. DV_PERIODIC_TIME_SPECIFICATION

TBD: this data type might not be used or supported by modeling tools

14.12. Data Types - encapsulated Package

14.12.1. DV_PARSABLE

14.12.1.1. Test Case CONT-DV_PARSABLE-validate_open
value formalism expected violated constraints

NULL

NULL

rejected

RM/schema value and formalism are required

abc

NULL

rejected

RM/schema formalism is required

NULL

abc

rejected

RM/schema value is required

xxx

abc

accepted

14.12.1.2. Test Case CONT-DV_PARSABLE-validate_value_formalism

Each field of the DV_PARSABLE could be constrained by a C_STRING.

value formalism C_STRING.pattern (value) C_STRING.list (value) C_STRING.pattern (formalism) C_STRING.list (formalism) expected violated constraints

xxx

abc

x*

NULL

abc

NULL

accepted

xxx

abc

a*

NULL

abc

NULL

rejected

C_STRING.pattern (value)

xxx

abc

x*

NULL

x*

NULL

rejected

C_STRING.pattern (formalism)

xxx

abc

NULL

[xxx, yyy, zzz]

abc

NULL

accepted

xxx

abc

NULL

[yyy, zzz]

abc

NULL

rejected

C_STRING.list (value)

xxx

abc

NULL

[xxx, yyy, zzz]

NULL

[abc, bbb, aaa]

accepted

xxx

abc

NULL

[xxx, yyy, zzz]

NULL

[bbb, aaa]

rejected

C_STRING.list (formalism)

14.12.2. DV_MULTIMEDIA

14.12.2.1. Test Case CONT-DV_MULTIMEDIA-validate_open
media_type size expected violated constraints

NULL

NULL

rejected

RM/schema media_type and size are required

abc

NULL

rejected

media_type is not in the media type openEHR term set, RM/schema size is required

NULL

123

rejected

RM/schema media_type is required

application/dicom

123

accepted

14.12.2.2. Test Case CONT-DV_MULTIMEDIA-validate_media_type
Note
media_type could be constrained by a C_CODE_PHRASE and size could be constrained by C_INTEGER. A NULL C_CODE_PHRASE for the media_type means any code is allowed from the openEHR media type codeset.
media_type size C_CODE_PHRASE C_INTEGER.list C_INTEGER.range expected violated constraints

application/dicom

123

NULL

[10, 100, 1000]

NULL

rejected

C_INTEGER.list

application/dicom

100

NULL

[10, 100, 1000]

NULL

accepted

application/dicom

123

NULL

NULL

0..1000

accepted

application/dicom

123

NULL

NULL

200..1000

rejected

C_INTEGER.range

application/dicom

100

[application/dicom, text/plain, text/html]

[10, 100, 1000]

NULL

accepted

application/dicom

100

[text/plain, text/html]

[10, 100, 1000]

NULL

rejected

C_CODE_PHRASE

application/dicom

100

[application/dicom, text/plain, text/html]

NULL

0..1000

accepted

application/dicom

100

[text/plain, text/html]

NULL

200..1000

rejected

C_CODE_PHRASE, C_INTEGER.range

14.13. Data Types - uri Package

14.13.1. DV_URI

14.13.1.1. Test Case CONT-DV_URI-validate_open

On this test case, only invalid URIs should be rejected. Any RFC3986-compliant URI should be accepted.

value expected violated constraints

NULL

rejected

RM/schema: value is required

xyz

rejected

value doesn’t comply with RFC3986

ftp://ftp.is.co.za/rfc/rfc1808.txt

accepted

http://www.ietf.org/rfc/rfc2396.txt

accepted

ldap://[2001:db8::7]/c=GB?objectClass?one

accepted

mailto:John.Doe@example.com

accepted

news:comp.infosystems.www.servers.unix

accepted

tel:+1-816-555-1212

accepted

telnet://192.0.2.16:80/

accepted

urn:oasis:names:specification:docbook:dtd:xml:4.1.2

accepted

http://www.carestreamserver/um/webapp_services/wado?requestType=WADO&studyUID=1.2.250.1.59.40211.12345678.678910&seriesUID=1.2.250.1.59.40211.789001276.14556172.67789&objectUID=1.2.250.1.59.40211.2678810.87991027.899772.2&contentType=application%2Fdicom

accepted

14.13.1.2. Test Case CONT-DV_URI-validate_pattern
Note
to use the pattern constraint, the pattern should comply with the URI format from RFC3986, so the pattern defines a subset of valid URIs. If the pattern doesn’t comply with the URI format, modeling tools should be responsible to notify the modeler and shouldn’t allow to export archetypes or templates in that case. Testing this is not part of the data validation compliance scope, because it is validation of AOM objects not RM.
value C_STRING.pattern expected violated constraints

xyz

https://.*

rejected

C_STRING.pattern

https://cabolabs.com

https://.*

accepted

14.13.1.3. Test Case CONT-DV_URI-validate_list
Note
the values in the C_STRING.list should be valid URIs compliant with RFC3986. If this doesn’t happen, the archetype/template is invalid. Testing this case is not in the scope of the data validation.
value C_STRING.list expected violated constraints

xyz

[https://cabolabs.com, https://cloudehrserver.com]

rejected

C_STRING.list

https://cabolabs.com

[https://cabolabs.com, https://cloudehrserver.com]

accepted

14.13.2. DV_EHR_URI

14.13.2.1. Test Case CONT-DV_EHR_URI-validate_open
value expected violated constraints notes

NULL

rejected

RM/schema: value is required

xyz

rejected

value doesn’t comply with RFC3986

ftp://ftp.is.co.za/rfc/rfc1808.txt

rejected

URI doesn’t have schema = 'ehr'

http://www.ietf.org/rfc/rfc2396.txt

rejected

URI doesn’t have schema = 'ehr'

ldap://[2001:db8::7]/c=GB?objectClass?one

rejected

URI doesn’t have schema = 'ehr'

mailto:John.Doe@example.com

rejected

URI doesn’t have schema = 'ehr'

news:comp.infosystems.www.servers.unix

rejected

URI doesn’t have schema = 'ehr'

tel:+1-816-555-1212

rejected

URI doesn’t have schema = 'ehr'

telnet://192.0.2.16:80/

rejected

URI doesn’t have schema = 'ehr'

urn:oasis:names:specification:docbook:dtd:xml:4.1.2

rejected

URI doesn’t have schema = 'ehr'

http://www.carestreamserver/um/webapp_services/wado?requestType=WADO&studyUID=1.2.250.1.59.40211.12345678.678910&seriesUID=1.2.250.1.59.40211.789001276.14556172.67789&objectUID=1.2.250.1.59.40211.2678810.87991027.899772.2&contentType=application%2Fdicom

rejected

URI doesn’t have schema = 'ehr'

ehr:/89c0752e-0815-47d7-8b3c-b3aaea2cea7a

accepted

This should be a valid reference to an EHR

ehr:/89c0752e-0815-47d7-8b3c-b3aaea2cea7a/031f2513-b9ef-47b2-bbef-8db24ae68c2f::EHRSERVER::1

accepted

This should be a valid reference to a COMPOSITION or FOLDER in an EHR (some top-level VERSIONED_OBJECT)

ehr:/89c0752e-0815-47d7-8b3c-b3aaea2cea7a/031f2513-b9ef-47b2-bbef-8db24ae68c2f::EHRSERVER::1/context/other_context[at0001]/items[archetype_id=openEHR-EHR-CLUSTER.sample_symptom.v1]/items[at0034]/items[at0021]/value

accepted

This should be a valid reference to a DATA_VALUE node in a COMPOSITION from an EHR

ehr://CLOUD_EHRSERVER/89c0752e-0815-47d7-8b3c-b3aaea2cea7a

accepted

Similar to the examples above, with given system_id as the URI authority

ehr://CLOUD_EHRSERVER/89c0752e-0815-47d7-8b3c-b3aaea2cea7a/031f2513-b9ef-47b2-bbef-8db24ae68c2f::EHRSERVER::1

accepted

Similar to the examples above, with given system_id as the URI authority

ehr://CLOUD_EHRSERVER/89c0752e-0815-47d7-8b3c-b3aaea2cea7a/031f2513-b9ef-47b2-bbef-8db24ae68c2f::EHRSERVER::1/context/other_context[at0001]/items[archetype_id=openEHR-EHR-CLUSTER.sample_symptom.v1]/items[at0034]/items[at0021]/value

accepted

Similar to the examples above, with given system_id as the URI authority

14.13.2.2. Test Case CONT-DV_EHR_URI-validate_pattern
Note
to use the pattern constraint, the pattern should comply with the URI format from RFC3986, so the pattern defines a subset of valid URIs. If the pattern doesn’t comply with the URI format, modeling tools should be responsible to notify the modeler and shouldn’t allow to export archetypes or templates in that case. Testing this is not part of the data validation compliance scope, because it is validation of AOM objects not RM.
value C_STRING.pattern expected violated constraints

xyz

ehr://.*

rejected

C_STRING.pattern

https://cabolabs.com

ehr://.*

rejected

C_STRING.pattern

ehr://CLOUD_EHRSERVER/89c0752e-0815-47d7-8b3c-b3aaea2cea7a

ehr://.*

accepted

14.13.2.3. Test Case CONT-DV_EHR_URI-validate_list
Note
the values in the C_STRING.list should be valid URIs compliant with RFC3986. If this doesn’t happen, the archetype/template is invalid. Testing this case is not in the scope of the data validation.
value C_STRING.list expected violated constraints

xyz

[ehr:/89c0752e-0815-47d7-8b3c-b3aaea2cea7a, ehr://CLOUD_EHRSERVER/89c0752e-0815-47d7-8b3c-b3aaea2cea7a]

rejected

C_STRING.list

https://cabolabs.com

[ehr:/89c0752e-0815-47d7-8b3c-b3aaea2cea7a, ehr://CLOUD_EHRSERVER/89c0752e-0815-47d7-8b3c-b3aaea2cea7a]

rejected

C_STRING.list

ehr:/89c0752e-0815-47d7-8b3c-b3aaea2cea7a

[ehr:/89c0752e-0815-47d7-8b3c-b3aaea2cea7a, ehr://CLOUD_EHRSERVER/89c0752e-0815-47d7-8b3c-b3aaea2cea7a]

accepted

15. Amendment Record

Issue Details Raiser Completed

CNF Release 1.0.0 (unreleased)

0.8.6

Improved headings based on openEHR Service Model; simplified test categories.

P Pazos

24 Mar 2022

0.8.5

Improve identifiers, structure;
add content tests from EhrBase

T Beale,
P Pazos

21 Feb 2022

0.8.0

Rewrite main schedule based on EhrBase (Github commit 674e8b2)

P Pazos;
W Wagner;
T Beale

23 Nov 2021

0.7.1

Updates and new diagrams for SUT section; Adjust some test sets.

T Beale

17 Mar 2017

0.7.0

Major rework based on openEHR Patform SM.

openEHR SEC

18 Oct 2017

0.6.2

Updates to REST API at 25 Aug 2017. Added glossary. Improved SUT diagram.

T Beale,
S Iancu

26 Aug 2017

0.6.1

Major rework from SEC call 9 Aug 2017.

C Chevalley,
H Frankel,
S Iancu,
B Lah,
B Naess,
T Beale

11 Aug 2017

0.5.0

SPECCNF-1: Initial Writing.

B Naess,
I McNicoll,
P Pazos,
T Beale

01 Jun 2017