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

mendersoftware / mender / 1056236935

31 Oct 2023 12:52PM UTC coverage: 80.126% (-0.06%) from 80.182%
1056236935

push

gitlab-ci

lluiscampos
fix: Serialize identity keys as single strings when possible

Use the same logic than for inventory keys: if the vector has one
element serialize as string, else submit as a list of strings.

Changelog: None
Ticket: MEN-6813

Signed-off-by: Lluis Campos <lluis.campos@northern.tech>

25 of 25 new or added lines in 3 files covered. (100.0%)

6886 of 8594 relevant lines covered (80.13%)

9361.12 hits per line

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

81.74
/src/common/json/platform/nlohmann/nlohmann_json.cpp
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
#include <common/json.hpp>
16

17
#include <fstream>
18
#include <map>
19
#include <string>
20

21
#include <nlohmann/json.hpp>
22

23
#include <common/io.hpp>
24

25
using njson = nlohmann::json;
26
using namespace std;
27
namespace expected = mender::common::expected;
28
namespace error = mender::common::error;
29
namespace io = mender::common::io;
30

31
namespace mender::common::json {
32

33
static error::Error GetErrorFromException(exception &e, const string &context_message) {
70✔
34
        try {
35
                // Trick to delegate the exception into the handlers below: Rethrow the exception
36
                // (Lippincott Function). The `e` argument is not actually needed, but included for
37
                // clarity.
38
                throw;
70✔
39
        } catch (njson::parse_error &e) {
70✔
40
                return MakeError(JsonErrorCode::ParseError, context_message + ": " + e.what());
134✔
41
        } catch (njson::type_error &e) {
3✔
42
                return MakeError(JsonErrorCode::TypeError, context_message + ": " + e.what());
6✔
43
        } catch (system_error &e) {
×
44
                return error::Error(e.code().default_error_condition(), context_message + ": " + e.what());
×
45
        } catch (exception &e) {
×
46
                return error::MakeError(error::GenericError, context_message + ": " + e.what());
×
47
        }
48
}
49

50
ExpectedJson LoadFromFile(string file_path) {
240✔
51
        ifstream f;
480✔
52
        errno = 0;
240✔
53
        f.open(file_path);
240✔
54
        if (!f) {
240✔
55
                int io_errno = errno;
220✔
56
                auto err = error::Error(
57
                        std::generic_category().default_error_condition(io_errno),
440✔
58
                        "Failed to open '" + file_path + "': " + strerror(io_errno));
440✔
59
                return expected::unexpected(err);
440✔
60
        }
61

62
        try {
63
                njson parsed = njson::parse(f);
38✔
64
                Json j = Json(parsed);
18✔
65
                return ExpectedJson(j);
18✔
66
        } catch (exception &e) {
2✔
67
                return expected::unexpected(
2✔
68
                        GetErrorFromException(e, "Failed to parse '" + file_path + "'"));
6✔
69
        }
70
}
71

72
ExpectedJson Load(string json_str) {
225✔
73
        try {
74
                njson parsed = njson::parse(json_str);
445✔
75
                Json j = Json(parsed);
220✔
76
                return ExpectedJson(j);
220✔
77
        } catch (exception &e) {
5✔
78
                return expected::unexpected(GetErrorFromException(e, "Failed to parse '" + json_str + "'"));
15✔
79
        }
80
}
81

82
ExpectedJson Load(istream &str) {
485✔
83
        try {
84
                njson parsed = njson::parse(str);
910✔
85
                Json j = Json(parsed);
425✔
86
                return ExpectedJson(j);
425✔
87
        } catch (exception &e) {
120✔
88
                return expected::unexpected(GetErrorFromException(e, "Failed to parse JSON from stream"));
180✔
89
        }
90
}
91

92
ExpectedJson Load(io::Reader &reader) {
481✔
93
        auto str_ptr = reader.GetStream();
962✔
94
        try {
95
                return Load(*str_ptr);
481✔
96
        } catch (exception &e) {
×
97
                return expected::unexpected(GetErrorFromException(e, "Failed to parse JSON from stream"));
×
98
        }
99
}
100

101
string Json::Dump(const int indent) const {
279✔
102
        return this->n_json.dump(indent);
279✔
103
}
104

105
ExpectedJson Json::Get(const char *child_key) const {
3,661✔
106
        if (!this->n_json.is_object()) {
3,661✔
107
                auto err = MakeError(
108
                        JsonErrorCode::TypeError, "Invalid JSON type to get '" + string(child_key) + "' from");
×
109
                return expected::unexpected(err);
×
110
        }
111

112
        bool contains = this->n_json.contains(child_key);
3,661✔
113
        if (!contains) {
3,661✔
114
                auto err =
115
                        MakeError(JsonErrorCode::KeyError, "Key '" + string(child_key) + "' doesn't exist");
1,518✔
116
                return expected::unexpected(err);
1,518✔
117
        }
118

119
        njson n_json = this->n_json[child_key];
5,804✔
120
        Json j = Json(n_json);
2,902✔
121
        return j;
2,902✔
122
}
123

124
ExpectedJson Json::Get(const size_t idx) const {
735✔
125
        if (!this->n_json.is_array()) {
735✔
126
                auto err = MakeError(
127
                        JsonErrorCode::TypeError,
128
                        "Invalid JSON type to get item at index " + to_string(idx) + " from");
×
129
                return expected::unexpected(err);
×
130
        }
131

132
        if (this->n_json.size() <= idx) {
735✔
133
                auto err =
134
                        MakeError(JsonErrorCode::IndexError, "Index " + to_string(idx) + " out of range");
2✔
135
                return expected::unexpected(err);
2✔
136
        }
137

138
        njson n_json = this->n_json[idx];
734✔
139
        return Json(n_json);
2,202✔
140
}
141

142
ExpectedChildrenMap Json::GetChildren() const {
276✔
143
        if (!this->IsObject()) {
276✔
144
                auto err = MakeError(JsonErrorCode::TypeError, "Invalid JSON type to get children from");
×
145
                return expected::unexpected(err);
×
146
        }
147

148
        ChildrenMap ret {};
149
        for (const auto &item : this->n_json.items()) {
946✔
150
                ret[item.key()] = Json(item.value());
1,182✔
151
        }
152
        return ExpectedChildrenMap(ret);
276✔
153
}
154

155
bool Json::IsObject() const {
199✔
156
        return this->n_json.is_object();
199✔
157
}
158

159
bool Json::IsArray() const {
588✔
160
        return this->n_json.is_array();
588✔
161
}
162

163
bool Json::IsString() const {
431✔
164
        return this->n_json.is_string();
431✔
165
}
166

167
bool Json::IsInt() const {
2✔
168
        return this->n_json.is_number_integer();
2✔
169
}
170

171
bool Json::IsNumber() const {
8✔
172
        return this->n_json.is_number();
8✔
173
}
174

175
bool Json::IsDouble() const {
×
176
        return this->n_json.is_number_float();
×
177
}
178

179
bool Json::IsBool() const {
2✔
180
        return this->n_json.is_boolean();
2✔
181
}
182

183
bool Json::IsNull() const {
148✔
184
        return this->n_json.is_null();
148✔
185
}
186

187
ExpectedString Json::GetString() const {
2,045✔
188
        try {
189
                string s = this->n_json.get<string>();
2,045✔
190
                return s;
2,045✔
191
        } catch (exception &e) {
×
192
                return expected::unexpected(GetErrorFromException(e, "Type mismatch when getting string"));
×
193
        }
194
}
195

196
ExpectedInt64 Json::GetInt() const {
280✔
197
        try {
198
                int64_t s {this->n_json.get<int64_t>()};
280✔
199
                return s;
200
        } catch (exception &e) {
2✔
201
                return expected::unexpected(GetErrorFromException(e, "Type mismatch when getting int"));
3✔
202
        }
203
}
204

205
ExpectedDouble Json::GetDouble() const {
4✔
206
        try {
207
                return this->n_json.get<double>();
4✔
208
        } catch (exception &e) {
×
209
                return expected::unexpected(GetErrorFromException(e, "Type mismatch when getting double"));
×
210
        }
211
}
212

213
ExpectedBool Json::GetBool() const {
91✔
214
        try {
215
                bool s = this->n_json.get<bool>();
91✔
216
                return s;
217
        } catch (exception &e) {
4✔
218
                return expected::unexpected(GetErrorFromException(e, "Type mismatch when getting bool"));
6✔
219
        }
220
}
221

222
ExpectedSize Json::GetArraySize() const {
599✔
223
        if (!this->n_json.is_array()) {
599✔
224
                auto err = MakeError(JsonErrorCode::TypeError, "Not a JSON array");
4✔
225
                return expected::unexpected(err);
4✔
226
        } else {
227
                return this->n_json.size();
597✔
228
        }
229
}
230

231

232
template <>
233
ExpectedString Dump(unordered_map<string, vector<string>> std_map) {
×
234
        njson map_json(std_map);
×
235
        return map_json.dump();
×
236
}
237

238
template <>
239
ExpectedString Dump(unordered_map<string, string> std_map) {
6✔
240
        njson map_json(std_map);
6✔
241
        return map_json.dump();
12✔
242
}
243

244

245
} // namespace mender::common::json
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

© 2025 Coveralls, Inc