11 #include <gmock/gmock.h>
12 #include <gtest/gtest.h>
13 #include <nlohmann/json.hpp>
21 using namespace std::string_view_literals;
27 std::string_view name,
28 std::string_view logical_name) {
29 using namespace ::testing;
33 EXPECT_THAT(record, StartsWith(std::string(kw.
GetRecord())));
35 auto [kw_name, kw_type] = kw.
GetName();
47 std::fill_n(std::back_inserter(too_long), constants::RECORD_LENGTH + 1,
'N');
48 ASSERT_EQ(too_long.size(), constants::RECORD_LENGTH + 1);
54 auto [name, type] = kw.
GetName();
62 auto [name, type] = kw.
GetName();
70 auto [name, type] = kw.
GetName();
78 auto [name, type] = kw.
GetName();
81 EXPECT_EQ(kw.GetRecord(),
"HIERARCH ESO A=T/");
86 auto [name, type] = kw.
GetName();
89 EXPECT_EQ(kw.GetRecord(),
"HIERARCH ESO A=''/");
93 using namespace ::testing;
94 std::string_view record =
"ORIGIN = 'ESO-PARANAL' / European Southern Observatory";
96 std::array<char, constants::RECORD_LENGTH> array_record = {
' '};
97 std::copy(std::begin(record), std::end(record), std::begin(array_record));
99 EXPECT_THAT(std::string(kw.
GetRecord()), StartsWith(std::string(record)));
106 ExpectKeyword(
"SIMPLE = T / Standard FITS ",
113 ExpectKeyword(
"DATE = '2019-12-12T04:30:53.8930' / Date the file was written",
124 EXPECT_THROW(
LiteralKeyword(
"HIERARCH ESO HAS NO VALUE AFTER INDICATOR="),
125 std::invalid_argument);
131 ExpectKeyword(
"HIERARCH ESO ADA ABSROT END = 36.49838 / [deg] Abs rot angle at exp end",
139 "HIERARCH ESO DEL DLT2 VCM CURV = 0.001512604 / mm-1 actual curv. of VCM beam i",
142 "DEL DLT2 VCM CURV");
147 "HIERARCH ESO DEL DLT2 VCM CURV=0.001512604 / mm-1 actual curv. of VCM beam i",
150 "DEL DLT2 VCM CURV");
154 ExpectKeyword(
"HIERARCH ESO N = 0.001512604 / mm-1 actual curv. of VCM beam i",
161 ExpectKeyword(
"HIERARCH ESO N =0.001512604 / mm-1 actual curv. of VCM beam i",
168 ExpectKeyword(
"HIERARCH ESO N= 0.001512604 / mm-1 actual curv. of VCM beam i",
175 ExpectKeyword(
"HIERARCH ESO N=0.001512604 / mm-1 actual curv. of VCM beam i",
194 "HIERARCH DET.CAM.ID = 'TestCamera1Id' / System wide unique ID allocated to camer",
202 ExpectKeyword(
"HIERARCH ESOADA ABSROT END = 36.49838 / [deg] Abs rot angle at exp end",
210 ExpectKeyword(
"HIERARCH ESO ADA ABSROT END 36.49838 / [deg] Abs rot angle at exp end",
229 using namespace ::testing;
230 using namespace std::literals::string_view_literals;
234 auto view =
"HIERARCH ESO TEL MOON DEC = 22.00047 / [deg] 22:00:01.7 DEC (J2000)"sv;
236 std::stringstream ss;
241 auto view =
"COMMENT "sv;
243 std::stringstream ss;
251 template <
typename Type>
254 using Types = ::testing::Types<ValueKeyword, EsoKeyword>;
258 using Keyword = TypeParam;
260 Keyword orig(
"NAME", 1.0,
"comment");
262 EXPECT_EQ(orig.value,
typename Keyword::ValueType(1.0));
269 Keyword move_assign(
"TOBE",
"replaced");
270 move_assign = std::move(copy_assign);
273 Keyword copy_construct(orig);
276 Keyword move_construct(std::move(copy_construct));
281 using Keyword = TypeParam;
283 Keyword orig(
"NAME", 1.0, std::nullopt);
292 using Keyword = TypeParam;
294 Keyword kw(
"NAME",
"str",
"comment");
295 ASSERT_TRUE(std::holds_alternative<std::string>(kw.value));
296 EXPECT_EQ(
"str", std::get<std::string>(kw.value));
300 using Keyword = TypeParam;
302 Keyword lhs(
"NAME", 1.0,
"comment");
303 Keyword rhs(
"NAME", 1.0,
"comment");
305 EXPECT_TRUE(lhs == rhs);
307 EXPECT_FALSE(lhs != rhs);
309 rhs.comment = std::nullopt;
312 rhs.comment =
"comment ";
317 using Keyword = TypeParam;
319 Keyword lhs(
"A", 1.0,
"comment");
320 Keyword rhs(
"B", 1.0,
"comment");
323 EXPECT_FALSE(rhs < lhs);
324 EXPECT_FALSE(lhs < lhs);
328 using Keyword = TypeParam;
331 using namespace ::testing;
335 Keyword kw(
"NAME", std::string(
"value"),
"comment");
336 std::stringstream ss;
338 EXPECT_EQ(ss.str(),
"name='NAME', value=(str)'value', comment='comment'");
341 Keyword kw(
"NAME",
true, std::nullopt);
342 std::stringstream ss;
344 EXPECT_EQ(ss.str(),
"name='NAME', value=(bool)true, comment=n/a");
347 Keyword kw(
"NAME", 1234ul, std::nullopt);
348 std::stringstream ss;
350 EXPECT_THAT(ss.str(),
"name='NAME', value=(uint64_t)1234, comment=n/a");
353 Keyword kw(
"NAME", 1234l, std::nullopt);
354 std::stringstream ss;
356 EXPECT_THAT(ss.str(),
"name='NAME', value=(int64_t)1234, comment=n/a");
359 Keyword kw(
"NAME", 1.234, std::nullopt);
360 std::stringstream ss;
362 EXPECT_THAT(ss.str(),
"name='NAME', value=(double)1.234, comment=n/a");
366 TEST(TestKeywordCombinations, OperatorLessComparesKeywordName) {
385 EXPECT_FALSE(value_kw < eso_kw);
387 EXPECT_LT(literal_value_kw1, literal_value_kw2);
388 EXPECT_FALSE(literal_value_kw1 < literal_eso_kw1);
389 EXPECT_FALSE(literal_value_kw1 < literal_eso_kw2);
390 EXPECT_LT(literal_eso_kw1, literal_eso_kw2);
392 EXPECT_LT(value_kw, literal_commentary_kw1);
393 EXPECT_LT(eso_kw, literal_commentary_kw1);
394 EXPECT_LT(literal_value_kw1, literal_commentary_kw1);
395 EXPECT_LT(literal_eso_kw1, literal_commentary_kw1);
396 EXPECT_LT(literal_commentary_kw1, literal_commentary_kw2);
398 EXPECT_FALSE(literal_eso_kw1 < eso_kw);
399 EXPECT_FALSE(value_kw < value_kw);
400 EXPECT_FALSE(eso_kw < eso_kw);
401 EXPECT_FALSE(eso_kw < value_kw);
402 EXPECT_FALSE(literal_eso_kw1 < value_kw);
403 EXPECT_FALSE(literal_commentary_kw1 < literal_commentary_kw1);
404 EXPECT_FALSE(literal_commentary_kw2 < literal_commentary_kw1);
422 EXPECT_NE(literal_value_kw1.
GetName(), literal_eso_kw1.
GetName());
423 EXPECT_NE(literal_value_kw1.
GetName(), literal_commentary_kw1.
GetName());
434 using namespace ::testing;
457 EXPECT_THAT(to, ContainerEq(result));
462 using namespace ::testing;
490 EXPECT_THAT(to, ContainerEq(result));
495 using namespace ::testing;
521 EXPECT_THAT(to, ContainerEq(result));
526 using namespace ::testing;
552 auto pos = to.begin();
553 std::advance(pos, 3);
555 EXPECT_THAT(to, ContainerEq(result));
562 LiteralKeyword(
"DATE = '2019-12-12T04:30:53.8930' / Date the file was written"),
563 Format(
ValueKeyword(
"DATE",
"2019-12-12T04:30:53.8930",
"Date the file was written")));
571 LiteralKeyword(
"INHERIT = F / denotes the INHERIT keyword convention"),
576 <<
"XTENSION has an exception and must be padded to be minimum 8 chars for legacy reasons";
579 <<
"XTENSION has an exception and must be padded to be minimum 8 chars for legacy reasons";
584 Format(
EsoKeyword(
"ADA ABSROT END", 36.5,
"[deg] Abs rot angle at exp end")));
588 Format(
EsoKeyword(
"DET ACQ1 REV", 1lu,
"Pre-processor framework revision")));
593 "HIERARCH ESO DET CLDC1 DCNM16 = 'DC16_RelaySwitchLowActive' / Name of bias volta"),
595 EsoKeyword(
"DET CLDC1 DCNM16",
"DC16_RelaySwitchLowActive",
"Name of bias voltage")));
598 "HIERARCH ESO PCR SUMMARY NSCANNED = 1273000 / Total Number of scanned records."),
599 Format(
EsoKeyword(
"PCR SUMMARY NSCANNED", 1273000ul,
"Total Number of scanned records.")));
602 "HIERARCH ESO INS TIM2 START = '2019-07-27T02:46:45.00' / Start UTC time in ISO f"),
603 Format(
EsoKeyword(
"INS TIM2 START",
"2019-07-27T02:46:45.00",
"Start UTC time in ISO f")));
609 "HIERARCH DET.CAM.ID = 'TestCamera1Id' / System wide unique ID allocated to camer"),
611 "HIERARCH DET.CAM.ID = 'TestCamera1Id' / System wide unique ID allocated to camer")));
614 TEST(TestFormatting, TooLongKeywords) {
619 Format(
EsoKeyword(
"LONG LONG LONG LONG LONG LONG LONG LONG LONG LONG LONG LONG LON",
622 LiteralKeyword(
"HIERARCH ESO LONG LONG LONG LONG LONG LONG LONG LONG LONG LONG LONG "
624 std::invalid_argument);
626 "LONG LONG LONG LONG LONG LONG LONG LONG LONG LONG LONG LONG LONX",
true)),
627 std::invalid_argument);
629 Format(
EsoKeyword(
"LONG LONG LONG LONG LONG LONG LONG",
"LONG LONG LONG LONG LONG LONX")),
630 std::invalid_argument);
636 ValueKeyword(
"ORIGIN",
"ESO-PARANAL",
"European Southern Observatory"))));
639 EsoKeyword(
"ADA ABSROT END", 36.5,
"[deg] Abs rot angle at exp end"))));
641 auto kw =
LiteralKeyword(
"HIERARCH ESO ADA ABSROT END = 36.5 / [deg] Abs rot angle at exp end");
645 TEST(TestStandardSortV1, StableSortsValueKeywords) {
646 using namespace testing;
648 std::vector<LiteralKeyword> kws;
649 kws.emplace_back(
"SIMPLE = T / Standard FITS");
650 kws.emplace_back(
"BITPIX = 8 / # of bits per pix value");
651 kws.emplace_back(
"NAXIS = 0 / # of axes in data array");
661 TEST(TestStandardSortV1, StableSortsByKeywordType) {
662 using namespace testing;
664 std::vector<LiteralKeyword> kws;
665 kws.emplace_back(
"COMMENT First");
666 kws.emplace_back(
"SIMPLE = T / Standard FITS");
667 kws.emplace_back(
"HIERARCH ESO KW = T / Comment");
668 kws.emplace_back(
"HIERARCH ESO DET A = T / Comment");
669 kws.emplace_back(
"COMMENT Second");
670 kws.emplace_back(
"BITPIX = 8 / # of bits per pix value");
684 TEST(TestStandardSortV1, EsoKeywordsAreSortedByCategory) {
685 using namespace testing;
687 std::vector<LiteralKeyword> kws;
688 kws.emplace_back(
"HIERARCH ESO DPR A = T / Comment");
689 kws.emplace_back(
"HIERARCH ESO DPR B = T / Comment");
690 kws.emplace_back(
"HIERARCH ESO DPR1 A = T / Comment");
691 kws.emplace_back(
"HIERARCH ESO DPR2 A = T / Comment");
692 kws.emplace_back(
"HIERARCH ESO OBS A = T / Comment");
693 kws.emplace_back(
"HIERARCH ESO OBS B = T / Comment");
694 kws.emplace_back(
"HIERARCH ESO TPL A = T / Comment");
695 kws.emplace_back(
"HIERARCH ESO TPL B = T / Comment");
696 kws.emplace_back(
"HIERARCH ESO GEN A = T / Comment");
697 kws.emplace_back(
"HIERARCH ESO GEN B = T / Comment");
698 kws.emplace_back(
"HIERARCH ESO TEL A = T / Comment");
699 kws.emplace_back(
"HIERARCH ESO TEL B = T / Comment");
700 kws.emplace_back(
"HIERARCH ESO ADA A = T / Comment");
701 kws.emplace_back(
"HIERARCH ESO ADA B = T / Comment");
702 kws.emplace_back(
"HIERARCH ESO INS A = T / Comment");
703 kws.emplace_back(
"HIERARCH ESO INS B = T / Comment");
704 kws.emplace_back(
"HIERARCH ESO DET A = T / Comment");
705 kws.emplace_back(
"HIERARCH ESO DET B = T / Comment");
706 kws.emplace_back(
"HIERARCH ESO DET1 A = T / Comment");
707 kws.emplace_back(
"HIERARCH ESO DET2 B = T / Comment");
708 kws.emplace_back(
"HIERARCH ESO DET3 A = T / Comment");
709 kws.emplace_back(
"HIERARCH ESO DET3 B = T / Comment");
710 kws.emplace_back(
"HIERARCH ESO DPRUN A = T / Comment");
711 kws.emplace_back(
"HIERARCH ESO UNK A = T / Comment");
712 kws.emplace_back(
"HIERARCH ESO UNK B = T / Comment");
714 auto [name, type] = kws[0].GetName();
718 std::random_device rd;
719 std::mt19937 g(rd());
721 for (
auto i = 0u;
i < 20u; ++
i) {
722 auto to_sort_kws = kws;
723 std::shuffle(std::begin(to_sort_kws), std::end(to_sort_kws), g);
725 ASSERT_THAT(to_sort_kws, ContainerEq(kws));
728 EXPECT_THAT(to_sort_kws, ContainerEq(kws));
732 TEST(TestStandardSortV1, EsoKeywordsAreSortedByNumberedCategory) {
733 using namespace testing;
735 std::vector<LiteralKeyword> kws;
736 kws.emplace_back(
"HIERARCH ESO DPR Z = T / Comment");
737 kws.emplace_back(
"HIERARCH ESO DPR1 A = T / Comment");
738 kws.emplace_back(
"HIERARCH ESO DPR2 A = T / Comment");
739 kws.emplace_back(
"HIERARCH ESO DET ZZ ZZ = T / Comment");
740 kws.emplace_back(
"HIERARCH ESO DET1 A = T / Comment");
741 kws.emplace_back(
"HIERARCH ESO DET2 B = T / Comment");
742 kws.emplace_back(
"HIERARCH ESO DET3 A = T / Comment");
743 kws.emplace_back(
"HIERARCH ESO DET3 B = T / Comment");
745 std::random_device rd;
746 std::mt19937 g(rd());
748 for (
auto i = 0u;
i < 20u; ++
i) {
749 auto to_sort_kws = kws;
750 std::shuffle(std::begin(to_sort_kws), std::end(to_sort_kws), g);
752 ASSERT_THAT(to_sort_kws, ContainerEq(kws));
755 EXPECT_THAT(to_sort_kws, ContainerEq(kws));
759 TEST(TestStandardSortV1, EsoKeywordAreSortedEvenIfCloslyMatched) {
760 using namespace testing;
775 TEST(TestStandardSortV1, EsoKeywordAreSortedEvenIfStrange) {
776 using namespace testing;
778 std::vector<LiteralKeyword> kws;
779 kws.emplace_back(
"HIERARCH ESO A=T");
780 kws.emplace_back(
"HIERARCH ESO D=T");
781 kws.emplace_back(
"HIERARCH ESO D C=T/D");
782 kws.emplace_back(
"HIERARCH ESO E1=T");
783 kws.emplace_back(
"HIERARCH ESO E2 C=T/D");
784 kws.emplace_back(
"HIERARCH ESO F1A1=T");
785 kws.emplace_back(
"HIERARCH ESO F1A2 C=T/D");
787 std::random_device rd;
788 std::mt19937 g(rd());
790 for (
auto i = 0u;
i < 20u; ++
i) {
791 auto to_sort_kws = kws;
792 std::shuffle(std::begin(to_sort_kws), std::end(to_sort_kws), g);
794 EXPECT_THAT(to_sort_kws, ContainerEq(kws));
798 TEST(TestStandardSortV1, CommentsSortedByName) {
799 using namespace testing;
801 std::vector<LiteralKeyword> kws;
802 kws.emplace_back(
"COMMENT XXX");
803 kws.emplace_back(
"COMMENT AAA");
804 kws.emplace_back(
"HISTORY XXX");
805 kws.emplace_back(
"HISTORY AAA");
807 std::vector<LiteralKeyword> unordered;
808 unordered.emplace_back(
"HISTORY XXX");
809 unordered.emplace_back(
"COMMENT XXX");
810 unordered.emplace_back(
"HISTORY AAA");
811 unordered.emplace_back(
"COMMENT AAA");
815 EXPECT_THAT(unordered, ContainerEq(kws));
818 TEST(TestStandardSortV1, EsoKeywordsAreSortedAlphabetically) {
819 using namespace testing;
821 std::vector<LiteralKeyword> kws;
822 kws.emplace_back(
"HIERARCH ESO KWB = T / Comment");
823 kws.emplace_back(
"HIERARCH ESO KWA = T / Comment");
824 kws.emplace_back(
"HIERARCH ESO KWA A = T / Comment");
825 kws.emplace_back(
"HIERARCH ESO KWA1 A = T / Comment");
Note that test cases must use TypeParam and cannot declare templated aliases.
void ExpectKeyword(std::string const &record, KeywordType type, std::string_view name, std::string_view logical_name)
Represents the literal 80-character FITS keyword record.
constexpr KeywordType GetType() const noexcept
std::string_view GetRecord() const &noexcept
constexpr KeywordNameView GetName() const &noexcept
Query logical keyword name.
Contains data structure for FITS keywords.
Contains common matchers.
void ReportNestedExceptions(std::ostream &os) noexcept
void StandardSort(std::vector< LiteralKeyword > &keywords)
Sorts keywords according to ESO DICD standards.
constexpr KeywordNameView GetKeywordName(EsoKeyword const &keyword) noexcept
Get keyword name from keyword.
void InsertKeywords(KeywordVector &keywords, KeywordVector::iterator position, KeywordVector::const_iterator from_first, KeywordVector::const_iterator from_last)
Insert keywords.
KeywordType
Type of FITS keyword.
@ Eso
An ESO hiearchical keyword.
@ Commentary
A commentary keyword, which are keywords that do not fall into the previous categories.
bool NameEquals(KeywordVariant const &lhs, KeywordVariant const &rhs) noexcept
Compare logical keyword names of keyword of the same type.
LiteralKeyword Format(KeywordVariant const &keyword)
std::vector< KeywordVariant > KeywordVector
Vector of keywords.
std::variant< ValueKeyword, EsoKeyword, LiteralKeyword > KeywordVariant
The different variants of keywords that are supported.
void UpdateKeywords(KeywordVector &to, KeywordVector const &from, ConflictPolicy policy=ConflictPolicy::Replace)
Updates to with keywords from from.
BasicKeyword< ValueKeywordTraits > ValueKeyword
Standard FITS value keyword.
BasicKeyword< EsoKeywordTraits > EsoKeyword
ESO hiearchical keyword.
TEST_F(TestDpmDaqController, StatusUpdateInNotScheduledSucceeds)
TEST(TestDaqContext, Files)
A type safe version of LiteralKeyword that consist of the three basic components of a FITS keyword ke...
constexpr KeywordNameView GetName() const &noexcept
Query logical keyword name.
TYPED_TEST(TestKeyword, Construction)
TYPED_TEST_CASE(TestKeyword, Types)
::testing::Types< ValueKeyword, EsoKeyword > Types
EXPECT_EQ(meta.rr_uri, "zpb.rr://meta")
ASSERT_EQ(meta.keyword_rules.size(), 1u)