Merge pull request #641 from Techatrix/testing-improvements
Move updated units_test.zig into tests directory
This commit is contained in:
commit
03565f42bf
@ -114,12 +114,6 @@ pub fn build(b: *std.build.Builder) !void {
|
|||||||
const test_step = b.step("test", "Run all the tests");
|
const test_step = b.step("test", "Run all the tests");
|
||||||
test_step.dependOn(b.getInstallStep());
|
test_step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
var unit_tests = b.addTest("src/unit_tests.zig");
|
|
||||||
unit_tests.use_stage1 = true;
|
|
||||||
unit_tests.setBuildMode(.Debug);
|
|
||||||
unit_tests.setTarget(target);
|
|
||||||
test_step.dependOn(&unit_tests.step);
|
|
||||||
|
|
||||||
var tests = b.addTest("tests/tests.zig");
|
var tests = b.addTest("tests/tests.zig");
|
||||||
tests.use_stage1 = true;
|
tests.use_stage1 = true;
|
||||||
tests.addPackage(.{ .name = "zls", .source = .{ .path = "src/zls.zig" }, .dependencies = exe.packages.items });
|
tests.addPackage(.{ .name = "zls", .source = .{ .path = "src/zls.zig" }, .dependencies = exe.packages.items });
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const analysis = @import("analysis.zig");
|
|
||||||
const types = @import("types.zig");
|
|
||||||
const offsets = @import("offsets.zig");
|
|
||||||
const URI = @import("uri.zig");
|
|
||||||
|
|
||||||
const allocator = std.testing.allocator;
|
|
||||||
|
|
||||||
fn makeDocument(uri: []const u8, text: []const u8) !types.TextDocument {
|
|
||||||
const mem = try allocator.alloc(u8, text.len + 1);
|
|
||||||
std.mem.copy(u8, mem, text);
|
|
||||||
mem[text.len] = 0;
|
|
||||||
|
|
||||||
return types.TextDocument{
|
|
||||||
.uri = uri,
|
|
||||||
.mem = mem,
|
|
||||||
.text = mem[0..text.len :0],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn freeDocument(doc: types.TextDocument) void {
|
|
||||||
allocator.free(doc.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn makeUnnamedDocument(text: []const u8) !types.TextDocument {
|
|
||||||
return try makeDocument("test", text);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn testContext(comptime line: []const u8, comptime tag: anytype, comptime range: ?[]const u8) !void {
|
|
||||||
const cursor_idx = comptime std.mem.indexOf(u8, line, "<cursor>").?;
|
|
||||||
const final_line = line[0..cursor_idx] ++ line[cursor_idx + "<cursor>".len ..];
|
|
||||||
|
|
||||||
const doc = try makeUnnamedDocument(final_line);
|
|
||||||
defer freeDocument(doc);
|
|
||||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
|
||||||
defer arena.deinit();
|
|
||||||
|
|
||||||
const p = try offsets.documentPosition(doc, .{ .line = 0, .character = @intCast(i64, cursor_idx) }, .utf8);
|
|
||||||
const ctx = try analysis.documentPositionContext(&arena, doc, p);
|
|
||||||
|
|
||||||
if (std.meta.activeTag(ctx) != tag) {
|
|
||||||
std.debug.print("Expected tag {}, got {}\n", .{ tag, std.meta.activeTag(ctx) });
|
|
||||||
return error.DifferentTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.range()) |ctx_range| {
|
|
||||||
if (range == null) {
|
|
||||||
std.debug.print("Expected null range, got `{s}`\n", .{
|
|
||||||
doc.text[ctx_range.start..ctx_range.end],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const range_start = comptime std.mem.indexOf(u8, final_line, range.?).?;
|
|
||||||
const range_end = range_start + range.?.len;
|
|
||||||
|
|
||||||
if (range_start != ctx_range.start or range_end != ctx_range.end) {
|
|
||||||
std.debug.print("Expected range `{s}` ({}..{}), got `{s}` ({}..{})\n", .{
|
|
||||||
doc.text[range_start..range_end], range_start, range_end,
|
|
||||||
doc.text[ctx_range.start..ctx_range.end], ctx_range.start, ctx_range.end,
|
|
||||||
});
|
|
||||||
return error.DifferentRange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (range != null) {
|
|
||||||
std.debug.print("Unexpected null range\n", .{});
|
|
||||||
return error.DifferentRange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test "documentPositionContext" {
|
|
||||||
try testContext(
|
|
||||||
\\const this_var = id<cursor>entifier;
|
|
||||||
,
|
|
||||||
.var_access,
|
|
||||||
"id",
|
|
||||||
);
|
|
||||||
|
|
||||||
try testContext(
|
|
||||||
\\if (displ.*.?.c.*[0].<cursor>@"a" == foo) {
|
|
||||||
,
|
|
||||||
.field_access,
|
|
||||||
"displ.*.?.c.*[0].",
|
|
||||||
);
|
|
||||||
|
|
||||||
try testContext(
|
|
||||||
\\const arr = std.ArrayList(SomeStruct(a, b, c, d)).in<cursor>it(allocator);
|
|
||||||
,
|
|
||||||
.field_access,
|
|
||||||
"std.ArrayList(SomeStruct(a, b, c, d)).in",
|
|
||||||
);
|
|
||||||
|
|
||||||
try testContext(
|
|
||||||
\\try erroringFn(the_first[arg], second[a..<cursor>]);
|
|
||||||
,
|
|
||||||
.empty,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
try testContext(
|
|
||||||
\\ fn add(lhf: lself, rhs: rself) !Se<cursor> {
|
|
||||||
,
|
|
||||||
.var_access,
|
|
||||||
"Se",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "pathRelative and escapes" {
|
|
||||||
const join1 = try URI.pathRelative(allocator, "file://project/zig", "/src/main+.zig");
|
|
||||||
defer allocator.free(join1);
|
|
||||||
try std.testing.expectEqualStrings("file://project/zig/src/main%2B.zig", join1);
|
|
||||||
|
|
||||||
const join2 = try URI.pathRelative(allocator, "file://project/zig/wow", "../]src]/]main.zig");
|
|
||||||
defer allocator.free(join2);
|
|
||||||
try std.testing.expectEqualStrings("file://project/zig/%5Dsrc%5D/%5Dmain.zig", join2);
|
|
||||||
}
|
|
@ -1,6 +1,9 @@
|
|||||||
// used by tests as a package
|
// used by tests as a package
|
||||||
|
pub const analysis = @import("analysis.zig");
|
||||||
pub const header = @import("header.zig");
|
pub const header = @import("header.zig");
|
||||||
pub const types = @import("types.zig");
|
pub const offsets = @import("offsets.zig");
|
||||||
pub const requests = @import("requests.zig");
|
pub const requests = @import("requests.zig");
|
||||||
pub const Server = @import("Server.zig");
|
pub const Server = @import("Server.zig");
|
||||||
pub const translate_c = @import("translate_c.zig");
|
pub const translate_c = @import("translate_c.zig");
|
||||||
|
pub const types = @import("types.zig");
|
||||||
|
pub const URI = @import("uri.zig");
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
comptime {
|
comptime {
|
||||||
_ = @import("sessions.zig");
|
_ = @import("sessions.zig");
|
||||||
|
_ = @import("utility/position_context.zig");
|
||||||
|
_ = @import("utility/uri.zig");
|
||||||
|
|
||||||
// TODO Lifecycle Messages
|
// TODO Lifecycle Messages
|
||||||
|
|
||||||
|
283
tests/utility/position_context.zig
Normal file
283
tests/utility/position_context.zig
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const zls = @import("zls");
|
||||||
|
|
||||||
|
const analysis = zls.analysis;
|
||||||
|
const types = zls.types;
|
||||||
|
const offsets = zls.offsets;
|
||||||
|
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
|
test "position context - var access" {
|
||||||
|
try testContext(
|
||||||
|
\\const this_var = id<cursor>entifier;
|
||||||
|
,
|
||||||
|
.var_access,
|
||||||
|
"id",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\const this_var = identifier<cursor>;
|
||||||
|
,
|
||||||
|
.var_access,
|
||||||
|
"identifier",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\ fn foo() !Str<cursor> {
|
||||||
|
,
|
||||||
|
.var_access,
|
||||||
|
"Str",
|
||||||
|
);
|
||||||
|
// TODO fix failing test!
|
||||||
|
// try testContext(
|
||||||
|
// \\ fn foo() Err<cursor>!void {
|
||||||
|
// ,
|
||||||
|
// .var_access,
|
||||||
|
// "Err",
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - field access" {
|
||||||
|
try testContext(
|
||||||
|
\\if (foo.<cursor>field == foo) {
|
||||||
|
,
|
||||||
|
.field_access,
|
||||||
|
"foo.",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\if (foo.member.<cursor>field == foo) {
|
||||||
|
,
|
||||||
|
.field_access,
|
||||||
|
"foo.member.",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\if (foo.*.?.<cursor>field == foo) {
|
||||||
|
,
|
||||||
|
.field_access,
|
||||||
|
"foo.*.?.",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\if (foo[0].<cursor>field == foo) {
|
||||||
|
,
|
||||||
|
.field_access,
|
||||||
|
"foo[0].",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\if (foo.<cursor>@"field" == foo) {
|
||||||
|
,
|
||||||
|
.field_access,
|
||||||
|
"foo.",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\const arr = std.ArrayList(SomeStruct(a, b, c, d)).in<cursor>it(allocator);
|
||||||
|
,
|
||||||
|
.field_access,
|
||||||
|
"std.ArrayList(SomeStruct(a, b, c, d)).in",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\fn foo() !Foo.b<cursor> {
|
||||||
|
,
|
||||||
|
.field_access,
|
||||||
|
"Foo.b",
|
||||||
|
);
|
||||||
|
// TODO fix failing test!
|
||||||
|
// try testContext(
|
||||||
|
// \\fn foo() Foo.b<cursor>!void {
|
||||||
|
// ,
|
||||||
|
// .field_access,
|
||||||
|
// "Foo.b",
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - builtin" {
|
||||||
|
try testContext(
|
||||||
|
\\var foo = @intC<cursor>(u32, 5);
|
||||||
|
,
|
||||||
|
.builtin,
|
||||||
|
"@intC",
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\fn foo() void { @setRuntime<cursor>(false); };
|
||||||
|
,
|
||||||
|
.builtin,
|
||||||
|
"@setRuntime",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - comment" {
|
||||||
|
// TODO fix failing test!
|
||||||
|
// try testContext(
|
||||||
|
// \\// i am<cursor> a test
|
||||||
|
// ,
|
||||||
|
// .comment,
|
||||||
|
// "// i am",
|
||||||
|
// );
|
||||||
|
// try testContext(
|
||||||
|
// \\/// i am<cursor> a test
|
||||||
|
// ,
|
||||||
|
// .comment,
|
||||||
|
// "/// i am",
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - import/embedfile string literal" {
|
||||||
|
try testContext(
|
||||||
|
\\const std = @import("st<cursor>");
|
||||||
|
,
|
||||||
|
.import_string_literal,
|
||||||
|
"\"st", // maybe report just "st"
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\const std = @embedFile("file.<cursor>");
|
||||||
|
,
|
||||||
|
.embedfile_string_literal,
|
||||||
|
"\"file.", // maybe report just "file."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - string literal" {
|
||||||
|
try testContext(
|
||||||
|
\\var foo = "he<cursor>llo world!";
|
||||||
|
,
|
||||||
|
.string_literal,
|
||||||
|
"\"he", // maybe report just "he"
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\var foo = \\hello<cursor>;
|
||||||
|
,
|
||||||
|
.string_literal,
|
||||||
|
"\\\\hello", // maybe report just "hello"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - global error set" {
|
||||||
|
try testContext(
|
||||||
|
\\fn foo() error<cursor>!void {
|
||||||
|
,
|
||||||
|
.global_error_set,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\fn foo() error.<cursor>!void {
|
||||||
|
,
|
||||||
|
.global_error_set,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
// TODO this should probably also be .global_error_set
|
||||||
|
// try testContext(
|
||||||
|
// \\fn foo() error{<cursor>}!void {
|
||||||
|
// ,
|
||||||
|
// .global_error_set,
|
||||||
|
// null,
|
||||||
|
// );
|
||||||
|
// try testContext(
|
||||||
|
// \\fn foo() error{OutOfMemory, <cursor>}!void {
|
||||||
|
// ,
|
||||||
|
// .global_error_set,
|
||||||
|
// null,
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - enum literal" {
|
||||||
|
try testContext(
|
||||||
|
\\var foo = .tag<cursor>;
|
||||||
|
,
|
||||||
|
.enum_literal,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\var foo = .<cursor>;
|
||||||
|
,
|
||||||
|
.enum_literal,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - label" {
|
||||||
|
try testContext(
|
||||||
|
\\var foo = blk: { break :blk<cursor> null };
|
||||||
|
,
|
||||||
|
.label,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "position context - empty" {
|
||||||
|
try testContext(
|
||||||
|
\\try foo(arg, slice[<cursor>]);
|
||||||
|
,
|
||||||
|
.empty,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\try foo(arg, slice[<cursor>..3]);
|
||||||
|
,
|
||||||
|
.empty,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
try testContext(
|
||||||
|
\\try foo(arg, slice[0..<cursor>]);
|
||||||
|
,
|
||||||
|
.empty,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn makeDocument(uri: []const u8, text: []const u8) !types.TextDocument {
|
||||||
|
const mem = try allocator.alloc(u8, text.len + 1);
|
||||||
|
std.mem.copy(u8, mem, text);
|
||||||
|
mem[text.len] = 0;
|
||||||
|
|
||||||
|
return types.TextDocument{
|
||||||
|
.uri = uri,
|
||||||
|
.mem = mem,
|
||||||
|
.text = mem[0..text.len :0],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freeDocument(doc: types.TextDocument) void {
|
||||||
|
allocator.free(doc.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn testContext(comptime line: []const u8, comptime tag: std.meta.Tag(analysis.PositionContext), comptime maybe_range: ?[]const u8) !void {
|
||||||
|
const cursor_idx = comptime std.mem.indexOf(u8, line, "<cursor>").?;
|
||||||
|
const final_line = line[0..cursor_idx] ++ line[cursor_idx + "<cursor>".len ..];
|
||||||
|
|
||||||
|
const doc = try makeDocument("", line);
|
||||||
|
defer freeDocument(doc);
|
||||||
|
|
||||||
|
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
|
||||||
|
const p = try offsets.documentPosition(doc, .{ .line = 0, .character = @intCast(i64, cursor_idx) }, .utf8);
|
||||||
|
const ctx = try analysis.documentPositionContext(&arena, doc, p);
|
||||||
|
|
||||||
|
if (std.meta.activeTag(ctx) != tag) {
|
||||||
|
std.debug.print("Expected tag `{s}`, got `{s}`\n", .{ @tagName(tag), @tagName(std.meta.activeTag(ctx)) });
|
||||||
|
return error.DifferentTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actual_range = ctx.range() orelse if(maybe_range) |expected_range| {
|
||||||
|
std.debug.print("Expected `{s}`, got null range\n", .{
|
||||||
|
expected_range,
|
||||||
|
});
|
||||||
|
return error.DifferentRange;
|
||||||
|
} else return;
|
||||||
|
|
||||||
|
const expected_range = maybe_range orelse {
|
||||||
|
std.debug.print("Expected null range, got `{s}`\n", .{
|
||||||
|
doc.text[actual_range.start..actual_range.end],
|
||||||
|
});
|
||||||
|
return error.DifferentRange;
|
||||||
|
};
|
||||||
|
|
||||||
|
const expected_range_start = comptime std.mem.indexOf(u8, final_line, expected_range).?;
|
||||||
|
const expected_range_end = expected_range_start + expected_range.len;
|
||||||
|
|
||||||
|
if (expected_range_start != actual_range.start or expected_range_end != actual_range.end) {
|
||||||
|
std.debug.print("Expected range `{s}` ({}..{}), got `{s}` ({}..{})\n", .{
|
||||||
|
doc.text[expected_range_start..expected_range_end], expected_range_start, expected_range_end,
|
||||||
|
doc.text[actual_range.start..actual_range.end], actual_range.start, actual_range.end,
|
||||||
|
});
|
||||||
|
return error.DifferentRange;
|
||||||
|
}
|
||||||
|
}
|
16
tests/utility/uri.zig
Normal file
16
tests/utility/uri.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const zls = @import("zls");
|
||||||
|
|
||||||
|
const URI = zls.URI;
|
||||||
|
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
|
test "uri - pathRelative" {
|
||||||
|
const join1 = try URI.pathRelative(allocator, "file://project/zig", "/src/main+.zig");
|
||||||
|
defer allocator.free(join1);
|
||||||
|
try std.testing.expectEqualStrings("file://project/zig/src/main%2B.zig", join1);
|
||||||
|
|
||||||
|
const join2 = try URI.pathRelative(allocator, "file://project/zig/wow", "../]src]/]main.zig");
|
||||||
|
defer allocator.free(join2);
|
||||||
|
try std.testing.expectEqualStrings("file://project/zig/%5Dsrc%5D/%5Dmain.zig", join2);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user