mymarkdown

My markdown
git clone https://git.grace.moe/mymarkdown
Log | Files | Refs

test.zig (8750B)


      1 const std = @import("std");
      2 const parse = @import("AstGen.zig").parse;
      3 const Ast = @import("Ast.zig");
      4 const PADDING = @import("padded_str.zig").PADDING;
      5 
      6 const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator(.{});
      7 const ArenaAllocator = std.heap.ArenaAllocator;
      8 
      9 fn readFile(gpa: std.mem.Allocator, path: []const u8) !std.ArrayList(u8) {
     10     var input_instance: std.ArrayList(u8) = .init(gpa);
     11     errdefer input_instance.deinit();
     12     const input_file = try std.fs.cwd().openFile(path, .{});
     13     defer input_file.close();
     14     const file_size = (try input_file.stat()).size;
     15     try input_instance.ensureTotalCapacity(file_size + PADDING + 1);
     16     try input_file.reader().readAllArrayList(&input_instance, std.math.maxInt(u32) - PADDING - 1);
     17     return input_instance;
     18 }
     19 
     20 fn testForCrashes(gpa: std.mem.Allocator, input: []const u8) !void {
     21     const padded_input = try std.mem.concat(gpa, u8, &.{ input, "\n" ** (PADDING + 1) });
     22     defer gpa.free(padded_input);
     23 
     24     const ast = try parse(gpa, null, padded_input);
     25     defer ast.deinit(gpa);
     26 
     27     var output_instance: std.ArrayList(u8) = .init(gpa);
     28     defer output_instance.deinit();
     29     try ast.renderAst(output_instance.writer(), padded_input);
     30 }
     31 
     32 fn testSnapshot(gpa: std.mem.Allocator, path: []const u8) !void {
     33     return testSnapshotImpl(gpa, path);
     34     // std.testing.checkAllAllocationFailures(
     35     //     gpa,
     36     //     testSnapshotImpl,
     37     //     .{path},
     38     // ) catch |err| if (err != error.SwallowedOutOfMemoryError)
     39     //     return err;
     40 }
     41 fn testSnapshotImpl(gpa: std.mem.Allocator, path: []const u8) !void {
     42     const snapshot_path = try std.mem.concat(gpa, u8, &.{ path, ".ast" });
     43     defer gpa.free(snapshot_path);
     44     const wrong_path = try std.mem.concat(gpa, u8, &.{ path, ".wrong.ast" });
     45     defer gpa.free(wrong_path);
     46 
     47     var input_instance = try readFile(gpa, path);
     48     defer input_instance.deinit();
     49     try input_instance.appendNTimes('\n', PADDING + 1);
     50 
     51     const ast = try parse(gpa, null, input_instance.items);
     52     defer ast.deinit(gpa);
     53     // const ast2 = try parse3(gpa, gpa, input_instance.items);
     54     // defer ast2.deinit(gpa);
     55 
     56     var output_instance: std.ArrayList(u8) = .init(gpa);
     57     defer output_instance.deinit();
     58     try ast.renderAst(output_instance.writer(), input_instance.items);
     59 
     60     var snapshot_instance: std.ArrayList(u8) = readFile(gpa, snapshot_path) catch |err| {
     61         const wrong_file = try std.fs.cwd().createFile(wrong_path, .{});
     62         defer wrong_file.close();
     63         try wrong_file.writer().writeAll(output_instance.items);
     64         std.debug.print(
     65             \\Snapshot could not be loaded for {[path]s} due to error {[err]}.
     66             \\
     67             \\Generated output written to {[wrong_path]s}.
     68             \\
     69             \\If generated output looks good:
     70             \\
     71             \\    mv {[wrong_path]s} {[snapshot_path]s}
     72             \\
     73             \\
     74         , .{ .path = path, .wrong_path = wrong_path, .snapshot_path = snapshot_path, .err = err });
     75         return err;
     76     };
     77     defer snapshot_instance.deinit();
     78 
     79     if (!std.mem.eql(u8, snapshot_instance.items, output_instance.items)) {
     80         const wrong_file = try std.fs.cwd().createFile(wrong_path, .{});
     81         defer wrong_file.close();
     82         try wrong_file.writer().writeAll(output_instance.items);
     83         std.debug.print(
     84             \\Snapshot test for {[path]s} failed.
     85             \\
     86             \\Generated output written to {[wrong_path]s}.
     87             \\If changes are expected, copy {[wrong_path]s} to {[snapshot_path]s}.
     88             \\
     89             \\Diff changes with your favourite diff viewer:
     90             \\
     91             \\    diff {[snapshot_path]s} {[wrong_path]s}
     92             \\    git diff --no-index -- {[snapshot_path]s} {[wrong_path]s}
     93             \\
     94             \\If changes are expected:
     95             \\
     96             \\    mv {[wrong_path]s} {[snapshot_path]s}
     97             \\
     98             \\
     99         , .{ .path = path, .wrong_path = wrong_path, .snapshot_path = snapshot_path });
    100         return error.TestFailed;
    101     }
    102 }
    103 
    104 test "empty" {
    105     try testSnapshot(std.testing.allocator, "src/test/empty.my");
    106 }
    107 
    108 test "Happy path paragraph" {
    109     try testSnapshot(std.testing.allocator, "src/test/paragraph.my");
    110 }
    111 
    112 test "Happy path headings" {
    113     try testSnapshot(std.testing.allocator, "src/test/heading.my");
    114 }
    115 
    116 test "Happy path quote" {
    117     try testSnapshot(std.testing.allocator, "src/test/quote.my");
    118 }
    119 
    120 test "Happy path list" {
    121     try testSnapshot(std.testing.allocator, "src/test/list.my");
    122 }
    123 
    124 test "Happy path list elaboration" {
    125     try testSnapshot(std.testing.allocator, "src/test/elaboration.my");
    126 }
    127 
    128 test "Thematic break" {
    129     try testSnapshot(std.testing.allocator, "src/test/thematic_break.my");
    130 }
    131 
    132 test "Sample" {
    133     try testSnapshot(std.testing.allocator, "src/test/sample.my");
    134 }
    135 
    136 test "fuzz" {
    137     var arena_instance: std.heap.ArenaAllocator = .init(std.testing.allocator);
    138     defer arena_instance.deinit();
    139     const arena = arena_instance.allocator();
    140     try std.testing.fuzz(std.testing.allocator, testForCrashes, .{
    141         .corpus = &.{
    142             // (try readFile(arena, "src/test/empty.my")).items,
    143             (try readFile(arena, "src/test/paragraph.my")).items,
    144             (try readFile(arena, "src/test/heading.my")).items,
    145             (try readFile(arena, "src/test/quote.my")).items,
    146             (try readFile(arena, "src/test/list.my")).items,
    147             (try readFile(arena, "src/test/elaboration.my")).items,
    148             (try readFile(arena, "src/test/thematic_break.my")).items,
    149             (try readFile(arena, "src/test/sample.my")).items,
    150         },
    151     });
    152 }
    153 
    154 test "Super long line" {
    155     const input = try std.testing.allocator.create([(1 << 24) * 4 + PADDING + 1]u8);
    156     defer std.testing.allocator.destroy(input);
    157     @memset(input[0 .. (1 << 24) * 4], 'a');
    158     @memset(input[(1 << 24) * 4 ..], '\n');
    159     var arena: ArenaAllocator = .init(std.testing.allocator);
    160     defer arena.deinit();
    161     const ast = try parse(std.testing.allocator, arena.allocator(), input);
    162     try std.testing.expectEqual(7, ast.nodes.len);
    163     try std.testing.expectEqual(0, ast.errors.len);
    164     try std.testing.expectEqual(.document, ast.nodes[0].tag);
    165     try std.testing.expectEqual(0, ast.nodes[0].off);
    166     try std.testing.expectEqual(1, ast.nodes[0].numChildren());
    167     try std.testing.expectEqual(.paragraph, ast.nodes[1].tag);
    168     try std.testing.expectEqual(0, ast.nodes[1].off);
    169     try std.testing.expectEqual(5, ast.nodes[1].numChildren());
    170     try std.testing.expectEqual(.text, ast.nodes[2].tag);
    171     try std.testing.expectEqual(0, ast.nodes[2].off);
    172     try std.testing.expectEqual(16777215, ast.nodes[2].len());
    173     try std.testing.expectEqual(.text, ast.nodes[3].tag);
    174     try std.testing.expectEqual(16777215, ast.nodes[3].off);
    175     try std.testing.expectEqual(16777215, ast.nodes[3].len());
    176     try std.testing.expectEqual(.text, ast.nodes[4].tag);
    177     try std.testing.expectEqual(33554430, ast.nodes[4].off);
    178     try std.testing.expectEqual(16777215, ast.nodes[4].len());
    179     try std.testing.expectEqual(.text, ast.nodes[5].tag);
    180     try std.testing.expectEqual(50331645, ast.nodes[5].off);
    181     try std.testing.expectEqual(16777215, ast.nodes[5].len());
    182     try std.testing.expectEqual(.text, ast.nodes[6].tag);
    183     try std.testing.expectEqual(67108860, ast.nodes[6].off);
    184     try std.testing.expectEqual(4, ast.nodes[6].len());
    185 }
    186 
    187 test "Many short lines" {
    188     const input = try std.testing.allocator.create([(1 << 25) - 4 + PADDING]u8);
    189     defer std.testing.allocator.destroy(input);
    190     @memset(@as(*[(1 << 24) - 2][2]u8, @ptrCast(input)), "a\n"[0..2].*);
    191     @memset(input[(1 << 25) - 4 ..], '\n');
    192 
    193     var arena: ArenaAllocator = .init(std.testing.allocator);
    194     defer arena.deinit();
    195     const ast = try parse(std.testing.allocator, arena.allocator(), input);
    196 
    197     try std.testing.expectEqual(1 << 24, ast.nodes.len);
    198     try std.testing.expectEqual(0, ast.errors.len);
    199     try std.testing.expectEqual(.document, ast.nodes[0].tag);
    200     try std.testing.expectEqual(0, ast.nodes[0].off);
    201     try std.testing.expectEqual(1, ast.nodes[0].numChildren());
    202     try std.testing.expectEqual(.paragraph, ast.nodes[1].tag);
    203     try std.testing.expectEqual(0, ast.nodes[1].off);
    204     try std.testing.expectEqual((1 << 24) - 2, ast.nodes[1].numChildren());
    205     try std.testing.expectEqual(.text, ast.nodes[2].tag);
    206     try std.testing.expectEqual(0, ast.nodes[2].off);
    207     try std.testing.expectEqual(1, ast.nodes[2].len());
    208     for (1..(1 << 24) - 2) |i| {
    209         try std.testing.expectEqual(.space_text, ast.nodes[i + 2].tag);
    210         try std.testing.expectEqual(i * 2, ast.nodes[i + 2].off);
    211         try std.testing.expectEqual(1, ast.nodes[i + 2].len());
    212     }
    213 }