$darkmode
error.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Robert Bosch GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * SPDX-License-Identifier: Apache-2.0
17  */
22 #pragma once
23 
24 #include <stdexcept> // for exception
25 #include <string> // for string
26 #include <utility> // for move
27 
28 #include <fmt/format.h> // for format
29 
30 #include <fable/conf.hpp>
31 #include <fable/fable_fwd.hpp>
32 #include <fable/json.hpp>
33 
34 namespace fable {
35 
36 class Error;
37 class ConfError;
38 class SchemaError;
39 
40 class Error : public std::exception {
41  std::string message_;
42 
43  public:
44  Error() = delete;
45  Error(const Error&) = default;
46  Error(Error&&) = default;
47  Error& operator=(const Error&) = default;
48  Error& operator=(Error&&) = default;
49  ~Error() noexcept override = default;
50 
51  Error(std::string what) : message_(std::move(what)) {}
52 
53  template <typename... Args>
54  explicit Error(std::string_view format, Args&&... args)
55  : message_(fmt::format(fmt::runtime(format), std::forward<Args>(args)...)) {}
56 
57  [[nodiscard]] const char* what() const noexcept override { return message_.c_str(); }
58 };
59 
60 class ConfError : public Error {
61  Conf data_;
62 
63  public:
64  ConfError() = delete;
65  ConfError(const ConfError&) = default;
66  ConfError(ConfError&&) = default;
67  ConfError& operator=(const ConfError&) = default;
68  ConfError& operator=(ConfError&&) = default;
69  ~ConfError() noexcept override = default;
70 
71  ConfError(Conf conf, const std::string& msg) : Error(msg), data_(std::move(conf)) {}
72  ConfError(Conf conf, const char* msg) : Error(msg), data_(std::move(conf)) {}
73 
74  template <typename... Args>
75  ConfError(Conf conf, std::string_view format, Args&&... args)
76  : Error(format, std::forward<Args>(args)...), data_(std::move(conf)) {}
77 
78  [[nodiscard]] std::string file() const noexcept { return data_.file(); }
79  [[nodiscard]] std::string root() const noexcept { return data_.root(); }
80  [[nodiscard]] const Conf& conf() const noexcept { return data_; }
81  [[nodiscard]] const Json& data() const noexcept { return *data_; }
82 
83  [[nodiscard]] virtual std::string message() const {
84  return fmt::format("{}:{}: {}", file(), root(), this->what());
85  }
86 
87  friend SchemaError;
88  friend void to_json(Json& jref, const ConfError& err) {
89  jref = Json{
90  {"error", err.what()}, {"file", err.file()}, {"root", err.root()},
91  {"data", err.data()}, {"message", err.message()},
92  };
93  }
94 };
95 
96 namespace error {
97 
98 inline ConfError MissingProperty(const Conf& conf, const std::string& key) {
99  return ConfError{conf, "required property missing: {}", key};
100 }
101 
102 inline ConfError MissingProperty(const Conf& conf, const JsonPointer& ptr) {
103  return ConfError{conf, "required property missing: {}", ptr.to_string()};
104 }
105 
106 inline ConfError UnexpectedProperty(const Conf& conf, const std::string& key) {
107  return ConfError{conf, "unexpected property present: {}", key};
108 }
109 
110 inline ConfError UnexpectedProperty(const Conf& conf, const JsonPointer& ptr) {
111  return ConfError{conf, "unexpected property present: {}", ptr.to_string()};
112 }
113 
114 inline ConfError WrongType(const Conf& conf, JsonType type) {
115  std::string want = to_string(type);
116  std::string got = to_string(conf->type());
117  return ConfError{conf, "property must have type {}, got {}", want, got};
118 }
119 
120 inline ConfError WrongType(const Conf& conf, const std::string& key, JsonType expected) {
121  std::string want = to_string(expected);
122  std::string got = to_string((*conf)[key].type());
123  return ConfError{conf, "property '{}' must have type {}, got {}", key, want, got};
124 }
125 
126 inline ConfError WrongType(const Conf& conf, const JsonPointer& ptr, JsonType expected) {
127  std::string want = to_string(expected);
128  std::string got = to_string((*conf)[ptr].type());
129  return ConfError{conf, "property '{}' must have type {}, got {}", ptr.to_string(), want, got};
130 }
131 
132 inline ConfError WrongType(const Conf& conf, const std::string& key) {
133  std::string got = to_string((*conf)[key].type());
134  return ConfError{conf, "property '{}' has wrong type {}", key, got};
135 }
136 
137 inline ConfError WrongType(const Conf& conf, const JsonPointer& ptr) {
138  std::string got = to_string((*conf)[ptr].type());
139  return ConfError{conf, "property '{}' has wrong type {}", ptr.to_string(), got};
140 }
141 
142 inline ConfError WrongType(const Conf& conf) {
143  std::string got = to_string(conf->type());
144  return ConfError{conf, "property has wrong type {}", got};
145 }
146 
147 } // namespace error
148 
149 class SchemaError : public ConfError {
150  Json schema_;
151  Json context_;
152 
153  public: // Constructors
154  SchemaError() = delete;
155  SchemaError(const SchemaError&) = default;
156  SchemaError(SchemaError&&) = default;
157  SchemaError& operator=(const SchemaError&) = default;
158  SchemaError& operator=(SchemaError&&) = default;
159  ~SchemaError() noexcept override = default;
160 
167  SchemaError(const ConfError& err, Json schema) : ConfError(err), schema_(std::move(schema)) {}
168 
177  template <typename... Args>
178  SchemaError(const Conf& conf, Json schema, std::string_view format, Args&&... args)
179  : ConfError(conf, format, std::forward<Args>(args)...), schema_(std::move(schema)) {}
180 
181  [[nodiscard]] const Json& schema() const { return schema_; }
182  [[nodiscard]] const Json& context() const { return context_; }
183 
184  SchemaError& with_context(Json ctx) {
185  context_ = std::move(ctx);
186  return *this;
187  }
188 
189  friend void to_json(Json& json, const SchemaError& err) {
190  json = Json{
191  {"error", err.what()}, {"file", err.file()}, {"root", err.root()},
192  {"data", err.data()}, {"message", err.message()}, {"schema", err.schema_},
193  };
194  if (!err.context_.empty()) {
195  json["context"] = err.context_;
196  }
197  }
198 };
199 
200 } // namespace fable
Definition: error.hpp:60
Definition: conf.hpp:82
std::string root() const
Definition: conf.hpp:154
const std::string & file() const
Definition: conf.hpp:105
Definition: error.hpp:40
Definition: error.hpp:149
SchemaError(const ConfError &err, Json schema)
Definition: error.hpp:167
SchemaError(const Conf &conf, Json schema, std::string_view format, Args &&... args)
Definition: error.hpp:178
nlohmann::json Json
Definition: fable_fwd.hpp:35