# Copyright 2015 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Fuzzing Infrastructure Tests

import("//build/config/features.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//testing/test.gni")

group("tests") {
  testonly = true
  deps = [ ":fuzzing_unittests" ]
}

# Basic smoke tests for fuzzing
test("fuzzing_unittests") {
  sources = [ "fuzztest_cq_smoke_test.cc" ]
  fuzztests = [ "FuzzTestCqSmokeTest.StringsAlwaysOccupyPositiveSpace" ]

  deps = [
    "//base/test:run_all_unittests",
    "//base/test:test_support",
    "//testing/gtest",
    "//third_party/fuzztest",
  ]
  data_deps = []
  data = []
  defines = []

  if (use_fuzzing_engine) {
    sources += [
      "fuzz_target.cc",
      "fuzz_target.h",
      "fuzzer_smoke_test.cc",
      "stacktrace_test.cc",
    ]

    deps += [
      "//base",
      "//testing/gmock",
      "//testing/libfuzzer:buildflags",
    ]

    data_deps += [
      ":llvm_crashing_fuzzer",
      ":llvm_stub_fuzzer",
      ":lpm_stub_fuzzer",
      ":stacktrace_test_fuzzer",
    ]

    # The __generate targets (the wrappers) are only generated on Linux, Mac,
    # and Windows (see _building_fuzztest_fuzzer in testing/test.gni).
    if (use_fuzztest_wrapper && (is_linux || is_mac || is_win)) {
      data_deps += [
        ":fuzztest_crashing_fuzzer_FuzzTestCrashing_FastCrash_fuzzer__generate",
        ":fuzztest_proto_crashing_fuzzer_FuzzTestProtoCrashing_FastCrash_fuzzer__generate",
        ":fuzztest_proto_stub_fuzzer_FuzzTestProtoStub_Stub_fuzzer__generate",
        ":fuzztest_stub_fuzzer_FuzzTestStub_Stub_fuzzer__generate",
      ]
      if (use_centipede) {
        data_deps += [
          ":wrapped_llvm_crashing_fuzzer_LLVMFuzzer_TestOneInput_fuzzer__generate",
          ":wrapped_llvm_stub_fuzzer_LLVMFuzzer_TestOneInput_fuzzer__generate",
        ]
      }
    }

    data += [
      "data/check",
      "data/uaf",
    ]

    # TODO(crbug.com/40603084): Get these tests working on Windows.
    if (!is_win) {
      sources += [ "fuzzer_launcher_test.cc" ]
      deps += [ "//testing/libfuzzer:buildflags" ]
      data_deps += [
        ":check_fuzzer_config",
        ":check_seed_corpus_archive",
        ":test_config_and_dict",
        ":test_config_and_seed_corpus",
        ":test_config_and_seed_corpuses",
        ":test_config_only",
        ":test_dict_from_subdir",
        ":test_dict_only",
      ]
    }
  }
}

# These fuzzer targets' outputs serve as inputs to `fuzzer_launcher_test.cc`,
# which checks that `.options`, `.dict` and corpus files are generated
# correctly. Only compile them when compiling the test itself.
if (use_fuzzing_engine && !is_win) {
  fuzzer_test("test_dict_only") {
    sources = [ "llvm_stub_fuzzer.cc" ]
    dict = "test.dict"
    additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  }

  fuzzer_test("test_config_only") {
    sources = [ "llvm_stub_fuzzer.cc" ]
    libfuzzer_options = [
      "some_test_option=test_value",
      "max_len=1024",
    ]
    additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  }

  fuzzer_test("test_config_and_dict") {
    sources = [ "llvm_stub_fuzzer.cc" ]
    dict = "test.dict"
    libfuzzer_options = [
      "max_len=random(1337, 31337)",
      "timeout   =   666",
      "use_traces=1",
    ]
    additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  }

  fuzzer_test("test_config_and_seed_corpus") {
    sources = [ "llvm_stub_fuzzer.cc" ]
    seed_corpus = "test_corpus"
    libfuzzer_options = [
      "some_test_option=test_value",
      "max_len=1024",
    ]
    additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  }

  fuzzer_test("test_config_and_seed_corpuses") {
    sources = [ "llvm_stub_fuzzer.cc" ]
    seed_corpuses = [
      "test_corpus",
      "test_corpus_2",
    ]
    libfuzzer_options = [
      "some_test_option=another_test_value",
      "max_len=1337",
    ]
    additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  }

  fuzzer_test("test_dict_from_subdir") {
    sources = [ "llvm_stub_fuzzer.cc" ]
    dict = "dicts_subdir/test_subdir.dict"
    additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  }

  copy("check_fuzzer_config") {
    sources = [ "check_fuzzer_config.py" ]
    outputs = [ "$root_build_dir/check_fuzzer_config.py" ]
  }

  copy("check_seed_corpus_archive") {
    sources = [ "check_seed_corpus_archive.py" ]
    outputs = [ "$root_build_dir/check_seed_corpus_archive.py" ]
  }
}

