From 68b1ff651ef3d507ca6c4fd8ecb3c43c34e0bffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Fern=C3=A1ndez?= Date: Thu, 10 Mar 2022 15:27:14 -0500 Subject: [PATCH] feat: add tests lib --- README.md | 56 +++++++++++++ lib/tests.ts | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 276 insertions(+) create mode 100644 lib/tests.ts diff --git a/README.md b/README.md index c525ea3..f7567a7 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,62 @@ module.exports = { ## Documentation ๐Ÿ“„ +### Tests + +This library aims to reduce the verbosity of [matschtick](https://github.com/LimeChain/matchstick) providing many useful functions to wrap repetitive tasks suchs as create events, mock calls an assert some TypedValues. + +#### Logs + +This is a simple wrapper to add an standard way to create custom logs including the parent test name. + +#### Asserts - Assert Many: +Avoids the repetition for "assert.fieldEquals" by providing a typedMap of params. + +Exmaple: + +`assert.fieldEquals("EntityName", "entityId", "propName", "propValue"); +assert.fieldEquals("EntityName", "entityId", "anotherProp", "anotherValue");` + +Can be replaced with: + +`let params = new TypedMap() +params.set("propName", propVal) +params.set("anotherProp", anotherVal) +asserts.assertMany( + "EntityName", entityId, params +)` + +The entity name and id will be typed once. + +#### Asserts - Assert Equal: + +An standar way to assert type values while simplifing the process of conversion between graph-ts types and ethereum.value and centralizing the logs allowing to know on each assertion the values being compared. + +It also provides support for standard graph-ts type suchs as Address, Bytes, BigInt, etc. + + +#### events - getNewEvent: + +Simplifies the process of mocking events taking care of mockEvent instanciation and params pushing +. Create a new event just by passing an array of ethereum.EventParam + +#### calls - getNewCall: + +Simplifies the process of mocking calls taking care of mockCall instanciation and params pushing +. Create a new call just by passing an array of ethereum.EventParam + +#### contractCalls - mockFunction + +Simplifies the process of mocking contract calls +exmaple: +`tests.helpers.contractCalls.mockFunction( + contractAddress, + "isInitialized", + "isInitialized():(bool)", + [], + [tests.helpers.ethereumValue.getFromBoolean(true)] + )` + ### Constants
ADDRESS_ZERO
diff --git a/lib/tests.ts b/lib/tests.ts new file mode 100644 index 0000000..8325b0e --- /dev/null +++ b/lib/tests.ts @@ -0,0 +1,220 @@ +import { Address, Bytes, BigInt, ethereum, TypedMap } from "@graphprotocol/graph-ts" +import { newMockEvent, newMockCall, assert, log, createMockedFunction } from "matchstick-as" + +export namespace tests { + + export namespace logs { + export namespace global { + export function started(funcName: string, id: string): void { + log.info( + "\n_____\n\nfunc={} :: testing entity w/ id={}\n_____\n", + [funcName, id] + ) + } + + export function success(funcName: string, id: string): void { + log.success( + "\nfunc={} :: succesfully tested w/ id={}\n", + [funcName, id] + ) + } + + export function error(funcName: string, detail: string): void { + log.error( + "\nfunc={} :: ={}\n", + [funcName, detail] + ) + } + + export function warn(funcName: string, detail: string): void { + log.warning( + "\nfunc={} :: ={}\n", + [funcName, detail] + ) + } + } + + export namespace internal { + export function testing( + funcName: string, expected: string, actual: string + ): void { + log.debug( + "\n ยท func={} ::\ntesting expected={}\nactual={}\n", + [funcName, expected, actual] + ) + } + } + } + + export namespace helpers { + + export namespace asserts { + + export function assertMany( + entityName: string, + entityId: string, + fields: TypedMap + ): void { + for (let index = 0; index < fields.entries.length; index++) { + let entry = fields.entries[index]; + assert.fieldEquals(entityName, entityId, entry.key, entry.value) + } + } + + export function assertEqual( + expected: T, actual: T, pipe: (e: T) => ethereum.Value + ): void { + assert.equals( + pipe(expected), + pipe(actual) + ) + } + + export function assertBytes( + expected: Bytes, actual: Bytes + ): void { + logs.internal.testing( + "assertBytes", expected.toHexString(), actual.toHexString() + ) + assertEqual( + expected, + actual, + ethereum.Value.fromBytes + ) + } + + export function assertAddress( + expected: Address, actual: Address + ): void { + logs.internal.testing( + "assertAddress", expected.toHexString(), actual.toHexString() + ) + assertEqual
( + expected, + actual, + ethereum.Value.fromAddress + ) + } + + export function assertBigInt( + expected: BigInt, actual: BigInt + ): void { + logs.internal.testing( + "assertBigInt", expected.toString(), actual.toString() + ) + assertEqual( + expected, + actual, + ethereum.Value.fromUnsignedBigInt + ) + } + + export function assertString( + expected: string, actual: string + ): void { + logs.internal.testing( + "assertString", expected, actual + ) + assertEqual( + expected, + actual, + ethereum.Value.fromString + ) + } + + export function assertStringArray( + expected: string[], actual: string[] + ): void { + logs.internal.testing( + "assertStringArray", expected.toString(), actual.toString() + ) + assertEqual( + expected, + actual, + ethereum.Value.fromStringArray + ) + } + + } export namespace events { + export function getNewEvent(params: ethereum.EventParam[]): ethereum.Event { + let event = newMockEvent() + event.parameters = new Array() + for (let index = 0; index < params.length; index++) { + event.parameters.push(params[index]) + } + return event + } + } + + export namespace calls { + export function getNewCall(inputs: ethereum.EventParam[]): ethereum.Call { + let call = newMockCall() + call.inputValues = new Array() + for (let index = 0; index < inputs.length; index++) { + call.inputValues.push(inputs[index]) + } + return call + } + } + + export namespace contractCalls { + export function mockFunction( + contractAddress: Address, + functionName: string, + functionSignature: string, + args: ethereum.Value[], + returnValues: ethereum.Value[] + ): void { + createMockedFunction(contractAddress, functionName, functionSignature) + .withArgs(args) + .returns(returnValues) + } + } + export namespace params { + + function getNewParam(name: string, value: ethereum.Value): ethereum.EventParam { + return new ethereum.EventParam(name, value) + } + + export function getI32(name: string, value: i32): ethereum.EventParam { + return getNewParam(name, ethereum.Value.fromI32(value)) + } + + export function getString(name: string, value: string): ethereum.EventParam { + return getNewParam(name, ethereum.Value.fromString(value)) + } + + export function getBytes(name: string, value: Bytes): ethereum.EventParam { + return getNewParam(name, ethereum.Value.fromBytes(value)) + } + + export function getBoolean(name: string, value: boolean): ethereum.EventParam { + return getNewParam(name, ethereumValue.getFromBoolean(value)) + } + + export function getBigInt(name: string, value: BigInt): ethereum.EventParam { + return getNewParam(name, ethereum.Value.fromUnsignedBigInt(value)) + } + + export function getAddress(name: string, value: Address): ethereum.EventParam { + return getNewParam(name, ethereum.Value.fromAddress(value)) + } + + } + + export namespace ethereumValue { + export function getFromBoolean(value: boolean): ethereum.Value { + return ethereum.Value.fromBoolean(value) + } + + export function getFromI32(value: i32): ethereum.Value { + return ethereum.Value.fromI32(value) + } + + export function getFromBigInt(value: BigInt): ethereum.Value { + return ethereum.Value.fromUnsignedBigInt(value) + } + + } + } +} \ No newline at end of file