| // 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 <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(), value.release()); | 
 |   } | 
 | } | 
 |  | 
 | // 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 |