/*
Ousía
Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
namespace ousia {
// static Logger logger;
static TerminalLogger logger(std::cerr, true);
namespace {
class TestManaged1 : public Managed {
public:
using Managed::Managed;
};
class TestManaged2 : public TestManaged1 {
public:
using TestManaged1::TestManaged1;
};
}
namespace RttiTypes {
static const Rtti TestManaged1 =
RttiBuilder("TestManaged1");
static const Rtti TestManaged2 =
RttiBuilder("TestManaged2").parent(&TestManaged1);
}
TEST(Argument, validateAny)
{
Argument a = Argument::Any("a");
ASSERT_FALSE(a.hasDefault());
{
Variant v{true};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isBool());
ASSERT_TRUE(v.asBool());
}
{
Variant v{"test"};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("test", v.asString());
}
{
Variant v{{1, 2, 3, 4}};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(Variant::arrayType({1, 2, 3, 4}), v.asArray());
}
}
TEST(Argument, validateAnyDefault)
{
Argument a = Argument::Any("a", true);
ASSERT_TRUE(a.hasDefault());
ASSERT_TRUE(a.getDefaultValue().asBool());
{
Variant v{true};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isBool());
ASSERT_TRUE(v.asBool());
}
{
Variant v{"test"};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("test", v.asString());
}
{
Variant v{{1, 2, 3, 4}};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(Variant::arrayType({1, 2, 3, 4}), v.asArray());
}
}
TEST(Argument, validateBool)
{
Argument a = Argument::Bool("a");
ASSERT_FALSE(a.hasDefault());
{
Variant v{true};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isBool());
ASSERT_TRUE(v.asBool());
}
{
Variant v{false};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isBool());
ASSERT_FALSE(v.asBool());
}
{
Variant v{1};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isBool());
ASSERT_FALSE(v.asBool());
}
}
TEST(Argument, validateBoolDefault)
{
Argument a = Argument::Bool("a", true);
ASSERT_TRUE(a.hasDefault());
ASSERT_TRUE(a.getDefaultValue().asBool());
{
Variant v{true};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isBool());
ASSERT_TRUE(v.asBool());
}
{
Variant v{false};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isBool());
ASSERT_FALSE(v.asBool());
}
{
Variant v{1};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isBool());
ASSERT_TRUE(v.asBool());
}
}
TEST(Argument, validateInt)
{
Argument a = Argument::Int("a");
ASSERT_FALSE(a.hasDefault());
{
Variant v{123};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isInt());
ASSERT_EQ(123, v.asInt());
}
{
Variant v{1.1};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isInt());
ASSERT_EQ(0, v.asInt());
}
}
TEST(Argument, validateIntDefault)
{
Argument a = Argument::Int("a", 42);
ASSERT_TRUE(a.hasDefault());
ASSERT_EQ(42, a.getDefaultValue().asInt());
{
Variant v{123};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isInt());
ASSERT_EQ(123, v.asInt());
}
{
Variant v{1.1};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isInt());
ASSERT_EQ(42, v.asInt());
}
}
TEST(Argument, validateDouble)
{
Argument a = Argument::Double("a");
ASSERT_FALSE(a.hasDefault());
{
Variant v{123};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isDouble());
ASSERT_EQ(123.0, v.asDouble());
}
{
Variant v{1.1};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isDouble());
ASSERT_EQ(1.1, v.asDouble());
}
{
Variant v{"1.0"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isDouble());
ASSERT_EQ(0.0, v.asDouble());
}
}
TEST(Argument, validateDoubleDefault)
{
Argument a = Argument::Double("a", 42.0);
ASSERT_TRUE(a.hasDefault());
ASSERT_EQ(42.0, a.getDefaultValue().asDouble());
{
Variant v{123};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isDouble());
ASSERT_EQ(123.0, v.asDouble());
}
{
Variant v{1.1};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isDouble());
ASSERT_EQ(1.1, v.asDouble());
}
{
Variant v{"1.0"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isDouble());
ASSERT_EQ(42.0, v.asDouble());
}
}
TEST(Argument, validateString)
{
Argument a = Argument::String("a");
ASSERT_FALSE(a.hasDefault());
{
Variant v{"test"};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("test", v.asString());
}
{
Variant v{true};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("true", v.asString());
}
{
Variant v{nullptr};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("null", v.asString());
}
{
Variant v{42};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("42", v.asString());
}
{
Variant v{42.5};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("42.5", v.asString());
}
{
Variant v{{1, 2, 3}};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("", v.asString());
}
}
TEST(Argument, validateStringDefault)
{
Argument a = Argument::String("a", "test2");
ASSERT_TRUE(a.hasDefault());
ASSERT_EQ("test2", a.getDefaultValue().asString());
{
Variant v{"test"};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("test", v.asString());
}
{
Variant v{true};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("true", v.asString());
}
{
Variant v{nullptr};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("null", v.asString());
}
{
Variant v{42};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("42", v.asString());
}
{
Variant v{42.5};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("42.5", v.asString());
}
{
Variant v{{1, 2, 3}};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isString());
ASSERT_EQ("test2", v.asString());
}
}
TEST(Argument, validateObject)
{
Manager mgr;
Argument a = Argument::Object("a", &RttiTypes::TestManaged1);
ASSERT_FALSE(a.hasDefault());
{
Rooted m{new Managed(mgr)};
Variant v = Variant::fromObject(m);
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(nullptr, v.asObject());
}
{
Rooted m{new TestManaged1(mgr)};
Variant v = Variant::fromObject(m);
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(m, v.asObject());
}
{
Rooted m{new TestManaged2(mgr)};
Variant v = Variant::fromObject(m);
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(m, v.asObject());
}
{
Rooted m1{nullptr};
Variant v = Variant::fromObject(m1);
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(nullptr, v.asObject());
}
{
Variant v("test");
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(nullptr, v.asObject());
}
}
TEST(Argument, validateObjectDefault)
{
Manager mgr;
Argument a = Argument::Object("a", &RttiTypes::TestManaged1, nullptr);
ASSERT_TRUE(a.hasDefault());
ASSERT_TRUE(a.getDefaultValue().isObject());
ASSERT_EQ(nullptr, a.getDefaultValue().asObject());
{
Rooted m{new Managed(mgr)};
Variant v = Variant::fromObject(m);
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(nullptr, v.asObject());
}
{
Rooted m{new TestManaged1(mgr)};
Variant v = Variant::fromObject(m);
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(m, v.asObject());
}
{
Rooted m{new TestManaged2(mgr)};
Variant v = Variant::fromObject(m);
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(m, v.asObject());
}
{
Rooted m1{nullptr};
Variant v = Variant::fromObject(m1);
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(nullptr, v.asObject());
}
{
Variant v("test");
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isObject());
ASSERT_EQ(nullptr, v.asObject());
}
}
static std::shared_ptr helloWorldFun{new Method{
[](Variant::arrayType &arr, void *) { return Variant{"Hello World"}; }}};
static std::shared_ptr goodbyeWorldFun{
new Method{[](Variant::arrayType &arr,
void *) { return Variant{"Goodbye Cruel World"}; }}};
TEST(Argument, validateFunction)
{
Argument a = Argument::Function("a");
ASSERT_FALSE(a.hasDefault());
{
Variant v = Variant::fromFunction(helloWorldFun);
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isFunction());
ASSERT_EQ("Hello World", v.asFunction()->call().asString());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isFunction());
ASSERT_TRUE(v.asFunction()->call().isNull());
}
}
TEST(Argument, validateFunctionDefault)
{
Argument a = Argument::Function("a", goodbyeWorldFun);
ASSERT_TRUE(a.hasDefault());
ASSERT_TRUE(a.getDefaultValue().isFunction());
ASSERT_EQ(goodbyeWorldFun, a.getDefaultValue().asFunction());
{
Variant v = Variant::fromFunction(helloWorldFun);
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isFunction());
ASSERT_EQ("Hello World", v.asFunction()->call().asString());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isFunction());
ASSERT_EQ("Goodbye Cruel World", v.asFunction()->call().asString());
}
}
TEST(Argument, validateArray)
{
Argument a = Argument::Array("a");
ASSERT_FALSE(a.hasDefault());
{
Variant::arrayType arr{1, "a", nullptr};
Variant v{arr};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(arr, v.asArray());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(Variant::arrayType{}, v.asArray());
}
}
TEST(Argument, validateArrayDefault)
{
Variant::arrayType arrDefault{1, "a", nullptr};
Argument a = Argument::Array("a", arrDefault);
ASSERT_TRUE(a.hasDefault());
ASSERT_TRUE(a.getDefaultValue().isArray());
ASSERT_EQ(arrDefault, a.getDefaultValue().asArray());
{
Variant::arrayType arr{"test1", 42.5};
Variant v{arr};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(arr, v.asArray());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(arrDefault, v.asArray());
}
}
TEST(Argument, validateArrayInner)
{
Argument a = Argument::Array("a", &RttiTypes::String);
ASSERT_FALSE(a.hasDefault());
{
Variant::arrayType arr{1, "a", nullptr};
Variant v{arr};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(Variant::arrayType({"1", "a", "null"}), v.asArray());
}
{
Variant::arrayType arr{1, Variant::fromObject(nullptr), "a"};
Variant v{arr};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(Variant::arrayType({"1", "", "a"}), v.asArray());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(Variant::arrayType{}, v.asArray());
}
}
TEST(Argument, validateArrayInnerDefault)
{
Variant::arrayType arrDefault{1, "a", nullptr};
Argument a = Argument::Array("a", &RttiTypes::String, arrDefault);
ASSERT_TRUE(a.hasDefault());
ASSERT_TRUE(a.getDefaultValue().isArray());
ASSERT_EQ(arrDefault, a.getDefaultValue().asArray());
{
Variant::arrayType arr{"test1", 42.5};
Variant v{arr};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(Variant::arrayType({"test1", "42.5"}), v.asArray());
}
{
Variant::arrayType arr{"test1", 42.5, Variant::fromObject(nullptr)};
Variant v{arr};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(arrDefault, v.asArray());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isArray());
ASSERT_EQ(arrDefault, v.asArray());
}
}
TEST(Argument, validateMap)
{
Argument a = Argument::Map("a");
ASSERT_FALSE(a.hasDefault());
{
Variant::mapType map{{"key1", 1}, {"key2", "a"}, {"key3", nullptr}};
Variant v{map};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(map, v.asMap());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(Variant::mapType{}, v.asMap());
}
}
TEST(Argument, validateMapDefault)
{
Variant::mapType mapDefault{{"key1", 1}, {"key2", "a"}, {"key3", nullptr}};
Argument a = Argument::Map("a", mapDefault);
ASSERT_TRUE(a.hasDefault());
ASSERT_TRUE(a.getDefaultValue().isMap());
ASSERT_EQ(mapDefault, a.getDefaultValue().asMap());
{
Variant::mapType map{{"a", true}, {"b", "a"}};
Variant v{map};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(map, v.asMap());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(mapDefault, v.asMap());
}
}
TEST(Argument, validateMapInnerType)
{
Argument a = Argument::Map("a", &RttiTypes::String);
ASSERT_FALSE(a.hasDefault());
{
Variant::mapType map{{"key1", 1}, {"key2", "a"}, {"key3", nullptr}};
Variant v{map};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(
Variant::mapType({{"key1", "1"}, {"key2", "a"}, {"key3", "null"}}),
v.asMap());
}
{
Variant::mapType map{
{"key1", 1}, {"key2", Variant::fromObject(nullptr)}, {"key3", "a"}};
Variant v{map};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(
Variant::mapType({{"key1", "1"}, {"key2", ""}, {"key3", "a"}}),
v.asMap());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(Variant::mapType{}, v.asMap());
}
}
TEST(Argument, validateMapInnerTypeDefault)
{
Variant::mapType mapDefault{{"key1", "1"}};
Argument a = Argument::Map("a", &RttiTypes::String, mapDefault);
ASSERT_TRUE(a.hasDefault());
ASSERT_TRUE(a.getDefaultValue().isMap());
ASSERT_EQ(mapDefault, a.getDefaultValue().asMap());
{
Variant::mapType map{{"key1", 1}, {"key2", "a"}, {"key3", nullptr}};
Variant v{map};
ASSERT_TRUE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(
Variant::mapType({{"key1", "1"}, {"key2", "a"}, {"key3", "null"}}),
v.asMap());
}
{
Variant::mapType map{
{"key1", 1}, {"key2", Variant::fromObject(nullptr)}, {"key3", "a"}};
Variant v{map};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(mapDefault, v.asMap());
}
{
Variant v{"foo"};
ASSERT_FALSE(a.validate(v, logger));
ASSERT_TRUE(v.isMap());
ASSERT_EQ(mapDefault, v.asMap());
}
}
TEST(Arguments, construction)
{
// This should work without exception
Arguments{Argument::Int("a"), Argument::Any("b")};
// This should throw an exception
ASSERT_THROW(Arguments({Argument::Int("a"), Argument::Any("a")}),
OusiaException);
ASSERT_THROW(Arguments({Argument::Int("test test")}), OusiaException);
}
TEST(Arguments, invalid)
{
Arguments argsInvalid{};
Arguments argsValid{{}};
Variant::arrayType arr{1};
ASSERT_TRUE(argsInvalid.validateArray(arr, logger)); // No error message
ASSERT_FALSE(argsValid.validateArray(arr, logger)); // Too many arguments
}
TEST(Arguments, validateArray)
{
Arguments args{Argument::Int("a"), Argument::String("b", "test"),
Argument::Bool("c", true)};
{
Variant::arrayType arr{1, 5, false};
ASSERT_TRUE(args.validateArray(arr, logger));
ASSERT_EQ(Variant::arrayType({1, "5", false}), arr);
}
{
Variant::arrayType arr{1, 5};
ASSERT_TRUE(args.validateArray(arr, logger));
ASSERT_EQ(Variant::arrayType({1, "5", true}), arr);
}
{
Variant::arrayType arr{1};
ASSERT_TRUE(args.validateArray(arr, logger));
ASSERT_EQ(Variant::arrayType({1, "test", true}), arr);
}
{
Variant::arrayType arr{};
ASSERT_FALSE(args.validateArray(arr, logger));
ASSERT_EQ(Variant::arrayType({0, "test", true}), arr);
}
{
Variant::arrayType arr{1, "bla", false, 42};
ASSERT_FALSE(args.validateArray(arr, logger));
ASSERT_EQ(Variant::arrayType({1, "bla", false}), arr);
}
}
TEST(Arguments, validateMap)
{
Arguments args{Argument::Int("a"), Argument::String("b", "test"),
Argument::Bool("c", true)};
{
Variant::mapType map{{"a", 2}, {"b", 5}, {"c", true}};
ASSERT_TRUE(args.validateMap(map, logger, false));
ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "5"}, {"c", true}}), map);
}
{
Variant::mapType map{{"a", 2}, {"c", false}};
ASSERT_TRUE(args.validateMap(map, logger, false));
ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "test"}, {"c", false}}),
map);
}
{
Variant::mapType map{{"a", 2}};
ASSERT_TRUE(args.validateMap(map, logger, false));
ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "test"}, {"c", true}}),
map);
}
{
Variant::mapType map{};
ASSERT_FALSE(args.validateMap(map, logger, false));
ASSERT_EQ(Variant::mapType({{"a", 0}, {"b", "test"}, {"c", true}}),
map);
}
{
Variant::mapType map{{"a", 2}, {"d", nullptr}};
ASSERT_FALSE(args.validateMap(map, logger, false));
ASSERT_EQ(Variant::mapType(
{{"a", 2}, {"b", "test"}, {"c", true}, {"d", nullptr}}),
map);
}
{
Variant::mapType map{{"a", 2}, {"d", nullptr}};
ASSERT_TRUE(args.validateMap(map, logger, true));
ASSERT_EQ(Variant::mapType(
{{"a", 2}, {"b", "test"}, {"c", true}, {"d", nullptr}}),
map);
}
}
TEST(Arguments, validateMissing)
{
Arguments args{Argument::String("a")};
{
Variant::mapType map{};
ASSERT_FALSE(args.validateMap(map, logger, false));
ASSERT_EQ(Variant::mapType({{"a", ""}}), map);
}
{
Variant::arrayType arr{};
ASSERT_FALSE(args.validateArray(arr, logger));
ASSERT_EQ(Variant::arrayType({""}), arr);
}
}
}