Skip to content

Commit

Permalink
add responses prop test
Browse files Browse the repository at this point in the history
  • Loading branch information
bdemann committed Nov 1, 2024
1 parent c788c8c commit 395936a
Show file tree
Hide file tree
Showing 11 changed files with 6,330 additions and 0 deletions.
4 changes: 4 additions & 0 deletions tests/property/ic_api/responses/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.azle
.dfx
dfx_generated
node_modules
23 changes: 23 additions & 0 deletions tests/property/ic_api/responses/dfx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"canisters": {
"caller": {
"type": "azle",
"main": "src/caller/index.ts",
"declarations": {
"output": "test/dfx_generated/caller",
"node_compatibility": true
},
"custom": {
"env": ["REJECTOR_PRINCIPAL"]
}
},
"rejector": {
"type": "azle",
"main": "src/rejector/index.ts",
"declarations": {
"output": "test/dfx_generated/rejector",
"node_compatibility": true
}
}
}
}
11 changes: 11 additions & 0 deletions tests/property/ic_api/responses/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testTimeout: 100_000_000,
transform: {
'^.+\\.ts$': ['ts-jest', { isolatedModules: true }],
'^.+\\.js$': 'ts-jest'
},
transformIgnorePatterns: ['/node_modules/(?!(azle)/)'] // Make sure azle is transformed
};
6,020 changes: 6,020 additions & 0 deletions tests/property/ic_api/responses/package-lock.json

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions tests/property/ic_api/responses/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"scripts": {
"pretest": "tsx test/pretest.ts",
"test": "jest"
},
"dependencies": {
"azle": "0.24.1"
},
"devDependencies": {
"@dfinity/agent": "^0.19.2",
"jest": "^29.7.0",
"ts-jest": "^29.1.4",
"tsx": "^4.15.7",
"typescript": "^5.2.2"
}
}
113 changes: 113 additions & 0 deletions tests/property/ic_api/responses/src/caller/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {
call,
IDL,
query,
reject,
rejectCode,
rejectMessage,
reply,
trap,
update
} from 'azle';

const RejectionCodeVariant = IDL.Variant({
NoError: IDL.Null,
SysFatal: IDL.Null,
SysTransient: IDL.Null,
DestinationInvalid: IDL.Null,
CanisterReject: IDL.Null,
CanisterError: IDL.Null,
Unknown: IDL.Null
});

type RejectionCodeVariant =
| {
NoError: null;
}
| {
SysFatal: null;
}
| {
SysTransient: null;
}
| {
DestinationInvalid: null;
}
| {
CanisterReject: null;
}
| {
CanisterError: null;
}
| {
Unknown: null;
};

export default class {
@query([IDL.Text], IDL.Text, { manual: true })
alwaysReplyQuery(input: string): void {
reply({ data: input, idlType: IDL.Text });
}

@query([IDL.Text], IDL.Text, { manual: true })
alwaysRejectQuery(message: string): void {
reject(message);
}

@query([IDL.Int], IDL.Int, { manual: true })
evenOrRejectQuery(number: bigint): void {
if (number % 2n === 0n) {
reply({ data: number, idlType: IDL.Int });
} else {
reject('Odd numbers are rejected');
}
}

@update([IDL.Text], IDL.Text)
async echoThroughReject(message: string): Promise<string> {
try {
await call(getRejectorPrincipal(), 'echoReject', {
paramIdlTypes: [IDL.Text],
returnIdlType: IDL.Text,
args: [message]
});
} catch (error) {
console.log('echoThroughReject caught an error', error);
return rejectMessage();
}
throw new Error('This should never be thrown');
}

@update([], RejectionCodeVariant)
async getRejectCodeCanisterError(): Promise<RejectionCodeVariant> {
try {
await call(getRejectorPrincipal(), 'throwError', {
returnIdlType: IDL.Text
});
} catch (error) {
console.log('getRejectCodeCanisterError caught an error', error);
return rejectCode();
}
throw new Error('This should never be thrown');
}

@update([], RejectionCodeVariant)
async getRejectCodeCanisterReject(): Promise<RejectionCodeVariant> {
try {
await call(getRejectorPrincipal(), 'rejectWithMessage', {
returnIdlType: IDL.Text
});
} catch (error) {
console.log('getRejectCodeCanisterReject caught an error', error);
return rejectCode();
}
throw new Error('This should never be thrown');
}
}

