Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

test: Add tests for signatureHelp #253

Merged
merged 10 commits into from
Feb 17, 2025
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ yarn-error.log

# eslint
.eslintcache

# coverage
coverage/
65 changes: 65 additions & 0 deletions server/src/e2e/suite/signatureHelp.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import * as vscode from "vscode"
import * as assert from "node:assert"
import {BaseTestSuite} from "./BaseTestSuite"
import type {TestCase} from "./TestParser"

suite("Signatures Test Suite", () => {
const testSuite = new (class extends BaseTestSuite {
public async getSignature(input: string): Promise<vscode.SignatureHelp> {
const textWithoutCaret = input.replace("<caret>", "")
await this.replaceDocumentText(textWithoutCaret)

const caretIndex = input.indexOf("<caret>")
if (caretIndex === -1) {
throw new Error("No <caret> marker found in input")
}

const position = this.document.positionAt(caretIndex)
this.editor.selection = new vscode.Selection(position, position)
this.editor.revealRange(new vscode.Range(position, position))

return vscode.commands.executeCommand<vscode.SignatureHelp>(
"vscode.executeSignatureHelpProvider",
this.document.uri,
position,
)
}

protected runTest(testFile: string, testCase: TestCase): void {
test(`Signature: ${testCase.name}`, async () => {
const signature = await this.getSignature(testCase.input)
console.log("signature")
console.log(JSON.stringify(signature))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's remove debug statements

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, of course.

It was just to see why tests were failing CI on Windows. Already removed because the tests are fixed.

const items = signature.signatures.map(item => {
const label = item.label
if (item.activeParameter !== undefined) {
const activeParamLabel = item.parameters[item.activeParameter]?.label ?? ""
return `${activeParamLabel.toString()}\n${label}`
}
return ""
})
const expected = testCase.expected.split("\n").filter((line: string) => line !== "")
if (BaseTestSuite.UPDATE_SNAPSHOTS) {
this.updates.push({
filePath: testFile,
testName: testCase.name,
actual: items.join("\n"),
})
} else {
assert.deepStrictEqual(items.sort(), expected.sort())
}
})
}
})()

suiteSetup(async function () {
this.timeout(10_000)
await testSuite.suiteSetup()
})

setup(async () => testSuite.setup())
teardown(async () => testSuite.teardown())
suiteTeardown(() => testSuite.suiteTeardown())

testSuite.runTestsFromDirectory("signatures")
})
153 changes: 153 additions & 0 deletions server/src/e2e/suite/testcases/signatures/contract.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
========================================================================
Basic Function with Multiple Parameters
========================================================================
primitive Int;
primitive String;

struct User {
name: String;
age: Int;
}

contract Foo {
fun baz(user: User, action: String, value: Int) {
// ...
}

init() {
self.baz(user, "update", <caret>);
}
}
------------------------------------------------------------------------
value: Int
fun baz(user: User, action: String, value: Int)

========================================================================
Function Overloading
========================================================================
primitive Int;
primitive String;

contract Foo {
fun add(a: Int, b: Int): Int {
return a + b;
}

fun add(a: String, b: String): String {
return a + b;
}

init() {
self.add("hello", <caret>);
}
}
------------------------------------------------------------------------
b: Int
fun add(a: Int, b: Int)

========================================================================
Nested Function Calls
========================================================================
primitive Int;
primitive String;

contract Foo {
fun multiply(a: Int, b: Int): Int {
return a * b;
}

fun calculate(x: Int, y: Int, z: Int): Int {
return x + self.multiply(y, z);
}

init() {
self.calculate(10, <caret>);
}
}
------------------------------------------------------------------------
y: Int
fun calculate(x: Int, y: Int, z: Int)

========================================================================
Nested Function Calls - 2
========================================================================
primitive Int;

contract Foo {
fun double(x: Int): Int {
return x * 2;
}

fun triple(x: Int): Int {
return x * 3;
}

init() {
self.double(self.triple(<caret>));
}
}
------------------------------------------------------------------------
x: Int
fun triple(x: Int)

