commit 200b8c58cce70c76e5665ff48fd52f1ba9938ef5
parent 9a3da9d4fa2075ca5a908dd115845df4e769c987
Author: gracefu <81774659+gracefuu@users.noreply.github.com>
Date: Thu, 22 May 2025 03:28:13 +0800
Move to snapshot tests and remove old AstGens from test
Diffstat:
15 files changed, 428 insertions(+), 518 deletions(-)
diff --git a/src/test.zig b/src/test.zig
@@ -1,6 +1,4 @@
const std = @import("std");
-const parse = @import("AstGen.zig").parse;
-const parse2 = @import("AstGen2.zig").parse;
const parse3 = @import("AstGen3.zig").parse;
const Ast = @import("Ast.zig");
const PADDING = @import("padded_str.zig").PADDING;
@@ -8,11 +6,6 @@ const PADDING = @import("padded_str.zig").PADDING;
const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator(.{});
const ArenaAllocator = std.heap.ArenaAllocator;
-// This is in a function so the result is memoized.
-fn padInput(comptime input: []const u8) []const u8 {
- return input ++ "\n" ** 128;
-}
-
fn readFile(path: []const u8) !std.ArrayList(u8) {
var input_instance: std.ArrayList(u8) = .init(std.testing.allocator);
errdefer input_instance.deinit();
@@ -21,549 +14,84 @@ fn readFile(path: []const u8) !std.ArrayList(u8) {
const file_size = (try input_file.stat()).size;
try input_instance.ensureTotalCapacity(file_size + PADDING);
try input_file.reader().readAllArrayList(&input_instance, std.math.maxInt(u32) - PADDING);
- try input_instance.appendNTimes('\n', PADDING);
return input_instance;
}
-fn testParse(comptime input: []const u8, expected: []const u8) !void {
- try testParseWithFn(input, expected, parse);
- try testParseWithFn(input, expected, parse3);
-}
-
-fn testParseWithFn(comptime input: []const u8, expected: []const u8, parseFn: anytype) !void {
- var arena: ArenaAllocator = .init(std.testing.allocator);
- defer arena.deinit();
-
- const safe_input = padInput(input);
-
- const ast = try parseFn(std.testing.allocator, arena.allocator(), safe_input);
- var ast_render: std.ArrayListUnmanaged(u8) = .empty;
- defer ast_render.deinit(std.testing.allocator);
- try ast.renderAst(ast_render.writer(std.testing.allocator), safe_input);
- try std.testing.expectEqualStrings(expected, ast_render.items);
+fn testSnapshot(comptime path: []const u8) !void {
+ const snapshot_path = path ++ ".ast";
+ const wrong_path = path ++ ".wrong.ast";
+
+ var input_instance = try readFile(path);
+ defer input_instance.deinit();
+ try input_instance.appendNTimes('\n', 128);
+
+ const ast = try parse3(std.testing.allocator, null, input_instance.items);
+ defer ast.deinit(std.testing.allocator);
+
+ var output_instance: std.ArrayList(u8) = .init(std.testing.allocator);
+ defer output_instance.deinit();
+ try ast.renderAst(output_instance.writer(), input_instance.items);
+
+ var snapshot_instance: std.ArrayList(u8) = readFile(snapshot_path) catch .init(std.testing.allocator);
+ defer snapshot_instance.deinit();
+
+ if (!std.mem.eql(u8, snapshot_instance.items, output_instance.items)) {
+ const wrong_file = try std.fs.cwd().createFile(wrong_path, .{});
+ defer wrong_file.close();
+ try wrong_file.writer().writeAll(output_instance.items);
+ std.debug.print(
+ \\Snapshot test for {[path]s} failed.
+ \\Generated output written to {[wrong_path]s}.
+ \\If changes are expected, copy {[wrong_path]s} to {[snapshot_path]s}.
+ \\ diff {[snapshot_path]s} {[wrong_path]s}
+ \\ mv {[wrong_path]s} {[snapshot_path]s}
+ \\
+ , .{ .path = path, .wrong_path = wrong_path, .snapshot_path = snapshot_path });
+ return error.TestFailed;
+ }
}
-test "Empty" {
- try testParse("",
- \\.document
- \\
- );
+test "empty" {
+ try testSnapshot("src/test/empty.my");
}
test "Happy path paragraph" {
- try testParse(
- \\text
- \\
- \\text
- \\text
- \\
- \\text
- \\ text
- \\
- ,
- \\.document
- \\ .paragraph
- \\ .text
- \\ "text"
- \\ .paragraph
- \\ .text
- \\ "text"
- \\ .space_text
- \\ "text"
- \\ .paragraph
- \\ .text
- \\ "text"
- \\ .space_text
- \\ " text"
- \\
- );
+ try testSnapshot("src/test/paragraph.my");
}
test "Happy path headings" {
- try testParse(
- \\# text
- \\# text
- \\# text
- \\ text
- \\
- \\# text
- \\
- \\# text
- \\ text
- \\
- \\# text
- \\ text
- \\
- \\## text
- \\## text
- \\## text
- \\ text
- \\
- \\## text
- \\
- \\## text
- \\ text
- \\
- \\## text
- \\ text
- \\
- ,
- \\.document
- \\ .heading
- \\ .marker
- \\ "#"
- \\ .text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "#"
- \\ .text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "#"
- \\ .text
- \\ "text"
- \\ .space_text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "#"
- \\ .text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "#"
- \\ .text
- \\ "text"
- \\ .space_text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "#"
- \\ .text
- \\ "text"
- \\ .space_text
- \\ " text"
- \\ .heading
- \\ .marker
- \\ "##"
- \\ .text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "##"
- \\ .text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "##"
- \\ .text
- \\ "text"
- \\ .space_text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "##"
- \\ .text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "##"
- \\ .text
- \\ "text"
- \\ .space_text
- \\ "text"
- \\ .heading
- \\ .marker
- \\ "##"
- \\ .text
- \\ "text"
- \\ .space_text
- \\ " text"
- \\
- );
+ try testSnapshot("src/test/heading.my");
}
test "Happy path quote" {
- try testParse(
- \\> text
- \\ text
- \\
- \\> text
- \\ text
- \\> text
- \\> text
- \\text
- \\
- ,
- \\.document
- \\ .quote
- \\ .paragraph
- \\ .text
- \\ "text"
- \\ .space_text
- \\ "text"
- \\ .quote
- \\ .paragraph
- \\ .text
- \\ "text"
- \\ .space_text
- \\ " text"
- \\ .quote
- \\ .paragraph
- \\ .text
- \\ "text"
- \\ .quote
- \\ .paragraph
- \\ .text
- \\ "text"
- \\ .paragraph
- \\ .text
- \\ "text"
- \\
- );
+ try testSnapshot("src/test/quote.my");
}
test "Happy path list" {
- try testParseWithFn(
- \\- text
- \\- [ ] text
- \\. text
- \\: text
- \\-- text
- \\-- [ ] text
- \\.. text
- \\:: text
- \\
- ,
- \\.document
- \\ .list
- \\ .unordered_item
- \\ .marker
- \\ "-"
- \\ .text
- \\ "text"
- \\ .list
- \\ .task_item
- \\ .marker
- \\ "- [ ]"
- \\ .text
- \\ "text"
- \\ .list
- \\ .ordered_item
- \\ .marker
- \\ "."
- \\ .text
- \\ "text"
- \\ .list
- \\ .term_item
- \\ .marker
- \\ ":"
- \\ .text
- \\ "text"
- \\ .list
- \\ .unordered_item
- \\ .marker
- \\ "--"
- \\ .text
- \\ "text"
- \\ .list
- \\ .task_item
- \\ .marker
- \\ "-- [ ]"
- \\ .text
- \\ "text"
- \\ .list
- \\ .ordered_item
- \\ .marker
- \\ ".."
- \\ .text
- \\ "text"
- \\ .list
- \\ .term_item
- \\ .marker
- \\ "::"
- \\ .text
- \\ "text"
- \\
- , parse3);
-}
-
-test "List grouping" {
- try testParseWithFn(
- \\- text
- \\- text
- \\-- text
- \\- text
- \\
- \\- text
- \\paragraph
- \\- text
- \\. text
- \\
- ,
- \\.document
- \\ .list
- \\ .unordered_item
- \\ .marker
- \\ "-"
- \\ .text
- \\ "text"
- \\ .unordered_item
- \\ .marker
- \\ "-"
- \\ .text
- \\ "text"
- \\ .unordered_item
- \\ .marker
- \\ "--"
- \\ .text
- \\ "text"
- \\ .unordered_item
- \\ .marker
- \\ "-"
- \\ .text
- \\ "text"
- \\ .unordered_item
- \\ .marker
- \\ "-"
- \\ .text
- \\ "text"
- \\ .paragraph
- \\ .text
- \\ "paragraph"
- \\ .list
- \\ .unordered_item
- \\ .marker
- \\ "-"
- \\ .text
- \\ "text"
- \\ .list
- \\ .ordered_item
- \\ .marker
- \\ "."
- \\ .text
- \\ "text"
- \\
- , parse3);
+ try testSnapshot("src/test/list.my");
}
test "Happy path list elaboration" {
- try testParseWithFn(
- \\- a
- \\+ bb
- \\
- \\ ccc
- \\+ dddd
- \\## heading
- \\++ subtitle
- \\
- ,
- \\.document
- \\ .list
- \\ .unordered_item
- \\ .marker
- \\ "-"
- \\ .text
- \\ "a"
- \\ .elaboration
- \\ .marker
- \\ "+"
- \\ .paragraph
- \\ .text
- \\ "bb"
- \\ .paragraph
- \\ .text
- \\ "ccc"
- \\ .elaboration
- \\ .marker
- \\ "+"
- \\ .paragraph
- \\ .text
- \\ "dddd"
- \\ .heading
- \\ .marker
- \\ "##"
- \\ .text
- \\ "heading"
- \\ .elaboration
- \\ .marker
- \\ "++"
- \\ .paragraph
- \\ .text
- \\ "subtitle"
- \\
- , parse3);
-}
-
-test "Elaboration errors" {
- try testParseWithFn(
- \\- a
- \\++ bb
- \\-- ccc
- \\+ dddd
- \\paragraph
- \\+ eeeee
- \\
- ,
- \\.document
- \\ .list
- \\ .unordered_item
- \\ .error .incorrect_elaboration_marker
- \\ .marker
- \\ "-"
- \\ .text
- \\ "a"
- \\ .elaboration
- \\ .marker
- \\ "++"
- \\ .paragraph
- \\ .text
- \\ "bb"
- \\ .unordered_item
- \\ .error .incorrect_elaboration_marker
- \\ .marker
- \\ "--"
- \\ .text
- \\ "ccc"
- \\ .elaboration
- \\ .marker
- \\ "+"
- \\ .paragraph
- \\ .text
- \\ "dddd"
- \\ .paragraph
- \\ .text
- \\ "paragraph"
- \\ .elaboration
- \\ .error .elaboration_after_unelaboratable_node
- \\ .marker
- \\ "+"
- \\ .paragraph
- \\ .text
- \\ "eeeee"
- \\
- , parse3);
+ try testSnapshot("src/test/elaboration.my");
}
test "Thematic break" {
- try testParse(
- \\a
- \\***
- \\bb
- \\*
- \\ccc
- \\
- \\**bold text**
- \\
- ,
- \\.document
- \\ .paragraph
- \\ .text
- \\ "a"
- \\ .thematic_break
- \\ "***"
- \\ .paragraph
- \\ .text
- \\ "bb"
- \\ .space_text
- \\ "*"
- \\ .space_text
- \\ "ccc"
- \\ .paragraph
- \\ .text
- \\ "**bold text**"
- \\
- );
-}
-
-test "Mixed indentation" {
- // AstGen1 used to try very hard to recover when it sees a tab
- try testParseWithFn("" ++
- "> aaa\n" ++
- "\n" ++
- "\tbbbbb\n",
- \\.document
- \\ .quote
- \\ .error .inconsistent_indentation at 3:1
- \\ .paragraph
- \\ .text
- \\ "aaa"
- \\ .paragraph
- \\ .text
- \\ "bbbbb"
- \\
- , parse);
-
- try testParseWithFn("" ++
- "> aaa\n" ++
- "\n" ++
- "\tbbbbb\n",
- \\.document
- \\ .quote
- \\ .paragraph
- \\ .text
- \\ "aaa"
- \\ .paragraph
- \\ .error .inconsistent_indentation at 3:1
- \\ .text
- \\ "bbbbb"
- \\
- , parse3);
-}
-
-test "Tabs in text" {
- try testParse("" ++
- "aaa\n" ++
- "\tbbbbb\n",
- \\.document
- \\ .paragraph
- \\ .text
- \\ "aaa"
- \\ .space_text
- \\ "\tbbbbb"
- \\
- );
-}
-
-test "Empty line in heading" {
- try testParse(
- \\# heading
- \\
- \\ text
- \\
- \\text
- \\
- ,
- \\.document
- \\ .heading
- \\ .marker
- \\ "#"
- \\ .text
- \\ "heading"
- \\ .space_text
- \\ .error .unexpected_block_in_inline_context
- \\ "text"
- \\ .paragraph
- \\ .text
- \\ "text"
- \\
- );
+ try testSnapshot("src/test/thematic_break.my");
}
test "Super long line" {
- const input = try std.testing.allocator.create([(1 << 24) * 4]u8);
+ const input = try std.testing.allocator.create([(1 << 24) * 4 + PADDING + 1]u8);
defer std.testing.allocator.destroy(input);
- @memset(input, 'a');
+ @memset(input[0 .. (1 << 24) * 4], 'a');
+ @memset(input[(1 << 24) * 4 ..], '\n');
var arena: ArenaAllocator = .init(std.testing.allocator);
defer arena.deinit();
- const ast = try parse(std.testing.allocator, arena.allocator(), input);
+ const ast = try parse3(std.testing.allocator, arena.allocator(), input);
const taggedAst = try ast.toTagged(arena.allocator());
try std.testing.expectEqualDeep(@as(Ast.Tagged, .{
.nodes = &.{
.{ .document = .{ .num_children = 1 } },
- .{ .paragraph = .{ .off = 0, .num_children = 1 } },
+ .{ .paragraph = .{ .off = 0, .num_children = 5 } },
.{ .text = .{ .off = 0, .len = 16777215 } },
.{ .text = .{ .off = 16777215, .len = 16777215 } },
.{ .text = .{ .off = 33554430, .len = 16777215 } },
@@ -583,7 +111,7 @@ test "Many short lines" {
var arena: ArenaAllocator = .init(std.testing.allocator);
defer arena.deinit();
- const ast = try parse(std.testing.allocator, arena.allocator(), input);
+ const ast = try parse3(std.testing.allocator, arena.allocator(), input);
try std.testing.expectEqual(1 << 24, ast.nodes.len);
try std.testing.expectEqual(
diff --git a/src/test/elaboration.my b/src/test/elaboration.my
@@ -0,0 +1,14 @@
+- a
++ bb
+
+ ccc
++ dddd
+## heading
+++ subtitle
+
+- a
+++ bb
+-- ccc
++ dddd
+paragraph
++ eeeee
diff --git a/src/test/elaboration.my.ast b/src/test/elaboration.my.ast
@@ -0,0 +1,68 @@
+.document
+ .list
+ .unordered_item
+ .marker
+ "-"
+ .text
+ "a"
+ .elaboration
+ .marker
+ "+"
+ .paragraph
+ .text
+ "bb"
+ .paragraph
+ .text
+ "ccc"
+ .elaboration
+ .marker
+ "+"
+ .paragraph
+ .text
+ "dddd"
+ .heading
+ .marker
+ "##"
+ .text
+ "heading"
+ .elaboration
+ .marker
+ "++"
+ .paragraph
+ .text
+ "subtitle"
+ .list
+ .unordered_item
+ .error .incorrect_elaboration_marker
+ .marker
+ "-"
+ .text
+ "a"
+ .elaboration
+ .marker
+ "++"
+ .paragraph
+ .text
+ "bb"
+ .unordered_item
+ .error .incorrect_elaboration_marker
+ .marker
+ "--"
+ .text
+ "ccc"
+ .elaboration
+ .marker
+ "+"
+ .paragraph
+ .text
+ "dddd"
+ .paragraph
+ .text
+ "paragraph"
+ .elaboration
+ .error .elaboration_after_unelaboratable_node
+ .marker
+ "+"
+ .paragraph
+ .text
+ "eeeee"
diff --git a/src/test/empty.my b/src/test/empty.my
diff --git a/src/test/empty.my.ast b/src/test/empty.my.ast
@@ -0,0 +1 @@
+.document
diff --git a/src/test/heading.my b/src/test/heading.my
@@ -0,0 +1,31 @@
+# text
+# text
+# text
+ text
+
+# text
+
+# text
+ text
+
+# text
+ text
+
+## text
+## text
+## text
+ text
+
+## text
+
+## text
+ text
+
+## text
+ text
+
+# heading
+
+ text
+
+text
diff --git a/src/test/heading.my.ast b/src/test/heading.my.ast
@@ -0,0 +1,84 @@
+.document
+ .heading
+ .marker
+ "#"
+ .text
+ "text"
+ .heading
+ .marker
+ "#"
+ .text
+ "text"
+ .heading
+ .marker
+ "#"
+ .text
+ "text"
+ .space_text
+ "text"
+ .heading
+ .marker
+ "#"
+ .text
+ "text"
+ .heading
+ .marker
+ "#"
+ .text
+ "text"
+ .space_text
+ "text"
+ .heading
+ .marker
+ "#"
+ .text
+ "text"
+ .space_text
+ " text"
+ .heading
+ .marker
+ "##"
+ .text
+ "text"
+ .heading
+ .marker
+ "##"
+ .text
+ "text"
+ .heading
+ .marker
+ "##"
+ .text
+ "text"
+ .space_text
+ "text"
+ .heading
+ .marker
+ "##"
+ .text
+ "text"
+ .heading
+ .marker
+ "##"
+ .text
+ "text"
+ .space_text
+ "text"
+ .heading
+ .marker
+ "##"
+ .text
+ "text"
+ .space_text
+ " text"
+ .heading
+ .marker
+ "#"
+ .text
+ "heading"
+ .space_text
+ .error .unexpected_block_in_inline_context
+ "text"
+ .paragraph
+ .text
+ "text"
diff --git a/src/test/list.my b/src/test/list.my
@@ -0,0 +1,18 @@
+- text
+- [ ] text
+. text
+: text
+-- text
+-- [ ] text
+.. text
+:: text
+
+- text
+- text
+-- text
+- text
+
+- text
+paragraph
+- text
+. text
diff --git a/src/test/list.my.ast b/src/test/list.my.ast
@@ -0,0 +1,90 @@
+.document
+ .list
+ .unordered_item
+ .marker
+ "-"
+ .text
+ "text"
+ .list
+ .task_item
+ .marker
+ "- [ ]"
+ .text
+ "text"
+ .list
+ .ordered_item
+ .marker
+ "."
+ .text
+ "text"
+ .list
+ .term_item
+ .marker
+ ":"
+ .text
+ "text"
+ .list
+ .unordered_item
+ .marker
+ "--"
+ .text
+ "text"
+ .list
+ .task_item
+ .marker
+ "-- [ ]"
+ .text
+ "text"
+ .list
+ .ordered_item
+ .marker
+ ".."
+ .text
+ "text"
+ .list
+ .term_item
+ .marker
+ "::"
+ .text
+ "text"
+ .list
+ .unordered_item
+ .marker
+ "-"
+ .text
+ "text"
+ .unordered_item
+ .marker
+ "-"
+ .text
+ "text"
+ .unordered_item
+ .marker
+ "--"
+ .text
+ "text"
+ .unordered_item
+ .marker
+ "-"
+ .text
+ "text"
+ .unordered_item
+ .marker
+ "-"
+ .text
+ "text"
+ .paragraph
+ .text
+ "paragraph"
+ .list
+ .unordered_item
+ .marker
+ "-"
+ .text
+ "text"
+ .list
+ .ordered_item
+ .marker
+ "."
+ .text
+ "text"
diff --git a/src/test/paragraph.my b/src/test/paragraph.my
@@ -0,0 +1,7 @@
+text
+
+text
+text
+
+text
+ text
diff --git a/src/test/paragraph.my.ast b/src/test/paragraph.my.ast
@@ -0,0 +1,14 @@
+.document
+ .paragraph
+ .text
+ "text"
+ .paragraph
+ .text
+ "text"
+ .space_text
+ "text"
+ .paragraph
+ .text
+ "text"
+ .space_text
+ " text"
diff --git a/src/test/quote.my b/src/test/quote.my
@@ -0,0 +1,8 @@
+> text
+ text
+
+> text
+ text
+> text
+> text
+text
diff --git a/src/test/quote.my.ast b/src/test/quote.my.ast
@@ -0,0 +1,24 @@
+.document
+ .quote
+ .paragraph
+ .text
+ "text"
+ .space_text
+ "text"
+ .quote
+ .paragraph
+ .text
+ "text"
+ .space_text
+ " text"
+ .quote
+ .paragraph
+ .text
+ "text"
+ .quote
+ .paragraph
+ .text
+ "text"
+ .paragraph
+ .text
+ "text"
diff --git a/src/test/thematic_break.my b/src/test/thematic_break.my
@@ -0,0 +1,7 @@
+a
+***
+bb
+*
+ccc
+
+**bold text**
diff --git a/src/test/thematic_break.my.ast b/src/test/thematic_break.my.ast
@@ -0,0 +1,16 @@
+.document
+ .paragraph
+ .text
+ "a"
+ .thematic_break
+ "***"
+ .paragraph
+ .text
+ "bb"
+ .space_text
+ "*"
+ .space_text
+ "ccc"
+ .paragraph
+ .text
+ "**bold text**"