buffet: Clean up property system in preparation for Array support
- Made ObjectSchema::PropFromJson a public method to allow parsing
type definitions for other elements, not only object properties
(it will be used to parse "items" definition for arrays). Made this
method to return std::unique_ptr<PropType> instead of putting the
type directly into property map.
- Cleaned up error reporting when parsing type definitions from JSON.
Now PropFromJson does not refer to any particular property name
in error messages. The property name is added on the level higher
(at ObjectSchema::FromJson).
- Moved GetObjectSchema() method from base PropType class to the
only place where it is being used right now - ObjectPropType.
- Switched value constraints to use generic PropType instead of
ObjectSchema which will allow to add support for constraints
on more complex types (such as arrays). Also added
CloneWithNoConstraints() method to base class to help implement
OneOf() constraint of polymorphic type (will be used more in the
following CLs to support arrays of values).
- Fixed some formatting of function definitions.
- Moved static methods in object_schema.cc into an anonymous namespace
at the beginning of the source file.
BUG=brillo:107
TEST=`FEATURES=test emerge-link buffet`
Change-Id: I86dd6c0780a46f4996ffe698dffb5d409699ff31
Reviewed-on: https://chromium-review.googlesource.com/260852
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
Trybot-Ready: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/commands/command_instance.cc b/buffet/commands/command_instance.cc
index d39e4a1..cc03210 100644
--- a/buffet/commands/command_instance.cc
+++ b/buffet/commands/command_instance.cc
@@ -12,6 +12,7 @@
#include "buffet/commands/command_dictionary.h"
#include "buffet/commands/command_proxy_interface.h"
#include "buffet/commands/command_queue.h"
+#include "buffet/commands/prop_types.h"
#include "buffet/commands/schema_constants.h"
#include "buffet/commands/schema_utils.h"
@@ -85,8 +86,9 @@
// Now read in the parameters and validate their values against the command
// definition schema.
- if (!TypedValueFromJson(params, command_def->GetParameters().get(),
- parameters, error)) {
+ ObjectPropType obj_prop_type;
+ obj_prop_type.SetObjectSchema(command_def->GetParameters());
+ if (!TypedValueFromJson(params, &obj_prop_type, parameters, error)) {
return false;
}
return true;
diff --git a/buffet/commands/object_schema.cc b/buffet/commands/object_schema.cc
index 6437262..b89de98 100644
--- a/buffet/commands/object_schema.cc
+++ b/buffet/commands/object_schema.cc
@@ -9,6 +9,7 @@
#include <base/logging.h>
#include <base/values.h>
+#include <chromeos/map_utils.h>
#include "buffet/commands/prop_types.h"
#include "buffet/commands/prop_values.h"
@@ -16,49 +17,12 @@
namespace buffet {
-void ObjectSchema::AddProp(const std::string& name,
- std::shared_ptr<PropType> prop) {
- properties_[name] = prop;
-}
+namespace {
-const PropType* ObjectSchema::GetProp(const std::string& name) const {
- auto p = properties_.find(name);
- return p != properties_.end() ? p->second.get() : nullptr;
-}
-
-std::unique_ptr<base::DictionaryValue> ObjectSchema::ToJson(
- bool full_schema, chromeos::ErrorPtr* error) const {
- std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue);
- for (const auto& pair : properties_) {
- auto PropDef = pair.second->ToJson(full_schema, error);
- if (!PropDef)
- return std::unique_ptr<base::DictionaryValue>();
- value->SetWithoutPathExpansion(pair.first, PropDef.release());
- }
- return value;
-}
-
-bool ObjectSchema::FromJson(const base::DictionaryValue* value,
- const ObjectSchema* object_schema,
- chromeos::ErrorPtr* error) {
- Properties properties;
- base::DictionaryValue::Iterator iter(*value);
- while (!iter.IsAtEnd()) {
- std::string name = iter.key();
- const PropType* base_schema =
- object_schema ? object_schema->GetProp(iter.key()) : nullptr;
- if (!PropFromJson(iter.key(), iter.value(), base_schema, &properties,
- error))
- return false;
- iter.Advance();
- }
- properties_ = std::move(properties);
- return true;
-}
-
-static std::unique_ptr<PropType> CreatePropType(const std::string& type_name,
- const std::string& prop_name,
- chromeos::ErrorPtr* error) {
+// Helper function for to create a PropType based on type string.
+// Generates an error if the string identifies an unknown type.
+std::unique_ptr<PropType> CreatePropType(const std::string& type_name,
+ chromeos::ErrorPtr* error) {
std::unique_ptr<PropType> prop;
ValueType type;
if (PropType::GetTypeFromTypeString(type_name, &type))
@@ -66,71 +30,40 @@
if (!prop) {
chromeos::Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
errors::commands::kUnknownType,
- "Unknown type %s for parameter %s",
- type_name.c_str(), prop_name.c_str());
+ "Unknown type %s", type_name.c_str());
}
return prop;
}
-static bool ErrorInvalidTypeInfo(const std::string& prop_name,
- chromeos::ErrorPtr* error) {
- chromeos::Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kNoTypeInfo,
- "Unable to determine parameter type for %s",
- prop_name.c_str());
- return false;
+// Generates "no_type_info" error.
+void ErrorInvalidTypeInfo(chromeos::ErrorPtr* error) {
+ chromeos::Error::AddTo(error, FROM_HERE, errors::commands::kDomain,
+ errors::commands::kNoTypeInfo,
+ "Unable to determine parameter type");
}
-bool ObjectSchema::PropFromJson(const std::string& prop_name,
- const base::Value& value,
- const PropType* base_schema,
- Properties* properties,
- chromeos::ErrorPtr* error) const {
- if (value.IsType(base::Value::TYPE_STRING)) {
- // A string value is a short-hand object specification and provides
- // the parameter type.
- return PropFromJsonString(prop_name, value, base_schema, properties,
- error);
- } else if (value.IsType(base::Value::TYPE_LIST)) {
- // One of the enumerated types.
- return PropFromJsonArray(prop_name, value, base_schema, properties,
- error);
- } else if (value.IsType(base::Value::TYPE_DICTIONARY)) {
- // Full parameter definition.
- return PropFromJsonObject(prop_name, value, base_schema, properties,
- error);
- }
- chromeos::Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kInvalidPropDef,
- "Invalid parameter definition for %s",
- prop_name.c_str());
- return false;
-}
-
-bool ObjectSchema::PropFromJsonString(const std::string& prop_name,
- const base::Value& value,
- const PropType* base_schema,
- Properties* properties,
- chromeos::ErrorPtr* error) const {
+// Helper function for PropFromJson to handle the case of parameter being
+// defined as a JSON string like this:
+// "prop":"..."
+std::unique_ptr<PropType> PropFromJsonString(
+ const base::Value& value,
+ const PropType* base_schema,
+ chromeos::ErrorPtr* error) {
std::string type_name;
CHECK(value.GetAsString(&type_name)) << "Unable to get string value";
- std::unique_ptr<PropType> prop = CreatePropType(type_name, prop_name, error);
- if (!prop)
- return false;
+ std::unique_ptr<PropType> prop = CreatePropType(type_name, error);
base::DictionaryValue empty;
- if (!prop->FromJson(&empty, base_schema, error)) {
- chromeos::Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kInvalidPropDef,
- "Error in definition of property '%s'",
- prop_name.c_str());
- return false;
- }
- properties->insert(std::make_pair(prop_name, std::move(prop)));
- return true;
+ if (prop && !prop->FromJson(&empty, base_schema, error))
+ prop.reset();
+
+ return prop;
}
-static std::string DetectArrayType(const base::ListValue* list,
- const PropType* base_schema) {
+// Detects a type based on JSON array. Inspects the first element of the array
+// to deduce the PropType from. Returns the string name of the type detected
+// or empty string is type detection failed.
+std::string DetectArrayType(const base::ListValue* list,
+ const PropType* base_schema) {
std::string type_name;
if (base_schema) {
type_name = base_schema->GetTypeAsString();
@@ -162,35 +95,37 @@
return type_name;
}
-bool ObjectSchema::PropFromJsonArray(const std::string& prop_name,
- const base::Value& value,
- const PropType* base_schema,
- Properties* properties,
- chromeos::ErrorPtr* error) const {
+// Helper function for PropFromJson to handle the case of parameter being
+// defined as a JSON array like this:
+// "prop":[...]
+std::unique_ptr<PropType> PropFromJsonArray(
+ const base::Value& value,
+ const PropType* base_schema,
+ chromeos::ErrorPtr* error) {
+ std::unique_ptr<PropType> prop;
const base::ListValue* list = nullptr;
CHECK(value.GetAsList(&list)) << "Unable to get array value";
std::string type_name = DetectArrayType(list, base_schema);
- if (type_name.empty())
- return ErrorInvalidTypeInfo(prop_name, error);
- std::unique_ptr<PropType> prop = CreatePropType(type_name, prop_name, error);
- if (!prop)
- return false;
+ if (type_name.empty()) {
+ ErrorInvalidTypeInfo(error);
+ return prop;
+ }
base::DictionaryValue array_object;
array_object.SetWithoutPathExpansion(commands::attributes::kOneOf_Enum,
list->DeepCopy());
- if (!prop->FromJson(&array_object, base_schema, error)) {
- chromeos::Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kInvalidPropDef,
- "Error in definition of property '%s'",
- prop_name.c_str());
- return false;
- }
- properties->insert(std::make_pair(prop_name, std::move(prop)));
- return true;
+ prop = CreatePropType(type_name, error);
+ if (prop && !prop->FromJson(&array_object, base_schema, error))
+ prop.reset();
+
+ return prop;
}
-static std::string DetectObjectType(const base::DictionaryValue* dict,
- const PropType* base_schema) {
+// Detects a type based on JSON object definition of type. Looks at various
+// members such as minimum/maximum constraints, default and enum values to
+// try to deduce the underlying type of the element. Returns the string name of
+// the type detected or empty string is type detection failed.
+std::string DetectObjectType(const base::DictionaryValue* dict,
+ const PropType* base_schema) {
bool has_min_max = dict->HasKey(commands::attributes::kNumeric_Min) ||
dict->HasKey(commands::attributes::kNumeric_Max);
@@ -251,37 +186,119 @@
return std::string();
}
-bool ObjectSchema::PropFromJsonObject(const std::string& prop_name,
- const base::Value& value,
- const PropType* base_schema,
- Properties* properties,
- chromeos::ErrorPtr* error) const {
+// Helper function for PropFromJson to handle the case of parameter being
+// defined as a JSON object like this:
+// "prop":{...}
+std::unique_ptr<PropType> PropFromJsonObject(
+ const base::Value& value,
+ const PropType* base_schema,
+ chromeos::ErrorPtr* error) {
+ std::unique_ptr<PropType> prop;
const base::DictionaryValue* dict = nullptr;
CHECK(value.GetAsDictionary(&dict)) << "Unable to get dictionary value";
std::string type_name;
if (dict->HasKey(commands::attributes::kType)) {
- if (!dict->GetString(commands::attributes::kType, &type_name))
- return ErrorInvalidTypeInfo(prop_name, error);
+ if (!dict->GetString(commands::attributes::kType, &type_name)) {
+ ErrorInvalidTypeInfo(error);
+ return prop;
+ }
} else {
type_name = DetectObjectType(dict, base_schema);
}
if (type_name.empty()) {
- if (!base_schema)
- return ErrorInvalidTypeInfo(prop_name, error);
+ if (!base_schema) {
+ ErrorInvalidTypeInfo(error);
+ return prop;
+ }
type_name = base_schema->GetTypeAsString();
}
- std::unique_ptr<PropType> prop = CreatePropType(type_name, prop_name, error);
- if (!prop)
- return false;
- if (!prop->FromJson(dict, base_schema, error)) {
- chromeos::Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kInvalidPropDef,
- "Error in definition of property '%s'",
- prop_name.c_str());
- return false;
+ prop = CreatePropType(type_name, error);
+ if (prop && !prop->FromJson(dict, base_schema, error))
+ prop.reset();
+
+ return prop;
+}
+
+} // anonymous namespace
+
+void ObjectSchema::AddProp(const std::string& name,
+ std::shared_ptr<PropType> prop) {
+ properties_[name] = prop;
+}
+
+const PropType* ObjectSchema::GetProp(const std::string& name) const {
+ auto p = properties_.find(name);
+ return p != properties_.end() ? p->second.get() : nullptr;
+}
+
+std::unique_ptr<base::DictionaryValue> ObjectSchema::ToJson(
+ bool full_schema, chromeos::ErrorPtr* error) const {
+ std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue);
+ for (const auto& pair : properties_) {
+ auto PropDef = pair.second->ToJson(full_schema, error);
+ if (!PropDef)
+ return std::unique_ptr<base::DictionaryValue>();
+ value->SetWithoutPathExpansion(pair.first, PropDef.release());
}
- properties->insert(std::make_pair(prop_name, std::move(prop)));
+ return value;
+}
+
+bool ObjectSchema::FromJson(const base::DictionaryValue* value,
+ const ObjectSchema* object_schema,
+ chromeos::ErrorPtr* error) {
+ Properties properties;
+ base::DictionaryValue::Iterator iter(*value);
+ while (!iter.IsAtEnd()) {
+ std::string name = iter.key();
+ const PropType* base_schema =
+ object_schema ? object_schema->GetProp(iter.key()) : nullptr;
+ auto prop_type = PropFromJson(iter.value(), base_schema, error);
+ if (prop_type) {
+ properties.insert(std::make_pair(iter.key(), std::move(prop_type)));
+ } else {
+ chromeos::Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
+ errors::commands::kInvalidPropDef,
+ "Error in definition of property '%s'",
+ iter.key().c_str());
+ return false;
+ }
+ iter.Advance();
+ }
+ properties_ = std::move(properties);
return true;
}
+std::unique_ptr<PropType> ObjectSchema::PropFromJson(
+ const base::Value& value,
+ const PropType* base_schema,
+ chromeos::ErrorPtr* error) {
+ if (value.IsType(base::Value::TYPE_STRING)) {
+ // A string value is a short-hand object specification and provides
+ // the parameter type.
+ return PropFromJsonString(value, base_schema, error);
+ } else if (value.IsType(base::Value::TYPE_LIST)) {
+ // One of the enumerated types.
+ return PropFromJsonArray(value, base_schema, error);
+ } else if (value.IsType(base::Value::TYPE_DICTIONARY)) {
+ // Full parameter definition.
+ return PropFromJsonObject(value, base_schema, error);
+ }
+ static const std::map<base::Value::Type, const char*> type_names = {
+ {base::Value::TYPE_NULL, "Null"},
+ {base::Value::TYPE_BOOLEAN, "Boolean"},
+ {base::Value::TYPE_INTEGER, "Integer"},
+ {base::Value::TYPE_DOUBLE, "Double"},
+ {base::Value::TYPE_STRING, "String"},
+ {base::Value::TYPE_BINARY, "Binary"},
+ {base::Value::TYPE_DICTIONARY, "Object"},
+ {base::Value::TYPE_LIST, "Array"},
+ };
+ const char* type_name = chromeos::GetOrDefault(type_names, value.GetType(),
+ "<unknown>");
+ chromeos::Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
+ errors::commands::kUnknownType,
+ "Unexpected JSON value type: %s", type_name);
+ return {};
+}
+
} // namespace buffet
diff --git a/buffet/commands/object_schema.h b/buffet/commands/object_schema.h
index 8808fb0..e47cf14 100644
--- a/buffet/commands/object_schema.h
+++ b/buffet/commands/object_schema.h
@@ -63,36 +63,15 @@
// Loads the object schema from JSON. If |object_schema| is not nullptr, it is
// used as a base schema to inherit omitted properties and constraints from.
bool FromJson(const base::DictionaryValue* value,
- const ObjectSchema* object_schema, chromeos::ErrorPtr* error);
+ const ObjectSchema* object_schema,
+ chromeos::ErrorPtr* error);
+
+ // Helper method to load property type definitions from JSON.
+ static std::unique_ptr<PropType> PropFromJson(const base::Value& value,
+ const PropType* base_schema,
+ chromeos::ErrorPtr* error);
private:
- // Internal helper method to load individual parameter type definitions.
- bool PropFromJson(const std::string& prop_name,
- const base::Value& value,
- const PropType* base_schema,
- Properties* properties, chromeos::ErrorPtr* error) const;
- // Helper function in case the parameter is defined as JSON string like this:
- // "prop":"..."
- bool PropFromJsonString(const std::string& prop_name,
- const base::Value& value,
- const PropType* base_schema,
- Properties* properties,
- chromeos::ErrorPtr* error) const;
- // Helper function in case the parameter is defined as JSON array like this:
- // "prop":[...]
- bool PropFromJsonArray(const std::string& prop_name,
- const base::Value& value,
- const PropType* base_schema,
- Properties* properties,
- chromeos::ErrorPtr* error) const;
- // Helper function in case the parameter is defined as JSON object like this:
- // "prop":{...}
- bool PropFromJsonObject(const std::string& prop_name,
- const base::Value& value,
- const PropType* base_schema,
- Properties* properties,
- chromeos::ErrorPtr* error) const;
-
// Internal parameter type definition map.
Properties properties_;
bool extra_properties_allowed_{false};
diff --git a/buffet/commands/object_schema_unittest.cc b/buffet/commands/object_schema_unittest.cc
index 0f429a1..2031705 100644
--- a/buffet/commands/object_schema_unittest.cc
+++ b/buffet/commands/object_schema_unittest.cc
@@ -548,7 +548,7 @@
EXPECT_TRUE(base_prop.FromJson(CreateDictionaryValue(
"{'properties':{'name':'string','age':'integer'}}").get(), nullptr,
nullptr));
- auto schema = base_prop.GetObjectSchemaPtr();
+ auto schema = base_prop.GetObject()->GetObjectSchemaPtr();
const buffet::PropType* prop = schema->GetProp("name");
EXPECT_EQ(buffet::ValueType::String, prop->GetType());
prop = schema->GetProp("age");
diff --git a/buffet/commands/prop_constraints.h b/buffet/commands/prop_constraints.h
index ae93ccf..a898e0b 100644
--- a/buffet/commands/prop_constraints.h
+++ b/buffet/commands/prop_constraints.h
@@ -54,7 +54,8 @@
// Saves the constraint into the specified JSON |dict| object, representing
// the object schema. If |overridden_only| is set to true, then the
// inherited constraints will not be added to the schema object.
- virtual bool AddToJsonDict(base::DictionaryValue* dict, bool overridden_only,
+ virtual bool AddToJsonDict(base::DictionaryValue* dict,
+ bool overridden_only,
chromeos::ErrorPtr* error) const;
// Saves the value of constraint to JSON value. E.g., if the numeric
// constraint was defined as {"minimum":20} this will create a JSON value
diff --git a/buffet/commands/prop_types.cc b/buffet/commands/prop_types.cc
index 37a6dc8..abba22d 100644
--- a/buffet/commands/prop_types.cc
+++ b/buffet/commands/prop_types.cc
@@ -93,6 +93,14 @@
return std::unique_ptr<base::Value>(dict.release());
}
+std::unique_ptr<PropType> PropType::Clone() const {
+ auto cloned = PropType::Create(GetType());
+ cloned->based_on_schema_ = based_on_schema_;
+ cloned->constraints_ = constraints_;
+ cloned->default_ = default_;
+ return cloned;
+}
+
bool PropType::FromJson(const base::DictionaryValue* value,
const PropType* base_schema,
chromeos::ErrorPtr* error) {
@@ -167,7 +175,7 @@
return true;
}
-void PropType::AddConstraint(std::shared_ptr<Constraint> constraint) {
+void PropType::AddConstraint(const std::shared_ptr<Constraint>& constraint) {
constraints_[constraint->GetType()] = constraint;
}
@@ -175,6 +183,10 @@
constraints_.erase(constraint_type);
}
+void PropType::RemoveAllConstraints() {
+ constraints_.clear();
+}
+
const Constraint* PropType::GetConstraint(
ConstraintType constraint_type) const {
auto p = constraints_.find(constraint_type);
@@ -270,7 +282,8 @@
template<typename T>
static std::shared_ptr<Constraint> LoadOneOfConstraint(
- const base::DictionaryValue* value, const ObjectSchema* object_schema,
+ const base::DictionaryValue* value,
+ const std::shared_ptr<const PropType>& prop_type,
chromeos::ErrorPtr* error) {
const base::ListValue* list = nullptr;
if (!value->GetListWithoutPathExpansion(commands::attributes::kOneOf_Enum,
@@ -284,7 +297,7 @@
set.reserve(list->GetSize());
for (const base::Value* item : *list) {
T val{};
- if (!TypedValueFromJson(item, object_schema, &val, error))
+ if (!TypedValueFromJson(item, prop_type.get(), &val, error))
return std::shared_ptr<Constraint>();
set.push_back(val);
}
@@ -294,13 +307,14 @@
template<class ConstraintClass, typename T>
static std::shared_ptr<Constraint> LoadMinMaxConstraint(
- const char* dict_key, const base::DictionaryValue* value,
- const ObjectSchema* object_schema, chromeos::ErrorPtr* error) {
+ const char* dict_key,
+ const base::DictionaryValue* value,
+ chromeos::ErrorPtr* error) {
InheritableAttribute<T> limit;
const base::Value* src_val = nullptr;
CHECK(value->Get(dict_key, &src_val)) << "Unable to get min/max constraints";
- if (!TypedValueFromJson(src_val, object_schema, &limit.value, error))
+ if (!TypedValueFromJson(src_val, nullptr, &limit.value, error))
return std::shared_ptr<Constraint>();
limit.is_inherited = false;
@@ -311,14 +325,16 @@
template<class Derived, class Value, typename T>
bool PropTypeBase<Derived, Value, T>::ConstraintsFromJson(
- const base::DictionaryValue* value, std::set<std::string>* processed_keys,
+ const base::DictionaryValue* value,
+ std::set<std::string>* processed_keys,
chromeos::ErrorPtr* error) {
if (!PropType::ConstraintsFromJson(value, processed_keys, error))
return false;
if (value->HasKey(commands::attributes::kOneOf_Enum)) {
- auto constraint = LoadOneOfConstraint<T>(value, this->GetObjectSchemaPtr(),
- error);
+ auto type = Clone();
+ type->RemoveAllConstraints();
+ auto constraint = LoadOneOfConstraint<T>(value, std::move(type), error);
if (!constraint)
return false;
this->AddConstraint(constraint);
@@ -334,7 +350,8 @@
template<class Derived, class Value, typename T>
bool NumericPropTypeBase<Derived, Value, T>::ConstraintsFromJson(
- const base::DictionaryValue* value, std::set<std::string>* processed_keys,
+ const base::DictionaryValue* value,
+ std::set<std::string>* processed_keys,
chromeos::ErrorPtr* error) {
if (!_Base::ConstraintsFromJson(value, processed_keys, error))
return false;
@@ -345,8 +362,7 @@
// specified.
if (value->HasKey(commands::attributes::kNumeric_Min)) {
auto constraint = LoadMinMaxConstraint<ConstraintMin<T>, T>(
- commands::attributes::kNumeric_Min, value, this->GetObjectSchemaPtr(),
- error);
+ commands::attributes::kNumeric_Min, value, error);
if (!constraint)
return false;
this->AddConstraint(constraint);
@@ -355,8 +371,7 @@
}
if (value->HasKey(commands::attributes::kNumeric_Max)) {
auto constraint = LoadMinMaxConstraint<ConstraintMax<T>, T>(
- commands::attributes::kNumeric_Max, value, this->GetObjectSchemaPtr(),
- error);
+ commands::attributes::kNumeric_Max, value, error);
if (!constraint)
return false;
this->AddConstraint(constraint);
@@ -371,7 +386,8 @@
// StringPropType -------------------------------------------------------------
bool StringPropType::ConstraintsFromJson(
- const base::DictionaryValue* value, std::set<std::string>* processed_keys,
+ const base::DictionaryValue* value,
+ std::set<std::string>* processed_keys,
chromeos::ErrorPtr* error) {
if (!_Base::ConstraintsFromJson(value, processed_keys, error))
return false;
@@ -382,8 +398,7 @@
// specified.
if (value->HasKey(commands::attributes::kString_MinLength)) {
auto constraint = LoadMinMaxConstraint<ConstraintStringLengthMin, int>(
- commands::attributes::kString_MinLength, value, GetObjectSchemaPtr(),
- error);
+ commands::attributes::kString_MinLength, value, error);
if (!constraint)
return false;
AddConstraint(constraint);
@@ -392,8 +407,7 @@
}
if (value->HasKey(commands::attributes::kString_MaxLength)) {
auto constraint = LoadMinMaxConstraint<ConstraintStringLengthMax, int>(
- commands::attributes::kString_MaxLength, value, GetObjectSchemaPtr(),
- error);
+ commands::attributes::kString_MaxLength, value, error);
if (!constraint)
return false;
AddConstraint(constraint);
@@ -433,6 +447,12 @@
!object_schema_.is_inherited;
}
+std::unique_ptr<PropType> ObjectPropType::Clone() const {
+ auto cloned = _Base::Clone();
+ cloned->GetObject()->object_schema_ = object_schema_;
+ return cloned;
+}
+
std::unique_ptr<base::Value> ObjectPropType::ToJson(
bool full_schema, chromeos::ErrorPtr* error) const {
std::unique_ptr<base::Value> value = PropType::ToJson(full_schema, error);
@@ -452,9 +472,10 @@
return value;
}
-bool ObjectPropType::ObjectSchemaFromJson(
- const base::DictionaryValue* value, const PropType* base_schema,
- std::set<std::string>* processed_keys, chromeos::ErrorPtr* error) {
+bool ObjectPropType::ObjectSchemaFromJson(const base::DictionaryValue* value,
+ const PropType* base_schema,
+ std::set<std::string>* processed_keys,
+ chromeos::ErrorPtr* error) {
if (!_Base::ObjectSchemaFromJson(value, base_schema, processed_keys, error))
return false;
diff --git a/buffet/commands/prop_types.h b/buffet/commands/prop_types.h
index 2533c34..a2d4a18 100644
--- a/buffet/commands/prop_types.h
+++ b/buffet/commands/prop_types.h
@@ -78,7 +78,8 @@
virtual ObjectPropType const* GetObject() const { return nullptr; }
// Makes a full copy of this type definition.
- virtual std::shared_ptr<PropType> Clone() const = 0;
+ virtual std::unique_ptr<PropType> Clone() const;
+
// Creates an instance of associated value object, using the parameter
// type as a factory class.
virtual std::shared_ptr<PropValue> CreateValue() const = 0;
@@ -101,7 +102,8 @@
// Returns true on success, otherwise fills in the |error| with additional
// error information.
virtual bool FromJson(const base::DictionaryValue* value,
- const PropType* base_schema, chromeos::ErrorPtr* error);
+ const PropType* base_schema,
+ chromeos::ErrorPtr* error);
// Helper function to load object schema from JSON.
virtual bool ObjectSchemaFromJson(const base::DictionaryValue* value,
const PropType* base_schema,
@@ -142,23 +144,16 @@
static std::unique_ptr<PropType> Create(ValueType type);
// Adds a constraint to the type definition.
- void AddConstraint(std::shared_ptr<Constraint> constraint);
+ void AddConstraint(const std::shared_ptr<Constraint>& constraint);
// Removes a constraint of given type, if it exists.
void RemoveConstraint(ConstraintType constraint_type);
+ // Removes all constraints.
+ void RemoveAllConstraints();
// Finds a constraint of given type. Returns nullptr if not found.
const Constraint* GetConstraint(ConstraintType constraint_type) const;
Constraint* GetConstraint(ConstraintType constraint_type);
- // Returns a schema for Object-type parameter. This will be nullptr for
- // every type but Object.
- const ObjectSchema* GetObjectSchemaPtr() const {
- return GetObjectSchema().get();
- }
- virtual std::shared_ptr<const ObjectSchema> GetObjectSchema() const {
- return std::shared_ptr<const ObjectSchema>();
- }
-
// Validates the given value against all the constraints.
bool ValidateConstraints(const PropValue& value,
chromeos::ErrorPtr* error) const;
@@ -187,9 +182,6 @@
class PropTypeBase : public PropType {
public:
ValueType GetType() const override { return GetValueType<T>(); }
- std::shared_ptr<PropType> Clone() const override {
- return std::make_shared<Derived>(*static_cast<const Derived*>(this));
- }
std::shared_ptr<PropValue> CreateValue() const override {
return std::make_shared<Value>(this);
}
@@ -305,6 +297,8 @@
ObjectPropType* GetObject() override { return this; }
ObjectPropType const* GetObject() const override { return this; }
+ std::unique_ptr<PropType> Clone() const override;
+
std::unique_ptr<base::Value> ToJson(bool full_schema,
chromeos::ErrorPtr* error) const override;
bool ObjectSchemaFromJson(const base::DictionaryValue* value,
@@ -312,7 +306,11 @@
std::set<std::string>* processed_keys,
chromeos::ErrorPtr* error) override;
- std::shared_ptr<const ObjectSchema> GetObjectSchema() const override {
+ // Returns a schema for Object-type parameter.
+ inline const ObjectSchema* GetObjectSchemaPtr() const {
+ return GetObjectSchema().get();
+ }
+ std::shared_ptr<const ObjectSchema> GetObjectSchema() const {
return object_schema_.value;
}
void SetObjectSchema(const std::shared_ptr<const ObjectSchema>& schema) {
diff --git a/buffet/commands/prop_values.h b/buffet/commands/prop_values.h
index 1d1c26d..bf0d88d 100644
--- a/buffet/commands/prop_values.h
+++ b/buffet/commands/prop_values.h
@@ -137,8 +137,7 @@
}
bool FromJson(const base::Value* value, chromeos::ErrorPtr* error) override {
- return TypedValueFromJson(value, GetPropType()->GetObjectSchemaPtr(),
- &value_, error);
+ return TypedValueFromJson(value, GetPropType(), &value_, error);
}
bool IsEqual(const PropValue* value) const override {
@@ -190,8 +189,8 @@
};
// Value of type Object.
-class ObjectValue final : public TypedValueBase<ObjectValue,
- native_types::Object> {
+class ObjectValue final
+ : public TypedValueBase<ObjectValue, native_types::Object> {
public:
using _Base::_Base; // Expose the custom constructor of the base class.
ObjectValue* GetObject() override { return this; }
diff --git a/buffet/commands/schema_utils.cc b/buffet/commands/schema_utils.cc
index 043f0ae..c9531c5 100644
--- a/buffet/commands/schema_utils.cc
+++ b/buffet/commands/schema_utils.cc
@@ -82,43 +82,49 @@
}
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
- bool* value_out, chromeos::ErrorPtr* error) {
+ const PropType* type,
+ bool* value_out,
+ chromeos::ErrorPtr* error) {
return value_in->GetAsBoolean(value_out) ||
ReportUnexpectedJson(value_in, value_out, error);
}
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
- int* value_out, chromeos::ErrorPtr* error) {
+ const PropType* type,
+ int* value_out,
+ chromeos::ErrorPtr* error) {
return value_in->GetAsInteger(value_out) ||
ReportUnexpectedJson(value_in, value_out, error);
}
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
- double* value_out, chromeos::ErrorPtr* error) {
+ const PropType* type,
+ double* value_out,
+ chromeos::ErrorPtr* error) {
return value_in->GetAsDouble(value_out) ||
ReportUnexpectedJson(value_in, value_out, error);
}
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
- std::string* value_out, chromeos::ErrorPtr* error) {
+ const PropType* type,
+ std::string* value_out,
+ chromeos::ErrorPtr* error) {
return value_in->GetAsString(value_out) ||
ReportUnexpectedJson(value_in, value_out, error);
}
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
+ const PropType* type,
native_types::Object* value_out,
chromeos::ErrorPtr* error) {
const base::DictionaryValue* dict = nullptr;
if (!value_in->GetAsDictionary(&dict))
return ReportUnexpectedJson(value_in, value_out, error);
- CHECK(object_schema) << "Object schema must be provided";
+ CHECK(type) << "Object definition must be provided";
+ CHECK(ValueType::Object == type->GetType()) << "Type must be Object";
+ const ObjectSchema* object_schema = type->GetObject()->GetObjectSchemaPtr();
std::set<std::string> keys_processed;
for (const auto& pair : object_schema->GetProps()) {
const PropValue* def_value = pair.second->GetDefaultValue();
@@ -231,10 +237,10 @@
type->GenerateErrorValueTypeMismatch(error);
return {};
}
- CHECK(nullptr != type->GetObjectSchemaPtr())
+ CHECK(nullptr != type->GetObject()->GetObjectSchemaPtr())
<< "An object type must have a schema defined for it";
native_types::Object obj;
- if (!ObjectFromDBusVariant(type->GetObjectSchemaPtr(),
+ if (!ObjectFromDBusVariant(type->GetObject()->GetObjectSchemaPtr(),
value.Get<chromeos::VariantDictionary>(),
&obj,
error))
diff --git a/buffet/commands/schema_utils.h b/buffet/commands/schema_utils.h
index 597a580..55c07a1 100644
--- a/buffet/commands/schema_utils.h
+++ b/buffet/commands/schema_utils.h
@@ -78,19 +78,23 @@
// helper methods allow to extract specific C++ data types from base::Value.
// Also used in template classes below to simplify specialization logic.
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
- bool* value_out, chromeos::ErrorPtr* error);
+ const PropType* type,
+ bool* value_out,
+ chromeos::ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
- int* value_out, chromeos::ErrorPtr* error);
+ const PropType* type,
+ int* value_out,
+ chromeos::ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
- double* value_out, chromeos::ErrorPtr* error);
+ const PropType* type,
+ double* value_out,
+ chromeos::ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
- std::string* value_out, chromeos::ErrorPtr* error);
+ const PropType* type,
+ std::string* value_out,
+ chromeos::ErrorPtr* error);
bool TypedValueFromJson(const base::Value* value_in,
- const ObjectSchema* object_schema,
+ const PropType* type,
native_types::Object* value_out,
chromeos::ErrorPtr* error);
diff --git a/buffet/commands/schema_utils_unittest.cc b/buffet/commands/schema_utils_unittest.cc
index 4d0b90a..3cd0b5d 100644
--- a/buffet/commands/schema_utils_unittest.cc
+++ b/buffet/commands/schema_utils_unittest.cc
@@ -159,18 +159,20 @@
TEST(CommandSchemaUtils, TypedValueFromJson_Object) {
buffet::native_types::Object value;
- buffet::ObjectSchema schema;
+ auto schema = std::make_shared<buffet::ObjectSchema>();
auto age_prop = std::make_shared<buffet::IntPropType>();
age_prop->AddMinMaxConstraint(0, 150);
- schema.AddProp("age", age_prop);
+ schema->AddProp("age", age_prop);
auto name_prop = std::make_shared<buffet::StringPropType>();
name_prop->AddLengthConstraint(1, 30);
- schema.AddProp("name", name_prop);
+ schema->AddProp("name", name_prop);
+ buffet::ObjectPropType type;
+ type.SetObjectSchema(schema);
EXPECT_TRUE(buffet::TypedValueFromJson(
- CreateValue("{'age':20,'name':'Bob'}").get(), &schema, &value, nullptr));
+ CreateValue("{'age':20,'name':'Bob'}").get(), &type, &value, nullptr));
buffet::native_types::Object value2;
value2.insert(std::make_pair("age", age_prop->CreateValue(20, nullptr)));
value2.insert(std::make_pair("name",