diff --git a/centipede/BUILD b/centipede/BUILD index 78b3e955..1cd6c1b5 100644 --- a/centipede/BUILD +++ b/centipede/BUILD @@ -226,7 +226,7 @@ cc_library( ], ) -# simple definitions only, no code, no deps other than span. +# simple definitions only, no code, no deps. cc_library( name = "defs", hdrs = ["defs.h"], @@ -1119,6 +1119,7 @@ cc_library( cc_library( name = "test_util", + testonly = True, srcs = ["test_util.cc"], hdrs = ["test_util.h"], deps = [ @@ -1128,6 +1129,7 @@ cc_library( ":util", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", + "@com_google_googletest//:gtest", ], ) @@ -1393,6 +1395,7 @@ cc_test( name = "execution_metadata_test", srcs = ["execution_metadata_test.cc"], deps = [ + ":defs", ":execution_metadata", "@com_google_googletest//:gtest_main", ], @@ -1402,6 +1405,7 @@ cc_test( name = "runner_result_test", srcs = ["runner_result_test.cc"], deps = [ + ":defs", ":feature", ":runner_result", ":shared_memory_blob_sequence", @@ -1425,6 +1429,7 @@ cc_test( deps = [ ":byte_array_mutator", ":defs", + ":test_util", "@com_google_absl//absl/container:flat_hash_set", "@com_google_googletest//:gtest_main", ], diff --git a/centipede/blob_file_test.cc b/centipede/blob_file_test.cc index 81c3c515..0da35eec 100644 --- a/centipede/blob_file_test.cc +++ b/centipede/blob_file_test.cc @@ -59,9 +59,9 @@ void TestOneBlobFile(std::unique_ptr (*ReaderFactory)(), auto reader = ReaderFactory(); EXPECT_OK(reader->Open(path)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(input1, blob); + EXPECT_THAT(blob, EqByteSpan(input1)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(input2, blob); + EXPECT_THAT(blob, EqByteSpan(input2)); EXPECT_EQ(reader->Read(blob), absl::OutOfRangeError("no more blobs")); EXPECT_OK(reader->Close()); } @@ -79,11 +79,11 @@ void TestOneBlobFile(std::unique_ptr (*ReaderFactory)(), auto reader = ReaderFactory(); EXPECT_OK(reader->Open(path)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(input1, blob); + EXPECT_THAT(blob, EqByteSpan(input1)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(input2, blob); + EXPECT_THAT(blob, EqByteSpan(input2)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(input3, blob); + EXPECT_THAT(blob, EqByteSpan(input3)); EXPECT_EQ(reader->Read(blob), absl::OutOfRangeError("no more blobs")); EXPECT_OK(reader->Close()); } @@ -101,7 +101,7 @@ void TestOneBlobFile(std::unique_ptr (*ReaderFactory)(), auto reader = ReaderFactory(); EXPECT_OK(reader->Open(path)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(input4, blob); + EXPECT_THAT(blob, EqByteSpan(input4)); EXPECT_EQ(reader->Read(blob), absl::OutOfRangeError("no more blobs")); EXPECT_OK(reader->Close()); } @@ -134,7 +134,7 @@ TEST_P(BlobFile, AfterFailedOpenTest) { // are as expected. ASSERT_OK(reader->Open(path)); ASSERT_OK(reader->Read(blob)); - EXPECT_EQ(input, blob); + EXPECT_THAT(blob, EqByteSpan(input)); EXPECT_EQ(reader->Read(blob), absl::OutOfRangeError("no more blobs")); EXPECT_OK(reader->Close()); } @@ -214,7 +214,7 @@ TEST_P(ReadMultipleFiles, SingleObjectMultipleFormats) { EXPECT_OK(writer->Close()); EXPECT_OK(reader->Open(path)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(file1_blob1, blob); + EXPECT_THAT(blob, EqByteSpan(file1_blob1)); EXPECT_EQ(reader->Read(blob), absl::OutOfRangeError("no more blobs")); EXPECT_OK(reader->Close()); @@ -226,9 +226,9 @@ TEST_P(ReadMultipleFiles, SingleObjectMultipleFormats) { EXPECT_OK(writer->Close()); EXPECT_OK(reader->Open(path)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(file2_blob1, blob); + EXPECT_THAT(blob, EqByteSpan(file2_blob1)); EXPECT_OK(reader->Read(blob)); - EXPECT_EQ(file2_blob2, blob); + EXPECT_THAT(blob, EqByteSpan(file2_blob2)); EXPECT_EQ(reader->Read(blob), absl::OutOfRangeError("no more blobs")); EXPECT_OK(reader->Close()); } diff --git a/centipede/byte_array_mutator_test.cc b/centipede/byte_array_mutator_test.cc index 2952077f..ae53328d 100644 --- a/centipede/byte_array_mutator_test.cc +++ b/centipede/byte_array_mutator_test.cc @@ -23,6 +23,7 @@ #include "gtest/gtest.h" #include "absl/container/flat_hash_set.h" #include "./centipede/defs.h" +#include "./centipede/test_util.h" namespace centipede { @@ -87,6 +88,9 @@ TEST(ByteArrayMutator, RoundDownToRemoveCorrectly) { namespace { +using ::testing::ElementsAre; +using ::testing::UnorderedElementsAre; + TEST(DictEntry, DictEntry) { uint8_t bytes[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; DictEntry a_0_10({bytes + 0, 10}); @@ -126,27 +130,27 @@ TEST(CmpDictionary, CmpDictionary) { std::vector suggestions; suggestions.reserve(5); - dict.SuggestReplacement({42, 43}, suggestions); + dict.SuggestReplacement(S({42, 43}), suggestions); EXPECT_TRUE(suggestions.empty()); - dict.SuggestReplacement({1, 2, 3}, suggestions); - EXPECT_THAT(suggestions, testing::ElementsAre(S({3, 4}))); + dict.SuggestReplacement(S({1, 2, 3}), suggestions); + EXPECT_THAT(suggestions, ElementsAre(EqByteSpan(S({3, 4})))); - dict.SuggestReplacement({5, 6, 7, 8}, suggestions); - EXPECT_THAT(suggestions, testing::ElementsAre(S({8, 9, 10}))); + dict.SuggestReplacement(S({5, 6, 7, 8}), suggestions); + EXPECT_THAT(suggestions, ElementsAre(EqByteSpan(S({8, 9, 10})))); - dict.SuggestReplacement({15, 16, 17, 18, 0, 0}, suggestions); - EXPECT_THAT(suggestions, testing::UnorderedElementsAre(S({11, 12, 13, 14}), - S({20, 21, 22}))); + dict.SuggestReplacement(S({15, 16, 17, 18, 0, 0}), suggestions); + EXPECT_THAT(suggestions, UnorderedElementsAre(EqByteSpan(S({11, 12, 13, 14})), + EqByteSpan(S({20, 21, 22})))); - dict.SuggestReplacement({15, 16, 20}, suggestions); - EXPECT_THAT(suggestions, testing::UnorderedElementsAre(S({30, 40, 50}))); + dict.SuggestReplacement(S({15, 16, 20}), suggestions); + EXPECT_THAT(suggestions, UnorderedElementsAre(EqByteSpan(S({30, 40, 50})))); // check that we don't exceed capacity. std::vector capacity1; capacity1.reserve(1); EXPECT_EQ(capacity1.capacity(), 1); - dict.SuggestReplacement({15, 16, 17, 18, 0, 0}, capacity1); + dict.SuggestReplacement(S({15, 16, 17, 18, 0, 0}), capacity1); EXPECT_EQ(capacity1.size(), 1); EXPECT_EQ(capacity1.capacity(), 1); } @@ -599,23 +603,23 @@ TEST(ByteArrayMutator, OverwriteFromDictionary) { } TEST(ByteArrayMutator, OverwriteFromCmpDictionary) { - TestMutatorFn(&ByteArrayMutator::OverwriteFromCmpDictionary, - {1, 2, 40, 50, 60}, - /*expected_mutants=*/ - { - {3, 4, 40, 50, 60}, - {1, 2, 10, 20, 30}, - }, - /*unexpected_mutants=*/ - { - {3, 4, 10, 20, 30}, - }, - /*size_alignment=*/1, - /*max_len=*/std::numeric_limits::max(), - /*dictionary=*/ - {}, - /*cmp_data=*/ - {/*args1*/ 2, 1, 2, 3, 4, /*args2*/ 3, 10, 20, 30, 40, 50, 60}); + TestMutatorFn( + &ByteArrayMutator::OverwriteFromCmpDictionary, {1, 2, 40, 50, 60}, + /*expected_mutants=*/ + { + {3, 4, 40, 50, 60}, + {1, 2, 10, 20, 30}, + }, + /*unexpected_mutants=*/ + { + {3, 4, 10, 20, 30}, + }, + /*size_alignment=*/1, + /*max_len=*/std::numeric_limits::max(), + /*dictionary=*/ + {}, + /*cmp_data=*/ + ByteSpan({/*args1*/ 2, 1, 2, 3, 4, /*args2*/ 3, 10, 20, 30, 40, 50, 60})); } TEST(ByteArrayMutator, OverwriteFromCmpDictionaryAndSkipLongEntry) { @@ -632,15 +636,17 @@ TEST(ByteArrayMutator, OverwriteFromCmpDictionaryAndSkipLongEntry) { /*max_len=*/std::numeric_limits::max(), /*dictionary=*/ {}, - /*cmp_data=*/ - {/*size*/ 20, /*lhs*/ 0, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, - /*rhs*/ 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, - /*size*/ 4, /*lhs*/ 0, 1, 2, 3, /*rhs*/ 100, 101, - 102, 103}); + /*cmp_data=*/ByteSpan({/*size*/ 20, /*lhs*/ 0, 1, 2, 3, + 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, + 19, + /*rhs*/ 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, + /*size*/ 4, /*lhs*/ 0, 1, 2, 3, + /*rhs*/ 100, 101, 102, 103})); } TEST(ByteArrayMutator, InsertFromDictionary) { diff --git a/centipede/centipede_interface.cc b/centipede/centipede_interface.cc index 7f073f0d..ecb791c3 100644 --- a/centipede/centipede_interface.cc +++ b/centipede/centipede_interface.cc @@ -115,7 +115,7 @@ int ForEachBlob(const Environment &env) { ByteSpan blob; while (blob_reader->Read(blob) == absl::OkStatus()) { ByteArray bytes; - bytes.insert(bytes.begin(), blob.data(), blob.end()); + bytes.insert(bytes.begin(), blob.begin(), blob.end()); // TODO(kcc): [impl] add a variant of WriteToLocalFile that accepts Span. WriteToLocalFile(tmpfile, bytes); std::string command_line = absl::StrReplaceAll( diff --git a/centipede/defs.h b/centipede/defs.h index e06baca9..fbc512c2 100644 --- a/centipede/defs.h +++ b/centipede/defs.h @@ -15,16 +15,15 @@ #ifndef THIRD_PARTY_CENTIPEDE_DEFS_H_ #define THIRD_PARTY_CENTIPEDE_DEFS_H_ // Only simple definitions here. No code, no dependencies. -// span.h is an exception as it's header-only and very simple. #include #include #include +#include "absl/types/span.h" + #include #include -#include "absl/types/span.h" - namespace centipede { // Just a good random number generator. @@ -32,7 +31,6 @@ using Rng = std::mt19937_64; using ByteArray = std::vector; using ByteSpan = absl::Span; - inline ByteSpan AsByteSpan(std::string_view str) { return ByteSpan(reinterpret_cast(str.data()), str.size()); } diff --git a/centipede/execution_metadata_test.cc b/centipede/execution_metadata_test.cc index 2c8e6d78..ad3c2b1d 100644 --- a/centipede/execution_metadata_test.cc +++ b/centipede/execution_metadata_test.cc @@ -14,16 +14,29 @@ #include "./centipede/execution_metadata.h" +#include #include #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "./centipede/defs.h" namespace centipede { namespace { using ::testing::IsEmpty; -using ::testing::UnorderedElementsAreArray; + +testing::Matcher>> +UnorderedElementsAre( + const std::vector>& expected) { + std::vector>> matchers; + for (const auto& p : expected) { + auto [v1, v2] = p; + matchers.push_back(testing::Pair(testing::ElementsAreArray(v1), + testing::ElementsAreArray(v2))); + } + return testing::UnorderedElementsAreArray(matchers); +} TEST(ExecutionMetadata, ForEachCmpEntryEnumeratesEntriesInRawBytes) { ExecutionMetadata metadata{.cmp_data = { @@ -38,14 +51,9 @@ TEST(ExecutionMetadata, ForEachCmpEntryEnumeratesEntriesInRawBytes) { std::vector> enumeration_result; EXPECT_TRUE(metadata.ForEachCmpEntry( [&](ByteSpan a, ByteSpan b) { enumeration_result.emplace_back(a, b); })); - - EXPECT_THAT( - enumeration_result, - UnorderedElementsAreArray(std::vector>{ - {{1, 2}, {3, 4}}, - {{}, {}}, - {{5, 6, 7}, {8, 9, 10}}, - })); + EXPECT_THAT(enumeration_result, + UnorderedElementsAre( + {{{1, 2}, {3, 4}}, {{}, {}}, {{5, 6, 7}, {8, 9, 10}}})); } TEST(ExecutionMetadata, ForEachCmpEntryHandlesEmptyCmpData) { @@ -64,21 +72,19 @@ TEST(ExecutionMetadata, TEST(ExecutionMetadata, ForEachCmpEntryEnumeratesEntriesFromAppendCmpEntry) { ExecutionMetadata metadata; - ASSERT_TRUE(metadata.AppendCmpEntry({1, 2}, {3, 4})); + ASSERT_TRUE(metadata.AppendCmpEntry(ByteSpan({1, 2}), ByteSpan({3, 4}))); std::vector> enumeration_result; EXPECT_TRUE(metadata.ForEachCmpEntry( [&](ByteSpan a, ByteSpan b) { enumeration_result.emplace_back(a, b); })); - EXPECT_THAT( - enumeration_result, - UnorderedElementsAreArray(std::vector>{ - {{1, 2}, {3, 4}}, - })); + EXPECT_THAT(enumeration_result, UnorderedElementsAre({ + {{1, 2}, {3, 4}}, + })); } TEST(ExecutionMetadata, AppendCmpEntryReturnsFalseAndSkipsOnBadArgs) { ExecutionMetadata metadata; // Sizes don't match. - EXPECT_FALSE(metadata.AppendCmpEntry({}, {1})); + EXPECT_FALSE(metadata.AppendCmpEntry(ByteSpan({}), ByteSpan({1}))); ByteArray long_byte_array; long_byte_array.resize(256); // Args too long. @@ -92,7 +98,7 @@ TEST(ExecutionMetadata, AppendCmpEntryReturnsFalseAndSkipsOnBadArgs) { TEST(ExecutionMetadata, ReadAndWriteKeepsCmpEntries) { ExecutionMetadata metadata_in; - ASSERT_TRUE(metadata_in.AppendCmpEntry({1, 2}, {3, 4})); + ASSERT_TRUE(metadata_in.AppendCmpEntry(ByteSpan({1, 2}), ByteSpan({3, 4}))); SharedMemoryBlobSequence blobseq("test", /*size=*/1024, /*use_posix_shmem=*/false); EXPECT_TRUE(metadata_in.Write(/*tag=*/1, blobseq)); @@ -103,11 +109,9 @@ TEST(ExecutionMetadata, ReadAndWriteKeepsCmpEntries) { std::vector> enumeration_result; EXPECT_TRUE(metadata_out.ForEachCmpEntry( [&](ByteSpan a, ByteSpan b) { enumeration_result.emplace_back(a, b); })); - EXPECT_THAT( - enumeration_result, - UnorderedElementsAreArray(std::vector>{ - {{1, 2}, {3, 4}}, - })); + EXPECT_THAT(enumeration_result, UnorderedElementsAre({ + {{1, 2}, {3, 4}}, + })); } } // namespace diff --git a/centipede/hash.cc b/centipede/hash.cc index 14a4d195..d31d5c63 100644 --- a/centipede/hash.cc +++ b/centipede/hash.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -40,6 +41,10 @@ std::string Hash(ByteSpan span) { return {sha1_hex_text, sha1_hex_text + kHashLen}; } +std::string Hash(std::initializer_list il) { + return Hash(ByteSpan(il)); +} + std::string Hash(std::string_view str) { static_assert(sizeof(decltype(str)::value_type) == sizeof(uint8_t)); return Hash(AsByteSpan(str)); diff --git a/centipede/minimize_crash_test.cc b/centipede/minimize_crash_test.cc index c4911de3..f5e9df70 100644 --- a/centipede/minimize_crash_test.cc +++ b/centipede/minimize_crash_test.cc @@ -83,7 +83,7 @@ TEST(MinimizeTest, MinimizeTest) { MinimizerMockFactory factory; // Test with a non-crashy input. - EXPECT_EQ(MinimizeCrash({1, 2, 3}, env, factory), EXIT_FAILURE); + EXPECT_EQ(MinimizeCrash(ByteSpan({1, 2, 3}), env, factory), EXIT_FAILURE); ByteArray expected_minimized = {'f', 'u', 'z'}; diff --git a/centipede/runner.cc b/centipede/runner.cc index 68a5308e..5cd0ea45 100644 --- a/centipede/runner.cc +++ b/centipede/runner.cc @@ -498,7 +498,7 @@ PostProcessCoverage(int target_return_value) { } void RunnerCallbacks::GetSeeds(std::function seed_callback) { - seed_callback({0}); + seed_callback(ByteSpan({0})); } class LegacyRunnerCallbacks : public RunnerCallbacks { diff --git a/centipede/runner_result_test.cc b/centipede/runner_result_test.cc index 19cb6602..095a672d 100644 --- a/centipede/runner_result_test.cc +++ b/centipede/runner_result_test.cc @@ -22,6 +22,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "./centipede/defs.h" #include "./centipede/feature.h" #include "./centipede/shared_memory_blob_sequence.h" #include "./centipede/test_util.h" @@ -38,7 +39,7 @@ TEST(ExecutionResult, WriteThenRead) { FeatureVec v1{1, 2, 3}; FeatureVec v2{5, 6, 7, 8}; ExecutionMetadata metadata; - metadata.AppendCmpEntry({1, 2, 3}, {4, 5, 6}); + metadata.AppendCmpEntry(ByteSpan({1, 2, 3}), ByteSpan({4, 5, 6})); ExecutionResult::Stats stats1{.peak_rss_mb = 10}; ExecutionResult::Stats stats2{.peak_rss_mb = 20}; // First input. @@ -102,7 +103,7 @@ TEST(ExecutionResult, WriteIntoFileThenRead) { ExecutionResult::Stats stats1{.peak_rss_mb = 10}; ExecutionResult::Stats stats2{.peak_rss_mb = 20}; ExecutionMetadata metadata; - metadata.AppendCmpEntry({1, 2, 3}, {4, 5, 6}); + metadata.AppendCmpEntry(ByteSpan({1, 2, 3}), ByteSpan({4, 5, 6})); std::vector buffer1(1000); BlobSequence blobseq1(buffer1.data(), buffer1.size()); diff --git a/centipede/test_util.h b/centipede/test_util.h index 394ac974..ce8056e6 100644 --- a/centipede/test_util.h +++ b/centipede/test_util.h @@ -18,6 +18,7 @@ #include #include +#include "gmock/gmock.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "./centipede/blob_file.h" @@ -122,6 +123,11 @@ class TempCorpusDir : public TempDir { std::unique_ptr reader_ = DefaultBlobFileReaderFactory(); }; +// A matcher for `ByteSpan` equality (`std::span` doesn't implement `op==`). +inline testing::Matcher EqByteSpan(const ByteSpan& expected) { + return testing::ElementsAreArray(expected); +} + } // namespace centipede #endif // THIRD_PARTY_CENTIPEDE_INTERNAL_TEST_UTIL_H_ diff --git a/centipede/testing/seeded_fuzz_target.cc b/centipede/testing/seeded_fuzz_target.cc index 4a552418..98028f59 100644 --- a/centipede/testing/seeded_fuzz_target.cc +++ b/centipede/testing/seeded_fuzz_target.cc @@ -31,14 +31,14 @@ class SeededRunnerCallbacks : public centipede::RunnerCallbacks { void GetSeeds(std::function seed_callback) override { constexpr size_t kNumAvailSeeds = 10; for (size_t i = 0; i < kNumAvailSeeds; ++i) - seed_callback({static_cast(i)}); + seed_callback(ByteSpan({static_cast(i)})); } bool Mutate(const std::vector &inputs, size_t num_mutants, std::function new_mutant_callback) override { // Should not be called in the test, but return a dummy mutant anyway. - new_mutant_callback({0}); + new_mutant_callback(ByteSpan({0})); return true; } }; diff --git a/centipede/util.h b/centipede/util.h index 4a705da2..f083f032 100644 --- a/centipede/util.h +++ b/centipede/util.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,8 @@ namespace centipede { std::string Hash(ByteSpan span); // Same as above, but for std::string_view. std::string Hash(std::string_view str); +// To be callable on braced lists. +std::string Hash(std::initializer_list il); // Hashes are always this many bytes. inline constexpr size_t kHashLen = 40; // Returns the hash of the contents of the file `file_path`. Supports the file