function, forin and ifelse blocks to support generic end command #53

This commit is contained in:
sagie gur ari 2020-01-12 17:39:58 +00:00
parent 6d79fe0cb0
commit f852d67229
37 changed files with 415 additions and 484 deletions

View file

@ -2,6 +2,7 @@
### v0.1.6
* function, forin and ifelse blocks to support generic end command #53
* duckscript cli now accepts inline script #40
* Unit test framework for internal SDK commands and full test suite #51
* New exit_on_error command #49

View file

@ -0,0 +1,95 @@
use crate::utils::state::get_core_sub_state_for_command;
use duckscript::runner;
use duckscript::types::command::{Command, CommandResult, Commands};
use duckscript::types::instruction::{
Instruction, InstructionMetaInfo, InstructionType, ScriptInstruction,
};
use duckscript::types::runtime::StateValue;
use std::collections::HashMap;
#[cfg(test)]
#[path = "./mod_test.rs"]
mod mod_test;
static END_STATE_KEY: &str = "end";
pub(crate) static END_COMMAND_NAME: &str = "end";
fn get_command(line: usize, state: &mut HashMap<String, StateValue>) -> Option<String> {
let sub_state = get_core_sub_state_for_command(state, END_STATE_KEY.to_string());
let key = line.to_string();
match sub_state.get(&key) {
Some(state_value) => match state_value {
StateValue::String(command) => Some(command.clone()),
_ => {
// remove corrupted data
sub_state.remove(&key);
None
}
},
None => None,
}
}
pub(crate) fn set_command(line: usize, state: &mut HashMap<String, StateValue>, command: String) {
let sub_state = get_core_sub_state_for_command(state, END_STATE_KEY.to_string());
sub_state.insert(line.to_string(), StateValue::String(command));
}
struct CommandImpl {}
impl Command for CommandImpl {
fn name(&self) -> String {
END_COMMAND_NAME.to_string()
}
fn help(&self) -> String {
"".to_string()
}
fn requires_context(&self) -> bool {
true
}
fn run_with_context(
&self,
_arguments: Vec<String>,
state: &mut HashMap<String, StateValue>,
variables: &mut HashMap<String, String>,
_output_variable: Option<String>,
instructions: &Vec<Instruction>,
commands: &mut Commands,
line: usize,
) -> CommandResult {
match get_command(line, state) {
Some(command) => {
let mut script_instruction = ScriptInstruction::new();
script_instruction.command = Some(command);
let mut instruction_meta_info = InstructionMetaInfo::new();
instruction_meta_info.line = Some(line);
let instruction = Instruction {
meta_info: instruction_meta_info,
instruction_type: InstructionType::Script(script_instruction),
};
let (command_result, _) = runner::run_instruction(
commands,
variables,
state,
instructions,
instruction,
line,
);
command_result
}
None => CommandResult::Continue(None),
}
}
}
pub(crate) fn create() -> Box<dyn Command> {
Box::new(CommandImpl {})
}

View file

@ -0,0 +1,13 @@
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 = end", CommandValidation::None);
}

View file

