Skip to content

Commit

Permalink
PROCALL-3029 Repated is now differing between SetOf and SequenceOf. A…
Browse files Browse the repository at this point in the history
… choice may contain repeated values such as SequenceOf and SetOf. Added some test cases for it
  • Loading branch information
JanFellner committed Jan 10, 2023
1 parent 9e94210 commit e5096b2
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 44 deletions.
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@
},
"devDependencies": {
"@types/mocha": "^10.0.1",
"@types/node": "^18.11.10",
"@typescript-eslint/eslint-plugin": "^5.23.0",
"@typescript-eslint/parser": "^5.23.0",
"@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "^5.48.1",
"@typescript-eslint/parser": "^5.48.1",
"asn1-test-suite": "^1.0.2",
"eslint": "^8.15.0",
"eslint-plugin-deprecation": "^1.3.2",
"mocha": "^10.0.0",
"eslint": "^8.31.0",
"eslint-plugin-deprecation": "^1.3.3",
"mocha": "^10.2.0",
"nyc": "^15.1.0",
"rollup": "^3.6.0",
"rollup-plugin-dts": "^5.0.0",
"rollup": "^3.9.1",
"rollup-plugin-dts": "^5.1.1",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-typescript2": "^0.34.1",
"ts-node": "^10.7.0",
"typescript": "^4.6.4"
"ts-node": "^10.9.1",
"typescript": "^4.9.4"
},
"repository": {
"type": "git",
Expand All @@ -40,7 +40,7 @@
"dependencies": {
"pvtsutils": "^1.3.2",
"pvutils": "^1.1.3",
"tslib": "^2.4.0"
"tslib": "^2.4.1"
},
"description": "ASN1.ts is a cross platform ASN1 library written in typescript. It supports encoding and (schema supported) decoding of ber encoded asn1 structures.",
"keywords": [
Expand Down Expand Up @@ -79,6 +79,6 @@
"lint:fix": "eslint --fix . --ext .ts",
"coverage": "nyc npm test"
},
"version": "3.1.10",
"version": "3.1.11",
"license": "BSD-3-Clause"
}
19 changes: 15 additions & 4 deletions src/Choice.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
import { BaseBlock } from "./BaseBlock";
import { IAny, Any } from "./Any";
import { BaseBlock } from "./BaseBlock";
import { ILocalIdentificationBlockParams, LocalIdentificationBlock } from "./internals/LocalIdentificationBlock";
import { SequenceOf } from "./SequenceOf";
import { SetOf } from "./SetOf";

export interface IChoice extends IAny {
value: BaseBlock[];
value: (BaseBlock | SequenceOf | SetOf | Choice)[];
}

export type ChoiceParams = Partial<IChoice>;
export interface ChoiceParams extends ILocalIdentificationBlockParams, Partial<IChoice> {
}