========================================================================
Promt first arg while second is filled
========================================================================
primitive Int;

contract Foo {
fun add(a: Int, b: Int): Int {
return a + b;
}

init() {
self.add(<caret>, 2);
}
}
------------------------------------------------------------------------
a: Int
fun add(a: Int, b: Int)

========================================================================
Global function with Map
========================================================================
primitive Int;
primitive String;

struct Key {
id: Int;
name: String;
}

get fun globalFunc(map: Map<Key, Int>) {
// ...
}

contract Foo {
init() {
let key = Key { id: 1, name: "Test" };
let map = emptyMap();
globalFunc(<caret>)
}
}
------------------------------------------------------------------------
map: Map
fun globalFunc(map: Map)

========================================================================
Global function with String
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But function takes Int 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added also for Int 🤖

========================================================================
primitive Int;

fun globalFunc(input: Int): Int {
return input;
}

contract A {
init() {
globalFunc(<caret>)
}
}
------------------------------------------------------------------------
input: Int
fun globalFunc(input: Int)
59 changes: 59 additions & 0 deletions server/src/e2e/suite/testcases/signatures/initOf.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
========================================================================
initOf with one argument
========================================================================
primitive Int;

contract ContractA {
init(a: Int) {

}
}

contract ContractB {
init() {
initOf ContractA(<caret>)
}
}
------------------------------------------------------------------------
a: Int
init(a: Int)

========================================================================
initOf with many arguments
========================================================================
primitive Int;

contract ContractA {
init(a: Int, b: Int, c: Int) {
// ...
}
}

contract ContractB {
init() {
initOf ContractA(<caret>)
}
}
------------------------------------------------------------------------
a: Int
init(a: Int, b: Int, c: Int)

========================================================================
initOf with many arguments (first is filled)
========================================================================
primitive Int;

contract ContractA {
init(a: Int, b: Int, c: Int) {
// ...
}
}

contract ContractB {
init() {
initOf ContractA(42, <caret>)
}
}
------------------------------------------------------------------------
b: Int
init(a: Int, b: Int, c: Int)
81 changes: 81 additions & 0 deletions server/src/e2e/suite/testcases/signatures/map.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
========================================================================
Set Map (Key)
========================================================================
primitive Int;
extends mutates fun set(self: map<K, V>, key: K, val: V);

contract A {
init() {
let fizz: map<Int, Int> = emptyMap();

fizz.set(<caret>)
}
}
------------------------------------------------------------------------
key: K
fun set(self: map<K, V>, key: K, val: V)

========================================================================
Set Map (Value)
========================================================================
primitive Int;
extends mutates fun set(self: map<K, V>, key: K, val: V);

contract A {
init() {
let fizz: map<Int, Int> = emptyMap();

fizz.set(42, <caret>)
}
}
------------------------------------------------------------------------
val: V
fun set(self: map<K, V>, key: K, val: V)

========================================================================
Get value from Map
========================================================================
primitive Int;
extends fun get(self: map<K, V>, key: K): V?;
contract A {
init() {
let fizz: map<Int, Int> = emptyMap();

fizz.get(<caret>);
}
}
------------------------------------------------------------------------
key: K
fun get(self: map<K, V>, key: K)

========================================================================
Replace value map by key (caret on key)
========================================================================
primitive Int;
extends mutates fun replace(self: map<K, V>, key: K, val: V): Bool;
contract A {
init() {
let fizz: map<Int, Int> = emptyMap();

fizz.replace(<caret>)
}
}
------------------------------------------------------------------------
key: K
fun replace(self: map<K, V>, key: K, val: V)

========================================================================
Replace value map by key (caret on value)
========================================================================
primitive Int;
extends mutates fun replace(self: map<K, V>, key: K, val: V): Bool;
contract A {
init() {
let fizz: map<Int, Int> = emptyMap();

fizz.replace(42, <caret>)
}
}
------------------------------------------------------------------------
val: V
fun replace(self: map<K, V>, key: K, val: V)
Loading
Loading