// Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/base/optional.h" #include #include #include namespace astc_codec { namespace base { TEST(Optional, TypeProperties) { // Making sure optional has the correct alignment and doesn't waste too much // space static_assert(sizeof(Optional) == 2, "bad Optional size"); static_assert(std::alignment_of>::value == std::alignment_of::value, "bad Optional alignment"); static_assert(sizeof(Optional) == 2, "bad Optional size"); static_assert(std::alignment_of>::value == std::alignment_of::value, "bad Optional alignment"); static_assert(sizeof(Optional) == 4, "bad Optional size"); static_assert(std::alignment_of>::value == std::alignment_of::value, "bad Optional alignment"); static_assert(sizeof(Optional) == 8, "bad Optional size"); static_assert(std::alignment_of>::value == std::alignment_of::value, "bad Optional alignment"); static_assert(sizeof(Optional) == 16, "bad Optional size"); static_assert(std::alignment_of>::value == std::alignment_of::value, "bad Optional alignment"); struct S128 { int64_t data[2]; }; static_assert(sizeof(Optional) == 3 * sizeof(int64_t), "bad Optional size"); static_assert(std::alignment_of>::value == std::alignment_of::value, "bad Optional alignment"); } TEST(Optional, ConstructFromValue) { { Optional o; EXPECT_FALSE(o); } { Optional o = {}; EXPECT_FALSE(o); } { Optional o = kNullopt; EXPECT_FALSE(o); } { Optional o(1); EXPECT_TRUE(o); EXPECT_EQ(1, *o); } { // check the std::decay<> constructor Optional o = static_cast(1); EXPECT_TRUE(o); EXPECT_EQ(1, *o); } { Optional o = 1; EXPECT_TRUE(o); EXPECT_EQ(1, *o); } { Optional o{1}; EXPECT_TRUE(o); EXPECT_EQ(1, *o); } { short val = 10; Optional o = val; EXPECT_TRUE(o); EXPECT_EQ(10, *o); } { Optional> o(kInplace, 10); EXPECT_TRUE(o); EXPECT_EQ((std::vector(10)), *o); } { Optional> o(kInplace, {1, 2, 3, 4}); EXPECT_TRUE(o); EXPECT_EQ((std::vector{1, 2, 3, 4}), *o); } } TEST(Optional, ConstructFromOptional) { { Optional o = Optional(); EXPECT_FALSE(o); } { Optional o2; Optional o(o2); EXPECT_FALSE(o); } { Optional o2 = 42; Optional o(o2); EXPECT_TRUE(o); EXPECT_EQ(42, *o); } { Optional o(Optional(1)); EXPECT_TRUE(o); EXPECT_EQ(1, *o); } { Optional o2 = 2; Optional o = o2; EXPECT_TRUE(o); EXPECT_EQ(2, *o); } { Optional> o2 = std::vector{20, 30, 40}; Optional> o = o2; EXPECT_TRUE(o); EXPECT_EQ((std::vector{20, 30, 40}), *o); } } TEST(Optional, Assign) { { Optional o; o = 1; EXPECT_TRUE(o); EXPECT_EQ(1, *o); o = 2; EXPECT_TRUE(o); EXPECT_EQ(2, *o); o = kNullopt; EXPECT_FALSE(o); o = Optional(10); EXPECT_TRUE(o); EXPECT_EQ(10, *o); Optional o2; o = o2; EXPECT_FALSE(o); o = 2u; EXPECT_TRUE(o); EXPECT_EQ(2, *o); o = Optional(); EXPECT_FALSE(o); o = Optional(20); EXPECT_TRUE(o); EXPECT_EQ(20, *o); Optional o3(200); o = o3; EXPECT_TRUE(o); EXPECT_EQ(200, *o); o = {}; EXPECT_FALSE(o); // check the std::decay<> assignment o = static_cast(1); EXPECT_TRUE(o); EXPECT_EQ(1, *o); } } TEST(Optional, MakeOptional) { { auto o = makeOptional(1); static_assert(std::is_same>::value, "Bad type deduction in makeOptional()"); EXPECT_TRUE(o); EXPECT_EQ(1, *o); } { auto o = makeOptional(std::vector{'1', '2'}); static_assert(std::is_same>>::value, "Bad type deduction in makeOptional()"); EXPECT_TRUE(o); EXPECT_EQ((std::vector{'1', '2'}), *o); } { // check std::decay<> in the factory function auto o = makeOptional("String"); static_assert(std::is_same>::value, "Bad type deduction in makeOptional()"); EXPECT_TRUE(o); EXPECT_STREQ("String", *o); } { auto o = makeOptional("String"); static_assert(std::is_same>::value, "Bad type deduction in makeOptional()"); EXPECT_TRUE(o); EXPECT_STREQ("String", o->c_str()); } { auto o = makeOptional(5, 'b'); static_assert(std::is_same>::value, "Bad type deduction in makeOptional()"); EXPECT_TRUE(o); EXPECT_STREQ("bbbbb", o->c_str()); } { auto o = makeOptional(); static_assert(std::is_same>::value, "Bad type deduction in makeOptional()"); EXPECT_TRUE(o); EXPECT_STREQ("", o->c_str()); } } TEST(Optional, Move) { auto o = makeOptional(std::unique_ptr(new int(10))); { decltype(o) o2 = std::move(o); EXPECT_TRUE(o); EXPECT_TRUE(o2); EXPECT_FALSE(bool(*o)); EXPECT_TRUE(bool(*o2)); EXPECT_EQ(10, **o2); decltype(o) o3; o3 = std::move(o2); EXPECT_TRUE(o2); EXPECT_TRUE(o3); EXPECT_FALSE(bool(*o2)); EXPECT_TRUE(bool(*o3)); EXPECT_EQ(10, **o3); o3 = std::move(o2); EXPECT_TRUE(o2); EXPECT_TRUE(o3); EXPECT_FALSE(bool(*o2)); EXPECT_FALSE(bool(*o3)); } { decltype(o) o1; decltype(o) o2 = std::move(o1); EXPECT_FALSE(o1); EXPECT_FALSE(o2); o2 = std::move(o1); EXPECT_FALSE(o1); EXPECT_FALSE(o2); decltype(o) o3{kInplace, new int(20)}; o3 = std::move(o1); EXPECT_FALSE(o1); EXPECT_FALSE(o3); } } TEST(Optional, Value) { auto o = makeOptional(1); EXPECT_EQ(1, o.value()); EXPECT_EQ(1, o.valueOr(2)); o = kNullopt; EXPECT_EQ(2, o.valueOr(2)); } TEST(Optional, Clear) { auto o = makeOptional(1); o.clear(); EXPECT_FALSE(o); o.clear(); EXPECT_FALSE(o); } TEST(Optional, Emplace) { auto o = makeOptional(std::vector{1, 2, 3, 4}); o.emplace(3, 1); EXPECT_TRUE(o); EXPECT_EQ((std::vector{1, 1, 1}), *o); EXPECT_EQ(3U, o->capacity()); o.clear(); o.emplace({1, 2}); EXPECT_TRUE(o); EXPECT_EQ((std::vector{1, 2}), *o); EXPECT_EQ(2U, o->capacity()); } TEST(Optional, Reset) { auto o = makeOptional(std::vector{1, 2, 3, 4}); o.reset(std::vector{4, 3}); EXPECT_TRUE(o); EXPECT_EQ((std::vector{4, 3}), *o); EXPECT_EQ(2U, o->capacity()); o.clear(); o.reset(std::vector{1}); EXPECT_EQ((std::vector{1}), *o); EXPECT_EQ(1U, o->capacity()); } TEST(Optional, CompareEqual) { EXPECT_TRUE(makeOptional(1) == makeOptional(1)); EXPECT_TRUE(makeOptional(1) == 1); EXPECT_TRUE(1 == makeOptional(1)); EXPECT_FALSE(makeOptional(1) == makeOptional(2)); EXPECT_FALSE(makeOptional(2) == 1); EXPECT_FALSE(2 == makeOptional(1)); EXPECT_TRUE(makeOptional(1) != makeOptional(2)); EXPECT_TRUE(makeOptional(1) != 2); EXPECT_TRUE(1 != makeOptional(2)); EXPECT_FALSE(makeOptional(1) == kNullopt); EXPECT_FALSE(makeOptional(1) == Optional()); EXPECT_FALSE(kNullopt == makeOptional(1)); EXPECT_FALSE(Optional() == makeOptional(1)); EXPECT_TRUE(makeOptional(1) != kNullopt); EXPECT_TRUE(makeOptional(1) != Optional()); EXPECT_TRUE(kNullopt != makeOptional(1)); EXPECT_TRUE(Optional() != makeOptional(1)); EXPECT_TRUE(kNullopt == Optional()); EXPECT_TRUE(kNullopt == Optional()); EXPECT_FALSE(kNullopt != Optional()); EXPECT_FALSE(kNullopt != Optional()); EXPECT_TRUE(Optional() == Optional()); EXPECT_FALSE(Optional() != Optional()); } TEST(Optional, CompareLess) { EXPECT_TRUE(makeOptional(1) < makeOptional(2)); EXPECT_TRUE(1 < makeOptional(2)); EXPECT_TRUE(makeOptional(1) < 2); EXPECT_FALSE(makeOptional(1) < makeOptional(1)); EXPECT_FALSE(1 < makeOptional(1)); EXPECT_FALSE(makeOptional(1) < 1); EXPECT_FALSE(makeOptional(2) < makeOptional(1)); EXPECT_FALSE(2 < makeOptional(1)); EXPECT_FALSE(makeOptional(2) < 1); EXPECT_TRUE(kNullopt < makeOptional(2)); EXPECT_TRUE(Optional() < makeOptional(2)); EXPECT_TRUE(Optional() < 2); EXPECT_FALSE(makeOptional(2) < kNullopt); EXPECT_FALSE(makeOptional(2) < Optional()); EXPECT_FALSE(2 < Optional()); EXPECT_FALSE(kNullopt < Optional()); EXPECT_FALSE(Optional() < kNullopt); } TEST(Optional, Destruction) { // create a reference counting class to check if we delete everything // we've created struct Track { Track(int& val) : mVal(val) { ++mVal.get(); } Track(std::initializer_list vals) : mVal(**vals.begin()) { ++mVal.get(); } Track(const Track& other) : mVal(other.mVal) { ++mVal.get(); } Track(Track&& other) : mVal(other.mVal) { ++mVal.get(); } Track& operator=(const Track& other) { --mVal.get(); mVal = other.mVal; ++mVal.get(); return *this; } Track& operator=(Track&& other) { --mVal.get(); mVal = other.mVal; ++mVal.get(); return *this; } ~Track() { --mVal.get(); } std::reference_wrapper mVal; }; int counter = 0; { auto o = makeOptional(Track(counter)); EXPECT_EQ(1, counter); } EXPECT_EQ(0, counter); { auto o = makeOptional(Track(counter)); EXPECT_EQ(1, counter); o.clear(); EXPECT_EQ(0, counter); } EXPECT_EQ(0, counter); { auto o = makeOptional(Track(counter)); EXPECT_EQ(1, counter); int counter2 = 0; o.emplace(counter2); EXPECT_EQ(0, counter); EXPECT_EQ(1, counter2); o = Track(counter); EXPECT_EQ(1, counter); EXPECT_EQ(0, counter2); auto o2 = o; EXPECT_EQ(2, counter); EXPECT_EQ(0, counter2); } EXPECT_EQ(0, counter); { auto o = makeOptional(Track(counter)); auto o2 = std::move(o); EXPECT_EQ(2, counter); o = o2; EXPECT_EQ(2, counter); } EXPECT_EQ(0, counter); int counter2 = 0; { Optional o; o.emplace(counter); EXPECT_EQ(1, counter); o.emplace(counter2); EXPECT_EQ(0, counter); EXPECT_EQ(1, counter2); } EXPECT_EQ(0, counter); EXPECT_EQ(0, counter2); { Optional o; o.emplace({&counter}); EXPECT_EQ(1, counter); counter2 = 0; o.emplace({&counter2}); EXPECT_EQ(0, counter); EXPECT_EQ(1, counter2); } EXPECT_EQ(0, counter); EXPECT_EQ(0, counter2); } } // namespace base } // namespace astc_codec