1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// This file is part of Substrate.

// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// 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
//
// 	http://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.

//! # Running
//! Running this fuzzer can be done with `cargo hfuzz run per_thing_rational`. `honggfuzz` CLI options can
//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
//!
//! # Debugging a panic
//! Once a panic is found, it can be debugged with
//! `cargo hfuzz run-debug per_thing_rational hfuzz_workspace/per_thing_rational/*.fuzz`.

use honggfuzz::fuzz;
use sp_arithmetic::{traits::SaturatedConversion, PerThing, PerU16, Perbill, Percent, Perquintill};

fn main() {
	loop {
		fuzz!(|data: ((u16, u16), (u32, u32), (u64, u64))| {
			let (u16_pair, u32_pair, u64_pair) = data;

			// peru16
			let (smaller, bigger) = (u16_pair.0.min(u16_pair.1), u16_pair.0.max(u16_pair.1));
			let ratio = PerU16::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				PerU16::from_float(smaller as f64 / bigger.max(1) as f64),
				1,
			);
			let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1));
			let ratio = PerU16::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				PerU16::from_float(smaller as f64 / bigger.max(1) as f64),
				1,
			);
			let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1));
			let ratio = PerU16::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				PerU16::from_float(smaller as f64 / bigger.max(1) as f64),
				1,
			);

			// percent
			let (smaller, bigger) = (u16_pair.0.min(u16_pair.1), u16_pair.0.max(u16_pair.1));
			let ratio = Percent::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				Percent::from_float(smaller as f64 / bigger.max(1) as f64),
				1,
			);

			let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1));
			let ratio = Percent::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				Percent::from_float(smaller as f64 / bigger.max(1) as f64),
				1,
			);

			let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1));
			let ratio = Percent::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				Percent::from_float(smaller as f64 / bigger.max(1) as f64),
				1,
			);

			// perbill
			let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1));
			let ratio = Perbill::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				Perbill::from_float(smaller as f64 / bigger.max(1) as f64),
				100,
			);

			let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1));
			let ratio = Perbill::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				Perbill::from_float(smaller as f64 / bigger.max(1) as f64),
				100,
			);

			// perquintillion
			let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1));
			let ratio = Perquintill::from_rational(smaller, bigger);
			assert_per_thing_equal_error(
				ratio,
				Perquintill::from_float(smaller as f64 / bigger.max(1) as f64),
				1000,
			);
		})
	}
}

fn assert_per_thing_equal_error<P: PerThing>(a: P, b: P, err: u128) {
	let a_abs = a.deconstruct().saturated_into::<u128>();
	let b_abs = b.deconstruct().saturated_into::<u128>();
	let diff = a_abs.max(b_abs) - a_abs.min(b_abs);
	assert!(diff <= err, "{:?} !~ {:?}", a, b);
}