Skip to content

Clean up the algorithms suite. #127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,13 @@ export * as assertions from './assertions.js';
export {generators} from './vc-generator/generators.js';
export {deriveCloned, issueCloned} from './vc-generator/issuer.js';
export {createDocLoader} from './vc-generator/documentLoader.js';
// this is just here for backwards compatitility to avoid a major release
// FIXME remove this on next MAJOR release
export {
dateRegex, expectedMultibasePrefix, isObjectOrArrayOfObjects,
shouldBeErrorResponse, shouldBeUrl, isStringOrArrayOfStrings,
isValidMultibaseEncoded, shouldBeBs58, shouldBeBase64NoPadUrl,
verificationFail
} from './assertions.js';
export {createInitialVc} from './helpers.js';
export {algorithmsSuite} from './suites/algorithms.js';
154 changes: 86 additions & 68 deletions suites/algorithms.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,43 @@
/*!
* Copyright (c) 2024 Digital Bazaar, Inc.
*/
import chai from 'chai';
import {createInitialVc} from '../helpers.js';

const expect = chai.expect;

export function algorithmsAssertions({
endpoints,
testDescription,
vendorName,
export function algorithmsSuite({
implemented,
testDescription = 'Data Integrity - Algorithms',
credential,
features = {
authentication: false,
proofChain: false
}
}) {
return describe(testDescription, function() {
const columnId = testDescription;
// this will tell the report
// to make an interop matrix with this suite
this.matrix = true;
this.report = true;
this.rowLabel = 'Test Name';
this.columnLabel = 'Implementation';
this.implemented = [];
for(const [vendorName, {endpoints}] of implemented) {
if(!endpoints) {
throw new Error(`Expected ${vendorName} to have endpoints.`);
}
algorithmsAssert({vendorName, credential, endpoints, features});
}
});
}

function algorithmsAssert({vendorName, credential, endpoints, features}) {
return describe(vendorName, function() {
const [issuer] = endpoints;
beforeEach(function() {
this.currentTest.cell = {
columnId,
columnId: vendorName,
rowId: this.currentTest.title
};
});
Expand Down Expand Up @@ -54,78 +77,73 @@ and proof.proofPurpose values is not set, an error MUST be raised.',
'type', 'proofPurpose', 'verificationMethod');
}
});
it('If options has a non-null domain item, it MUST be equal to \
proof.domain or an error MUST be raised.',
function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20options%20has%20a%20non%2Dnull%20domain%20item%2C%20it%20MUST%20be%20equal%20to%20proof.domain%20or%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.';
this.test.cell.skipMessage = 'Pending test.';
this.skip();
});
it('If options has a non-null challenge item, it MUST be equal to \
proof.challenge or an error MUST be raised.',
function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20options%20has%20a%20non%2Dnull%20challenge%20item%2C%20it%20MUST%20be%20equal%20to%20proof.challenge%20or%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.';
this.test.cell.skipMessage = 'Pending test.';
this.skip();
});
it('Whenever this algorithm encodes strings, it MUST use UTF-8 encoding.',
if(features?.authentication) {
it('If options has a non-null domain item, it MUST be equal to \
proof.domain or an error MUST be raised.',
function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=(map).-,Whenever%20this%20algorithm%20encodes%20strings%2C%20it%20MUST%20use%20UTF%2D8%20encoding.,-Let%20proof%20be';
for(const proof of proofs) {
expect(proof.proofValue.isWellFormed()).to.be.true;
}
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20options%20has%20a%20non%2Dnull%20domain%20item%2C%20it%20MUST%20be%20equal%20to%20proof.domain%20or%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.';
this.test.cell.skipMessage = 'Pending test.';
this.skip();
});
it('If a proof with id equal to previousProof does not exist in allProofs, \
an error MUST be raised.',
function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProofdoes%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.';
for(const proof of proofs) {
if('previousProof' in proof) {
if(typeof proof.previousProof === 'string') {
proofs.some(
otherProof => otherProof.id == proof.previousProof).
should.equal(true,
'Expected previousProof ' +
`${proof.previousProof} ` +
'to be the id of another included proof.'
);
} if(Array.isArray(proof.previousProof)) {
for(const previousProof in proof.previousProof) {
it('If options has a non-null challenge item, it MUST be equal to \
proof.challenge or an error MUST be raised.',
function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20options%20has%20a%20non%2Dnull%20challenge%20item%2C%20it%20MUST%20be%20equal%20to%20proof.challenge%20or%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.';
this.test.cell.skipMessage = 'Pending test.';
this.skip();
});
}
if(features?.proofChain) {
it('If a proof with id equal to previousProof does not exist in ' +
'allProofs, an error MUST be raised.', function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProofdoes%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.';
for(const proof of proofs) {
if('previousProof' in proof) {
if(typeof proof.previousProof === 'string') {
proofs.some(
otherProof => otherProof.id == previousProof).
otherProof => otherProof.id == proof.previousProof).
should.equal(true,
'Expected previousProof ' +
`${proof.previousProof} ` +
'to be the id of another included proof.'
`${proof.previousProof} ` +
'to be the id of another included proof.'
);
} if(Array.isArray(proof.previousProof)) {
for(const previousProof in proof.previousProof) {
proofs.some(
otherProof => otherProof.id == previousProof).
should.equal(true,
'Expected previousProof ' +
`${proof.previousProof} ` +
'to be the id of another included proof.'
);
}
}
}
}
}
});
it('If any element of previousProof array has an id attribute \
that does not match the id attribute of any element of allProofs, \
an error MUST be raised.',
function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20any%20element%20of%20previousProof%20array%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.';
const previousProofs = [];
for(const proof of proofs) {
if('previousProof' in proof) {
if(typeof proof.previousProof === 'string') {
previousProofs.push(proof.previousProof);
} if(Array.isArray(proof.previousProof)) {
previousProofs.concat(proof.previousProof);
});
it('If any element of previousProof array has an id attribute' +
' that does not match the id attribute of any element of allProofs,' +
' an error MUST be raised.', function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20any%20element%20of%20previousProof%20array%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.';
const previousProofs = [];
for(const proof of proofs) {
if('previousProof' in proof) {
if(typeof proof.previousProof === 'string') {
previousProofs.push(proof.previousProof);
} if(Array.isArray(proof.previousProof)) {
previousProofs.concat(proof.previousProof);
}
}
}
}
for(const previousProof of previousProofs) {
proofs.some(
otherProof => otherProof.id == previousProof).should.equal(
true,
'Expected all previousProof values to be the id of \
another included proof.'
);
}
});
for(const previousProof of previousProofs) {
proofs.some(
otherProof => otherProof.id == previousProof).should.equal(
true,
'Expected all previousProof values to be the id of \
another included proof.'
);
}
});
}
});
}
62 changes: 62 additions & 0 deletions tests/30-algorithms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*!
* Copyright (c) 2024 Digital Bazaar, Inc.
*/
import {algorithmsSuite} from '../index.js';
import {createSuite} from './helpers.js';
import {cryptosuites} from './fixtures/cryptosuites.js';
import {documentLoader} from './fixtures/documentLoader.js';
import {MockIssuer} from './mock-data.js';
import {versionedCredentials} from './fixtures/credentials/index.js';

const tag = 'Test-Issuer-Valid';
const tags = [tag];

describe('should run with all suites', function() {
for(const testDataOptions of cryptosuites) {
for(const [
vcVersion,
{credential, mandatoryPointers}
] of versionedCredentials) {
_runSuite({
vcVersion,
testDataOptions,
credential,
mandatoryPointers
});
}
}
});

function _runSuite({
vcVersion, testDataOptions,
credential, mandatoryPointers
}) {
const {suiteName, keyType = ''} = testDataOptions;
let title = `VC ${vcVersion} Suite ${suiteName}`;
if(keyType) {
title += `keyType ${keyType}`;
}
return describe(title,
function() {
const implemented = new Map();
const {cryptosuite, key, derived} = testDataOptions;
const signer = key.signer();
const suite = createSuite({
signer, cryptosuite,
mandatoryPointers, derived
});
// pass the VC's context to the issuer
const {'@context': contexts} = credential;
const issuer = new MockIssuer({
tags, suite,
contexts, documentLoader
});
implemented.set(suiteName, {endpoints: [issuer]});
algorithmsSuite({
implemented,
tag,
credential,
cryptosuiteName: suiteName,
});
});
}
Loading