| /* |
| * Copyright 2021 Google LLC. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/private/SkTArray.h" |
| #include "include/private/SkTOptional.h" |
| |
| #include "tests/Test.h" |
| |
| DEF_TEST(SkTOptionalEmpty, r) { |
| skstd::optional<int> o; |
| REPORTER_ASSERT(r, !o); |
| REPORTER_ASSERT(r, !o.has_value()); |
| } |
| |
| DEF_TEST(SkTOptionalNulloptCtor, r) { |
| skstd::optional<int> o(skstd::nullopt); |
| REPORTER_ASSERT(r, !o); |
| REPORTER_ASSERT(r, !o.has_value()); |
| } |
| |
| DEF_TEST(SkTOptionalValueOr, r) { |
| { |
| skstd::optional<const char*> o; |
| REPORTER_ASSERT(r, !strcmp(o.value_or("Hello"), "Hello")); |
| } |
| { |
| skstd::optional<const char*> o("Bye"); |
| REPORTER_ASSERT(r, !strcmp(o.value_or("Hello"), "Bye")); |
| } |
| { |
| skstd::optional<std::unique_ptr<int>> o; |
| std::unique_ptr<int> a = std::move(o).value_or(std::make_unique<int>(5)); |
| REPORTER_ASSERT(r, *a == 5); |
| } |
| { |
| skstd::optional<std::unique_ptr<int>> o(std::make_unique<int>(3)); |
| std::unique_ptr<int> a = std::move(o).value_or(std::make_unique<int>(5)); |
| REPORTER_ASSERT(r, *a == 3); |
| } |
| } |
| |
| DEF_TEST(SkTOptionalValue, r) { |
| skstd::optional<const char*> o("test"); |
| REPORTER_ASSERT(r, o); |
| REPORTER_ASSERT(r, o.has_value()); |
| REPORTER_ASSERT(r, !strcmp(*o, "test")); |
| REPORTER_ASSERT(r, !strcmp(o.value(), "test")); |
| o.reset(); |
| REPORTER_ASSERT(r, !o); |
| REPORTER_ASSERT(r, !o.has_value()); |
| } |
| |
| DEF_TEST(SkTOptionalNulloptAssignment, r) { |
| skstd::optional<const char*> o("test"); |
| REPORTER_ASSERT(r, o); |
| REPORTER_ASSERT(r, o.has_value()); |
| o = skstd::nullopt; |
| REPORTER_ASSERT(r, !o); |
| REPORTER_ASSERT(r, !o.has_value()); |
| } |
| |
| DEF_TEST(SkTOptionalNulloptReturn, r) { |
| auto fn = []() -> skstd::optional<float> { return skstd::nullopt; }; |
| |
| skstd::optional<float> o = fn(); |
| REPORTER_ASSERT(r, !o); |
| REPORTER_ASSERT(r, !o.has_value()); |
| } |
| |
| DEF_TEST(SkTOptionalComparisons, r) { |
| int v[] = { 1, 2, 3, 4, 5 }; |
| skstd::optional<int> o[] = {1, 2, skstd::nullopt, 4, 5}; |
| skstd::optional<int> five = 5; |
| skstd::optional<int> six = 6; |
| |
| for (int index = 0; index < (int)SK_ARRAY_COUNT(v); ++index) { |
| REPORTER_ASSERT(r, v[index] < six); |
| REPORTER_ASSERT(r, o[index] < six); |
| REPORTER_ASSERT(r, six > v[index]); |
| REPORTER_ASSERT(r, six > o[index]); |
| |
| REPORTER_ASSERT(r, v[index] < 6); |
| REPORTER_ASSERT(r, o[index] < 6); |
| REPORTER_ASSERT(r, 6 > v[index]); |
| REPORTER_ASSERT(r, 6 > o[index]); |
| |
| REPORTER_ASSERT(r, !(six < v[index])); |
| REPORTER_ASSERT(r, !(six < o[index])); |
| REPORTER_ASSERT(r, !(v[index] > six)); |
| REPORTER_ASSERT(r, !(o[index] > six)); |
| |
| REPORTER_ASSERT(r, !(6 < v[index])); |
| REPORTER_ASSERT(r, !(6 < o[index])); |
| REPORTER_ASSERT(r, !(v[index] > 6)); |
| REPORTER_ASSERT(r, !(o[index] > 6)); |
| |
| REPORTER_ASSERT(r, v[index] <= five); |
| REPORTER_ASSERT(r, o[index] <= five); |
| REPORTER_ASSERT(r, five >= v[index]); |
| REPORTER_ASSERT(r, five >= o[index]); |
| |
| REPORTER_ASSERT(r, v[index] <= 5); |
| REPORTER_ASSERT(r, o[index] <= 5); |
| REPORTER_ASSERT(r, 5 >= v[index]); |
| REPORTER_ASSERT(r, 5 >= o[index]); |
| |
| REPORTER_ASSERT(r, skstd::nullopt <= o[index]); |
| REPORTER_ASSERT(r, !(skstd::nullopt > o[index])); |
| REPORTER_ASSERT(r, o[index] >= skstd::nullopt); |
| REPORTER_ASSERT(r, !(o[index] < skstd::nullopt)); |
| |
| if (o[index].has_value()) { |
| REPORTER_ASSERT(r, o[index] != skstd::nullopt); |
| REPORTER_ASSERT(r, skstd::nullopt != o[index]); |
| |
| REPORTER_ASSERT(r, o[index] == o[index]); |
| REPORTER_ASSERT(r, o[index] != six); |
| REPORTER_ASSERT(r, o[index] == v[index]); |
| REPORTER_ASSERT(r, v[index] == o[index]); |
| REPORTER_ASSERT(r, o[index] > 0); |
| REPORTER_ASSERT(r, o[index] >= 1); |
| REPORTER_ASSERT(r, o[index] <= 5); |
| REPORTER_ASSERT(r, o[index] < 6); |
| REPORTER_ASSERT(r, 0 < o[index]); |
| REPORTER_ASSERT(r, 1 <= o[index]); |
| REPORTER_ASSERT(r, 5 >= o[index]); |
| REPORTER_ASSERT(r, 6 > o[index]); |
| } else { |
| REPORTER_ASSERT(r, o[index] == skstd::nullopt); |
| REPORTER_ASSERT(r, skstd::nullopt == o[index]); |
| |
| REPORTER_ASSERT(r, o[index] == o[index]); |
| REPORTER_ASSERT(r, o[index] != five); |
| REPORTER_ASSERT(r, o[index] != v[index]); |
| REPORTER_ASSERT(r, v[index] != o[index]); |
| REPORTER_ASSERT(r, o[index] < 0); |
| REPORTER_ASSERT(r, o[index] <= 0); |
| REPORTER_ASSERT(r, 0 > o[index]); |
| REPORTER_ASSERT(r, 0 >= o[index]); |
| REPORTER_ASSERT(r, !(o[index] > 0)); |
| REPORTER_ASSERT(r, !(o[index] >= 0)); |
| REPORTER_ASSERT(r, !(0 < o[index])); |
| REPORTER_ASSERT(r, !(0 <= o[index])); |
| } |
| } |
| } |
| |
| class SkTOptionalTestPayload { |
| public: |
| enum State { |
| kConstructed, |
| kCopyConstructed, |
| kCopyAssigned, |
| kMoveConstructed, |
| kMoveAssigned, |
| kMovedFrom |
| }; |
| |
| SkTOptionalTestPayload(int payload) |
| : fState(kConstructed) |
| , fPayload(payload) {} |
| |
| SkTOptionalTestPayload(const SkTOptionalTestPayload& other) |
| : fState(kCopyConstructed) |
| , fPayload(other.fPayload) {} |
| |
| SkTOptionalTestPayload(SkTOptionalTestPayload&& other) |
| : fState(kMoveConstructed) |
| , fPayload(other.fPayload) { |
| other.fState = kMovedFrom; |
| } |
| |
| SkTOptionalTestPayload& operator=(const SkTOptionalTestPayload& other) { |
| fState = kCopyAssigned; |
| fPayload = other.fPayload; |
| return *this; |
| } |
| |
| SkTOptionalTestPayload& operator=(SkTOptionalTestPayload&& other) { |
| fState = kMoveAssigned; |
| fPayload = other.fPayload; |
| other.fState = kMovedFrom; |
| return *this; |
| } |
| State fState; |
| int fPayload; |
| }; |
| |
| DEF_TEST(SkTOptionalConstruction, r) { |
| skstd::optional<SkTOptionalTestPayload> o(1); |
| REPORTER_ASSERT(r, o); |
| REPORTER_ASSERT(r, o->fState == SkTOptionalTestPayload::kConstructed); |
| REPORTER_ASSERT(r, o->fPayload == 1); |
| |
| skstd::optional<SkTOptionalTestPayload> copy(o); |
| REPORTER_ASSERT(r, copy); |
| REPORTER_ASSERT(r, copy->fState == SkTOptionalTestPayload::kCopyConstructed); |
| REPORTER_ASSERT(r, copy->fPayload == 1); |
| REPORTER_ASSERT(r, o->fState == SkTOptionalTestPayload::kConstructed); |
| |
| skstd::optional<SkTOptionalTestPayload> move(std::move(o)); |
| REPORTER_ASSERT(r, move); |
| REPORTER_ASSERT(r, move->fState == SkTOptionalTestPayload::kMoveConstructed); |
| REPORTER_ASSERT(r, move->fPayload == 1); |
| // NOLINTNEXTLINE(bugprone-use-after-move) |
| REPORTER_ASSERT(r, o->fState == SkTOptionalTestPayload::kMovedFrom); |
| } |
| |
| DEF_TEST(SkTOptionalMoveAssignment, r) { |
| skstd::optional<SkTOptionalTestPayload> o; |
| REPORTER_ASSERT(r, !o); |
| |
| // assign to an empty optional from an empty optional |
| o = skstd::optional<SkTOptionalTestPayload>(); |
| REPORTER_ASSERT(r, !o); |
| |
| // assign to an empty optional from a full optional |
| skstd::optional<SkTOptionalTestPayload> full(1); |
| o = std::move(full); |
| REPORTER_ASSERT(r, o); |
| REPORTER_ASSERT(r, o->fState == SkTOptionalTestPayload::kMoveConstructed); |
| REPORTER_ASSERT(r, o->fPayload == 1); |
| // NOLINTNEXTLINE(bugprone-use-after-move) |
| REPORTER_ASSERT(r, full->fState == SkTOptionalTestPayload::kMovedFrom); |
| |
| // assign to a full optional from a full optional |
| full = skstd::optional<SkTOptionalTestPayload>(2); |
| o = std::move(full); |
| REPORTER_ASSERT(r, o); |
| REPORTER_ASSERT(r, o->fState == SkTOptionalTestPayload::kMoveAssigned); |
| REPORTER_ASSERT(r, o->fPayload == 2); |
| // NOLINTNEXTLINE(bugprone-use-after-move) |
| REPORTER_ASSERT(r, full->fState == SkTOptionalTestPayload::kMovedFrom); |
| |
| // assign to a full optional from an empty optional |
| o = skstd::optional<SkTOptionalTestPayload>(); |
| REPORTER_ASSERT(r, !o); |
| } |
| |
| DEF_TEST(SkTOptionalCopyAssignment, r) { |
| skstd::optional<SkTOptionalTestPayload> o; |
| REPORTER_ASSERT(r, !o); |
| |
| skstd::optional<SkTOptionalTestPayload> empty; |
| skstd::optional<SkTOptionalTestPayload> full(1); |
| |
| // assign to an empty optional from an empty optional |
| o = empty; |
| REPORTER_ASSERT(r, !o); |
| |
| // assign to an empty optional from a full optional |
| o = full; |
| REPORTER_ASSERT(r, o); |
| REPORTER_ASSERT(r, o->fState == SkTOptionalTestPayload::kCopyConstructed); |
| REPORTER_ASSERT(r, o->fPayload == 1); |
| |
| // assign to a full optional from a full optional |
| o = full; |
| REPORTER_ASSERT(r, o); |
| REPORTER_ASSERT(r, o->fState == SkTOptionalTestPayload::kCopyAssigned); |
| REPORTER_ASSERT(r, o->fPayload == 1); |
| |
| // assign to a full optional from an empty optional |
| o = empty; |
| REPORTER_ASSERT(r, !o); |
| } |
| |
| DEF_TEST(SkTOptionalEmplace, r) { |
| skstd::optional<std::vector<int>> o; |
| REPORTER_ASSERT(r, !o); |
| |
| // Emplace with the no-argument constructor |
| o.emplace(); |
| REPORTER_ASSERT(r, o.has_value()); |
| REPORTER_ASSERT(r, o->empty()); |
| |
| // Emplace with the initializer-list constructor |
| o.emplace({1, 2, 3}); |
| REPORTER_ASSERT(r, o.has_value()); |
| REPORTER_ASSERT(r, (*o == std::vector<int>{1, 2, 3})); |
| |
| // Emplace with a normal constructor |
| std::vector<int> otherVec = {4, 5, 6}; |
| o.emplace(otherVec.begin(), otherVec.end()); |
| REPORTER_ASSERT(r, o.has_value()); |
| REPORTER_ASSERT(r, (*o == std::vector<int>{4, 5, 6})); |
| } |
| |
| DEF_TEST(SkTOptionalNoDefaultConstructor, r) { |
| class NoDefaultConstructor { |
| public: |
| NoDefaultConstructor(int value) |
| : fValue(value) {} |
| |
| int fValue; |
| }; |
| |
| skstd::optional<NoDefaultConstructor> o1; |
| REPORTER_ASSERT(r, !o1); |
| skstd::optional<NoDefaultConstructor> o2(5); |
| REPORTER_ASSERT(r, o2); |
| REPORTER_ASSERT(r, o2->fValue == 5); |
| o1 = std::move(o2); |
| REPORTER_ASSERT(r, o1); |
| REPORTER_ASSERT(r, o1->fValue == 5); |
| } |
| |
| DEF_TEST(SkTOptionalSelfAssignment, r) { |
| skstd::optional<SkString> empty; |
| skstd::optional<SkString>& emptyRef = empty; |
| empty = emptyRef; |
| REPORTER_ASSERT(r, !empty); |
| empty = std::move(emptyRef); |
| REPORTER_ASSERT(r, !empty); |
| |
| skstd::optional<SkString> full("full"); |
| skstd::optional<SkString>& fullRef = full; |
| full = fullRef; |
| REPORTER_ASSERT(r, full); |
| REPORTER_ASSERT(r, *full == SkString("full")); |
| full = std::move(fullRef); |
| REPORTER_ASSERT(r, full); |
| REPORTER_ASSERT(r, *full == SkString("full")); |
| } |