Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
16 kB · 517 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518#include <components/esm/fourcc.hpp>#include <components/esm3/esmreader.hpp>#include <components/esm3/esmwriter.hpp>#include <components/esm3/variant.hpp>
#include <gmock/gmock.h>#include <gtest/gtest.h>
#include <array>#include <functional>
namespace{ using namespace testing; using namespace ESM;
constexpr std::uint32_t fakeRecordId = fourCC("FAKE");
Variant makeVariant(VarType type) { Variant v; v.setType(type); return v; }
Variant makeVariant(VarType type, int value) { Variant v; v.setType(type); v.setInteger(value); return v; }
TEST(ESMVariantTest, move_constructed_should_have_data) { Variant a(int{ 42 }); const Variant b(std::move(a)); ASSERT_EQ(b.getInteger(), 42); }
TEST(ESMVariantTest, copy_constructed_is_equal_to_source) { const Variant a(int{ 42 }); const Variant b(a); ASSERT_EQ(a, b); }
TEST(ESMVariantTest, copy_constructed_does_not_share_data_with_source) { const Variant a(int{ 42 }); Variant b(a); b.setInteger(13); ASSERT_EQ(a.getInteger(), 42); ASSERT_EQ(b.getInteger(), 13); }
TEST(ESMVariantTest, move_assigned_should_have_data) { Variant b; { Variant a(int{ 42 }); b = std::move(a); } ASSERT_EQ(b.getInteger(), 42); }
TEST(ESMVariantTest, copy_assigned_is_equal_to_source) { const Variant a(int{ 42 }); Variant b; b = a; ASSERT_EQ(a, b); }
TEST(ESMVariantTest, not_equal_is_negation_of_equal) { const Variant a(int{ 42 }); Variant b; b = a; ASSERT_TRUE(!(a != b)); }
TEST(ESMVariantTest, different_types_are_not_equal) { ASSERT_NE(Variant(int{ 42 }), Variant(float{ 2.7f })); }
struct ESMVariantWriteToOStreamTest : TestWithParam<std::tuple<Variant, std::string>> { };
TEST_P(ESMVariantWriteToOStreamTest, should_write) { const auto [variant, result] = GetParam(); std::ostringstream s; s << variant; ASSERT_EQ(s.str(), result); }
INSTANTIATE_TEST_SUITE_P(VariantAsString, ESMVariantWriteToOStreamTest, Values(std::make_tuple(Variant(), "variant none"), std::make_tuple(Variant(int{ 42 }), "variant long: 42"), std::make_tuple(Variant(float{ 2.7f }), "variant float: 2.7"), std::make_tuple(Variant(std::string("foo")), "variant string: \"foo\""), std::make_tuple(makeVariant(VT_Unknown), "variant unknown"), std::make_tuple(makeVariant(VT_Short, 42), "variant short: 42"), std::make_tuple(makeVariant(VT_Int, 42), "variant int: 42")));
struct ESMVariantGetTypeTest : Test { };
TEST(ESMVariantGetTypeTest, default_constructed_should_return_none) { ASSERT_EQ(Variant().getType(), VT_None); }
TEST(ESMVariantGetTypeTest, for_constructed_from_int_should_return_long) { ASSERT_EQ(Variant(int{}).getType(), VT_Long); }
TEST(ESMVariantGetTypeTest, for_constructed_from_float_should_return_float) { ASSERT_EQ(Variant(float{}).getType(), VT_Float); }
TEST(ESMVariantGetTypeTest, for_constructed_from_lvalue_string_should_return_string) { const std::string string; ASSERT_EQ(Variant(string).getType(), VT_String); }
TEST(ESMVariantGetTypeTest, for_constructed_from_rvalue_string_should_return_string) { ASSERT_EQ(Variant(std::string{}).getType(), VT_String); }
struct ESMVariantGetIntegerTest : Test { };
TEST(ESMVariantGetIntegerTest, for_default_constructed_should_throw_exception) { ASSERT_THROW(Variant().getInteger(), std::runtime_error); }
TEST(ESMVariantGetIntegerTest, for_constructed_from_int_should_return_same_value) { const Variant variant(int{ 42 }); ASSERT_EQ(variant.getInteger(), 42); }
TEST(ESMVariantGetIntegerTest, for_constructed_from_float_should_return_casted_to_int) { const Variant variant(float{ 2.7 }); ASSERT_EQ(variant.getInteger(), 2); }
TEST(ESMVariantGetIntegerTest, for_constructed_from_string_should_throw_exception) { const Variant variant(std::string("foo")); ASSERT_THROW(variant.getInteger(), std::runtime_error); }
TEST(ESMVariantGetFloatTest, for_default_constructed_should_throw_exception) { ASSERT_THROW(Variant().getFloat(), std::runtime_error); }
TEST(ESMVariantGetFloatTest, for_constructed_from_int_should_return_casted_to_float) { const Variant variant(int{ 42 }); ASSERT_EQ(variant.getFloat(), 42); }
TEST(ESMVariantGetFloatTest, for_constructed_from_float_should_return_same_value) { const Variant variant(float{ 2.7f }); ASSERT_EQ(variant.getFloat(), 2.7f); }
TEST(ESMVariantGetFloatTest, for_constructed_from_string_should_throw_exception) { const Variant variant(std::string("foo")); ASSERT_THROW(variant.getFloat(), std::runtime_error); }
TEST(ESMVariantGetStringTest, for_default_constructed_should_throw_exception) { ASSERT_THROW(Variant().getString(), std::bad_variant_access); }
TEST(ESMVariantGetStringTest, for_constructed_from_int_should_throw_exception) { const Variant variant(int{ 42 }); ASSERT_THROW(variant.getString(), std::bad_variant_access); }
TEST(ESMVariantGetStringTest, for_constructed_from_float_should_throw_exception) { const Variant variant(float{ 2.7 }); ASSERT_THROW(variant.getString(), std::bad_variant_access); }
TEST(ESMVariantGetStringTest, for_constructed_from_string_should_return_same_value) { const Variant variant(std::string("foo")); ASSERT_EQ(variant.getString(), "foo"); }
TEST(ESMVariantSetTypeTest, for_unknown_should_reset_data) { Variant variant(int{ 42 }); variant.setType(VT_Unknown); ASSERT_THROW(variant.getInteger(), std::runtime_error); }
TEST(ESMVariantSetTypeTest, for_none_should_reset_data) { Variant variant(int{ 42 }); variant.setType(VT_None); ASSERT_THROW(variant.getInteger(), std::runtime_error); }
TEST(ESMVariantSetTypeTest, for_same_type_should_not_change_value) { Variant variant(int{ 42 }); variant.setType(VT_Long); ASSERT_EQ(variant.getInteger(), 42); }
TEST(ESMVariantSetTypeTest, for_float_replaced_by_int_should_cast_float_to_int) { Variant variant(float{ 2.7f }); variant.setType(VT_Int); ASSERT_EQ(variant.getInteger(), 2); }
TEST(ESMVariantSetTypeTest, for_string_replaced_by_int_should_set_default_initialized_data) { Variant variant(std::string("foo")); variant.setType(VT_Int); ASSERT_EQ(variant.getInteger(), 0); }
TEST(ESMVariantSetTypeTest, for_default_constructed_replaced_by_float_should_set_default_initialized_value) { Variant variant; variant.setType(VT_Float); ASSERT_EQ(variant.getInteger(), 0.0f); }
TEST(ESMVariantSetTypeTest, for_float_replaced_by_short_should_cast_data_to_int) { Variant variant(float{ 2.7f }); variant.setType(VT_Short); ASSERT_EQ(variant.getInteger(), 2); }
TEST(ESMVariantSetTypeTest, for_float_replaced_by_long_should_cast_data_to_int) { Variant variant(float{ 2.7f }); variant.setType(VT_Long); ASSERT_EQ(variant.getInteger(), 2); }
TEST(ESMVariantSetTypeTest, for_int_replaced_by_float_should_cast_data_to_float) { Variant variant(int{ 42 }); variant.setType(VT_Float); ASSERT_EQ(variant.getFloat(), 42.0f); }
TEST(ESMVariantSetTypeTest, for_int_replaced_by_string_should_set_default_initialized_data) { Variant variant(int{ 42 }); variant.setType(VT_String); ASSERT_EQ(variant.getString(), ""); }
TEST(ESMVariantSetIntegerTest, for_default_constructed_should_throw_exception) { Variant variant; ASSERT_THROW(variant.setInteger(42), std::runtime_error); }
TEST(ESMVariantSetIntegerTest, for_unknown_should_throw_exception) { Variant variant; variant.setType(VT_Unknown); ASSERT_THROW(variant.setInteger(42), std::runtime_error); }
TEST(ESMVariantSetIntegerTest, for_default_int_should_change_value) { Variant variant(int{ 13 }); variant.setInteger(42); ASSERT_EQ(variant.getInteger(), 42); }
TEST(ESMVariantSetIntegerTest, for_int_should_change_value) { Variant variant; variant.setType(VT_Int); variant.setInteger(42); ASSERT_EQ(variant.getInteger(), 42); }
TEST(ESMVariantSetIntegerTest, for_short_should_change_value) { Variant variant; variant.setType(VT_Short); variant.setInteger(42); ASSERT_EQ(variant.getInteger(), 42); }
TEST(ESMVariantSetIntegerTest, for_float_should_change_value) { Variant variant(float{ 2.7f }); variant.setInteger(42); ASSERT_EQ(variant.getFloat(), 42.0f); }
TEST(ESMVariantSetIntegerTest, for_string_should_throw_exception) { Variant variant(std::string{}); ASSERT_THROW(variant.setInteger(42), std::runtime_error); }
TEST(ESMVariantSetFloatTest, for_default_constructed_should_throw_exception) { Variant variant; ASSERT_THROW(variant.setFloat(2.7f), std::runtime_error); }
TEST(ESMVariantSetFloatTest, for_unknown_should_throw_exception) { Variant variant; variant.setType(VT_Unknown); ASSERT_THROW(variant.setFloat(2.7f), std::runtime_error); }
TEST(ESMVariantSetFloatTest, for_default_int_should_change_value) { Variant variant(int{ 13 }); variant.setFloat(2.7f); ASSERT_EQ(variant.getInteger(), 2); }
TEST(ESMVariantSetFloatTest, for_int_should_change_value) { Variant variant; variant.setType(VT_Int); variant.setFloat(2.7f); ASSERT_EQ(variant.getInteger(), 2); }
TEST(ESMVariantSetFloatTest, for_short_should_change_value) { Variant variant; variant.setType(VT_Short); variant.setFloat(2.7f); ASSERT_EQ(variant.getInteger(), 2); }
TEST(ESMVariantSetFloatTest, for_float_should_change_value) { Variant variant(float{ 2.7f }); variant.setFloat(3.14f); ASSERT_EQ(variant.getFloat(), 3.14f); }
TEST(ESMVariantSetFloatTest, for_string_should_throw_exception) { Variant variant(std::string{}); ASSERT_THROW(variant.setFloat(2.7f), std::runtime_error); }
TEST(ESMVariantSetStringTest, for_default_constructed_should_throw_exception) { Variant variant; ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); }
TEST(ESMVariantSetStringTest, for_unknown_should_throw_exception) { Variant variant; variant.setType(VT_Unknown); ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); }
TEST(ESMVariantSetStringTest, for_default_int_should_throw_exception) { Variant variant(int{ 13 }); ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); }
TEST(ESMVariantSetStringTest, for_int_should_throw_exception) { Variant variant; variant.setType(VT_Int); ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); }
TEST(ESMVariantSetStringTest, for_short_should_throw_exception) { Variant variant; variant.setType(VT_Short); ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); }
TEST(ESMVariantSetStringTest, for_float_should_throw_exception) { Variant variant(float{ 2.7f }); ASSERT_THROW(variant.setString("foo"), std::bad_variant_access); }
TEST(ESMVariantSetStringTest, for_string_should_change_value) { Variant variant(std::string("foo")); variant.setString("bar"); ASSERT_EQ(variant.getString(), "bar"); }
struct WriteToESMTestCase { Variant mVariant; Variant::Format mFormat; std::size_t mDataSize{}; };
std::string write(const Variant& variant, const Variant::Format format) { std::ostringstream out; ESMWriter writer; writer.save(out); writer.startRecord(fakeRecordId); variant.write(writer, format); writer.endRecord(fakeRecordId); writer.close(); return out.str(); }
void read(const Variant::Format format, const std::string& data, Variant& result) { ESMReader reader; reader.open(std::make_unique<std::istringstream>(data), "stream"); ASSERT_TRUE(reader.hasMoreRecs()); ASSERT_EQ(reader.getRecName().toInt(), fakeRecordId); reader.getRecHeader(); result.read(reader, format); }
void writeAndRead(const Variant& variant, const Variant::Format format, std::size_t dataSize, Variant& result) { const std::string data = write(variant, format); EXPECT_EQ(data.size(), dataSize); read(format, data, result); }
struct ESMVariantToESMTest : TestWithParam<WriteToESMTestCase> { };
TEST_P(ESMVariantToESMTest, deserialized_is_equal_to_serialized) { const auto param = GetParam(); ESM::Variant result; writeAndRead(param.mVariant, param.mFormat, param.mDataSize, result); ASSERT_EQ(param.mVariant, result); }
const std::array deserializedParams = { WriteToESMTestCase{ Variant(), Variant::Format_Gmst, 340 }, WriteToESMTestCase{ Variant(int{ 42 }), Variant::Format_Global, 361 }, WriteToESMTestCase{ Variant(float{ 2.7f }), Variant::Format_Global, 361 }, WriteToESMTestCase{ Variant(float{ 2.7f }), Variant::Format_Info, 352 }, WriteToESMTestCase{ Variant(float{ 2.7f }), Variant::Format_Local, 352 }, WriteToESMTestCase{ makeVariant(VT_Short, 42), Variant::Format_Global, 361 }, WriteToESMTestCase{ makeVariant(VT_Short, 42), Variant::Format_Local, 350 }, WriteToESMTestCase{ makeVariant(VT_Int, 42), Variant::Format_Info, 352 }, WriteToESMTestCase{ makeVariant(VT_Int, 42), Variant::Format_Local, 352 }, WriteToESMTestCase{ Variant(float{ 2.7f }), Variant::Format_Gmst, 352 }, WriteToESMTestCase{ Variant(std::string("foo")), Variant::Format_Gmst, 351 }, WriteToESMTestCase{ makeVariant(VT_Int, 42), Variant::Format_Gmst, 352 }, };
INSTANTIATE_TEST_SUITE_P(VariantAndData, ESMVariantToESMTest, ValuesIn(deserializedParams));
struct ESMVariantWriteToESMFailTest : TestWithParam<WriteToESMTestCase> { };
TEST_P(ESMVariantWriteToESMFailTest, write_is_not_supported) { const auto param = GetParam(); std::ostringstream out; ESMWriter writer; writer.save(out); ASSERT_THROW(param.mVariant.write(writer, param.mFormat), std::runtime_error); }
INSTANTIATE_TEST_SUITE_P(VariantAndFormat, ESMVariantWriteToESMFailTest, Values(WriteToESMTestCase{ Variant(), Variant::Format_Global }, WriteToESMTestCase{ Variant(), Variant::Format_Info }, WriteToESMTestCase{ Variant(), Variant::Format_Local }, WriteToESMTestCase{ Variant(int{ 42 }), Variant::Format_Gmst }, WriteToESMTestCase{ Variant(int{ 42 }), Variant::Format_Info }, WriteToESMTestCase{ Variant(int{ 42 }), Variant::Format_Local }, WriteToESMTestCase{ Variant(std::string("foo")), Variant::Format_Global }, WriteToESMTestCase{ Variant(std::string("foo")), Variant::Format_Info }, WriteToESMTestCase{ Variant(std::string("foo")), Variant::Format_Local }, WriteToESMTestCase{ makeVariant(VT_Unknown), Variant::Format_Global }, WriteToESMTestCase{ makeVariant(VT_Int, 42), Variant::Format_Global }, WriteToESMTestCase{ makeVariant(VT_Short, 42), Variant::Format_Gmst }, WriteToESMTestCase{ makeVariant(VT_Short, 42), Variant::Format_Info }));}