| // Copyright 2021 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef SRC_SYS_FUZZING_COMMON_TESTING_RUNNER_H_ | |
| #define SRC_SYS_FUZZING_COMMON_TESTING_RUNNER_H_ | |
| #include <fuchsia/fuzzer/cpp/fidl.h> | |
| #include <zircon/compiler.h> | |
| #include <vector> | |
| #include "src/lib/fxl/macros.h" | |
| #include "src/sys/fuzzing/common/async-types.h" | |
| #include "src/sys/fuzzing/common/runner.h" | |
| namespace fuzzing { | |
| // Fake command line argument recognized by this runner. | |
| extern const char* kFakeRunnerFlag; | |
| // This class implements |Runner| without actually running anything. For the fuzzing workflows, it | |
| // simply returns whatever results are preloaded by a unit test. | |
| class FakeRunner final : public Runner { | |
| public: | |
| ~FakeRunner() override = default; | |
| // Factory method. | |
| static RunnerPtr MakePtr(ExecutorPtr executor); | |
| static Input valid_dictionary() { return Input("key1=\"value\"\n"); } | |
| static Input invalid_dictionary() { return Input("invalid"); } | |
| bool has_flag() const { return flag_; } | |
| const std::vector<Input>& get_inputs() const { return inputs_; } | |
| void set_validation_error(zx_status_t error) { validation_error_ = error; } | |
| void set_error(zx_status_t error) { error_ = error; } | |
| void set_status(Status status) { status_ = std::move(status); } | |
| const std::vector<Input>& seed_corpus() const { return seed_corpus_; } | |
| const std::vector<Input>& live_corpus() const { return live_corpus_; } | |
| void set_seed_corpus(std::vector<Input>&& seed_corpus) { seed_corpus_ = std::move(seed_corpus); } | |
| void set_live_corpus(std::vector<Input>&& live_corpus) { live_corpus_ = std::move(live_corpus); } | |
| void set_result(FuzzResult result) { result_ = result; } | |
| void set_result_input(const Input& input) { result_input_ = input.Duplicate(); } | |
| // |Runner| methods. Since this runner does not have a "real" fuzzer engine, these use the | |
| // object's local variables to simulate the responses for the various `fuchsia.fuzzer.Controller` | |
| // methods, e.g. |TryOne| returns whatever was passed to |set_result|. | |
| ZxPromise<> Initialize(std::string pkg_dir, std::vector<std::string> args) override; | |
| __WARN_UNUSED_RESULT zx_status_t AddToCorpus(CorpusType corpus_type, Input input) override; | |
| std::vector<Input> GetCorpus(CorpusType corpus_type) override; | |
| __WARN_UNUSED_RESULT zx_status_t ParseDictionary(const Input& input) override; | |
| Input GetDictionaryAsInput() const override; | |
| using Runner::UpdateMonitors; | |
| ZxPromise<Artifact> Fuzz() override; | |
| ZxPromise<Artifact> TryEach(std::vector<Input> inputs) override; | |
| ZxPromise<Artifact> ValidateMinimize(Input input) override; | |
| ZxPromise<Artifact> Minimize(Artifact artifact) override; | |
| ZxPromise<Artifact> Cleanse(Input input) override; | |
| ZxPromise<> ValidateMerge() override; | |
| ZxPromise<Artifact> Merge() override; | |
| Status CollectStatus() override; | |
| ZxPromise<> Stop() override; | |
| Promise<> AwaitStop(); | |
| private: | |
| explicit FakeRunner(ExecutorPtr executor); | |
| ZxPromise<Artifact> Run(); | |
| bool flag_ = false; | |
| zx_status_t validation_error_ = ZX_OK; | |
| zx_status_t error_ = ZX_OK; | |
| std::vector<Input> inputs_; | |
| FuzzResult result_ = FuzzResult::NO_ERRORS; | |
| Input result_input_; | |
| Status status_; | |
| std::vector<Input> seed_corpus_; | |
| std::vector<Input> live_corpus_; | |
| Input dictionary_; | |
| Completer<> completer_; | |
| Consumer<> consumer_; | |
| Workflow workflow_; | |
| FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(FakeRunner); | |
| }; | |
| // Makes a packaged seed corpus suitable for testing. | |
| // Creates a directory at `pkg_path`. For each input in `inputs`, creates a file under `pkg_path` | |
| // with name and contents matching that input, and adds a corresponding `Input` to `out`. The | |
| // returned inputs are guaranteed to be sorted and unique. This should be called as part of a test | |
| // using `ASSERT_NO_FATAL_FAILURES`, e.g. | |
| // | |
| // std::vector<Input> corpus; | |
| // ASSERT_NO_FATAL_FAILURE(MakeCorpus("/tmp/my-test/corpus", {"foo", "bar"}, &corpus)); | |
| // | |
| void MakeCorpus(const std::string& pkg_path, std::initializer_list<const char*> inputs, | |
| std::vector<Input>* out); | |
| // Makes a packaged input file suitable for testing. | |
| // | |
| // Writes `contents` to a file at `pkg_path`, creating any intermediary directories in the | |
| // process. This should be called as part of a test using `ASSERT_NO_FATAL_FAILURES`, e.g. | |
| // | |
| // ASSERT_NO_FATAL_FAILURE(WriteInput("/tmp/my-test/dictionary", Input("key=\"val\"))); | |
| // | |
| void WriteInput(const std::string& pkg_path, Input contents); | |
| } // namespace fuzzing | |
| #endif // SRC_SYS_FUZZING_COMMON_TESTING_RUNNER_H_ |