aboutsummaryrefslogtreecommitdiff
path: root/tests/drivers/hover_features_test.js
diff options
context:
space:
mode:
Diffstat (limited to 'tests/drivers/hover_features_test.js')
-rw-r--r--tests/drivers/hover_features_test.js86
1 files changed, 66 insertions, 20 deletions
diff --git a/tests/drivers/hover_features_test.js b/tests/drivers/hover_features_test.js
index 895e923..d6e1226 100644
--- a/tests/drivers/hover_features_test.js
+++ b/tests/drivers/hover_features_test.js
@@ -38,15 +38,15 @@ for (const type of ['word', 'int', 'char', 'bool', 'float', 'f64', 'f32', 'byte'
assert.ok(value && value.startsWith('```zc\n') && value.includes('\n\n'), type + ' has formatted built-in documentation');
}
assert.match(hover('void noop() {}\nfn main() { return 0; }\n', 'void'), /no meaningful result/);
-const array = 'fn main() {\n [4]u8 values;\n return values[0];\n}\n';
+const array = 'fn main() {\n u8[4] values;\n return values[0];\n}\n';
assert.match(hover(array, '[4]'), /fixed length of 4/);
-assert.match(hover(array, 'values', 1), /type \[4\]u8/);
+assert.match(hover(array, 'values', 1), /\(u8\[4\]\) let values/);
const struct = 'struct pair { int left; float right; };\nfn main() { pair value; return value.left; }\n';
assert.match(hover(struct, 'pair', 1), /int left;[\s\S]*float right;/);
-assert.match(hover(struct, 'value', 1), /type pair/);
+assert.match(hover(struct, 'value', 1), /\(pair\) let value/);
const fields = 'struct pair { int /* left field */ left, /* right field */ right; };\nfn main() { pair p; return p.left + p.right; }\n';
-assert.match(hover(fields, 'left +'), /field; type int[\s\S]*left field/);
-assert.match(hover(fields, 'right;'), /field; type int[\s\S]*right field/);
+assert.match(hover(fields, 'left +'), /\(int\) let left \/\/ field;[\s\S]*left field/);
+assert.match(hover(fields, 'right;'), /\(int\) let right \/\/ field;[\s\S]*right field/);
const empty = '/**/ int helper() { return 1; }\nfn main() { return helper(); }\n';
assert.match(hover(empty, 'helper();'), /int helper\(\)/);
const variableDocs = 'fn main() {\n int /* first variable */ first = 1, /* second variable */ second = 2;\n return first + second;\n}\n';
@@ -63,23 +63,69 @@ const functionDocs = '/**\n * adds **one** to its argument.\n */\nint add(int x)
assert.match(hover(functionDocs, 'add(2)'), /adds \*\*one\*\*/);
const inferred = 'fn twice(x) { return x * 2; }\nfn main() { let value = twice(3); return value; }\n';
assert.match(hover(inferred, 'twice(3)'), /int twice\(int x\)/);
-assert.match(hover(inferred, 'x *'), /type int/);
-assert.match(hover(inferred, 'value;'), /type int/);
+assert.match(hover(inferred, 'x *'), /\(int\) let x \/\/ parameter;/);
+assert.match(hover(inferred, 'value;'), /\(int\) let value/);
const pointer = 'int read(int* p) { return p[0]; }\nfn main() { int value = 3; return read(&value); }\n';
-assert.match(hover(pointer, 'p[0]'), /type int\*[\s\S]*pointer to `int`/);
-const alias = 'type row = [3]int;\nfn main() { row values; return values[0]; }\n';
-assert.match(hover(alias, 'row values'), /\[3\]int[\s\S]*fixed length of 3/);
+assert.match(hover(pointer, 'p[0]'), /\(int\*\) let p \/\/ parameter;[\s\S]*pointer to `int`/);
+const alias = 'type row = int[3];\nfn main() { row values; return values[0]; }\n';
+assert.match(hover(alias, 'row values'), /int\[3\][\s\S]*fixed length of 3/);
const enumeration = 'enum color { red, green = 5, blue };\nfn main() { color shade = green; return shade; }\n';
-assert.match(hover(enumeration, 'shade;'), /type color/);
-const dynamic = 'fn main() { []int items; push(items, 3); return len(items); }\n';
-assert.match(hover(dynamic, 'items);'), /type \[\]int[\s\S]*growable array handle/);
+assert.match(hover(enumeration, 'shade;'), /\(color\) let shade/);
+const dynamic = 'fn main() { int[?] items; push(items, 3); return len(items); }\n';
+assert.match(hover(dynamic, 'items);'), /\(int\[\?\]\) let items[\s\S]*growable array handle/);
const callable = 'fn main() { let apply = fn(int x) { return x + 1; }; return apply(2); }\n';
-assert.match(hover(callable, 'apply(2)'), /type .*\([\s\S]*callable value/);
-assert.match(hover(callable, 'apply(2)'), /type int\(int\)/);
+assert.match(hover(callable, 'apply(2)'), /\(.*\([\s\S]*callable value/);
+assert.match(hover(callable, 'apply(2)'), /\(int\(int\)\) let.m apply/);
const floatClosure = 'fn main() { let f = fn(float x) { return x + 1.5; }; let result = f(2.0); return result; }\n';
-assert.match(hover(floatClosure, 'result;'), /type float/);
-const inferredPointer = 'struct node { int value; };\nfn make_node() { return new(node); }\nfn main() { let p = make_node(); return p.value; }\n';
-assert.match(hover(inferredPointer, 'p.value'), /type node\*/);
-const aggregateAlias = 'fn main() { [3]int a; a[1] = 7; let alias = a; return alias[1]; }\n';
-assert.match(hover(aggregateAlias, 'alias[1]'), /type int\*/);
+assert.match(hover(floatClosure, 'result;'), /\(float\) let result/);
+const inferredPointer = 'include rt;\nstruct node { int value; };\nfn make_node() { return new(node); }\nfn main() { let p = make_node(); return p.value; }\n';
+assert.match(hover(inferredPointer, 'p.value'), /\(node\*\) let.m p/);
+const aggregateAlias = 'fn main() { int[3] a; a[1] = 7; let alias = a; return alias[1]; }\n';
+assert.match(hover(aggregateAlias, 'alias[1]'), /\(int\*\) let alias/);
+const sections = '// --- values ---\n// these declarations form a group.\nconst int limit = 7;\nfn main() { return limit; }';
+assert.ok(!hover(sections, 'limit;').includes('these declarations form a group'));
+assert.ok(!hover(sections, 'limit;').includes('--- values ---'));
+const blockSection = '/* ---- values ---- */\nint limit = 7;\nfn main() { return limit; }';
+assert.ok(!hover(blockSection, 'limit;').includes('---- values ----'));
+const trailing = 'fn main() {\n int n = 7; // the current count\n int next = 2;\n return n + next;\n}';
+assert.match(hover(trailing, 'n +'), /the current count/);
+assert.ok(!hover(trailing, 'next;').includes('the current count'));
+const trailingBlock = 'fn main() { int a = 1, b = 2; /* final count */\n return a + b; }';
+assert.ok(!hover(trailingBlock, 'a +').includes('final count'));
+assert.match(hover(trailingBlock, 'b;'), /final count/);
+const adjacent = 'fn main() { int a /* first count */ = 1, b /* second count */ = 2; return a + b; }';
+assert.match(hover(adjacent, 'a +'), /first count/);
+assert.ok(!hover(adjacent, 'a +').includes('second count'));
+assert.match(hover(adjacent, 'b;'), /second count/);
+// section headings end a doc block; trailing comments belong to their own line's declaration
+const sectionDocs = '// ---- one ----\n\n// adds.\nint add(int a, int b) { return a + b; } // after add\n// overview\n// ---- two ----\nint sub(int a, int b) { return a - b; }\n// ---- three ----\n// own doc\nint mul(int a, int b) { return a * b; }\nint g = 3; /* after g */\nfn main() { return add(1, 2) + sub(3, 1) + mul(2, 2) + g; }\n';
+const addHover = hover(sectionDocs, 'add(1');
+assert.ok(addHover.includes('adds.') && addHover.includes('after add') && !addHover.includes('overview') && !addHover.includes('after g'), addHover);
+assert.strictEqual(hover(sectionDocs, 'sub(3'), '```zc\nint sub(int a, int b)\n```');
+const mulHover = hover(sectionDocs, 'mul(2');
+assert.ok(!mulHover.includes('own doc') && !mulHover.includes('three') && !mulHover.includes('after'), mulHover);
+assert.ok(hover(sectionDocs, 'g; }').includes('after g'));
+// ownership and transfers explained in hovers
+const lifeDocs = 'include rt; struct node { int v; node* next; };\nint*.u make(int n) { int* q = new(int); *q = n; return u*q; }\nfn take(.d p) { return p[0]; }\nfn main() {\n let a = make(1);\n node* b = new(node), c = new(node);\n b.next = c;\n node* r = b.next;\n let d = new(3);\n take(d*d);\n return a[0] + r.v;\n}\n';
+assert.match(hover(lifeDocs, 'q = new'), /let.m q[\s\S]*passed up: returned on line 2/);
+assert.match(hover(lifeDocs, 'a ='), /let.m a[\s\S]*freed where its block ends on line 12/);
+assert.match(hover(lifeDocs, 'r.v'), /borrows from `b`, declared on line 6/);
+assert.match(hover(lifeDocs, 'c = new'), /passed down: stored in a container `b` on line 7/);
+assert.match(hover(lifeDocs, 'd = new'), /passed down: given to a d parameter on line 10/);
+const declaredResult = 'fn main() { let f = fn:float(int x) { return x; }; return f(2); }\n';
+assert.match(hover(declaredResult, 'f(2)'), /\(float\(int\)\) let.m f/);
+const nonDocs = '//: scratch region overview\nint scratch = 1;\n/* public count */ int count = 2; //: implementation note\nfn main() { return scratch + count; }';
+assert.ok(!hover(nonDocs, 'scratch +').includes('scratch region overview'));
+assert.match(hover(nonDocs, 'count;'), /public count/);
+assert.ok(!hover(nonDocs, 'count;').includes('implementation note'));
+const globals = 'let hello = "hello", prog[20000];\nint count = 3;\nfn main() { return hello[0] + prog[0] + count; }\n';
+for (const [name, type, use] of [['hello', 'char*', 'hello[0]'], ['prog', 'word[20000]', 'prog[0]'], ['count', 'int', 'count;']]) {
+ for (const needle of [name, use]) {
+ const value = hover(globals, needle);
+ assert.ok(value.startsWith('```zc\n(' + type + ') let ' + name + ' // global;\n```'), value);
+ assert.ok(!value.includes('; type '), value);
+ }
+}
+assert.match(hover('include run; fn main() { return run.sval[0]; }', 'sval'), /symbol[\s\S]*value/i);
+assert.match(hover('include rt; fn main() { return rt.len_s(b"bytes"); }', 'len_s'), /number of bytes in a packed byte string/i);
console.log('ok built-in and composite types, inferred signatures, and separate block docs');