LimeChain / matchstick

🔥 Unit testing framework for Subgraph development on The Graph protocol. ⚙️
MIT License
210 stars 18 forks source link

Decouple the Unit Tests, Gain cool features #187

Closed VIVelev closed 3 years ago

VIVelev commented 3 years ago

TLDR;

Change the syntax of writing unit tests from:

export function runtTests(): void {
    test("Some fancy unit test", () => {
        // ...
    }
    test("Just my other fancy unit test", () => {
        // ...
    }
}

To:

export function someFancyTest(): void {
    // ...
}

export function anotherFancyTest(): void {
    // ...
}

In order to decouple the tests and, thus, gain some cool features like:

More details

The Problem

As of the time of this writing, Matchstick uses the function runTests in order to, well, run the tests. However, since all the test blocks are written in the body of a single exported function, there is no way to gain access to the distinct tests in the Rust environment as wasmtime::Func entities. In other word, we can't manipulate the individual tests. This introduces strong coupling which makes it hard to implement the features mentioned above.

The Solution

By exporting each individual unit test from the AssemblyScript file, we can gain access to each test as wasmtime::Func in Rust, allowing us to manipulate this block of code however we want.

Drawbacks

The only drawback one can argue about is the change of syntax. Of course, it is up to the subgraph devs to express their opinion on this issue.

Tried and failed approaches

Attempts have been made to keep the syntax while still decouple the unit tests, however there are some challenges. In essence, in order for this to work you need to have a way to pass functions (executable code as a pointer) from AssemblyScript to Rust.

Two ways to do this: 1) Obtain a function type from AssemblyScript and simply pass it as a pointer to Rust through the WebAssembly Module, just like a regular variable (i32, bool, etc.). 2) Make use of WebAssembly.Table.

Unfortunately, neither way is supported by AssemblyScript as of today.

schmidsi commented 3 years ago

This looks good to me. Actually I would not try too hard to stay close to the Javascript ecosystem standards as AssemblyScript is NOT TypeScript is NOT JavaScript. This is an important lesson that a fresh subgraph developer needs to learn anyways.

VIVelev commented 3 years ago

By the way, I found a way to decouple the unit tests and keep the current syntax with the test function, and also remove the runTests function, so it becomes just:

test("Some fancy unit test", () => {
    // ...
}

test("Just my other fancy unit test", () => {
    // ...
}

Which seems much more clean to me.

I am making use of WebAssembly.Table, so nothing hacky. Turns out AssemblyScript actually supports it, just in their own kind of way.

So, we can keep the syntax! Unless you liked the new one better, hah. :)