xref: /llvm-project/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp (revision 9d52f69afef64776b830bb9adc4e1737ff8fc426)
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 
TEST(MsgPackDocument,DocNodeTest)15 TEST(MsgPackDocument, DocNodeTest) {
16   Document Doc;
17 
18   DocNode Int1 = Doc.getNode(1), Int2 = Doc.getNode(2);
19   DocNode Str1 = Doc.getNode("ab"), Str2 = Doc.getNode("ab");
20 
21   ASSERT_TRUE(Int1 != Int2);
22   ASSERT_TRUE(Str1 == Str2);
23 }
24 
TEST(MsgPackDocument,TestReadInt)25 TEST(MsgPackDocument, TestReadInt) {
26   Document Doc;
27   bool Ok = Doc.readFromBlob(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 
TEST(MsgPackDocument,TestReadBinary)33 TEST(MsgPackDocument, TestReadBinary) {
34   Document Doc;
35   uint8_t data[] = {1, 2, 3, 4};
36   bool Ok =
37       Doc.readFromBlob(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 
TEST(MsgPackDocument,TestReadMergeArray)44 TEST(MsgPackDocument, TestReadMergeArray) {
45   Document Doc;
46   bool Ok = Doc.readFromBlob(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(StringRef("\x91\xd0\x2a"), /*Multi=*/false,
58                         [](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                                 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 
TEST(MsgPackDocument,TestReadAppendArray)80 TEST(MsgPackDocument, TestReadAppendArray) {
81   Document Doc;
82   bool Ok = Doc.readFromBlob(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(StringRef("\x91\xd0\x2a"), /*Multi=*/false,
94                         [](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 
TEST(MsgPackDocument,TestReadMergeMap)113 TEST(MsgPackDocument, TestReadMergeMap) {
114   Document Doc;
115   bool Ok = Doc.readFromBlob(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(StringRef("\x82\xa3"
133                                   "foz"
134                                   "\xd0\x03\xa3"
135                                   "baz"
136                                   "\xd0\x04"),
137                         /*Multi=*/false,
138                         [](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       StringRef("\x82\xa3"
158                 "foz"
159                 "\xd0\x06\xa3"
160                 "bay"
161                 "\xd0\x08"),
162       /*Multi=*/false, [](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(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 
TEST(MsgPackDocument,TestWriteInt)195 TEST(MsgPackDocument, TestWriteInt) {
196   Document Doc;
197   Doc.getRoot() = 1;
198   std::string Buffer;
199   Doc.writeToBlob(Buffer);
200   ASSERT_EQ(Buffer, "\x01");
201 }
202 
TEST(MsgPackDocument,TestWriteBinary)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(Buffer);
210   ASSERT_EQ(Buffer, "\xC4\x4\x1\x2\x3\x4");
211 }
212 
TEST(MsgPackDocument,TestWriteArray)213 TEST(MsgPackDocument, TestWriteArray) {
214   Document Doc;
215   auto A = Doc.getRoot().getArray(/*Convert=*/true);
216   A.push_back(Doc.getNode(int64_t(1)));
217   A.push_back(Doc.getNode());
218   std::string Buffer;
219   Doc.writeToBlob(Buffer);
220   ASSERT_EQ(Buffer, "\x92\x01\xc0");
221 }
222 
TEST(MsgPackDocument,TestWriteMap)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(Buffer);
230   ASSERT_EQ(Buffer, "\x82\xa3"
231                     "bar"
232                     "\x02\xa3"
233                     "foo"
234                     "\x01");
235 }
236 
TEST(MsgPackDocument,TestOutputYAMLArray)237 TEST(MsgPackDocument, TestOutputYAMLArray) {
238   Document Doc;
239   auto A = Doc.getRoot().getArray(/*Convert=*/true);
240   A.push_back(Doc.getNode(int64_t(1)));
241   A.push_back(Doc.getNode(int64_t(2)));
242   std::string Buffer;
243   raw_string_ostream OStream(Buffer);
244   Doc.toYAML(OStream);
245   ASSERT_EQ(OStream.str(), "---\n- 1\n- 2\n...\n");
246 }
247 
TEST(MsgPackDocument,TestInputYAMLArray)248 TEST(MsgPackDocument, TestInputYAMLArray) {
249   Document Doc;
250   bool Ok = Doc.fromYAML("---\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 
TEST(MsgPackDocument,TestOutputYAMLMap)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(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 
TEST(MsgPackDocument,TestOutputYAMLMapWithErase)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(Doc.getNode("bar"));
291   std::string Buffer;
292   raw_string_ostream OStream(Buffer);
293   Doc.toYAML(OStream);
294   ASSERT_EQ(OStream.str(), "---\n"
295                            "foo:             1\n"
296                            "qux:\n"
297                            "  baz:             true\n"
298                            "...\n");
299 }
300 
TEST(MsgPackDocument,TestOutputYAMLMapHex)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(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 
TEST(MsgPackDocument,TestInputYAMLMap)321 TEST(MsgPackDocument, TestInputYAMLMap) {
322   Document Doc;
323   bool Ok = Doc.fromYAML("---\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