Skip to content

Commit

Permalink
Add PostUpgradeArb
Browse files Browse the repository at this point in the history
  • Loading branch information
dansteren authored and bdemann committed Jan 17, 2024
1 parent dc3926c commit 9c9191c
Show file tree
Hide file tree
Showing 25 changed files with 1,483 additions and 25 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ jobs:
"property_tests/tests/nat64",
"property_tests/tests/null",
"property_tests/tests/opt",
"property_tests/tests/post_upgrade_method",
"property_tests/tests/principal",
"property_tests/tests/query_methods",
"property_tests/tests/record",
Expand Down
39 changes: 24 additions & 15 deletions property_tests/arbitraries/canister_arb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { QueryMethod } from './canister_methods/query_method_arb';
import { Test } from '../../test';
import { UpdateMethod } from './canister_methods/update_method_arb';
import { InitMethod } from './canister_methods/init_method_arb';
import { PostUpgradeMethod } from './canister_methods/post_upgrade_arb';
import { CorrespondingJSType } from './candid/corresponding_js_type';
import { TextClass, FloatClass } from '@dfinity/candid/lib/cjs/idl';

Expand All @@ -28,12 +29,25 @@ export type Canister = {
tests: Test[][];
};

export type CanisterMethod<
ParamAgentArgumentValue extends CorrespondingJSType,
ParamAgentResponseValue
> =
| QueryMethod
| UpdateMethod
| InitMethod<ParamAgentArgumentValue, ParamAgentResponseValue>
| PostUpgradeMethod<ParamAgentArgumentValue, ParamAgentResponseValue>;

