blob: 75c705f569263d54dd806ba6a0d179a4805c32b5 [file] [log] [blame]
// 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_