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
12using namespace llvm;
13using namespace msgpack;
14
15TEST(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
25TEST(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
33TEST(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
44TEST(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
80TEST(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
113TEST(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
195TEST(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
203TEST(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
213TEST(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
223TEST(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
237TEST(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
248TEST(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
263TEST(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
282TEST(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
301TEST(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
321TEST(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

source code of llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp