summaryrefslogtreecommitdiffstats
path: root/mfbt/tests
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/tests')
-rw-r--r--mfbt/tests/TestMaybe.cpp266
-rw-r--r--mfbt/tests/TestUtf8.cpp10
2 files changed, 261 insertions, 15 deletions
diff --git a/mfbt/tests/TestMaybe.cpp b/mfbt/tests/TestMaybe.cpp
index 2c56b85b6d..f9e5ae00dc 100644
--- a/mfbt/tests/TestMaybe.cpp
+++ b/mfbt/tests/TestMaybe.cpp
@@ -519,8 +519,6 @@ static bool TestCopyAndMove() {
{
Maybe<UnmovableValue> mayUnmovableValue = Some(UnmovableValue());
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
- mayUnmovableValue = Some(UnmovableValue());
- MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyAssigned);
mayUnmovableValue.reset();
mayUnmovableValue.emplace(UnmovableValue());
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
@@ -530,9 +528,8 @@ static bool TestCopyAndMove() {
static_assert(std::is_copy_constructible_v<Maybe<UnmovableValue>>);
static_assert(std::is_copy_assignable_v<Maybe<UnmovableValue>>);
- // XXX Why do these static_asserts not hold?
- // static_assert(!std::is_move_constructible_v<Maybe<UnmovableValue>>);
- // static_assert(!std::is_move_assignable_v<Maybe<UnmovableValue>>);
+ static_assert(!std::is_move_constructible_v<Maybe<UnmovableValue>>);
+ static_assert(!std::is_move_assignable_v<Maybe<UnmovableValue>>);
}
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
@@ -837,6 +834,15 @@ static bool TestApply() {
[&](const BasicValue& aVal) { gFunctionWasApplied = true; });
MOZ_RELEASE_ASSERT(gFunctionWasApplied == true);
+ // Check that apply can move the contained value.
+ mayValue = Some(BasicValue(1));
+ Maybe<BasicValue> otherValue;
+ std::move(mayValue).apply(
+ [&](BasicValue&& aVal) { otherValue = Some(std::move(aVal)); });
+ MOZ_RELEASE_ASSERT(mayValue.isNothing());
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+ MOZ_RELEASE_ASSERT(otherValue->GetStatus() == eWasMoveConstructed);
+
return true;
}
@@ -898,6 +904,14 @@ static bool TestMap() {
[&](const BasicValue& aVal) { return aVal.GetTag() * two; });
MOZ_RELEASE_ASSERT(mappedValue == Some(4));
+ // Check that map can move the contained value.
+ mayValue = Some(BasicValue(1));
+ Maybe<BasicValue> otherValue = std::move(mayValue).map(
+ [](BasicValue&& aValue) { return std::move(aValue); });
+ MOZ_RELEASE_ASSERT(mayValue.isNothing());
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+ MOZ_RELEASE_ASSERT(otherValue->GetStatus() == eWasMoveConstructed);
+
// Check that function object qualifiers are preserved when invoked.
struct F {
std::integral_constant<int, 1> operator()(int) & { return {}; }
@@ -1439,6 +1453,245 @@ static bool TestReference() {
return true;
}
+static Maybe<int> IncrementAndReturnTag(BasicValue& aValue) {
+ gFunctionWasApplied = true;
+ aValue.SetTag(aValue.GetTag() + 1);
+ return Some(aValue.GetTag());
+}
+
+static Maybe<int> AccessValueAndReturnNothing(const BasicValue&) {
+ gFunctionWasApplied = true;
+ return Nothing();
+}
+
+static Maybe<int> AccessValueAndReturnOther(const BasicValue&) {
+ gFunctionWasApplied = true;
+ return Some(42);
+}
+
+struct IncrementAndReturnTagFunctor {
+ IncrementAndReturnTagFunctor() : mBy(1) {}
+
+ Maybe<int> operator()(BasicValue& aValue) {
+ aValue.SetTag(aValue.GetTag() + mBy.GetTag());
+ return Some(aValue.GetTag());
+ }
+
+ BasicValue mBy;
+};
+
+struct AccessValueAndReturnOtherFunctor {
+ explicit AccessValueAndReturnOtherFunctor(int aVal) : mBy(aVal) {}
+
+ Maybe<BasicValue> operator()() {
+ gFunctionWasApplied = true;
+ return Some(mBy);
+ }
+
+ BasicValue mBy;
+};
+
+static bool TestAndThen() {
+ // Check that andThen handles the 'Nothing' case.
+ gFunctionWasApplied = false;
+ Maybe<BasicValue> mayValue;
+ Maybe<int> otherValue = mayValue.andThen(&AccessValueAndReturnOther);
+ MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(otherValue.isNothing());
+
+ // Check that andThen handles the 'Some' case.
+ mayValue = Some(BasicValue(1));
+ otherValue = mayValue.andThen(&AccessValueAndReturnNothing);
+ MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(otherValue.isNothing());
+ gFunctionWasApplied = false;
+ otherValue = mayValue.andThen(&IncrementAndReturnTag);
+ MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
+ MOZ_RELEASE_ASSERT(*otherValue == 2);
+ gFunctionWasApplied = false;
+ otherValue = mayValue.andThen(&AccessValueAndReturnOther);
+ MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(*otherValue == 42);
+
+ // Check that andThen works with a const reference.
+ const Maybe<BasicValue>& mayValueCRef = mayValue;
+ gFunctionWasApplied = false;
+ otherValue = mayValueCRef.andThen(&AccessValueAndReturnOther);
+ MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(*otherValue == 42);
+
+ // Check that andThen works with functors.
+ IncrementAndReturnTagFunctor tagIncrementer;
+ MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
+ mayValue = Some(BasicValue(1));
+ otherValue = mayValue.andThen(tagIncrementer);
+ MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
+ MOZ_RELEASE_ASSERT(*otherValue == 2);
+ MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
+
+ // Check that andThen works with lambda expressions.
+ gFunctionWasApplied = false;
+ mayValue = Some(BasicValue(2));
+ otherValue = mayValue.andThen(
+ [](BasicValue& aVal) { return Some(aVal.GetTag() * 2); });
+ MOZ_RELEASE_ASSERT(*otherValue == 4);
+ otherValue = otherValue.andThen([](int aVal) { return Some(aVal * 2); });
+ MOZ_RELEASE_ASSERT(*otherValue == 8);
+ otherValue = mayValueCRef.andThen([&](const BasicValue& aVal) {
+ gFunctionWasApplied = true;
+ return Some(42);
+ });
+ MOZ_RELEASE_ASSERT(gFunctionWasApplied == true);
+ MOZ_RELEASE_ASSERT(*otherValue == 42);
+
+ // Check that andThen can move the contained value.
+ mayValue = Some(BasicValue(1));
+ otherValue = std::move(mayValue).andThen([&](BasicValue&& aVal) {
+ BasicValue tmp = std::move(aVal);
+ return Some(tmp.GetTag());
+ });
+ MOZ_RELEASE_ASSERT(mayValue.isNothing());
+ MOZ_RELEASE_ASSERT(*otherValue == 1);
+
+ return true;
+}
+
+static bool TestOrElse() {
+ const auto createValue = [&](int aTag) {
+ return [&, aTag]() -> Maybe<BasicValue> {
+ gFunctionWasApplied = true;
+ return Some(BasicValue(aTag));
+ };
+ };
+ // Check that orElse handles the 'Some' case.
+ gFunctionWasApplied = false;
+ Maybe<BasicValue> mayValue = Some(BasicValue(1));
+ Maybe<BasicValue> otherValue = mayValue.orElse(createValue(2));
+ MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+
+ // Check that orElse handles the 'Nothing' case.
+ mayValue = Nothing();
+ otherValue = mayValue.orElse(createValue(1));
+ MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+ gFunctionWasApplied = false;
+ otherValue = otherValue.orElse(createValue(2));
+ MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+
+ // Check that orElse works with a const reference.
+ mayValue = Nothing();
+ const Maybe<BasicValue>& mayValueCRef = mayValue;
+ gFunctionWasApplied = false;
+ otherValue = mayValueCRef.orElse(createValue(1));
+ MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+
+ // Check that orElse works with functors.
+ gFunctionWasApplied = false;
+ AccessValueAndReturnOtherFunctor accesser(42);
+ mayValue = Some(BasicValue(1));
+ otherValue = mayValue.orElse(accesser);
+ MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+ mayValue = Nothing();
+ otherValue = mayValue.orElse(accesser);
+ MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(mayValue.isNothing());
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 42);
+
+ // Check that orElse works with lambda expressions.
+ gFunctionWasApplied = false;
+ mayValue = Nothing();
+ otherValue = mayValue.orElse([] { return Some(BasicValue(1)); });
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+ mayValue = otherValue.orElse([] { return Some(BasicValue(2)); });
+ MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
+ otherValue = mayValueCRef.orElse([&] {
+ gFunctionWasApplied = true;
+ return Some(BasicValue(42));
+ });
+ MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+
+ // Check that orElse can move the contained value.
+ mayValue = Some(BasicValue(1));
+ otherValue = std::move(mayValue).orElse([] { return Some(BasicValue(2)); });
+ MOZ_RELEASE_ASSERT(mayValue.isNothing());
+ MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
+
+ return true;
+}
+
+static bool TestComposedMoves() {
+ const auto moveAlong = [](UncopyableValue&& aValue) {
+ return Some(std::move(aValue));
+ };
+ const auto justNothing = []() -> Maybe<UncopyableValue> { return Nothing(); };
+ const auto createValue = [] { return Some(UncopyableValue()); };
+
+ // Check that andThen and orElse can propagate a non-copyable value created
+ // mid-chain.
+ Maybe<UncopyableValue> mayValue;
+ Maybe<UncopyableValue> movedValue = std::move(mayValue)
+ .andThen(moveAlong)
+ .orElse(createValue)
+ .andThen(moveAlong);
+ MOZ_RELEASE_ASSERT(mayValue.isNothing());
+ MOZ_RELEASE_ASSERT(movedValue->GetStatus() == eWasMoveConstructed);
+
+ // Check that andThen and orElse can propagate a non-copyable value created
+ // pre-chain.
+ mayValue = Some(UncopyableValue{});
+ movedValue = std::move(mayValue)
+ .andThen(moveAlong)
+ .orElse(justNothing)
+ .andThen(moveAlong);
+ MOZ_RELEASE_ASSERT(mayValue.isNothing());
+ MOZ_RELEASE_ASSERT(movedValue->GetStatus() == eWasMoveAssigned);
+
+ // Check that andThen and orElse can propagate a reference.
+ {
+ UncopyableValue val{};
+ UncopyableValue otherVal{};
+ const auto passAlong = [](UncopyableValue& aValue) {
+ return SomeRef(aValue);
+ };
+ const auto fallbackToOther = [&]() { return SomeRef(otherVal); };
+
+ Maybe<UncopyableValue&> mayRef = SomeRef(val);
+ Maybe<UncopyableValue&> chainedRef =
+ mayRef.andThen(passAlong).orElse(fallbackToOther).andThen(passAlong);
+ MOZ_RELEASE_ASSERT(&val != &otherVal,
+ "Distinct values should not compare equal");
+ MOZ_RELEASE_ASSERT(&*mayRef == &*chainedRef,
+ "Chain should pass along the same reference");
+ }
+
+ // Check that andThen and orElse can propagate a const reference.
+ {
+ const UncopyableValue val{};
+ const UncopyableValue otherVal{};
+ const auto passAlong = [](const UncopyableValue& aValue) {
+ return SomeRef(aValue);
+ };
+ const auto fallbackToOther = [&]() { return SomeRef(otherVal); };
+
+ Maybe<const UncopyableValue&> mayRef = SomeRef(val);
+ Maybe<const UncopyableValue&> chainedRef =
+ mayRef.andThen(passAlong).orElse(fallbackToOther).andThen(passAlong);
+ MOZ_RELEASE_ASSERT(&val != &otherVal,
+ "Distinct values should not compare equal");
+ MOZ_RELEASE_ASSERT(&*mayRef == &*chainedRef,
+ "Chain should pass along the same reference");
+ }
+
+ return true;
+}
+
// These are quasi-implementation details, but we assert them here to prevent
// backsliding to earlier times when Maybe<T> for smaller T took up more space
// than T's alignment required.
@@ -1468,6 +1721,9 @@ int main() {
RUN_TEST(TestSomePointerConversion);
RUN_TEST(TestTypeConversion);
RUN_TEST(TestReference);
+ RUN_TEST(TestAndThen);
+ RUN_TEST(TestOrElse);
+ RUN_TEST(TestComposedMoves);
return 0;
}
diff --git a/mfbt/tests/TestUtf8.cpp b/mfbt/tests/TestUtf8.cpp
index b3ff9e9ee8..2c51d9abfb 100644
--- a/mfbt/tests/TestUtf8.cpp
+++ b/mfbt/tests/TestUtf8.cpp
@@ -24,12 +24,6 @@ using mozilla::IsUtf8;
using mozilla::Span;
using mozilla::Utf8Unit;
-// Disable the C++ 2a warning. See bug #1509926
-#if defined(__clang__) && (__clang_major__ >= 6)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wc++2a-compat"
-#endif
-
static void TestUtf8Unit() {
Utf8Unit c('A');
MOZ_RELEASE_ASSERT(c.toChar() == 'A');
@@ -749,7 +743,3 @@ int main() {
TestDecodeOneUtf8CodePoint();
return 0;
}
-
-#if defined(__clang__) && (__clang_major__ >= 6)
-# pragma clang diagnostic pop
-#endif