/* * 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 o; REPORTER_ASSERT(r, !o); REPORTER_ASSERT(r, !o.has_value()); } DEF_TEST(SkTOptionalNulloptCtor, r) { skstd::optional o(skstd::nullopt); REPORTER_ASSERT(r, !o); REPORTER_ASSERT(r, !o.has_value()); } DEF_TEST(SkTOptionalValueOr, r) { { skstd::optional o; REPORTER_ASSERT(r, !strcmp(o.value_or("Hello"), "Hello")); } { skstd::optional o("Bye"); REPORTER_ASSERT(r, !strcmp(o.value_or("Hello"), "Bye")); } { skstd::optional> o; std::unique_ptr a = std::move(o).value_or(std::make_unique(5)); REPORTER_ASSERT(r, *a == 5); } { skstd::optional> o(std::make_unique(3)); std::unique_ptr a = std::move(o).value_or(std::make_unique(5)); REPORTER_ASSERT(r, *a == 3); } } DEF_TEST(SkTOptionalValue, r) { skstd::optional 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 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 { return skstd::nullopt; }; skstd::optional 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 o[] = {1, 2, skstd::nullopt, 4, 5}; skstd::optional five = 5; skstd::optional 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 o(1); REPORTER_ASSERT(r, o); REPORTER_ASSERT(r, o->fState == SkTOptionalTestPayload::kConstructed); REPORTER_ASSERT(r, o->fPayload == 1); skstd::optional 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 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 o; REPORTER_ASSERT(r, !o); // assign to an empty optional from an empty optional o = skstd::optional(); REPORTER_ASSERT(r, !o); // assign to an empty optional from a full optional skstd::optional 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(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(); REPORTER_ASSERT(r, !o); } DEF_TEST(SkTOptionalCopyAssignment, r) { skstd::optional o; REPORTER_ASSERT(r, !o); skstd::optional empty; skstd::optional 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> 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{1, 2, 3})); // Emplace with a normal constructor std::vector otherVec = {4, 5, 6}; o.emplace(otherVec.begin(), otherVec.end()); REPORTER_ASSERT(r, o.has_value()); REPORTER_ASSERT(r, (*o == std::vector{4, 5, 6})); } DEF_TEST(SkTOptionalNoDefaultConstructor, r) { class NoDefaultConstructor { public: NoDefaultConstructor(int value) : fValue(value) {} int fValue; }; skstd::optional o1; REPORTER_ASSERT(r, !o1); skstd::optional 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 empty; skstd::optional& emptyRef = empty; empty = emptyRef; REPORTER_ASSERT(r, !empty); empty = std::move(emptyRef); REPORTER_ASSERT(r, !empty); skstd::optional full("full"); skstd::optional& 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")); }