blob: b7e9cf6746af3d71504dc110cc84d07df1d7f603 [file] [log] [blame]
// 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