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 "StudyName", 29 Runtime{HostState{"CpuName", 30 123, 31 {CacheInfo{"A", 1, 2, 3}, CacheInfo{"B", 4, 5, 6}}}, 32 456, 789, 33 BenchmarkOptions{std::chrono::seconds(1), std::chrono::seconds(2), 34 10, 100, 6, 100, 0.1, 2, BenchmarkLog::Full}}, 35 StudyConfiguration{std::string("Function"), 30U, false, 32U, 36 std::string("Distribution"), Align(16), 3U}, 37 {std::chrono::seconds(3), std::chrono::seconds(4)}}; 38 } 39 40 static std::string serializeToString(const Study &S) { 41 std::string Buffer; 42 raw_string_ostream RSO(Buffer); 43 json::OStream JOS(RSO); 44 serializeToJson(S, JOS); 45 return Buffer; 46 } 47 48 MATCHER(EqualsCacheInfo, "") { 49 const CacheInfo &A = ::testing::get<0>(arg); 50 const CacheInfo &B = ::testing::get<1>(arg); 51 return ExplainMatchResult(AllOf(Field(&CacheInfo::Type, B.Type), 52 Field(&CacheInfo::Level, B.Level), 53 Field(&CacheInfo::Size, B.Size), 54 Field(&CacheInfo::NumSharing, B.NumSharing)), 55 A, result_listener); 56 } 57 58 auto equals(const HostState &H) -> auto { 59 return AllOf( 60 Field(&HostState::CpuName, H.CpuName), 61 Field(&HostState::CpuFrequency, H.CpuFrequency), 62 Field(&HostState::Caches, Pointwise(EqualsCacheInfo(), H.Caches))); 63 } 64 65 auto equals(const StudyConfiguration &SC) -> auto { 66 return AllOf( 67 Field(&StudyConfiguration::Function, SC.Function), 68 Field(&StudyConfiguration::NumTrials, SC.NumTrials), 69 Field(&StudyConfiguration::IsSweepMode, SC.IsSweepMode), 70 Field(&StudyConfiguration::SweepModeMaxSize, SC.SweepModeMaxSize), 71 Field(&StudyConfiguration::SizeDistributionName, SC.SizeDistributionName), 72 Field(&StudyConfiguration::AccessAlignment, SC.AccessAlignment), 73 Field(&StudyConfiguration::MemcmpMismatchAt, SC.MemcmpMismatchAt)); 74 } 75 76 auto equals(const BenchmarkOptions &BO) -> auto { 77 return AllOf( 78 Field(&BenchmarkOptions::MinDuration, BO.MinDuration), 79 Field(&BenchmarkOptions::MaxDuration, BO.MaxDuration), 80 Field(&BenchmarkOptions::InitialIterations, BO.InitialIterations), 81 Field(&BenchmarkOptions::MaxIterations, BO.MaxIterations), 82 Field(&BenchmarkOptions::MinSamples, BO.MinSamples), 83 Field(&BenchmarkOptions::MaxSamples, BO.MaxSamples), 84 Field(&BenchmarkOptions::Epsilon, BO.Epsilon), 85 Field(&BenchmarkOptions::ScalingFactor, BO.ScalingFactor), 86 Field(&BenchmarkOptions::Log, BO.Log)); 87 } 88 89 auto equals(const Runtime &RI) -> auto { 90 return AllOf(Field(&Runtime::Host, equals(RI.Host)), 91 Field(&Runtime::BufferSize, RI.BufferSize), 92 Field(&Runtime::BatchParameterCount, RI.BatchParameterCount), 93 Field(&Runtime::BenchmarkOptions, equals(RI.BenchmarkOptions))); 94 } 95 96 auto equals(const Study &S) -> auto { 97 return AllOf(Field(&Study::StudyName, S.StudyName), 98 Field(&Study::Runtime, equals(S.Runtime)), 99 Field(&Study::Configuration, equals(S.Configuration)), 100 Field(&Study::Measurements, S.Measurements)); 101 } 102 103 TEST(JsonTest, RoundTrip) { 104 const Study S = getStudy(); 105 const auto Serialized = serializeToString(S); 106 auto StudyOrError = parseJsonStudy(Serialized); 107 if (auto Err = StudyOrError.takeError()) 108 EXPECT_FALSE(Err) << "Unexpected error : " << Err << "\n" << Serialized; 109 const Study &Parsed = *StudyOrError; 110 EXPECT_THAT(Parsed, equals(S)) << Serialized << "\n" 111 << serializeToString(Parsed); 112 } 113 114 TEST(JsonTest, SupplementaryField) { 115 auto Failure = parseJsonStudy(R"({ 116 "UnknownField": 10 117 } 118 )"); 119 EXPECT_EQ(toString(Failure.takeError()), "Unknown field: UnknownField"); 120 } 121 122 TEST(JsonTest, InvalidType) { 123 auto Failure = parseJsonStudy(R"({ 124 "Runtime": 1 125 } 126 )"); 127 EXPECT_EQ(toString(Failure.takeError()), "Expected JSON Object"); 128 } 129 130 TEST(JsonTest, InvalidDuration) { 131 auto Failure = parseJsonStudy(R"({ 132 "Runtime": { 133 "BenchmarkOptions": { 134 "MinDuration": "Duration should be a Number" 135 } 136 } 137 } 138 )"); 139 EXPECT_EQ(toString(Failure.takeError()), "Can't parse Duration"); 140 } 141 142 TEST(JsonTest, InvalidAlignType) { 143 auto Failure = parseJsonStudy(R"({ 144 "Configuration": { 145 "AccessAlignment": "Align should be an Integer" 146 } 147 } 148 )"); 149 EXPECT_EQ(toString(Failure.takeError()), "Can't parse Align, not an Integer"); 150 } 151 152 TEST(JsonTest, InvalidAlign) { 153 auto Failure = parseJsonStudy(R"({ 154 "Configuration": { 155 "AccessAlignment": 3 156 } 157 } 158 )"); 159 EXPECT_EQ(toString(Failure.takeError()), 160 "Can't parse Align, not a power of two"); 161 } 162 163 TEST(JsonTest, InvalidBenchmarkLogType) { 164 auto Failure = parseJsonStudy(R"({ 165 "Runtime": { 166 "BenchmarkOptions":{ 167 "Log": 3 168 } 169 } 170 } 171 )"); 172 EXPECT_EQ(toString(Failure.takeError()), 173 "Can't parse BenchmarkLog, not a String"); 174 } 175 176 TEST(JsonTest, InvalidBenchmarkLog) { 177 auto Failure = parseJsonStudy(R"({ 178 "Runtime": { 179 "BenchmarkOptions":{ 180 "Log": "Unknown" 181 } 182 } 183 } 184 )"); 185 EXPECT_EQ(toString(Failure.takeError()), 186 "Can't parse BenchmarkLog, invalid value 'Unknown'"); 187 } 188 189 } // namespace 190 } // namespace libc_benchmarks 191 } // namespace llvm 192