1*438f7fc0SSiva Chandra Reddy //===-- JSON Tests --------------------------------------------------------===//
2*438f7fc0SSiva Chandra Reddy //
3*438f7fc0SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*438f7fc0SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5*438f7fc0SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*438f7fc0SSiva Chandra Reddy //
7*438f7fc0SSiva Chandra Reddy //===----------------------------------------------------------------------===//
8*438f7fc0SSiva Chandra Reddy 
9*438f7fc0SSiva Chandra Reddy #include "JSON.h"
10*438f7fc0SSiva Chandra Reddy #include "LibcBenchmark.h"
11*438f7fc0SSiva Chandra Reddy #include "LibcMemoryBenchmark.h"
12*438f7fc0SSiva Chandra Reddy #include "llvm/Support/JSON.h"
13*438f7fc0SSiva Chandra Reddy #include "llvm/Support/raw_ostream.h"
14*438f7fc0SSiva Chandra Reddy #include "gmock/gmock.h"
15*438f7fc0SSiva Chandra Reddy #include "gtest/gtest.h"
16*438f7fc0SSiva Chandra Reddy 
17*438f7fc0SSiva Chandra Reddy using testing::AllOf;
18*438f7fc0SSiva Chandra Reddy using testing::ExplainMatchResult;
19*438f7fc0SSiva Chandra Reddy using testing::Field;
20*438f7fc0SSiva Chandra Reddy using testing::Pointwise;
21*438f7fc0SSiva Chandra Reddy 
22*438f7fc0SSiva Chandra Reddy namespace llvm {
23*438f7fc0SSiva Chandra Reddy namespace libc_benchmarks {
24*438f7fc0SSiva Chandra Reddy namespace {
25*438f7fc0SSiva Chandra Reddy 
26*438f7fc0SSiva Chandra Reddy Study getStudy() {
27*438f7fc0SSiva Chandra Reddy   return Study{
28*438f7fc0SSiva Chandra Reddy       HostState{
29*438f7fc0SSiva Chandra Reddy           "CpuName", 123, {CacheInfo{"A", 1, 2, 3}, CacheInfo{"B", 4, 5, 6}}},
30*438f7fc0SSiva Chandra Reddy       BenchmarkOptions{std::chrono::seconds(1), std::chrono::seconds(2), 10,
31*438f7fc0SSiva Chandra Reddy                        100, 6, 100, 0.1, 2, BenchmarkLog::Full},
32*438f7fc0SSiva Chandra Reddy       StudyConfiguration{2, 3, SizeRange{4, 5, 6}, Align(8), 9, 10},
33*438f7fc0SSiva Chandra Reddy       {FunctionMeasurements{"A",
34*438f7fc0SSiva Chandra Reddy                             {Measurement{3, std::chrono::seconds(3)},
35*438f7fc0SSiva Chandra Reddy                              Measurement{3, std::chrono::seconds(4)}}},
36*438f7fc0SSiva Chandra Reddy        FunctionMeasurements{"B", {}}}};
37*438f7fc0SSiva Chandra Reddy }
38*438f7fc0SSiva Chandra Reddy 
39*438f7fc0SSiva Chandra Reddy static std::string SerializeToString(const Study &S) {
40*438f7fc0SSiva Chandra Reddy   std::string Buffer;
41*438f7fc0SSiva Chandra Reddy   raw_string_ostream RSO(Buffer);
42*438f7fc0SSiva Chandra Reddy   json::OStream JOS(RSO);
43*438f7fc0SSiva Chandra Reddy   SerializeToJson(S, JOS);
44*438f7fc0SSiva Chandra Reddy   return Buffer;
45*438f7fc0SSiva Chandra Reddy }
46*438f7fc0SSiva Chandra Reddy 
47*438f7fc0SSiva Chandra Reddy MATCHER(EqualsCacheInfo, "") {
48*438f7fc0SSiva Chandra Reddy   const CacheInfo &A = ::testing::get<0>(arg);
49*438f7fc0SSiva Chandra Reddy   const CacheInfo &B = ::testing::get<1>(arg);
50*438f7fc0SSiva Chandra Reddy   return ExplainMatchResult(AllOf(Field(&CacheInfo::Type, B.Type),
51*438f7fc0SSiva Chandra Reddy                                   Field(&CacheInfo::Level, B.Level),
52*438f7fc0SSiva Chandra Reddy                                   Field(&CacheInfo::Size, B.Size),
53*438f7fc0SSiva Chandra Reddy                                   Field(&CacheInfo::NumSharing, B.NumSharing)),
54*438f7fc0SSiva Chandra Reddy                             A, result_listener);
55*438f7fc0SSiva Chandra Reddy }
56*438f7fc0SSiva Chandra Reddy 
57*438f7fc0SSiva Chandra Reddy auto Equals(const HostState &H) -> auto {
58*438f7fc0SSiva Chandra Reddy   return AllOf(
59*438f7fc0SSiva Chandra Reddy       Field(&HostState::CpuName, H.CpuName),
60*438f7fc0SSiva Chandra Reddy       Field(&HostState::CpuFrequency, H.CpuFrequency),
61*438f7fc0SSiva Chandra Reddy       Field(&HostState::Caches, Pointwise(EqualsCacheInfo(), H.Caches)));
62*438f7fc0SSiva Chandra Reddy }
63*438f7fc0SSiva Chandra Reddy 
64*438f7fc0SSiva Chandra Reddy auto Equals(const BenchmarkOptions &BO) -> auto {
65*438f7fc0SSiva Chandra Reddy   return AllOf(
66*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::MinDuration, BO.MinDuration),
67*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::MaxDuration, BO.MaxDuration),
68*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::InitialIterations, BO.InitialIterations),
69*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::MaxIterations, BO.MaxIterations),
70*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::MinSamples, BO.MinSamples),
71*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::MaxSamples, BO.MaxSamples),
72*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::Epsilon, BO.Epsilon),
73*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::ScalingFactor, BO.ScalingFactor),
74*438f7fc0SSiva Chandra Reddy       Field(&BenchmarkOptions::Log, BO.Log));
75*438f7fc0SSiva Chandra Reddy }
76*438f7fc0SSiva Chandra Reddy 
77*438f7fc0SSiva Chandra Reddy auto Equals(const SizeRange &SR) -> auto {
78*438f7fc0SSiva Chandra Reddy   return AllOf(Field(&SizeRange::From, SR.From), Field(&SizeRange::To, SR.To),
79*438f7fc0SSiva Chandra Reddy                Field(&SizeRange::Step, SR.Step));
80*438f7fc0SSiva Chandra Reddy }
81*438f7fc0SSiva Chandra Reddy 
82*438f7fc0SSiva Chandra Reddy auto Equals(const StudyConfiguration &SC) -> auto {
83*438f7fc0SSiva Chandra Reddy   return AllOf(
84*438f7fc0SSiva Chandra Reddy       Field(&StudyConfiguration::Runs, SC.Runs),
85*438f7fc0SSiva Chandra Reddy       Field(&StudyConfiguration::BufferSize, SC.BufferSize),
86*438f7fc0SSiva Chandra Reddy       Field(&StudyConfiguration::Size, Equals(SC.Size)),
87*438f7fc0SSiva Chandra Reddy       Field(&StudyConfiguration::AddressAlignment, SC.AddressAlignment),
88*438f7fc0SSiva Chandra Reddy       Field(&StudyConfiguration::MemsetValue, SC.MemsetValue),
89*438f7fc0SSiva Chandra Reddy       Field(&StudyConfiguration::MemcmpMismatchAt, SC.MemcmpMismatchAt));
90*438f7fc0SSiva Chandra Reddy }
91*438f7fc0SSiva Chandra Reddy 
92*438f7fc0SSiva Chandra Reddy MATCHER(EqualsMeasurement, "") {
93*438f7fc0SSiva Chandra Reddy   const Measurement &A = ::testing::get<0>(arg);
94*438f7fc0SSiva Chandra Reddy   const Measurement &B = ::testing::get<1>(arg);
95*438f7fc0SSiva Chandra Reddy   return ExplainMatchResult(AllOf(Field(&Measurement::Size, B.Size),
96*438f7fc0SSiva Chandra Reddy                                   Field(&Measurement::Runtime, B.Runtime)),
97*438f7fc0SSiva Chandra Reddy                             A, result_listener);
98*438f7fc0SSiva Chandra Reddy }
99*438f7fc0SSiva Chandra Reddy 
100*438f7fc0SSiva Chandra Reddy MATCHER(EqualsFunctions, "") {
101*438f7fc0SSiva Chandra Reddy   const FunctionMeasurements &A = ::testing::get<0>(arg);
102*438f7fc0SSiva Chandra Reddy   const FunctionMeasurements &B = ::testing::get<1>(arg);
103*438f7fc0SSiva Chandra Reddy   return ExplainMatchResult(
104*438f7fc0SSiva Chandra Reddy       AllOf(Field(&FunctionMeasurements::Name, B.Name),
105*438f7fc0SSiva Chandra Reddy             Field(&FunctionMeasurements::Measurements,
106*438f7fc0SSiva Chandra Reddy                   Pointwise(EqualsMeasurement(), B.Measurements))),
107*438f7fc0SSiva Chandra Reddy       A, result_listener);
108*438f7fc0SSiva Chandra Reddy }
109*438f7fc0SSiva Chandra Reddy 
110*438f7fc0SSiva Chandra Reddy auto Equals(const Study &S) -> auto {
111*438f7fc0SSiva Chandra Reddy   return AllOf(
112*438f7fc0SSiva Chandra Reddy       Field(&Study::Host, Equals(S.Host)),
113*438f7fc0SSiva Chandra Reddy       Field(&Study::Options, Equals(S.Options)),
114*438f7fc0SSiva Chandra Reddy       Field(&Study::Configuration, Equals(S.Configuration)),
115*438f7fc0SSiva Chandra Reddy       Field(&Study::Functions, Pointwise(EqualsFunctions(), S.Functions)));
116*438f7fc0SSiva Chandra Reddy }
117*438f7fc0SSiva Chandra Reddy 
118*438f7fc0SSiva Chandra Reddy TEST(JsonTest, RoundTrip) {
119*438f7fc0SSiva Chandra Reddy   const Study S = getStudy();
120*438f7fc0SSiva Chandra Reddy   auto StudyOrError = ParseJsonStudy(SerializeToString(S));
121*438f7fc0SSiva Chandra Reddy   if (auto Err = StudyOrError.takeError())
122*438f7fc0SSiva Chandra Reddy     EXPECT_FALSE(Err) << "Unexpected error";
123*438f7fc0SSiva Chandra Reddy   const Study &Parsed = *StudyOrError;
124*438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Parsed, Equals(S));
125*438f7fc0SSiva Chandra Reddy }
126*438f7fc0SSiva Chandra Reddy 
127*438f7fc0SSiva Chandra Reddy TEST(JsonTest, SupplementaryField) {
128*438f7fc0SSiva Chandra Reddy   auto Failure = ParseJsonStudy(R"({
129*438f7fc0SSiva Chandra Reddy       "UnknownField": 10
130*438f7fc0SSiva Chandra Reddy     }
131*438f7fc0SSiva Chandra Reddy   )");
132*438f7fc0SSiva Chandra Reddy   EXPECT_EQ(toString(Failure.takeError()), "Unknown field: UnknownField");
133*438f7fc0SSiva Chandra Reddy }
134*438f7fc0SSiva Chandra Reddy 
135*438f7fc0SSiva Chandra Reddy TEST(JsonTest, InvalidType) {
136*438f7fc0SSiva Chandra Reddy   auto Failure = ParseJsonStudy(R"({
137*438f7fc0SSiva Chandra Reddy       "Options": 1
138*438f7fc0SSiva Chandra Reddy     }
139*438f7fc0SSiva Chandra Reddy   )");
140*438f7fc0SSiva Chandra Reddy   EXPECT_EQ(toString(Failure.takeError()), "Expected JSON Object");
141*438f7fc0SSiva Chandra Reddy }
142*438f7fc0SSiva Chandra Reddy 
143*438f7fc0SSiva Chandra Reddy TEST(JsonTest, InvalidDuration) {
144*438f7fc0SSiva Chandra Reddy   auto Failure = ParseJsonStudy(R"({
145*438f7fc0SSiva Chandra Reddy       "Options": {
146*438f7fc0SSiva Chandra Reddy         "MinDuration": "Duration should be a Number"
147*438f7fc0SSiva Chandra Reddy       }
148*438f7fc0SSiva Chandra Reddy     }
149*438f7fc0SSiva Chandra Reddy   )");
150*438f7fc0SSiva Chandra Reddy   EXPECT_EQ(toString(Failure.takeError()), "Can't parse Duration");
151*438f7fc0SSiva Chandra Reddy }
152*438f7fc0SSiva Chandra Reddy 
153*438f7fc0SSiva Chandra Reddy TEST(JsonTest, InvalidAlignType) {
154*438f7fc0SSiva Chandra Reddy   auto Failure = ParseJsonStudy(R"({
155*438f7fc0SSiva Chandra Reddy       "Configuration":{
156*438f7fc0SSiva Chandra Reddy         "AddressAlignment": "Align should be an Integer"
157*438f7fc0SSiva Chandra Reddy       }
158*438f7fc0SSiva Chandra Reddy     }
159*438f7fc0SSiva Chandra Reddy   )");
160*438f7fc0SSiva Chandra Reddy   EXPECT_EQ(toString(Failure.takeError()), "Can't parse Align, not an Integer");
161*438f7fc0SSiva Chandra Reddy }
162*438f7fc0SSiva Chandra Reddy 
163*438f7fc0SSiva Chandra Reddy TEST(JsonTest, InvalidAlign) {
164*438f7fc0SSiva Chandra Reddy   auto Failure = ParseJsonStudy(R"({
165*438f7fc0SSiva Chandra Reddy       "Configuration":{
166*438f7fc0SSiva Chandra Reddy         "AddressAlignment":3
167*438f7fc0SSiva Chandra Reddy       }
168*438f7fc0SSiva Chandra Reddy     }
169*438f7fc0SSiva Chandra Reddy   )");
170*438f7fc0SSiva Chandra Reddy   EXPECT_EQ(toString(Failure.takeError()),
171*438f7fc0SSiva Chandra Reddy             "Can't parse Align, not a power of two");
172*438f7fc0SSiva Chandra Reddy }
173*438f7fc0SSiva Chandra Reddy 
174*438f7fc0SSiva Chandra Reddy TEST(JsonTest, InvalidBenchmarkLogType) {
175*438f7fc0SSiva Chandra Reddy   auto Failure = ParseJsonStudy(R"({
176*438f7fc0SSiva Chandra Reddy       "Options":{
177*438f7fc0SSiva Chandra Reddy         "Log": 3
178*438f7fc0SSiva Chandra Reddy       }
179*438f7fc0SSiva Chandra Reddy     }
180*438f7fc0SSiva Chandra Reddy   )");
181*438f7fc0SSiva Chandra Reddy   EXPECT_EQ(toString(Failure.takeError()),
182*438f7fc0SSiva Chandra Reddy             "Can't parse BenchmarkLog, not a String");
183*438f7fc0SSiva Chandra Reddy }
184*438f7fc0SSiva Chandra Reddy 
185*438f7fc0SSiva Chandra Reddy TEST(JsonTest, InvalidBenchmarkLog) {
186*438f7fc0SSiva Chandra Reddy   auto Failure = ParseJsonStudy(R"({
187*438f7fc0SSiva Chandra Reddy       "Options":{
188*438f7fc0SSiva Chandra Reddy         "Log": "Unknown"
189*438f7fc0SSiva Chandra Reddy       }
190*438f7fc0SSiva Chandra Reddy     }
191*438f7fc0SSiva Chandra Reddy   )");
192*438f7fc0SSiva Chandra Reddy   EXPECT_EQ(toString(Failure.takeError()),
193*438f7fc0SSiva Chandra Reddy             "Can't parse BenchmarkLog, invalid value 'Unknown'");
194*438f7fc0SSiva Chandra Reddy }
195*438f7fc0SSiva Chandra Reddy 
196*438f7fc0SSiva Chandra Reddy } // namespace
197*438f7fc0SSiva Chandra Reddy } // namespace libc_benchmarks
198*438f7fc0SSiva Chandra Reddy } // namespace llvm
199