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

mendersoftware / mender / 1507843000

21 Oct 2024 08:08AM UTC coverage: 76.257% (-0.05%) from 76.305%
1507843000

push

gitlab-ci

web-flow
Merge pull request #1676 from kacf/size_fixes

MEN-7613: Size fixes

48 of 72 new or added lines in 18 files covered. (66.67%)

3 existing lines in 2 files now uncovered.

7313 of 9590 relevant lines covered (76.26%)

11280.06 hits per line

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

58.33
/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 <common/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
        EmptyError,
50
};
51

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

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

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

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

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

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

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

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

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

103
        Json() = default;
104

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

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

122
        ExpectedChildrenMap GetChildren() const;
123

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

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

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

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

165
        ExpectedSize GetArraySize() const;
166

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

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

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

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

189
string EscapeString(const string &str);
190

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

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

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

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

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

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

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

236
#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