New random_range and random_text commands #128

This commit is contained in:
sagie gur ari 2020-08-27 08:56:51 +00:00
parent fb13d11187
commit b267106753
13 changed files with 349 additions and 0 deletions

View File

@ -3,6 +3,7 @@
### v0.6.7
* New --get-exit-code flag for exec command #127
* New random_range and random_text commands #128
* New semver_parse, semver_is_equal and semver_is_newer commands #129
### v0.6.6 (2020-08-14)

View File

@ -129,6 +129,8 @@
* [std::process::ProcessID (pid, process_id)](#std__process__ProcessID)
* [std::process::Spawn (spawn)](#std__process__Spawn)
* [std::process::Watchdog (watchdog)](#std__process__Watchdog)
* [std::random::Range (random_range, rand_range)](#std__random__Range)
* [std::random::Text (random_text, rand_text)](#std__random__Text)
* [std::scope::Clear (clear_scope)](#std__scope__Clear)
* [std::scope::PopStack (scope_pop_stack)](#std__scope__PopStack)
* [std::scope::PushStack (scope_push_stack)](#std__scope__PushStack)
@ -4800,6 +4802,61 @@ assert_eq ${count} 4
#### Aliases:
watchdog
<a name="std__random__Range"></a>
## std::random::Range
```sh
output = random_range min max
```
Generate a random value in the range of min and max values provided, i.e. inclusive of min and exclusive of max.
#### Parameters
* min - The min range value (inclusive)
* max - The max range value (exclusive)
#### Return Value
The generated numeric value.
#### Examples
```sh
value = random_range -10 10
echo ${value}
```
#### Aliases:
random_range, rand_range
<a name="std__random__Text"></a>
## std::random::Text
```sh
output = random_text [length]
```
Generates random alphanumeric text with the requested length (length is 1 if not provided).
#### Parameters
Optional text length. Length is defaulted to 1 if not provided.
#### Return Value
The generated alphanumeric value.
#### Examples
```sh
value = random_text 50
echo ${value}
```
#### Aliases:
random_text, rand_text
<a name="std__scope__Clear"></a>
## std::scope::Clear
```sh

View File

@ -15,6 +15,7 @@ mod noop;
mod not;
pub(crate) mod on_error;
mod process;
mod random;
mod read;
pub(crate) mod release;
pub(crate) mod scope;
@ -51,6 +52,7 @@ pub(crate) fn load(commands: &mut Commands) -> Result<(), ScriptError> {
net::load(commands, PACKAGE)?;
on_error::load(commands, PACKAGE)?;
process::load(commands, PACKAGE)?;
random::load(commands, PACKAGE)?;
scope::load(commands, PACKAGE)?;
semver::load(commands, PACKAGE)?;
string::load(commands, PACKAGE)?;

View File

@ -0,0 +1,17 @@
mod range;
mod text;
use crate::utils::pckg;
use duckscript::types::command::Commands;
use duckscript::types::error::ScriptError;
static PACKAGE: &str = "random";
pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptError> {
let package = pckg::concat(parent, PACKAGE);
commands.set(range::create(&package))?;
commands.set(text::create(&package))?;
Ok(())
}

View File

@ -0,0 +1,21 @@
```sh
output = random_range min max
```
Generate a random value in the range of min and max values provided, i.e. inclusive of min and exclusive of max.
#### Parameters
* min - The min range value (inclusive)
* max - The max range value (exclusive)
#### Return Value
The generated numeric value.
#### Examples
```sh
value = random_range -10 10
echo ${value}
```

View File

@ -0,0 +1,69 @@
use crate::utils::pckg;
use duckscript::types::command::{Command, CommandResult};
use rand::{thread_rng, Rng};
#[cfg(test)]
#[path = "./mod_test.rs"]
mod mod_test;
#[derive(Clone)]
pub(crate) struct CommandImpl {
package: String,
}
impl Command for CommandImpl {
fn name(&self) -> String {
pckg::concat(&self.package, "Range")
}
fn aliases(&self) -> Vec<String> {
vec!["random_range".to_string(), "rand_range".to_string()]
}
fn help(&self) -> String {
include_str!("help.md").to_string()
}
fn clone_and_box(&self) -> Box<dyn Command> {
Box::new((*self).clone())
}
fn run(&self, arguments: Vec<String>) -> CommandResult {
if arguments.len() < 2 {
CommandResult::Error("Missing random min/max values.".to_string())
} else {
match arguments[0].parse() {
Ok(min) => match arguments[1].parse() {
Ok(max) => {
if min > max {
CommandResult::Error(
format!("Min value: {} bigger than max value: {}", min, max)
.to_string(),
)
} else {
let mut rng = thread_rng();
let min_128: i128 = min;
let max_128: i128 = max;
let rand_value: i128 = rng.gen_range(min_128, max_128);
CommandResult::Continue(Some(rand_value.to_string()))
}
}
Err(_) => CommandResult::Error(
format!("Non numeric max value: {} provided.", &arguments[1]).to_string(),
),
},
Err(_) => CommandResult::Error(
format!("Non numeric min value: {} provided.", &arguments[0]).to_string(),
),
}
}
}
}
pub(crate) fn create(package: &str) -> Box<dyn Command> {
Box::new(CommandImpl {
package: package.to_string(),
})
}

View File

@ -0,0 +1,32 @@
use super::*;
use crate::test;
use crate::test::CommandValidation;
#[test]
fn common_functions() {
test::test_common_command_functions(create(""));
}
#[test]
fn run_no_args() {
test::run_script_and_error(vec![create("")], "out = rand_range", "out");
}
#[test]
fn run_single_arg() {
test::run_script_and_error(vec![create("")], "out = rand_range 1", "out");
}
#[test]
fn run_min_bigger_than_max() {
test::run_script_and_error(vec![create("")], "out = rand_range 10 5", "out");
}
#[test]
fn run_valid() {
test::run_script_and_validate(
vec![create("")],
"out = rand_range 10 15",
CommandValidation::PositiveNumber("out".to_string()),
);
}

View File

@ -0,0 +1,20 @@
```sh
output = random_text [length]
```
Generates random alphanumeric text with the requested length (length is 1 if not provided).
#### Parameters
Optional text length. Length is defaulted to 1 if not provided.
#### Return Value
The generated alphanumeric value.
#### Examples
```sh
value = random_text 50
echo ${value}
```

View File

@ -0,0 +1,64 @@
use crate::utils::pckg;
use duckscript::types::command::{Command, CommandResult};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use std::iter;
#[cfg(test)]
#[path = "./mod_test.rs"]
mod mod_test;
#[derive(Clone)]
pub(crate) struct CommandImpl {
package: String,
}
impl Command for CommandImpl {
fn name(&self) -> String {
pckg::concat(&self.package, "Text")
}
fn aliases(&self) -> Vec<String> {
vec!["random_text".to_string(), "rand_text".to_string()]
}
fn help(&self) -> String {
include_str!("help.md").to_string()
}
fn clone_and_box(&self) -> Box<dyn Command> {
Box::new((*self).clone())
}
fn run(&self, arguments: Vec<String>) -> CommandResult {
let length = if arguments.is_empty() {
1
} else {
match arguments[0].parse() {
Ok(value) => {
let value_usize: usize = value;
value_usize
}
Err(_) => {
return CommandResult::Error(
format!("Invalid length provided: {}", &arguments[0]).to_string(),
)
}
}
};
let mut rng = thread_rng();
let random_value: String = iter::repeat(())
.map(|()| rng.sample(Alphanumeric))
.take(length)
.collect();
CommandResult::Continue(Some(random_value))
}
}
pub(crate) fn create(package: &str) -> Box<dyn Command> {
Box::new(CommandImpl {
package: package.to_string(),
})
}

View File

@ -0,0 +1,31 @@
use super::*;
use crate::test;
use crate::test::CommandValidation;
#[test]
fn common_functions() {
test::test_common_command_functions(create(""));
}
#[test]
fn run_no_args() {
test::run_script_and_validate(
vec![create("")],
"out = rand_text",
CommandValidation::StringLength("out".to_string(), 1),
);
}
#[test]
fn run_invalid_size() {
test::run_script_and_error(vec![create("")], "out = rand_text -10", "out");
}
#[test]
fn run_valid_size() {
test::run_script_and_validate(
vec![create("")],
"out = rand_text 10",
CommandValidation::StringLength("out".to_string(), 10),
);
}

View File

@ -186,6 +186,7 @@ impl Command for OnErrorCommand {
pub(crate) enum CommandValidation {
None,
PositiveNumber(String),
StringLength(String, usize),
Match(String, String),
Contains(String, String),
Any(String, Vec<String>),
@ -295,6 +296,12 @@ pub(crate) fn run_script_and_validate(
let numeric_value: u128 = var_value.parse().unwrap();
assert!(numeric_value > 0)
}
CommandValidation::StringLength(key, length) => {
assert!(!context.variables.is_empty());
let var_value = context.variables.get(&key).unwrap();
assert!(var_value.len() == length)
}
CommandValidation::Ignore => {
assert!(!context.variables.is_empty());
}

View File

@ -0,0 +1,11 @@
fn test_valid
value = random_range -10 10
in_min = greater_than ${value} -11
in_max = greater_than 10 ${value}
assert ${in_min}
assert ${in_max}
end

View File

@ -0,0 +1,17 @@
fn test_no_length
value = random_text
len = strlen ${value}
assert_eq ${len} 1
end
fn test_with_length
value = random_text 50
len = strlen ${value}
assert_eq ${len} 50
end