| // Copyright 2015 The Weave Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/commands/object_schema.h" | |
| #include <algorithm> | |
| #include <limits> | |
| #include <memory> | |
| #include <vector> | |
| #include <base/json/json_reader.h> | |
| #include <base/json/json_writer.h> | |
| #include <base/values.h> | |
| #include <gtest/gtest.h> | |
| #include "src/commands/prop_constraints.h" | |
| #include "src/commands/prop_types.h" | |
| #include "src/commands/schema_constants.h" | |
| #include "src/commands/unittest_utils.h" | |
| namespace weave { | |
| using test::CreateValue; | |
| using test::CreateDictionaryValue; | |
| namespace { | |
| template <typename T> | |
| std::vector<T> GetArrayValues(const ValueVector& arr) { | |
| std::vector<T> values; | |
| values.reserve(arr.size()); | |
| for (const auto& prop_value : arr) { | |
| const auto& value = static_cast<const TypedValueBase<T>&>(*prop_value); | |
| values.push_back(value.GetValue()); | |
| } | |
| return values; | |
| } | |
| template <typename T> | |
| std::vector<T> GetOneOfValues(const PropType* prop_type) { | |
| auto one_of = static_cast<const ConstraintOneOf*>( | |
| prop_type->GetConstraint(ConstraintType::OneOf)); | |
| if (!one_of) | |
| return {}; | |
| return GetArrayValues<T>(one_of->set_.value); | |
| } | |
| bool ValidateValue(const PropType& type, | |
| const base::Value& value, | |
| ErrorPtr* error) { | |
| std::unique_ptr<PropValue> val = type.CreatePropValue(value, error); | |
| return val != nullptr; | |
| } | |
| } // anonymous namespace | |
| TEST(CommandSchema, IntPropType_Empty) { | |
| IntPropType prop; | |
| EXPECT_TRUE(prop.GetConstraints().empty()); | |
| EXPECT_FALSE(prop.HasOverriddenAttributes()); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| EXPECT_EQ(nullptr, prop.GetDefaultValue()); | |
| } | |
| TEST(CommandSchema, IntPropType_Types) { | |
| IntPropType prop; | |
| EXPECT_EQ(nullptr, prop.GetBoolean()); | |
| EXPECT_EQ(&prop, prop.GetInt()); | |
| EXPECT_EQ(nullptr, prop.GetDouble()); | |
| EXPECT_EQ(nullptr, prop.GetString()); | |
| EXPECT_EQ(nullptr, prop.GetObject()); | |
| EXPECT_EQ(nullptr, prop.GetArray()); | |
| } | |
| TEST(CommandSchema, IntPropType_ToJson) { | |
| IntPropType prop; | |
| EXPECT_JSON_EQ("'integer'", *prop.ToJson(false, false)); | |
| EXPECT_JSON_EQ("{'type':'integer'}", *prop.ToJson(true, false)); | |
| IntPropType param2; | |
| param2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_JSON_EQ("{}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'minimum':3}").get(), &prop, nullptr); | |
| EXPECT_JSON_EQ("{'minimum':3}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'maximum':-7}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'maximum':-7}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'minimum':0,'maximum':5}").get(), | |
| &prop, nullptr); | |
| EXPECT_JSON_EQ("{'maximum':5,'minimum':0}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'enum':[1,2,3]}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("[1,2,3]", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'default':123}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'default':123}", *param2.ToJson(false, false)); | |
| } | |
| TEST(CommandSchema, IntPropType_FromJson) { | |
| IntPropType prop; | |
| prop.AddMinMaxConstraint(2, 8); | |
| IntPropType param2; | |
| param2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_FALSE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_EQ(2, prop.GetMinValue()); | |
| EXPECT_EQ(8, prop.GetMaxValue()); | |
| prop.AddMinMaxConstraint(-2, 30); | |
| param2.FromJson(CreateDictionaryValue("{'minimum':7}").get(), &prop, nullptr); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_EQ(7, param2.GetMinValue()); | |
| EXPECT_EQ(30, param2.GetMaxValue()); | |
| param2.FromJson(CreateDictionaryValue("{'maximum':17}").get(), &prop, | |
| nullptr); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_EQ(-2, param2.GetMinValue()); | |
| EXPECT_EQ(17, param2.GetMaxValue()); | |
| ASSERT_TRUE(param2.FromJson(CreateDictionaryValue("{'default':3}").get(), | |
| &prop, nullptr)); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| ASSERT_NE(nullptr, param2.GetDefaultValue()); | |
| EXPECT_EQ(3, param2.GetDefaultValue()->GetInt()->GetValue()); | |
| } | |
| TEST(CommandSchema, IntPropType_Validate) { | |
| IntPropType prop; | |
| prop.AddMinMaxConstraint(2, 4); | |
| ErrorPtr error; | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("-1"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("0"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("1"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("2"), &error)); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("3"), &error)); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("4"), &error)); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("5"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("true"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("3.0"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("'3'"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| } | |
| TEST(CommandSchema, IntPropType_CreateValue) { | |
| IntPropType prop; | |
| ErrorPtr error; | |
| auto val = prop.CreateValue(base::FundamentalValue{2}, &error); | |
| ASSERT_NE(nullptr, val.get()); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_EQ(2, val->GetValue()); | |
| val = prop.CreateValue(base::StringValue{"blah"}, &error); | |
| EXPECT_EQ(nullptr, val.get()); | |
| ASSERT_NE(nullptr, error.get()); | |
| EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode()); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| TEST(CommandSchema, BoolPropType_Empty) { | |
| BooleanPropType prop; | |
| EXPECT_TRUE(prop.GetConstraints().empty()); | |
| EXPECT_FALSE(prop.HasOverriddenAttributes()); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| EXPECT_EQ(nullptr, prop.GetDefaultValue()); | |
| EXPECT_FALSE(prop.IsRequired()); | |
| } | |
| TEST(CommandSchema, BoolPropType_Types) { | |
| BooleanPropType prop; | |
| EXPECT_EQ(nullptr, prop.GetInt()); | |
| EXPECT_EQ(&prop, prop.GetBoolean()); | |
| EXPECT_EQ(nullptr, prop.GetDouble()); | |
| EXPECT_EQ(nullptr, prop.GetString()); | |
| EXPECT_EQ(nullptr, prop.GetObject()); | |
| EXPECT_EQ(nullptr, prop.GetArray()); | |
| } | |
| TEST(CommandSchema, BoolPropType_ToJson) { | |
| BooleanPropType prop; | |
| EXPECT_JSON_EQ("'boolean'", *prop.ToJson(false, false)); | |
| EXPECT_JSON_EQ("{'type':'boolean'}", *prop.ToJson(true, false)); | |
| BooleanPropType param2; | |
| param2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_JSON_EQ("{}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'enum':[true,false]}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("[true,false]", *param2.ToJson(false, false)); | |
| EXPECT_JSON_EQ("{'enum':[true,false],'type':'boolean'}", | |
| *param2.ToJson(true, false)); | |
| param2.FromJson(CreateDictionaryValue("{'default':true}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'default':true}", *param2.ToJson(false, false)); | |
| } | |
| TEST(CommandSchema, BoolPropType_FromJson) { | |
| BooleanPropType prop; | |
| prop.FromJson(CreateDictionaryValue("{'enum':[true]}").get(), &prop, nullptr); | |
| BooleanPropType param2; | |
| param2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_FALSE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_EQ(std::vector<bool>{true}, GetOneOfValues<bool>(&prop)); | |
| BooleanPropType prop_base; | |
| BooleanPropType param3; | |
| ASSERT_TRUE(param3.FromJson(CreateDictionaryValue("{'default':false}").get(), | |
| &prop_base, nullptr)); | |
| EXPECT_TRUE(param3.HasOverriddenAttributes()); | |
| ASSERT_NE(nullptr, param3.GetDefaultValue()); | |
| EXPECT_FALSE(param3.GetDefaultValue()->GetBoolean()->GetValue()); | |
| } | |
| TEST(CommandSchema, BoolPropType_Validate) { | |
| BooleanPropType prop; | |
| prop.FromJson(CreateDictionaryValue("{'enum':[true]}").get(), &prop, nullptr); | |
| ErrorPtr error; | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("false"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("true"), &error)); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("1"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("3.0"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("'3'"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| } | |
| TEST(CommandSchema, BoolPropType_CreateValue) { | |
| BooleanPropType prop; | |
| ErrorPtr error; | |
| auto val = prop.CreateValue(base::FundamentalValue{true}, &error); | |
| ASSERT_NE(nullptr, val.get()); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_TRUE(val->GetValue()); | |
| val = prop.CreateValue(base::StringValue{"blah"}, &error); | |
| EXPECT_EQ(nullptr, val.get()); | |
| ASSERT_NE(nullptr, error.get()); | |
| EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode()); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| TEST(CommandSchema, DoublePropType_Empty) { | |
| DoublePropType prop; | |
| EXPECT_DOUBLE_EQ(std::numeric_limits<double>::lowest(), prop.GetMinValue()); | |
| EXPECT_DOUBLE_EQ((std::numeric_limits<double>::max)(), prop.GetMaxValue()); | |
| EXPECT_FALSE(prop.HasOverriddenAttributes()); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| EXPECT_EQ(nullptr, prop.GetDefaultValue()); | |
| EXPECT_FALSE(prop.IsRequired()); | |
| } | |
| TEST(CommandSchema, DoublePropType_Types) { | |
| DoublePropType prop; | |
| EXPECT_EQ(nullptr, prop.GetInt()); | |
| EXPECT_EQ(nullptr, prop.GetBoolean()); | |
| EXPECT_EQ(&prop, prop.GetDouble()); | |
| EXPECT_EQ(nullptr, prop.GetString()); | |
| EXPECT_EQ(nullptr, prop.GetObject()); | |
| EXPECT_EQ(nullptr, prop.GetArray()); | |
| } | |
| TEST(CommandSchema, DoublePropType_ToJson) { | |
| DoublePropType prop; | |
| EXPECT_JSON_EQ("'number'", *prop.ToJson(false, false)); | |
| EXPECT_JSON_EQ("{'type':'number'}", *prop.ToJson(true, false)); | |
| DoublePropType param2; | |
| param2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_JSON_EQ("{}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'minimum':3}").get(), &prop, nullptr); | |
| EXPECT_JSON_EQ("{'minimum':3.0}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'maximum':-7}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'maximum':-7.0}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'minimum':0,'maximum':5}").get(), | |
| &prop, nullptr); | |
| EXPECT_JSON_EQ("{'maximum':5.0,'minimum':0.0}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'default':12.3}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'default':12.3}", *param2.ToJson(false, false)); | |
| } | |
| TEST(CommandSchema, DoublePropType_FromJson) { | |
| DoublePropType prop; | |
| prop.AddMinMaxConstraint(2.5, 8.7); | |
| DoublePropType param2; | |
| param2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_FALSE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_DOUBLE_EQ(2.5, prop.GetMinValue()); | |
| EXPECT_DOUBLE_EQ(8.7, prop.GetMaxValue()); | |
| prop.AddMinMaxConstraint(-2.2, 30.4); | |
| param2.FromJson(CreateDictionaryValue("{'minimum':7}").get(), &prop, nullptr); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_DOUBLE_EQ(7.0, param2.GetMinValue()); | |
| EXPECT_DOUBLE_EQ(30.4, param2.GetMaxValue()); | |
| param2.FromJson(CreateDictionaryValue("{'maximum':17.2}").get(), &prop, | |
| nullptr); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_DOUBLE_EQ(-2.2, param2.GetMinValue()); | |
| EXPECT_DOUBLE_EQ(17.2, param2.GetMaxValue()); | |
| param2.FromJson(CreateDictionaryValue("{'minimum':0,'maximum':6.1}").get(), | |
| &prop, nullptr); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_DOUBLE_EQ(0.0, param2.GetMinValue()); | |
| EXPECT_DOUBLE_EQ(6.1, param2.GetMaxValue()); | |
| ASSERT_TRUE(param2.FromJson(CreateDictionaryValue("{'default':-1.234}").get(), | |
| &prop, nullptr)); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| ASSERT_NE(nullptr, param2.GetDefaultValue()); | |
| EXPECT_DOUBLE_EQ(-1.234, param2.GetDefaultValue()->GetDouble()->GetValue()); | |
| } | |
| TEST(CommandSchema, DoublePropType_Validate) { | |
| DoublePropType prop; | |
| prop.AddMinMaxConstraint(-1.2, 1.3); | |
| ErrorPtr error; | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("-2"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("-1.3"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("-1.2"), &error)); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("0.0"), &error)); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("1.3"), &error)); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("1.31"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("true"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("'0.0'"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| } | |
| TEST(CommandSchema, DoublePropType_CreateValue) { | |
| DoublePropType prop; | |
| ErrorPtr error; | |
| auto val = prop.CreateValue(base::FundamentalValue{2.0}, &error); | |
| ASSERT_NE(nullptr, val.get()); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_DOUBLE_EQ(2.0, val->GetValue()); | |
| val = prop.CreateValue(base::StringValue{"blah"}, &error); | |
| EXPECT_EQ(nullptr, val.get()); | |
| ASSERT_NE(nullptr, error.get()); | |
| EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode()); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| TEST(CommandSchema, StringPropType_Empty) { | |
| StringPropType prop; | |
| EXPECT_EQ(0, prop.GetMinLength()); | |
| EXPECT_EQ((std::numeric_limits<int>::max)(), prop.GetMaxLength()); | |
| EXPECT_FALSE(prop.HasOverriddenAttributes()); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| EXPECT_EQ(nullptr, prop.GetDefaultValue()); | |
| EXPECT_FALSE(prop.IsRequired()); | |
| } | |
| TEST(CommandSchema, StringPropType_Types) { | |
| StringPropType prop; | |
| EXPECT_EQ(nullptr, prop.GetInt()); | |
| EXPECT_EQ(nullptr, prop.GetBoolean()); | |
| EXPECT_EQ(nullptr, prop.GetDouble()); | |
| EXPECT_EQ(&prop, prop.GetString()); | |
| EXPECT_EQ(nullptr, prop.GetObject()); | |
| EXPECT_EQ(nullptr, prop.GetArray()); | |
| } | |
| TEST(CommandSchema, StringPropType_ToJson) { | |
| StringPropType prop; | |
| EXPECT_JSON_EQ("'string'", *prop.ToJson(false, false)); | |
| EXPECT_JSON_EQ("{'type':'string'}", *prop.ToJson(true, false)); | |
| StringPropType param2; | |
| param2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_JSON_EQ("{}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'minLength':3}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'minLength':3}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'maxLength':7}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'maxLength':7}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'minLength':0,'maxLength':5}").get(), | |
| &prop, nullptr); | |
| EXPECT_JSON_EQ("{'maxLength':5,'minLength':0}", *param2.ToJson(false, false)); | |
| param2.FromJson(CreateDictionaryValue("{'default':'abcd'}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'default':'abcd'}", *param2.ToJson(false, false)); | |
| } | |
| TEST(CommandSchema, StringPropType_FromJson) { | |
| StringPropType prop; | |
| prop.AddLengthConstraint(2, 8); | |
| StringPropType param2; | |
| param2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_FALSE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_EQ(2, prop.GetMinLength()); | |
| EXPECT_EQ(8, prop.GetMaxLength()); | |
| prop.AddLengthConstraint(3, 5); | |
| param2.FromJson(CreateDictionaryValue("{'minLength':4}").get(), &prop, | |
| nullptr); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_EQ(4, param2.GetMinLength()); | |
| EXPECT_EQ(5, param2.GetMaxLength()); | |
| param2.FromJson(CreateDictionaryValue("{'maxLength':8}").get(), &prop, | |
| nullptr); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_EQ(3, param2.GetMinLength()); | |
| EXPECT_EQ(8, param2.GetMaxLength()); | |
| param2.FromJson(CreateDictionaryValue("{'minLength':1,'maxLength':7}").get(), | |
| &prop, nullptr); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| EXPECT_TRUE(param2.IsBasedOnSchema()); | |
| EXPECT_EQ(1, param2.GetMinLength()); | |
| EXPECT_EQ(7, param2.GetMaxLength()); | |
| ASSERT_TRUE(param2.FromJson(CreateDictionaryValue("{'default':'foo'}").get(), | |
| &prop, nullptr)); | |
| EXPECT_TRUE(param2.HasOverriddenAttributes()); | |
| ASSERT_NE(nullptr, param2.GetDefaultValue()); | |
| EXPECT_EQ("foo", param2.GetDefaultValue()->GetString()->GetValue()); | |
| } | |
| TEST(CommandSchema, StringPropType_Validate) { | |
| StringPropType prop; | |
| prop.AddLengthConstraint(1, 3); | |
| ErrorPtr error; | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("''"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| prop.AddLengthConstraint(2, 3); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("''"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("'a'"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("'ab'"), &error)); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("'abc'"), &error)); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("'abcd'"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| prop.FromJson(CreateDictionaryValue("{'enum':['abc','def','xyz!!']}").get(), | |
| nullptr, &error); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("'abc'"), &error)); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("'def'"), &error)); | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("'xyz!!'"), &error)); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("'xyz'"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| } | |
| TEST(CommandSchema, StringPropType_CreateValue) { | |
| StringPropType prop; | |
| ErrorPtr error; | |
| auto val = prop.CreateValue(base::StringValue{"blah"}, &error); | |
| ASSERT_NE(nullptr, val.get()); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_EQ("blah", val->GetValue()); | |
| val = prop.CreateValue(base::FundamentalValue{4}, &error); | |
| EXPECT_EQ(nullptr, val.get()); | |
| ASSERT_NE(nullptr, error.get()); | |
| EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode()); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| TEST(CommandSchema, ObjectPropType_Empty) { | |
| ObjectPropType prop; | |
| EXPECT_TRUE(prop.HasOverriddenAttributes()); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| EXPECT_EQ(nullptr, prop.GetDefaultValue()); | |
| EXPECT_FALSE(prop.IsRequired()); | |
| } | |
| TEST(CommandSchema, ObjectPropType_Types) { | |
| ObjectPropType prop; | |
| EXPECT_EQ(nullptr, prop.GetInt()); | |
| EXPECT_EQ(nullptr, prop.GetBoolean()); | |
| EXPECT_EQ(nullptr, prop.GetDouble()); | |
| EXPECT_EQ(nullptr, prop.GetString()); | |
| EXPECT_EQ(&prop, prop.GetObject()); | |
| EXPECT_EQ(nullptr, prop.GetArray()); | |
| } | |
| TEST(CommandSchema, ObjectPropType_ToJson) { | |
| ObjectPropType prop; | |
| EXPECT_JSON_EQ("{'additionalProperties':false,'properties':{}}", | |
| *prop.ToJson(false, false)); | |
| EXPECT_JSON_EQ( | |
| "{'additionalProperties':false,'properties':{},'type':'object'}", | |
| *prop.ToJson(true, false)); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| ObjectPropType prop2; | |
| prop2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_JSON_EQ("{}", *prop2.ToJson(false, false)); | |
| EXPECT_TRUE(prop2.IsBasedOnSchema()); | |
| auto schema = ObjectSchema::Create(); | |
| schema->AddProp("expires", PropType::Create(ValueType::Int)); | |
| auto pw = PropType::Create(ValueType::String); | |
| pw->GetString()->AddLengthConstraint(6, 100); | |
| schema->AddProp("password", std::move(pw)); | |
| prop2.SetObjectSchema(std::move(schema)); | |
| auto expected = R"({ | |
| 'additionalProperties': false, | |
| 'properties': { | |
| 'expires': 'integer', | |
| 'password': { | |
| 'maxLength': 100, | |
| 'minLength': 6 | |
| } | |
| } | |
| })"; | |
| EXPECT_JSON_EQ(expected, *prop2.ToJson(false, false)); | |
| expected = R"({ | |
| 'additionalProperties': false, | |
| 'properties': { | |
| 'expires': { | |
| 'type': 'integer' | |
| }, | |
| 'password': { | |
| 'maxLength': 100, | |
| 'minLength': 6, | |
| 'type': 'string' | |
| } | |
| }, | |
| 'type': 'object' | |
| })"; | |
| EXPECT_JSON_EQ(expected, *prop2.ToJson(true, false)); | |
| ObjectPropType prop3; | |
| ASSERT_TRUE( | |
| prop3.FromJson(CreateDictionaryValue( | |
| "{'default':{'expires':3,'password':'abracadabra'}}") | |
| .get(), | |
| &prop2, nullptr)); | |
| expected = R"({ | |
| 'default': { | |
| 'expires': 3, | |
| 'password': 'abracadabra' | |
| } | |
| })"; | |
| EXPECT_JSON_EQ(expected, *prop3.ToJson(false, false)); | |
| expected = R"({ | |
| 'additionalProperties': false, | |
| 'default': { | |
| 'expires': 3, | |
| 'password': 'abracadabra' | |
| }, | |
| 'properties': { | |
| 'expires': { | |
| 'type': 'integer' | |
| }, | |
| 'password': { | |
| 'maxLength': 100, | |
| 'minLength': 6, | |
| 'type': 'string' | |
| } | |
| }, | |
| 'type': 'object' | |
| })"; | |
| EXPECT_JSON_EQ(expected, *prop3.ToJson(true, false)); | |
| ObjectPropType prop4; | |
| ASSERT_TRUE(prop4.FromJson( | |
| CreateDictionaryValue("{'additionalProperties':true," | |
| "'default':{'expires':3,'password':'abracadabra'}}") | |
| .get(), | |
| &prop2, nullptr)); | |
| expected = R"({ | |
| 'additionalProperties': true, | |
| 'default': { | |
| 'expires': 3, | |
| 'password': 'abracadabra' | |
| }, | |
| 'properties': { | |
| 'expires': 'integer', | |
| 'password': { | |
| 'maxLength': 100, | |
| 'minLength': 6 | |
| } | |
| } | |
| })"; | |
| EXPECT_JSON_EQ(expected, *prop4.ToJson(false, false)); | |
| expected = R"({ | |
| 'additionalProperties': true, | |
| 'default': { | |
| 'expires': 3, | |
| 'password': 'abracadabra' | |
| }, | |
| 'properties': { | |
| 'expires': { | |
| 'type': 'integer' | |
| }, | |
| 'password': { | |
| 'maxLength': 100, | |
| 'minLength': 6, | |
| 'type': 'string' | |
| } | |
| }, | |
| 'type': 'object' | |
| })"; | |
| EXPECT_JSON_EQ(expected, *prop4.ToJson(true, false)); | |
| } | |
| TEST(CommandSchema, ObjectPropType_FromJson) { | |
| ObjectPropType base_prop; | |
| EXPECT_TRUE(base_prop.FromJson( | |
| CreateDictionaryValue("{'properties':{'name':'string','age':'integer'}}") | |
| .get(), | |
| nullptr, nullptr)); | |
| auto schema = base_prop.GetObject()->GetObjectSchemaPtr(); | |
| const PropType* prop = schema->GetProp("name"); | |
| EXPECT_EQ(ValueType::String, prop->GetType()); | |
| prop = schema->GetProp("age"); | |
| EXPECT_EQ(ValueType::Int, prop->GetType()); | |
| ObjectPropType prop2; | |
| ASSERT_TRUE(prop2.FromJson( | |
| CreateDictionaryValue("{'properties':{'name':'string','age':'integer'}," | |
| "'default':{'name':'Bob','age':33}}") | |
| .get(), | |
| nullptr, nullptr)); | |
| ASSERT_NE(nullptr, prop2.GetDefaultValue()); | |
| const ObjectValue* defval = prop2.GetDefaultValue()->GetObject(); | |
| ASSERT_NE(nullptr, defval); | |
| ValueMap objval = defval->GetValue(); | |
| EXPECT_EQ("Bob", objval["name"]->GetString()->GetValue()); | |
| EXPECT_EQ(33, objval["age"]->GetInt()->GetValue()); | |
| } | |
| TEST(CommandSchema, ObjectPropType_Validate) { | |
| ObjectPropType prop; | |
| prop.FromJson( | |
| CreateDictionaryValue("{'properties':{'expires':'integer'," | |
| "'password':{'maxLength':100,'minLength':6}}," | |
| "'required':['expires','password']}") | |
| .get(), | |
| nullptr, nullptr); | |
| ErrorPtr error; | |
| EXPECT_TRUE(ValidateValue( | |
| prop, *CreateValue("{'expires':10,'password':'abcdef'}"), &error)); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("{'expires':10}"), &error)); | |
| EXPECT_EQ("parameter_missing", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE( | |
| ValidateValue(prop, *CreateValue("{'password':'abcdef'}"), &error)); | |
| EXPECT_EQ("parameter_missing", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue( | |
| prop, *CreateValue("{'expires':10,'password':'abcde'}"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("2"), &error)); | |
| EXPECT_EQ("type_mismatch", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue( | |
| prop, *CreateValue("{'expires':10,'password':'abcdef','retry':true}"), | |
| &error)); | |
| EXPECT_EQ("unexpected_parameter", error->GetCode()); | |
| error.reset(); | |
| } | |
| TEST(CommandSchema, ObjectPropType_Validate_Enum) { | |
| ObjectPropType prop; | |
| EXPECT_TRUE(prop.FromJson( | |
| CreateDictionaryValue( | |
| "{'properties':{'width':'integer','height':'integer'}," | |
| "'enum':[{'width':10,'height':20},{'width':100,'height':200}]}") | |
| .get(), | |
| nullptr, nullptr)); | |
| ErrorPtr error; | |
| EXPECT_TRUE( | |
| ValidateValue(prop, *CreateValue("{'height':20,'width':10}"), &error)); | |
| error.reset(); | |
| EXPECT_TRUE( | |
| ValidateValue(prop, *CreateValue("{'height':200,'width':100}"), &error)); | |
| error.reset(); | |
| EXPECT_FALSE( | |
| ValidateValue(prop, *CreateValue("{'height':12,'width':10}"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| } | |
| TEST(CommandSchema, ObjectPropType_CreateValue) { | |
| ObjectPropType prop; | |
| IntPropType int_type; | |
| ASSERT_TRUE(prop.FromJson( | |
| CreateDictionaryValue( | |
| "{'properties':{'width':'integer','height':'integer'}," | |
| "'enum':[{'width':10,'height':20},{'width':100,'height':200}]}") | |
| .get(), | |
| nullptr, nullptr)); | |
| ValueMap obj{ | |
| {"width", int_type.CreateValue(base::FundamentalValue{10}, nullptr)}, | |
| {"height", int_type.CreateValue(base::FundamentalValue{20}, nullptr)}, | |
| }; | |
| ErrorPtr error; | |
| auto val = prop.CreateValue( | |
| *CreateDictionaryValue("{'width': 10, 'height': 20}"), &error); | |
| ASSERT_NE(nullptr, val.get()); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_EQ(obj, val->GetValue()); | |
| val = prop.CreateValue(base::StringValue{"blah"}, &error); | |
| EXPECT_EQ(nullptr, val.get()); | |
| ASSERT_NE(nullptr, error.get()); | |
| EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode()); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| TEST(CommandSchema, ArrayPropType_Empty) { | |
| ArrayPropType prop; | |
| EXPECT_FALSE(prop.HasOverriddenAttributes()); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| EXPECT_EQ(nullptr, prop.GetDefaultValue()); | |
| EXPECT_EQ(nullptr, prop.GetItemTypePtr()); | |
| prop.SetItemType(PropType::Create(ValueType::Int)); | |
| EXPECT_TRUE(prop.HasOverriddenAttributes()); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| EXPECT_NE(nullptr, prop.GetItemTypePtr()); | |
| EXPECT_FALSE(prop.IsRequired()); | |
| } | |
| TEST(CommandSchema, ArrayPropType_Types) { | |
| ArrayPropType prop; | |
| EXPECT_EQ(nullptr, prop.GetInt()); | |
| EXPECT_EQ(nullptr, prop.GetBoolean()); | |
| EXPECT_EQ(nullptr, prop.GetDouble()); | |
| EXPECT_EQ(nullptr, prop.GetString()); | |
| EXPECT_EQ(nullptr, prop.GetObject()); | |
| EXPECT_EQ(&prop, prop.GetArray()); | |
| } | |
| TEST(CommandSchema, ArrayPropType_ToJson) { | |
| ArrayPropType prop; | |
| prop.SetItemType(PropType::Create(ValueType::Int)); | |
| EXPECT_JSON_EQ("{'items':'integer'}", *prop.ToJson(false, false)); | |
| EXPECT_JSON_EQ("{'items':{'type':'integer'},'type':'array'}", | |
| *prop.ToJson(true, false)); | |
| EXPECT_FALSE(prop.IsBasedOnSchema()); | |
| ArrayPropType prop2; | |
| prop2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr); | |
| EXPECT_JSON_EQ("{}", *prop2.ToJson(false, false)); | |
| EXPECT_TRUE(prop2.IsBasedOnSchema()); | |
| prop2.FromJson(CreateDictionaryValue("{'default':[1,2,3]}").get(), &prop, | |
| nullptr); | |
| EXPECT_JSON_EQ("{'default':[1,2,3]}", *prop2.ToJson(false, false)); | |
| EXPECT_JSON_EQ( | |
| "{'default':[1,2,3],'items':{'type':'integer'},'type':'array'}", | |
| *prop2.ToJson(true, false)); | |
| } | |
| TEST(CommandSchema, ArrayPropType_FromJson) { | |
| ArrayPropType prop; | |
| EXPECT_TRUE(prop.FromJson(CreateDictionaryValue("{'items':'integer'}").get(), | |
| nullptr, nullptr)); | |
| EXPECT_EQ(ValueType::Int, prop.GetItemTypePtr()->GetType()); | |
| ArrayPropType prop2; | |
| ASSERT_TRUE( | |
| prop2.FromJson(CreateDictionaryValue( | |
| "{'items':'string','default':['foo', 'bar', 'baz']}") | |
| .get(), | |
| nullptr, nullptr)); | |
| ASSERT_NE(nullptr, prop2.GetDefaultValue()); | |
| const ArrayValue* defval = prop2.GetDefaultValue()->GetArray(); | |
| ASSERT_NE(nullptr, defval); | |
| EXPECT_EQ((std::vector<std::string>{"foo", "bar", "baz"}), | |
| GetArrayValues<std::string>(defval->GetValue())); | |
| } | |
| TEST(CommandSchema, ArrayPropType_Validate) { | |
| ArrayPropType prop; | |
| prop.FromJson( | |
| CreateDictionaryValue("{'items':{'minimum':2.3, 'maximum':10.5}}").get(), | |
| nullptr, nullptr); | |
| ErrorPtr error; | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("[3,4,10.5]"), &error)); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("[2]"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("[4, 5, 20]"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| } | |
| TEST(CommandSchema, ArrayPropType_Validate_Enum) { | |
| ArrayPropType prop; | |
| prop.FromJson( | |
| CreateDictionaryValue("{'items':'integer', 'enum':[[1], [2,3], [4,5,6]]}") | |
| .get(), | |
| nullptr, nullptr); | |
| ErrorPtr error; | |
| EXPECT_TRUE(ValidateValue(prop, *CreateValue("[2,3]"), &error)); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("[2]"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| EXPECT_FALSE(ValidateValue(prop, *CreateValue("[2,3,4]"), &error)); | |
| EXPECT_EQ("out_of_range", error->GetCode()); | |
| error.reset(); | |
| } | |
| TEST(CommandSchema, ArrayPropType_CreateValue) { | |
| ArrayPropType prop; | |
| ASSERT_TRUE(prop.FromJson( | |
| CreateDictionaryValue( | |
| "{'items':{'properties':{'width':'integer','height':'integer'}}}") | |
| .get(), | |
| nullptr, nullptr)); | |
| ErrorPtr error; | |
| ValueVector arr; | |
| auto val = prop.CreateValue(base::ListValue{}, &error); | |
| ASSERT_NE(nullptr, val.get()); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_EQ(arr, val->GetValue()); | |
| EXPECT_JSON_EQ("[]", *val->ToJson()); | |
| val = prop.CreateValue( | |
| *CreateValue("[{'height':20,'width':10},{'width':17, 'height':18}]"), | |
| &error); | |
| ASSERT_NE(nullptr, val.get()); | |
| EXPECT_EQ(nullptr, error.get()); | |
| EXPECT_JSON_EQ("[{'height':20,'width':10},{'height':18,'width':17}]", | |
| *val->ToJson()); | |
| val = prop.CreateValue(base::StringValue{"blah"}, &error); | |
| EXPECT_EQ(nullptr, val.get()); | |
| ASSERT_NE(nullptr, error.get()); | |
| EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode()); | |
| } | |
| TEST(CommandSchema, ArrayPropType_NestedArrays_NotSupported) { | |
| ArrayPropType prop; | |
| ErrorPtr error; | |
| EXPECT_FALSE(prop.FromJson( | |
| CreateDictionaryValue("{'items':{'items':'integer'}}").get(), nullptr, | |
| &error)); | |
| EXPECT_EQ(errors::commands::kInvalidObjectSchema, error->GetCode()); | |
| error.reset(); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| TEST(CommandSchema, ObjectSchema_FromJson_Shorthand_TypeName) { | |
| ObjectSchema schema; | |
| const char* schema_str = | |
| "{" | |
| "'param1':'integer'," | |
| "'param2':'number'," | |
| "'param3':'string'" | |
| "}"; | |
| EXPECT_TRUE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| nullptr)); | |
| EXPECT_EQ(ValueType::Int, schema.GetProp("param1")->GetType()); | |
| EXPECT_EQ(ValueType::Double, schema.GetProp("param2")->GetType()); | |
| EXPECT_EQ(ValueType::String, schema.GetProp("param3")->GetType()); | |
| EXPECT_EQ("integer", schema.GetProp("param1")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param2")->GetTypeAsString()); | |
| EXPECT_EQ("string", schema.GetProp("param3")->GetTypeAsString()); | |
| EXPECT_EQ(nullptr, schema.GetProp("param4")); | |
| int min_int = (std::numeric_limits<int>::min)(); | |
| int max_int = (std::numeric_limits<int>::max)(); | |
| double min_dbl = (std::numeric_limits<double>::lowest)(); | |
| double max_dbl = (std::numeric_limits<double>::max)(); | |
| EXPECT_EQ(min_int, schema.GetProp("param1")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(max_int, schema.GetProp("param1")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ(min_dbl, schema.GetProp("param2")->GetDouble()->GetMinValue()); | |
| EXPECT_EQ(max_dbl, schema.GetProp("param2")->GetDouble()->GetMaxValue()); | |
| EXPECT_EQ(0, schema.GetProp("param3")->GetString()->GetMinLength()); | |
| EXPECT_EQ(max_int, schema.GetProp("param3")->GetString()->GetMaxLength()); | |
| } | |
| TEST(CommandSchema, ObjectSchema_FromJson_Full_TypeName) { | |
| ObjectSchema schema; | |
| const char* schema_str = | |
| "{" | |
| "'param1':{'type':'integer'}," | |
| "'param2':{'type':'number'}," | |
| "'param3':{'type':'string'}," | |
| "'param4':{'type':'array', 'items':'integer'}," | |
| "'param5':{'type':'object', 'properties':{'p1':'integer'}}" | |
| "}"; | |
| EXPECT_TRUE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| nullptr)); | |
| EXPECT_EQ(ValueType::Int, schema.GetProp("param1")->GetType()); | |
| EXPECT_EQ(ValueType::Double, schema.GetProp("param2")->GetType()); | |
| EXPECT_EQ(ValueType::String, schema.GetProp("param3")->GetType()); | |
| EXPECT_EQ(ValueType::Array, schema.GetProp("param4")->GetType()); | |
| EXPECT_EQ(ValueType::Object, schema.GetProp("param5")->GetType()); | |
| EXPECT_EQ("integer", schema.GetProp("param1")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param2")->GetTypeAsString()); | |
| EXPECT_EQ("string", schema.GetProp("param3")->GetTypeAsString()); | |
| EXPECT_EQ("array", schema.GetProp("param4")->GetTypeAsString()); | |
| EXPECT_EQ("object", schema.GetProp("param5")->GetTypeAsString()); | |
| EXPECT_EQ(nullptr, schema.GetProp("param77")); | |
| int min_int = (std::numeric_limits<int>::min)(); | |
| int max_int = (std::numeric_limits<int>::max)(); | |
| double min_dbl = (std::numeric_limits<double>::lowest)(); | |
| double max_dbl = (std::numeric_limits<double>::max)(); | |
| EXPECT_EQ(min_int, schema.GetProp("param1")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(max_int, schema.GetProp("param1")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ(min_dbl, schema.GetProp("param2")->GetDouble()->GetMinValue()); | |
| EXPECT_EQ(max_dbl, schema.GetProp("param2")->GetDouble()->GetMaxValue()); | |
| EXPECT_EQ(0, schema.GetProp("param3")->GetString()->GetMinLength()); | |
| EXPECT_EQ(max_int, schema.GetProp("param3")->GetString()->GetMaxLength()); | |
| } | |
| TEST(CommandSchema, ObjectSchema_FromJson_Shorthand_TypeDeduction_Scalar) { | |
| ObjectSchema schema; | |
| const char* schema_str = | |
| "{" | |
| "'param1' :{'minimum':2}," | |
| "'param2' :{'maximum':10}," | |
| "'param3' :{'maximum':8, 'minimum':2}," | |
| "'param4' :{'minimum':2.1}," | |
| "'param5' :{'maximum':10.1}," | |
| "'param6' :{'maximum':8.1, 'minimum':3.1}," | |
| "'param7' :{'maximum':8, 'minimum':3.1}," | |
| "'param8' :{'maximum':8.1, 'minimum':3}," | |
| "'param9' :{'minLength':2}," | |
| "'param10':{'maxLength':10}," | |
| "'param11':{'maxLength':8, 'minLength':3}," | |
| "'param12':{'default':12}," | |
| "'param13':{'default':13.5}," | |
| "'param14':{'default':true}," | |
| "'param15':{'default':false}," | |
| "'param16':{'default':'foobar'}," | |
| "'param17':{'default':[1,2,3]}," | |
| "'param18':{'items':'number', 'default':[]}" | |
| "}"; | |
| EXPECT_TRUE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| nullptr)); | |
| EXPECT_EQ("integer", schema.GetProp("param1")->GetTypeAsString()); | |
| EXPECT_EQ("integer", schema.GetProp("param2")->GetTypeAsString()); | |
| EXPECT_EQ("integer", schema.GetProp("param3")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param4")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param5")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param6")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param7")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param8")->GetTypeAsString()); | |
| EXPECT_EQ("string", schema.GetProp("param9")->GetTypeAsString()); | |
| EXPECT_EQ("string", schema.GetProp("param10")->GetTypeAsString()); | |
| EXPECT_EQ("string", schema.GetProp("param11")->GetTypeAsString()); | |
| EXPECT_EQ("integer", schema.GetProp("param12")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param13")->GetTypeAsString()); | |
| EXPECT_EQ("boolean", schema.GetProp("param14")->GetTypeAsString()); | |
| EXPECT_EQ("boolean", schema.GetProp("param15")->GetTypeAsString()); | |
| EXPECT_EQ("string", schema.GetProp("param16")->GetTypeAsString()); | |
| EXPECT_EQ("array", schema.GetProp("param17")->GetTypeAsString()); | |
| auto prop17 = schema.GetProp("param17"); | |
| EXPECT_EQ("integer", prop17->GetArray()->GetItemTypePtr()->GetTypeAsString()); | |
| EXPECT_EQ("array", schema.GetProp("param18")->GetTypeAsString()); | |
| auto prop18 = schema.GetProp("param18"); | |
| EXPECT_EQ("number", prop18->GetArray()->GetItemTypePtr()->GetTypeAsString()); | |
| int min_int = (std::numeric_limits<int>::min)(); | |
| int max_int = (std::numeric_limits<int>::max)(); | |
| double min_dbl = (std::numeric_limits<double>::lowest)(); | |
| double max_dbl = (std::numeric_limits<double>::max)(); | |
| EXPECT_EQ(2, schema.GetProp("param1")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(max_int, schema.GetProp("param1")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ(min_int, schema.GetProp("param2")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(10, schema.GetProp("param2")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ(2, schema.GetProp("param3")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(8, schema.GetProp("param3")->GetInt()->GetMaxValue()); | |
| EXPECT_DOUBLE_EQ(2.1, schema.GetProp("param4")->GetDouble()->GetMinValue()); | |
| EXPECT_DOUBLE_EQ(max_dbl, | |
| schema.GetProp("param4")->GetDouble()->GetMaxValue()); | |
| EXPECT_DOUBLE_EQ(min_dbl, | |
| schema.GetProp("param5")->GetDouble()->GetMinValue()); | |
| EXPECT_DOUBLE_EQ(10.1, schema.GetProp("param5")->GetDouble()->GetMaxValue()); | |
| EXPECT_DOUBLE_EQ(3.1, schema.GetProp("param6")->GetDouble()->GetMinValue()); | |
| EXPECT_DOUBLE_EQ(8.1, schema.GetProp("param6")->GetDouble()->GetMaxValue()); | |
| EXPECT_DOUBLE_EQ(3.1, schema.GetProp("param7")->GetDouble()->GetMinValue()); | |
| EXPECT_DOUBLE_EQ(8.0, schema.GetProp("param7")->GetDouble()->GetMaxValue()); | |
| EXPECT_DOUBLE_EQ(3.0, schema.GetProp("param8")->GetDouble()->GetMinValue()); | |
| EXPECT_DOUBLE_EQ(8.1, schema.GetProp("param8")->GetDouble()->GetMaxValue()); | |
| EXPECT_EQ(2, schema.GetProp("param9")->GetString()->GetMinLength()); | |
| EXPECT_EQ(max_int, schema.GetProp("param9")->GetString()->GetMaxLength()); | |
| EXPECT_EQ(0, schema.GetProp("param10")->GetString()->GetMinLength()); | |
| EXPECT_EQ(10, schema.GetProp("param10")->GetString()->GetMaxLength()); | |
| EXPECT_EQ(3, schema.GetProp("param11")->GetString()->GetMinLength()); | |
| EXPECT_EQ(8, schema.GetProp("param11")->GetString()->GetMaxLength()); | |
| const PropValue* val = schema.GetProp("param12")->GetDefaultValue(); | |
| EXPECT_EQ(12, val->GetInt()->GetValue()); | |
| val = schema.GetProp("param13")->GetDefaultValue(); | |
| EXPECT_DOUBLE_EQ(13.5, val->GetDouble()->GetValue()); | |
| val = schema.GetProp("param14")->GetDefaultValue(); | |
| EXPECT_TRUE(val->GetBoolean()->GetValue()); | |
| val = schema.GetProp("param15")->GetDefaultValue(); | |
| EXPECT_FALSE(val->GetBoolean()->GetValue()); | |
| val = schema.GetProp("param16")->GetDefaultValue(); | |
| EXPECT_EQ("foobar", val->GetString()->GetValue()); | |
| val = schema.GetProp("param17")->GetDefaultValue(); | |
| EXPECT_EQ((std::vector<int>{1, 2, 3}), | |
| GetArrayValues<int>(val->GetArray()->GetValue())); | |
| val = schema.GetProp("param18")->GetDefaultValue(); | |
| EXPECT_TRUE(val->GetArray()->GetValue().empty()); | |
| } | |
| TEST(CommandSchema, ObjectSchema_FromJson_Shorthand_TypeDeduction_Array) { | |
| ObjectSchema schema; | |
| const char* schema_str = | |
| "{" | |
| "'param1' :[0,1,2,3]," | |
| "'param2' :[0.0,1.1,2.2]," | |
| "'param3' :['id1', 'id2']," | |
| "'param4' :{'enum':[1,2,3]}," | |
| "'param5' :{'enum':[-1.1,2.2,3]}," | |
| "'param6' :{'enum':['id0', 'id1']}," | |
| "'param7' :{'type':'integer', 'enum':[1,2,3]}," | |
| "'param8' :{'type':'number', 'enum':[1,2,3]}," | |
| "'param9' :{'type':'number', 'enum':[]}," | |
| "'param10':{'type':'integer', 'enum':[]}," | |
| "'param11':[[0,1],[2,3]]," | |
| "'param12':[['foo','bar']]," | |
| "'param13':{'enum':[['id0', 'id1']]}" | |
| "}"; | |
| EXPECT_TRUE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| nullptr)); | |
| EXPECT_EQ("integer", schema.GetProp("param1")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param2")->GetTypeAsString()); | |
| EXPECT_EQ("string", schema.GetProp("param3")->GetTypeAsString()); | |
| EXPECT_EQ("integer", schema.GetProp("param4")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param5")->GetTypeAsString()); | |
| EXPECT_EQ("string", schema.GetProp("param6")->GetTypeAsString()); | |
| EXPECT_EQ("integer", schema.GetProp("param7")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param8")->GetTypeAsString()); | |
| EXPECT_EQ("number", schema.GetProp("param9")->GetTypeAsString()); | |
| EXPECT_EQ("integer", schema.GetProp("param10")->GetTypeAsString()); | |
| auto prop_type11 = schema.GetProp("param11"); | |
| EXPECT_EQ("array", prop_type11->GetTypeAsString()); | |
| EXPECT_EQ("integer", | |
| prop_type11->GetArray()->GetItemTypePtr()->GetTypeAsString()); | |
| auto prop_type12 = schema.GetProp("param12"); | |
| EXPECT_EQ("array", prop_type12->GetTypeAsString()); | |
| EXPECT_EQ("string", | |
| prop_type12->GetArray()->GetItemTypePtr()->GetTypeAsString()); | |
| auto prop_type13 = schema.GetProp("param13"); | |
| EXPECT_EQ("array", prop_type12->GetTypeAsString()); | |
| EXPECT_EQ("string", | |
| prop_type13->GetArray()->GetItemTypePtr()->GetTypeAsString()); | |
| EXPECT_EQ((std::vector<int>{0, 1, 2, 3}), | |
| GetOneOfValues<int>(schema.GetProp("param1"))); | |
| EXPECT_EQ((std::vector<double>{0.0, 1.1, 2.2}), | |
| GetOneOfValues<double>(schema.GetProp("param2"))); | |
| EXPECT_EQ((std::vector<std::string>{"id1", "id2"}), | |
| GetOneOfValues<std::string>(schema.GetProp("param3"))); | |
| EXPECT_EQ((std::vector<int>{1, 2, 3}), | |
| GetOneOfValues<int>(schema.GetProp("param4"))); | |
| EXPECT_EQ((std::vector<double>{-1.1, 2.2, 3.0}), | |
| GetOneOfValues<double>(schema.GetProp("param5"))); | |
| EXPECT_EQ((std::vector<std::string>{"id0", "id1"}), | |
| GetOneOfValues<std::string>(schema.GetProp("param6"))); | |
| EXPECT_EQ((std::vector<int>{1, 2, 3}), | |
| GetOneOfValues<int>(schema.GetProp("param7"))); | |
| EXPECT_EQ((std::vector<double>{1.0, 2.0, 3.0}), | |
| GetOneOfValues<double>(schema.GetProp("param8"))); | |
| EXPECT_TRUE(GetOneOfValues<double>(schema.GetProp("param9")).empty()); | |
| EXPECT_TRUE(GetOneOfValues<int>(schema.GetProp("param10")).empty()); | |
| } | |
| TEST(CommandSchema, ObjectSchema_FromJson_Inheritance) { | |
| const char* base_schema_str = | |
| "{" | |
| "'param0' :{'minimum':1, 'maximum':5}," | |
| "'param1' :{'minimum':1, 'maximum':5}," | |
| "'param2' :{'minimum':1, 'maximum':5}," | |
| "'param3' :{'minimum':1, 'maximum':5}," | |
| "'param4' :{'minimum':1, 'maximum':5}," | |
| "'param5' :{'minimum':1.1, 'maximum':5.5}," | |
| "'param6' :{'minimum':1.1, 'maximum':5.5}," | |
| "'param7' :{'minimum':1.1, 'maximum':5.5}," | |
| "'param8' :{'minimum':1.1, 'maximum':5.5}," | |
| "'param9' :{'minLength':1, 'maxLength':5}," | |
| "'param10':{'minLength':1, 'maxLength':5}," | |
| "'param11':{'minLength':1, 'maxLength':5}," | |
| "'param12':{'minLength':1, 'maxLength':5}," | |
| "'param13':[1,2,3]," | |
| "'param14':[1,2,3]," | |
| "'param15':[1.1,2.2,3.3]," | |
| "'param16':[1.1,2.2,3.3]," | |
| "'param17':['id1', 'id2']," | |
| "'param18':['id1', 'id2']," | |
| "'param19':{'minimum':1, 'maximum':5}," | |
| "'param20':{'default':49}," | |
| "'param21':{'default':49}," | |
| "'param22':'integer'" | |
| "}"; | |
| ObjectSchema base_schema; | |
| EXPECT_TRUE(base_schema.FromJson(CreateDictionaryValue(base_schema_str).get(), | |
| nullptr, nullptr)); | |
| const char* schema_str = | |
| "{" | |
| "'param1' :{}," | |
| "'param2' :{'minimum':2}," | |
| "'param3' :{'maximum':9}," | |
| "'param4' :{'minimum':2, 'maximum':9}," | |
| "'param5' :{}," | |
| "'param6' :{'minimum':2.2}," | |
| "'param7' :{'maximum':9.9}," | |
| "'param8' :{'minimum':2.2, 'maximum':9.9}," | |
| "'param9' :{}," | |
| "'param10':{'minLength':3}," | |
| "'param11':{'maxLength':8}," | |
| "'param12':{'minLength':3, 'maxLength':8}," | |
| "'param13':{}," | |
| "'param14':[1,2,3,4]," | |
| "'param15':{}," | |
| "'param16':[1.1,2.2,3.3,4.4]," | |
| "'param17':{}," | |
| "'param18':['id1', 'id3']," | |
| "'param19':{}," | |
| "'param20':{}," | |
| "'param21':{'default':8}," | |
| "'param22':{'default':123}" | |
| "}"; | |
| ObjectSchema schema; | |
| EXPECT_TRUE(schema.FromJson(CreateDictionaryValue(schema_str).get(), | |
| &base_schema, nullptr)); | |
| EXPECT_EQ(nullptr, schema.GetProp("param0")); | |
| EXPECT_NE(nullptr, schema.GetProp("param1")); | |
| EXPECT_EQ("integer", schema.GetProp("param1")->GetTypeAsString()); | |
| EXPECT_EQ(1, schema.GetProp("param1")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(5, schema.GetProp("param1")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ("integer", schema.GetProp("param2")->GetTypeAsString()); | |
| EXPECT_EQ(2, schema.GetProp("param2")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(5, schema.GetProp("param2")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ("integer", schema.GetProp("param3")->GetTypeAsString()); | |
| EXPECT_EQ(1, schema.GetProp("param3")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(9, schema.GetProp("param3")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ("integer", schema.GetProp("param4")->GetTypeAsString()); | |
| EXPECT_EQ(2, schema.GetProp("param4")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(9, schema.GetProp("param4")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ("number", schema.GetProp("param5")->GetTypeAsString()); | |
| EXPECT_EQ(1.1, schema.GetProp("param5")->GetDouble()->GetMinValue()); | |
| EXPECT_EQ(5.5, schema.GetProp("param5")->GetDouble()->GetMaxValue()); | |
| EXPECT_EQ("number", schema.GetProp("param6")->GetTypeAsString()); | |
| EXPECT_EQ(2.2, schema.GetProp("param6")->GetDouble()->GetMinValue()); | |
| EXPECT_EQ(5.5, schema.GetProp("param6")->GetDouble()->GetMaxValue()); | |
| EXPECT_EQ("number", schema.GetProp("param7")->GetTypeAsString()); | |
| EXPECT_EQ(1.1, schema.GetProp("param7")->GetDouble()->GetMinValue()); | |
| EXPECT_EQ(9.9, schema.GetProp("param7")->GetDouble()->GetMaxValue()); | |
| EXPECT_EQ("number", schema.GetProp("param8")->GetTypeAsString()); | |
| EXPECT_EQ(2.2, schema.GetProp("param8")->GetDouble()->GetMinValue()); | |
| EXPECT_EQ(9.9, schema.GetProp("param8")->GetDouble()->GetMaxValue()); | |
| EXPECT_EQ("string", schema.GetProp("param9")->GetTypeAsString()); | |
| EXPECT_EQ(1, schema.GetProp("param9")->GetString()->GetMinLength()); | |
| EXPECT_EQ(5, schema.GetProp("param9")->GetString()->GetMaxLength()); | |
| EXPECT_EQ("string", schema.GetProp("param10")->GetTypeAsString()); | |
| EXPECT_EQ(3, schema.GetProp("param10")->GetString()->GetMinLength()); | |
| EXPECT_EQ(5, schema.GetProp("param10")->GetString()->GetMaxLength()); | |
| EXPECT_EQ("string", schema.GetProp("param11")->GetTypeAsString()); | |
| EXPECT_EQ(1, schema.GetProp("param11")->GetString()->GetMinLength()); | |
| EXPECT_EQ(8, schema.GetProp("param11")->GetString()->GetMaxLength()); | |
| EXPECT_EQ("string", schema.GetProp("param12")->GetTypeAsString()); | |
| EXPECT_EQ(3, schema.GetProp("param12")->GetString()->GetMinLength()); | |
| EXPECT_EQ(8, schema.GetProp("param12")->GetString()->GetMaxLength()); | |
| EXPECT_EQ("integer", schema.GetProp("param13")->GetTypeAsString()); | |
| EXPECT_EQ((std::vector<int>{1, 2, 3}), | |
| GetOneOfValues<int>(schema.GetProp("param13"))); | |
| EXPECT_EQ("integer", schema.GetProp("param14")->GetTypeAsString()); | |
| EXPECT_EQ((std::vector<int>{1, 2, 3, 4}), | |
| GetOneOfValues<int>(schema.GetProp("param14"))); | |
| EXPECT_EQ("number", schema.GetProp("param15")->GetTypeAsString()); | |
| EXPECT_EQ((std::vector<double>{1.1, 2.2, 3.3}), | |
| GetOneOfValues<double>(schema.GetProp("param15"))); | |
| EXPECT_EQ("number", schema.GetProp("param16")->GetTypeAsString()); | |
| EXPECT_EQ((std::vector<double>{1.1, 2.2, 3.3, 4.4}), | |
| GetOneOfValues<double>(schema.GetProp("param16"))); | |
| EXPECT_EQ("string", schema.GetProp("param17")->GetTypeAsString()); | |
| EXPECT_EQ((std::vector<std::string>{"id1", "id2"}), | |
| GetOneOfValues<std::string>(schema.GetProp("param17"))); | |
| EXPECT_EQ("string", schema.GetProp("param18")->GetTypeAsString()); | |
| EXPECT_EQ((std::vector<std::string>{"id1", "id3"}), | |
| GetOneOfValues<std::string>(schema.GetProp("param18"))); | |
| EXPECT_EQ("integer", schema.GetProp("param19")->GetTypeAsString()); | |
| EXPECT_EQ(1, schema.GetProp("param19")->GetInt()->GetMinValue()); | |
| EXPECT_EQ(5, schema.GetProp("param19")->GetInt()->GetMaxValue()); | |
| EXPECT_EQ(49, | |
| schema.GetProp("param20")->GetDefaultValue()->GetInt()->GetValue()); | |
| EXPECT_EQ(8, | |
| schema.GetProp("param21")->GetDefaultValue()->GetInt()->GetValue()); | |
| EXPECT_EQ(123, | |
| schema.GetProp("param22")->GetDefaultValue()->GetInt()->GetValue()); | |
| } | |
| TEST(CommandSchema, ObjectSchema_UseDefaults) { | |
| ObjectPropType prop; | |
| const char* schema_str = | |
| "{'properties':{" | |
| "'param1':{'default':true}," | |
| "'param2':{'default':2}," | |
| "'param3':{'default':3.3}," | |
| "'param4':{'default':'four'}," | |
| "'param5':{'default':{'x':5,'y':6}," | |
| "'properties':{'x':'integer','y':'integer'}}," | |
| "'param6':{'default':[1,2,3]}" | |
| "}}"; | |
| ASSERT_TRUE( | |
| prop.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, nullptr)); | |
| // Omit all. | |
| auto value = | |
| prop.CreatePropValue(*CreateDictionaryValue("{}").get(), nullptr); | |
| ASSERT_NE(nullptr, value); | |
| ValueMap obj = value->GetObject()->GetValue(); | |
| EXPECT_TRUE(obj["param1"]->GetBoolean()->GetValue()); | |
| EXPECT_EQ(2, obj["param2"]->GetInt()->GetValue()); | |
| EXPECT_DOUBLE_EQ(3.3, obj["param3"]->GetDouble()->GetValue()); | |
| EXPECT_EQ("four", obj["param4"]->GetString()->GetValue()); | |
| ValueMap param5 = obj["param5"]->GetObject()->GetValue(); | |
| EXPECT_EQ(5, param5["x"]->GetInt()->GetValue()); | |
| EXPECT_EQ(6, param5["y"]->GetInt()->GetValue()); | |
| ValueVector param6 = obj["param6"]->GetArray()->GetValue(); | |
| EXPECT_EQ((std::vector<int>{1, 2, 3}), GetArrayValues<int>(param6)); | |
| // Specify some. | |
| const char* val_json = | |
| "{" | |
| "'param1':false," | |
| "'param3':33.3," | |
| "'param5':{'x':-5,'y':-6}" | |
| "}"; | |
| value = prop.CreatePropValue(*CreateDictionaryValue(val_json).get(), nullptr); | |
| ASSERT_NE(nullptr, value); | |
| obj = value->GetObject()->GetValue(); | |
| EXPECT_FALSE(obj["param1"]->GetBoolean()->GetValue()); | |
| EXPECT_EQ(2, obj["param2"]->GetInt()->GetValue()); | |
| EXPECT_DOUBLE_EQ(33.3, obj["param3"]->GetDouble()->GetValue()); | |
| EXPECT_EQ("four", obj["param4"]->GetString()->GetValue()); | |
| param5 = obj["param5"]->GetObject()->GetValue(); | |
| EXPECT_EQ(-5, param5["x"]->GetInt()->GetValue()); | |
| EXPECT_EQ(-6, param5["y"]->GetInt()->GetValue()); | |
| param6 = obj["param6"]->GetArray()->GetValue(); | |
| EXPECT_EQ((std::vector<int>{1, 2, 3}), GetArrayValues<int>(param6)); | |
| // Specify all. | |
| val_json = | |
| "{" | |
| "'param1':false," | |
| "'param2':22," | |
| "'param3':333.3," | |
| "'param4':'FOUR'," | |
| "'param5':{'x':-55,'y':66}," | |
| "'param6':[-1, 0]" | |
| "}"; | |
| value = prop.CreatePropValue(*CreateDictionaryValue(val_json).get(), nullptr); | |
| ASSERT_NE(nullptr, value); | |
| obj = value->GetObject()->GetValue(); | |
| EXPECT_FALSE(obj["param1"]->GetBoolean()->GetValue()); | |
| EXPECT_EQ(22, obj["param2"]->GetInt()->GetValue()); | |
| EXPECT_DOUBLE_EQ(333.3, obj["param3"]->GetDouble()->GetValue()); | |
| EXPECT_EQ("FOUR", obj["param4"]->GetString()->GetValue()); | |
| param5 = obj["param5"]->GetObject()->GetValue(); | |
| EXPECT_EQ(-55, param5["x"]->GetInt()->GetValue()); | |
| EXPECT_EQ(66, param5["y"]->GetInt()->GetValue()); | |
| param6 = obj["param6"]->GetArray()->GetValue(); | |
| EXPECT_EQ((std::vector<int>{-1, 0}), GetArrayValues<int>(param6)); | |
| } | |
| TEST(CommandSchema, ObjectSchema_FromJson_BaseSchema_Failures) { | |
| ObjectSchema schema; | |
| ErrorPtr error; | |
| const char* schema_str = | |
| "{" | |
| "'param1':{}" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("no_type_info", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':{'type':'foo'}" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("unknown_type", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':[]" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("no_type_info", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':{'minimum':'foo'}" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("type_mismatch", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':[1,2.2]" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("type_mismatch", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':{'minimum':1, 'enum':[1,2,3]}" // can't have min/max & enum. | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("unexpected_parameter", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':{'maximum':1, 'blah':2}" // 'blah' is unexpected. | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("unexpected_parameter", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':{'enum':[1,2,3],'default':5}" // 'default' must be 1, 2, or 3. | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("out_of_range", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':[[1,2.3]]" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("type_mismatch", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':[[1,2],[3,4],['blah']]" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("type_mismatch", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':{'default':[]}" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("no_type_info", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':[[[1]],[[2]]]" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("no_type_info", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':{'enum':[[['foo']]]}" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("no_type_info", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| schema_str = | |
| "{" | |
| "'param1':{'default':[[1],[2]]}" | |
| "}"; | |
| EXPECT_FALSE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ("no_type_info", error->GetFirstError()->GetCode()); | |
| error.reset(); | |
| } | |
| TEST(CommandSchema, RequiredProperties_Integral) { | |
| IntPropType prop; | |
| prop.MakeRequired(false); | |
| EXPECT_JSON_EQ("{'type':'integer'}", *prop.ToJson(true, false)); | |
| EXPECT_JSON_EQ("{'isRequired':false,'type':'integer'}", | |
| *prop.ToJson(true, true)); | |
| prop.MakeRequired(true); | |
| EXPECT_JSON_EQ("{'type':'integer'}", *prop.ToJson(true, false)); | |
| EXPECT_JSON_EQ("{'isRequired':true,'type':'integer'}", | |
| *prop.ToJson(true, true)); | |
| IntPropType prop2; | |
| EXPECT_TRUE( | |
| prop2.FromJson(CreateDictionaryValue("{}").get(), &prop, nullptr)); | |
| EXPECT_TRUE(prop2.IsRequired()); | |
| EXPECT_TRUE(prop2.FromJson( | |
| CreateDictionaryValue("{'isRequired': false}").get(), &prop, nullptr)); | |
| EXPECT_FALSE(prop2.IsRequired()); | |
| EXPECT_JSON_EQ("{'type':'integer'}", *prop2.ToJson(true, false)); | |
| EXPECT_JSON_EQ("{'isRequired':false,'type':'integer'}", | |
| *prop2.ToJson(true, true)); | |
| } | |
| TEST(CommandSchema, RequiredProperties_Object) { | |
| ObjectPropType obj_type; | |
| auto schema = ObjectSchema::Create(); | |
| auto type = PropType::Create(ValueType::Int); | |
| type->MakeRequired(true); | |
| schema->AddProp("prop1", std::move(type)); | |
| type = PropType::Create(ValueType::String); | |
| type->MakeRequired(false); | |
| schema->AddProp("prop2", std::move(type)); | |
| type = PropType::Create(ValueType::Boolean); | |
| type->MakeRequired(true); | |
| schema->AddProp("prop3", std::move(type)); | |
| type = PropType::Create(ValueType::Array); | |
| type->GetArray()->SetItemType(PropType::Create(ValueType::String)); | |
| schema->AddProp("prop4", std::move(type)); | |
| auto expected1 = R"({ | |
| 'prop1': 'integer', | |
| 'prop2': 'string', | |
| 'prop3': 'boolean', | |
| 'prop4': {'items': 'string'} | |
| })"; | |
| EXPECT_JSON_EQ(expected1, *schema->ToJson(false, false)); | |
| auto expected2 = R"({ | |
| 'prop1': {'type':'integer','isRequired': true}, | |
| 'prop2': {'type':'string','isRequired': false}, | |
| 'prop3': {'type':'boolean','isRequired': true}, | |
| 'prop4': {'items': 'string'} | |
| })"; | |
| EXPECT_JSON_EQ(expected2, *schema->ToJson(false, true)); | |
| obj_type.SetObjectSchema(std::move(schema)); | |
| auto expected3 = R"({ | |
| 'additionalProperties': false, | |
| 'properties': { | |
| 'prop1': 'integer', | |
| 'prop2': 'string', | |
| 'prop3': 'boolean', | |
| 'prop4': {'items': 'string'} | |
| }, | |
| 'required': ['prop1','prop3'] | |
| })"; | |
| EXPECT_JSON_EQ(expected3, *obj_type.ToJson(false, false)); | |
| EXPECT_JSON_EQ(expected3, *obj_type.ToJson(false, true)); | |
| } | |
| TEST(CommandSchema, RequiredProperties_Schema_FromJson) { | |
| ObjectSchema schema; | |
| auto schema_str = R"({ | |
| 'prop1': {'type':'integer','isRequired': true}, | |
| 'prop2': {'type':'string','isRequired': false}, | |
| 'prop3': 'boolean' | |
| })"; | |
| EXPECT_TRUE(schema.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, | |
| nullptr)); | |
| EXPECT_TRUE(schema.GetProp("prop1")->IsRequired()); | |
| EXPECT_FALSE(schema.GetProp("prop2")->IsRequired()); | |
| EXPECT_FALSE(schema.GetProp("prop3")->IsRequired()); | |
| EXPECT_JSON_EQ(schema_str, *schema.ToJson(false, true)); | |
| } | |
| TEST(CommandSchema, RequiredProperties_Schema_FromJson_Inherit) { | |
| ObjectSchema base_schema; | |
| auto base_schema_str = R"({ | |
| 'prop1': {'type':'integer','isRequired': true}, | |
| 'prop2': {'type':'integer','isRequired': false}, | |
| 'prop3': {'type':'integer','isRequired': true}, | |
| 'prop4': {'type':'integer','isRequired': false} | |
| })"; | |
| EXPECT_TRUE(base_schema.FromJson(CreateDictionaryValue(base_schema_str).get(), | |
| nullptr, nullptr)); | |
| ObjectSchema schema; | |
| auto schema_str = R"({ | |
| 'prop1': {'isRequired': false}, | |
| 'prop2': {'isRequired': true}, | |
| 'prop3': {}, | |
| 'prop4': 'integer' | |
| })"; | |
| EXPECT_TRUE(schema.FromJson(CreateDictionaryValue(schema_str).get(), | |
| &base_schema, nullptr)); | |
| EXPECT_FALSE(schema.GetProp("prop1")->IsRequired()); | |
| EXPECT_TRUE(schema.GetProp("prop2")->IsRequired()); | |
| EXPECT_TRUE(schema.GetProp("prop3")->IsRequired()); | |
| EXPECT_FALSE(schema.GetProp("prop4")->IsRequired()); | |
| auto expected = R"({ | |
| 'prop1': {'type':'integer','isRequired': false}, | |
| 'prop2': {'type':'integer','isRequired': true}, | |
| 'prop3': {}, | |
| 'prop4': {} | |
| })"; | |
| EXPECT_JSON_EQ(expected, *schema.ToJson(false, true)); | |
| } | |
| TEST(CommandSchema, RequiredProperties_ObjectPropType_FromJson) { | |
| ObjectPropType obj_type; | |
| auto type_str = R"({ | |
| 'properties': { | |
| 'prop1': 'integer', | |
| 'prop2': 'string', | |
| 'prop3': {'type':'boolean','isRequired':true}, | |
| 'prop4': {'items': 'string','isRequired':false}, | |
| 'prop5': {'type':'number','isRequired':true} | |
| }, | |
| 'required': ['prop1','prop3','prop4','prop5'] | |
| })"; | |
| EXPECT_TRUE(obj_type.FromJson(CreateDictionaryValue(type_str).get(), nullptr, | |
| nullptr)); | |
| EXPECT_TRUE(obj_type.GetObjectSchemaPtr()->GetProp("prop1")->IsRequired()); | |
| EXPECT_FALSE(obj_type.GetObjectSchemaPtr()->GetProp("prop2")->IsRequired()); | |
| EXPECT_TRUE(obj_type.GetObjectSchemaPtr()->GetProp("prop3")->IsRequired()); | |
| // 'required' takes precedence over 'isRequired'. | |
| EXPECT_TRUE(obj_type.GetObjectSchemaPtr()->GetProp("prop4")->IsRequired()); | |
| EXPECT_TRUE(obj_type.GetObjectSchemaPtr()->GetProp("prop5")->IsRequired()); | |
| } | |
| TEST(CommandSchema, RequiredProperties_Failures) { | |
| ObjectPropType obj_type; | |
| ErrorPtr error; | |
| auto type_str = R"({ | |
| 'properties': { | |
| 'prop1': 'integer', | |
| 'prop2': 'string' | |
| }, | |
| 'required': ['prop1','prop3','prop4'] | |
| })"; | |
| EXPECT_FALSE(obj_type.FromJson(CreateDictionaryValue(type_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ(errors::commands::kUnknownProperty, error->GetCode()); | |
| error.reset(); | |
| type_str = R"({ | |
| 'properties': { | |
| 'prop1': 'integer', | |
| 'prop2': 'string' | |
| }, | |
| 'required': 'prop1' | |
| })"; | |
| EXPECT_FALSE(obj_type.FromJson(CreateDictionaryValue(type_str).get(), nullptr, | |
| &error)); | |
| EXPECT_EQ(errors::commands::kInvalidObjectSchema, error->GetCode()); | |
| error.reset(); | |
| } | |
| TEST(CommandSchema, ObjectSchema_UseRequired) { | |
| ObjectPropType prop; | |
| auto schema_str = R"({ | |
| 'properties':{ | |
| 'param1':'integer', | |
| 'param2':'integer', | |
| 'param3':{'default':3}, | |
| 'param4':{'default':4} | |
| }, | |
| 'required':['param1','param3'] | |
| })"; | |
| ASSERT_TRUE( | |
| prop.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, nullptr)); | |
| auto val_json = R"({ | |
| 'param1':10, | |
| 'param2':20, | |
| 'param3':30, | |
| 'param4':40 | |
| })"; | |
| auto value = | |
| prop.CreatePropValue(*CreateDictionaryValue(val_json).get(), nullptr); | |
| ASSERT_NE(nullptr, value); | |
| ValueMap obj = value->GetObject()->GetValue(); | |
| EXPECT_EQ(10, obj["param1"]->GetInt()->GetValue()); | |
| EXPECT_EQ(20, obj["param2"]->GetInt()->GetValue()); | |
| EXPECT_EQ(30, obj["param3"]->GetInt()->GetValue()); | |
| EXPECT_EQ(40, obj["param4"]->GetInt()->GetValue()); | |
| val_json = "{'param1':100}"; | |
| value = prop.CreatePropValue(*CreateDictionaryValue(val_json).get(), nullptr); | |
| ASSERT_NE(nullptr, value); | |
| obj = value->GetObject()->GetValue(); | |
| EXPECT_EQ(3, obj.size()); | |
| EXPECT_EQ(100, obj["param1"]->GetInt()->GetValue()); | |
| EXPECT_EQ(obj.end(), obj.find("param2")); | |
| EXPECT_EQ(3, obj["param3"]->GetInt()->GetValue()); | |
| EXPECT_EQ(4, obj["param4"]->GetInt()->GetValue()); | |
| } | |
| TEST(CommandSchema, ObjectSchema_UseRequired_Failure) { | |
| ObjectPropType prop; | |
| auto schema_str = R"({ | |
| 'properties':{ | |
| 'param1':'integer', | |
| 'param2':'integer', | |
| 'param3':{'default':3}, | |
| 'param4':{'default':4} | |
| }, | |
| 'required':['param1','param3'] | |
| })"; | |
| ASSERT_TRUE( | |
| prop.FromJson(CreateDictionaryValue(schema_str).get(), nullptr, nullptr)); | |
| auto val_json = "{'param2':20}"; | |
| ErrorPtr error; | |
| auto value = | |
| prop.CreatePropValue(*CreateDictionaryValue(val_json).get(), &error); | |
| ASSERT_EQ(nullptr, value); | |
| EXPECT_EQ(errors::commands::kPropertyMissing, error->GetCode()); | |
| } | |
| } // namespace weave |