1 | //===- MsgPackDocumentTest.cpp --------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/BinaryFormat/MsgPackDocument.h" |
10 | #include "gtest/gtest.h" |
11 | |
12 | using namespace llvm; |
13 | using namespace msgpack; |
14 | |
15 | TEST(MsgPackDocument, DocNodeTest) { |
16 | Document Doc; |
17 | |
18 | DocNode Int1 = Doc.getNode(V: 1), Int2 = Doc.getNode(V: 2); |
19 | DocNode Str1 = Doc.getNode(V: "ab" ), Str2 = Doc.getNode(V: "ab" ); |
20 | |
21 | ASSERT_TRUE(Int1 != Int2); |
22 | ASSERT_TRUE(Str1 == Str2); |
23 | } |
24 | |
25 | TEST(MsgPackDocument, TestReadInt) { |
26 | Document Doc; |
27 | bool Ok = Doc.readFromBlob(Blob: StringRef("\xd0\x00" , 2), /*Multi=*/false); |
28 | ASSERT_TRUE(Ok); |
29 | ASSERT_EQ(Doc.getRoot().getKind(), Type::Int); |
30 | ASSERT_EQ(Doc.getRoot().getInt(), 0); |
31 | } |
32 | |
33 | TEST(MsgPackDocument, TestReadBinary) { |
34 | Document Doc; |
35 | uint8_t data[] = {1, 2, 3, 4}; |
36 | bool Ok = |
37 | Doc.readFromBlob(Blob: StringRef("\xC4\x4\x1\x2\x3\x4" , 6), /*Multi=*/false); |
38 | ASSERT_TRUE(Ok); |
39 | ASSERT_EQ(Doc.getRoot().getKind(), Type::Binary); |
40 | ASSERT_EQ(Doc.getRoot().getBinary().getBuffer(), |
41 | StringRef(reinterpret_cast<const char *>(data), 4)); |
42 | } |
43 | |
44 | TEST(MsgPackDocument, TestReadMergeArray) { |
45 | Document Doc; |
46 | bool Ok = Doc.readFromBlob(Blob: StringRef("\x92\xd0\x01\xc0" ), /*Multi=*/false); |
47 | ASSERT_TRUE(Ok); |
48 | ASSERT_EQ(Doc.getRoot().getKind(), Type::Array); |
49 | auto A = Doc.getRoot().getArray(); |
50 | ASSERT_EQ(A.size(), 2u); |
51 | auto SI = A[0]; |
52 | ASSERT_EQ(SI.getKind(), Type::Int); |
53 | ASSERT_EQ(SI.getInt(), 1); |
54 | auto SN = A[1]; |
55 | ASSERT_EQ(SN.getKind(), Type::Nil); |
56 | |
57 | Ok = Doc.readFromBlob(Blob: StringRef("\x91\xd0\x2a" ), /*Multi=*/false, |
58 | Merger: [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) { |
59 | // Allow array, merging into existing elements, ORing |
60 | // ints. |
61 | if (DestNode->getKind() == Type::Int && |
62 | SrcNode.getKind() == Type::Int) { |
63 | *DestNode = DestNode->getDocument()->getNode( |
64 | V: DestNode->getInt() | SrcNode.getInt()); |
65 | return 0; |
66 | } |
67 | return DestNode->isArray() && SrcNode.isArray() ? 0 |
68 | : -1; |
69 | }); |
70 | ASSERT_TRUE(Ok); |
71 | A = Doc.getRoot().getArray(); |
72 | ASSERT_EQ(A.size(), 2u); |
73 | SI = A[0]; |
74 | ASSERT_EQ(SI.getKind(), Type::Int); |
75 | ASSERT_EQ(SI.getInt(), 43); |
76 | SN = A[1]; |
77 | ASSERT_EQ(SN.getKind(), Type::Nil); |
78 | } |
79 | |
80 | TEST(MsgPackDocument, TestReadAppendArray) { |
81 | Document Doc; |
82 | bool Ok = Doc.readFromBlob(Blob: StringRef("\x92\xd0\x01\xc0" ), /*Multi=*/false); |
83 | ASSERT_TRUE(Ok); |
84 | ASSERT_EQ(Doc.getRoot().getKind(), Type::Array); |
85 | auto A = Doc.getRoot().getArray(); |
86 | ASSERT_EQ(A.size(), 2u); |
87 | auto SI = A[0]; |
88 | ASSERT_EQ(SI.getKind(), Type::Int); |
89 | ASSERT_EQ(SI.getInt(), 1); |
90 | auto SN = A[1]; |
91 | ASSERT_EQ(SN.getKind(), Type::Nil); |
92 | |
93 | Ok = Doc.readFromBlob(Blob: StringRef("\x91\xd0\x2a" ), /*Multi=*/false, |
94 | Merger: [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) { |
95 | // Allow array, appending after existing elements |
96 | return DestNode->isArray() && SrcNode.isArray() |
97 | ? DestNode->getArray().size() |
98 | : -1; |
99 | }); |
100 | ASSERT_TRUE(Ok); |
101 | A = Doc.getRoot().getArray(); |
102 | ASSERT_EQ(A.size(), 3u); |
103 | SI = A[0]; |
104 | ASSERT_EQ(SI.getKind(), Type::Int); |
105 | ASSERT_EQ(SI.getInt(), 1); |
106 | SN = A[1]; |
107 | ASSERT_EQ(SN.getKind(), Type::Nil); |
108 | SI = A[2]; |
109 | ASSERT_EQ(SI.getKind(), Type::Int); |
110 | ASSERT_EQ(SI.getInt(), 42); |
111 | } |
112 | |
113 | TEST(MsgPackDocument, TestReadMergeMap) { |
114 | Document Doc; |
115 | bool Ok = Doc.readFromBlob(Blob: StringRef("\x82\xa3" |
116 | "foo" |
117 | "\xd0\x01\xa3" |
118 | "bar" |
119 | "\xd0\x02" ), |
120 | /*Multi=*/false); |
121 | ASSERT_TRUE(Ok); |
122 | ASSERT_EQ(Doc.getRoot().getKind(), Type::Map); |
123 | auto M = Doc.getRoot().getMap(); |
124 | ASSERT_EQ(M.size(), 2u); |
125 | auto FooS = M["foo" ]; |
126 | ASSERT_EQ(FooS.getKind(), Type::Int); |
127 | ASSERT_EQ(FooS.getInt(), 1); |
128 | auto BarS = M["bar" ]; |
129 | ASSERT_EQ(BarS.getKind(), Type::Int); |
130 | ASSERT_EQ(BarS.getInt(), 2); |
131 | |
132 | Ok = Doc.readFromBlob(Blob: StringRef("\x82\xa3" |
133 | "foz" |
134 | "\xd0\x03\xa3" |
135 | "baz" |
136 | "\xd0\x04" ), |
137 | /*Multi=*/false, |
138 | Merger: [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) { |
139 | return DestNode->isMap() && SrcNode.isMap() ? 0 : -1; |
140 | }); |
141 | ASSERT_TRUE(Ok); |
142 | ASSERT_EQ(M.size(), 4u); |
143 | FooS = M["foo" ]; |
144 | ASSERT_EQ(FooS.getKind(), Type::Int); |
145 | ASSERT_EQ(FooS.getInt(), 1); |
146 | BarS = M["bar" ]; |
147 | ASSERT_EQ(BarS.getKind(), Type::Int); |
148 | ASSERT_EQ(BarS.getInt(), 2); |
149 | auto FozS = M["foz" ]; |
150 | ASSERT_EQ(FozS.getKind(), Type::Int); |
151 | ASSERT_EQ(FozS.getInt(), 3); |
152 | auto BazS = M["baz" ]; |
153 | ASSERT_EQ(BazS.getKind(), Type::Int); |
154 | ASSERT_EQ(BazS.getInt(), 4); |
155 | |
156 | Ok = Doc.readFromBlob( |
157 | Blob: StringRef("\x82\xa3" |
158 | "foz" |
159 | "\xd0\x06\xa3" |
160 | "bay" |
161 | "\xd0\x08" ), |
162 | /*Multi=*/false, Merger: [](DocNode *Dest, DocNode Src, DocNode MapKey) { |
163 | // Merger function that merges two ints by ORing their values, as long |
164 | // as the map key is "foz". |
165 | if (Src.isMap()) |
166 | return Dest->isMap(); |
167 | if (Src.isArray()) |
168 | return Dest->isArray(); |
169 | if (MapKey.isString() && MapKey.getString() == "foz" && |
170 | Dest->getKind() == Type::Int && Src.getKind() == Type::Int) { |
171 | *Dest = Src.getDocument()->getNode(V: Dest->getInt() | Src.getInt()); |
172 | return true; |
173 | } |
174 | return false; |
175 | }); |
176 | ASSERT_TRUE(Ok); |
177 | ASSERT_EQ(M.size(), 5u); |
178 | FooS = M["foo" ]; |
179 | ASSERT_EQ(FooS.getKind(), Type::Int); |
180 | ASSERT_EQ(FooS.getInt(), 1); |
181 | BarS = M["bar" ]; |
182 | ASSERT_EQ(BarS.getKind(), Type::Int); |
183 | ASSERT_EQ(BarS.getInt(), 2); |
184 | FozS = M["foz" ]; |
185 | ASSERT_EQ(FozS.getKind(), Type::Int); |
186 | ASSERT_EQ(FozS.getInt(), 7); |
187 | BazS = M["baz" ]; |
188 | ASSERT_EQ(BazS.getKind(), Type::Int); |
189 | ASSERT_EQ(BazS.getInt(), 4); |
190 | auto BayS = M["bay" ]; |
191 | ASSERT_EQ(BayS.getKind(), Type::Int); |
192 | ASSERT_EQ(BayS.getInt(), 8); |
193 | } |
194 | |
195 | TEST(MsgPackDocument, TestWriteInt) { |
196 | Document Doc; |
197 | Doc.getRoot() = 1; |
198 | std::string Buffer; |
199 | Doc.writeToBlob(Blob&: Buffer); |
200 | ASSERT_EQ(Buffer, "\x01" ); |
201 | } |
202 | |
203 | TEST(MsgPackDocument, TestWriteBinary) { |
204 | uint8_t data[] = {1, 2, 3, 4}; |
205 | Document Doc; |
206 | Doc.getRoot() = MemoryBufferRef( |
207 | StringRef(reinterpret_cast<const char *>(data), sizeof(data)), "" ); |
208 | std::string Buffer; |
209 | Doc.writeToBlob(Blob&: Buffer); |
210 | ASSERT_EQ(Buffer, "\xC4\x4\x1\x2\x3\x4" ); |
211 | } |
212 | |
213 | TEST(MsgPackDocument, TestWriteArray) { |
214 | Document Doc; |
215 | auto A = Doc.getRoot().getArray(/*Convert=*/true); |
216 | A.push_back(N: Doc.getNode(V: int64_t(1))); |
217 | A.push_back(N: Doc.getNode()); |
218 | std::string Buffer; |
219 | Doc.writeToBlob(Blob&: Buffer); |
220 | ASSERT_EQ(Buffer, "\x92\x01\xc0" ); |
221 | } |
222 | |
223 | TEST(MsgPackDocument, TestWriteMap) { |
224 | Document Doc; |
225 | auto M = Doc.getRoot().getMap(/*Convert=*/true); |
226 | M["foo" ] = 1; |
227 | M["bar" ] = 2; |
228 | std::string Buffer; |
229 | Doc.writeToBlob(Blob&: Buffer); |
230 | ASSERT_EQ(Buffer, "\x82\xa3" |
231 | "bar" |
232 | "\x02\xa3" |
233 | "foo" |
234 | "\x01" ); |
235 | } |
236 | |
237 | TEST(MsgPackDocument, TestOutputYAMLArray) { |
238 | Document Doc; |
239 | auto A = Doc.getRoot().getArray(/*Convert=*/true); |
240 | A.push_back(N: Doc.getNode(V: int64_t(1))); |
241 | A.push_back(N: Doc.getNode(V: int64_t(2))); |
242 | std::string Buffer; |
243 | raw_string_ostream OStream(Buffer); |
244 | Doc.toYAML(OS&: OStream); |
245 | ASSERT_EQ(OStream.str(), "---\n- 1\n- 2\n...\n" ); |
246 | } |
247 | |
248 | TEST(MsgPackDocument, TestInputYAMLArray) { |
249 | Document Doc; |
250 | bool Ok = Doc.fromYAML(S: "---\n- !int 0x1\n- !str 2\n...\n" ); |
251 | ASSERT_TRUE(Ok); |
252 | ASSERT_EQ(Doc.getRoot().getKind(), Type::Array); |
253 | auto A = Doc.getRoot().getArray(); |
254 | ASSERT_EQ(A.size(), 2u); |
255 | auto SI = A[0]; |
256 | ASSERT_EQ(SI.getKind(), Type::UInt); |
257 | ASSERT_EQ(SI.getUInt(), 1u); |
258 | auto SS = A[1]; |
259 | ASSERT_EQ(SS.getKind(), Type::String); |
260 | ASSERT_EQ(SS.getString(), "2" ); |
261 | } |
262 | |
263 | TEST(MsgPackDocument, TestOutputYAMLMap) { |
264 | Document Doc; |
265 | auto M = Doc.getRoot().getMap(/*Convert=*/true); |
266 | M["foo" ] = 1; |
267 | M["bar" ] = 2U; |
268 | auto N = Doc.getMapNode(); |
269 | M["qux" ] = N; |
270 | N["baz" ] = true; |
271 | std::string Buffer; |
272 | raw_string_ostream OStream(Buffer); |
273 | Doc.toYAML(OS&: OStream); |
274 | ASSERT_EQ(OStream.str(), "---\n" |
275 | "bar: 2\n" |
276 | "foo: 1\n" |
277 | "qux:\n" |
278 | " baz: true\n" |
279 | "...\n" ); |
280 | } |
281 | |
282 | TEST(MsgPackDocument, TestOutputYAMLMapWithErase) { |
283 | Document Doc; |
284 | auto M = Doc.getRoot().getMap(/*Convert=*/true); |
285 | M["foo" ] = 1; |
286 | M["bar" ] = 2U; |
287 | auto N = Doc.getMapNode(); |
288 | M["qux" ] = N; |
289 | N["baz" ] = true; |
290 | M.erase(Key: Doc.getNode(V: "bar" )); |
291 | std::string Buffer; |
292 | raw_string_ostream OStream(Buffer); |
293 | Doc.toYAML(OS&: OStream); |
294 | ASSERT_EQ(OStream.str(), "---\n" |
295 | "foo: 1\n" |
296 | "qux:\n" |
297 | " baz: true\n" |
298 | "...\n" ); |
299 | } |
300 | |
301 | TEST(MsgPackDocument, TestOutputYAMLMapHex) { |
302 | Document Doc; |
303 | Doc.setHexMode(); |
304 | auto M = Doc.getRoot().getMap(/*Convert=*/true); |
305 | M["foo" ] = 1; |
306 | M["bar" ] = 2U; |
307 | auto N = Doc.getMapNode(); |
308 | M["qux" ] = N; |
309 | N["baz" ] = true; |
310 | std::string Buffer; |
311 | raw_string_ostream OStream(Buffer); |
312 | Doc.toYAML(OS&: OStream); |
313 | ASSERT_EQ(OStream.str(), "---\n" |
314 | "bar: 0x2\n" |
315 | "foo: 1\n" |
316 | "qux:\n" |
317 | " baz: true\n" |
318 | "...\n" ); |
319 | } |
320 | |
321 | TEST(MsgPackDocument, TestInputYAMLMap) { |
322 | Document Doc; |
323 | bool Ok = Doc.fromYAML(S: "---\nfoo: !int 0x1\nbaz: !str 2\n...\n" ); |
324 | ASSERT_TRUE(Ok); |
325 | ASSERT_EQ(Doc.getRoot().getKind(), Type::Map); |
326 | auto M = Doc.getRoot().getMap(); |
327 | ASSERT_EQ(M.size(), 2u); |
328 | auto SI = M["foo" ]; |
329 | ASSERT_EQ(SI.getKind(), Type::UInt); |
330 | ASSERT_EQ(SI.getUInt(), 1u); |
331 | auto SS = M["baz" ]; |
332 | ASSERT_EQ(SS.getKind(), Type::String); |
333 | ASSERT_EQ(SS.getString(), "2" ); |
334 | } |
335 | |