Skip to content

Commit

Permalink
First pass at updating the validator
Browse files Browse the repository at this point in the history
  • Loading branch information
ptsefton committed Sep 20, 2023
1 parent 4a45f3b commit 1232a39
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 113 deletions.
67 changes: 25 additions & 42 deletions lib/checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class Checker {
const root = this.crate.rootDataset;
return new CheckItem({
name: 'Root dataset has appropriate @id',
message: `The root dataset @id ends in "/"`,
message: `The root dataset is './' `,
status: !!(root && root['@id'].endsWith('/'))
});
}
Expand All @@ -112,63 +112,45 @@ class Checker {
});
}

hasDescription() {
const root = this.crate.rootDataset;
return new CheckItem({
name: 'Has description',
message: 'The root Dataset has a description (http://schema.org/description)',
status: !!(root && root.description && root.description.length > 0)
});
}

hasAuthor() {
hasLicense() {
const root = this.crate.rootDataset;
const authors = Utils.asArray(root?.author).map(a => this.crate.getEntity(a['@id']));
return new CheckItem({
name: 'Has valid Authors',
message: 'The root Dataset has at least one Author (http://schema.org/author) referred to by @id, and all authors have @type Person (http://schema.org/Person) or Organization (http://schema.org/Organization)',
status: (authors.length > 0) && authors.every(a => includesTextCI(a?.['@type'], ['Person', 'Organization']))
});
const licenses = Utils.asArray(root?.license);
const check = new CheckItem({
name: 'Has a license',
type: "ERROR",
message: "The Root dataset has a license property",
status: !!(licenses.length > 0 || false)
});

return check;

}

hasLicense() {
hasDescription() {
const root = this.crate.rootDataset;
const licenses = Utils.asArray(root?.license).map(l => this.crate.getEntity(l['@id']));
return new CheckItem({
name: 'Has a license ',
message: 'The root Dataset has a License' +
licenses.map(license => license && license.name && license.description &&
includesTextCI(license['@type'], 'CreativeWork') ?
' (the license is a Creative Work with a name and description as it SHOULD be)' : ''
).join(''),
status: (licenses.length > 0)
name: 'Has description',
message: 'The root Dataset has a description (http://schema.org/description)',
status: !!(root && root.description && root.description.length > 0),
type: "ERROR"
});
}


hasDatePublished() {
const root = this.crate.rootDataset;
var date = Utils.asArray(root?.datePublished);
return new CheckItem({
name: 'Has a datePublished ',
message: 'The root Dataset has a datePublished with ONE value which is an ISO 8601 format precision of at least a day',
message: 'The root Dataset has a datePublished with ONE value which is an ISO 8601 format',
diagnostics: date.length === 1 ? '' : `Number of datePublished values is ${date.length} NOT 1`,
status: !!(date.length === 1 && date[0]?.match(/^\d{4}-([0]\d|1[0-2])-([0-2]\d|3[01])/))
status: !!(date.length === 1 && date[0].match(/^\d{4}-?([0]\d|1[0-2])?-?([0-2]\d|3[01])?/)),
type: "ERROR"
});
}


hasContactPoint() {
const root = this.crate.rootDataset;
var contacts = Utils.asArray(root?.contactPoint).map(c => this.crate.getEntity(c['@id']));
return new CheckItem({
name: 'Has a contactPoint',
message: 'The root Dataset has at least one contactPoint property which references a ContactPoint of type Customer Service',
status: contacts.some(contact => contact && contact.email &&
Utils.asArray(contact['@type']).includes('ContactPoint') &&
Utils.asArray(contact.contactType).includes('customer service'))
});
}

async check() {
var checkNames = methods.filter(n => !(n in { hasContext: 0, hasAuthor: 0, hasContactPoint: 0 }));
var context = await this.hasContext();
Expand All @@ -189,8 +171,8 @@ class Checker {
report() {
var report = [];
for (var item of this.checklist) {
const tick = item.status ? '✔️' : '❌';
report.push(`${tick} ${item.name}: ${item.message}`);
const tick = item.status ? '✔️ OK' : `❌ ${item.type}`;
report.push(`${tick} ${item.name}: ${item.message} ${item.diagnostics}`);
}
return report.join('\n');
}
Expand All @@ -210,8 +192,9 @@ class CheckItem {
constructor(data) {
this.name = data.name;
this.message = data.message;
this.type = data?.type || "WARNING"
this.status = data.status ?? false;
if (data.diagnostics) this.diagnostics = data.diagnostics;
this.diagnostics = data.diagnostics || "";
}
}

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 35 additions & 66 deletions test/checker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/



/*
The Root Data Entity MUST have the following properties:
@type: MUST be [Dataset] or an array that contain Dataset
@id: SHOULD be the string ./ or an absolute URI (see below)
name: SHOULD identify the dataset to humans well enough to disambiguate it from other RO-Crates
description: SHOULD further elaborate on the name to provide a summary of the context in which the dataset is important.
datePublished: MUST be a string in [ISO 8601 date format][DateTime] and SHOULD be specified to at least the precision of a day, MAY be a timestamp down to the millisecond.
license: SHOULD link to a Contextual Entity or Data Entity in the RO-Crate Metadata Document with a name and description (see section on licensing). MAY, if necessary be a textual description of how the RO-Crate may be used.
*/

const assert = require("assert");
Expand Down Expand Up @@ -44,93 +61,67 @@ describe("Incremental checking", async function () {
//var dataset = crate.getRootDataset();
var dataset = json["@graph"][0];
dataset.name = "";


var checker = new Checker(new ROCrate(json));
assert(!checker.hasName().status, "Does not have a name");
dataset.name = "Name!";

var checker = new Checker(new ROCrate(json));
assert(checker.hasName().status, "Does have a name");
assert(!checker.hasAuthor().status, "Does not have author");

// Author
var author1 = {
"@id": "http://orcid.org/some-orcid",
name: "Some Person",
};
dataset.author = [{ "@id": "http://orcid.org/some-orcid" }];
json["@graph"].push(author1);
var checker = new Checker(new ROCrate(json));
assert(
!checker.hasAuthor().status,
"Does not have one or more authors with @type Person or Organization"
);

// One good author and one dodgy one
var author2 = {
"@id": "http://orcid.org/some-other-orcid",
name: "Some Person",
"@type": "Person",
};
dataset.author = [{ "@id": "http://orcid.org/some-orcid" }, { "@id": "http://orcid.org/some-other-orcid" }];
json["@graph"].push(author1, author2);
var checker = new Checker(new ROCrate(json));
assert(
!checker.hasAuthor().status,
"Does not have one or more authors with @type Person or Organization"
);
assert(!checker.hasDescription().status, "Does not have a description");
dataset.description = "Description!";

// One good author
dataset.author = [author2];
json["@graph"] = [
defaults.metadataFileDescriptorTemplate,
dataset,
author2,
];
var checker = new Checker(new ROCrate(json));
assert(
checker.hasAuthor().status,
"Does have a author with @type Person or Organization"
);
assert(checker.hasName().status, "Does have a description");

// License
// No name, description
console.log(checker.hasLicense());
assert(
!checker.hasLicense().status,
"Does not have a license with @type CreativeWork"
"Has a license"
);

var license = {
"@id": "http://example.com/some_kind_of_license",
"@type": "CreativeWork",
URL: "http://example.com/some_kind_of_license",
};
dataset.license = { "@id": license["@id"] };

json["@graph"].push(license);
crate = new ROCrate(json);
var checker = new Checker(crate);
assert(
checker.hasLicense().status,
"Has a license with @type CreativeWork"
"Has a license"
);

license.name = "Some license";
license.description = "Description of at least 20 characters.";

assert(
checker.hasLicense().status,
"Does have a license with @type CreativeWork and a name and description"
"Has a license"
);

// datePublished
assert(
!checker.hasDatePublished().status,
"Does not have a datePublished"
);


crate.rootDataset.datePublished = "2017"; // Not enough detail!
assert(
!checker.hasDatePublished().status,
"Does not have a datePublished (not enough detail)"
checker.hasDatePublished().status,
);

crate.rootDataset.datePublished = ["2017-07-21", "2019-08-09"]; // this should do it
crate.rootDataset.datePublished = ["2017-07-21", "2019-08-09"];
assert(
!checker.hasDatePublished().status,
"Does not have a single datePublished"
Expand All @@ -139,32 +130,10 @@ describe("Incremental checking", async function () {
crate.rootDataset.datePublished = ["2017-07-21"]; // this should do it
assert(checker.hasDatePublished().status, "Does have a datePublished");

//contactPoint missing
assert(
!checker.hasContactPoint().status,
"Does not have a single contact point"
);
var contact = {
"@id": "[email protected]",
"@type": "ContactPoint",
}; // Not enough
dataset.contactPoint = [{ "@id": "[email protected]" }];
json["@graph"].push(contact);
var checker = new Checker(new ROCrate(json));
assert(
!checker.hasContactPoint().status,
"Does not have a contact point with enough properties"
);
contact.contactType = "customer service";
contact.email = "some@email"; // TODO: Not validated!
var checker = new Checker(new ROCrate(json));
assert(
checker.hasContactPoint().status,
"Does have a proper contact point"
);


await checker.check();
//console.log(checker.report());
console.log(checker.report());
});
});

Expand Down
24 changes: 23 additions & 1 deletion test/rocrate.new.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,20 @@ describe("setProperty", function () {
assert.strictEqual(r.license.length, 2);

});

it("Does not kill existing entities", function() {
let crate = new ROCrate(testData, { link: true, replace: true });
let e = crate.getEntity('https://orcid.org/0000');
assert.ok(e);
assert.strictEqual(e.contactPoint.email, "[email protected]");
crate.rootDataset.author = {'@id': 'https://orcid.org/0000'}
let auth = crate.getEntity('https://orcid.org/0000');
assert.strictEqual(auth.contactPoint.email, "[email protected]");


});


it("can replace existing entities", function() {
let crate = new ROCrate(testData, { link: true, replace: true });
let e = crate.getEntity('https://orcid.org/0000');
Expand All @@ -505,7 +519,7 @@ describe("setProperty", function () {
// ref only, don't replace
crate.rootDataset.author = {'@id': 'https://orcid.org/0000'}
let auth = crate.getEntity('https://orcid.org/0000');
assert.strictEqual(auth.name, "John Doe");
assert.strictEqual(auth.name, "John Doe");
assert.strictEqual(auth.contactPoint.email, "[email protected]");
// replace here
crate.rootDataset.author = {
Expand All @@ -517,6 +531,14 @@ describe("setProperty", function () {
assert.ok(!auth.contactPoint);
assert.strictEqual(auth.name, "Jane Doe");



crate.rootDataset.author = {'@id': 'https://orcid.org/0000'}
let auth1 = crate.getEntity('https://orcid.org/0000');
assert.strictEqual(auth1.name, "John Doe");
assert.strictEqual(auth1.contactPoint.email, "[email protected]");


});

});
Expand Down
5 changes: 4 additions & 1 deletion test/rocrate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/




const fs = require("fs");
const assert = require("assert");
const expect = require("chai").expect;
Expand Down Expand Up @@ -412,7 +415,7 @@ describe("IDs and identifiers", function () {
//console.log(newItem.name)

assert(Array.isArray(newItem.name));
//consol.og(crate.flatify(newItem, 2));
console.log(crate.flatify(newItem, 2));
//console.log(crate.objectified);
});

Expand Down
2 changes: 1 addition & 1 deletion test_data/sample-ro-crate-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -4000,4 +4000,4 @@
"name": "pics/thumbs/sepia_fence.png"
}
]
}
}

0 comments on commit 1232a39

Please sign in to comment.