//===- MsgPackDocumentTest.cpp --------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/BinaryFormat/MsgPackDocument.h" #include "gtest/gtest.h" using namespace llvm; using namespace msgpack; TEST(MsgPackDocument, DocNodeTest) { Document Doc; DocNode Int1 = Doc.getNode(1), Int2 = Doc.getNode(2); DocNode Str1 = Doc.getNode("ab"), Str2 = Doc.getNode("ab"); ASSERT_TRUE(Int1 != Int2); ASSERT_TRUE(Str1 == Str2); } TEST(MsgPackDocument, TestReadInt) { Document Doc; bool Ok = Doc.readFromBlob(StringRef("\xd0\x00", 2), /*Multi=*/false); ASSERT_TRUE(Ok); ASSERT_EQ(Doc.getRoot().getKind(), Type::Int); ASSERT_EQ(Doc.getRoot().getInt(), 0); } TEST(MsgPackDocument, TestReadMergeArray) { Document Doc; bool Ok = Doc.readFromBlob(StringRef("\x92\xd0\x01\xc0"), /*Multi=*/false); ASSERT_TRUE(Ok); ASSERT_EQ(Doc.getRoot().getKind(), Type::Array); auto A = Doc.getRoot().getArray(); ASSERT_EQ(A.size(), 2u); auto SI = A[0]; ASSERT_EQ(SI.getKind(), Type::Int); ASSERT_EQ(SI.getInt(), 1); auto SN = A[1]; ASSERT_EQ(SN.getKind(), Type::Nil); Ok = Doc.readFromBlob(StringRef("\x91\xd0\x2a"), /*Multi=*/false, [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) { // Allow array, merging into existing elements, ORing // ints. if (DestNode->getKind() == Type::Int && SrcNode.getKind() == Type::Int) { *DestNode = DestNode->getDocument()->getNode( DestNode->getInt() | SrcNode.getInt()); return 0; } return DestNode->isArray() && SrcNode.isArray() ? 0 : -1; }); ASSERT_TRUE(Ok); A = Doc.getRoot().getArray(); ASSERT_EQ(A.size(), 2u); SI = A[0]; ASSERT_EQ(SI.getKind(), Type::Int); ASSERT_EQ(SI.getInt(), 43); SN = A[1]; ASSERT_EQ(SN.getKind(), Type::Nil); } TEST(MsgPackDocument, TestReadAppendArray) { Document Doc; bool Ok = Doc.readFromBlob(StringRef("\x92\xd0\x01\xc0"), /*Multi=*/false); ASSERT_TRUE(Ok); ASSERT_EQ(Doc.getRoot().getKind(), Type::Array); auto A = Doc.getRoot().getArray(); ASSERT_EQ(A.size(), 2u); auto SI = A[0]; ASSERT_EQ(SI.getKind(), Type::Int); ASSERT_EQ(SI.getInt(), 1); auto SN = A[1]; ASSERT_EQ(SN.getKind(), Type::Nil); Ok = Doc.readFromBlob(StringRef("\x91\xd0\x2a"), /*Multi=*/false, [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) { // Allow array, appending after existing elements return DestNode->isArray() && SrcNode.isArray() ? DestNode->getArray().size() : -1; }); ASSERT_TRUE(Ok); A = Doc.getRoot().getArray(); ASSERT_EQ(A.size(), 3u); SI = A[0]; ASSERT_EQ(SI.getKind(), Type::Int); ASSERT_EQ(SI.getInt(), 1); SN = A[1]; ASSERT_EQ(SN.getKind(), Type::Nil); SI = A[2]; ASSERT_EQ(SI.getKind(), Type::Int); ASSERT_EQ(SI.getInt(), 42); } TEST(MsgPackDocument, TestReadMergeMap) { Document Doc; bool Ok = Doc.readFromBlob(StringRef("\x82\xa3" "foo" "\xd0\x01\xa3" "bar" "\xd0\x02"), /*Multi=*/false); ASSERT_TRUE(Ok); ASSERT_EQ(Doc.getRoot().getKind(), Type::Map); auto M = Doc.getRoot().getMap(); ASSERT_EQ(M.size(), 2u); auto FooS = M["foo"]; ASSERT_EQ(FooS.getKind(), Type::Int); ASSERT_EQ(FooS.getInt(), 1); auto BarS = M["bar"]; ASSERT_EQ(BarS.getKind(), Type::Int); ASSERT_EQ(BarS.getInt(), 2); Ok = Doc.readFromBlob(StringRef("\x82\xa3" "foz" "\xd0\x03\xa3" "baz" "\xd0\x04"), /*Multi=*/false, [](DocNode *DestNode, DocNode SrcNode, DocNode MapKey) { return DestNode->isMap() && SrcNode.isMap() ? 0 : -1; }); ASSERT_TRUE(Ok); ASSERT_EQ(M.size(), 4u); FooS = M["foo"]; ASSERT_EQ(FooS.getKind(), Type::Int); ASSERT_EQ(FooS.getInt(), 1); BarS = M["bar"]; ASSERT_EQ(BarS.getKind(), Type::Int); ASSERT_EQ(BarS.getInt(), 2); auto FozS = M["foz"]; ASSERT_EQ(FozS.getKind(), Type::Int); ASSERT_EQ(FozS.getInt(), 3); auto BazS = M["baz"]; ASSERT_EQ(BazS.getKind(), Type::Int); ASSERT_EQ(BazS.getInt(), 4); Ok = Doc.readFromBlob( StringRef("\x82\xa3" "foz" "\xd0\x06\xa3" "bay" "\xd0\x08"), /*Multi=*/false, [](DocNode *Dest, DocNode Src, DocNode MapKey) { // Merger function that merges two ints by ORing their values, as long // as the map key is "foz". if (Src.isMap()) return Dest->isMap(); if (Src.isArray()) return Dest->isArray(); if (MapKey.isString() && MapKey.getString() == "foz" && Dest->getKind() == Type::Int && Src.getKind() == Type::Int) { *Dest = Src.getDocument()->getNode(Dest->getInt() | Src.getInt()); return true; } return false; }); ASSERT_TRUE(Ok); ASSERT_EQ(M.size(), 5u); FooS = M["foo"]; ASSERT_EQ(FooS.getKind(), Type::Int); ASSERT_EQ(FooS.getInt(), 1); BarS = M["bar"]; ASSERT_EQ(BarS.getKind(), Type::Int); ASSERT_EQ(BarS.getInt(), 2); FozS = M["foz"]; ASSERT_EQ(FozS.getKind(), Type::Int); ASSERT_EQ(FozS.getInt(), 7); BazS = M["baz"]; ASSERT_EQ(BazS.getKind(), Type::Int); ASSERT_EQ(BazS.getInt(), 4); auto BayS = M["bay"]; ASSERT_EQ(BayS.getKind(), Type::Int); ASSERT_EQ(BayS.getInt(), 8); } TEST(MsgPackDocument, TestWriteInt) { Document Doc; Doc.getRoot() = 1; std::string Buffer; Doc.writeToBlob(Buffer); ASSERT_EQ(Buffer, "\x01"); } TEST(MsgPackDocument, TestWriteArray) { Document Doc; auto A = Doc.getRoot().getArray(/*Convert=*/true); A.push_back(Doc.getNode(int64_t(1))); A.push_back(Doc.getNode()); std::string Buffer; Doc.writeToBlob(Buffer); ASSERT_EQ(Buffer, "\x92\x01\xc0"); } TEST(MsgPackDocument, TestWriteMap) { Document Doc; auto M = Doc.getRoot().getMap(/*Convert=*/true); M["foo"] = 1; M["bar"] = 2; std::string Buffer; Doc.writeToBlob(Buffer); ASSERT_EQ(Buffer, "\x82\xa3" "bar" "\x02\xa3" "foo" "\x01"); } TEST(MsgPackDocument, TestOutputYAMLArray) { Document Doc; auto A = Doc.getRoot().getArray(/*Convert=*/true); A.push_back(Doc.getNode(int64_t(1))); A.push_back(Doc.getNode(int64_t(2))); std::string Buffer; raw_string_ostream OStream(Buffer); Doc.toYAML(OStream); ASSERT_EQ(OStream.str(), "---\n- 1\n- 2\n...\n"); } TEST(MsgPackDocument, TestInputYAMLArray) { Document Doc; bool Ok = Doc.fromYAML("---\n- !int 0x1\n- !str 2\n...\n"); ASSERT_TRUE(Ok); ASSERT_EQ(Doc.getRoot().getKind(), Type::Array); auto A = Doc.getRoot().getArray(); ASSERT_EQ(A.size(), 2u); auto SI = A[0]; ASSERT_EQ(SI.getKind(), Type::UInt); ASSERT_EQ(SI.getUInt(), 1u); auto SS = A[1]; ASSERT_EQ(SS.getKind(), Type::String); ASSERT_EQ(SS.getString(), "2"); } TEST(MsgPackDocument, TestOutputYAMLMap) { Document Doc; auto M = Doc.getRoot().getMap(/*Convert=*/true); M["foo"] = 1; M["bar"] = 2U; auto N = Doc.getMapNode(); M["qux"] = N; N["baz"] = true; std::string Buffer; raw_string_ostream OStream(Buffer); Doc.toYAML(OStream); ASSERT_EQ(OStream.str(), "---\n" "bar: 2\n" "foo: 1\n" "qux:\n" " baz: true\n" "...\n"); } TEST(MsgPackDocument, TestOutputYAMLMapWithErase) { Document Doc; auto M = Doc.getRoot().getMap(/*Convert=*/true); M["foo"] = 1; M["bar"] = 2U; auto N = Doc.getMapNode(); M["qux"] = N; N["baz"] = true; M.erase(Doc.getNode("bar")); std::string Buffer; raw_string_ostream OStream(Buffer); Doc.toYAML(OStream); ASSERT_EQ(OStream.str(), "---\n" "foo: 1\n" "qux:\n" " baz: true\n" "...\n"); } TEST(MsgPackDocument, TestOutputYAMLMapHex) { Document Doc; Doc.setHexMode(); auto M = Doc.getRoot().getMap(/*Convert=*/true); M["foo"] = 1; M["bar"] = 2U; auto N = Doc.getMapNode(); M["qux"] = N; N["baz"] = true; std::string Buffer; raw_string_ostream OStream(Buffer); Doc.toYAML(OStream); ASSERT_EQ(OStream.str(), "---\n" "bar: 0x2\n" "foo: 1\n" "qux:\n" " baz: true\n" "...\n"); } TEST(MsgPackDocument, TestInputYAMLMap) { Document Doc; bool Ok = Doc.fromYAML("---\nfoo: !int 0x1\nbaz: !str 2\n...\n"); ASSERT_TRUE(Ok); ASSERT_EQ(Doc.getRoot().getKind(), Type::Map); auto M = Doc.getRoot().getMap(); ASSERT_EQ(M.size(), 2u); auto SI = M["foo"]; ASSERT_EQ(SI.getKind(), Type::UInt); ASSERT_EQ(SI.getUInt(), 1u); auto SS = M["baz"]; ASSERT_EQ(SS.getKind(), Type::String); ASSERT_EQ(SS.getString(), "2"); }