sTodo-m5paper-client/libraries/M5Utility/test/optional/noexcept.cpp
2025-06-30 20:47:33 +02:00

119 lines
3.7 KiB
C++

#include <gtest/gtest.h>
#include <m5_utility/stl/optional.hpp>
TEST(Optional, Noexcept)
{
m5::stl::optional<int> o1{4};
m5::stl::optional<int> o2{42};
{
SCOPED_TRACE("comparison with nullopt");
EXPECT_TRUE(noexcept(o1 == m5::stl::nullopt));
EXPECT_TRUE(noexcept(m5::stl::nullopt == o1));
EXPECT_TRUE(noexcept(o1 != m5::stl::nullopt));
EXPECT_TRUE(noexcept(m5::stl::nullopt != o1));
EXPECT_TRUE(noexcept(o1 < m5::stl::nullopt));
EXPECT_TRUE(noexcept(m5::stl::nullopt < o1));
EXPECT_TRUE(noexcept(o1 <= m5::stl::nullopt));
EXPECT_TRUE(noexcept(m5::stl::nullopt <= o1));
EXPECT_TRUE(noexcept(o1 > m5::stl::nullopt));
EXPECT_TRUE(noexcept(m5::stl::nullopt > o1));
EXPECT_TRUE(noexcept(o1 >= m5::stl::nullopt));
EXPECT_TRUE(noexcept(m5::stl::nullopt >= o1));
}
{
SCOPED_TRACE("swap");
// TODO see why this fails
#if !defined(_MSC_VER) || _MSC_VER > 1900
EXPECT_TRUE(noexcept(swap(o1, o2)) == noexcept(o1.swap(o2)));
struct nothrow_swappable {
nothrow_swappable &swap(const nothrow_swappable &) noexcept
{
return *this;
}
};
struct throw_swappable {
throw_swappable() = default;
throw_swappable(const throw_swappable &)
{
}
throw_swappable(throw_swappable &&)
{
}
throw_swappable &swap(const throw_swappable &)
{
return *this;
}
};
m5::stl::optional<nothrow_swappable> ont;
m5::stl::optional<throw_swappable> ot;
EXPECT_TRUE(noexcept(ont.swap(ont)));
EXPECT_TRUE(!noexcept(ot.swap(ot)));
#endif
}
{
SCOPED_TRACE("constructors");
// TODO see why this fails
#if !defined(_MSC_VER) || _MSC_VER > 1900
EXPECT_TRUE(noexcept(m5::stl::optional<int>{}));
EXPECT_TRUE(noexcept(m5::stl::optional<int>{m5::stl::nullopt}));
struct nothrow_move {
nothrow_move(nothrow_move &&) noexcept = default;
};
struct throw_move {
throw_move(throw_move &&)
{
}
};
using nothrow_opt = m5::stl::optional<nothrow_move>;
using throw_opt = m5::stl::optional<throw_move>;
EXPECT_TRUE(std::is_nothrow_move_constructible<nothrow_opt>::value);
EXPECT_TRUE(!std::is_nothrow_move_constructible<throw_opt>::value);
#endif
}
{
SCOPED_TRACE("assignment");
EXPECT_TRUE(noexcept(o1 = m5::stl::nullopt));
struct nothrow_move_assign {
nothrow_move_assign() = default;
nothrow_move_assign(nothrow_move_assign &&) noexcept = default;
nothrow_move_assign &operator=(const nothrow_move_assign &) = default;
};
struct throw_move_assign {
throw_move_assign() = default;
throw_move_assign(throw_move_assign &&)
{
}
throw_move_assign &operator=(const throw_move_assign &)
{
return *this;
}
};
using nothrow_opt = m5::stl::optional<nothrow_move_assign>;
using throw_opt = m5::stl::optional<throw_move_assign>;
EXPECT_TRUE(noexcept(std::declval<nothrow_opt>() = std::declval<nothrow_opt>()));
EXPECT_TRUE(!noexcept(std::declval<throw_opt>() = std::declval<throw_opt>()));
}
{
SCOPED_TRACE("observers");
EXPECT_TRUE(noexcept(static_cast<bool>(o1)));
EXPECT_TRUE(noexcept(o1.has_value()));
}
{
SCOPED_TRACE("modifiers");
EXPECT_TRUE(noexcept(o1.reset()));
}
}