#include <cstdint>
#include <limits>
#include <string>
#include <variant>
#include <gtest/gtest.h>
#include "game_field.h"
namespace
{
GameDefinitionSnapshot definition()
{
return {
{"test", "Test", "", GameVisibility::PUBLIC, 1},
{
{1, "test", "score", "Score", GameFieldType::INTEGER, 0, {}},
{2, "test", "note", "Note", GameFieldType::STRING, 1, {}},
{3, "test", "route", "Route", GameFieldType::CHOICE, 2,
{{"Home", 0}, {"Forest", 1}, {"A&B+ C", 2}}},
},
};
}
TEST(GameFieldTest, DecodesAllSupportedTypesAndUnsetValues)
{
const auto decoded = decodeGameFields(definition(), {
{"score", "-7"}, {"note", "Near\nthe station"},
{"route", "Forest"},
});
ASSERT_TRUE(decoded) << decoded.error().msg();
ASSERT_EQ(decoded->size(), 3);
EXPECT_EQ(std::get<std::int64_t>((*decoded)[0].value), -7);
EXPECT_EQ(
std::get<std::string>((*decoded)[1].value), "Near\nthe station");
EXPECT_EQ(std::get<std::string>((*decoded)[2].value), "Forest");
const auto empty = decodeGameFields(definition(), {
{"score", ""}, {"note", ""}, {"route", ""},
});
ASSERT_TRUE(empty);
EXPECT_TRUE(empty->empty());
}
TEST(GameFieldTest, AcceptsFullSignedIntegerRange)
{
auto smallest = decodeGameFields(definition(), {{
"score", std::to_string(std::numeric_limits<std::int64_t>::min())}});
auto largest = decodeGameFields(definition(), {{
"score", std::to_string(std::numeric_limits<std::int64_t>::max())}});
ASSERT_TRUE(smallest);
ASSERT_TRUE(largest);
EXPECT_EQ(
std::get<std::int64_t>(smallest->front().value),
std::numeric_limits<std::int64_t>::min());
EXPECT_EQ(
std::get<std::int64_t>(largest->front().value),
std::numeric_limits<std::int64_t>::max());
auto zero = decodeGameFields(definition(), {{"score", "0"}});
auto leading_zero = decodeGameFields(
definition(), {{"score", "007"}});
ASSERT_TRUE(zero);
ASSERT_TRUE(leading_zero);
EXPECT_EQ(std::get<std::int64_t>(zero->front().value), 0);
EXPECT_EQ(std::get<std::int64_t>(leading_zero->front().value), 7);
}
TEST(GameFieldTest, RejectsMalformedIntegersAndUnknownChoices)
{
for(const std::string& value : {
"+1", " 1", "1 ", "1.0", "1e2", "1x",
"9223372036854775808", "-9223372036854775809"})
{
EXPECT_FALSE(decodeGameFields(definition(), {{"score", value}}))
<< value;
}
EXPECT_FALSE(decodeGameFields(definition(), {{"route", "home"}}));
EXPECT_FALSE(decodeGameFields(definition(), {{"route", "Home "}}));
EXPECT_FALSE(decodeGameFields(definition(), {{"route", "Unknown"}}));
auto punctuation = decodeGameFields(
definition(), {{"route", "A&B+ C"}});
ASSERT_TRUE(punctuation);
EXPECT_EQ(
std::get<std::string>(punctuation->front().value), "A&B+ C");
}
TEST(GameFieldTest, RejectsUnknownKeysAndInvalidText)
{
EXPECT_FALSE(decodeGameFields(definition(), {{"other", "value"}}));
EXPECT_FALSE(decodeGameFields(
definition(), {{"note", std::string("bad\0text", 8)}}));
EXPECT_FALSE(decodeGameFields(
definition(), {{"note", std::string("\xc3", 1)}}));
const auto whitespace = decodeGameFields(
definition(), {{"note", " \n"}});
ASSERT_TRUE(whitespace);
EXPECT_EQ(std::get<std::string>(whitespace->front().value), " \n");
const std::string large_text(2 * 1024 * 1024, 'x');
auto large = decodeGameFields(
definition(), {{"note", large_text}});
ASSERT_TRUE(large);
EXPECT_EQ(std::get<std::string>(large->front().value), large_text);
}
} // namespace