/**
* A Choice is only used while schema validation
* In that case the choice takes the place of a list of possible options while verifying a schema
*/
export class Choice extends Any implements IChoice {
public value: BaseBlock[];
public value: (BaseBlock | SequenceOf | SetOf | Choice)[];
public idBlock: LocalIdentificationBlock;

constructor({
value = [],
...parameters
}: ChoiceParams = {}) {
super(parameters);

/** If the property is not explicitly defined as optional it may also be defined as optional with defining of the optionalID */
if(parameters.idBlock?.optionalID !== undefined && parameters.idBlock.optionalID >= 0)
this.optional = true;

this.idBlock = new LocalIdentificationBlock(parameters);

this.value = value;
}

Expand Down
41 changes: 41 additions & 0 deletions src/SequenceOf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { IAny, Any } from "./Any";
import { ILocalIdentificationBlockParams, LocalIdentificationBlock } from "./internals/LocalIdentificationBlock";
import { ETagClass, EUniversalTagNumber } from "./TypeStore";

export interface ISequenceOf extends IAny {
value: Any;
local: boolean;
}

export interface SequenceOfParams extends ILocalIdentificationBlockParams, Partial<ISequenceOf> {
}

export class SequenceOf extends Any {

public value: Any;
public local: boolean;
public idBlock: LocalIdentificationBlock;

constructor({
value = new Any(),
local = false,
...parameters
}: SequenceOfParams = {}) {
super(parameters);

/** If the property is not explicitly defined as optional it may also be defined as optional with defining of the optionalID */
if(parameters.idBlock?.optionalID !== undefined && parameters.idBlock.optionalID >= 0)
this.optional = true;

if(!parameters.idBlock)
parameters.idBlock = {};
parameters.idBlock.tagNumber = EUniversalTagNumber.Sequence;
parameters.idBlock.tagClass = ETagClass.UNIVERSAL;

this.idBlock = new LocalIdentificationBlock(parameters);

this.value = value;
this.local = local; /** Could local or global array to store elements */
}

}
15 changes: 10 additions & 5 deletions src/Repeated.ts → src/SetOf.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { IAny, Any } from "./Any";
import { ILocalIdentificationBlockParams, LocalIdentificationBlock } from "./internals/LocalIdentificationBlock";
import { ETagClass, EUniversalTagNumber } from "./TypeStore";

export interface IRepeated extends IAny {
export interface ISetOf extends IAny {
value: Any;
local: boolean;
}

export interface RepeatedParams extends ILocalIdentificationBlockParams, Partial<IRepeated> {
export interface SetOfParams extends ILocalIdentificationBlockParams, Partial<ISetOf> {
}


export class Repeated extends Any {
export class SetOf extends Any {

public value: Any;
public local: boolean;
Expand All @@ -20,13 +20,18 @@ export class Repeated extends Any {
value = new Any(),
local = false,
...parameters
}: RepeatedParams = {}) {
}: SetOfParams = {}) {
super(parameters);

/** If the property is not explicitly defined as optional it may also be defined as optional with defining of the optionalID */
if(parameters.idBlock?.optionalID !== undefined && parameters.idBlock.optionalID >= 0)
this.optional = true;

if(!parameters.idBlock)
parameters.idBlock = {};
parameters.idBlock.tagNumber = EUniversalTagNumber.Set;
parameters.idBlock.tagClass = ETagClass.UNIVERSAL;

this.idBlock = new LocalIdentificationBlock(parameters);

this.value = value;
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ export * from "./TIME";
/** schema types */
export * from "./Any";
export * from "./Choice";
export * from "./Repeated";
export * from "./SequenceOf";
export * from "./SetOf";

/** special */
export * from "./RawData";
Expand Down
27 changes: 11 additions & 16 deletions src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import * as pvtsutils from "pvtsutils";
import { IS_CONSTRUCTED, ID_BLOCK, FROM_BER, TO_BER, TAG_CLASS, TAG_NUMBER, IS_HEX_ONLY, VALUE_HEX_VIEW } from "./internals/constants";
import { Any } from "./Any";
import { Choice } from "./Choice";
import { Repeated } from "./Repeated";
import { Sequence } from "./Sequence";
import { getTypeForIDBlock, localFromBER, TnewAsnType } from "./parser";
import { AsnType, ETagClass, EUniversalTagNumber, typeStore } from "./TypeStore";
import { getTypeForIDBlock, localFromBER } from "./parser";
import { AsnType, ETagClass, typeStore } from "./TypeStore";
import { ILocalConstructedValueBlock } from "./internals/LocalConstructedValueBlock";
import { LocalIdentificationBlock } from "./internals/LocalIdentificationBlock";
import { LocalLengthBlock } from "./internals/LocalLengthBlock";
import { BaseBlock } from "./BaseBlock";
import { SequenceOf } from "./SequenceOf";
import { SetOf } from "./SetOf";

export type AsnSchemaType = AsnType | Any | Choice | Repeated;
export type AsnSchemaType = AsnType | Any | Choice | SequenceOf | SetOf;

export interface CompareSchemaSuccess {
verified: true;
Expand Down Expand Up @@ -113,6 +114,7 @@ export enum ESchemaError {
/** If you add new Values !!! Add them to the getTextForError as well !!! */
}

/* istanbul ignore next */
function getTextForError(error: ESchemaError): string {
switch (error) {
case ESchemaError.NO_ERROR:
Expand Down Expand Up @@ -256,12 +258,8 @@ function compareSchemaInternal(root: AsnType, inputSchema: AsnSchemaType, option
//#endregion

//#region Special case for Repeated schema element type
else if (inputSchema instanceof Repeated) {
/**
* We iterate over the value fields and validate whether the schema matches the value data
*/
if (inputData.idBlock.tagClass !== ETagClass.UNIVERSAL
|| inputData.idBlock.tagNumber !== EUniversalTagNumber.Sequence) {
else if (inputSchema instanceof SequenceOf || inputSchema instanceof SetOf) {
if (!inputSchema.idBlock.isIdenticalType(inputData.idBlock)) {
errors.push(new SchemaError(ESchemaError.INVALID_ASN1DATA, context));
return errors;
}
Expand Down Expand Up @@ -472,7 +470,8 @@ function compareSchemaInternal(root: AsnType, inputSchema: AsnSchemaType, option
let maxLength = Math.max(inputSchema.valueBlock.value.length, inputValue.length);

if (maxLength > 0) {
if (inputSchema.valueBlock.value[0] instanceof Repeated) {
const element = inputSchema.valueBlock.value[0];
if (element instanceof SequenceOf || element instanceof SetOf) {
maxLength = inputValue.length; /** TODO debug it */
}
}
Expand Down Expand Up @@ -542,11 +541,7 @@ function compareSchemaInternal(root: AsnType, inputSchema: AsnSchemaType, option
bFound = true;
schema = check;
/** As we have a context specific attribute the type comes from the schema field */
let newType: TnewAsnType | undefined;
if (schema instanceof Repeated)
newType = typeStore.Sequence;
else
newType = getTypeForIDBlock(schema.idBlock);
const newType = getTypeForIDBlock(schema.idBlock);
if (newType) {
/** Create the new object matching the type of the scheme for the context spcific parameter from the input */
const contextualElement = new newType();
Expand Down
104 changes: 101 additions & 3 deletions test/asn1choice.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as assert from "assert";
import * as asn1ts from "../src";
import * as pvtsutils from "pvtsutils";
import { SchemaContext } from "../src";
import { ESchemaError, SchemaContext } from "../src";
import { ETagClass } from "../src/TypeStore";

/**
Expand All @@ -15,7 +15,6 @@ import { ETagClass } from "../src/TypeStore";
* @returns an asn1 sequence object containing the choice
*/
function getChoice(getschema: boolean, bAddString: boolean, bAddBoolean: boolean, bAddInteger: boolean): asn1ts.AsnType {

if(getschema) {
const choice = new asn1ts.Choice({name: "choice"});
if (bAddString)
Expand Down Expand Up @@ -70,6 +69,106 @@ context("Asn1Choice implementation tests", () => {
}
});

it("test context specific choice with correct repeated values", () => {
const schema = new asn1ts.Choice({
name: "choice",
value: [
new asn1ts.SequenceOf({value: new asn1ts.Integer, name: "integers1", idBlock: {optionalID: 1} }),
new asn1ts.SequenceOf({value: new asn1ts.Utf8String, name: "strings1", idBlock: {optionalID: 2} }),
new asn1ts.SetOf({value: new asn1ts.Integer, name: "integers2", idBlock: {optionalID: 3} }),
new asn1ts.SetOf({value: new asn1ts.Utf8String, name: "strings2", idBlock: {optionalID: 4} }),
]
});
const seq = new asn1ts.Constructed({
name: "constructed",
idBlock: {
tagClass: ETagClass.CONTEXT_SPECIFIC,
tagNumber: 2,
},
value: [
new asn1ts.Utf8String({value:"1"}),
new asn1ts.Utf8String({value:"2"}),
new asn1ts.Utf8String({value:"3"})
]
});
const data = seq.toBER();
const hex = pvtsutils.Convert.ToHex(data);

const context = new SchemaContext();
context.debug = true;

const result = asn1ts.verifySchema(data, schema, undefined, context);
assert.equal(result.verified, true, "Schema verification failed");
if (result.verified)
assert.equal(result.result.name, "strings1");
});

it("test context specific choice with wrong repeated values", () => {
const schema = new asn1ts.Choice({
name: "choice",
value: [
new asn1ts.SequenceOf({value: new asn1ts.Integer, name: "integers1", idBlock: {optionalID: 1} }),
new asn1ts.SequenceOf({value: new asn1ts.Utf8String, name: "strings1", idBlock: {optionalID: 2} }),
new asn1ts.SetOf({value: new asn1ts.Integer, name: "integers2", idBlock: {optionalID: 3} }),
new asn1ts.SetOf({value: new asn1ts.Utf8String, name: "strings2", idBlock: {optionalID: 4} }),
]
});
const seq = new asn1ts.Constructed({
name: "constructed",
idBlock: {
tagClass: ETagClass.CONTEXT_SPECIFIC,
tagNumber: 2,
},
value: [
new asn1ts.Utf8String({value:"1"}),
new asn1ts.Utf8String({value:"2"}),
new asn1ts.Utf8String({value:"3"}),
new asn1ts.Integer({value: 4})
]
});
const data = seq.toBER();
const hex = pvtsutils.Convert.ToHex(data);

const context = new SchemaContext();
context.debug = true;

const result = asn1ts.verifySchema(data, schema, undefined, context);
assert.equal(result.verified, false, "Schema verification failed");
if (!result.verified) {
assert.equal(result.errors?.length, 1);
if(result.errors) {
const error = result.errors[0];
assert.equal(error.error, ESchemaError.NO_MATCHING_DATA_FOR_CHOICE);
}
}
});

it("test regular choice with repeated values", () => {
const schema = new asn1ts.Choice({
value: [
new asn1ts.SetOf({value: new asn1ts.Utf8String, name: "strings1"}),
new asn1ts.SequenceOf({value: new asn1ts.Utf8String, name: "strings2"}),
]
});
const seq = new asn1ts.Sequence({
value: [
new asn1ts.Utf8String({value:"1"}),
new asn1ts.Utf8String({value:"2"}),
new asn1ts.Utf8String({value:"3"})
]
});
const data = seq.toBER();
const hex = pvtsutils.Convert.ToHex(data);

const context = new SchemaContext();
context.debug = true;

const result = asn1ts.verifySchema(data, schema, undefined, context);
assert.equal(result.verified, true, "Schema verification failed");
if (result.verified)
assert.equal(result.result.name, "strings2");
});

it("test choice on root level", () => {
/** All choices would match the asn1 type but the type exposed the optional context-specific */
/** Thus the context needs to be found by id and not by matching schema */
Expand Down Expand Up @@ -113,7 +212,6 @@ context("Asn1Choice implementation tests", () => {
const hex = pvtsutils.Convert.ToHex(data);

const context = new SchemaContext();
context.debug = true;

const result = asn1ts.verifySchema(data, schema, undefined, context);
assert.equal(result.verified, true, "Schema verification failed");
Expand Down
5 changes: 2 additions & 3 deletions test/asn1repeated.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { ETagClass } from "../src/TypeStore";
* @param type the type of object we want to get a repeated schema for
* @returns the repeated schema
*/
function getRepeatedSchema(type: asn1ts.AsnType, params: asn1ts.RepeatedParams): asn1ts.Repeated {
return new asn1ts.Repeated({
function getRepeatedSchema(type: asn1ts.AsnType, params: asn1ts.SequenceOfParams): asn1ts.SequenceOf {
return new asn1ts.SequenceOf({
...params,
value: type
});
Expand Down Expand Up @@ -118,5 +118,4 @@ context("Asn1Repeated implementation tests", () => {
assert.equal(optional2.valueBlock.value.length, 1, "failed");
}
});

});

0 comments on commit e5096b2

Please sign in to comment.