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(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 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 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 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 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 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 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 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 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 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 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 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 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 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