@ -1,6 +1,6 @@
use crate::utils::instruction_query;
use crate::utils::pckg;
use crate::sdk::std::flowcontrol::{end, function, ifelse};
use crate::utils::state::{get_core_sub_state_for_command, get_handle, get_list, get_sub_state};
use crate::utils::{instruction_query, pckg};
use duckscript::types::command::{Command, CommandResult, Commands, GoToValue};
use duckscript::types::error::ScriptError;
use duckscript::types::instruction::Instruction;
@ -116,6 +116,22 @@ fn create_forin_meta_info_for_line(
};
let mut end_names = end_forin_command.aliases();
end_names.push(end_forin_command.name());
end_names.push(end::END_COMMAND_NAME.to_string());
let if_command = ifelse::IfCommand::new(&package);
let mut start_blocks = if_command.aliases();
start_blocks.push(if_command.name());
let function_command = function::FunctionCommand::new(&package);
start_blocks.append(&mut function_command.aliases());
start_blocks.push(function_command.name());
let end_if_command = ifelse::EndIfCommand::new(&package);
let mut end_blocks = end_if_command.aliases();
end_blocks.push(end_if_command.name());
let end_function_command = function::EndFunctionCommand::new(&package);
end_blocks.append(&mut end_function_command.aliases());
end_blocks.push(end_function_command.name());
end_blocks.push(end::END_COMMAND_NAME.to_string());
let positions_options = instruction_query::find_commands(
instructions,
@ -125,6 +141,8 @@ fn create_forin_meta_info_for_line(
Some(line + 1),
None,
true,
&start_blocks,
&end_blocks,
)?;
match positions_options {
@ -148,16 +166,28 @@ fn get_or_create_forin_meta_info_for_line(
let key = line.to_string();
let mut forin_state_for_line = get_sub_state(key.clone(), forin_meta_info_state);
match deserialize_forin_meta_info(&mut forin_state_for_line) {
let result = match deserialize_forin_meta_info(&mut forin_state_for_line) {
Some(if_else_info) => Ok(if_else_info),
None => match create_forin_meta_info_for_line(line, instructions, package) {
None => match create_forin_meta_info_for_line(line, instructions, package.clone()) {
Ok(if_else_info) => {
serialize_forin_meta_info(&if_else_info, forin_state_for_line);
Ok(if_else_info)
}
Err(error) => Err(error),
},
}
};
match result {
Ok(ref info) => {
let end_forin_command = EndForInCommand {
package: package.clone(),
};
end::set_command(info.end, state, end_forin_command.name());
}
_ => (),
};
result
}
fn pop_call_info_for_line(
@ -231,10 +261,19 @@ fn get_next_iteration(
}
}
struct ForInCommand {
pub(crate) struct ForInCommand {
package: String,
}
impl ForInCommand {
/// Creates and returns a new instance.
pub(crate) fn new(package: &str) -> ForInCommand {
ForInCommand {
package: package.to_string(),
}
}
}
impl Command for ForInCommand {
fn name(&self) -> String {
pckg::concat(&self.package, "ForIn")
@ -311,10 +350,19 @@ impl Command for ForInCommand {
}
}
struct EndForInCommand {
pub(crate) struct EndForInCommand {
package: String,
}
impl EndForInCommand {
/// Creates and returns a new instance.
pub(crate) fn new(package: &str) -> EndForInCommand {
EndForInCommand {
package: package.to_string(),
}
}
}
impl Command for EndForInCommand {
fn name(&self) -> String {
pckg::concat(&self.package, "EndForIn")

View file

@ -1,6 +1,6 @@
use crate::utils::instruction_query;
use crate::utils::pckg;
use crate::sdk::std::flowcontrol::{end, forin, ifelse};
use crate::utils::state::{get_core_sub_state_for_command, get_list, get_sub_state};
use crate::utils::{instruction_query, pckg};
use duckscript::types::command::{Command, CommandResult, Commands, GoToValue};
use duckscript::types::error::ScriptError;
use duckscript::types::instruction::Instruction;
@ -207,10 +207,19 @@ fn run_call(
}
}
struct FunctionCommand {
pub(crate) struct FunctionCommand {
package: String,
}
impl FunctionCommand {
/// Creates and returns a new instance.
pub(crate) fn new(package: &str) -> FunctionCommand {
FunctionCommand {
package: package.to_string(),
}
}
}
impl Command for FunctionCommand {
fn name(&self) -> String {
pckg::concat(&self.package, "Function")
@ -264,22 +273,46 @@ impl Command for FunctionCommand {
};
let mut end_names = end_command.aliases();
end_names.push(end_command.name());
end_names.push(end::END_COMMAND_NAME.to_string());
match instruction_query::find_command(
&instructions,
let if_command = ifelse::IfCommand::new(&self.package);
let mut start_blocks = if_command.aliases();
start_blocks.push(if_command.name());
let forin_command = forin::ForInCommand::new(&self.package);
start_blocks.append(&mut forin_command.aliases());
start_blocks.push(forin_command.name());
let end_if_command = ifelse::EndIfCommand::new(&self.package);
let mut end_blocks = end_if_command.aliases();
end_blocks.push(end_if_command.name());
let end_forin_command = forin::EndForInCommand::new(&self.package);
end_blocks.append(&mut end_forin_command.aliases());
end_blocks.push(end_forin_command.name());
end_blocks.push(end::END_COMMAND_NAME.to_string());
match instruction_query::find_commands(
instructions,
&start_names,
&vec![],
&end_names,
Some(line + 1),
None,
&start_names,
false,
&start_blocks,
&end_blocks,
) {
Ok(fn_end_line_option) => match fn_end_line_option {
Some(fn_end_line) => {
Ok(positions_options) => match positions_options {
Some(positions) => {
let fn_end_line = positions.end;
let fn_info = FunctionMetaInfo {
name: function_name.clone(),
start: line,
end: fn_end_line,
};
end::set_command(fn_end_line, state, end_command.name());
match store_fn_info_in_state(state, &fn_info) {
Ok(_) => {
pub(crate) struct CallFunctionCommand {
@ -346,10 +379,19 @@ impl Command for FunctionCommand {
}
}
struct EndFunctionCommand {
pub(crate) struct EndFunctionCommand {
package: String,
}
impl EndFunctionCommand {
/// Creates and returns a new instance.
pub(crate) fn new(package: &str) -> EndFunctionCommand {
EndFunctionCommand {
package: package.to_string(),
}
}
}
impl Command for EndFunctionCommand {
fn name(&self) -> String {
pckg::concat(&self.package, "EndFunction")

View file

@ -1,6 +1,6 @@
use crate::utils::instruction_query;
use crate::sdk::std::flowcontrol::{end, forin, function};
use crate::utils::state::{get_core_sub_state_for_command, get_list, get_sub_state};
use crate::utils::{condition, pckg};
use crate::utils::{condition, instruction_query, pckg};
use duckscript::types::command::{Command, CommandResult, Commands, GoToValue};
use duckscript::types::error::ScriptError;
use duckscript::types::instruction::Instruction;
@ -178,6 +178,22 @@ fn create_if_meta_info_for_line(
};
let mut end_names = end_if_command.aliases();
end_names.push(end_if_command.name());
end_names.push(end::END_COMMAND_NAME.to_string());
let function_command = function::FunctionCommand::new(&package);
let mut start_blocks = function_command.aliases();
start_blocks.push(function_command.name());
let forin_command = forin::ForInCommand::new(&package);
start_blocks.append(&mut forin_command.aliases());
start_blocks.push(forin_command.name());
let end_forin_command = forin::EndForInCommand::new(&package);
let mut end_blocks = end_forin_command.aliases();
end_blocks.push(end_forin_command.name());
let end_function_command = function::EndFunctionCommand::new(&package);
end_blocks.append(&mut end_function_command.aliases());
end_blocks.push(end_function_command.name());
end_blocks.push(end::END_COMMAND_NAME.to_string());
let positions_options = instruction_query::find_commands(
instructions,
@ -187,6 +203,8 @@ fn create_if_meta_info_for_line(
Some(line + 1),
None,
true,
&start_blocks,
&end_blocks,
)?;
match positions_options {
@ -211,16 +229,28 @@ fn get_or_create_if_meta_info_for_line(
let key = line.to_string();
let mut if_state_for_line = get_sub_state(key.clone(), if_meta_info_state);
match deserialize_ifelse_meta_info(&mut if_state_for_line) {
let result = match deserialize_ifelse_meta_info(&mut if_state_for_line) {
Some(if_else_info) => Ok(if_else_info),
None => match create_if_meta_info_for_line(line, instructions, package) {
None => match create_if_meta_info_for_line(line, instructions, package.clone()) {
Ok(if_else_info) => {
serialize_ifelse_meta_info(&if_else_info, if_state_for_line);
Ok(if_else_info)
}
Err(error) => Err(error),
},
}
};
match result {
Ok(ref info) => {
let end_if_command = EndIfCommand {
package: package.clone(),
};
end::set_command(info.end, state, end_if_command.name());
}
_ => (),
};
result
}
fn pop_call_info_for_line(
@ -259,10 +289,19 @@ fn store_call_info(call_info: &CallInfo, state: &mut HashMap<String, StateValue>
call_info_stack.push(StateValue::SubState(call_info_state));
}
struct IfCommand {
pub(crate) struct IfCommand {
package: String,
}
impl IfCommand {
/// Creates and returns a new instance.
pub(crate) fn new(package: &str) -> IfCommand {
IfCommand {
package: package.to_string(),
}
}
}
impl Command for IfCommand {
fn name(&self) -> String {
pckg::concat(&self.package, "If")
@ -484,10 +523,19 @@ impl Command for ElseCommand {
}
}
struct EndIfCommand {
pub(crate) struct EndIfCommand {
package: String,
}
impl EndIfCommand {
/// Creates and returns a new instance.
pub(crate) fn new(package: &str) -> EndIfCommand {
EndIfCommand {
package: package.to_string(),
}
}
}
impl Command for EndIfCommand {
fn name(&self) -> String {
pckg::concat(&self.package, "EndIf")

View file

@ -0,0 +1,17 @@
mod end;
mod forin;
mod function;
mod ifelse;
use duckscript::types::command::Commands;
use duckscript::types::error::ScriptError;
pub(crate) fn load(commands: &mut Commands, package: &str) -> Result<(), ScriptError> {
commands.set(end::create())?;
forin::load(commands, package)?;
function::load(commands, package)?;
ifelse::load(commands, package)?;
Ok(())
}

View file

@ -3,11 +3,9 @@ pub(crate) mod collections;
mod echo;
mod env;
mod eval;
mod forin;
mod flowcontrol;
mod fs;
mod function;
mod goto;
mod ifelse;
mod is_defined;
mod man;
mod math;
@ -45,10 +43,8 @@ pub(crate) fn load(commands: &mut Commands) -> Result<(), ScriptError> {
collections::load(commands, PACKAGE)?;
env::load(commands, PACKAGE)?;
forin::load(commands, PACKAGE)?;
flowcontrol::load(commands, PACKAGE)?;
fs::load(commands, PACKAGE)?;
function::load(commands, PACKAGE)?;
ifelse::load(commands, PACKAGE)?;
math::load(commands, PACKAGE)?;
net::load(commands, PACKAGE)?;
on_error::load(commands, PACKAGE)?;

View file

@ -25,44 +25,6 @@ fn get_end(end: Option<usize>, instructions: &Vec<Instruction>) -> usize {
}
}
pub(crate) fn find_command(
instructions: &Vec<Instruction>,
name_or_alias: &Vec<String>,
start: Option<usize>,
end: Option<usize>,
error_on_command: &Vec<String>,
) -> Result<Option<usize>, String> {
if name_or_alias.is_empty() {
Err("No command names/aliases provided for search.".to_string())
} else {
let start_index = get_start(start);
let end_index = get_end(end, instructions);
for line in start_index..end_index {
let instruction = &instructions[line];
match instruction.instruction_type {
InstructionType::Script(ref script_instruction) => match script_instruction.command
{
Some(ref command) => {
if name_or_alias.contains(command) {
return Ok(Some(line));
} else if error_on_command.contains(command) {
return Err(command.to_string());
}
()
}
None => (),
},
_ => (),
}
}
Ok(None)
}
}
pub(crate) fn find_commands(
instructions: &Vec<Instruction>,
start_names: &Vec<String>,
@ -71,6 +33,8 @@ pub(crate) fn find_commands(
start: Option<usize>,
end: Option<usize>,
allow_recursive: bool,
start_blocks: &Vec<String>,
end_blocks: &Vec<String>,
) -> Result<Option<Positions>, String> {
if start_names.is_empty() || end_names.is_empty() {
Err("No command names/aliases provided for search.".to_string())
@ -83,6 +47,7 @@ pub(crate) fn find_commands(
end: 0,
};
let mut skip_to = start_index;
let mut block_delta = 0;
for line in start_index..end_index {
if line >= skip_to {
let instruction = &instructions[line];
@ -91,8 +56,12 @@ pub(crate) fn find_commands(
InstructionType::Script(ref script_instruction) => {
match script_instruction.command {
Some(ref command) => {
if middle_names.contains(command) {
if start_blocks.contains(command) {
block_delta = block_delta + 1;
} else if middle_names.contains(command) {
positions.middle.push(line);
} else if end_blocks.contains(command) && block_delta > 0 {
block_delta = block_delta - 1;
} else if end_names.contains(command) {
positions.end = line;
return Ok(Some(positions));
@ -106,6 +75,8 @@ pub(crate) fn find_commands(
Some(line + 1),
Some(end_index),
allow_recursive,
start_blocks,
end_blocks,
) {
Ok(positions_options) => match positions_options {
Some(sub_positions) => {

View file

@ -62,316 +62,6 @@ fn create_valid_test_if_else_block() -> Vec<Instruction> {
instructions
}
#[test]
fn find_command_empty() {
let result = find_command(&vec![], &vec![], None, None, &vec![]);
assert!(result.is_err());
}
#[test]
fn find_command_no_instructions() {
let result = find_command(&vec![], &vec!["1".to_string()], None, None, &vec![]);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn find_command_only_empty_instructions() {
let result = find_command(
&vec![
Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Empty,
},
Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Empty,
},
Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Empty,
},
],
&vec!["1".to_string()],
None,
None,
&vec![],
);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn find_command_not_found() {
let mut instructions = vec![];
let mut script_instruction = ScriptInstruction::new();
script_instruction.command = Some("a".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("b".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("c".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
let result = find_command(&instructions, &vec!["1".to_string()], None, None, &vec![]);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn find_command_found() {
let mut instructions = vec![];
let mut script_instruction = ScriptInstruction::new();
script_instruction.command = Some("a".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("b".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("c".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("1".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
let result = find_command(&instructions, &vec!["1".to_string()], None, None, &vec![]);
assert!(result.is_ok());
assert_eq!(result.unwrap().unwrap(), 3);
}
#[test]
fn find_command_found_after_start_index() {
let mut instructions = vec![];
let mut script_instruction = ScriptInstruction::new();
script_instruction.command = Some("a".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("1".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("b".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("c".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
let result = find_command(
&instructions,
&vec!["1".to_string()],
Some(2),
None,
&vec![],
);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn find_command_found_with_start_index() {
let mut instructions = vec![];
let mut script_instruction = ScriptInstruction::new();
script_instruction.command = Some("a".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("b".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("1".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("c".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
let result = find_command(
&instructions,
&vec!["1".to_string()],
Some(2),
None,
&vec![],
);
assert!(result.is_ok());
assert_eq!(result.unwrap().unwrap(), 2);
}
#[test]
fn find_command_found_before_end_index() {
let mut instructions = vec![];
let mut script_instruction = ScriptInstruction::new();
script_instruction.command = Some("a".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("b".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("c".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("1".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
let result = find_command(
&instructions,
&vec!["1".to_string()],
None,
Some(2),
&vec![],
);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn find_command_found_after_error() {
let mut instructions = vec![];
let mut script_instruction = ScriptInstruction::new();
script_instruction.command = Some("a".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("b".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("c".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("1".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
let result = find_command(
&instructions,
&vec!["1".to_string()],
None,
None,
&vec!["b".to_string()],
);
assert!(result.is_err());
}
#[test]
fn find_command_found_before_error() {
let mut instructions = vec![];
let mut script_instruction = ScriptInstruction::new();
script_instruction.command = Some("a".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("1".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("b".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
script_instruction = ScriptInstruction::new();
script_instruction.command = Some("c".to_string());
instructions.push(Instruction {
meta_info: InstructionMetaInfo::new(),
instruction_type: InstructionType::Script(script_instruction),
});
let result = find_command(
&instructions,
&vec!["1".to_string()],
None,
None,
&vec!["b".to_string()],
);
assert!(result.is_ok());
assert_eq!(result.unwrap().unwrap(), 1);
}
#[test]
fn find_commands_nested_not_allowed() {
let mut instructions = create_valid_test_if_else_block();
@ -403,6 +93,8 @@ fn find_commands_nested_not_allowed() {
None,
None,
false,
&vec![],
&vec![],
);
assert!(result.is_err());
@ -421,6 +113,8 @@ fn find_commands_missing_end() {
None,
None,
false,
&vec![],
&vec![],
);
assert!(result.is_err());
@ -438,6 +132,8 @@ fn find_commands_simple_valid() {
None,
None,
false,
&vec![],
&vec![],
);
let positions_option = result.unwrap();
@ -474,6 +170,8 @@ fn find_commands_nested_valid() {
None,
None,
true,
&vec![],
&vec![],
);
let positions_option = result.unwrap();
@ -502,6 +200,8 @@ fn find_commands_middle_not_found() {
None,
None,
false,
&vec![],
&vec![],
);
let positions_option = result.unwrap();

View file

@ -1,26 +1,26 @@
function test_array_with_data
arr = array 1 2 3
len = array_length ${arr}
assert_eq ${len} 3
isempty = not array_is_empty ${arr}
assert ${isempty}
released = release ${arr}
assert ${released}
end_function
end
function test_array_no_data
arr = array
len = array_length ${arr}
assert_eq ${len} 0
isempty = array_is_empty ${arr}
assert ${isempty}
released = release ${arr}
assert ${released}
end_function
end

View file

@ -10,7 +10,7 @@ function test_range_with_data
released = release ${arr}
assert ${released}
end_function
end
function test_range_no_data
arr = range 0 0
@ -23,4 +23,4 @@ function test_range_no_data
released = release ${arr}
assert ${released}
end_function
end

View file

@ -8,4 +8,4 @@ function test_set_get_unset
assert ${value}
value = get_env TEST_SET_GET_UNSET
assert_eq ${value} "test value"
end_function
end

View file

@ -5,11 +5,11 @@ function test_array
for arg in ${args}
counter = calc ${counter} + 1
end_for
end
assert_eq ${counter} 3
released = release ${args}
end_function
end
function test_nested
counter = set 0
@ -18,12 +18,12 @@ function test_nested
for i in ${values}
for j in ${values}
counter = calc ${counter} + 1
end_for
end_for
end
end
assert_eq ${counter} 9
released = release ${args}
end_function
end
function test_range
counter = set 0
@ -32,9 +32,9 @@ function test_range
for i in ${args}
for j in ${args}
counter = calc ${counter} + 1
end_for
end_for
end
end
assert_eq ${counter} 100
released = release ${args}
end_function
end

View file

@ -7,17 +7,17 @@ function test_relative_path
value = basename .\\test.txt
else
value = basename ./test.txt
end_if
end
assert_eq ${value} test.txt
end_function
end
function test_full_path
if ${windows}
value = basename c:\\dir\\dir\\test.txt
else
value = basename /dir/dir/test.txt
end_if
end
assert_eq ${value} test.txt
end_function
end

View file

@ -7,15 +7,15 @@ function test_relative_path
value = dirname .\\test.txt
else
value = dirname ./test.txt
end_if
end
assert_eq ${value} .
end_function
end
function test_full_path
if not ${windows}
value = dirname /dir/test.txt
assert_eq ${value} /dir
end_if
end_function
end
end

View file

@ -5,4 +5,4 @@ function test_goto_with_valid_label
assert_fail
:test_goto_with_valid_label
end_function
end

View file

@ -4,36 +4,36 @@ function test_if_hardcoded_true
if true
valid = set true
end_if
end
assert ${valid}
end_function
end
function test_if_hardcoded_false
if false
assert_fail
end_if
end_function
end
end
function test_if_hardcoded_not_false
valid = set false
if not false
valid = set true
end_if
end
assert ${valid}
end_function
end
function test_if_command_returns_true
valid = set false
if set true
valid = set true
end_if
end
assert ${valid}
end_function
end
function test_simple_else
valid = set false
@ -42,10 +42,10 @@ function test_simple_else
assert_fail
else
valid = set true
end_if
end
assert ${valid}
end_function
end
function test_simple_elseif
valid = set false
@ -56,10 +56,10 @@ function test_simple_elseif
valid = set true
else
assert_fail
end_if
end
assert ${valid}
end_function
end
function test_nested_if
valid = set false
@ -69,13 +69,13 @@ function test_nested_if
elseif set true
if set true
valid = set true
end_if
end
else
assert_fail
end_if
end
assert ${valid}
end_function
end
function test_nested_if2
valid = set false
@ -93,11 +93,11 @@ function test_nested_if2
valid = set true
else
assert_fail
end_if
end_if
end
end
else
assert_fail
end_if
end
assert ${valid}
end_function
end

View file

@ -3,10 +3,10 @@ function test_not_true
value = not true
assert_false ${value}
end_function
end
function test_not_false
value = not false
assert ${value}
end_function
end

View file

@ -3,34 +3,34 @@ function test_prefix
output = contains "1 2 3 4 5" "1 2"
assert ${output}
end_function
end
function test_suffix
output = contains "1 2 3 4 5" "4 5"
assert ${output}
end_function
end
function test_middle
output = contains "1 2 3 4 5" "2 3"
assert ${output}
end_function
end
function test_all
output = contains "1 2 3 4 5" "1 2 3 4 5"
assert ${output}
end_function
end
function test_empty
output = contains "1 2 3 4 5" ""
assert ${output}
end_function
end
function test_not_contained
output = contains "1 2 3 4 5" "4 5 6"
assert_false ${output}
end_function
end

View file

@ -3,34 +3,34 @@ function test_prefix
output = ends_with "1 2 3 4 5" "1 2"
assert_false ${output}
end_function
end
function test_suffix
output = ends_with "1 2 3 4 5" "4 5"
assert ${output}
end_function
end
function test_middle
output = ends_with "1 2 3 4 5" "2 3"
assert_false ${output}
end_function
end
function test_all
output = ends_with "1 2 3 4 5" "1 2 3 4 5"
assert ${output}
end_function
end
function test_empty
output = ends_with "1 2 3 4 5" ""
assert ${output}
end_function
end
function test_not_contained
output = ends_with "1 2 3 4 5" "4 5 6"
assert_false ${output}
end_function
end

View file

@ -3,34 +3,34 @@ function test_prefix
output = equals "1 2 3 4 5" "1 2"
assert_false ${output}
end_function
end
function test_suffix
output = equals "1 2 3 4 5" "4 5"
assert_false ${output}
end_function
end
function test_middle
output = equals "1 2 3 4 5" "2 3"
assert_false ${output}
end_function
end
function test_all
output = equals "1 2 3 4 5" "1 2 3 4 5"
assert ${output}
end_function
end
function test_empty
output = equals "1 2 3 4 5" ""
assert_false ${output}
end_function
end
function test_not_contained
output = equals "1 2 3 4 5" "4 5 6"
assert_false ${output}
end_function
end

View file

@ -3,16 +3,16 @@ function test_not_found
output = indexof "1 2 3 4 5" "4 5 6"
assert_eq ${output} ""
end_function
end
function test_prefix
output = indexof "1 2 3 4 5 1 2 3 4 5" "1 2"
assert_eq ${output} 0
end_function
end
function test_suffix
output = indexof "1 2 3 4 5 1 2 3 4 5" "4 5"
assert_eq ${output} 6
end_function
end

View file

@ -3,16 +3,16 @@ function test_empty
output = is_empty ""
assert ${output}
end_function
end
function test_not_empty
output = is_empty "test"
assert_false ${output}
end_function
end
function test_undefined
output = is_empty ${test_undefined}
assert ${output}
end_function
end

View file

@ -3,16 +3,16 @@ function test_not_found
output = last_indexof "1 2 3 4 5" "4 5 6"
assert_eq ${output} ""
end_function
end
function test_prefix
output = last_indexof "1 2 3 4 5 1 2 3 4 5" "1 2"
assert_eq ${output} 10
end_function
end
function test_suffix
output = last_indexof "1 2 3 4 5 1 2 3 4 5" "4 5"
assert_eq ${output} 16
end_function
end

View file

@ -3,16 +3,16 @@ function test_empty
output = length ""
assert_eq ${output} 0
end_function
end
function test_not_empty
output = length "test"
assert_eq ${output} 4
end_function
end
function test_undefined
output = length ${test_undefined}
assert_eq ${output} 0
end_function
end

View file

@ -3,34 +3,34 @@ function test_prefix
output = starts_with "1 2 3 4 5" "1 2"
assert ${output}
end_function
end
function test_suffix
output = starts_with "1 2 3 4 5" "4 5"
assert_false ${output}
end_function
end
function test_middle
output = starts_with "1 2 3 4 5" "2 3"
assert_false ${output}
end_function
end
function test_all
output = starts_with "1 2 3 4 5" "1 2 3 4 5"
assert ${output}
end_function
end
function test_empty
output = starts_with "1 2 3 4 5" ""
assert ${output}
end_function
end
function test_not_contained
output = starts_with "1 2 3 4 5" "4 5 6"
assert_false ${output}
end_function
end

View file

@ -3,46 +3,46 @@ function test_empty_with_range
output = substring "" 0 0
assert_eq ${output} "false"
end_function
end
function test_text_with_empty_range
output = substring "test" 0 0
assert_eq ${output} ""
end_function
end
function test_text_with_range
output = substring "test" 1 3
assert_eq ${output} "es"
end_function
end
function test_text_with_start
output = substring "test" 1
assert_eq ${output} "est"
end_function
end
function test_text_with_end
output = substring "test" -2
assert_eq ${output} "st"
end_function
end
function test_text_with_range_and_start_too_big
output = substring "test" 6 8
assert_eq ${output} "false"
end_function
end
function test_text_with_start_too_big
output = substring "test" 6
assert_eq ${output} "false"
end_function
end
function test_text_with_range_and_end_too_big
output = substring "test" 0 8
assert_eq ${output} "false"
end_function
end

View file

@ -3,28 +3,28 @@ function test_empty
output = trim_end ""
assert_eq ${output} ""
end_function
end
function test_trimmed
output = trim_end "test test"
assert_eq ${output} "test test"
end_function
end
function test_start_untrimmed
output = trim_end " test test"
assert_eq ${output} " test test"
end_function
end
function test_end_untrimmed
output = trim_end "test test "
assert_eq ${output} "test test"
end_function
end
function test_both_untrimmed
output = trim_end " test test "
assert_eq ${output} " test test"
end_function
end

View file

@ -3,28 +3,28 @@ function test_empty
output = trim_start ""
assert_eq ${output} ""
end_function
end
function test_trimmed
output = trim_start "test test"
assert_eq ${output} "test test"
end_function
end
function test_start_untrimmed
output = trim_start " test test"
assert_eq ${output} "test test"
end_function
end
function test_end_untrimmed
output = trim_start "test test "
assert_eq ${output} "test test "
end_function
end
function test_both_untrimmed
output = trim_start " test test "
assert_eq ${output} "test test "
end_function
end

View file

@ -3,28 +3,28 @@ function test_empty
output = trim ""
assert_eq ${output} ""
end_function
end
function test_trimmed
output = trim "test test"
assert_eq ${output} "test test"
end_function
end
function test_start_untrimmed
output = trim " test test"
assert_eq ${output} "test test"
end_function
end
function test_end_untrimmed
output = trim "test test "
assert_eq ${output} "test test"
end_function
end
function test_both_untrimmed
output = trim " test test "
assert_eq ${output} "test test"
end_function
end