mirror of
https://github.com/sharkdp/hyperfine.git
synced 2024-11-26 03:25:46 +03:00
Split range into range_step and commands
This commit is contained in:
parent
a6baf49b72
commit
6db82cdb2a
180
src/command.rs
180
src/command.rs
@ -1,8 +1,11 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::error::OptionsError;
|
||||
use crate::parameter::range::get_parameterized_commands;
|
||||
use crate::{
|
||||
error::{OptionsError, ParameterScanError},
|
||||
parameter::range_step::{Numeric, RangeStep},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
|
||||
@ -10,6 +13,8 @@ use crate::parameter::tokenize::tokenize;
|
||||
use crate::parameter::ParameterValue;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use clap::Values;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
/// A command that should be benchmarked.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -103,10 +108,96 @@ fn find_duplicates<'a, I: IntoIterator<Item = &'a str>>(i: I) -> Vec<&'a str> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn build_parameterized_commands<'a, T: Numeric>(
|
||||
param_min: T,
|
||||
param_max: T,
|
||||
step: T,
|
||||
command_names: Vec<&'a str>,
|
||||
command_strings: Vec<&'a str>,
|
||||
param_name: &'a str,
|
||||
) -> Result<Vec<Command<'a>>, ParameterScanError> {
|
||||
let param_range = RangeStep::new(param_min, param_max, step)?;
|
||||
let param_count = param_range.size_hint().1.unwrap();
|
||||
let command_name_count = command_names.len();
|
||||
|
||||
// `--command-name` should appear exactly once or exactly B times,
|
||||
// where B is the total number of benchmarks.
|
||||
if command_name_count > 1 && command_name_count != param_count {
|
||||
return Err(ParameterScanError::UnexpectedCommandNameCount(
|
||||
command_name_count,
|
||||
param_count,
|
||||
));
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let mut commands = vec![];
|
||||
for value in param_range {
|
||||
for cmd in &command_strings {
|
||||
let name = command_names
|
||||
.get(i)
|
||||
.or_else(|| command_names.get(0))
|
||||
.copied();
|
||||
commands.push(Command::new_parametrized(
|
||||
name,
|
||||
cmd,
|
||||
vec![(param_name, ParameterValue::Numeric(value.into()))],
|
||||
));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
Ok(commands)
|
||||
}
|
||||
|
||||
fn get_parameterized_commands<'a>(
|
||||
command_names: Option<Values<'a>>,
|
||||
command_strings: Values<'a>,
|
||||
mut vals: clap::Values<'a>,
|
||||
step: Option<&str>,
|
||||
) -> Result<Vec<Command<'a>>, ParameterScanError> {
|
||||
let command_names = command_names.map_or(vec![], |names| names.collect::<Vec<&str>>());
|
||||
let command_strings = command_strings.collect::<Vec<&str>>();
|
||||
let param_name = vals.next().unwrap();
|
||||
let param_min = vals.next().unwrap();
|
||||
let param_max = vals.next().unwrap();
|
||||
|
||||
// attempt to parse as integers
|
||||
if let (Ok(param_min), Ok(param_max), Ok(step)) = (
|
||||
param_min.parse::<i32>(),
|
||||
param_max.parse::<i32>(),
|
||||
step.unwrap_or("1").parse::<i32>(),
|
||||
) {
|
||||
return build_parameterized_commands(
|
||||
param_min,
|
||||
param_max,
|
||||
step,
|
||||
command_names,
|
||||
command_strings,
|
||||
param_name,
|
||||
);
|
||||
}
|
||||
|
||||
// try parsing them as decimals
|
||||
let param_min = Decimal::from_str(param_min)?;
|
||||
let param_max = Decimal::from_str(param_max)?;
|
||||
|
||||
if step.is_none() {
|
||||
return Err(ParameterScanError::StepRequired);
|
||||
}
|
||||
|
||||
let step = Decimal::from_str(step.unwrap())?;
|
||||
build_parameterized_commands(
|
||||
param_min,
|
||||
param_max,
|
||||
step,
|
||||
command_names,
|
||||
command_strings,
|
||||
param_name,
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Commands<'a>(Vec<Command<'a>>);
|
||||
|
||||
impl<'a> Commands<'a> {
|
||||
/// Build the commands to benchmark
|
||||
pub fn from_cli_arguments(matches: &'a ArgMatches) -> Result<Commands> {
|
||||
let command_names = matches.values_of("command-name");
|
||||
let command_strings = matches.values_of("command").unwrap();
|
||||
@ -335,3 +426,86 @@ fn test_build_parameter_range_commands() {
|
||||
assert_eq!(commands[0].get_shell_command(), "echo 1");
|
||||
assert_eq!(commands[1].get_shell_command(), "echo 2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_parameterized_commands_int() {
|
||||
let commands =
|
||||
build_parameterized_commands(1i32, 7i32, 3i32, vec![], vec!["echo {val}"], "val").unwrap();
|
||||
assert_eq!(commands.len(), 3);
|
||||
assert_eq!(commands[2].get_name(), "echo 7");
|
||||
assert_eq!(commands[2].get_shell_command(), "echo 7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_parameterized_commands_decimal() {
|
||||
let param_min = Decimal::from_str("0").unwrap();
|
||||
let param_max = Decimal::from_str("1").unwrap();
|
||||
let step = Decimal::from_str("0.33").unwrap();
|
||||
|
||||
let commands = build_parameterized_commands(
|
||||
param_min,
|
||||
param_max,
|
||||
step,
|
||||
vec![],
|
||||
vec!["echo {val}"],
|
||||
"val",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(commands.len(), 4);
|
||||
assert_eq!(commands[3].get_name(), "echo 0.99");
|
||||
assert_eq!(commands[3].get_shell_command(), "echo 0.99");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_parameterized_command_names() {
|
||||
let commands = build_parameterized_commands(
|
||||
1i32,
|
||||
3i32,
|
||||
1i32,
|
||||
vec!["name-{val}"],
|
||||
vec!["echo {val}"],
|
||||
"val",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(commands.len(), 3);
|
||||
let command_names = commands
|
||||
.iter()
|
||||
.map(|c| c.get_name())
|
||||
.collect::<Vec<String>>();
|
||||
assert_eq!(command_names, vec!["name-1", "name-2", "name-3"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_specified_command_names() {
|
||||
let commands = build_parameterized_commands(
|
||||
1i32,
|
||||
3i32,
|
||||
1i32,
|
||||
vec!["name-a", "name-b", "name-c"],
|
||||
vec!["echo {val}"],
|
||||
"val",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(commands.len(), 3);
|
||||
let command_names = commands
|
||||
.iter()
|
||||
.map(|c| c.get_name())
|
||||
.collect::<Vec<String>>();
|
||||
assert_eq!(command_names, vec!["name-a", "name-b", "name-c"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_command_name_count_with_parameters() {
|
||||
let result = build_parameterized_commands(
|
||||
1i32,
|
||||
3i32,
|
||||
1i32,
|
||||
vec!["name-1", "name-2"],
|
||||
vec!["echo {val}"],
|
||||
"val",
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", result.unwrap_err()),
|
||||
"'--command-name' has been specified 2 times. It has to appear exactly once, or exactly 3 times (number of benchmarks)"
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::util::number::Number;
|
||||
|
||||
pub mod range;
|
||||
pub mod range_step;
|
||||
pub mod tokenize;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -1,318 +0,0 @@
|
||||
use std::convert::TryInto;
|
||||
use std::ops::{Add, AddAssign, Div, Sub};
|
||||
use std::str::FromStr;
|
||||
|
||||
use clap::Values;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
use super::ParameterValue;
|
||||
use crate::command::Command;
|
||||
use crate::error::ParameterScanError;
|
||||
use crate::util::number::Number;
|
||||
|
||||
trait Numeric:
|
||||
Add<Output = Self>
|
||||
+ Sub<Output = Self>
|
||||
+ Div<Output = Self>
|
||||
+ AddAssign
|
||||
+ PartialOrd
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ From<i32>
|
||||
+ Into<Number>
|
||||
{
|
||||
}
|
||||
impl<
|
||||
T: Add<Output = Self>
|
||||
+ Sub<Output = Self>
|
||||
+ Div<Output = Self>
|
||||
+ AddAssign
|
||||
+ PartialOrd
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ From<i32>
|
||||
+ Into<Number>,
|
||||
> Numeric for T
|
||||
{
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RangeStep<T> {
|
||||
state: T,
|
||||
end: T,
|
||||
step: T,
|
||||
}
|
||||
|
||||
impl<T: Numeric> RangeStep<T> {
|
||||
fn new(start: T, end: T, step: T) -> Result<Self, ParameterScanError> {
|
||||
if end < start {
|
||||
return Err(ParameterScanError::EmptyRange);
|
||||
}
|
||||
|
||||
if step == T::from(0) {
|
||||
return Err(ParameterScanError::ZeroStep);
|
||||
}
|
||||
|
||||
const MAX_PARAMETERS: usize = 100_000;
|
||||
match range_step_size_hint(start, end, step) {
|
||||
(_, Some(size)) if size <= MAX_PARAMETERS => Ok(Self {
|
||||
state: start,
|
||||
end,
|
||||
step,
|
||||
}),
|
||||
_ => Err(ParameterScanError::TooLarge),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Numeric> Iterator for RangeStep<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.state > self.end {
|
||||
return None;
|
||||
}
|
||||
let return_val = self.state;
|
||||
self.state += self.step;
|
||||
|
||||
Some(return_val)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
range_step_size_hint(self.state, self.end, self.step)
|
||||
}
|
||||
}
|
||||
|
||||
fn range_step_size_hint<T: Numeric>(start: T, end: T, step: T) -> (usize, Option<usize>) {
|
||||
if step == T::from(0) {
|
||||
return (usize::MAX, None);
|
||||
}
|
||||
|
||||
let steps = (end - start + T::from(1)) / step;
|
||||
steps
|
||||
.into()
|
||||
.try_into()
|
||||
.map_or((usize::MAX, None), |u| (u, Some(u)))
|
||||
}
|
||||
|
||||
fn build_parameterized_commands<'a, T: Numeric>(
|
||||
param_min: T,
|
||||
param_max: T,
|
||||
step: T,
|
||||
command_names: Vec<&'a str>,
|
||||
command_strings: Vec<&'a str>,
|
||||
param_name: &'a str,
|
||||
) -> Result<Vec<Command<'a>>, ParameterScanError> {
|
||||
let param_range = RangeStep::new(param_min, param_max, step)?;
|
||||
let param_count = param_range.size_hint().1.unwrap();
|
||||
let command_name_count = command_names.len();
|
||||
|
||||
// `--command-name` should appear exactly once or exactly B times,
|
||||
// where B is the total number of benchmarks.
|
||||
if command_name_count > 1 && command_name_count != param_count {
|
||||
return Err(ParameterScanError::UnexpectedCommandNameCount(
|
||||
command_name_count,
|
||||
param_count,
|
||||
));
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let mut commands = vec![];
|
||||
for value in param_range {
|
||||
for cmd in &command_strings {
|
||||
let name = command_names
|
||||
.get(i)
|
||||
.or_else(|| command_names.get(0))
|
||||
.copied();
|
||||
commands.push(Command::new_parametrized(
|
||||
name,
|
||||
cmd,
|
||||
vec![(param_name, ParameterValue::Numeric(value.into()))],
|
||||
));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
Ok(commands)
|
||||
}
|
||||
|
||||
pub fn get_parameterized_commands<'a>(
|
||||
command_names: Option<Values<'a>>,
|
||||
command_strings: Values<'a>,
|
||||
mut vals: clap::Values<'a>,
|
||||
step: Option<&str>,
|
||||
) -> Result<Vec<Command<'a>>, ParameterScanError> {
|
||||
let command_names = command_names.map_or(vec![], |names| names.collect::<Vec<&str>>());
|
||||
let command_strings = command_strings.collect::<Vec<&str>>();
|
||||
let param_name = vals.next().unwrap();
|
||||
let param_min = vals.next().unwrap();
|
||||
let param_max = vals.next().unwrap();
|
||||
|
||||
// attempt to parse as integers
|
||||
if let (Ok(param_min), Ok(param_max), Ok(step)) = (
|
||||
param_min.parse::<i32>(),
|
||||
param_max.parse::<i32>(),
|
||||
step.unwrap_or("1").parse::<i32>(),
|
||||
) {
|
||||
return build_parameterized_commands(
|
||||
param_min,
|
||||
param_max,
|
||||
step,
|
||||
command_names,
|
||||
command_strings,
|
||||
param_name,
|
||||
);
|
||||
}
|
||||
|
||||
// try parsing them as decimals
|
||||
let param_min = Decimal::from_str(param_min)?;
|
||||
let param_max = Decimal::from_str(param_max)?;
|
||||
|
||||
if step.is_none() {
|
||||
return Err(ParameterScanError::StepRequired);
|
||||
}
|
||||
|
||||
let step = Decimal::from_str(step.unwrap())?;
|
||||
build_parameterized_commands(
|
||||
param_min,
|
||||
param_max,
|
||||
step,
|
||||
command_names,
|
||||
command_strings,
|
||||
param_name,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_integer_range() {
|
||||
let param_range: Vec<i32> = RangeStep::new(0, 10, 3).unwrap().collect();
|
||||
|
||||
assert_eq!(param_range.len(), 4);
|
||||
assert_eq!(param_range[0], 0);
|
||||
assert_eq!(param_range[3], 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decimal_range() {
|
||||
let param_min = Decimal::from(0);
|
||||
let param_max = Decimal::from(1);
|
||||
let step = Decimal::from_str("0.1").unwrap();
|
||||
|
||||
let param_range: Vec<Decimal> = RangeStep::new(param_min, param_max, step)
|
||||
.unwrap()
|
||||
.collect();
|
||||
|
||||
assert_eq!(param_range.len(), 11);
|
||||
assert_eq!(param_range[0], Decimal::from(0));
|
||||
assert_eq!(param_range[10], Decimal::from(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_step_validate() {
|
||||
let result = RangeStep::new(0, 10, 3);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let result = RangeStep::new(
|
||||
Decimal::from(0),
|
||||
Decimal::from(1),
|
||||
Decimal::from_str("0.1").unwrap(),
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let result = RangeStep::new(11, 10, 1);
|
||||
assert_eq!(format!("{}", result.unwrap_err()), "Empty parameter range");
|
||||
|
||||
let result = RangeStep::new(0, 10, 0);
|
||||
assert_eq!(
|
||||
format!("{}", result.unwrap_err()),
|
||||
"Zero is not a valid parameter step"
|
||||
);
|
||||
|
||||
let result = RangeStep::new(0, 100_001, 1);
|
||||
assert_eq!(
|
||||
format!("{}", result.unwrap_err()),
|
||||
"Parameter range is too large"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_parameterized_commands_int() {
|
||||
let commands =
|
||||
build_parameterized_commands(1i32, 7i32, 3i32, vec![], vec!["echo {val}"], "val").unwrap();
|
||||
assert_eq!(commands.len(), 3);
|
||||
assert_eq!(commands[2].get_name(), "echo 7");
|
||||
assert_eq!(commands[2].get_shell_command(), "echo 7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_parameterized_commands_decimal() {
|
||||
let param_min = Decimal::from_str("0").unwrap();
|
||||
let param_max = Decimal::from_str("1").unwrap();
|
||||
let step = Decimal::from_str("0.33").unwrap();
|
||||
|
||||
let commands = build_parameterized_commands(
|
||||
param_min,
|
||||
param_max,
|
||||
step,
|
||||
vec![],
|
||||
vec!["echo {val}"],
|
||||
"val",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(commands.len(), 4);
|
||||
assert_eq!(commands[3].get_name(), "echo 0.99");
|
||||
assert_eq!(commands[3].get_shell_command(), "echo 0.99");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_parameterized_command_names() {
|
||||
let commands = build_parameterized_commands(
|
||||
1i32,
|
||||
3i32,
|
||||
1i32,
|
||||
vec!["name-{val}"],
|
||||
vec!["echo {val}"],
|
||||
"val",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(commands.len(), 3);
|
||||
let command_names = commands
|
||||
.iter()
|
||||
.map(|c| c.get_name())
|
||||
.collect::<Vec<String>>();
|
||||
assert_eq!(command_names, vec!["name-1", "name-2", "name-3"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_specified_command_names() {
|
||||
let commands = build_parameterized_commands(
|
||||
1i32,
|
||||
3i32,
|
||||
1i32,
|
||||
vec!["name-a", "name-b", "name-c"],
|
||||
vec!["echo {val}"],
|
||||
"val",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(commands.len(), 3);
|
||||
let command_names = commands
|
||||
.iter()
|
||||
.map(|c| c.get_name())
|
||||
.collect::<Vec<String>>();
|
||||
assert_eq!(command_names, vec!["name-a", "name-b", "name-c"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_command_name_count_with_parameters() {
|
||||
let result = build_parameterized_commands(
|
||||
1i32,
|
||||
3i32,
|
||||
1i32,
|
||||
vec!["name-1", "name-2"],
|
||||
vec!["echo {val}"],
|
||||
"val",
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", result.unwrap_err()),
|
||||
"'--command-name' has been specified 2 times. It has to appear exactly once, or exactly 3 times (number of benchmarks)"
|
||||
);
|
||||
}
|
150
src/parameter/range_step.rs
Normal file
150
src/parameter/range_step.rs
Normal file
@ -0,0 +1,150 @@
|
||||
use std::convert::TryInto;
|
||||
use std::ops::{Add, AddAssign, Div, Sub};
|
||||
|
||||
use crate::error::ParameterScanError;
|
||||
use crate::util::number::Number;
|
||||
|
||||
pub trait Numeric:
|
||||
Add<Output = Self>
|
||||
+ Sub<Output = Self>
|
||||
+ Div<Output = Self>
|
||||
+ AddAssign
|
||||
+ PartialOrd
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ From<i32>
|
||||
+ Into<Number>
|
||||
{
|
||||
}
|
||||
impl<
|
||||
T: Add<Output = Self>
|
||||
+ Sub<Output = Self>
|
||||
+ Div<Output = Self>
|
||||
+ AddAssign
|
||||
+ PartialOrd
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ From<i32>
|
||||
+ Into<Number>,
|
||||
> Numeric for T
|
||||
{
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RangeStep<T> {
|
||||
state: T,
|
||||
end: T,
|
||||
step: T,
|
||||
}
|
||||
|
||||
impl<T: Numeric> RangeStep<T> {
|
||||
pub fn new(start: T, end: T, step: T) -> Result<Self, ParameterScanError> {
|
||||
if end < start {
|
||||
return Err(ParameterScanError::EmptyRange);
|
||||
}
|
||||
|
||||
if step == T::from(0) {
|
||||
return Err(ParameterScanError::ZeroStep);
|
||||
}
|
||||
|
||||
const MAX_PARAMETERS: usize = 100_000;
|
||||
match range_step_size_hint(start, end, step) {
|
||||
(_, Some(size)) if size <= MAX_PARAMETERS => Ok(Self {
|
||||
state: start,
|
||||
end,
|
||||
step,
|
||||
}),
|
||||
_ => Err(ParameterScanError::TooLarge),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Numeric> Iterator for RangeStep<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.state > self.end {
|
||||
return None;
|
||||
}
|
||||
let return_val = self.state;
|
||||
self.state += self.step;
|
||||
|
||||
Some(return_val)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
range_step_size_hint(self.state, self.end, self.step)
|
||||
}
|
||||
}
|
||||
|
||||
fn range_step_size_hint<T: Numeric>(start: T, end: T, step: T) -> (usize, Option<usize>) {
|
||||
if step == T::from(0) {
|
||||
return (usize::MAX, None);
|
||||
}
|
||||
|
||||
let steps = (end - start + T::from(1)) / step;
|
||||
steps
|
||||
.into()
|
||||
.try_into()
|
||||
.map_or((usize::MAX, None), |u| (u, Some(u)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use rust_decimal::Decimal;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn test_integer_range() {
|
||||
let param_range: Vec<i32> = RangeStep::new(0, 10, 3).unwrap().collect();
|
||||
|
||||
assert_eq!(param_range.len(), 4);
|
||||
assert_eq!(param_range[0], 0);
|
||||
assert_eq!(param_range[3], 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decimal_range() {
|
||||
let param_min = Decimal::from(0);
|
||||
let param_max = Decimal::from(1);
|
||||
let step = Decimal::from_str("0.1").unwrap();
|
||||
|
||||
let param_range: Vec<Decimal> = RangeStep::new(param_min, param_max, step)
|
||||
.unwrap()
|
||||
.collect();
|
||||
|
||||
assert_eq!(param_range.len(), 11);
|
||||
assert_eq!(param_range[0], Decimal::from(0));
|
||||
assert_eq!(param_range[10], Decimal::from(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_step_validate() {
|
||||
let result = RangeStep::new(0, 10, 3);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let result = RangeStep::new(
|
||||
Decimal::from(0),
|
||||
Decimal::from(1),
|
||||
Decimal::from_str("0.1").unwrap(),
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let result = RangeStep::new(11, 10, 1);
|
||||
assert_eq!(format!("{}", result.unwrap_err()), "Empty parameter range");
|
||||
|
||||
let result = RangeStep::new(0, 10, 0);
|
||||
assert_eq!(
|
||||
format!("{}", result.unwrap_err()),
|
||||
"Zero is not a valid parameter step"
|
||||
);
|
||||
|
||||
let result = RangeStep::new(0, 100_001, 1);
|
||||
assert_eq!(
|
||||
format!("{}", result.unwrap_err()),
|
||||
"Parameter range is too large"
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user