Completely overhaul offsets.zig (#643)
* completely overhaul offsets.zig
This commit is contained in:
169
tests/utility/offsets.zig
Normal file
169
tests/utility/offsets.zig
Normal file
@@ -0,0 +1,169 @@
|
||||
const std = @import("std");
|
||||
const zls = @import("zls");
|
||||
|
||||
const types = zls.types;
|
||||
const offsets = zls.offsets;
|
||||
|
||||
test "offsets - index <-> Position" {
|
||||
try testIndexPosition("", 0, 0, .{ 0, 0, 0 });
|
||||
|
||||
try testIndexPosition("hello from zig", 10, 0, .{ 10, 10, 10 });
|
||||
|
||||
try testIndexPosition("\n", 0, 0, .{ 0, 0, 0 });
|
||||
try testIndexPosition("\n", 1, 1, .{ 0, 0, 0 });
|
||||
|
||||
try testIndexPosition("hello\nfrom\nzig\n", 5, 0, .{ 5, 5, 5 });
|
||||
try testIndexPosition("hello\nfrom\nzig\n", 6, 1, .{ 0, 0, 0 });
|
||||
try testIndexPosition("hello\nfrom\nzig\n", 8, 1, .{ 2, 2, 2 });
|
||||
try testIndexPosition("\nhello\nfrom\nzig", 15, 3, .{ 3, 3, 3 });
|
||||
|
||||
try testIndexPosition("a¶↉🠁", 10, 0, .{ 10, 5, 4 });
|
||||
try testIndexPosition("🇺🇸 🇩🇪", 17, 0, .{ 17, 9, 5 });
|
||||
|
||||
try testIndexPosition("a¶↉🠁\na¶↉🠁", 10, 0, .{ 10, 5, 4 });
|
||||
try testIndexPosition("a¶↉🠁\na¶↉🠁", 11, 1, .{ 0, 0, 0 });
|
||||
try testIndexPosition("a¶↉🠁\na¶↉🠁", 21, 1, .{ 10, 5, 4 });
|
||||
|
||||
try testIndexPosition("\na¶↉🠁", 4, 1, .{ 3, 2, 2 });
|
||||
try testIndexPosition("a¶↉🠁\n", 6, 0, .{ 6, 3, 3 });
|
||||
try testIndexPosition("a¶↉🠁\n", 11, 1, .{ 0, 0, 0 });
|
||||
}
|
||||
|
||||
test "offsets - tokenToLoc" {
|
||||
try testTokenToLoc("foo", 0, 0, 3);
|
||||
try testTokenToLoc("foo\n", 0, 0, 3);
|
||||
try testTokenToLoc("\nfoo", 0, 1, 4);
|
||||
try testTokenToLoc("foo:", 0, 0, 3);
|
||||
try testTokenToLoc(";;", 1, 1, 2);
|
||||
}
|
||||
|
||||
test "offsets - tokenIndexToLoc" {
|
||||
try testTokenIndexToLoc("", 0, 0, 0);
|
||||
try testTokenIndexToLoc("foo", 0, 0, 3);
|
||||
try testTokenIndexToLoc("0, 0", 3, 3, 4);
|
||||
try testTokenIndexToLoc(" bar ", 0, 1, 4);
|
||||
}
|
||||
|
||||
test "offsets - lineLocAtIndex" {
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceAtIndex("", 0));
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceAtIndex("\n", 0));
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceAtIndex("\n", 1));
|
||||
|
||||
try std.testing.expectEqualStrings("foo", offsets.lineSliceAtIndex("foo\nbar", 2));
|
||||
try std.testing.expectEqualStrings("bar", offsets.lineSliceAtIndex("foo\nbar", 4));
|
||||
try std.testing.expectEqualStrings("bar", offsets.lineSliceAtIndex("foo\nbar", 6));
|
||||
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceAtIndex("foo\n", 4));
|
||||
try std.testing.expectEqualStrings("foo", offsets.lineSliceAtIndex("foo\n", 3));
|
||||
}
|
||||
|
||||
test "offsets - lineLocUntilIndex" {
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceUntilIndex("", 0));
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceUntilIndex("\n", 0));
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceUntilIndex("\n", 1));
|
||||
|
||||
try std.testing.expectEqualStrings("fo", offsets.lineSliceUntilIndex("foo\nbar", 2));
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceUntilIndex("foo\nbar", 4));
|
||||
try std.testing.expectEqualStrings("ba", offsets.lineSliceUntilIndex("foo\nbar", 6));
|
||||
|
||||
try std.testing.expectEqualStrings("", offsets.lineSliceUntilIndex("foo\n", 4));
|
||||
try std.testing.expectEqualStrings("foo", offsets.lineSliceUntilIndex("foo\n", 3));
|
||||
}
|
||||
|
||||
test "offsets - convertPositionEncoding" {
|
||||
try testConvertPositionEncoding("", 0, 0, .{ 0, 0, 0 });
|
||||
try testConvertPositionEncoding("\n", 0, 0, .{ 0, 0, 0 });
|
||||
try testConvertPositionEncoding("\n", 1, 0, .{ 0, 0, 0 });
|
||||
try testConvertPositionEncoding("foo", 0, 3, .{ 3, 3, 3 });
|
||||
try testConvertPositionEncoding("a¶↉🠁", 0, 10, .{ 10, 5, 4 });
|
||||
try testConvertPositionEncoding("a¶↉🠁\na¶↉🠁", 1, 6, .{ 6, 3, 3 });
|
||||
}
|
||||
|
||||
test "offsets - advancePosition" {
|
||||
try testAdvancePosition("", 0, 0, 0, 0, 0, 0);
|
||||
try testAdvancePosition("foo", 0, 3, 0, 0, 0, 3);
|
||||
try testAdvancePosition("\n", 1, 0, 0, 0, 0, 1);
|
||||
try testAdvancePosition("foo\nbar", 1, 2, 0, 1, 1, 6);
|
||||
try testAdvancePosition("foo\nbar", 1, 3, 1, 0, 4, 7);
|
||||
}
|
||||
|
||||
test "offsets - countCodeUnits" {
|
||||
try testCountCodeUnits("", .{ 0, 0, 0 });
|
||||
try testCountCodeUnits("a\na", .{ 3, 3, 3 });
|
||||
try testCountCodeUnits("a¶↉🠁", .{ 10, 5, 4 });
|
||||
try testCountCodeUnits("🠁↉¶a", .{ 10, 5, 4 });
|
||||
try testCountCodeUnits("🇺🇸 🇩🇪", .{ 17, 9, 5 });
|
||||
}
|
||||
|
||||
test "offsets - getNCodeUnitByteCount" {
|
||||
try testGetNCodeUnitByteCount("", .{ 0, 0, 0 });
|
||||
try testGetNCodeUnitByteCount("foo", .{ 2, 2, 2 });
|
||||
try testGetNCodeUnitByteCount("a¶🠁🠁", .{ 7, 4, 3 });
|
||||
try testGetNCodeUnitByteCount("🇺🇸 🇩🇪", .{ 9, 5, 3 });
|
||||
}
|
||||
|
||||
fn testIndexPosition(text: []const u8, index: usize, line: u32, characters: [3]u32) !void {
|
||||
const position8: types.Position = .{ .line = line, .character = characters[0] };
|
||||
const position16: types.Position = .{ .line = line, .character = characters[1] };
|
||||
const position32: types.Position = .{ .line = line, .character = characters[2] };
|
||||
|
||||
try std.testing.expectEqual(position8, offsets.indexToPosition(text, index, .utf8));
|
||||
try std.testing.expectEqual(position16, offsets.indexToPosition(text, index, .utf16));
|
||||
try std.testing.expectEqual(position32, offsets.indexToPosition(text, index, .utf32));
|
||||
|
||||
try std.testing.expectEqual(index, offsets.positionToIndex(text, position8, .utf8));
|
||||
try std.testing.expectEqual(index, offsets.positionToIndex(text, position16, .utf16));
|
||||
try std.testing.expectEqual(index, offsets.positionToIndex(text, position32, .utf32));
|
||||
}
|
||||
|
||||
fn testTokenToLoc(text: [:0]const u8, token_index: std.zig.Ast.TokenIndex, start: usize, end: usize) !void {
|
||||
var tree = try std.zig.parse(std.testing.allocator, text);
|
||||
defer tree.deinit(std.testing.allocator);
|
||||
|
||||
const actual = offsets.tokenToLoc(tree, token_index);
|
||||
|
||||
try std.testing.expectEqual(start, actual.start);
|
||||
try std.testing.expectEqual(end, actual.end);
|
||||
}
|
||||
|
||||
fn testTokenIndexToLoc(text: [:0]const u8, index: usize, start: usize, end: usize) !void {
|
||||
const loc = offsets.tokenIndexToLoc(text, index);
|
||||
|
||||
try std.testing.expectEqual(start, loc.start);
|
||||
try std.testing.expectEqual(end, loc.end);
|
||||
}
|
||||
|
||||
fn testAdvancePosition(text: [:0]const u8, expected_line: u32, expected_character: u32, line: u32, character: u32, from: usize, to: usize) !void {
|
||||
const expected: types.Position = .{ .line = expected_line, .character = expected_character };
|
||||
const actual = offsets.advancePosition(text, .{ .line = line, .character = character }, from, to, .utf16);
|
||||
|
||||
try std.testing.expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
fn testConvertPositionEncoding(text: [:0]const u8, line: u32, character: u32, new_characters: [3]u32) !void {
|
||||
const position: types.Position = .{ .line = line, .character = character };
|
||||
|
||||
const position8 = offsets.convertPositionEncoding(text, position, .utf8, .utf8);
|
||||
const position16 = offsets.convertPositionEncoding(text, position, .utf8, .utf16);
|
||||
const position32 = offsets.convertPositionEncoding(text, position, .utf8, .utf32);
|
||||
|
||||
try std.testing.expectEqual(line, position8.line);
|
||||
try std.testing.expectEqual(line, position16.line);
|
||||
try std.testing.expectEqual(line, position32.line);
|
||||
|
||||
try std.testing.expectEqual(new_characters[0], position8.character);
|
||||
try std.testing.expectEqual(new_characters[1], position16.character);
|
||||
try std.testing.expectEqual(new_characters[2], position32.character);
|
||||
}
|
||||
|
||||
fn testCountCodeUnits(text: []const u8, counts: [3]usize) !void {
|
||||
try std.testing.expectEqual(counts[0], offsets.countCodeUnits(text, .utf8));
|
||||
try std.testing.expectEqual(counts[1], offsets.countCodeUnits(text, .utf16));
|
||||
try std.testing.expectEqual(counts[2], offsets.countCodeUnits(text, .utf32));
|
||||
}
|
||||
|
||||
fn testGetNCodeUnitByteCount(text: []const u8, n: [3]usize) !void {
|
||||
try std.testing.expectEqual(n[0], offsets.getNCodeUnitByteCount(text, n[0], .utf8));
|
||||
try std.testing.expectEqual(n[0], offsets.getNCodeUnitByteCount(text, n[1], .utf16));
|
||||
try std.testing.expectEqual(n[0], offsets.getNCodeUnitByteCount(text, n[2], .utf32));
|
||||
}
|
||||
@@ -201,6 +201,18 @@ test "position context - label" {
|
||||
}
|
||||
|
||||
test "position context - empty" {
|
||||
try testContext(
|
||||
\\<cursor>
|
||||
,
|
||||
.empty,
|
||||
null,
|
||||
);
|
||||
try testContext(
|
||||
\\<cursor>const foo = struct {};
|
||||
,
|
||||
.empty,
|
||||
null,
|
||||
);
|
||||
try testContext(
|
||||
\\try foo(arg, slice[<cursor>]);
|
||||
,
|
||||
@@ -245,18 +257,14 @@ fn testContext(comptime line: []const u8, comptime tag: std.meta.Tag(analysis.Po
|
||||
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);
|
||||
const ctx = try analysis.getPositionContext(allocator, doc, cursor_idx);
|
||||
|
||||
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| {
|
||||
const actual_loc = ctx.loc() orelse if(maybe_range) |expected_range| {
|
||||
std.debug.print("Expected `{s}`, got null range\n", .{
|
||||
expected_range,
|
||||
});
|
||||
@@ -265,7 +273,7 @@ fn testContext(comptime line: []const u8, comptime tag: std.meta.Tag(analysis.Po
|
||||
|
||||
const expected_range = maybe_range orelse {
|
||||
std.debug.print("Expected null range, got `{s}`\n", .{
|
||||
doc.text[actual_range.start..actual_range.end],
|
||||
doc.text[actual_loc.start..actual_loc.end],
|
||||
});
|
||||
return error.DifferentRange;
|
||||
};
|
||||
@@ -273,10 +281,10 @@ fn testContext(comptime line: []const u8, comptime tag: std.meta.Tag(analysis.Po
|
||||
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) {
|
||||
if (expected_range_start != actual_loc.start or expected_range_end != actual_loc.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,
|
||||
doc.text[actual_loc.start..actual_loc.end], actual_loc.start, actual_loc.end,
|
||||
});
|
||||
return error.DifferentRange;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user