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,TestReadMergeArray)33 TEST(MsgPackDocument, TestReadMergeArray) {
34   Document Doc;
35   bool Ok = Doc.readFromBlob(StringRef("\x92\xd0\x01\xc0"), /*Multi=*/false);
36   ASSERT_TRUE(Ok);
37   ASSERT_EQ(Doc.getRoot().getKind(), Type::Array);
38   auto A = Doc.getRoot().getArray();
39   ASSERT_EQ(A.size(), 2u);
40   auto SI = A[0];
41   ASSERT_EQ(SI.getKind(), Type::Int);
42   ASSERT_EQ(SI.getInt(), 1);
43   auto SN = A[1];
44   ASSERT_EQ(SN.getKind(), Type::Nil);
45 
46   Ok = Doc.readFromBlob(StringRef("\x91\xd0\x2a"), /*Multi=*/false,
47                         [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) {
48                           // Allow array, merging into existing elements, ORing
49                           // ints.
50                           if (DestNode->getKind() == Type::Int &&
51                               SrcNode.getKind() == Type::Int) {
52                             *DestNode = DestNode->getDocument()->getNode(
53                                 DestNode->getInt() | SrcNode.getInt());
54                             return 0;
55                           }
56                           return DestNode->isArray() && SrcNode.isArray() ? 0
57                                                                           : -1;
58                         });
59   ASSERT_TRUE(Ok);
60   A = Doc.getRoot().getArray();
61   ASSERT_EQ(A.size(), 2u);
62   SI = A[0];
63   ASSERT_EQ(SI.getKind(), Type::Int);
64   ASSERT_EQ(SI.getInt(), 43);
65   SN = A[1];
66   ASSERT_EQ(SN.getKind(), Type::Nil);
67 }
68 
TEST(MsgPackDocument,TestReadAppendArray)69 TEST(MsgPackDocument, TestReadAppendArray) {
70   Document Doc;
71   bool Ok = Doc.readFromBlob(StringRef("\x92\xd0\x01\xc0"), /*Multi=*/false);
72   ASSERT_TRUE(Ok);
73   ASSERT_EQ(Doc.getRoot().getKind(), Type::Array);
74   auto A = Doc.getRoot().getArray();
75   ASSERT_EQ(A.size(), 2u);
76   auto SI = A[0];
77   ASSERT_EQ(SI.getKind(), Type::Int);
78   ASSERT_EQ(SI.getInt(), 1);
79   auto SN = A[1];
80   ASSERT_EQ(SN.getKind(), Type::Nil);
81 
82   Ok = Doc.readFromBlob(StringRef("\x91\xd0\x2a"), /*Multi=*/false,
83                         [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) {
84                           // Allow array, appending after existing elements
85                           return DestNode->isArray() && SrcNode.isArray()
86                                      ? DestNode->getArray().size()
87                                      : -1;
88                         });
89   ASSERT_TRUE(Ok);
90   A = Doc.getRoot().getArray();
91   ASSERT_EQ(A.size(), 3u);
92   SI = A[0];
93   ASSERT_EQ(SI.getKind(), Type::Int);
94   ASSERT_EQ(SI.getInt(), 1);
95   SN = A[1];
96   ASSERT_EQ(SN.getKind(), Type::Nil);
97   SI = A[2];
98   ASSERT_EQ(SI.getKind(), Type::Int);
99   ASSERT_EQ(SI.getInt(), 42);
100 }
101 
TEST(MsgPackDocument,TestReadMergeMap)102 TEST(MsgPackDocument, TestReadMergeMap) {
103   Document Doc;
104   bool Ok = Doc.readFromBlob(StringRef("\x82\xa3"
105                                        "foo"
106                                        "\xd0\x01\xa3"
107                                        "bar"
108                                        "\xd0\x02"),
109                              /*Multi=*/false);
110   ASSERT_TRUE(Ok);
111   ASSERT_EQ(Doc.getRoot().getKind(), Type::Map);
112   auto M = Doc.getRoot().getMap();
113   ASSERT_EQ(M.size(), 2u);
114   auto FooS = M["foo"];
115   ASSERT_EQ(FooS.getKind(), Type::Int);
116   ASSERT_EQ(FooS.getInt(), 1);
117   auto BarS = M["bar"];
118   ASSERT_EQ(BarS.getKind(), Type::Int);
119   ASSERT_EQ(BarS.getInt(), 2);
120 
121   Ok = Doc.readFromBlob(StringRef("\x82\xa3"
122                                   "foz"
123                                   "\xd0\x03\xa3"
124                                   "baz"
125                                   "\xd0\x04"),
126                         /*Multi=*/false,
127                         [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) {
128                           return DestNode->isMap() && SrcNode.isMap() ? 0 : -1;
129                         });
130   ASSERT_TRUE(Ok);
131   ASSERT_EQ(M.size(), 4u);
132   FooS = M["foo"];
133   ASSERT_EQ(FooS.getKind(), Type::Int);
134   ASSERT_EQ(FooS.getInt(), 1);
135   BarS = M["bar"];
136   ASSERT_EQ(BarS.getKind(), Type::Int);
137   ASSERT_EQ(BarS.getInt(), 2);
138   auto FozS = M["foz"];
139   ASSERT_EQ(FozS.getKind(), Type::Int);
140   ASSERT_EQ(FozS.getInt(), 3);
141   auto BazS = M["baz"];
142   ASSERT_EQ(BazS.getKind(), Type::Int);
143   ASSERT_EQ(BazS.getInt(), 4);
144 
145   Ok = Doc.readFromBlob(
146       StringRef("\x82\xa3"
147                 "foz"
148                 "\xd0\x06\xa3"
149                 "bay"
150                 "\xd0\x08"),
151       /*Multi=*/false, [](DocNode *Dest, DocNode Src, DocNode MapKey) {
152         // Merger function that merges two ints by ORing their values, as long
153         // as the map key is "foz".
154         if (Src.isMap())
155           return Dest->isMap();
156         if (Src.isArray())
157           return Dest->isArray();
158         if (MapKey.isString() && MapKey.getString() == "foz" &&
159             Dest->getKind() == Type::Int && Src.getKind() == Type::Int) {
160           *Dest = Src.getDocument()->getNode(Dest->getInt() | Src.getInt());
161           return true;
162         }
163         return false;
164       });
165   ASSERT_TRUE(Ok);
166   ASSERT_EQ(M.size(), 5u);
167   FooS = M["foo"];
168   ASSERT_EQ(FooS.getKind(), Type::Int);
169   ASSERT_EQ(FooS.getInt(), 1);
170   BarS = M["bar"];
171   ASSERT_EQ(BarS.getKind(), Type::Int);
172   ASSERT_EQ(BarS.getInt(), 2);
173   FozS = M["foz"];
174   ASSERT_EQ(FozS.getKind(), Type::Int);
175   ASSERT_EQ(FozS.getInt(), 7);
176   BazS = M["baz"];
177   ASSERT_EQ(BazS.getKind(), Type::Int);
178   ASSERT_EQ(BazS.getInt(), 4);
179   auto BayS = M["bay"];
180   ASSERT_EQ(BayS.getKind(), Type::Int);
181   ASSERT_EQ(BayS.getInt(), 8);
182 }
183 
TEST(MsgPackDocument,TestWriteInt)184 TEST(MsgPackDocument, TestWriteInt) {
185   Document Doc;
186   Doc.getRoot() = 1;
187   std::string Buffer;
188   Doc.writeToBlob(Buffer);
189   ASSERT_EQ(Buffer, "\x01");
190 }
191 
TEST(MsgPackDocument,TestWriteArray)192 TEST(MsgPackDocument, TestWriteArray) {
193   Document Doc;
194   auto A = Doc.getRoot().getArray(/*Convert=*/true);
195   A.push_back(Doc.getNode(int64_t(1)));
196   A.push_back(Doc.getNode());
197   std::string Buffer;
198   Doc.writeToBlob(Buffer);
199   ASSERT_EQ(Buffer, "\x92\x01\xc0");
200 }
201 
TEST(MsgPackDocument,TestWriteMap)202 TEST(MsgPackDocument, TestWriteMap) {
203   Document Doc;
204   auto M = Doc.getRoot().getMap(/*Convert=*/true);
205   M["foo"] = 1;
206   M["bar"] = 2;
207   std::string Buffer;
208   Doc.writeToBlob(Buffer);
209   ASSERT_EQ(Buffer, "\x82\xa3"
210                     "bar"
211                     "\x02\xa3"
212                     "foo"
213                     "\x01");
214 }
215 
TEST(MsgPackDocument,TestOutputYAMLArray)216 TEST(MsgPackDocument, TestOutputYAMLArray) {
217   Document Doc;
218   auto A = Doc.getRoot().getArray(/*Convert=*/true);
219   A.push_back(Doc.getNode(int64_t(1)));
220   A.push_back(Doc.getNode(int64_t(2)));
221   std::string Buffer;
222   raw_string_ostream OStream(Buffer);
223   Doc.toYAML(OStream);
224   ASSERT_EQ(OStream.str(), "---\n- 1\n- 2\n...\n");
225 }
226 
TEST(MsgPackDocument,TestInputYAMLArray)227 TEST(MsgPackDocument, TestInputYAMLArray) {
228   Document Doc;
229   bool Ok = Doc.fromYAML("---\n- !int 0x1\n- !str 2\n...\n");
230   ASSERT_TRUE(Ok);
231   ASSERT_EQ(Doc.getRoot().getKind(), Type::Array);
232   auto A = Doc.getRoot().getArray();
233   ASSERT_EQ(A.size(), 2u);
234   auto SI = A[0];
235   ASSERT_EQ(SI.getKind(), Type::UInt);
236   ASSERT_EQ(SI.getUInt(), 1u);
237   auto SS = A[1];
238   ASSERT_EQ(SS.getKind(), Type::String);
239   ASSERT_EQ(SS.getString(), "2");
240 }
241 
TEST(MsgPackDocument,TestOutputYAMLMap)242 TEST(MsgPackDocument, TestOutputYAMLMap) {
243   Document Doc;
244   auto M = Doc.getRoot().getMap(/*Convert=*/true);
245   M["foo"] = 1;
246   M["bar"] = 2U;
247   auto N = Doc.getMapNode();
248   M["qux"] = N;
249   N["baz"] = true;
250   std::string Buffer;
251   raw_string_ostream OStream(Buffer);
252   Doc.toYAML(OStream);
253   ASSERT_EQ(OStream.str(), "---\n"
254                            "bar:             2\n"
255                            "foo:             1\n"
256                            "qux:\n"
257                            "  baz:             true\n"
258                            "...\n");
259 }
260 
TEST(MsgPackDocument,TestOutputYAMLMapWithErase)261 TEST(MsgPackDocument, TestOutputYAMLMapWithErase) {
262   Document Doc;
263   auto M = Doc.getRoot().getMap(/*Convert=*/true);
264   M["foo"] = 1;
265   M["bar"] = 2U;
266   auto N = Doc.getMapNode();
267   M["qux"] = N;
268   N["baz"] = true;
269   M.erase(Doc.getNode("bar"));
270   std::string Buffer;
271   raw_string_ostream OStream(Buffer);
272   Doc.toYAML(OStream);
273   ASSERT_EQ(OStream.str(), "---\n"
274                            "foo:             1\n"
275                            "qux:\n"
276                            "  baz:             true\n"
277                            "...\n");
278 }
279 
TEST(MsgPackDocument,TestOutputYAMLMapHex)280 TEST(MsgPackDocument, TestOutputYAMLMapHex) {
281   Document Doc;
282   Doc.setHexMode();
283   auto M = Doc.getRoot().getMap(/*Convert=*/true);
284   M["foo"] = 1;
285   M["bar"] = 2U;
286   auto N = Doc.getMapNode();
287   M["qux"] = N;
288   N["baz"] = true;
289   std::string Buffer;
290   raw_string_ostream OStream(Buffer);
291   Doc.toYAML(OStream);
292   ASSERT_EQ(OStream.str(), "---\n"
293                            "bar:             0x2\n"
294                            "foo:             1\n"
295                            "qux:\n"
296                            "  baz:             true\n"
297                            "...\n");
298 }
299 
TEST(MsgPackDocument,TestInputYAMLMap)300 TEST(MsgPackDocument, TestInputYAMLMap) {
301   Document Doc;
302   bool Ok = Doc.fromYAML("---\nfoo: !int 0x1\nbaz: !str 2\n...\n");
303   ASSERT_TRUE(Ok);
304   ASSERT_EQ(Doc.getRoot().getKind(), Type::Map);
305   auto M = Doc.getRoot().getMap();
306   ASSERT_EQ(M.size(), 2u);
307   auto SI = M["foo"];
308   ASSERT_EQ(SI.getKind(), Type::UInt);
309   ASSERT_EQ(SI.getUInt(), 1u);
310   auto SS = M["baz"];
311   ASSERT_EQ(SS.getKind(), Type::String);
312   ASSERT_EQ(SS.getString(), "2");
313 }
314