Skip to content

Commit

Permalink
Add test for CertStorage
Browse files Browse the repository at this point in the history
  • Loading branch information
zjkmxy committed Jan 30, 2024
1 parent 0aeef29 commit c987c32
Show file tree
Hide file tree
Showing 9 changed files with 622 additions and 143 deletions.
43 changes: 24 additions & 19 deletions pnpm-lock.yaml

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

41 changes: 41 additions & 0 deletions src/namespace/name-pattern.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Component } from '@ndn/packet';
import { assert as assertMod } from '../dep.ts';
import { name } from '../utils/mod.ts';
import * as namePattern from './name-pattern.ts';
import { pattern } from './name-pattern.ts';

const assert = assertMod.assert as ((expr: unknown, msg?: string) => void);
const { assertEquals } = assertMod;

Deno.test('Name Pattern construction', () => {
const pat = pattern`/8=base/<8=peerId:string>/<58=sequence:number>`;
assertEquals(pat.length, 3);
assert((pat[0] as Component).equals(new Component(8, 'base')));
assertEquals(pat[1] as namePattern.PatternComponent, {
type: 8,
kind: 'string',
tag: 'peerId',
});
assertEquals(pat[2] as namePattern.PatternComponent, {
type: 58,
kind: 'number',
tag: 'sequence',
});

const mapping = {};
assert(namePattern.match(pat, name`/base/peer-01/seq=${13}`, mapping));
assertEquals(mapping, {
peerId: 'peer-01',
sequence: 13,
});
});

Deno.test('Make name from patterns', () => {
const pat = pattern`/8=base/<8=peerId:string>/<58=sequence:number>`;
assert(
namePattern.make(pat, {
peerId: 'peer-01',
sequence: 13,
}).equals(name`/base/peer-01/seq=${13}`),
);
});
147 changes: 145 additions & 2 deletions src/namespace/name-pattern.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,146 @@
export const pattern = ([_value]: TemplateStringsArray) => {
throw new Error('Not implemented');
import { Component, Name } from '@ndn/packet';
import { Encoder, NNI } from '@ndn/tlv';

export type PatternKind = 'bytes' | 'number' | 'string';
export type MatchValue = Uint8Array | number | string;

export type PatternComponent = {
/** TLV-TYPE. */
type: number;
/** Pattern's matching variable name */
tag: string;
/** Pattern value type */
kind: PatternKind;
};

export type Pattern = Array<PatternComponent | Component>;

export const patternComponentToString = (comp: PatternComponent) => `<${comp.type}=${comp.tag}:${comp.kind}>`;

export const componentToString = (comp: PatternComponent | Component) =>
comp instanceof Component ? comp.toString() : patternComponentToString(comp);

/**
* Convert a name pattern to string
* @param pat The name pattern
* @returns String representation
*/
export const toString = (pat: Pattern) => '/' + pat.map(componentToString).join('/');

export const matchStep = (
pattern: PatternComponent | Component,
subject: Component,
mapping: Record<string, MatchValue>,
) => {
if (pattern.type !== subject.type) {
return false;
}
if (pattern instanceof Component) {
return pattern.equals(subject);
} else if (pattern.kind === 'bytes') {
mapping[pattern.tag] = subject.value;
return true;
} else if (pattern.kind === 'string') {
mapping[pattern.tag] = new TextDecoder().decode(subject.value);

This comment has been minimized.

Copy link
@yoursunny

yoursunny Jan 30, 2024

rhs can be simplified as:

subject.text
return true;
} else {
try {
mapping[pattern.tag] = NNI.decode(subject.value);
return true;
} catch {
return false;
}
}
};

/**
* Match a given name with a given name pattern, and put matched variables into mapping.
* Digest components are removen.
*
* @param pattern The name pattern to match with.
* @param subject The name to be matched.
* @param mapping The mapping holding matched variables.
* @returns `true` if succeeded, `false` if failed.
* @throws when the component type matches but its value cannot be decoded as specified value kind.
*/
export const match = (
pattern: Pattern,
subject: Name,
mapping: Record<string, MatchValue>,
) => {
// Remove automatically added component
// ImplicitSha256DigestComponent(0x01) and ParametersSha256DigestComponent(0x02)
while (subject.length > 0 && subject.at(subject.length - 1).type <= 2) {
subject = subject.getPrefix(subject.length - 1);
}
// Must be equal length
if (subject.length !== pattern.length) {
return false;
}
for (const [i, p] of pattern.entries()) {
if (!matchStep(p, subject.at(i), mapping)) {
return false;
}
}
return true;
};

export const makeStep = (
pattern: PatternComponent | Component,
mapping: Record<string, MatchValue>,
) => {
if (pattern instanceof Component) {
return pattern;
} else {
const value = mapping[pattern.tag];
if (!value) {
throw new Error(`The pattern variable ${pattern.tag} does not exist in the mapping.`);
}
const v = typeof value === 'number' ? Encoder.encode(NNI(value)) : value;
return new Component(pattern.type, v);
}
};

/**
* Construct a Name from a given name pattern with variable mapping.
*
* @remarks The value kind of pattern components are not checked.
* @param pattern The input name pattern
* @param mapping The variable mapping
* @returns The constructed name
* @throws if a pattern with a given variable is missing
*/
export const make = (
pattern: Pattern,
mapping: Record<string, MatchValue>,
) => new Name(pattern.map((p) => makeStep(p, mapping)));

export const componentFromString = (value: string) => {
if (value.length === 0) {
return new Component();
}
if (value[0] !== '<') {
return Component.from(value);
} else {
const matching = /^<(?<type>[0-9]+)=(?<tag>[a-zA-Z0-9$_-]+):(?<kind>bytes|number|string)>$/.exec(value);
if (!matching || !matching.groups) {
throw new Error(`Invalid pattern component: ${value}`);
}
return {
type: parseInt(matching.groups.type),
kind: matching.groups.kind as PatternKind,
tag: matching.groups.tag,
} as PatternComponent;
}
};

export const fromString = (value: string) => {
if (value[0] === '/') {
value = value.substring(1);
}
return value.split('/').map(componentFromString) as Pattern;
};

export const pattern = ([value]: TemplateStringsArray) => {
return fromString(value);
};
17 changes: 17 additions & 0 deletions src/namespace/schema-tree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Name } from '@ndn/packet';
import * as namePattern from './name-pattern.ts';

export type Node<R> = {
children: Map<number, {
edge: namePattern.PatternComponent;
dest: Node<R>;
}>;
parent: WeakRef<Node<R>> | undefined;
resource: R;
};

export type MatchedObject<R> = {
mapping: Record<string, namePattern.MatchValue>;
name: Name;
resource: R;
};
Loading

0 comments on commit c987c32

Please sign in to comment.