From b56a50064caf2a590ba43699e0074690fcd431bf Mon Sep 17 00:00:00 2001 From: Jeff McGlynn Date: Wed, 20 Jun 2018 11:34:20 -0700 Subject: Initial version of astc-codec for open source release Contains an implementation of an ASTC decoder that is able to pass the dEQP ASTC LDR tests. astc-codec has no external dependencies for the main library, only for test code, and is licensed under the Apache license. Components: include/ - Public API that can decode ASTC LDR data into a RGBA UNORM8 buffer. src/base/ - Base library with common functionality not directly related to ASTC decoding. Contains a uint128 implementation, BitStream for reading/writing bits with a primitive (or uint128 type), Optional implementation (to not take a dependency on C++17), and more. src/decoder/ - Internal implementation of the ASTC decoder. src/base/test/, src/decoder/test/ - Unit tests (and a fuzzing test) for the astc decoder. src/decoder/testdata/ - Sample ASTC images and golden image results for testing. src/decoder/tools/ - A tool to inspect contents of an ASTC file. third_party/ - Third party libraries, only used for tests. Change-Id: Ia98e5a7dc847daa3d3a48c5e62d94b8fb1cb98bd --- src/base/test/optional_test.cpp | 481 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 481 insertions(+) create mode 100644 src/base/test/optional_test.cpp (limited to 'src/base/test/optional_test.cpp') diff --git a/src/base/test/optional_test.cpp b/src/base/test/optional_test.cpp new file mode 100644 index 0000000..1eeefbd --- /dev/null +++ b/src/base/test/optional_test.cpp @@ -0,0 +1,481 @@ +// 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 -- cgit v1.2.3