• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 1582712564

10 Dec 2024 06:44PM UTC coverage: 79.706% (-0.2%) from 79.882%
1582712564

push

gitlab-ci

web-flow
Merge pull request #1713 from lluiscampos/4.0.x-MEN-7810-fix-and-changelog

4.0.x: MEN-7810 fix and changelog

11 of 11 new or added lines in 1 file covered. (100.0%)

43 existing lines in 10 files now uncovered.

7207 of 9042 relevant lines covered (79.71%)

12100.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/common/json.hpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#ifndef MENDER_COMMON_JSON_HPP
16
#define MENDER_COMMON_JSON_HPP
17

18
#include <config.h>
19

20
#include <string>
21
#include <map>
22
#include <unordered_map>
23

24
#include <common/common.hpp>
25
#include <common/error.hpp>
26
#include <common/expected.hpp>
27
#include <common/io.hpp>
28

29
#ifdef MENDER_USE_NLOHMANN_JSON
30
#include <nlohmann/json.hpp>
31
#endif
32

33
namespace mender {
34
namespace common {
35
namespace json {
36

37
using namespace std;
38

39
namespace error = mender::common::error;
40
namespace io = mender::common::io;
41
namespace common = mender::common;
42

43
enum JsonErrorCode {
44
        NoError = 0,
45
        ParseError,
46
        KeyError,
47
        IndexError,
48
        TypeError,
49
};
50

51
class CaseInsensitiveLess {
52
public:
53
        bool operator()(const string &lhs, const string &rhs) const {
54
                return common::StringToLower(lhs) < common::StringToLower(rhs);
55
        }
56
};
57

58
template <class Key, class T, class IgnoredLess, class Allocator = allocator<pair<const Key, T>>>
59
class CaseInsensitiveMap : public map<const Key, T, CaseInsensitiveLess, Allocator> {
×
60
public:
61
        using CaseInsensitiveMapType = map<const Key, T, CaseInsensitiveLess, Allocator>;
62

63
        CaseInsensitiveMap() :
64
                CaseInsensitiveMapType() {
65
        }
66

67
        template <class InputIterator>
68
        CaseInsensitiveMap(
69
                InputIterator first,
70
                InputIterator last,
71
                const CaseInsensitiveLess &comp = CaseInsensitiveLess(),
72
                const Allocator &alloc = Allocator()) :
73
                CaseInsensitiveMapType(first, last, comp, alloc) {
74
        }
75
};
76

77
#ifdef MENDER_USE_NLOHMANN_JSON
78
using insensitive_json = nlohmann::basic_json<CaseInsensitiveMap>;
79
#endif
80

81
class JsonErrorCategoryClass : public error_category {
82
public:
83
        const char *name() const noexcept override;
84
        string message(int code) const override;
85
};
86
extern const JsonErrorCategoryClass JsonErrorCategory;
87

88
error::Error MakeError(JsonErrorCode code, const string &msg);
89

90
using ExpectedString = mender::common::expected::ExpectedString;
91
using ExpectedInt64 = mender::common::expected::ExpectedInt64;
92
using ExpectedDouble = mender::common::expected::ExpectedDouble;
93
using ExpectedBool = mender::common::expected::ExpectedBool;
94
using ExpectedSize = mender::common::expected::ExpectedSize;
95

UNCOV
96
class Json {
×
97
public:
98
        using ExpectedJson = expected::expected<Json, error::Error>;
99
        using ChildrenMap = map<string, Json>;
100
        using ExpectedChildrenMap = expected::expected<ChildrenMap, error::Error>;
101

102
        Json() = default;
103

104
        string Dump(const int indent = 2) const;
105

106
        ExpectedJson Get(const char *child_key) const;
107
        ExpectedJson operator[](const char *child_key) const {
108
                return this->Get(child_key);
109
        }
110
        ExpectedJson Get(const string &child_key) const {
111
                return this->Get(child_key.data());
112
        }
113
        ExpectedJson operator[](const string &child_key) const {
114
                return this->Get(child_key.data());
115
        }
116
        ExpectedJson Get(const size_t idx) const;
117
        ExpectedJson operator[](const size_t idx) const {
118
                return this->Get(idx);
119
        }
120

121
        ExpectedChildrenMap GetChildren() const;
122

123
        bool IsObject() const;
124
        bool IsArray() const;
125
        bool IsString() const;
126
        bool IsInt64() const;
127
        bool IsNumber() const;
128
        bool IsDouble() const;
129
        bool IsBool() const;
130
        bool IsNull() const;
131

132
        ExpectedString GetString() const;
133
        ExpectedInt64 GetInt64() const;
134
        ExpectedDouble GetDouble() const;
135
        ExpectedBool GetBool() const;
136

137
        // Defined in cpp file as specialized templates.
138
        template <typename T>
139
        typename enable_if<
140
                not is_integral<T>::value or is_same<T, int64_t>::value,
141
                expected::expected<T, error::Error>>::type
142
        Get() const;
143

144
        // Use this as a catch-all for all integral types besides int64_t. It then automates the
145
        // process of checking whether it fits in the requested data type.
146
        template <typename T>
147
        typename enable_if<
148
                is_integral<T>::value and not is_same<T, int64_t>::value,
149
                expected::expected<T, error::Error>>::type
150
        Get() const {
151
                auto num = Get<int64_t>();
152
                if (!num) {
153
                        return expected::unexpected(num.error());
154
                }
155
                if (num.value() < numeric_limits<T>::min() or num.value() > numeric_limits<T>::max()) {
156
                        return expected::unexpected(error::Error(
157
                                make_error_condition(errc::result_out_of_range),
158
                                "Json::Get(): Number " + to_string(num.value())
159
                                        + " does not fit in requested data type"));
160
                }
161
                return static_cast<T>(num.value());
162
        }
163

164
        ExpectedSize GetArraySize() const;
165

166
        friend ExpectedJson LoadFromFile(string file_path);
167
        friend ExpectedJson Load(string json_str);
168
        friend ExpectedJson Load(istream &str);
169
        friend ExpectedJson Load(io::Reader &reader);
170

171
private:
172
#ifdef MENDER_USE_NLOHMANN_JSON
173
        insensitive_json n_json;
174
        Json(insensitive_json n_json) :
175
                n_json(n_json) {};
176
#endif
177
};
178

179
using ExpectedJson = expected::expected<Json, error::Error>;
180
using ChildrenMap = map<string, Json>;
181
using ExpectedChildrenMap = expected::expected<ChildrenMap, error::Error>;
182

183
ExpectedJson LoadFromFile(string file_path);
184
ExpectedJson Load(string json_str);
185
ExpectedJson Load(istream &str);
186
ExpectedJson Load(io::Reader &reader);
187

188
string EscapeString(const string &str);
189

190
using ExpectedStringVector = expected::ExpectedStringVector;
191
using KeyValueMap = unordered_map<string, string>;
192
using ExpectedKeyValueMap = expected::expected<KeyValueMap, error::Error>;
193

194
ExpectedStringVector ToStringVector(const json::Json &j);
195
ExpectedKeyValueMap ToKeyValueMap(const json::Json &j);
196
ExpectedString ToString(const json::Json &j);
197
ExpectedInt64 ToInt64(const json::Json &j);
198
ExpectedBool ToBool(const json::Json &j);
199

200
template <typename T>
201
expected::expected<T, error::Error> To(const json::Json &j) {
202
        return j.Get<T>();
203
}
204

205
// Template which we specialize for the given type in the platform dependent implementation
206
template <typename DataType>
207
ExpectedString Dump(DataType);
208

209
enum class MissingOk {
210
        No,
211
        Yes,
212
};
213

214
template <typename T>
215
expected::expected<T, error::Error> Get(
216
        const json::Json &json, const string &key, MissingOk missing_ok) {
217
        auto exp_value = json.Get(key);
218
        if (!exp_value) {
219
                if (missing_ok == MissingOk::Yes
220
                        && exp_value.error().code != json::MakeError(json::KeyError, "").code) {
221
                        return T();
222
                } else {
223
                        auto err = exp_value.error();
224
                        err.message += ": Could not get `" + key + "` from json data";
225
                        return expected::unexpected(err);
226
                }
227
        }
228
        return exp_value.value().Get<T>();
229
}
230

231
} // namespace json
232
} // namespace common
233
} // namespace mender
234

235
#endif // MENDER_COMMON_JSON_HPP
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc