lib/zen/src/diagram/test.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const subject = @import("root.zig");
3 const ascii_test = @import("ascii/test.zig");
4 const document_test = @import("document/test.zig");
5 const ego_test = @import("ego/test.zig");
6 const Document = subject.Document;
7 const AsciiRenderPlan = subject.AsciiRenderPlan;
8 const AsciiRenderCapacity = subject.AsciiRenderCapacity;
9 const AsciiRenderStorage = subject.AsciiRenderStorage;
10 const DocumentPlan = subject.DocumentPlan;
11 const DocumentCapacity = subject.DocumentCapacity;
12 const DocumentStorage = subject.DocumentStorage;
13 const parse = subject.parse;
14 const renderAsciiOwned = subject.renderAsciiOwned;
15 const renderAsciiDocument = subject.renderAsciiDocument;
16
17 test "diagram root exposes bounded ASCII rendering controls" {
18 comptime {
19 @stardustClaim(
20 @import("alloc_phase").capacity.witness(@import("./ascii/root.zig").RenderStorage, "zen_ascii_render_root"),
21 null,
22 null,
23 null,
24 null,
25 null,
26 null,
27 );
28 }
29
30 var empty_document = Document{ .allocator = std.testing.allocator };
31 defer empty_document.deinit();
32 const plan = try AsciiRenderPlan.inspect(&empty_document, .{ .width = 24, .height = 8 });
33 var storage = try AsciiRenderStorage.init(std.testing.allocator, plan.exactLimits());
34 defer storage.deinit(std.testing.allocator);
35 storage.activate();
36 const output = try renderAsciiDocument(&storage, &empty_document, .{ .width = 24, .height = 8 });
37 defer storage.reset();
38 try std.testing.expectEqual(@as(usize, 8), std.mem.count(u8, output, "\n"));
39 try std.testing.expectEqual(
40 (try AsciiRenderCapacity.derive(plan.exactLimits())).storage_bytes,
41 storage.status().storage_bytes,
42 );
43 }
44
45 test "diagram root exposes bounded Document parsing controls" {
46 comptime {
47 @stardustClaim(
48 @import("alloc_phase").capacity.witness(@import("./document/root.zig").Storage, "zen_diagram_document_root"),
49 null,
50 null,
51 null,
52 null,
53 null,
54 null,
55 );
56 }
57
58 const jsonl = "{\"kind\":\"point\",\"x\":1,\"y\":2}";
59 var storage = try DocumentStorage.initExact(std.testing.allocator, jsonl);
60 defer storage.deinit(std.testing.allocator);
61 storage.activate();
62 const parsed = try parse(&storage, jsonl);
63 defer storage.reset();
64 try std.testing.expectEqual(@as(usize, 1), parsed.marks.items.len);
65 try std.testing.expectEqual(
66 (try DocumentCapacity.derive(storage.capacity.limits)).storage_bytes,
67 storage.status().storage_bytes,
68 );
69 }
70
71 fn expectBoundedDocumentError(jsonl: []const u8, expected: anyerror) !void {
72 var storage = DocumentStorage.initExact(std.testing.allocator, jsonl) catch |err| {
73 try std.testing.expectEqualStrings(@errorName(expected), @errorName(err));
74 return;
75 };
76 defer storage.deinit(std.testing.allocator);
77 storage.activate();
78 _ = parse(&storage, jsonl) catch |err| {
79 try std.testing.expectEqualStrings(@errorName(expected), @errorName(err));
80 return;
81 };
82 storage.reset();
83 return error.TestUnexpectedResult;
84 }
85
86 fn expectDocumentParity(jsonl: []const u8) !void {
87 const scratch_bytes = try DocumentPlan.requiredLineScratchBytes(jsonl);
88 const scratch = try std.testing.allocator.alloc(u8, scratch_bytes);
89 defer std.testing.allocator.free(scratch);
90 var raw = Document.parse(std.testing.allocator, scratch, jsonl) catch |err| {
91 return expectBoundedDocumentError(jsonl, err);
92 };
93 defer raw.deinit();
94
95 var storage = try DocumentStorage.initExact(std.testing.allocator, jsonl);
96 defer storage.deinit(std.testing.allocator);
97 storage.activate();
98 const bounded = try parse(&storage, jsonl);
99 defer storage.reset();
100
101 var raw_rendered = try renderAsciiOwned(
102 std.testing.allocator,
103 &raw,
104 .{ .width = 48, .height = 14 },
105 );
106 defer raw_rendered.deinit(std.testing.allocator);
107 var bounded_rendered = try renderAsciiOwned(
108 std.testing.allocator,
109 bounded,
110 .{ .width = 48, .height = 14 },
111 );
112 defer bounded_rendered.deinit(std.testing.allocator);
113 try std.testing.expectEqualStrings(raw_rendered.output, bounded_rendered.output);
114 try std.testing.expectEqualStrings(raw.frame.title, bounded.frame.title);
115 try std.testing.expectEqualStrings(raw.frame.x_label, bounded.frame.x_label);
116 try std.testing.expectEqualStrings(raw.frame.y_label, bounded.frame.y_label);
117 try std.testing.expectEqualStrings(raw.frame.background, bounded.frame.background);
118 try std.testing.expectEqualStrings(raw.scales.x.label, bounded.scales.x.label);
119 try std.testing.expectEqualStrings(raw.scales.y.label, bounded.scales.y.label);
120 try std.testing.expectEqual(raw.transforms.items.len, bounded.transforms.items.len);
121 try std.testing.expectEqual(raw.data.items.len, bounded.data.items.len);
122 try std.testing.expectEqual(raw.marks.items.len, bounded.marks.items.len);
123 for (raw.data.items, bounded.data.items) |raw_row, bounded_row| {
124 try std.testing.expectEqualStrings(raw_row.name, bounded_row.name);
125 try std.testing.expectEqual(raw_row.fields.items.len, bounded_row.fields.items.len);
126 for (raw_row.fields.items, bounded_row.fields.items) |raw_field, bounded_field| {
127 try std.testing.expectEqualStrings(raw_field.name, bounded_field.name);
128 }
129 }
130 }
131
132 test "bounded and raw diagram parsing preserve output bytes and errors" {
133 comptime {
134 @stardustClaim(
135 @import("alloc_phase").capacity.witness(@import("./document/root.zig").Storage, "zen_diagram_document_differential"),
136 null,
137 null,
138 null,
139 null,
140 null,
141 null,
142 );
143 }
144
145 const cases = [_][]const u8{
146 "",
147 "{\"kind\":\"point\",\"x\":1,\"y\":2,\"label\":\"one\"}\n",
148 "{\"kind\":\"frame\",\"title\":\"Bytes <&>\",\"x_label\":\"phase\",\"y_label\":\"count\",\"background\":\"#ffffff\"}\n" ++
149 "{\"kind\":\"scale\",\"axis\":\"y\",\"type\":\"linear\",\"min\":1,\"max\":100,\"label\":\"events\"}\n" ++
150 "{\"kind\":\"transform\",\"op\":\"stack\",\"mark\":\"bar\"}\n" ++
151 "{\"kind\":\"bar\",\"x\":\"a\",\"y\":10,\"series\":\"first\",\"label\":\"A\"}\n" ++
152 "{\"kind\":\"rule\",\"x1\":0,\"y1\":1,\"x2\":2,\"y2\":1,\"label\":\"limit\"}\n",
153 "{\"kind\":\"data\",\"name\":\"d\",\"x\":\"alpha\",\"y\":3,\"label\":\"A\",\"enabled\":true}\n" ++
154 "{\"kind\":\"mark\",\"type\":\"bar\",\"data\":\"d\",\"x\":\"x\",\"y\":\"y\",\"label\":\"label\"}\n",
155 "not json",
156 "{\"x\":1}",
157 "[1,2]",
158 "{\"kind\":\"unknown\"}",
159 "{\"kind\":\"bar\",\"x\":\"a\"}",
160 "{\"kind\":\"bar\",\"x\":\"a\",\"y\":1,\"fill\":\"url(x)\"}",
161 "{\"kind\":\"scale\",\"axis\":\"y\",\"type\":\"log\",\"min\":0}",
162 "{\"kind\":\"mark\",\"type\":\"bar\",\"data\":\"missing\",\"x\":\"x\",\"y\":\"y\"}",
163 };
164 for (cases) |jsonl| try expectDocumentParity(jsonl);
165 }
166
167 test {
168 std.testing.refAllDecls(subject);
169 std.testing.refAllDecls(ascii_test);
170 std.testing.refAllDecls(document_test);
171 std.testing.refAllDecls(ego_test);
172 }