1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <stdio.h>
8 
9 #include <fuzz-utils/fuzzer.h>
10 #include <fuzz-utils/path.h>
11 #include <zircon/types.h>
12 
13 #include "fuzzer-fixture.h"
14 
15 namespace fuzzing {
16 namespace testing {
17 
18 // |fuzzing::testing::Fuzzer| exposes internal APIs for testing and buffers output.
19 class TestFuzzer : public Fuzzer {
20 public:
21     TestFuzzer();
22     ~TestFuzzer() override;
23 
fixture()24     const FuzzerFixture& fixture() const { return fixture_; }
25 
26     // Resets the out and err buffers to be unallocated.
27     void Reset() override;
28 
29     // Sets up the test fuzzer to buffer output with a Zircon-standalone test fixture
30     bool InitZircon();
31 
32     // Sets up the test fuzzer to buffer output with a test fixture of Fuchsia packages
33     bool InitFuchsia();
34 
35     // Resets |test| and reconstructs it from the |cmdline| in the context of the current fixture.
36     zx_status_t Eval(const char* cmdline);
37 
38     // Returns the value associated with the given |key|, or null if unset.
GetOption(const char * key)39     const char* GetOption(const char* key) { return options().get(key); }
40 
41     // Invoke the base method with the saved arguments.
Run()42     zx_status_t Run() { return Fuzzer::Run(&args_); }
43 
44     // Checks if the (case-insensitive) substring is in the buffered output
45     bool InStdOut(const char* needle);
46     bool InStdErr(const char* needle);
47 
48     // Returns the index in "argv" of the arg produced from |fmt| and any variadic parameters, or -1
49     // if it isn't found.
50     int FindArg(const char* fmt, const fbl::String& arg);
FindArg(const fbl::String & arg)51     int FindArg(const fbl::String& arg) { return FindArg("%s", arg); }
52 
53     // Various fixture locations
executable()54     const char* executable() const { return executable_.c_str(); }
manifest()55     const char* manifest() const { return manifest_.c_str(); }
dictionary()56     const char* dictionary() const { return dictionary_.c_str(); }
data_path()57     const char* data_path() const { return data_path_.c_str(); }
data_path(const char * relpath)58     fbl::String data_path(const char* relpath) { return data_path_.Join(relpath); }
59 
60     // Expose parent class methods
SetOption(const fbl::String & option)61     zx_status_t SetOption(const fbl::String& option) { return Fuzzer::SetOption(option); }
SetOption(const fbl::String & key,const fbl::String & val)62     zx_status_t SetOption(const fbl::String& key, const fbl::String& val) {
63         return Fuzzer::SetOption(key, val);
64     }
RebasePath(const fbl::String & package,Path * out)65     zx_status_t RebasePath(const fbl::String& package, Path* out) {
66         return Fuzzer::RebasePath(package, out);
67     }
GetPackagePath(const fbl::String & package,Path * out)68     zx_status_t GetPackagePath(const fbl::String& package, Path* out) {
69         return Fuzzer::GetPackagePath(package, out);
70     }
FindZirconFuzzers(const fbl::String & zircon_path,const fbl::String & target,StringMap * out)71     void FindZirconFuzzers(const fbl::String& zircon_path, const fbl::String& target,
72                            StringMap* out) {
73         Fuzzer::FindZirconFuzzers(zircon_path, target, out);
74     }
FindFuchsiaFuzzers(const fbl::String & package,const fbl::String & target,StringMap * out)75     void FindFuchsiaFuzzers(const fbl::String& package, const fbl::String& target, StringMap* out) {
76         Fuzzer::FindFuchsiaFuzzers(package, target, out);
77     }
FindFuzzers(const fbl::String & name,StringMap * out)78     void FindFuzzers(const fbl::String& name, StringMap* out) { Fuzzer::FindFuzzers(name, out); }
79 
80     // Exposes |Fuzzer::CheckProcess| optionally overriding the executable name to look for.
81     bool CheckProcess(zx_handle_t process, const char* executable = nullptr);
82 
83 protected:
84     // Overrides |Fuzzer::Execute| to simply save the subprocess' command line without spawning it.
85     zx_status_t Execute() override;
86 
87 private:
88     // Sets up the test fuzzer to buffer output without changing the test fixture
89     bool Init();
90 
91     // The current test fixture
92     FuzzerFixture fixture_;
93 
94     // The arguments passed to the subprocess
95     StringList args_;
96 
97     // Test info, captured by |Execute|
98     fbl::String executable_;
99     fbl::String manifest_;
100     fbl::String dictionary_;
101     Path data_path_;
102 
103     // Output stream
104     FILE* out_;
105     char* outbuf_;
106     size_t outbuflen_;
107 
108     // Error stream
109     FILE* err_;
110     char* errbuf_;
111     size_t errbuflen_;
112 };
113 
114 } // namespace testing
115 } // namespace fuzzing
116