@0x:contracts-integrations
Added better documentation to FunctionAssertions
This commit is contained in:
parent
6402d29dd4
commit
205c895d75
@ -18,9 +18,26 @@ export interface Result {
|
||||
receipt?: TransactionReceiptWithDecodedLogs;
|
||||
}
|
||||
|
||||
export interface Condition {
|
||||
before?: (...args: any[]) => Promise<any>;
|
||||
after?: (beforeInfo: any, result: Result, ...args: any[]) => Promise<any>;
|
||||
/**
|
||||
* This interface represents a condition that can be placed on a contract function.
|
||||
* This can be used to represent the pre- and post-conditions of a "Hoare Triple" on a
|
||||
* given contract function. The "Hoare Triple" is a way to represent the way that a
|
||||
* function changes state.
|
||||
* @param before A function that will be run before a call to the contract wrapper
|
||||
* function. Ideally, this will be a "precondition."
|
||||
* @param after A function that will be run after a call to the contract wrapper
|
||||
* function.
|
||||
*/
|
||||
export interface Condition<TBefore extends any> {
|
||||
before?: (...args: any[]) => Promise<TBefore>;
|
||||
after?: (beforeInfo: TBefore, result: Result, ...args: any[]) => Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export interface Assertion {
|
||||
runAsync: (...args: any[]) => Promise<any>;
|
||||
}
|
||||
|
||||
export interface RunResult {
|
||||
@ -28,18 +45,16 @@ export interface RunResult {
|
||||
afterInfo: any;
|
||||
}
|
||||
|
||||
export interface Assertion {
|
||||
runAsync: (...args: any[]) => Promise<any>;
|
||||
}
|
||||
|
||||
export class FunctionAssertion implements Assertion {
|
||||
// A before and an after assertion that will be called around the wrapper function.
|
||||
public condition: Condition;
|
||||
export class FunctionAssertion<TBefore extends any> implements Assertion {
|
||||
// A condition that will be applied to `wrapperFunction`.
|
||||
// Note: `TBefore | undefined` is used because the `before` and `after` functions
|
||||
// are optional in `Condition`.
|
||||
public condition: Condition<TBefore | undefined>;
|
||||
|
||||
// The wrapper function that will be wrapped in assertions.
|
||||
public wrapperFunction: ContractWrapperFunction;
|
||||
|
||||
constructor(wrapperFunction: ContractWrapperFunction, condition: Condition) {
|
||||
constructor(wrapperFunction: ContractWrapperFunction, condition: Condition<TBefore | undefined>) {
|
||||
this.condition = condition;
|
||||
this.wrapperFunction = wrapperFunction;
|
||||
}
|
||||
@ -82,63 +97,76 @@ export class FunctionAssertion implements Assertion {
|
||||
}
|
||||
}
|
||||
|
||||
export type InputGenerator = () => Promise<any[]>;
|
||||
|
||||
export interface AssertionGenerator {
|
||||
assertion: Assertion;
|
||||
generator: InputGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This can be treated like a normal `FunctionAssertion`.
|
||||
* A class that can run a set of function assertions in a sequence. This will terminate
|
||||
* after every assertion in the sequence has been executed.
|
||||
*/
|
||||
export class FunctionAssertionSequence {
|
||||
public readonly assertions: Assertion[] = [];
|
||||
public readonly inputGenerators: Array<() => any[]> = [];
|
||||
/**
|
||||
* @constructor Initializes a readonly list of AssertionGenerator objects.
|
||||
* @param assertionGenerators A list of objects that contain (1) assertions
|
||||
* and (2) functions that generate the arguments to "run" the assertions.
|
||||
*/
|
||||
constructor(protected readonly assertionGenerators: AssertionGenerator[]) {}
|
||||
|
||||
/**
|
||||
* Set up a set of function assertions equipped with generator functions.
|
||||
* A number can be specified for each assertion that will detail the frequency
|
||||
* that this assertion will be called relative to the other assertions in the
|
||||
* set.
|
||||
* Execute this class's function assertions in the order that they were initialized.
|
||||
* The assertions corresponding input generators will provide the arguments when the
|
||||
* assertion is executed.
|
||||
*/
|
||||
constructor(assertionGenerators: [Assertion, (() => any[])][]) {
|
||||
for (const assertionGenerator of assertionGenerators) {
|
||||
this.assertions.push(assertionGenerator[0]);
|
||||
this.inputGenerators.push(assertionGenerator[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the functions in this assertion set in order.
|
||||
*/
|
||||
public async runAsync(environment: BlockchainTestsEnvironment): Promise<void> {
|
||||
for (let i = 0; i < this.assertions.length; i++) {
|
||||
await this.assertions[i].runAsync(...this.inputGenerators[i]());
|
||||
public async runAsync(): Promise<void> {
|
||||
for (let i = 0; i < this.assertionGenerators.length; i++) {
|
||||
const args = await this.assertionGenerators[i].generator();
|
||||
await this.assertionGenerators[i].assertion.runAsync(...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface WeightedAssertionGenerator extends AssertionGenerator {
|
||||
weight?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that can execute a set of function assertions at random continuously.
|
||||
* This will not terminate unless the process that called `runAsync` terminates.
|
||||
*/
|
||||
export class ContinuousFunctionAssertionSet {
|
||||
public readonly assertions: Assertion[] = [];
|
||||
public readonly inputGenerators: Array<() => any[]> = [];
|
||||
protected readonly assertionGenerators: AssertionGenerator[] = [];
|
||||
|
||||
/**
|
||||
* Set up a set of function assertions equipped with generator functions.
|
||||
* A number can be specified for each assertion that will detail the frequency
|
||||
* that this assertion will be called relative to the other assertions in the
|
||||
* set.
|
||||
* @constructor Initializes assertion generators so that assertion's can be
|
||||
* selected using a uniform distribution and the weights of the
|
||||
* assertions hold.
|
||||
* @param weightedAssertionGenerators An array of assertion generators that
|
||||
* have specified "weights." These "weights" specify the relative frequency
|
||||
* that assertions should be executed when the set is run.
|
||||
*/
|
||||
constructor(assertionGenerators: [Assertion, (() => any[]), number?][]) {
|
||||
for (const assertionGenerator of assertionGenerators) {
|
||||
const frequency = assertionGenerator[2] || 1;
|
||||
for (let i = 0; i < frequency; i++) {
|
||||
this.assertions.push(assertionGenerator[0]);
|
||||
this.inputGenerators.push(assertionGenerator[1]);
|
||||
}
|
||||
constructor(weightedAssertionGenerators: WeightedAssertionGenerator[]) {
|
||||
for (const { assertion, generator, weight } of weightedAssertionGenerators) {
|
||||
const weightedAssertions: AssertionGenerator[] = [];
|
||||
_.fill(weightedAssertions, { assertion, generator }, 0, weight || 1);
|
||||
this.assertionGenerators = this.assertionGenerators.concat(weightedAssertions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the functions in this assertion set continuously.
|
||||
* Execute this class's function assertions continuously and randomly using the weights
|
||||
* of the assertions to bias the assertion selection. The assertions corresponding
|
||||
* input generators will provide the arguments when the
|
||||
* assertion is executed.
|
||||
*/
|
||||
public async runAsync(environment: BlockchainTestsEnvironment): Promise<void> {
|
||||
public async runAsync(): Promise<void> {
|
||||
for (;;) {
|
||||
const randomIdx = Math.round(Math.random() * (this.assertions.length - 1));
|
||||
await this.assertions[randomIdx].runAsync(...this.inputGenerators[randomIdx]());
|
||||
const randomIdx = Math.round(Math.random() * (this.assertionGenerators.length - 1));
|
||||
const args = await this.assertionGenerators[randomIdx].generator();
|
||||
await this.assertionGenerators[randomIdx].assertion.runAsync(...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user