# Test fuzzer targets used as fixtures for the smoke tests in this directory.
# All targets are marked with `no_clusterfuzz` to prevent continuous fuzzing on
# ClusterFuzz bots.

# To catch bugs that only present themselves in content fuzzers, e.g.
# https://crbug.com/524216727, depend on content when possible. In component
# builds, //content/public/browser brings in many shared libraries. Centipede
# attempts to symbolize all of them, which causes the tests to time out. Avoid
# bringing in so many symbols to avoid this.
_test_fuzzer_extra_deps = []
if (use_blink && !use_centipede) {
  _test_fuzzer_extra_deps += [ "//content/public/browser" ]
}

fuzzer_test("llvm_stub_fuzzer") {
  sources = [ "llvm_stub_fuzzer.cc" ]
  deps = _test_fuzzer_extra_deps
  additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  is_fuzztest_compatible = false
}

fuzzer_test("llvm_crashing_fuzzer") {
  sources = [ "llvm_crashing_fuzzer.cc" ]
  deps = [ "//base" ]
  deps += _test_fuzzer_extra_deps
  additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  is_fuzztest_compatible = false
}

# Regression test fuzzer for LPM.
fuzzer_test("lpm_stub_fuzzer") {
  sources = [ "lpm_stub_fuzzer.cc" ]
  deps = [ "//third_party/libprotobuf-mutator" ]
  deps += _test_fuzzer_extra_deps
  additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  is_fuzztest_compatible = false
}

test("fuzztest_stub_fuzzer") {
  sources = [ "fuzztest_stub_fuzzer.cc" ]
  fuzztests = [ "FuzzTestStub.Stub" ]
  deps = [ "//third_party/fuzztest:fuzztest_gtest_main" ]
  deps += _test_fuzzer_extra_deps
  configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
}

test("fuzztest_crashing_fuzzer") {
  sources = [ "fuzztest_crashing_fuzzer.cc" ]
  fuzztests = [ "FuzzTestCrashing.FastCrash" ]
  deps = [
    "//base",
    "//third_party/fuzztest:fuzztest_gtest_main",
  ]
  deps += _test_fuzzer_extra_deps
  configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
}

test("fuzztest_proto_stub_fuzzer") {
  sources = [ "fuzztest_proto_stub_fuzzer.cc" ]
  fuzztests = [ "FuzzTestProtoStub.Stub" ]
  deps = [
    "//testing/libfuzzer/proto:string_compare_proto_fuzzable",
    "//third_party/fuzztest:fuzztest_gtest_main",
  ]
  deps += _test_fuzzer_extra_deps
  configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
}

test("fuzztest_proto_crashing_fuzzer") {
  sources = [ "fuzztest_proto_crashing_fuzzer.cc" ]
  fuzztests = [ "FuzzTestProtoCrashing.FastCrash" ]
  deps = [
    "//base",
    "//testing/libfuzzer/proto:string_compare_proto_fuzzable",
    "//third_party/fuzztest:fuzztest_gtest_main",
  ]
  deps += _test_fuzzer_extra_deps
  configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
}

if (use_centipede) {
  test("wrapped_llvm_stub_fuzzer") {
    sources = [ "llvm_stub_fuzzer.cc" ]
    fuzztests = [ "LLVMFuzzer.TestOneInput" ]
    deps = [ "//third_party/fuzztest:llvm_wrapper" ]
    deps += _test_fuzzer_extra_deps
    configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
  }

  test("wrapped_llvm_crashing_fuzzer") {
    sources = [ "llvm_crashing_fuzzer.cc" ]
    fuzztests = [ "LLVMFuzzer.TestOneInput" ]
    deps = [
      "//base",
      "//third_party/fuzztest:llvm_wrapper",
    ]
    deps += _test_fuzzer_extra_deps
    configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
  }
}

fuzzer_test("stacktrace_test_fuzzer") {
  sources = [ "stacktrace_test_fuzzer.cc" ]
  deps = [
    "//base",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
  ]
  additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]

  # TODO(crbug.com/509668952): Remove this when FuzzTest is supported by tests.
  is_fuzztest_compatible = false
}
