// Copyright 2020 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.

use {arbitrary::Arbitrary, fuzz::fuzz};

// This is the "library code" tested in this example.
#[derive(Arbitrary)]
pub struct ToyStruct {
    n: u8,
    s: String,
}

pub fn toy_example(input: ToyStruct) -> Result<u8, &'static str> {
    if input.n != 42 {
        return Err("n must be 42");
    }
    let mut chars = input.s.chars();
    if chars.next() == Some('H') {
        if chars.next() == Some('I') {
            if chars.next() == Some('!') {
                panic!("it works!");
            }
        }
    }
    return Ok(0);
}

// This is the "fuzzer code" for the library code above.
// It can typically be placed alongside that code and will only be compiled when fuzzing.

// "Automatic" transform: Use one or more immutable types that implement `Arbitrary` as inputs.
#[fuzz]
fn toy_example_arbitrary(input1: ToyStruct, input2: ToyStruct) -> Result<u8, &'static str> {
    let _ = toy_example(input1);
    toy_example(input2) // Arbitrary return values are okay.
}

// "Manual" transform: convert a reference to an immutable byte slice to inputs.
#[fuzz]
fn toy_example_u8(input: &[u8]) {
    if input.len() == 0 {
        return; // Early returns are okay.
    }
    let n = input[0];
    if let Ok(s) = std::str::from_utf8(&input[1..]) {
        let _ = toy_example(ToyStruct { n, s: s.to_string() });
    }
}

// You can reuse the same name with `[#fuzz]` in different modules. Compare this function with
// `helper::toy_example_same_name`.
#[fuzz]
fn toy_example_same_name(input: String) {
    use helper;
    helper::toy_example(helper::add_bang(input));
}
