Skip to content

Commit

Permalink
Test and coverage updates.
Browse files Browse the repository at this point in the history
- Fix maxWorkFactor === 0 use case.
- Improve error if N-Quads input not a string.
- Fix calls without options.
- Test error messages to ensure correct errors are thrown.
- Remove default options not needed for testing.
- Add various tests for complexity controls, edge cases, and coverage.
- Add simple duplicate quads test.
  • Loading branch information
davidlehn committed Sep 19, 2023
1 parent e58b091 commit c58827b
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 19 deletions.
2 changes: 1 addition & 1 deletion lib/URDNA2015.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ module.exports = class URDNA2015 {
if(this.maxDeepIterations < 0) {
// calculate maxDeepIterations if not explicit
if(this.maxWorkFactor === 0) {
// use 0 default
this.maxDeepIterations = 0;
} else if(this.maxWorkFactor === Infinity) {
this.maxDeepIterations = Infinity;
} else {
Expand Down
7 changes: 5 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ try {
function _inputToDataset(input, options) {
if(options.inputFormat) {
if(options.inputFormat === 'application/n-quads') {
if(typeof input !== 'string') {
throw new Error('N-Quads input must be a string.');
}
return exports.NQuads.parse(input);
}
throw new Error(
Expand Down Expand Up @@ -141,7 +144,7 @@ exports._rdfCanonizeNative = function(api) {
* @returns {Promise<object>} - A Promise that resolves to the canonicalized
* RDF Dataset.
*/
exports.canonize = async function(input, options) {
exports.canonize = async function(input, options = {}) {
const dataset = _inputToDataset(input, options);
_checkOutputFormat(options);

Expand Down Expand Up @@ -229,7 +232,7 @@ exports.canonize = async function(input, options) {
* @returns {Promise<object>} - A Promise that resolves to the canonicalized
* RDF Dataset.
*/
exports._canonizeSync = function(input, options) {
exports._canonizeSync = function(input, options = {}) {
const dataset = _inputToDataset(input, options);
_checkOutputFormat(options);

Expand Down
150 changes: 134 additions & 16 deletions test/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ describe('API tests', () => {
error = e;
}
assert(error);
assert.match(error.message,
/No RDF Dataset Canonicalization algorithm specified./);
});

it('should reject invalid algorithm', async () => {
Expand All @@ -28,20 +30,22 @@ describe('API tests', () => {
error = e;
}
assert(error);
assert.match(error.message,
/Invalid RDF Dataset Canonicalization algorithm/);
});

it('should reject invalid inputFormat', async () => {
let error;
try {
await rdfCanonize.canonize('', {
algorithm: 'RDFC-1.0',
inputFormat: 'application/bogus',
format: 'application/n-quads'
inputFormat: 'application/bogus'
});
} catch(e) {
error = e;
}
assert(error);
assert.match(error.message, /Unknown canonicalization input format/);
});

it('should handle falsy inputFormat', async () => {
Expand All @@ -67,6 +71,7 @@ describe('API tests', () => {
error = e;
}
assert(error);
assert.match(error.message, /Unsupported algorithm/);
});

it('should reject invalid output format', async () => {
Expand All @@ -80,6 +85,17 @@ describe('API tests', () => {
error = e;
}
assert(error);
assert.match(error.message, /Unknown canonicalization output format/);
});

it('should handle valid output format', async () => {
const input = [];
const expected = '';
const output = await rdfCanonize.canonize(input, {
algorithm: 'RDFC-1.0',
format: 'application/n-quads'
});
assert.deepStrictEqual(output, expected);
});

it('should handle falsy output format', async () => {
Expand All @@ -98,13 +114,13 @@ describe('API tests', () => {
try {
await rdfCanonize.canonize([], {
algorithm: 'RDFC-1.0',
inputFormat: 'application/bogus',
format: 'application/n-quads'
inputFormat: 'application/n-quads'
});
} catch(e) {
error = e;
}
assert(error);
assert.match(error.message, /N-Quads input must be a string./);
});

it('should set canonicalIdMap data', async () => {
Expand All @@ -125,7 +141,6 @@ _:c14n1 <urn:p1> "v1" .
const output = await rdfCanonize.canonize(input, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
format: 'application/n-quads',
canonicalIdMap
});
assert.deepStrictEqual(output, expected);
Expand All @@ -134,8 +149,7 @@ _:c14n1 <urn:p1> "v1" .

it('should allow URDNA2015 by default', async () => {
await rdfCanonize.canonize([], {
algorithm: 'URDNA2015',
format: 'application/n-quads'
algorithm: 'URDNA2015'
});
});

Expand All @@ -144,13 +158,14 @@ _:c14n1 <urn:p1> "v1" .
try {
await rdfCanonize.canonize([], {
algorithm: 'URDNA2015',
format: 'application/n-quads',
rejectURDNA2015: true
});
} catch(e) {
error = e;
}
assert(error);
assert.match(error.message,
/Invalid RDF Dataset Canonicalization algorithm/);
});

it('should abort (timeout)', async () => {
Expand All @@ -163,29 +178,50 @@ _:c14n1 <urn:p1> "v1" .
output = await rdfCanonize.canonize(data, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
format: 'application/n-quads',
signal: AbortSignal.timeout(100),
maxDeepIterations: Infinity
});
} catch(e) {
error = e;
}
assert(error, 'no abort error');
assert.match(error.message, /Abort signal received/);
assert.match(error.message, /TimeoutError/);
assert(!output, 'abort should have no output');
});

it('should abort (work factor)', async () => {
it('should abort (work factor = 0)', async () => {
const {data} = graphs.makeDataA({
subjects: 6,
objects: 6
subjects: 2,
objects: 2
});
let error;
let output;
try {
output = await rdfCanonize.canonize(data, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
signal: null,
maxWorkFactor: 0
});
} catch(e) {
error = e;
}
assert(error, 'no abort error');
assert(!output, 'abort should have no output');
});

it('should abort (work factor = 1)', async () => {
const {data} = graphs.makeDataA({
subjects: 3,
objects: 3
});
let error;
let output;
try {
output = await rdfCanonize.canonize(data, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
format: 'application/n-quads',
signal: null,
maxWorkFactor: 1
});
Expand All @@ -196,7 +232,74 @@ _:c14n1 <urn:p1> "v1" .
assert(!output, 'abort should have no output');
});

it('should abort (iterations)', async () => {
it('should not abort (work factor = Infinity)', async () => {
const {data} = graphs.makeDataA({
subjects: 3,
objects: 3
});
await rdfCanonize.canonize(data, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
maxWorkFactor: Infinity
});
});

it('should not abort (work factor = 1, max iterations set)', async () => {
const {data} = graphs.makeDataA({
subjects: 3,
objects: 3
});
await rdfCanonize.canonize(data, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
maxWorkFactor: 1,
maxDeepIterations: 33
});
});

it('should abort (iterations [max deep = 0])', async () => {
const {data} = graphs.makeDataA({
subjects: 2,
objects: 2
});
let error;
let output;
try {
output = await rdfCanonize.canonize(data, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
maxDeepIterations: 0
});
} catch(e) {
error = e;
}
assert(error, 'no abort error');
assert.match(error.message, /Maximum deep iterations exceeded/);
assert(!output, 'abort should have no output');
});

it('should abort (iterations [max work factor = 0])', async () => {
const {data} = graphs.makeDataA({
subjects: 2,
objects: 2
});
let error;
let output;
try {
output = await rdfCanonize.canonize(data, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
maxWorkFactor: 0
});
} catch(e) {
error = e;
}
assert(error, 'no abort error');
assert.match(error.message, /Maximum deep iterations exceeded/);
assert(!output, 'abort should have no output');
});

it('should abort (iterations [max deep = 1000])', async () => {
const {data} = graphs.makeDataA({
subjects: 6,
objects: 6
Expand All @@ -207,14 +310,13 @@ _:c14n1 <urn:p1> "v1" .
output = await rdfCanonize.canonize(data, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
format: 'application/n-quads',
signal: null,
maxDeepIterations: 1000
});
} catch(e) {
error = e;
}
assert(error, 'no abort error');
assert.match(error.message, /Maximum deep iterations exceeded/);
assert(!output, 'abort should have no output');
});

Expand Down Expand Up @@ -277,4 +379,20 @@ _:b0 _:b1 _:b2 .
assert.deepStrictEqual(output, expected);
});

it('should handle duplicate quads', async () => {
const input = `\
_:b0 <ex:p> _:b1 .
_:b0 <ex:p> _:b1 .
`;
const expected = `\
_:c14n1 <ex:p> _:c14n0 .
`;

const output = await rdfCanonize.canonize(input, {
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads'
});
assert.deepStrictEqual(output, expected);
});

});

0 comments on commit c58827b

Please sign in to comment.