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