423 lines · cpp
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-exception6//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(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 25TEST(MsgPackDocument, TestReadBoolean) {26 Document Doc1;27 bool Ok = Doc1.readFromBlob(StringRef("\xC2", 1), /*Multi=*/false);28 ASSERT_TRUE(Ok);29 ASSERT_EQ(Doc1.getRoot().getKind(), Type::Boolean);30 ASSERT_EQ(Doc1.getRoot().getBool(), false);31 Document Doc2;32 Ok = Doc2.readFromBlob(StringRef("\xC3", 1), /*Multi=*/false);33 ASSERT_TRUE(Ok);34 ASSERT_EQ(Doc2.getRoot().getKind(), Type::Boolean);35 ASSERT_EQ(Doc2.getRoot().getBool(), true);36}37 38TEST(MsgPackDocument, TestReadInt) {39 Document Doc1;40 bool Ok = Doc1.readFromBlob(StringRef("\xD0\x00", 2), /*Multi=*/false);41 ASSERT_TRUE(Ok);42 ASSERT_EQ(Doc1.getRoot().getKind(), Type::Int);43 ASSERT_EQ(Doc1.getRoot().getInt(), 0);44 Document Doc2;45 Ok = Doc2.readFromBlob(StringRef("\xFF", 1), /*Multi=*/false);46 ASSERT_TRUE(Ok);47 ASSERT_EQ(Doc2.getRoot().getKind(), Type::Int);48 ASSERT_EQ(Doc2.getRoot().getInt(), -1);49}50 51TEST(MsgPackDocument, TestReadUInt) {52 Document Doc1;53 bool Ok = Doc1.readFromBlob(StringRef("\xCC\x00", 2), /*Multi=*/false);54 ASSERT_TRUE(Ok);55 ASSERT_EQ(Doc1.getRoot().getKind(), Type::UInt);56 ASSERT_EQ(Doc1.getRoot().getUInt(), 0U);57 Document Doc2;58 Ok = Doc2.readFromBlob(StringRef("\x01", 1), /*Multi=*/false);59 ASSERT_TRUE(Ok);60 ASSERT_EQ(Doc2.getRoot().getKind(), Type::UInt);61 ASSERT_EQ(Doc2.getRoot().getUInt(), 1U);62}63 64TEST(MsgPackDocument, TestReadFloat) {65 Document Doc1;66 bool Ok =67 Doc1.readFromBlob(StringRef("\xCA\x3F\x80\x00\x00", 5), /*Multi=*/false);68 ASSERT_TRUE(Ok);69 ASSERT_EQ(Doc1.getRoot().getKind(), Type::Float);70 ASSERT_EQ(Doc1.getRoot().getFloat(), 1.0);71 Document Doc2;72 Ok = Doc2.readFromBlob(StringRef("\xCB\x48\x3D\x63\x29\xF1\xC3\x5C\xA5", 9),73 /*Multi=*/false);74 ASSERT_TRUE(Ok);75 ASSERT_EQ(Doc2.getRoot().getKind(), Type::Float);76 ASSERT_EQ(Doc2.getRoot().getFloat(), 1e40);77}78 79TEST(MsgPackDocument, TestReadBinary) {80 Document Doc;81 uint8_t data[] = {1, 2, 3, 4};82 bool Ok =83 Doc.readFromBlob(StringRef("\xC4\x4\x1\x2\x3\x4", 6), /*Multi=*/false);84 ASSERT_TRUE(Ok);85 ASSERT_EQ(Doc.getRoot().getKind(), Type::Binary);86 ASSERT_EQ(Doc.getRoot().getBinary().getBuffer(),87 StringRef(reinterpret_cast<const char *>(data), 4));88}89 90TEST(MsgPackDocument, TestReadMergeArray) {91 Document Doc;92 bool Ok = Doc.readFromBlob(StringRef("\x92\xd0\x01\xc0"), /*Multi=*/false);93 ASSERT_TRUE(Ok);94 ASSERT_EQ(Doc.getRoot().getKind(), Type::Array);95 auto A = Doc.getRoot().getArray();96 ASSERT_EQ(A.size(), 2u);97 auto SI = A[0];98 ASSERT_EQ(SI.getKind(), Type::Int);99 ASSERT_EQ(SI.getInt(), 1);100 auto SN = A[1];101 ASSERT_EQ(SN.getKind(), Type::Nil);102 103 Ok = Doc.readFromBlob(StringRef("\x91\xd0\x2a"), /*Multi=*/false,104 [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) {105 // Allow array, merging into existing elements, ORing106 // ints.107 if (DestNode->getKind() == Type::Int &&108 SrcNode.getKind() == Type::Int) {109 *DestNode = DestNode->getDocument()->getNode(110 DestNode->getInt() | SrcNode.getInt());111 return 0;112 }113 return DestNode->isArray() && SrcNode.isArray() ? 0114 : -1;115 });116 ASSERT_TRUE(Ok);117 A = Doc.getRoot().getArray();118 ASSERT_EQ(A.size(), 2u);119 SI = A[0];120 ASSERT_EQ(SI.getKind(), Type::Int);121 ASSERT_EQ(SI.getInt(), 43);122 SN = A[1];123 ASSERT_EQ(SN.getKind(), Type::Nil);124}125 126TEST(MsgPackDocument, TestReadAppendArray) {127 Document Doc;128 bool Ok = Doc.readFromBlob(StringRef("\x92\xd0\x01\xc0"), /*Multi=*/false);129 ASSERT_TRUE(Ok);130 ASSERT_EQ(Doc.getRoot().getKind(), Type::Array);131 auto A = Doc.getRoot().getArray();132 ASSERT_EQ(A.size(), 2u);133 auto SI = A[0];134 ASSERT_EQ(SI.getKind(), Type::Int);135 ASSERT_EQ(SI.getInt(), 1);136 auto SN = A[1];137 ASSERT_EQ(SN.getKind(), Type::Nil);138 139 Ok = Doc.readFromBlob(StringRef("\x91\xd0\x2a"), /*Multi=*/false,140 [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) {141 // Allow array, appending after existing elements142 return DestNode->isArray() && SrcNode.isArray()143 ? DestNode->getArray().size()144 : -1;145 });146 ASSERT_TRUE(Ok);147 A = Doc.getRoot().getArray();148 ASSERT_EQ(A.size(), 3u);149 SI = A[0];150 ASSERT_EQ(SI.getKind(), Type::Int);151 ASSERT_EQ(SI.getInt(), 1);152 SN = A[1];153 ASSERT_EQ(SN.getKind(), Type::Nil);154 SI = A[2];155 ASSERT_EQ(SI.getKind(), Type::Int);156 ASSERT_EQ(SI.getInt(), 42);157}158 159TEST(MsgPackDocument, TestReadMergeMap) {160 Document Doc;161 bool Ok = Doc.readFromBlob(StringRef("\x82\xa3"162 "foo"163 "\xd0\x01\xa3"164 "bar"165 "\xd0\x02"),166 /*Multi=*/false);167 ASSERT_TRUE(Ok);168 ASSERT_EQ(Doc.getRoot().getKind(), Type::Map);169 auto M = Doc.getRoot().getMap();170 ASSERT_EQ(M.size(), 2u);171 auto FooS = M["foo"];172 ASSERT_EQ(FooS.getKind(), Type::Int);173 ASSERT_EQ(FooS.getInt(), 1);174 auto BarS = M["bar"];175 ASSERT_EQ(BarS.getKind(), Type::Int);176 ASSERT_EQ(BarS.getInt(), 2);177 178 Ok = Doc.readFromBlob(StringRef("\x82\xa3"179 "foz"180 "\xd0\x03\xa3"181 "baz"182 "\xd0\x04"),183 /*Multi=*/false,184 [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) {185 return DestNode->isMap() && SrcNode.isMap() ? 0 : -1;186 });187 ASSERT_TRUE(Ok);188 ASSERT_EQ(M.size(), 4u);189 FooS = M["foo"];190 ASSERT_EQ(FooS.getKind(), Type::Int);191 ASSERT_EQ(FooS.getInt(), 1);192 BarS = M["bar"];193 ASSERT_EQ(BarS.getKind(), Type::Int);194 ASSERT_EQ(BarS.getInt(), 2);195 auto FozS = M["foz"];196 ASSERT_EQ(FozS.getKind(), Type::Int);197 ASSERT_EQ(FozS.getInt(), 3);198 auto BazS = M["baz"];199 ASSERT_EQ(BazS.getKind(), Type::Int);200 ASSERT_EQ(BazS.getInt(), 4);201 202 Ok = Doc.readFromBlob(203 StringRef("\x82\xa3"204 "foz"205 "\xd0\x06\xa3"206 "bay"207 "\xd0\x08"),208 /*Multi=*/false, [](DocNode *Dest, DocNode Src, DocNode MapKey) {209 // Merger function that merges two ints by ORing their values, as long210 // as the map key is "foz".211 if (Src.isMap())212 return Dest->isMap();213 if (Src.isArray())214 return Dest->isArray();215 if (MapKey.isString() && MapKey.getString() == "foz" &&216 Dest->getKind() == Type::Int && Src.getKind() == Type::Int) {217 *Dest = Src.getDocument()->getNode(Dest->getInt() | Src.getInt());218 return true;219 }220 return false;221 });222 ASSERT_TRUE(Ok);223 ASSERT_EQ(M.size(), 5u);224 FooS = M["foo"];225 ASSERT_EQ(FooS.getKind(), Type::Int);226 ASSERT_EQ(FooS.getInt(), 1);227 BarS = M["bar"];228 ASSERT_EQ(BarS.getKind(), Type::Int);229 ASSERT_EQ(BarS.getInt(), 2);230 FozS = M["foz"];231 ASSERT_EQ(FozS.getKind(), Type::Int);232 ASSERT_EQ(FozS.getInt(), 7);233 BazS = M["baz"];234 ASSERT_EQ(BazS.getKind(), Type::Int);235 ASSERT_EQ(BazS.getInt(), 4);236 auto BayS = M["bay"];237 ASSERT_EQ(BayS.getKind(), Type::Int);238 ASSERT_EQ(BayS.getInt(), 8);239}240 241TEST(MsgPackDocument, TestWriteBoolean) {242 Document Doc;243 Doc.getRoot() = true;244 std::string Buffer;245 Doc.writeToBlob(Buffer);246 ASSERT_EQ(Buffer, "\xc3");247 Doc.getRoot() = false;248 Doc.writeToBlob(Buffer);249 ASSERT_EQ(Buffer, "\xc2");250}251 252TEST(MsgPackDocument, TestWriteInt) {253 Document Doc;254 Doc.getRoot() = 1;255 std::string Buffer;256 Doc.writeToBlob(Buffer);257 ASSERT_EQ(Buffer, "\x01");258 Doc.getRoot() = -1;259 Doc.writeToBlob(Buffer);260 ASSERT_EQ(Buffer, "\xFF");261 Doc.getRoot() = -4096;262 Doc.writeToBlob(Buffer);263 ASSERT_EQ(Buffer, StringRef("\xD1\xF0\x00", 3));264}265 266TEST(MsgPackDocument, TestWriteUInt) {267 Document Doc;268 Doc.getRoot() = 1U;269 std::string Buffer;270 Doc.writeToBlob(Buffer);271 ASSERT_EQ(Buffer, "\x01");272 Doc.getRoot() = 4096U;273 Doc.writeToBlob(Buffer);274 ASSERT_EQ(Buffer, StringRef("\xCD\x10\x00", 3));275}276 277TEST(MsgPackDocument, TestWriteFloat) {278 Document Doc;279 Doc.getRoot() = 1.0;280 std::string Buffer;281 Doc.writeToBlob(Buffer);282 ASSERT_EQ(Buffer, StringRef("\xCA\x3F\x80\x00\x00", 5));283 Doc.getRoot() = 1.0f;284 Doc.writeToBlob(Buffer);285 ASSERT_EQ(Buffer, StringRef("\xCA\x3F\x80\x00\x00", 5));286 Doc.getRoot() = 1e40;287 Doc.writeToBlob(Buffer);288 ASSERT_EQ(Buffer, "\xCB\x48\x3D\x63\x29\xF1\xC3\x5C\xA5");289}290 291TEST(MsgPackDocument, TestWriteBinary) {292 uint8_t data[] = {1, 2, 3, 4};293 Document Doc;294 Doc.getRoot() = MemoryBufferRef(295 StringRef(reinterpret_cast<const char *>(data), sizeof(data)), "");296 std::string Buffer;297 Doc.writeToBlob(Buffer);298 ASSERT_EQ(Buffer, "\xC4\x4\x1\x2\x3\x4");299}300 301TEST(MsgPackDocument, TestWriteArray) {302 Document Doc;303 auto A = Doc.getRoot().getArray(/*Convert=*/true);304 A.push_back(Doc.getNode(int64_t(1)));305 A.push_back(Doc.getNode());306 std::string Buffer;307 Doc.writeToBlob(Buffer);308 ASSERT_EQ(Buffer, "\x92\x01\xc0");309}310 311TEST(MsgPackDocument, TestWriteMap) {312 Document Doc;313 auto M = Doc.getRoot().getMap(/*Convert=*/true);314 M["foo"] = 1;315 M["bar"] = 2;316 std::string Buffer;317 Doc.writeToBlob(Buffer);318 ASSERT_EQ(Buffer, "\x82\xa3"319 "bar"320 "\x02\xa3"321 "foo"322 "\x01");323}324 325TEST(MsgPackDocument, TestOutputYAMLArray) {326 Document Doc;327 auto A = Doc.getRoot().getArray(/*Convert=*/true);328 A.push_back(Doc.getNode(int64_t(1)));329 A.push_back(Doc.getNode(int64_t(2)));330 std::string Buffer;331 raw_string_ostream OStream(Buffer);332 Doc.toYAML(OStream);333 ASSERT_EQ(OStream.str(), "---\n- 1\n- 2\n...\n");334}335 336TEST(MsgPackDocument, TestInputYAMLArray) {337 Document Doc;338 bool Ok = Doc.fromYAML("---\n- !int 0x1\n- !str 2\n...\n");339 ASSERT_TRUE(Ok);340 ASSERT_EQ(Doc.getRoot().getKind(), Type::Array);341 auto A = Doc.getRoot().getArray();342 ASSERT_EQ(A.size(), 2u);343 auto SI = A[0];344 ASSERT_EQ(SI.getKind(), Type::UInt);345 ASSERT_EQ(SI.getUInt(), 1u);346 auto SS = A[1];347 ASSERT_EQ(SS.getKind(), Type::String);348 ASSERT_EQ(SS.getString(), "2");349}350 351TEST(MsgPackDocument, TestOutputYAMLMap) {352 Document Doc;353 auto M = Doc.getRoot().getMap(/*Convert=*/true);354 M["foo"] = 1;355 M["bar"] = 2U;356 auto N = Doc.getMapNode();357 M["qux"] = N;358 N["baz"] = true;359 std::string Buffer;360 raw_string_ostream OStream(Buffer);361 Doc.toYAML(OStream);362 ASSERT_EQ(OStream.str(), "---\n"363 "bar: 2\n"364 "foo: 1\n"365 "qux:\n"366 " baz: true\n"367 "...\n");368}369 370TEST(MsgPackDocument, TestOutputYAMLMapWithErase) {371 Document Doc;372 auto M = Doc.getRoot().getMap(/*Convert=*/true);373 M["foo"] = 1;374 M["bar"] = 2U;375 auto N = Doc.getMapNode();376 M["qux"] = N;377 N["baz"] = true;378 M.erase(Doc.getNode("bar"));379 std::string Buffer;380 raw_string_ostream OStream(Buffer);381 Doc.toYAML(OStream);382 ASSERT_EQ(OStream.str(), "---\n"383 "foo: 1\n"384 "qux:\n"385 " baz: true\n"386 "...\n");387}388 389TEST(MsgPackDocument, TestOutputYAMLMapHex) {390 Document Doc;391 Doc.setHexMode();392 auto M = Doc.getRoot().getMap(/*Convert=*/true);393 M["foo"] = 1;394 M["bar"] = 2U;395 auto N = Doc.getMapNode();396 M["qux"] = N;397 N["baz"] = true;398 std::string Buffer;399 raw_string_ostream OStream(Buffer);400 Doc.toYAML(OStream);401 ASSERT_EQ(OStream.str(), "---\n"402 "bar: 0x2\n"403 "foo: 1\n"404 "qux:\n"405 " baz: true\n"406 "...\n");407}408 409TEST(MsgPackDocument, TestInputYAMLMap) {410 Document Doc;411 bool Ok = Doc.fromYAML("---\nfoo: !int 0x1\nbaz: !str 2\n...\n");412 ASSERT_TRUE(Ok);413 ASSERT_EQ(Doc.getRoot().getKind(), Type::Map);414 auto M = Doc.getRoot().getMap();415 ASSERT_EQ(M.size(), 2u);416 auto SI = M["foo"];417 ASSERT_EQ(SI.getKind(), Type::UInt);418 ASSERT_EQ(SI.getUInt(), 1u);419 auto SS = M["baz"];420 ASSERT_EQ(SS.getKind(), Type::String);421 ASSERT_EQ(SS.getString(), "2");422}423