Skip to content

Commit

Permalink
Merge pull request #1454 from demergent-labs/property_test_arbitrary_…
Browse files Browse the repository at this point in the history
…depth_variant

Property test arbitrary depth variant
  • Loading branch information
lastmjs authored Nov 21, 2023
2 parents 2616415 + e0b6b22 commit 69a0395
Show file tree
Hide file tree
Showing 46 changed files with 997 additions and 663 deletions.
1 change: 1 addition & 0 deletions examples/list_of_lists/test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export function getTests(listOfListsCanister: ActorSubclass<_SERVICE>): Test[] {
}
},
// TODO we don't know we this just started breaking
// https://github.com/demergent-labs/azle/issues/1453
// {
// name: 'listOfNull test',
// test: async () => {
Expand Down
27 changes: 15 additions & 12 deletions property_tests/arbitraries/candid/candid_arb.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import fc from 'fast-check';
import { deepEqual } from 'fast-equals';
import { CandidType } from './candid_type_arb';

// TODO we're thinking that Candid is not the best name for this. What is better?
export type CandidMeta<T extends CandidType> = {
value: T;
src: {
candidType: string;
typeDeclaration?: string;
imports: Set<string>;
valueLiteral: string;
};
export type CandidMeta<T extends CandidType, E = T> = {
agentArgumentValue: T;
agentResponseValue: E;
src: Src;
};

export type Src = {
candidType: string;
typeDeclaration?: string;
imports: Set<string>;
valueLiteral: string;
};

export const CandidMetaArb = <T extends CandidType>(
Expand All @@ -19,13 +21,14 @@ export const CandidMetaArb = <T extends CandidType>(
toLiteral: (value: T) => string
) => {
return arb.map(
(value): CandidMeta<T> => ({
(agentArgumentValue): CandidMeta<T> => ({
src: {
candidType,
imports: new Set([candidType]),
valueLiteral: toLiteral(value)
valueLiteral: toLiteral(agentArgumentValue)
},
value
agentArgumentValue,
agentResponseValue: agentArgumentValue
})
);
};
74 changes: 53 additions & 21 deletions property_tests/arbitraries/candid/candid_type_arb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@ import { CandidMeta } from './candid_arb';
import { Func } from './reference/func_arb';
import { Opt } from './constructed/opt_arb';
import { Variant } from './constructed/variant_arb';
import { BaseVariantArb } from './constructed/variant_arb/base';
import { Record } from './constructed/record_arb';
import { Tuple } from './constructed/tuple_arb';
import { RecordArb } from './constructed/record_arb/base';
import { TupleArb } from './constructed/tuple_arb/base';
import { OptArb } from './constructed/opt_arb/base';
import { Vec, VecArb } from './constructed/vec_arb';
import { FuncArb } from './reference/func_arb/base';

export type CandidType =
| number
Expand All @@ -45,30 +51,56 @@ export type CandidType =
| Uint16Array
| Uint32Array
| Uint8Array
| BigUint64Array;
| BigUint64Array
| Vec;

/**
* An arbitrary representing all possible Candid types.
*
* **Note:** This currently only supports ints, nats, and null arbitraries
*/
export const CandidTypeArb: fc.Arbitrary<CandidMeta<CandidType>> = fc.oneof(
Float32Arb,
Float64Arb,
IntArb,
Int8Arb,
Int16Arb,
Int32Arb,
Int64Arb,
NatArb,
Nat8Arb,
Nat16Arb,
Nat32Arb,
Nat64Arb,
BoolArb,
NullArb,
TextArb,
PrincipalArb,
BlobArb
);
// TODO: This needs to support ALL valid candid types, including records, variants, etc.
export const CandidTypeArb: fc.Arbitrary<CandidMeta<CandidType>> = fc.letrec(
(tie) => ({
CandidType: fc.oneof(
BlobArb,
tie('Opt').map((sample) => sample as CandidMeta<Opt>),
tie('Record').map((sample) => sample as CandidMeta<Record>),
tie('Tuple').map((sample) => sample as CandidMeta<Tuple>),
tie('Variant').map((sample) => sample as CandidMeta<Variant>),
tie('Vec').map((sample) => sample as CandidMeta<Vec>),
Float32Arb,
Float64Arb,
IntArb,
Int8Arb,
Int16Arb,
Int32Arb,
Int64Arb,
NatArb,
Nat8Arb,
Nat16Arb,
Nat32Arb,
Nat64Arb,
BoolArb,
NullArb,
TextArb,
tie('Func').map((sample) => sample as CandidMeta<Func>),
PrincipalArb
),
Func: FuncArb(
tie('CandidType') as fc.Arbitrary<CandidMeta<CandidType>>
),
Vec: VecArb,
Opt: OptArb(tie('CandidType') as fc.Arbitrary<CandidMeta<CandidType>>),
Variant: BaseVariantArb(
tie('CandidType') as fc.Arbitrary<CandidMeta<CandidType>>
),
Tuple: TupleArb(
tie('CandidType') as fc.Arbitrary<CandidMeta<CandidType>>
),
Record: RecordArb(
tie('CandidType') as fc.Arbitrary<CandidMeta<CandidType>>
)
})
).CandidType;

// TODO: This needs to support service.
118 changes: 0 additions & 118 deletions property_tests/arbitraries/candid/constructed/opt_arb.ts

This file was deleted.

89 changes: 89 additions & 0 deletions property_tests/arbitraries/candid/constructed/opt_arb/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import fc from 'fast-check';
import { CandidType } from '../../candid_type_arb';
import { CandidMeta } from '../../candid_arb';
import { Opt } from './index';
import { UniqueIdentifierArb } from '../../../unique_identifier_arb';

type SomeOrNone = 'Some' | 'None';

export function OptArb(
candidTypeArb: fc.Arbitrary<CandidMeta<CandidType>>
): fc.Arbitrary<CandidMeta<Opt>> {
return fc
.tuple(
UniqueIdentifierArb('typeDeclaration'),
fc.constantFrom('Some', 'None') as fc.Arbitrary<SomeOrNone>,
candidTypeArb,
fc.boolean()
)
.map(([name, someOrNone, innerType, useTypeDeclaration]) => {
const candidType = useTypeDeclaration
? name
: generateCandidType(innerType);

const typeDeclaration = generateTypeDeclaration(
name,
innerType,
useTypeDeclaration
);

return {
src: {
candidType,
imports: generateImports(innerType),
typeDeclaration,
valueLiteral: generateValueLiteral(someOrNone, innerType)
},
agentArgumentValue: generateValue(someOrNone, innerType),
agentResponseValue: generateValue(someOrNone, innerType, true)
};
});
}

function generateTypeDeclaration(
name: string,
innerType: CandidMeta<CandidType>,
useTypeDeclaration: boolean
) {
if (useTypeDeclaration) {
return `${
innerType.src.typeDeclaration ?? ''
}\nconst ${name} = ${generateCandidType(innerType)}`;
}
return innerType.src.typeDeclaration;
}

function generateCandidType(innerType: CandidMeta<CandidType>): string {
return `Opt(${innerType.src.candidType})`;
}

function generateImports(innerType: CandidMeta<CandidType>): Set<string> {
return new Set([...innerType.src.imports, 'Opt', 'Some', 'None']);
}

function generateValue(
someOrNone: SomeOrNone,
innerType: CandidMeta<CandidType>,
useAgentResponseValue: boolean = false
): Opt {
if (someOrNone === 'Some') {
return [
useAgentResponseValue
? innerType.agentResponseValue
: innerType.agentArgumentValue
];
} else {
return [];
}
}

function generateValueLiteral(
someOrNone: SomeOrNone,
innerType: CandidMeta<CandidType>
): string {
if (someOrNone === 'Some') {
return `Some(${innerType.src.valueLiteral})`;
} else {
return `None`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { CandidType, CandidTypeArb } from '../../candid_type_arb';
import { OptArb as Base } from './base';

export type Opt = [CandidType] | never[];

export const OptArb = Base(CandidTypeArb);
Loading

0 comments on commit 69a0395

Please sign in to comment.