diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea40950..8ea6020 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
### v0.1.2
+* New **assert** command #2
* New **touch** command #4
* New **dirname** command #6
* New **canonicalize** command #21
diff --git a/docs/sdk.md b/docs/sdk.md
index 068aebc..ec28a34 100644
--- a/docs/sdk.md
+++ b/docs/sdk.md
@@ -25,6 +25,7 @@
* [sdk::fs::Write](#sdk__fs__Write)
* [sdk::process::Execute](#sdk__process__Execute)
* [sdk::process::Exit](#sdk__process__Exit)
+* [sdk::test::Assert](#sdk__test__Assert)
* [sdk::thread::Sleep](#sdk__thread__Sleep)
@@ -1045,6 +1046,58 @@ code = exit 1
#### Aliases:
exit
+
+## sdk::test::Assert
+```sh
+assert value [error message]
+```
+
+Used to validate the input is truthy.
+If the value is one of the following:
+
+* No output
+* false (case insensitive)
+* 0
+* no (case insensitive)
+* Empty value
+
+It is considered falsy and will exist with an error.
+
+#### Parameters
+
+* The value to evaluate
+* Optional error message
+
+#### Return Value
+
+**true** is truthy.
+
+#### Examples
+
+Valid condition:
+
+```sh
+assert ok
+assert true
+assert yes
+
+value = set "some text"
+assert ${value}
+```
+
+Error example:
+
+```sh
+assert
+assert false
+assert 0
+assert false "This is my error message"
+```
+
+
+#### Aliases:
+assert
+
## sdk::thread::Sleep
```sh
diff --git a/duckscript_sdk/src/sdk/std/mod.rs b/duckscript_sdk/src/sdk/std/mod.rs
index 4af60fc..a1c5eb5 100755
--- a/duckscript_sdk/src/sdk/std/mod.rs
+++ b/duckscript_sdk/src/sdk/std/mod.rs
@@ -12,6 +12,7 @@ mod not;
mod process;
mod release;
mod set;
+mod test;
mod thread;
mod unalias;
@@ -37,6 +38,7 @@ pub(crate) fn load(commands: &mut Commands) -> Result<(), ScriptError> {
function::load(commands, PACKAGE)?;
ifelse::load(commands, PACKAGE)?;
process::load(commands, PACKAGE)?;
+ test::load(commands, PACKAGE)?;
thread::load(commands, PACKAGE)?;
Ok(())
diff --git a/duckscript_sdk/src/sdk/std/test/assert/help.md b/duckscript_sdk/src/sdk/std/test/assert/help.md
new file mode 100644
index 0000000..f4a937b
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/test/assert/help.md
@@ -0,0 +1,45 @@
+```sh
+assert value [error message]
+```
+
+Used to validate the input is truthy.
+If the value is one of the following:
+
+* No output
+* false (case insensitive)
+* 0
+* no (case insensitive)
+* Empty value
+
+It is considered falsy and will exist with an error.
+
+#### Parameters
+
+* The value to evaluate
+* Optional error message
+
+#### Return Value
+
+**true** is truthy.
+
+#### Examples
+
+Valid condition:
+
+```sh
+assert ok
+assert true
+assert yes
+
+value = set "some text"
+assert ${value}
+```
+
+Error example:
+
+```sh
+assert
+assert false
+assert 0
+assert false "This is my error message"
+```
diff --git a/duckscript_sdk/src/sdk/std/test/assert/mod.rs b/duckscript_sdk/src/sdk/std/test/assert/mod.rs
new file mode 100755
index 0000000..37fdb43
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/test/assert/mod.rs
@@ -0,0 +1,50 @@
+use crate::utils::{condition, pckg};
+use duckscript::types::command::{Command, CommandResult};
+
+#[cfg(test)]
+#[path = "./mod_test.rs"]
+mod mod_test;
+
+struct CommandImpl {
+ package: String,
+}
+
+impl Command for CommandImpl {
+ fn name(&self) -> String {
+ pckg::concat(&self.package, "Assert")
+ }
+
+ fn aliases(&self) -> Vec {
+ vec!["assert".to_string()]
+ }
+
+ fn help(&self) -> String {
+ include_str!("help.md").to_string()
+ }
+
+ fn run(&self, arguments: Vec) -> CommandResult {
+ if arguments.is_empty() {
+ CommandResult::Error("Assert failed, empty value.".to_string())
+ } else {
+ let passed = condition::is_true(Some(arguments[0].clone()));
+
+ if passed {
+ CommandResult::Continue(Some("true".to_string()))
+ } else {
+ let error_message = if arguments.len() == 1 {
+ format!("Assert failed, value is falsy: {}", &arguments[0]).to_string()
+ } else {
+ arguments[1].clone()
+ };
+
+ CommandResult::Error(error_message)
+ }
+ }
+ }
+}
+
+pub(crate) fn create(package: &str) -> Box {
+ Box::new(CommandImpl {
+ package: package.to_string(),
+ })
+}
diff --git a/duckscript_sdk/src/sdk/std/test/assert/mod_test.rs b/duckscript_sdk/src/sdk/std/test/assert/mod_test.rs
new file mode 100644
index 0000000..f96619e
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/test/assert/mod_test.rs
@@ -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_fail(vec![create("")], "out = assert");
+}
+
+#[test]
+fn run_single_false_argument() {
+ test::run_script_and_fail(vec![create("")], "out = assert false");
+}
+
+#[test]
+fn run_single_true_argument() {
+ test::run_script_and_validate(
+ vec![create("")],
+ "out = assert true",
+ CommandValidation::Match("out".to_string(), "true".to_string()),
+ );
+}
+
+#[test]
+fn run_single_false_condition_and_message() {
+ test::run_script_and_fail(vec![create("")], "out = assert false test error");
+}
diff --git a/duckscript_sdk/src/sdk/std/test/mod.rs b/duckscript_sdk/src/sdk/std/test/mod.rs
new file mode 100755
index 0000000..6ac209b
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/test/mod.rs
@@ -0,0 +1,15 @@
+mod assert;
+
+use crate::utils::pckg;
+use duckscript::types::command::Commands;
+use duckscript::types::error::ScriptError;
+
+static PACKAGE: &str = "test";
+
+pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptError> {
+ let package = pckg::concat(parent, PACKAGE);
+
+ commands.set(assert::create(&package))?;
+
+ Ok(())
+}