ifw-daq  3.0.0-pre2
IFW Data Acquisition modules
testJson.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_ocm_fits_test
4  * @copyright 2022 ESO - European Southern Observatory
5  *
6  * @brief Unit tests for json handling.
7  */
8 
9 #include <gtest/gtest.h>
10 #include <gmock/gmock.h>
11 
12 #include <nlohmann/json.hpp>
13 #include <ostream>
14 
15 #include <daq/fits/json.hpp>
16 
17 using namespace daq::fits;
18 
19 class TestJson : public ::testing::Test {
20 public:
21 };
22 
23 TEST_F(TestJson, ParseInvalidJsonThrowsNlohmannException) {
24  // Setup
25  auto trailing_comma = R"(
26  [
27  {
28  "type": "valueKeyword",
29  "name": "STRKW",
30  "value": "VALUE STRING"
31  },
32  ]
33  )";
34 
35  // Test
36  EXPECT_THROW(ParseJsonKeywords(trailing_comma), nlohmann::json::exception);
37 }
38 
39 TEST_F(TestJson, ParseValueKeywords) {
40  // Setup
41  auto keywords_str = R"(
42  [
43  {
44  "type": "valueKeyword",
45  "name": "STRKW",
46  "value": "VALUE STRING"
47  },
48  {
49  "type": "valueKeyword",
50  "name": "BOOLKW",
51  "value": true
52  },
53  {
54  "type": "valueKeyword",
55  "name": "INTMIN",
56  "value": -9223372036854775807
57  },
58  {
59  "type": "valueKeyword",
60  "name": "INTMAX",
61  "value": 9223372036854775807
62  },
63  {
64  "type": "valueKeyword",
65  "name": "UINTMAX",
66  "value": 18446744073709551615
67  },
68  {
69  "type": "valueKeyword",
70  "name": "FLOATMIN",
71  "value": -1.79769313486231e+308
72  },
73  {
74  "type": "valueKeyword",
75  "name": "FLOATMAX",
76  "value": 1.79769313486231e+308
77  }
78  ]
79  )";
80 
81  // Test
82  std::vector<KeywordVariant> parsed = ParseJsonKeywords(keywords_str);
83  ASSERT_EQ(7u, parsed.size());
84  for (auto const& kw_var : parsed) {
85  ASSERT_TRUE(std::holds_alternative<ValueKeyword>(kw_var));
86  }
87 
88  {
89  ValueKeyword kw = std::get<ValueKeyword>(parsed[0]);
90  EXPECT_EQ(ValueKeyword("STRKW", std::string("VALUE STRING"), std::nullopt), kw);
91  }
92  {
93  ValueKeyword kw = std::get<ValueKeyword>(parsed[1]);
94  EXPECT_EQ(ValueKeyword("BOOLKW", true, std::nullopt), kw);
95  }
96  {
97  ValueKeyword kw = std::get<ValueKeyword>(parsed[2]);
98  EXPECT_EQ(ValueKeyword("INTMIN", int64_t(-9223372036854775807), std::nullopt), kw);
99  }
100  {
101  ValueKeyword kw = std::get<ValueKeyword>(parsed[3]);
102  EXPECT_EQ(ValueKeyword("INTMAX", uint64_t(9223372036854775807), std::nullopt), kw);
103  }
104  {
105  ValueKeyword kw = std::get<ValueKeyword>(parsed[4]);
106  EXPECT_EQ(ValueKeyword("UINTMAX", 18446744073709551615u, std::nullopt), kw);
107  }
108  {
109  ValueKeyword kw = std::get<ValueKeyword>(parsed[5]);
110  EXPECT_EQ(ValueKeyword("FLOATMIN", -1.79769313486231e+308, std::nullopt), kw);
111  }
112  {
113  ValueKeyword kw = std::get<ValueKeyword>(parsed[6]);
114  EXPECT_EQ(ValueKeyword("FLOATMAX", 1.79769313486231e+308, std::nullopt), kw);
115  }
116 }
117 
118 TEST_F(TestJson, ParseEsoKeywords) {
119  // Setup
120  auto keywords_str = R"(
121  [
122  {
123  "type": "esoKeyword",
124  "name": "STRKW",
125  "value": "VALUE STRING"
126  },
127  {
128  "type": "esoKeyword",
129  "name": "BOOLKW",
130  "value": true
131  },
132  {
133  "type": "esoKeyword",
134  "name": "INTMIN",
135  "value": -9223372036854775807
136  },
137  {
138  "type": "esoKeyword",
139  "name": "INTMAX",
140  "value": 9223372036854775807
141  },
142  {
143  "type": "esoKeyword",
144  "name": "UINTMAX",
145  "value": 18446744073709551615
146  },
147  {
148  "type": "esoKeyword",
149  "name": "FLOATMIN",
150  "value": -1.79769313486231e+308
151  },
152  {
153  "type": "esoKeyword",
154  "name": "FLOATMAX",
155  "value": 1.79769313486231e+308
156  },
157  {
158  "type": "esoKeyword",
159  "name": "KW WITH SPACE",
160  "value": "spaces"
161  }
162  ]
163  )";
164 
165  // Test
166  std::vector<KeywordVariant> parsed = ParseJsonKeywords(keywords_str);
167  ASSERT_EQ(8u, parsed.size());
168  for (auto const& kw_var : parsed) {
169  ASSERT_TRUE(std::holds_alternative<EsoKeyword>(kw_var));
170  }
171 
172  {
173  EsoKeyword kw = std::get<EsoKeyword>(parsed[0]);
174  EXPECT_EQ(EsoKeyword("STRKW", std::string("VALUE STRING"), std::nullopt), kw);
175  }
176  {
177  EsoKeyword kw = std::get<EsoKeyword>(parsed[1]);
178  EXPECT_EQ(EsoKeyword("BOOLKW", true, std::nullopt), kw);
179  }
180  {
181  EsoKeyword kw = std::get<EsoKeyword>(parsed[2]);
182  EXPECT_EQ(EsoKeyword("INTMIN", int64_t(-9223372036854775807), std::nullopt), kw);
183  }
184  {
185  EsoKeyword kw = std::get<EsoKeyword>(parsed[3]);
186  EXPECT_EQ(EsoKeyword("INTMAX", uint64_t(9223372036854775807), std::nullopt), kw);
187  }
188  {
189  EsoKeyword kw = std::get<EsoKeyword>(parsed[4]);
190  EXPECT_EQ(EsoKeyword("UINTMAX", 18446744073709551615u, std::nullopt), kw);
191  }
192  {
193  EsoKeyword kw = std::get<EsoKeyword>(parsed[5]);
194  EXPECT_EQ(EsoKeyword("FLOATMIN", -1.79769313486231e+308, std::nullopt), kw);
195  }
196  {
197  EsoKeyword kw = std::get<EsoKeyword>(parsed[6]);
198  EXPECT_EQ(EsoKeyword("FLOATMAX", 1.79769313486231e+308, std::nullopt), kw);
199  }
200  {
201  EsoKeyword kw = std::get<EsoKeyword>(parsed[7]);
202  EXPECT_EQ(EsoKeyword("KW WITH SPACE", "spaces", std::nullopt), kw);
203  }
204 }
205 
206 TEST_F(TestJson, ParseLiteralKeyword) {
207  // Setup
208  auto keywords_str = R"(
209  [
210  {
211  "type": "literalKeyword",
212  "value": "SIMPLE = T / Standard FITS"
213  },
214  {
215  "type": "literalKeyword",
216  "value": "OBJECT = 'target.cat' / Original target."
217  },
218  {
219  "type": "literalKeyword",
220  "value": "HIERARCH ESO KW = T / Comment"
221  }
222  ]
223  )";
224 
225  // Test
226  std::vector<KeywordVariant> parsed = ParseJsonKeywords(keywords_str);
227  ASSERT_EQ(3u, parsed.size());
228  for (auto const& kw_var : parsed) {
229  ASSERT_TRUE(std::holds_alternative<LiteralKeyword>(kw_var));
230  }
231 
232  {
233  LiteralKeyword kw = std::get<LiteralKeyword>(parsed[0]);
234  EXPECT_EQ(LiteralKeyword("SIMPLE = T / Standard FITS"), kw);
235  }
236  {
237  LiteralKeyword kw = std::get<LiteralKeyword>(parsed[1]);
238  EXPECT_EQ(LiteralKeyword("OBJECT = 'target.cat' / Original target."), kw);
239  EXPECT_EQ("OBJECT = 'target.cat' / Original target.", kw.GetRecord());
240  }
241  {
242  LiteralKeyword kw = std::get<LiteralKeyword>(parsed[2]);
243  EXPECT_EQ(LiteralKeyword("HIERARCH ESO KW = T / Comment"), kw);
244  }
245 }
246 
247 TEST_F(TestJson, ParseOptionalKeywordComment) {
248  // Setup
249  auto keywords_str = R"(
250  [
251  {
252  "type": "valueKeyword",
253  "name": "STRKW1",
254  "value": "VALUE STRING",
255  "comment": "this is a comment"
256  },
257  {
258  "type": "esoKeyword",
259  "name": "STRKW2",
260  "value": "VALUE STRING",
261  "comment": "this is also a comment"
262  }
263  ]
264  )";
265 
266  // Test
267  std::vector<KeywordVariant> parsed = ParseJsonKeywords(keywords_str);
268  ASSERT_EQ(2u, parsed.size());
269  ASSERT_TRUE(std::holds_alternative<ValueKeyword>(parsed[0]));
270  ASSERT_TRUE(std::holds_alternative<EsoKeyword>(parsed[1]));
271 
272  {
273  ValueKeyword kw = std::get<ValueKeyword>(parsed[0]);
274  EXPECT_EQ(ValueKeyword("STRKW1", std::string("VALUE STRING"), "this is a comment"), kw);
275  }
276  {
277  EsoKeyword kw = std::get<EsoKeyword>(parsed[1]);
278  EXPECT_EQ(EsoKeyword("STRKW2", std::string("VALUE STRING"), "this is also a comment"), kw);
279  }
280 }
281 
282 TEST_F(TestJson, ParseEmptyArray) {
283  // Setup
284  auto keywords_str = R"(
285  []
286  )";
287  auto res = ParseJsonKeywords(keywords_str);
288  EXPECT_EQ(0u, res.size());
289 }
290 
291 TEST_F(TestJson, ParseFailsIfNotAnArray) {
292  // Setup
293  auto keywords_str = R"(
294  {
295  "type": "valueKeyword",
296  "name": "FLOATMAX",
297  "value": 1.79769313486231e+308
298  }
299  )";
300  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
301 }
302 
303 TEST_F(TestJson, ParseFailsIfNotAnObjectInArray) {
304  // Setup
305  auto keywords_str = R"(
306  [
307  1,
308  [],
309  "",
310  null
311  ]
312  )";
313  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
314 }
315 
316 TEST_F(TestJson, ParseFailsIfObjectMissTypeProperty) {
317  // Setup
318  auto keywords_str = R"(
319  [
320  {
321  "name": "FLOATMAX",
322  "value": "value"
323  }
324  ]
325  )";
326  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
327 }
328 
329 TEST_F(TestJson, ParseFailsIfObjectHasUnknownTypeProperty) {
330  // Setup
331  auto keywords_str = R"(
332  [
333  {
334  "type": "unknown",
335  "name": "FLOATMAX",
336  "value": 1.79769313486231e+308
337  }
338  ]
339  )";
340  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
341 }
342 
343 TEST_F(TestJson, ParseFailsIfTypeIsNotString) {
344  // Setup
345  auto keywords_str = R"(
346  [
347  {
348  "type": true,
349  "name": "FLOATMAX",
350  "value": 1.79769313486231e+308
351  }
352  ]
353  )";
354  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
355 }
356 
357 TEST_F(TestJson, ParseFailsIfObjectMissNameProperty) {
358  // Setup
359  auto keywords_str = R"(
360  [
361  {
362  "type": "valueKeyword",
363  "value": 1.79769313486231e+308
364  }
365  ]
366  )";
367  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
368 }
369 
370 TEST_F(TestJson, ParseFailsIfObjectMissValue) {
371  // Setup
372  auto keywords_str = R"(
373  [
374  {
375  "type": "valueKeyword",
376  "name": "FLOATMAX"
377  }
378  ]
379  )";
380  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
381 }
382 
383 TEST_F(TestJson, ParseFailsIfLiteralKeywordMissValue) {
384  // Setup
385  auto keywords_str = R"(
386  [
387  {
388  "type": "literalKeyword"
389  }
390  ]
391  )";
392  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
393 }
394 
395 TEST_F(TestJson, ParseFailsIfLiteralKeywordValueIsNotString) {
396  // Setup
397  auto keywords_str = R"(
398  [
399  {
400  "type": "literalKeyword",
401  "value": null
402  }
403  ]
404  )";
405  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
406 }
407 
408 TEST_F(TestJson, ParseFailsIfLiteralKeywordValueTooLong) {
409  // Setup
410  auto keywords_str = R"(
411  [
412  {
413  "type": "literalKeyword",
414  "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0"
415  }
416  ]
417  )";
418  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
419 }
420 
421 TEST_F(TestJson, ParseFailsIfObjectHasUnsupportedValueType) {
422  // Setup
423  auto keywords_str = R"(
424  [
425  {
426  "type": "valueKeyword",
427  "name": "NAME",
428  "value": {"foo": true}
429  }
430  ]
431  )";
432  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
433 }
434 
435 TEST_F(TestJson, ParseFailsIfNameIsNotString) {
436  // Setup
437  auto keywords_str = R"(
438  [
439  {
440  "type": "valueKeyword",
441  "name": 1.0,
442  "value": "value"
443  }
444  ]
445  )";
446  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
447 }
448 
449 TEST_F(TestJson, ParseFailsIfObjectHasCommentThatIsNotString) {
450  // Setup
451  auto keywords_str = R"(
452  [
453  {
454  "type": "valueKeyword",
455  "name": "NAME",
456  "value": "value",
457  "comment": 1.0
458  }
459  ]
460  )";
461  EXPECT_THROW(ParseJsonKeywords(keywords_str), std::invalid_argument);
462 }
463 
465  KeywordVector kws;
466  kws.push_back(ValueKeyword("NAME", "VALUE", "COMMENT"));
467  kws.push_back(ValueKeyword("NAME2", 1.0, "COMMENT"));
468  kws.push_back(ValueKeyword("NAME3", false));
469  kws.push_back(EsoKeyword("FOO BAR", -1234l, "COMMENT"));
470  kws.push_back(EsoKeyword("FOO BAR BAZ", 1234lu, "COMMENT"));
471  kws.push_back(LiteralKeyword("HIERARCH ESO KW = T / Comment"));
472 
473  auto json = SerializeJsonKeywords(kws);
474  auto parsed_kws = ParseJsonKeywords(json);
475 
476  EXPECT_THAT(parsed_kws, ::testing::ContainerEq(kws));
477 }
Represents the literal 80-character FITS keyword record.
Definition: keyword.hpp:125
std::string_view GetRecord() const &noexcept
Definition: keyword.cpp:415
Contains data structure for FITS keywords.
nlohmann::json SerializeJsonKeywords(std::vector< KeywordVariant > const &keywords)
SerializeJsons keyword to JSON.
Definition: json.cpp:200
std::vector< KeywordVariant > KeywordVector
Vector of keywords.
Definition: keyword.hpp:414
std::vector< KeywordVariant > ParseJsonKeywords(char const *keywords)
Parse and return FITS keywords.
Definition: json.cpp:124
BasicKeyword< ValueKeywordTraits > ValueKeyword
Standard FITS value keyword.
Definition: keyword.hpp:330
BasicKeyword< EsoKeywordTraits > EsoKeyword
ESO hiearchical keyword.
Definition: keyword.hpp:337
TEST_F(TestDpmDaqController, StatusUpdateInNotScheduledSucceeds)
A type safe version of LiteralKeyword that consist of the three basic components of a FITS keyword ke...
Definition: keyword.hpp:266
EXPECT_EQ(meta.rr_uri, "zpb.rr://meta")
ASSERT_EQ(meta.keyword_rules.size(), 1u)