NASA Astrobee Robot Software  Astrobee Version:
Flight software for the Astrobee robots operating inside the International Space Station.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
validation.h
Go to the documentation of this file.
1 /* Copyright (c) 2017, United States Government, as represented by the
2  * Administrator of the National Aeronautics and Space Administration.
3  *
4  * All rights reserved.
5  *
6  * The Astrobee platform is licensed under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with the
8  * License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15  * License for the specific language governing permissions and limitations
16  * under the License.
17  */
18 
19 #ifndef JSONLOADER_VALIDATION_H_
20 #define JSONLOADER_VALIDATION_H_
21 
22 #include <json/value.h>
23 
24 #include <string>
25 #include <vector>
26 
27 namespace jsonloader {
28 
29 // Make sure a field in an object is the right type, optionally require
30 // the field to be present.
31 class Field {
32  public:
33  Field(std::string const& name, Json::ValueType type, bool required = true);
34 
35  virtual bool Validate(Json::Value const& obj) const;
36 
37  protected:
38  std::string const& name() const noexcept;
39 
40  private:
41  std::string name_;
42  Json::ValueType type_;
43  bool required_;
44 };
45 
46 using Fields = std::vector<const Field*>;
47 
48 bool Validate(Json::Value const& obj, Fields const& fields);
49 
50 // Make sure a field in an object has the right value, optionally
51 // compare the strings case-sensitively.
52 class StringField : public Field {
53  public:
54  StringField(std::string const& name, std::string const& value,
55  bool case_sensitive = false, bool required = true);
56 
57  bool Validate(Json::Value const& obj) const override;
58 
59  private:
60  std::string value_;
61  bool case_sensitive_;
62 };
63 
64 // Compare to a sub-object in an array or object
65 class ObjectField : public Field {
66  public:
67  ObjectField(std::string const& name, Fields const& fields,
68  bool required = true);
69 
70  bool Validate(Json::Value const& obj) const override;
71 
72  private:
73  Fields fields_;
74 };
75 
76 // Make sure a field conforms to a certain set of values
77 // This doees case-insensitive comparisons.
78 class EnumField : public Field {
79  public:
80  using Values = std::vector<std::string>;
81 
82  EnumField(std::string const& name, Values const &values,
83  bool required = true);
84 
85  bool Validate(Json::Value const& obj) const override;
86 
87  private:
88  Values values_;
89 };
90 
91 // Make sure a field matches a specific value
92 template<typename T>
93 class ValueField : public Field {
94  static_assert(!std::is_same<std::string, T>::value,
95  "use StringField to compare strings");
96 
97  constexpr Json::ValueType GetType() {
98  static_assert(!(std::is_integral<T>::value &&
99  std::is_floating_point<T>::value),
100  "invalid type for ValueField");
101 
102  if (std::is_same<bool, T>::value) {
103  return Json::booleanValue;
104  } else if (std::is_floating_point<T>::value) {
105  // TODO(tfmorse): should probably warn the user this is a bad idea...
106  return Json::realValue;
107  } else if (std::is_integral<T>::value) {
108  return Json::intValue;
109  }
110  }
111 
112  public:
113  ValueField(std::string const& name, T const& value, bool required = true)
114  : Field(name, GetType(), required), value_(value)
115  { }
116 
117  bool Validate(Json::Value const& obj) const override {
118  if (!Field::Validate(obj)) {
119  return false;
120  }
121 
122  // Field is not required and not present
123  if (!obj.isMember(name())) {
124  return true;
125  }
126 
127  Json::Value wanted(value_);
128  Json::Value const& actual = obj[name()];
129 
130  if (wanted != actual) {
131  // Special case: jsoncpp will not decode integers as unsigned. Thus,
132  // if we're comparing against an unsigned int template type,
133  // we have to coerce them and compare :/
134  if (wanted.type() == Json::uintValue &&
135  actual.type() == Json::intValue &&
136  wanted.isConvertibleTo(Json::uintValue)) {
137  return wanted.asUInt() == actual.asUInt();
138  }
139 
140  return false;
141  }
142 
143  return true;
144  }
145 
146  private:
147  const T value_;
148 };
149 
152 
153 // Make sure a field is within the given range of values.
154 template<typename T>
155 class RangeField : public Field {
156  static_assert(std::is_arithmetic<T>::value, "Arithmetic type required");
157 
158  constexpr Json::ValueType GetType() {
159  return (std::is_floating_point<T>::value) ?
160  Json::realValue : Json::intValue;
161  }
162 
163  public:
164  RangeField(std::string const& name, T const& min, T const& max,
165  bool required = true)
166  : Field(name, GetType(), required), min_(min), max_(max)
167  { };
168 
169  bool Validate(Json::Value const& obj) const override {
170  if (!Field::Validate(obj)) {
171  return false;
172  }
173 
174  // Field is not required and not present
175  if (!obj.isMember(name())) {
176  return true;
177  }
178 
179  T val;
180  if (std::is_floating_point<T>::value) {
181  val = obj[name()].asFloat();
182  } else {
183  val = obj[name()].asInt();
184  }
185 
186  if (val < min_ || val > max_) {
187  return false;
188  }
189 
190  return true;
191  };
192 
193  private:
194  T min_, max_;
195 };
196 
197 using RangeFieldF = RangeField<float>; // helper type for floats
198 using RangeFieldI = RangeField<int>; // helper type for integers
199 
200 } // end namespace jsonloader
201 
202 #endif // JSONLOADER_VALIDATION_H_
203 
jsonloader::StringField::StringField
StringField(std::string const &name, std::string const &value, bool case_sensitive=false, bool required=true)
Definition: validation.cc:116
jsonloader::RangeField::RangeField
RangeField(std::string const &name, T const &min, T const &max, bool required=true)
Definition: validation.h:164
jsonloader::Field::Field
Field(std::string const &name, Json::ValueType type, bool required=true)
Definition: validation.cc:24
jsonloader::ObjectField::ObjectField
ObjectField(std::string const &name, Fields const &fields, bool required=true)
Definition: validation.cc:148
jsonloader::StringField
Definition: validation.h:52
jsonloader::Field::Validate
virtual bool Validate(Json::Value const &obj) const
Definition: validation.cc:53
jsonloader::ObjectField::Validate
bool Validate(Json::Value const &obj) const override
Definition: validation.cc:153
jsonloader::Field::name
std::string const & name() const noexcept
Definition: validation.cc:29
jsonloader::ObjectField
Definition: validation.h:65
jsonloader
Definition: command.h:28
gpio::Value
Value
Definition: GPIO.h:42
jsonloader::RangeField::Validate
bool Validate(Json::Value const &obj) const override
Definition: validation.h:169
jsonloader::EnumField::Validate
bool Validate(Json::Value const &obj) const override
Definition: validation.cc:178
jsonloader::RangeField
Definition: validation.h:155
jsonloader::Fields
std::vector< const Field * > Fields
Definition: validation.h:46
jsonloader::ValueField::Validate
bool Validate(Json::Value const &obj) const override
Definition: validation.h:117
jsonloader::ValueField
Definition: validation.h:93
jsonloader::EnumField::Values
std::vector< std::string > Values
Definition: validation.h:80
jsonloader::EnumField::EnumField
EnumField(std::string const &name, Values const &values, bool required=true)
Definition: validation.cc:173
jsonloader::ValueField::ValueField
ValueField(std::string const &name, T const &value, bool required=true)
Definition: validation.h:113
jsonloader::EnumField
Definition: validation.h:78
jsonloader::Field
Definition: validation.h:31
jsonloader::StringField::Validate
bool Validate(Json::Value const &obj) const override
Definition: validation.cc:122
jsonloader::Validate
bool Validate(Json::Value const &obj, Fields const &fields)
Definition: validation.cc:86