From 6933e1598ab88352d5ec3b37c2ab7e8a6dbded4d Mon Sep 17 00:00:00 2001 From: Techatrix <19954306+Techatrix@users.noreply.github.com> Date: Sun, 11 Sep 2022 00:07:01 +0200 Subject: [PATCH] move updated units_test.zig into tests directory --- build.zig | 6 - src/unit_tests.zig | 114 ------------ src/zls.zig | 5 +- tests/tests.zig | 2 + tests/utility/position_context.zig | 283 +++++++++++++++++++++++++++++ tests/utility/uri.zig | 16 ++ 6 files changed, 305 insertions(+), 121 deletions(-) delete mode 100644 src/unit_tests.zig create mode 100644 tests/utility/position_context.zig create mode 100644 tests/utility/uri.zig diff --git a/build.zig b/build.zig index d796185..ff1ddb5 100644 --- a/build.zig +++ b/build.zig @@ -114,12 +114,6 @@ pub fn build(b: *std.build.Builder) !void { const test_step = b.step("test", "Run all the tests"); 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"); tests.use_stage1 = true; tests.addPackage(.{ .name = "zls", .source = .{ .path = "src/zls.zig" }, .dependencies = exe.packages.items }); diff --git a/src/unit_tests.zig b/src/unit_tests.zig deleted file mode 100644 index 4a5867d..0000000 --- a/src/unit_tests.zig +++ /dev/null @@ -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, "").?; - const final_line = line[0..cursor_idx] ++ line[cursor_idx + "".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 = identifier; - , - .var_access, - "id", - ); - - try testContext( - \\if (displ.*.?.c.*[0].@"a" == foo) { - , - .field_access, - "displ.*.?.c.*[0].", - ); - - try testContext( - \\const arr = std.ArrayList(SomeStruct(a, b, c, d)).init(allocator); - , - .field_access, - "std.ArrayList(SomeStruct(a, b, c, d)).in", - ); - - try testContext( - \\try erroringFn(the_first[arg], second[a..]); - , - .empty, - null, - ); - - try testContext( - \\ fn add(lhf: lself, rhs: rself) !Se { - , - .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); -} diff --git a/src/zls.zig b/src/zls.zig index 569270e..2f89d96 100644 --- a/src/zls.zig +++ b/src/zls.zig @@ -1,6 +1,9 @@ // used by tests as a package +pub const analysis = @import("analysis.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 Server = @import("Server.zig"); pub const translate_c = @import("translate_c.zig"); +pub const types = @import("types.zig"); +pub const URI = @import("uri.zig"); diff --git a/tests/tests.zig b/tests/tests.zig index 8e754bf..82bf51b 100644 --- a/tests/tests.zig +++ b/tests/tests.zig @@ -1,5 +1,7 @@ comptime { _ = @import("sessions.zig"); + _ = @import("utility/position_context.zig"); + _ = @import("utility/uri.zig"); // TODO Lifecycle Messages diff --git a/tests/utility/position_context.zig b/tests/utility/position_context.zig new file mode 100644 index 0000000..e93c3a9 --- /dev/null +++ b/tests/utility/position_context.zig @@ -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 = identifier; + , + .var_access, + "id", + ); + try testContext( + \\const this_var = identifier; + , + .var_access, + "identifier", + ); + try testContext( + \\ fn foo() !Str { + , + .var_access, + "Str", + ); + // TODO fix failing test! + // try testContext( + // \\ fn foo() Err!void { + // , + // .var_access, + // "Err", + // ); +} + +test "position context - field access" { + try testContext( + \\if (foo.field == foo) { + , + .field_access, + "foo.", + ); + try testContext( + \\if (foo.member.field == foo) { + , + .field_access, + "foo.member.", + ); + try testContext( + \\if (foo.*.?.field == foo) { + , + .field_access, + "foo.*.?.", + ); + try testContext( + \\if (foo[0].field == foo) { + , + .field_access, + "foo[0].", + ); + try testContext( + \\if (foo.@"field" == foo) { + , + .field_access, + "foo.", + ); + try testContext( + \\const arr = std.ArrayList(SomeStruct(a, b, c, d)).init(allocator); + , + .field_access, + "std.ArrayList(SomeStruct(a, b, c, d)).in", + ); + try testContext( + \\fn foo() !Foo.b { + , + .field_access, + "Foo.b", + ); + // TODO fix failing test! + // try testContext( + // \\fn foo() Foo.b!void { + // , + // .field_access, + // "Foo.b", + // ); +} + +test "position context - builtin" { + try testContext( + \\var foo = @intC(u32, 5); + , + .builtin, + "@intC", + ); + try testContext( + \\fn foo() void { @setRuntime(false); }; + , + .builtin, + "@setRuntime", + ); +} + +test "position context - comment" { + // TODO fix failing test! + // try testContext( + // \\// i am a test + // , + // .comment, + // "// i am", + // ); + // try testContext( + // \\/// i am a test + // , + // .comment, + // "/// i am", + // ); +} + +test "position context - import/embedfile string literal" { + try testContext( + \\const std = @import("st"); + , + .import_string_literal, + "\"st", // maybe report just "st" + ); + try testContext( + \\const std = @embedFile("file."); + , + .embedfile_string_literal, + "\"file.", // maybe report just "file." + ); +} + +test "position context - string literal" { + try testContext( + \\var foo = "hello world!"; + , + .string_literal, + "\"he", // maybe report just "he" + ); + try testContext( + \\var foo = \\hello; + , + .string_literal, + "\\\\hello", // maybe report just "hello" + ); +} + +test "position context - global error set" { + try testContext( + \\fn foo() error!void { + , + .global_error_set, + null, + ); + try testContext( + \\fn foo() error.!void { + , + .global_error_set, + null, + ); + // TODO this should probably also be .global_error_set + // try testContext( + // \\fn foo() error{}!void { + // , + // .global_error_set, + // null, + // ); + // try testContext( + // \\fn foo() error{OutOfMemory, }!void { + // , + // .global_error_set, + // null, + // ); +} + +test "position context - enum literal" { + try testContext( + \\var foo = .tag; + , + .enum_literal, + null, + ); + try testContext( + \\var foo = .; + , + .enum_literal, + null, + ); +} + +test "position context - label" { + try testContext( + \\var foo = blk: { break :blk null }; + , + .label, + null, + ); +} + +test "position context - empty" { + try testContext( + \\try foo(arg, slice[]); + , + .empty, + null, + ); + try testContext( + \\try foo(arg, slice[..3]); + , + .empty, + null, + ); + try testContext( + \\try foo(arg, slice[0..]); + , + .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, "").?; + const final_line = line[0..cursor_idx] ++ line[cursor_idx + "".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; + } +} diff --git a/tests/utility/uri.zig b/tests/utility/uri.zig new file mode 100644 index 0000000..4aeb3b4 --- /dev/null +++ b/tests/utility/uri.zig @@ -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); +} \ No newline at end of file