@@ -101,9 +101,11 @@ auto TestSuite::parse(const sourcemeta::core::JSON &document,
101101 TEST_ERROR_IF (!document.defines (" target" ), tracker,
102102 sourcemeta::core::empty_pointer,
103103 " The test document must contain a `target` property" );
104- TEST_ERROR_IF (!document.at (" target" ).is_string (), tracker,
105- sourcemeta::core::Pointer{" target" },
106- " The test document `target` property must be a URI" );
104+ TEST_ERROR_IF (!document.at (" target" ).is_string () &&
105+ !document.at (" target" ).is_array (),
106+ tracker, sourcemeta::core::Pointer{" target" },
107+ " The test document `target` property must be a URI or an "
108+ " array of URIs" );
107109 TEST_ERROR_IF (!document.defines (" tests" ), tracker,
108110 sourcemeta::core::empty_pointer,
109111 " The test document must contain a `tests` property" );
@@ -113,12 +115,33 @@ auto TestSuite::parse(const sourcemeta::core::JSON &document,
113115
114116 const auto base_path_uri{
115117 sourcemeta::core::URI::from_path (base_path / " test.json" )};
116- sourcemeta::core::URI schema_uri{document.at (" target" ).to_string ()};
117- schema_uri.resolve_from (base_path_uri);
118- schema_uri.canonicalize ();
119118
120119 TestSuite test_suite;
121- test_suite.target = schema_uri.recompose ();
120+
121+ if (document.at (" target" ).is_string ()) {
122+ sourcemeta::core::URI schema_uri{document.at (" target" ).to_string ()};
123+ schema_uri.resolve_from (base_path_uri);
124+ schema_uri.canonicalize ();
125+ test_suite.targets .push_back (schema_uri.recompose ());
126+ } else {
127+ TEST_ERROR_IF (document.at (" target" ).empty (), tracker,
128+ sourcemeta::core::Pointer{" target" },
129+ " The test document `target` array must contain at least "
130+ " one URI" );
131+ // TODO(C++23): Use std::views::enumerate when available in libc++
132+ std::size_t target_index{0 };
133+ for (const auto &target_entry : document.at (" target" ).as_array ()) {
134+ const sourcemeta::core::Pointer target_location{" target" , target_index};
135+ TEST_ERROR_IF (!target_entry.is_string (), tracker, target_location,
136+ " Each entry in the test document `target` array must be "
137+ " a URI" );
138+ sourcemeta::core::URI schema_uri{target_entry.to_string ()};
139+ schema_uri.resolve_from (base_path_uri);
140+ schema_uri.canonicalize ();
141+ test_suite.targets .push_back (schema_uri.recompose ());
142+ target_index += 1 ;
143+ }
144+ }
122145
123146 // TODO(C++23): Use std::views::enumerate when available in libc++
124147 std::size_t index{0 };
@@ -131,23 +154,28 @@ auto TestSuite::parse(const sourcemeta::core::JSON &document,
131154 index += 1 ;
132155 }
133156
134- const auto target_schema{sourcemeta::core::wrap (test_suite.target )};
135-
136- try {
137- test_suite.schema_fast =
138- compile (target_schema, walker, schema_resolver, compiler,
139- Mode::FastValidation, default_dialect, default_id, " " , tweaks);
140- test_suite.schema_exhaustive =
141- compile (target_schema, walker, schema_resolver, compiler,
142- Mode::Exhaustive, default_dialect, default_id, " " , tweaks);
143- } catch (const sourcemeta::core::SchemaReferenceError &error) {
144- if (error.location () == sourcemeta::core::Pointer{" $ref" } &&
145- error.identifier () == test_suite.target ) {
146- throw sourcemeta::core::SchemaResolutionError{
147- test_suite.target , " Could not resolve schema under test" };
157+ test_suite.schemas_fast .reserve (test_suite.targets .size ());
158+ test_suite.schemas_exhaustive .reserve (test_suite.targets .size ());
159+
160+ for (const auto &target : test_suite.targets ) {
161+ const auto target_schema{sourcemeta::core::wrap (target)};
162+
163+ try {
164+ test_suite.schemas_fast .push_back (compile (
165+ target_schema, walker, schema_resolver, compiler,
166+ Mode::FastValidation, default_dialect, default_id, " " , tweaks));
167+ test_suite.schemas_exhaustive .push_back (
168+ compile (target_schema, walker, schema_resolver, compiler,
169+ Mode::Exhaustive, default_dialect, default_id, " " , tweaks));
170+ } catch (const sourcemeta::core::SchemaReferenceError &error) {
171+ if (error.location () == sourcemeta::core::Pointer{" $ref" } &&
172+ error.identifier () == target) {
173+ throw sourcemeta::core::SchemaResolutionError{
174+ target, " Could not resolve schema under test" };
175+ }
176+
177+ throw ;
148178 }
149-
150- throw ;
151179 }
152180
153181 return test_suite;
0 commit comments