atproto utils for zig
zat.dev
atproto
sdk
zig
1const std = @import("std");
2const cbor = @import("cbor.zig");
3
4const writeArg = cbor.writeArg;
5const writeText = cbor.writeText;
6const writeBytes = cbor.writeBytes;
7const writeUint = cbor.writeUint;
8const writeInt = cbor.writeInt;
9const writeMapHeader = cbor.writeMapHeader;
10const writeArrayHeader = cbor.writeArrayHeader;
11const writeBool = cbor.writeBool;
12const writeNull = cbor.writeNull;
13const writeCidLink = cbor.writeCidLink;
14
15const readArg = cbor.readArg;
16const readText = cbor.readText;
17const readBytes = cbor.readBytes;
18const readUint = cbor.readUint;
19const readInt = cbor.readInt;
20const readBool = cbor.readBool;
21const readNull = cbor.readNull;
22const readMapHeader = cbor.readMapHeader;
23const readArrayHeader = cbor.readArrayHeader;
24const readCidLink = cbor.readCidLink;
25
26const decodeAll = cbor.decodeAll;
27
28// ===========================================================================
29// writeArg
30// ===========================================================================
31
32test "writeArg: value 0 (1 byte)" {
33 var buf: [16]u8 = undefined;
34 const end = writeArg(&buf, 0, 0, 0);
35 try std.testing.expectEqual(@as(usize, 1), end);
36 try std.testing.expectEqual(@as(u8, 0x00), buf[0]);
37}
38
39test "writeArg: value 23 (1 byte)" {
40 var buf: [16]u8 = undefined;
41 const end = writeArg(&buf, 0, 0, 23);
42 try std.testing.expectEqual(@as(usize, 1), end);
43 try std.testing.expectEqual(@as(u8, 0x17), buf[0]);
44}
45
46test "writeArg: value 24 (2 bytes)" {
47 var buf: [16]u8 = undefined;
48 const end = writeArg(&buf, 0, 0, 24);
49 try std.testing.expectEqual(@as(usize, 2), end);
50 try std.testing.expectEqual(@as(u8, 0x18), buf[0]);
51 try std.testing.expectEqual(@as(u8, 24), buf[1]);
52}
53
54test "writeArg: value 1000 (3 bytes)" {
55 var buf: [16]u8 = undefined;
56 const end = writeArg(&buf, 0, 0, 1000);
57 try std.testing.expectEqual(@as(usize, 3), end);
58 try std.testing.expectEqual(@as(u8, 0x19), buf[0]);
59 try std.testing.expectEqual(@as(u8, 0x03), buf[1]);
60 try std.testing.expectEqual(@as(u8, 0xe8), buf[2]);
61}
62
63// ===========================================================================
64// writeText round-trip
65// ===========================================================================
66
67test "writeText: 'hello' round-trip" {
68 var buf: [64]u8 = undefined;
69 const end = writeText(&buf, 0, "hello");
70 const result = try readText(&buf, 0);
71 try std.testing.expectEqualStrings("hello", result.val);
72 try std.testing.expectEqual(end, result.end);
73}
74
75// ===========================================================================
76// writeBytes round-trip
77// ===========================================================================
78
79test "writeBytes: [1,2,3] round-trip" {
80 var buf: [64]u8 = undefined;
81 const input = [_]u8{ 1, 2, 3 };
82 const end = writeBytes(&buf, 0, &input);
83 const result = try readBytes(&buf, 0);
84 try std.testing.expectEqual(@as(usize, 3), result.val.len);
85 try std.testing.expectEqual(@as(u8, 1), result.val[0]);
86 try std.testing.expectEqual(@as(u8, 2), result.val[1]);
87 try std.testing.expectEqual(@as(u8, 3), result.val[2]);
88 try std.testing.expectEqual(end, result.end);
89}
90
91// ===========================================================================
92// writeUint round-trip
93// ===========================================================================
94
95test "writeUint: 42 round-trip" {
96 var buf: [16]u8 = undefined;
97 const end = writeUint(&buf, 0, 42);
98 const result = try readUint(&buf, 0);
99 try std.testing.expectEqual(@as(u64, 42), result.val);
100 try std.testing.expectEqual(end, result.end);
101}
102
103// ===========================================================================
104// writeInt
105// ===========================================================================
106
107test "writeInt: -10 verify bytes" {
108 var buf: [16]u8 = undefined;
109 const end = writeInt(&buf, 0, -10);
110 try std.testing.expectEqual(@as(usize, 1), end);
111 try std.testing.expectEqual(@as(u8, 0x29), buf[0]);
112}
113
114test "writeInt: positive 42 round-trip" {
115 var buf: [16]u8 = undefined;
116 const end = writeInt(&buf, 0, 42);
117 const result = try readInt(&buf, 0);
118 try std.testing.expectEqual(@as(i64, 42), result.val);
119 try std.testing.expectEqual(end, result.end);
120}
121
122// ===========================================================================
123// writeMapHeader
124// ===========================================================================
125
126test "writeMapHeader: count 3 verify byte" {
127 var buf: [16]u8 = undefined;
128 const end = writeMapHeader(&buf, 0, 3);
129 try std.testing.expectEqual(@as(usize, 1), end);
130 try std.testing.expectEqual(@as(u8, 0xa3), buf[0]);
131}
132
133// ===========================================================================
134// writeArrayHeader
135// ===========================================================================
136
137test "writeArrayHeader: count 2 verify byte" {
138 var buf: [16]u8 = undefined;
139 const end = writeArrayHeader(&buf, 0, 2);
140 try std.testing.expectEqual(@as(usize, 1), end);
141 try std.testing.expectEqual(@as(u8, 0x82), buf[0]);
142}
143
144// ===========================================================================
145// writeBool
146// ===========================================================================
147
148test "writeBool: true and false consecutive" {
149 var buf: [16]u8 = undefined;
150 var p = writeBool(&buf, 0, true);
151 p = writeBool(&buf, p, false);
152 try std.testing.expectEqual(@as(u8, 0xf5), buf[0]);
153 try std.testing.expectEqual(@as(u8, 0xf4), buf[1]);
154 try std.testing.expectEqual(@as(usize, 2), p);
155
156 const r1 = try readBool(&buf, 0);
157 try std.testing.expectEqual(true, r1.val);
158 const r2 = try readBool(&buf, r1.end);
159 try std.testing.expectEqual(false, r2.val);
160}
161
162// ===========================================================================
163// writeNull
164// ===========================================================================
165
166test "writeNull: verify byte" {
167 var buf: [16]u8 = undefined;
168 const end = writeNull(&buf, 0);
169 try std.testing.expectEqual(@as(usize, 1), end);
170 try std.testing.expectEqual(@as(u8, 0xf6), buf[0]);
171 // round-trip
172 const read_end = try readNull(&buf, 0);
173 try std.testing.expectEqual(end, read_end);
174}
175
176// ===========================================================================
177// writeCidLink round-trip
178// ===========================================================================
179
180test "writeCidLink: round-trip" {
181 var buf: [128]u8 = undefined;
182 const cid_raw = [_]u8{ 0x01, 0x71, 0x12, 0x20 } ++ [_]u8{0xaa} ** 32;
183 const end = writeCidLink(&buf, 0, &cid_raw);
184 const result = try readCidLink(&buf, 0);
185 try std.testing.expectEqual(@as(usize, 36), result.val.len);
186 try std.testing.expectEqualSlices(u8, &cid_raw, result.val);
187 try std.testing.expectEqual(end, result.end);
188}
189
190// ===========================================================================
191// Full record: manually write {"text": "hello", "value": 42} then decodeAll
192// ===========================================================================
193
194test "full record: write map then decodeAll" {
195 var buf: [128]u8 = undefined;
196 // DAG-CBOR sorts keys by length then lex: "text" (4) < "value" (5)
197 var p: usize = 0;
198 p = writeMapHeader(&buf, p, 2);
199 p = writeText(&buf, p, "text");
200 p = writeText(&buf, p, "hello");
201 p = writeText(&buf, p, "value");
202 p = writeUint(&buf, p, 42);
203
204 const encoded = buf[0..p];
205
206 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
207 defer arena.deinit();
208 const decoded = try decodeAll(arena.allocator(), encoded);
209
210 try std.testing.expectEqualStrings("hello", decoded.getString("text").?);
211 try std.testing.expectEqual(@as(u64, 42), decoded.getUint("value").?);
212}