pw_fuzzer: Fix fuzz target unit tests

The path for the fuzzer unit test source was not source absolute.
Additionally, we need to provide a stub implementation of
FuzzedDataProvider when not using clang.

Change-Id: I440125b5aa86b6c1d1a194c399d8de6f53f58d48
diff --git a/pw_fuzzer/BUILD.gn b/pw_fuzzer/BUILD.gn
index 36f4cb4..479fcb8 100644
--- a/pw_fuzzer/BUILD.gn
+++ b/pw_fuzzer/BUILD.gn
@@ -21,8 +21,12 @@
   pw_sanitizer = ""
 }
 
+config("default_config") {
+  include_dirs = [ "public" ]
+}
+
 # This is added automatically by the `pw_fuzzer` template.
-config("pw_fuzzer") {
+config("fuzzing") {
   common_flags = [ "-fsanitize=fuzzer" ]
   if (pw_sanitizer != "") {
     common_flags += [ "-fsanitize=$pw_sanitizer" ]
@@ -31,6 +35,22 @@
   ldflags = common_flags
 }
 
+source_set("pw_fuzzer") {
+  public_configs = [ ":default_config" ]
+  public = [ "public/pw_fuzzer/fuzzed_data_provider.h" ]
+  sources = public
+  public_deps = [ "$dir_pw_log" ]
+}
+
+# See https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode
+config("fuzzing_build_mode_unsafe_for_production") {
+  defines = [ "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION" ]
+}
+
+config("fuzzing_verbose_logging") {
+  defines = [ "FUZZING_VERBOSE_LOGGING" ]
+}
+
 pw_doc_group("docs") {
   inputs = [ "doc_resources/pw_fuzzer_coverage_guided.png" ]
   sources = [ "docs.rst" ]
diff --git a/pw_fuzzer/fuzzer.gni b/pw_fuzzer/fuzzer.gni
index 4e0eefb..07f9562 100644
--- a/pw_fuzzer/fuzzer.gni
+++ b/pw_fuzzer/fuzzer.gni
@@ -39,7 +39,10 @@
       configs = []
       forward_variables_from(invoker, "*", [ "visibility" ])
       forward_variables_from(invoker, [ "visibility" ])
-      configs += [ "$dir_pw_fuzzer" ]
+      configs += [
+        "$dir_pw_fuzzer:default_config",
+        "$dir_pw_fuzzer:fuzzing",
+      ]
     }
 
     # Dummy target to satisfy `pw_test_group`. It is empty as we don't want to
@@ -50,10 +53,12 @@
     # Build a unit test that exercise the fuzz target function.
     pw_test(target_name) {
       sources = []
+      configs = []
       deps = []
       forward_variables_from(invoker, "*", [ "visibility" ])
       forward_variables_from(invoker, [ "visibility" ])
-      sources += [ "pw_fuzzer_disabled.cc" ]
+      sources += [ "$dir_pw_fuzzer/pw_fuzzer_disabled.cc" ]
+      configs += [ "$dir_pw_fuzzer:default_config" ]
       deps += [
         "$dir_pw_log",
         "$dir_pw_unit_test",
diff --git a/pw_fuzzer/public/pw_fuzzer/fuzzed_data_provider.h b/pw_fuzzer/public/pw_fuzzer/fuzzed_data_provider.h
new file mode 100644
index 0000000..a136da2
--- /dev/null
+++ b/pw_fuzzer/public/pw_fuzzer/fuzzed_data_provider.h
@@ -0,0 +1,139 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// Simply forwards to <fuzzer/FuzzedDataProvider.h> when available from clang,
+// or provides a simple stub implementation.
+#pragma once
+
+#if defined(__clang__)
+#include <fuzzer/FuzzedDataProvider.h>
+#else  // !defined(__clang__)
+
+// If a fuzzer wants to use FuzzedDataProvider to build a fuzz target unit
+// test without clang, it can use this trivial class with the same signature.
+// The behavior will NOT be the same as a fuzzer unit test built by clang for
+// non-trivial inputs. This means non-clang fuzzer unit tests will not be
+// effective regression tests if given a seed corpus. These non-clang tests are
+// still useful, however, as they will guarantee the fuzzer code can compile and
+// link.
+//
+// The methods of this class are intentionally undocumented. To see the
+// documentation for each, consult the real header file, e.g. in
+// .cipd/pigweed/lib/clang/11.0.0/include/fuzzer/FuzzedDataProvider.h
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "pw_log/log.h"
+
+class FuzzedDataProvider {
+ public:
+  FuzzedDataProvider(const uint8_t* data, size_t size) {
+    PW_UNUSED(data);
+    PW_UNUSED(size);
+    PW_LOG_INFO("Fuzzing is disabled for the current compiler.");
+    PW_LOG_INFO("Using trivial stub implementation for FuzzedDataProvider.");
+  }
+
+  ~FuzzedDataProvider() = default;
+
+  template <typename T>
+  std::vector<T> ConsumeBytes(size_t num_bytes) {
+    PW_UNUSED(num_bytes);
+    return std::vector<T>{};
+  }
+
+  template <typename T>
+  std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes,
+                                            T terminator = 0) {
+    PW_UNUSED(num_bytes);
+    return std::vector<T>{terminator};
+  }
+
+  template <typename T>
+  std::vector<T> ConsumeRemainingBytes() {
+    return std::vector<T>{};
+  }
+
+  std::string ConsumeBytesAsString(size_t num_bytes) {
+    PW_UNUSED(num_bytes);
+    return std::string{};
+  }
+
+  std::string ConsumeRandomLengthString(size_t max_length) {
+    PW_UNUSED(max_length);
+    return std::string{};
+  }
+
+  std::string ConsumeRandomLengthString() { return std::string{}; }
+
+  std::string ConsumeRemainingBytesAsString() { return std::string{}; }
+
+  template <typename T>
+  T ConsumeIntegral() {
+    return T(0);
+  }
+
+  template <typename T>
+  T ConsumeIntegralInRange(T min, T max) {
+    PW_UNUSED(max);
+    return T(min);
+  }
+
+  template <typename T>
+  T ConsumeFloatingPoint() {
+    return T(0.0);
+  }
+
+  template <typename T>
+  T ConsumeFloatingPointInRange(T min, T max) {
+    PW_UNUSED(max);
+    return T(min);
+  }
+
+  template <typename T>
+  T ConsumeProbability() {
+    return T(0.0);
+  }
+
+  bool ConsumeBool() { return false; }
+
+  template <typename T>
+  T ConsumeEnum() {
+    return static_cast<T>(0);
+  }
+
+  template <typename T, size_t size>
+  T PickValueInArray(const T (&array)[size]) {
+    static_assert(size > 0, "The array must be non empty.");
+    return array[0];
+  }
+
+  template <typename T>
+  T PickValueInArray(std::initializer_list<const T> list) {
+    static_assert(list.size() > 0, "The list must be non empty.");
+    return *list.begin();
+  }
+
+  size_t ConsumeData(void* destination, size_t num_bytes) {
+    PW_UNUSED(destination);
+    PW_UNUSED(num_bytes);
+    return 0;
+  }
+
+  size_t remaining_bytes() { return 0; }
+};
+
+#endif  // defined(__clang__)
diff --git a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
index 55b157c..5cee92b 100755
--- a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
+++ b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
@@ -438,7 +438,7 @@
             missing_gn.append(path)
 
     # TODO(pwbug/176) Replace this workaround for fuzzers.
-    missing_bazel = [p for p in missing_bazel if 'fuzzer' not in p.name]
+    missing_bazel = [p for p in missing_bazel if 'fuzz' not in p.name]
 
     if missing_bazel or missing_gn:
         for build, files in [('Bazel', missing_bazel), ('GN', missing_gn)]: