// Copyright 2014 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <string> #include <brillo/any.h> #include <gtest/gtest.h> using brillo::internal_details::Buffer; using brillo::GetTypeTag; TEST(Buffer, Empty) { Buffer buffer; EXPECT_TRUE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kExternal, buffer.storage_); EXPECT_EQ(nullptr, buffer.GetDataPtr()); } TEST(Buffer, Store_Int) { Buffer buffer; buffer.Assign(2); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); EXPECT_STREQ(GetTypeTag<int>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Store_Double) { Buffer buffer; buffer.Assign(2.3); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); EXPECT_STREQ(GetTypeTag<double>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Store_Pointers) { Buffer buffer; // nullptr buffer.Assign(nullptr); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); EXPECT_STREQ(GetTypeTag<std::nullptr_t>(), buffer.GetDataPtr()->GetTypeTag()); // char * buffer.Assign("abcd"); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); EXPECT_STREQ(GetTypeTag<const char*>(), buffer.GetDataPtr()->GetTypeTag()); // pointer to non-trivial object class NonTrivial { public: virtual ~NonTrivial() {} } non_trivial; buffer.Assign(&non_trivial); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); EXPECT_STREQ(GetTypeTag<NonTrivial*>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Store_NonTrivialObjects) { class NonTrivial { public: virtual ~NonTrivial() {} } non_trivial; Buffer buffer; buffer.Assign(non_trivial); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kExternal, buffer.storage_); EXPECT_STREQ(GetTypeTag<NonTrivial>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Store_Objects) { Buffer buffer; struct Small { double d; } small = {}; buffer.Assign(small); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); EXPECT_STREQ(GetTypeTag<Small>(), buffer.GetDataPtr()->GetTypeTag()); struct Large { char c[20]; } large = {}; buffer.Assign(large); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kExternal, buffer.storage_); EXPECT_STREQ(GetTypeTag<Large>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Copy) { Buffer buffer1; Buffer buffer2; buffer1.Assign(30); buffer1.CopyTo(&buffer2); EXPECT_FALSE(buffer1.IsEmpty()); EXPECT_FALSE(buffer2.IsEmpty()); EXPECT_STREQ(GetTypeTag<int>(), buffer1.GetDataPtr()->GetTypeTag()); EXPECT_STREQ(GetTypeTag<int>(), buffer2.GetDataPtr()->GetTypeTag()); EXPECT_EQ(30, buffer1.GetData<int>()); EXPECT_EQ(30, buffer2.GetData<int>()); buffer1.Assign(std::string("abc")); buffer1.CopyTo(&buffer2); EXPECT_FALSE(buffer1.IsEmpty()); EXPECT_FALSE(buffer2.IsEmpty()); EXPECT_STREQ(GetTypeTag<std::string>(), buffer1.GetDataPtr()->GetTypeTag()); EXPECT_STREQ(GetTypeTag<std::string>(), buffer2.GetDataPtr()->GetTypeTag()); EXPECT_EQ("abc", buffer1.GetData<std::string>()); EXPECT_EQ("abc", buffer2.GetData<std::string>()); } TEST(Buffer, Move) { // Move operations essentially leave the source object in a state that is // guaranteed to be safe for reuse or destruction. There is no other explicit // guarantees on the exact state of the source after move (e.g. that the // source Any will be Empty after the move is complete). Buffer buffer1; Buffer buffer2; buffer1.Assign(30); buffer1.MoveTo(&buffer2); // Contained types aren't flushed, so the source Any doesn't become empty. // The contained value is just moved, but for scalars this just copies // the data and any retains the actual type. EXPECT_FALSE(buffer1.IsEmpty()); EXPECT_FALSE(buffer2.IsEmpty()); EXPECT_STREQ(GetTypeTag<int>(), buffer2.GetDataPtr()->GetTypeTag()); EXPECT_EQ(30, buffer2.GetData<int>()); buffer1.Assign(std::string("abc")); buffer1.MoveTo(&buffer2); // External types are moved by just moving the pointer value from src to dest. // This will make the source object effectively "Empty". EXPECT_TRUE(buffer1.IsEmpty()); EXPECT_FALSE(buffer2.IsEmpty()); EXPECT_STREQ(GetTypeTag<std::string>(), buffer2.GetDataPtr()->GetTypeTag()); EXPECT_EQ("abc", buffer2.GetData<std::string>()); }