|  | // 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/prop_constraints.h" | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include <base/json/json_writer.h> | 
|  | #include <base/logging.h> | 
|  |  | 
|  | #include "src/commands/prop_values.h" | 
|  | #include "src/commands/schema_constants.h" | 
|  | #include "src/string_utils.h" | 
|  |  | 
|  | namespace weave { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Helper function to convert a property value to string, which is used for | 
|  | // error reporting. | 
|  | std::string PropValueToString(const PropValue& value) { | 
|  | std::string result; | 
|  | auto json = value.ToJson(); | 
|  | CHECK(json); | 
|  | base::JSONWriter::Write(*json, &result); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | }  // anonymous namespace | 
|  |  | 
|  | // Constraint ---------------------------------------------------------------- | 
|  | Constraint::~Constraint() {} | 
|  |  | 
|  | bool Constraint::ReportErrorLessThan(ErrorPtr* error, | 
|  | const std::string& val, | 
|  | const std::string& limit) { | 
|  | Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, | 
|  | errors::commands::kOutOfRange, | 
|  | "Value %s is out of range. It must not be less than %s", | 
|  | val.c_str(), limit.c_str()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Constraint::ReportErrorGreaterThan(ErrorPtr* error, | 
|  | const std::string& val, | 
|  | const std::string& limit) { | 
|  | Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, | 
|  | errors::commands::kOutOfRange, | 
|  | "Value %s is out of range. It must not be greater than %s", | 
|  | val.c_str(), limit.c_str()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Constraint::ReportErrorNotOneOf(ErrorPtr* error, | 
|  | const std::string& val, | 
|  | const std::vector<std::string>& values) { | 
|  | Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, | 
|  | errors::commands::kOutOfRange, | 
|  | "Value %s is invalid. Expected one of [%s]", val.c_str(), | 
|  | Join(",", values).c_str()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void Constraint::AddToJsonDict(base::DictionaryValue* dict, | 
|  | bool overridden_only) const { | 
|  | if (!overridden_only || HasOverriddenAttributes()) { | 
|  | auto value = ToJson(); | 
|  | CHECK(value); | 
|  | dict->SetWithoutPathExpansion(GetDictKey(), std::move(value)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // ConstraintStringLength ----------------------------------------------------- | 
|  | ConstraintStringLength::ConstraintStringLength( | 
|  | const InheritableAttribute<int>& limit) | 
|  | : limit_(limit) {} | 
|  | ConstraintStringLength::ConstraintStringLength(int limit) : limit_(limit) {} | 
|  |  | 
|  | bool ConstraintStringLength::HasOverriddenAttributes() const { | 
|  | return !limit_.is_inherited; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<base::Value> ConstraintStringLength::ToJson() const { | 
|  | return TypedValueToJson(limit_.value); | 
|  | } | 
|  |  | 
|  | // ConstraintStringLengthMin -------------------------------------------------- | 
|  | ConstraintStringLengthMin::ConstraintStringLengthMin( | 
|  | const InheritableAttribute<int>& limit) | 
|  | : ConstraintStringLength(limit) {} | 
|  | ConstraintStringLengthMin::ConstraintStringLengthMin(int limit) | 
|  | : ConstraintStringLength(limit) {} | 
|  |  | 
|  | bool ConstraintStringLengthMin::Validate(const PropValue& value, | 
|  | ErrorPtr* error) const { | 
|  | CHECK(value.GetString()) << "Expecting a string value for this constraint"; | 
|  | const std::string& str = value.GetString()->GetValue(); | 
|  | int length = static_cast<int>(str.size()); | 
|  | if (length < limit_.value) { | 
|  | if (limit_.value == 1) { | 
|  | Error::AddTo(error, FROM_HERE, errors::commands::kDomain, | 
|  | errors::commands::kOutOfRange, "String must not be empty"); | 
|  | } else { | 
|  | Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, | 
|  | errors::commands::kOutOfRange, | 
|  | "String must be at least %d characters long," | 
|  | " actual length of string '%s' is %d", | 
|  | limit_.value, str.c_str(), length); | 
|  | } | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Constraint> ConstraintStringLengthMin::Clone() const { | 
|  | return std::unique_ptr<Constraint>{new ConstraintStringLengthMin{limit_}}; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Constraint> ConstraintStringLengthMin::CloneAsInherited() | 
|  | const { | 
|  | return std::unique_ptr<Constraint>{ | 
|  | new ConstraintStringLengthMin{limit_.value}}; | 
|  | } | 
|  |  | 
|  | // ConstraintStringLengthMax -------------------------------------------------- | 
|  | ConstraintStringLengthMax::ConstraintStringLengthMax( | 
|  | const InheritableAttribute<int>& limit) | 
|  | : ConstraintStringLength(limit) {} | 
|  | ConstraintStringLengthMax::ConstraintStringLengthMax(int limit) | 
|  | : ConstraintStringLength(limit) {} | 
|  |  | 
|  | bool ConstraintStringLengthMax::Validate(const PropValue& value, | 
|  | ErrorPtr* error) const { | 
|  | CHECK(value.GetString()) << "Expecting a string value for this constraint"; | 
|  | const std::string& str = value.GetString()->GetValue(); | 
|  | int length = static_cast<int>(str.size()); | 
|  | if (length > limit_.value) { | 
|  | Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, | 
|  | errors::commands::kOutOfRange, | 
|  | "String must be no more than %d character(s) " | 
|  | "long, actual length of string '%s' is %d", | 
|  | limit_.value, str.c_str(), length); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Constraint> ConstraintStringLengthMax::Clone() const { | 
|  | return std::unique_ptr<Constraint>{new ConstraintStringLengthMax{limit_}}; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Constraint> ConstraintStringLengthMax::CloneAsInherited() | 
|  | const { | 
|  | return std::unique_ptr<Constraint>{ | 
|  | new ConstraintStringLengthMax{limit_.value}}; | 
|  | } | 
|  |  | 
|  | // ConstraintOneOf -------------------------------------------------- | 
|  | ConstraintOneOf::ConstraintOneOf(InheritableAttribute<ValueVector> set) | 
|  | : set_(std::move(set)) {} | 
|  | ConstraintOneOf::ConstraintOneOf(ValueVector set) : set_(std::move(set)) {} | 
|  |  | 
|  | bool ConstraintOneOf::Validate(const PropValue& value, ErrorPtr* error) const { | 
|  | for (const auto& item : set_.value) { | 
|  | if (value.IsEqual(item.get())) | 
|  | return true; | 
|  | } | 
|  | std::vector<std::string> choice_list; | 
|  | choice_list.reserve(set_.value.size()); | 
|  | for (const auto& item : set_.value) { | 
|  | choice_list.push_back(PropValueToString(*item)); | 
|  | } | 
|  | return ReportErrorNotOneOf(error, PropValueToString(value), choice_list); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Constraint> ConstraintOneOf::Clone() const { | 
|  | InheritableAttribute<ValueVector> attr; | 
|  | attr.is_inherited = set_.is_inherited; | 
|  | attr.value.reserve(set_.value.size()); | 
|  | for (const auto& prop_value : set_.value) { | 
|  | attr.value.push_back(prop_value->Clone()); | 
|  | } | 
|  | return std::unique_ptr<Constraint>{new ConstraintOneOf{std::move(attr)}}; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Constraint> ConstraintOneOf::CloneAsInherited() const { | 
|  | ValueVector cloned; | 
|  | cloned.reserve(set_.value.size()); | 
|  | for (const auto& prop_value : set_.value) { | 
|  | cloned.push_back(prop_value->Clone()); | 
|  | } | 
|  | return std::unique_ptr<Constraint>{new ConstraintOneOf{std::move(cloned)}}; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<base::Value> ConstraintOneOf::ToJson() const { | 
|  | return TypedValueToJson(set_.value); | 
|  | } | 
|  |  | 
|  | const char* ConstraintOneOf::GetDictKey() const { | 
|  | return commands::attributes::kOneOf_Enum; | 
|  | } | 
|  |  | 
|  | }  // namespace weave |