From 8d6f5394ff52647f6f888243a9ff07be0e09f00d Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Wed, 16 Sep 2026 09:44:30 +0100 Subject: [PATCH 01/20] Bump test fixtures to 1.3 examples --- .../example-with-file-author-location.json | 47 ------------------ .../fixtures/example-with-file-directory.json | 47 ++++++++++++++++++ .../fixtures/example-with-web-resources.json | 10 ++-- .../fixtures/minimal-example-of-ro-crate.json | 33 ++++++++----- ...focus-on-multiple-contextual-entities.json | 48 +++++++++++++++++++ ...-with-contextual-entity-as-mainentity.json | 19 ++++++++ ...-crate-with-data-entity-as-mainentity.json | 22 +++++++++ 7 files changed, 163 insertions(+), 63 deletions(-) delete mode 100644 tests/fixtures/example-with-file-author-location.json create mode 100644 tests/fixtures/example-with-file-directory.json create mode 100644 tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json create mode 100644 tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json create mode 100644 tests/fixtures/ro-crate-with-data-entity-as-mainentity.json diff --git a/tests/fixtures/example-with-file-author-location.json b/tests/fixtures/example-with-file-author-location.json deleted file mode 100644 index 91fca09..0000000 --- a/tests/fixtures/example-with-file-author-location.json +++ /dev/null @@ -1,47 +0,0 @@ -{ "@context": "https://w3id.org/ro/crate/1.1/context", - "@graph": [ - - { - "@type": "CreativeWork", - "@id": "ro-crate-metadata.json", - "conformsTo": {"@id": "https://w3id.org/ro/crate/1.1"}, - "about": {"@id": "./"}, - "description": "RO-Crate Metadata File Descriptor (this file)" - }, - { - "@id": "./", - "@type": "Dataset", - "name": "Example RO-Crate", - "description": "The RO-Crate Root Data Entity", - "hasPart": [ - {"@id": "data1.txt"}, - {"@id": "data2.txt"} - ] - }, - - - { - "@id": "data1.txt", - "@type": "File", - "description": "One of hopefully many Data Entities", - "author": {"@id": "#alice"}, - "contentLocation": {"@id": "http://sws.geonames.org/8152662/"} - }, - { - "@id": "data2.txt", - "@type": "File" - }, - - { - "@id": "#alice", - "@type": "Person", - "name": "Alice", - "description": "One of hopefully many Contextual Entities" - }, - { - "@id": "http://sws.geonames.org/8152662/", - "@type": "Place", - "name": "Catalina Park" - } - ] -} diff --git a/tests/fixtures/example-with-file-directory.json b/tests/fixtures/example-with-file-directory.json new file mode 100644 index 0000000..07c7788 --- /dev/null +++ b/tests/fixtures/example-with-file-directory.json @@ -0,0 +1,47 @@ +{ "@context": "https://w3id.org/ro/crate/1.3/context", + "@graph": [ + { + "@type": "CreativeWork", + "@id": "ro-crate-metadata.json", + "conformsTo": {"@id": "https://w3id.org/ro/crate/1.3"}, + "about": {"@id": "./"} + }, + { + "@id": "./", + "@type": [ + "Dataset" + ], + "name": "Example Dataset", + "datePublished": "2016-02-01", + "author": "https://orcid.org/0000-0003-4953-0830", + "license": "CC-BY", + "hasPart": [ + { + "@id": "cp7glop.ai" + }, + { + "@id": "lots_of_little_files/" + } + ] + }, + { + "@id": "cp7glop.ai", + "@type": "File", + "name": "Diagram showing trend to increase", + "contentSize": "383766", + "description": "Illustrator file for Glop Pot", + "encodingFormat": "application/pdf" + }, + { + "@id": "lots_of_little_files/", + "@type": "Dataset", + "name": "Too many files", + "description": "This directory contains many small files -- the name of the file is a date in YYYY-MM-DD.csv, each file contains daily temperature readings, sampled hourly for the Glop Pot cave." + }, + { + "@id": "https://orcid.org/0000-0003-4953-0830", + "@type": "Person", + "name": "Michael Lake", + } + ] +} diff --git a/tests/fixtures/example-with-web-resources.json b/tests/fixtures/example-with-web-resources.json index ec015b1..729af54 100644 --- a/tests/fixtures/example-with-web-resources.json +++ b/tests/fixtures/example-with-web-resources.json @@ -1,14 +1,16 @@ -{ "@context": "https://w3id.org/ro/crate/1.1/context", +{ "@context": "https://w3id.org/ro/crate/1.3/context", "@graph": [ { "@type": "CreativeWork", "@id": "ro-crate-metadata.json", - "conformsTo": {"@id": "https://w3id.org/ro/crate/1.1"}, + "conformsTo": {"@id": "https://w3id.org/ro/crate/1.3"}, "about": {"@id": "./"} }, { "@id": "./", - "@type": "Dataset", + "@type": [ + "Dataset" + ], "hasPart": [ { "@id": "survey-responses-2019.csv" @@ -16,7 +18,7 @@ { "@id": "https://zenodo.org/record/3541888/files/ro-crate-1.0.0.pdf" } - ] + ] }, { "@id": "survey-responses-2019.csv", diff --git a/tests/fixtures/minimal-example-of-ro-crate.json b/tests/fixtures/minimal-example-of-ro-crate.json index 4f004f5..9ef0779 100644 --- a/tests/fixtures/minimal-example-of-ro-crate.json +++ b/tests/fixtures/minimal-example-of-ro-crate.json @@ -1,27 +1,36 @@ -{ "@context": "https://w3id.org/ro/crate/1.1/context", +{ "@context": "https://w3id.org/ro/crate/1.3/context", "@graph": [ { - "@type": "CreativeWork", "@id": "ro-crate-metadata.json", - "conformsTo": {"@id": "https://w3id.org/ro/crate/1.1"}, - "about": {"@id": "./"} + "@type": "CreativeWork", + "about": {"@id": "./"}, + "conformsTo": {"@id": "https://w3id.org/ro/crate/1.3"} }, { "@id": "./", - "identifier": "https://doi.org/10.4225/59/59672c09f4a4b", "@type": "Dataset", + "identifier": {"@id": "https://doi.org/10.4225/59/59672c09f4a4b"}, + "cite-as": "https://doi.org/10.4225/59/59672c09f4a4b", "datePublished": "2017", "name": "Data files associated with the manuscript:Effects of facilitated family case conferencing for ...", "description": "Palliative care planning for nursing home residents with advanced dementia ...", - "license": {"@id": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/"} + "license": {"@id": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/"}, + "creditText": "Agar, M. et al., 2017. Data supporting \"Effects of facilitated family case conferencing for advanced dementia: A cluster randomised clinical trial\". https://doi.org/10.4225/59/59672c09f4a4b" + }, + { + "@id": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/", + "@type": "CreativeWork", + "description": "This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Australia License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/au/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.", + "identifier": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/", + "name": "Attribution-NonCommercial-ShareAlike 3.0 Australia (CC BY-NC-SA 3.0 AU)" }, { - "@id": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/", - "@type": "CreativeWork", - "description": "This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Australia License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/au/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.", - "identifier": "https://creativecommons.org/licenses/by-nc-sa/3.0/au/", - "name": "Attribution-NonCommercial-ShareAlike 3.0 Australia (CC BY-NC-SA 3.0 AU)" - } + "@id": "https://doi.org/10.4225/59/59672c09f4a4b", + "@type": "PropertyValue", + "propertyID": "https://registry.identifiers.org/registry/doi", + "value": "doi:10.4225/59/59672c09f4a4b", + "url": "https://doi.org/10.4225/59/59672c09f4a4b" + } ] } diff --git a/tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json b/tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json new file mode 100644 index 0000000..c787325 --- /dev/null +++ b/tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json @@ -0,0 +1,48 @@ +{ "@context": [ + "https://w3id.org/ro/crate/1.3/context", + {"txc": "https://purl.archive.org/language-data-commons/terms#"} + ], + "@graph": [ + { + "@id": "ro-crate-metadata.json", + "@type": "CreativeWork", + "description": "RO-Crate Metadata File Descriptor (this file)", + "conformsTo": {"@id": "https://w3id.org/ro/crate/1.3"}, + "about": {"@id": "./"} + }, + { + "@id": "./", + "@type": "Dataset", + "description": "This is an experimental language data ontology based on OLAC terms for use in the ATAP and LDaCA projects", + "hasPart": [], + "name": "Language Data Ontology", + "mentions": ["txc:Annotation", "txc:CollectionEvent"] + }, + { + "@id": "txc:Annotation", + "@type": "rdfs:Class", + "name": "Annotation", + "sameAs": "http://www.language-archives.org/REC/type-20020628.html#annotation", + "rdfs:comment": "The resource includes information which annotates some other linguistic record.", + "rdfs:label": "Annotation", + "rdfs:subClassOf": { + "@id": "schema:CreativeWork" + } + }, + { + "@id": "txc:CollectionEvent", + "@type": "rdfs:Class", + "name": "CollectionEvent", + "rdfs:comment": "A description of an event at which one or more PrimaryTexts were captured, e.g. as video or audio", + "rdfs:label": "CollectionEvent", + "rdfs:subClassOf": [ + { + "@id": "schema:Event" + }, + { + "@id": "schema:CreateAction" + } + ] + } + ] +} diff --git a/tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json b/tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json new file mode 100644 index 0000000..773b3e3 --- /dev/null +++ b/tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json @@ -0,0 +1,19 @@ +{ + "@id": "./", + "@type": ["Dataset", "RepositoryObject"], + "name": "Reibey, Mary (1777 - 1855)", + "mainEntity": { + "@id": "https://en.wikipedia.org/wiki/Mary_Reibey" + }, + "hasPart" : [ + {"@id": "photo1.jpg"}, + {"@id": "photo2.jpg"} + ] +} + +{ + "@id": "https://en.wikipedia.org/wiki/Mary_Reibey", + "@type": "Person", + "name": "Mary Reibey", + "description": "Mary Reibey née Haydock (12 May 1777 – 30 May 1855) was an English-born merchant, shipowner and trader ..." +} diff --git a/tests/fixtures/ro-crate-with-data-entity-as-mainentity.json b/tests/fixtures/ro-crate-with-data-entity-as-mainentity.json new file mode 100644 index 0000000..82d07b2 --- /dev/null +++ b/tests/fixtures/ro-crate-with-data-entity-as-mainentity.json @@ -0,0 +1,22 @@ +{ + "@id": "./", + "@type": "Dataset", + "name": "Example Workflow", + "description": "An example workflow RO Crate", + "license": "Apache-2.0", + "datePublished": "2023-01-01", + "mainEntity": { + "@id": "example_workflow.cwl" + }, + "hasPart": [ + { + "@id": "example_workflow.cwl" + }, + { + "@id": "diagram.svg" + }, + { + "@id": "README.md" + } + ] +} From b1721d23313faf117e542a2717d31220d225ffa3 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Wed, 16 Sep 2026 10:51:56 +0100 Subject: [PATCH 02/20] Annotate minimal crate test better --- tests/integration.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integration.cpp b/tests/integration.cpp index b30b1fe..d3df40e 100644 --- a/tests/integration.cpp +++ b/tests/integration.cpp @@ -6,7 +6,8 @@ using rocrate::Entity; using rocrate::ROCrate; -// https://www.researchobject.org/ro-crate/specification/1.1/root-data-entity#minimal-example-of-ro-crate +// REF: https://www.researchobject.org/ro-crate/specification/1.3/root-data-entity.html#minimal-example-of-ro-crate +// FIXTURE: tests/fixtures/minimal-example-of-ro-crate.json TEST_CASE("Minimal RO-Crate", "[integration]") { ROCrate crate; From 8113a4143762e6147aebc0a6decfa871ae5aebd6 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Wed, 16 Sep 2026 10:52:24 +0100 Subject: [PATCH 03/20] Add file and directory example, remove state --- tests/integration.cpp | 97 ++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/tests/integration.cpp b/tests/integration.cpp index d3df40e..d8432c5 100644 --- a/tests/integration.cpp +++ b/tests/integration.cpp @@ -42,59 +42,52 @@ TEST_CASE("Minimal RO-Crate", "[integration]") ); } -// https://www.researchobject.org/ro-crate/specification/1.1/appendix/jsonld -TEST_CASE("Example with file, author, location", "[integration]") +// REF: https://www.researchobject.org/ro-crate/specification/1.3/data-entities.html#example-attached-ro-crate-package +// FIXTURE: tests/fixtures/example-with-file-directory.json +TEST_CASE("Example with file and directory", "[integration]") { - ROCrate crate; - - // Add description to the root metadata entity (ro-crate-metadata.json) - Entity root = crate.getEntity("ro-crate-metadata.json"); - root.set("description", "RO-Crate Metadata File Descriptor (this file)"); - REQUIRE_NOTHROW(crate.getEntity("ro-crate-metadata.json")); - - // Add name, description to the root data entity (./) - Entity rootData = crate.getEntity("./"); - rootData.set("name", "Example RO-Crate"); - rootData.set("description", "The RO-Crate Root Data Entity"); - REQUIRE_NOTHROW(crate.getEntity("./")); - - // Create the person - Entity alice({"Person"}); - alice.set("name", "Alice"); - alice.set("description", "One of hopefully many Contextual Entities"); - crate.addEntity("#alice", alice); - REQUIRE_NOTHROW(crate.getEntity("#alice")); - - // Create the place - Entity catalinaPark({"Place"}); - catalinaPark.set("name", "Catalina Park"); - crate.addEntity("http://sws.geonames.org/8152662/", catalinaPark); - REQUIRE_NOTHROW(crate.getEntity("http://sws.geonames.org/8152662/")); - - // Create two datasets - Entity data1({"File"}); - data1.set("description", "One of hopefully many Data Entities"); - data1.set("author", alice); - data1.set("contentLocation", catalinaPark); - crate.addEntity("data1.txt", data1); - rootData.set("hasPart", data1); - REQUIRE_NOTHROW(crate.getEntity("data1.txt")); - - Entity data2({"File"}); - crate.addEntity("data2.txt", data2); - rootData.set("hasPart", data2); - REQUIRE_NOTHROW(crate.getEntity("data2.txt")); - - // Write out - const std::string outputPath = - std::string(TEST_SOURCE_DIR) + "/ro-crate-metadata.json"; - crate.writeOut(outputPath); - - REQUIRE_RO_CRATE_FILE_EQUAL_BY_ID( - std::string(TEST_SOURCE_DIR) + - "/tests/fixtures/example-with-file-author-location.json", - outputPath - ); + ROCrate crate; + + // Add metadata to root data entity + Entity rootData = crate.getEntity("./"); + rootData.set("name", "Example Dataset"); + rootData.set("datePublished", "2016-02-01"); + rootData.set("license", "CC-BY"); + + // Create the author entity + Entity author({"Person"}); + author.set("name", "Michael Lake"); + crate.addEntity("https://orcid.org/0000-0003-4953-0830", author); + + // Create the file entity + Entity file({"File"}); + file.set("name", "Diagram showing trend to increase"); + file.set("contentSize", "383766"); + file.set("description", "Illustrator file for Glop Pot"); + file.set("encodingFormat", "application/pdf"); + crate.addEntity("cp7glop.ai", file); + + // Create the directory entity + Entity directory({"Dataset"}); + directory.set("name", "Too many files"); + directory.set("description", "This directory contains many small files -- the name of the file is a date in YYYY-MM-DD.csv, each file contains daily temperature readings, sampled hourly for the Glop Pot cave."); + crate.addEntity("lots_of_little_files/", directory); + + // Add file and directory to root data entity + rootData.set("hasPart", file); + rootData.set("hasPart", directory); + + // Write out + const std::string outputPath = + std::string(TEST_SOURCE_DIR) + "/ro-crate-metadata.json"; + crate.writeOut(outputPath); + + REQUIRE_RO_CRATE_FILE_EQUAL_BY_ID( + std::string(TEST_SOURCE_DIR) + + "/tests/fixtures/example-with-file-directory.json", + outputPath + ); + } TEST_CASE("Example with web resources", "[integration]") From a18d5c80a54c17e693fda48f24ccf3015124ecc9 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Wed, 16 Sep 2026 10:52:51 +0100 Subject: [PATCH 04/20] Add focus with data entity example --- tests/integration.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/integration.cpp b/tests/integration.cpp index d8432c5..71e47f3 100644 --- a/tests/integration.cpp +++ b/tests/integration.cpp @@ -126,3 +126,51 @@ TEST_CASE("Example with web resources", "[integration]") ); } + +// REF: https://www.researchobject.org/ro-crate/specification/1.3/crate-focus.html (RO-Crates with a data entity as mainEntity) +// FIXTURE: tests/fixtures/ro-crate-with-a-data-entity-as-mainentity.json +TEST_CASE("RO-Crate with a data entity as mainEntity", "[integration]") +{ + ROCrate crate; + + // Add metadata to root data entity + Entity rootData = crate.getEntity("./"); + rootData.set("name", "Example Workflow"); + rootData.set("description", "An example workflow RO Crate"); + rootData.set("license", "Apache-2.0"); + rootData.set("datePublished", "2023-01-01"); + + // Create the mainEntity file entity + Entity mainEntity({"File"}); + mainEntity.set("name", "example_workflow.cwl"); + crate.addEntity("example_workflow.cwl", mainEntity); + + // Set mainEntity for root data entity + rootData.set("mainEntity", mainEntity); + + // Create additional file entities + Entity diagram({"File"}); + diagram.set("name", "diagram.svg"); + crate.addEntity("diagram.svg", diagram); + + Entity readme({"File"}); + readme.set("name", "README.md"); + crate.addEntity("README.md", readme); + + // Add hasPart to root data entity + rootData.set("hasPart", mainEntity); + rootData.set("hasPart", diagram); + rootData.set("hasPart", readme); + + // Write out + const std::string outputPath = + std::string(TEST_SOURCE_DIR) + "/ro-crate-metadata.json"; + crate.writeOut(outputPath); + + REQUIRE_RO_CRATE_FILE_EQUAL_BY_ID( + std::string(TEST_SOURCE_DIR) + + "/tests/fixtures/ro-crate-with-data-entity-as-mainentity.json", + outputPath + ); +} + From 71ffbb093c3b61ef57a7a9380412db7a62ec4305 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Wed, 16 Sep 2026 10:53:05 +0100 Subject: [PATCH 05/20] Add focus with contextual entity example --- tests/integration.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/integration.cpp b/tests/integration.cpp index 71e47f3..2e70880 100644 --- a/tests/integration.cpp +++ b/tests/integration.cpp @@ -174,3 +174,50 @@ TEST_CASE("RO-Crate with a data entity as mainEntity", "[integration]") ); } +// REF: https://www.researchobject.org/ro-crate/specification/1.3/crate-focus.html (RO-Crates with a contextual entity as mainEntity) +// FIXTURE: tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json +TEST_CASE("RO-Crate with a contextual entity as mainEntity", "[integration]") +{ + ROCrate crate; + + // Add metadata to root data entity + Entity rootData = crate.getEntity("./"); + rootData.set("name", "Reibey, Mary (1777 - 1855)"); + rootData.set("license", "CC-BY"); + rootData.set("datePublished", "2023-01-01"); + + // Create the mainEntity contextual entity + Entity mainEntity({"Person"}); + mainEntity.set("name", "Mary Reibey"); + mainEntity.set("description", "Mary Reibey née Haydock (12 May 1777 – 30 May 1855) was an English-born merchant, shipowner and trader ..."); + crate.addEntity("https://en.wikipedia.org/wiki/Mary_Reibey", mainEntity); + + // Set mainEntity for root data entity + rootData.set("mainEntity", mainEntity); + + // Create additional file entities + Entity photo1({"File"}); + photo1.set("name", "photo1.jpg"); + crate.addEntity("photo1.jpg", photo1); + + Entity photo2({"File"}); + photo2.set("name", "photo2.jpg"); + crate.addEntity("photo2.jpg", photo2); + + // Add hasPart to root data entity + rootData.set("hasPart", photo1); + rootData.set("hasPart", photo2); + + // Write out + const std::string outputPath = + std::string(TEST_SOURCE_DIR) + "/ro-crate-metadata.json"; + crate.writeOut(outputPath); + + REQUIRE_RO_CRATE_FILE_EQUAL_BY_ID( + std::string(TEST_SOURCE_DIR) + + "/tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json", + outputPath + ); + +} + From 8f5e9775d1629502baa90a2036dfc8d5819a3cfb Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Wed, 16 Sep 2026 10:53:18 +0100 Subject: [PATCH 06/20] Bump hpp to 1.3 --- include/ro-crate.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ro-crate.hpp b/include/ro-crate.hpp index 3449cdc..51b2803 100644 --- a/include/ro-crate.hpp +++ b/include/ro-crate.hpp @@ -210,7 +210,7 @@ namespace rocrate { Entity rootEntity({"CreativeWork"}); rootEntity.set( "conformsTo", - "https://w3id.org/ro/crate/1.1", + "https://w3id.org/ro/crate/1.3", ValueType::Reference ); addEntity("ro-crate-metadata.json", rootEntity); @@ -251,7 +251,7 @@ namespace rocrate { inline void ROCrate::writeOut(const std::string& path) { nlohmann::json outCrate = { - {"@context", "https://w3id.org/ro/crate/1.1/context"}, + {"@context", "https://w3id.org/ro/crate/1.3/context"}, {"@graph", nlohmann::json::array()} }; From 05f1aca5c4e50fa9e235f0c38dd1ea90f53985ca Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Wed, 16 Sep 2026 10:53:35 +0100 Subject: [PATCH 07/20] Change examples to singleton tag preference --- tests/fixtures/example-with-file-directory.json | 4 +--- tests/fixtures/example-with-web-resources.json | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/fixtures/example-with-file-directory.json b/tests/fixtures/example-with-file-directory.json index 07c7788..267beb9 100644 --- a/tests/fixtures/example-with-file-directory.json +++ b/tests/fixtures/example-with-file-directory.json @@ -8,9 +8,7 @@ }, { "@id": "./", - "@type": [ - "Dataset" - ], + "@type": "Dataset", "name": "Example Dataset", "datePublished": "2016-02-01", "author": "https://orcid.org/0000-0003-4953-0830", diff --git a/tests/fixtures/example-with-web-resources.json b/tests/fixtures/example-with-web-resources.json index 729af54..4be3b86 100644 --- a/tests/fixtures/example-with-web-resources.json +++ b/tests/fixtures/example-with-web-resources.json @@ -8,9 +8,7 @@ }, { "@id": "./", - "@type": [ - "Dataset" - ], + "@type": "Dataset", "hasPart": [ { "@id": "survey-responses-2019.csv" From 839b19ee4dc50097f3b31a4c2973fdca8071c7ab Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Wed, 16 Sep 2026 10:53:47 +0100 Subject: [PATCH 08/20] Annotate web example --- tests/integration.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration.cpp b/tests/integration.cpp index 2e70880..d9faab7 100644 --- a/tests/integration.cpp +++ b/tests/integration.cpp @@ -90,6 +90,8 @@ TEST_CASE("Example with file and directory", "[integration]") } +// REF: https://www.researchobject.org/ro-crate/specification/1.3/data-entities.html#web-based-data-entities +// FIXTURE: tests/fixtures/example-with-web-resources.json TEST_CASE("Example with web resources", "[integration]") { ROCrate crate; From 886078bd9916f8f8f50f463eaba49066186e00d6 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Fri, 18 Sep 2026 15:06:43 +0100 Subject: [PATCH 09/20] Drop fixtures --- ...-with-contextual-entity-as-mainentity.json | 19 ---------------- ...-crate-with-data-entity-as-mainentity.json | 22 ------------------- 2 files changed, 41 deletions(-) delete mode 100644 tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json delete mode 100644 tests/fixtures/ro-crate-with-data-entity-as-mainentity.json diff --git a/tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json b/tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json deleted file mode 100644 index 773b3e3..0000000 --- a/tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "@id": "./", - "@type": ["Dataset", "RepositoryObject"], - "name": "Reibey, Mary (1777 - 1855)", - "mainEntity": { - "@id": "https://en.wikipedia.org/wiki/Mary_Reibey" - }, - "hasPart" : [ - {"@id": "photo1.jpg"}, - {"@id": "photo2.jpg"} - ] -} - -{ - "@id": "https://en.wikipedia.org/wiki/Mary_Reibey", - "@type": "Person", - "name": "Mary Reibey", - "description": "Mary Reibey née Haydock (12 May 1777 – 30 May 1855) was an English-born merchant, shipowner and trader ..." -} diff --git a/tests/fixtures/ro-crate-with-data-entity-as-mainentity.json b/tests/fixtures/ro-crate-with-data-entity-as-mainentity.json deleted file mode 100644 index 82d07b2..0000000 --- a/tests/fixtures/ro-crate-with-data-entity-as-mainentity.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "@id": "./", - "@type": "Dataset", - "name": "Example Workflow", - "description": "An example workflow RO Crate", - "license": "Apache-2.0", - "datePublished": "2023-01-01", - "mainEntity": { - "@id": "example_workflow.cwl" - }, - "hasPart": [ - { - "@id": "example_workflow.cwl" - }, - { - "@id": "diagram.svg" - }, - { - "@id": "README.md" - } - ] -} From 13f69c1109040ade79505a24b5f200aa826f4289 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Fri, 18 Sep 2026 15:07:00 +0100 Subject: [PATCH 10/20] Remove invalid json trailing comma --- tests/fixtures/example-with-file-directory.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fixtures/example-with-file-directory.json b/tests/fixtures/example-with-file-directory.json index 267beb9..92328f8 100644 --- a/tests/fixtures/example-with-file-directory.json +++ b/tests/fixtures/example-with-file-directory.json @@ -39,7 +39,7 @@ { "@id": "https://orcid.org/0000-0003-4953-0830", "@type": "Person", - "name": "Michael Lake", + "name": "Michael Lake" } ] } From 740caad15f2be2303f7a1375213f6b52a6f97839 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Fri, 18 Sep 2026 15:07:10 +0100 Subject: [PATCH 11/20] Add context handling --- include/ro-crate.hpp | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/include/ro-crate.hpp b/include/ro-crate.hpp index 51b2803..9eb19f5 100644 --- a/include/ro-crate.hpp +++ b/include/ro-crate.hpp @@ -177,6 +177,15 @@ namespace rocrate { */ Entity& getEntity(const std::string& id); + /** + * Adds a context entry to the RO-Crate's root metadata entity. + * + * @param key The context key to add. + * @param value The context value associated with the key. + * @throw std::invalid_argument if the key is empty. + */ + void addContext(const std::string& key, const std::string& value); + /** * Serializes the RO-Crate to a JSON file at the specified path. * @@ -200,6 +209,7 @@ namespace rocrate { ) const; EntityRegister entities_; + std::map context_; }; inline ROCrate::ROCrate() { @@ -249,12 +259,35 @@ namespace rocrate { return it->second; } - inline void ROCrate::writeOut(const std::string& path) { + inline void ROCrate::addContext(const std::string& key, const std::string& value) { + // Validate the context + if (key.empty()) { + throw std::invalid_argument("Context key cannot be empty."); + } + if (value.empty()) { + throw std::invalid_argument("Context value cannot be empty."); + } + + // Add the context entry to the RO-Crate's root metadata entity + context_[key] = value; + } + + inline void ROCrate::writeOut(const std::string& path) { + // Create the JSON representation of the RO-Crate nlohmann::json outCrate = { {"@context", "https://w3id.org/ro/crate/1.3/context"}, {"@graph", nlohmann::json::array()} }; + // Add the context entries to the JSON representation + if (!context_.empty()) { + outCrate["@context"] = nlohmann::json::array(); + outCrate["@context"].push_back("https://w3id.org/ro/crate/1.3/context"); + for (const auto& [key, value] : context_) { + outCrate["@context"].push_back({{key, value}}); + } + } + // Iterate over the entities, conver to json and append to the graph for (const auto& [id, entity] : entities_) { outCrate["@graph"].push_back(serializeEntity(id, entity)); From 2a1fb5514dc63ce8bacd642dc0da385a61fbdab5 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Mon, 21 Sep 2026 13:52:59 +0100 Subject: [PATCH 12/20] Regularise fixtures --- tests/fixtures/example-with-file-directory.json | 2 +- ...o-crate-which-focus-on-multiple-contextual-entities.json | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/fixtures/example-with-file-directory.json b/tests/fixtures/example-with-file-directory.json index 92328f8..6dff969 100644 --- a/tests/fixtures/example-with-file-directory.json +++ b/tests/fixtures/example-with-file-directory.json @@ -11,7 +11,7 @@ "@type": "Dataset", "name": "Example Dataset", "datePublished": "2016-02-01", - "author": "https://orcid.org/0000-0003-4953-0830", + "author": {"@id": "https://orcid.org/0000-0003-4953-0830"}, "license": "CC-BY", "hasPart": [ { diff --git a/tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json b/tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json index c787325..a876a15 100644 --- a/tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json +++ b/tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json @@ -14,9 +14,11 @@ "@id": "./", "@type": "Dataset", "description": "This is an experimental language data ontology based on OLAC terms for use in the ATAP and LDaCA projects", - "hasPart": [], "name": "Language Data Ontology", - "mentions": ["txc:Annotation", "txc:CollectionEvent"] + "mentions": [ + {"@id": "txc:Annotation"}, + {"@id": "txc:CollectionEvent"} + ] }, { "@id": "txc:Annotation", From d9cf50847f4bcfd511d74203cb4a2ebce4e916b0 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Mon, 21 Sep 2026 13:53:39 +0100 Subject: [PATCH 13/20] Bump integration tests to 1.3 --- tests/integration.cpp | 125 ++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 78 deletions(-) diff --git a/tests/integration.cpp b/tests/integration.cpp index d9faab7..2d48ddd 100644 --- a/tests/integration.cpp +++ b/tests/integration.cpp @@ -5,6 +5,7 @@ using rocrate::Entity; using rocrate::ROCrate; +using rocrate::ValueType; // REF: https://www.researchobject.org/ro-crate/specification/1.3/root-data-entity.html#minimal-example-of-ro-crate // FIXTURE: tests/fixtures/minimal-example-of-ro-crate.json @@ -14,10 +15,11 @@ TEST_CASE("Minimal RO-Crate", "[integration]") // Add metadata to root data entity Entity rootData = crate.getEntity("./"); - rootData.set("identifier", "https://doi.org/10.4225/59/59672c09f4a4b"); + rootData.set("cite-as", "https://doi.org/10.4225/59/59672c09f4a4b"); rootData.set("datePublished", "2017"); rootData.set("name", "Data files associated with the manuscript:Effects of facilitated family case conferencing for ..."); rootData.set("description", "Palliative care planning for nursing home residents with advanced dementia ..."); + rootData.set("creditText", "Agar, M. et al., 2017. Data supporting \"Effects of facilitated family case conferencing for advanced dementia: A cluster randomised clinical trial\". https://doi.org/10.4225/59/59672c09f4a4b"); // Create the license entity Entity license({"CreativeWork"}); @@ -27,6 +29,14 @@ TEST_CASE("Minimal RO-Crate", "[integration]") crate.addEntity("https://creativecommons.org/licenses/by-nc-sa/3.0/au/", license); + // Create the DOI entry + Entity doi({"PropertyValue"}); + doi.set("propertyID", "https://registry.identifiers.org/registry/doi"); + doi.set("value", "doi:10.4225/59/59672c09f4a4b"); + doi.set("url", "https://doi.org/10.4225/59/59672c09f4a4b"); + crate.addEntity("https://doi.org/10.4225/59/59672c09f4a4b", doi); + rootData.set("identifier", doi); + // Add license to root data entity rootData.set("license", license); @@ -58,6 +68,7 @@ TEST_CASE("Example with file and directory", "[integration]") Entity author({"Person"}); author.set("name", "Michael Lake"); crate.addEntity("https://orcid.org/0000-0003-4953-0830", author); + rootData.set("author", author); // Create the file entity Entity file({"File"}); @@ -71,6 +82,7 @@ TEST_CASE("Example with file and directory", "[integration]") Entity directory({"Dataset"}); directory.set("name", "Too many files"); directory.set("description", "This directory contains many small files -- the name of the file is a date in YYYY-MM-DD.csv, each file contains daily temperature readings, sampled hourly for the Glop Pot cave."); + crate.addEntity("lots_of_little_files/", directory); // Add file and directory to root data entity @@ -129,86 +141,45 @@ TEST_CASE("Example with web resources", "[integration]") } -// REF: https://www.researchobject.org/ro-crate/specification/1.3/crate-focus.html (RO-Crates with a data entity as mainEntity) -// FIXTURE: tests/fixtures/ro-crate-with-a-data-entity-as-mainentity.json -TEST_CASE("RO-Crate with a data entity as mainEntity", "[integration]") +// REF: https://www.researchobject.org/ro-crate/specification/1.3/crate-focus.html (RO-Crates which focus on multiple Contextual Entities) +// FIXTURE: tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json +TEST_CASE("RO-Crate which focuses on multiple Contextual Entities", "[integration]") { ROCrate crate; - // Add metadata to root data entity - Entity rootData = crate.getEntity("./"); - rootData.set("name", "Example Workflow"); - rootData.set("description", "An example workflow RO Crate"); - rootData.set("license", "Apache-2.0"); - rootData.set("datePublished", "2023-01-01"); - - // Create the mainEntity file entity - Entity mainEntity({"File"}); - mainEntity.set("name", "example_workflow.cwl"); - crate.addEntity("example_workflow.cwl", mainEntity); - - // Set mainEntity for root data entity - rootData.set("mainEntity", mainEntity); - - // Create additional file entities - Entity diagram({"File"}); - diagram.set("name", "diagram.svg"); - crate.addEntity("diagram.svg", diagram); - - Entity readme({"File"}); - readme.set("name", "README.md"); - crate.addEntity("README.md", readme); - - // Add hasPart to root data entity - rootData.set("hasPart", mainEntity); - rootData.set("hasPart", diagram); - rootData.set("hasPart", readme); - - // Write out - const std::string outputPath = - std::string(TEST_SOURCE_DIR) + "/ro-crate-metadata.json"; - crate.writeOut(outputPath); - - REQUIRE_RO_CRATE_FILE_EQUAL_BY_ID( - std::string(TEST_SOURCE_DIR) + - "/tests/fixtures/ro-crate-with-data-entity-as-mainentity.json", - outputPath - ); -} - -// REF: https://www.researchobject.org/ro-crate/specification/1.3/crate-focus.html (RO-Crates with a contextual entity as mainEntity) -// FIXTURE: tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json -TEST_CASE("RO-Crate with a contextual entity as mainEntity", "[integration]") -{ - ROCrate crate; + // Add metadata to the RO-Crate metadata file descriptor + Entity metadataFileDescriptor = crate.getEntity("ro-crate-metadata.json"); + metadataFileDescriptor.set("description", "RO-Crate Metadata File Descriptor (this file)"); // Add metadata to root data entity Entity rootData = crate.getEntity("./"); - rootData.set("name", "Reibey, Mary (1777 - 1855)"); - rootData.set("license", "CC-BY"); - rootData.set("datePublished", "2023-01-01"); - - // Create the mainEntity contextual entity - Entity mainEntity({"Person"}); - mainEntity.set("name", "Mary Reibey"); - mainEntity.set("description", "Mary Reibey née Haydock (12 May 1777 – 30 May 1855) was an English-born merchant, shipowner and trader ..."); - crate.addEntity("https://en.wikipedia.org/wiki/Mary_Reibey", mainEntity); - - // Set mainEntity for root data entity - rootData.set("mainEntity", mainEntity); - - // Create additional file entities - Entity photo1({"File"}); - photo1.set("name", "photo1.jpg"); - crate.addEntity("photo1.jpg", photo1); - - Entity photo2({"File"}); - photo2.set("name", "photo2.jpg"); - crate.addEntity("photo2.jpg", photo2); - - // Add hasPart to root data entity - rootData.set("hasPart", photo1); - rootData.set("hasPart", photo2); + rootData.set("name", "Language Data Ontology"); + rootData.set("description", "This is an experimental language data ontology based on OLAC terms for use in the ATAP and LDaCA projects"); + + // Add additonal context + crate.addContext("txc", "https://purl.archive.org/language-data-commons/terms#"); + + // Create the first contextual entity + Entity annotation({"rdfs:Class"}); + annotation.set("name", "Annotation"); + annotation.set("sameAs", "http://www.language-archives.org/REC/type-20020628.html#annotation"); + annotation.set("rdfs:comment", "The resource includes information which annotates some other linguistic record."); + annotation.set("rdfs:label", "Annotation"); + annotation.set("rdfs:subClassOf", "schema:CreativeWork", ValueType::Reference); + crate.addEntity("txc:Annotation", annotation); + + // Create the second contextual entity + Entity collectionEvent({"rdfs:Class"}); + collectionEvent.set("name", "CollectionEvent"); + collectionEvent.set("rdfs:comment", "A description of an event at which one or more PrimaryTexts were captured, e.g. as video or audio"); + collectionEvent.set("rdfs:label", "CollectionEvent"); + collectionEvent.set("rdfs:subClassOf", "schema:Event", ValueType::Reference); + collectionEvent.set("rdfs:subClassOf", "schema:CreateAction", ValueType::Reference); + crate.addEntity("txc:CollectionEvent", collectionEvent); + + // Add mentions to root data entity + rootData.set("mentions", annotation); + rootData.set("mentions", collectionEvent); // Write out const std::string outputPath = @@ -217,9 +188,7 @@ TEST_CASE("RO-Crate with a contextual entity as mainEntity", "[integration]") REQUIRE_RO_CRATE_FILE_EQUAL_BY_ID( std::string(TEST_SOURCE_DIR) + - "/tests/fixtures/ro-crate-with-contextual-entity-as-mainentity.json", + "/tests/fixtures/ro-crate-which-focus-on-multiple-contextual-entities.json", outputPath ); - } - From 8e8019612a1b7e8dc56af26d4a4a973d9df07c84 Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Mon, 21 Sep 2026 13:58:12 +0100 Subject: [PATCH 14/20] Complete add context docstring --- include/ro-crate.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/ro-crate.hpp b/include/ro-crate.hpp index 9eb19f5..875ec08 100644 --- a/include/ro-crate.hpp +++ b/include/ro-crate.hpp @@ -183,6 +183,7 @@ namespace rocrate { * @param key The context key to add. * @param value The context value associated with the key. * @throw std::invalid_argument if the key is empty. + * @throw std::runtime_error if the key already exists in the context. */ void addContext(const std::string& key, const std::string& value); From 2612445dc03c7664f290f0c84b7d845fb21f429c Mon Sep 17 00:00:00 2001 From: Oliver Woolland Date: Mon, 21 Sep 2026 14:26:38 +0100 Subject: [PATCH 15/20] Update readme --- README.md | 20 ++++++++++++++++---- tests/unit.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 537b1d2..a2f4b5a 100644 --- a/README.md +++ b/README.md @@ -96,8 +96,8 @@ ROCrate crate; ### Create an Entity -To create an entity, instantiate the `Entity` class. You can must provide a type, -or list of types. +To create an entity, instantiate the `Entity` class. You must provide a type, +or can provide a list of types. ```cpp // Single type @@ -139,16 +139,28 @@ Entity alice({"Person"}); crate.addEntity("#alice", alice); ``` +### Add additional context to an RO-Crate + +To add additional context to an RO-Crate, use the `addContext` method. The first +argument is the id of the context to add. The second is the context link itself +which must be a valid URL. + +```cpp +ROCrate crate; + +crate.addContext("txc", "https://purl.archive.org/language-data-commons/terms#"); +``` + ### Write out an RO-Crate To write out an RO-Crate, use the `writeOut` method. The argument is the path to write the RO-Crate to. This will write out the `ro-crate-metadata.json` file. ```cpp -crate.writeOut("./routput/");o +crate.writeOut("./routput/"); ``` -## Explaination +## Explanation These notes are mostly aimed at developers who want to understand the design of this library, but may be of interest to users as well. diff --git a/tests/unit.cpp b/tests/unit.cpp index c9b5d08..df6c571 100644 --- a/tests/unit.cpp +++ b/tests/unit.cpp @@ -112,6 +112,33 @@ TEST_CASE("Crate and builder observe shared entity updates", "[unit]") { SUCCEED("No exceptions thrown, can't currently assert on entity values as they are not exposed in the API"); } +TEST_CASE("Context can be added without error", "[unit]") { + rocrate::ROCrate crate; + + REQUIRE_NOTHROW(crate.addContext("example", "https://example.com/context.jsonld")); +} + +TEST_CASE("Duplicate context doesn't throw", "[unit]") { + rocrate::ROCrate crate; + + REQUIRE_NOTHROW(crate.addContext("example", "https://example.com/context.jsonld")); + REQUIRE_NOTHROW(crate.addContext("example", "https://example.com/context.jsonld")); + +} + +TEST_CASE("Add context throws if context is empty", "[unit]") { + rocrate::ROCrate crate; + + REQUIRE_THROWS_AS(crate.addContext("", ""), std::invalid_argument); +} + +TEST_CASE("Add entity throws if ID is empty", "[unit]") { + rocrate::ROCrate crate; + Entity alice({"Person"}); + + REQUIRE_THROWS_AS(crate.addEntity("", alice), std::invalid_argument); +} + TEST_CASE("Add entity rejects entities with duplicate IDs", "[unit]") { // Create a crate and add an entity rocrate::ROCrate crate; From df2ce2d2af19d19b787ba99a739677ca69072a56 Mon Sep 17 00:00:00 2001 From: Oliver Woolland <86293426+OliverWoolland@users.noreply.github.com> Date: Mon, 21 Sep 2026 14:37:28 +0100 Subject: [PATCH 16/20] Modify test for adding context with empty ID Update test case to check for invalid context addition with a URL. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/unit.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unit.cpp b/tests/unit.cpp index df6c571..ca94674 100644 --- a/tests/unit.cpp +++ b/tests/unit.cpp @@ -129,7 +129,11 @@ TEST_CASE("Duplicate context doesn't throw", "[unit]") { TEST_CASE("Add context throws if context is empty", "[unit]") { rocrate::ROCrate crate; - REQUIRE_THROWS_AS(crate.addContext("", ""), std::invalid_argument); + REQUIRE_THROWS_AS( + crate.addContext("", "https://example.com/context.jsonld"), + std::invalid_argument + ); + REQUIRE_THROWS_AS(crate.addContext("example", ""), std::invalid_argument); } TEST_CASE("Add entity throws if ID is empty", "[unit]") { From 0a0f89e56735dd84436ae0c03c5c9c5e428b3373 Mon Sep 17 00:00:00 2001 From: Oliver Woolland <86293426+OliverWoolland@users.noreply.github.com> Date: Mon, 21 Sep 2026 14:37:39 +0100 Subject: [PATCH 17/20] Update context link requirements in README Clarify context link requirements in documentation. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2f4b5a..8cb8654 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ crate.addEntity("#alice", alice); To add additional context to an RO-Crate, use the `addContext` method. The first argument is the id of the context to add. The second is the context link itself -which must be a valid URL. +which must be non-empty. ```cpp ROCrate crate; From 0fc79d0aef5a272d9a5c15da17cd16e41a91810a Mon Sep 17 00:00:00 2001 From: Oliver Woolland <86293426+OliverWoolland@users.noreply.github.com> Date: Mon, 21 Sep 2026 14:37:55 +0100 Subject: [PATCH 18/20] Change output path to ro-crate-metadata.json Update output path for RO-Crate metadata file. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8cb8654..20b8070 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ To write out an RO-Crate, use the `writeOut` method. The argument is the path to write the RO-Crate to. This will write out the `ro-crate-metadata.json` file. ```cpp -crate.writeOut("./routput/"); +crate.writeOut("./routput/ro-crate-metadata.json"); ``` ## Explanation From 3261942992d3ad6b42a4b580835476b995cf1ea1 Mon Sep 17 00:00:00 2001 From: Oliver Woolland <86293426+OliverWoolland@users.noreply.github.com> Date: Mon, 21 Sep 2026 14:38:07 +0100 Subject: [PATCH 19/20] Fix typo in comment for additional context Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/integration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration.cpp b/tests/integration.cpp index 2d48ddd..6080384 100644 --- a/tests/integration.cpp +++ b/tests/integration.cpp @@ -156,7 +156,7 @@ TEST_CASE("RO-Crate which focuses on multiple Contextual Entities", "[integratio rootData.set("name", "Language Data Ontology"); rootData.set("description", "This is an experimental language data ontology based on OLAC terms for use in the ATAP and LDaCA projects"); - // Add additonal context + // Add additional context crate.addContext("txc", "https://purl.archive.org/language-data-commons/terms#"); // Create the first contextual entity From 87f16cc5ba87a83436425d7bdb21ac4478929574 Mon Sep 17 00:00:00 2001 From: Oliver Woolland <86293426+OliverWoolland@users.noreply.github.com> Date: Mon, 21 Sep 2026 14:38:22 +0100 Subject: [PATCH 20/20] Clarify exception handling in addContext documentation Updated documentation for addContext method to clarify exceptions. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- include/ro-crate.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/ro-crate.hpp b/include/ro-crate.hpp index 875ec08..63018bd 100644 --- a/include/ro-crate.hpp +++ b/include/ro-crate.hpp @@ -182,8 +182,7 @@ namespace rocrate { * * @param key The context key to add. * @param value The context value associated with the key. - * @throw std::invalid_argument if the key is empty. - * @throw std::runtime_error if the key already exists in the context. + * @throw std::invalid_argument if the key or value is empty. */ void addContext(const std::string& key, const std::string& value);