export type CanisterConfig<
ParamAgentArgumentValue extends CorrespondingJSType = undefined,
ParamAgentResponseValue = undefined
> = {
globalDeclarations?: string[];
initMethod?: InitMethod<ParamAgentArgumentValue, ParamAgentResponseValue>;
postUpgradeMethod?: PostUpgradeMethod<
ParamAgentArgumentValue,
ParamAgentResponseValue
>;
queryMethods?: QueryMethod[];
updateMethods?: UpdateMethod[];
};
Expand All @@ -48,12 +62,12 @@ export function CanisterArb<
>
) {
return configArb.map((config): Canister => {
const canisterMethods: (
| QueryMethod
| UpdateMethod
| InitMethod<ParamAgentArgumentValue, ParamAgentResponseValue>
)[] = [
const canisterMethods: CanisterMethod<
ParamAgentArgumentValue,
ParamAgentResponseValue
>[] = [
...(config.initMethod ? [config.initMethod] : []),
...(config.postUpgradeMethod ? [config.postUpgradeMethod] : []),
...(config.queryMethods ?? []),
...(config.updateMethods ?? [])
];
Expand Down Expand Up @@ -107,14 +121,10 @@ function generateSourceCode(
canisterMethods: (UpdateMethod | QueryMethod)[]
) {
const imports = [
...new Set(
canisterMethods.reduce(
(acc, method) => {
return [...acc, ...method.imports];
},
['Canister', 'query', 'update']
)
)
...new Set([
'Canister',
...canisterMethods.flatMap((method) => [...method.imports])
])
]
.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))
.join();
Expand All @@ -124,8 +134,7 @@ function generateSourceCode(
);

const declarations = [
...globalDeclarations,
...declarationsFromCanisterMethods
...new Set([...globalDeclarations, ...declarationsFromCanisterMethods])
].join('\n');

const sourceCodes = canisterMethods.map((method) => method.sourceCode);
Expand Down
141 changes: 141 additions & 0 deletions property_tests/arbitraries/canister_methods/post_upgrade_arb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import fc from 'fast-check';

import { CandidValueAndMeta } from '../candid/candid_value_and_meta_arb';
import { CorrespondingJSType } from '../candid/corresponding_js_type';
import { UniqueIdentifierArb } from '../unique_identifier_arb';
import { Named } from '../..';
import {
BodyGenerator,
TestsGenerator,
CallbackLocation,
isDefined,
generateCallback
} from '.';
import { Test } from '../../../test';
import { VoidArb } from '../candid/primitive/void';

export type PostUpgradeMethod<
ParamAgentArgumentValue extends CorrespondingJSType,
ParamAgentResponseValue
> = {
imports: Set<string>;
globalDeclarations: string[];
params: Named<
CandidValueAndMeta<ParamAgentArgumentValue, ParamAgentResponseValue>
>[];
sourceCode: string;
tests: Test[][];
};

export function PostUpgradeMethodArb<
ParamAgentArgumentValue extends CorrespondingJSType,
ParamAgentResponseValue
>(
paramTypeArrayArb: fc.Arbitrary<
CandidValueAndMeta<ParamAgentArgumentValue, ParamAgentResponseValue>[]
>,
constraints: {
generateBody: BodyGenerator<
ParamAgentArgumentValue,
ParamAgentResponseValue
>;
generateTests: TestsGenerator<
ParamAgentArgumentValue,
ParamAgentResponseValue
>;
callbackLocation?: CallbackLocation;
}
) {
return fc
.tuple(
UniqueIdentifierArb('canisterMethod'),
paramTypeArrayArb,
VoidArb(),
fc.constantFrom(
'INLINE',
'STANDALONE'
) as fc.Arbitrary<CallbackLocation>,
UniqueIdentifierArb('typeDeclaration')
// TODO: This unique id would be better named globalScope or something
// But needs to match the same scope as typeDeclarations so I'm using
// that for now.
)
.map(
([
functionName,
paramTypes,
returnType,
defaultCallbackLocation,
callbackName
]) => {
// TODO: Add a return type to this map callback of type PostUpgradeMethod<Something, Something>

const callbackLocation =
constraints.callbackLocation ?? defaultCallbackLocation;

const imports = new Set([
'postUpgrade',
...paramTypes.flatMap((param) => [...param.src.imports])
]);

const namedParams = paramTypes.map(
<T>(param: T, index: number): Named<T> => ({
name: `param${index}`,
el: param
})
);

const callback = generateCallback(
namedParams,
returnType,
constraints.generateBody,
callbackLocation,
callbackName
);

const variableAliasDeclarations = paramTypes
.flatMap((param) => param.src.variableAliasDeclarations)
.filter(isDefined);

const globalDeclarations =
callbackLocation === 'STANDALONE'
? [...variableAliasDeclarations, callback]
: variableAliasDeclarations;

const sourceCode = generateSourceCode(
functionName,
paramTypes,
callbackLocation === 'STANDALONE' ? callbackName : callback
);

const tests = constraints.generateTests(
functionName,
namedParams,
returnType
);

return {
imports,
globalDeclarations,
params: namedParams,
sourceCode,
tests
};
}
);
}

function generateSourceCode<
ParamType extends CorrespondingJSType,
ParamAgentType
>(
functionName: string,
paramTypes: CandidValueAndMeta<ParamType, ParamAgentType>[],
callback: string
): string {
const paramCandidTypeObjects = paramTypes
.map((param) => param.src.candidTypeObject)
.join(', ');

return `${functionName}: postUpgrade([${paramCandidTypeObjects}], ${callback})`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export function QueryMethodArb<
constraints.callbackLocation ?? defaultCallbackLocation;

const imports = new Set([
'query',
...paramTypes.flatMap((param) => [...param.src.imports]),
...returnType.src.imports
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export function UpdateMethodArb<
constraints.callbackLocation ?? defaultCallbackLocation;

const imports = new Set([
'update',
...paramTypes.flatMap((param) => [...param.src.imports]),
...returnType.src.imports
]);
Expand Down
2 changes: 1 addition & 1 deletion property_tests/tests/init_method/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ function generateGetInitValuesCanisterMethod(
globalInitVariableNames: string[]
): QueryMethod {
return {
imports: new Set(['Tuple', 'bool']),
imports: new Set(['bool', 'query', 'Tuple']),
globalDeclarations: [],
sourceCode: /*TS*/ `getInitValues: query(
[],
Expand Down
16 changes: 16 additions & 0 deletions property_tests/tests/post_upgrade_method/dfx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"canisters": {
"canister": {
"type": "custom",
"main": "src/index.ts",
"candid": "src/index.did",
"build": "npx azle canister",
"wasm": ".azle/canister/canister.wasm",
"gzip": true,
"declarations": {
"output": "test/dfx_generated/canister",
"node_compatibility": true
}
}
}
}
Loading

0 comments on commit 9c9191c

Please sign in to comment.