function getRejectorPrincipal(): string {
return (
process.env.REJECTOR_PRINCIPAL ??
trap('process.env.REJECTOR_PRINCIPAL is undefined')
);
}
18 changes: 18 additions & 0 deletions tests/property/ic_api/responses/src/rejector/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { IDL, query, reject } from 'azle';

export default class {
@query([IDL.Text], IDL.Text, { manual: true })
echoReject(message: string): void {
reject(message);
}

@query([], IDL.Text)
throwError(): string {
throw new Error('Thrown error');
}

@query([], IDL.Text, { manual: true })
rejectWithMessage(): void {
reject('Rejection with message');
}
}
29 changes: 29 additions & 0 deletions tests/property/ic_api/responses/test/pretest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { getCanisterId } from 'azle/dfx';
import { execSync } from 'child_process';

function pretest(): void {
execSync(`dfx canister uninstall-code caller || true`, {
stdio: 'inherit'
});

execSync(`dfx canister uninstall-code rejector || true`, {
stdio: 'inherit'
});

execSync(`dfx deploy rejector`, {
stdio: 'inherit'
});

execSync(
`REJECTOR_PRINCIPAL=${getCanisterId('rejector')} dfx deploy caller`,
{
stdio: 'inherit'
}
);

execSync(`dfx generate`, {
stdio: 'inherit'
});
}

pretest();
13 changes: 13 additions & 0 deletions tests/property/ic_api/responses/test/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getCanisterId } from 'azle/dfx';
import { runTests } from 'azle/test';

import { createActor } from './dfx_generated/caller';
import { getTests } from './tests';

const callerCanister = createActor(getCanisterId('caller'), {
agentOptions: {
host: 'http://127.0.0.1:8000'
}
});

runTests(getTests(callerCanister));
73 changes: 73 additions & 0 deletions tests/property/ic_api/responses/test/tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ActorSubclass } from '@dfinity/agent';
import { defaultPropTestParams, expect, it, Test } from 'azle/test';
import fc from 'fast-check';

// @ts-ignore this path may not exist when these tests are imported into other test projects
import { _SERVICE } from './dfx_generated/caller/caller.did';

export function getTests(callerCanister: ActorSubclass<_SERVICE>): Test {
return () => {
it('should always reply with the input in alwaysReplyQuery', async () => {
await fc.assert(
fc.asyncProperty(fc.string(), async (input) => {
const result = await callerCanister.alwaysReplyQuery(input);
expect(result).toBe(input);
}),
defaultPropTestParams
);
});

it('should always reject with the provided message in alwaysRejectQuery', async () => {
await fc.assert(
fc.asyncProperty(fc.string(), async (message) => {
await expect(
callerCanister.alwaysRejectQuery(message)
).rejects.toThrow(escapeCandidString(message));
}),
defaultPropTestParams
);
});

it('should reply with even numbers and reject odd numbers in evenOrRejectQuery', async () => {
await fc.assert(
fc.asyncProperty(fc.bigInt(), async (number) => {
if (number % 2n === 0n) {
const result =
await callerCanister.evenOrRejectQuery(number);
expect(result).toBe(number);
} else {
await expect(
callerCanister.evenOrRejectQuery(number)
).rejects.toThrow('Odd numbers are rejected');
}
}),
defaultPropTestParams
);
});

it('should echo the rejection message in echoThroughReject', async () => {
await fc.assert(
fc.asyncProperty(fc.string(), async (message) => {
const result =
await callerCanister.echoThroughReject(message);
expect(result).toBe(message);
}),
defaultPropTestParams
);
});

it('should return CanisterError for getRejectCodeCanisterError', async () => {
const result = await callerCanister.getRejectCodeCanisterError();
expect(result).toEqual({ CanisterError: null });
});

it('should return CanisterReject for getRejectCodeCanisterReject', async () => {
const result = await callerCanister.getRejectCodeCanisterReject();
expect(result).toEqual({ CanisterReject: null });
});
};
}

function escapeCandidString(data: string): string {
return data.replace(/[\\"']/g, '\\$&');
}
10 changes: 10 additions & 0 deletions tests/property/ic_api/responses/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"strict": true,
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"allowJs": true,
"outDir": "HACK_BECAUSE_OF_ALLOW_JS"
}
}

0 comments on commit 395936a

Please sign in to comment.