mirror of
https://github.com/teo3300/rust-mal.git
synced 2026-01-12 01:05:32 +01:00
Adding tests
- functional tests - more tests - tests tests tests Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
@ -1 +0,0 @@
|
|||||||
.git/hooks/pre-commit
|
|
||||||
13
.git_hooks_pre-commit-shadow
Executable file
13
.git_hooks_pre-commit-shadow
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Quit when first command fails
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# format code in a consistent way
|
||||||
|
cargo fmt
|
||||||
|
|
||||||
|
# yeet on any clippy warning
|
||||||
|
cargo clippy -- -Dwarnings
|
||||||
|
|
||||||
|
# check test pass
|
||||||
|
cargo test
|
||||||
@ -50,7 +50,11 @@ pub fn ns_init() -> Env {
|
|||||||
"list?" => Fun(|a| Ok(Bool(a.iter().all(|el| matches!(el, List(_))))), "Return true if the first argument is a list, false otherwise"),
|
"list?" => Fun(|a| Ok(Bool(a.iter().all(|el| matches!(el, List(_))))), "Return true if the first argument is a list, false otherwise"),
|
||||||
"empty?" => Fun(|a| Ok(Bool(car(a)?.if_list()?.is_empty())), "Return true if the first parameter is an empty list, false otherwise, returns an error if the element is not a list"),
|
"empty?" => Fun(|a| Ok(Bool(car(a)?.if_list()?.is_empty())), "Return true if the first parameter is an empty list, false otherwise, returns an error if the element is not a list"),
|
||||||
"count" => Fun(|a| Ok(Int(car(a)?.if_list()?.len() as isize)), "Return the number of elements in the first argument"),
|
"count" => Fun(|a| Ok(Int(car(a)?.if_list()?.len() as isize)), "Return the number of elements in the first argument"),
|
||||||
|
"and" => Fun(|a| Ok(Bool(a.iter().all(|a| !matches!(a, Nil | Bool(false))))), "Returns false if at least one of the arguments is 'false' or 'nil', true otherwise"),
|
||||||
|
"or" => Fun(|a| Ok(Bool(a.iter().any(|a| !matches!(a, Nil | Bool(false))))), "Returns false if all the arguments are 'false' or 'nil', true otherwise"),
|
||||||
|
"xor" => Fun(|a| Ok(Bool(a.iter().filter(|a| !matches!(a, Nil | Bool(false))).count() == 1)), "Returns true if one of the arguments is different from 'nil' or 'false', false otherwise"),
|
||||||
|
"not" => Fun(|a| Ok(Bool(matches!(car(a)?, Nil | Bool(false)))), "Negate the first argument"),
|
||||||
"=" => Fun(mal_comp, "Return true if the first two parameters are the same type and content, in case of lists propagate to all elements"),
|
"=" => Fun(mal_comp, "Return true if the first two parameters are the same type and content, in case of lists propagate to all elements"),
|
||||||
"assert" => Fun(mal_assert, "Panic if one of the arguments is false")
|
"assert" => Fun(mal_assert, "Return an error if assertion fails")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,11 +4,11 @@ use std::env::args;
|
|||||||
mod core;
|
mod core;
|
||||||
mod env;
|
mod env;
|
||||||
mod eval;
|
mod eval;
|
||||||
|
mod mal_tests;
|
||||||
mod parse_tools;
|
mod parse_tools;
|
||||||
mod printer;
|
mod printer;
|
||||||
mod reader;
|
mod reader;
|
||||||
mod step4_if_fn_do;
|
mod step4_if_fn_do;
|
||||||
mod tests;
|
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use core::ns_init;
|
use core::ns_init;
|
||||||
|
|||||||
@ -16,19 +16,32 @@ mod functional {
|
|||||||
($file:expr) => {{
|
($file:expr) => {{
|
||||||
use crate::core::ns_init;
|
use crate::core::ns_init;
|
||||||
use crate::load_file;
|
use crate::load_file;
|
||||||
let env = ns_init();
|
load_file!(format!("tests/{}.mal", $file).as_str(), &ns_init());
|
||||||
load_file!("core.mal", &env);
|
|
||||||
load_file!(format!("tests/{}.mal", $file).as_str(), &env);
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fibonacci() {
|
fn assert_fail() {
|
||||||
test!("fibonacci");
|
use crate::core::ns_init;
|
||||||
|
use crate::load_file;
|
||||||
|
assert!(matches!(
|
||||||
|
load_file("tests/assert_fail.mal", &ns_init()),
|
||||||
|
Err(_)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_logic() {
|
||||||
|
test!("logic")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builtin_equals() {
|
fn builtin_equals() {
|
||||||
test!("equals");
|
test!("equals");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fibonacci() {
|
||||||
|
test!("fibonacci");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
47
src/types.rs
47
src/types.rs
@ -94,11 +94,11 @@ pub fn mal_comp(args: &[MalType]) -> MalRet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mal_assert(args: &[MalType]) -> MalRet {
|
pub fn mal_assert(args: &[MalType]) -> MalRet {
|
||||||
args.iter().for_each(|i| match i {
|
if args.iter().any(|i| matches!(i, M::Nil | M::Bool(false))) {
|
||||||
M::Nil | M::Bool(false) => panic!(),
|
Err(MalErr::unrecoverable("Assertion failed"))
|
||||||
_ => (),
|
} else {
|
||||||
});
|
Ok(M::Nil)
|
||||||
Ok(M::Nil)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Copy)]
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
@ -184,3 +184,40 @@ pub fn unescape_str(s: &str) -> String {
|
|||||||
.replace("\\n", "\n")
|
.replace("\\n", "\n")
|
||||||
.replace("\\\"", "\"")
|
.replace("\\\"", "\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tests //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::types::mal_assert;
|
||||||
|
use crate::types::MalType as M;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn _mal_assert() {
|
||||||
|
assert!(matches!(mal_assert(&[M::Nil]), Err(_)));
|
||||||
|
assert!(matches!(mal_assert(&[M::Bool(false)]), Err(_)));
|
||||||
|
assert!(matches!(mal_assert(&[M::Bool(true)]), Ok(_)));
|
||||||
|
assert!(matches!(mal_assert(&[M::Int(1)]), Ok(_)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn _escape_str() {
|
||||||
|
use crate::types::escape_str;
|
||||||
|
assert_eq!(escape_str(""), "\"\""); // add quotations
|
||||||
|
assert_eq!(escape_str("\\"), "\"\\\\\""); // escape "\"
|
||||||
|
assert_eq!(escape_str("\n"), "\"\\n\""); // escape "\n"
|
||||||
|
assert_eq!(escape_str("\""), "\"\\\"\""); // escape "\""
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn _unescape_str() {
|
||||||
|
use crate::types::unescape_str;
|
||||||
|
assert_eq!(unescape_str("\"\""), ""); // remove quotations
|
||||||
|
assert_eq!(unescape_str("\"a\""), "a"); // remove quotations
|
||||||
|
assert_eq!(unescape_str("\"\\\\\""), "\\"); // unescape "\"
|
||||||
|
assert_eq!(unescape_str("\"\\n\""), "\n"); // unescape "\n"
|
||||||
|
assert_eq!(unescape_str("\"\\\"\""), "\""); // unescape "\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
1
tests/assert_fail.mal
Normal file
1
tests/assert_fail.mal
Normal file
@ -0,0 +1 @@
|
|||||||
|
(assert nil)
|
||||||
31
tests/logic.mal
Normal file
31
tests/logic.mal
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
; positive assert
|
||||||
|
(assert true)
|
||||||
|
(assert ())
|
||||||
|
(assert 1)
|
||||||
|
|
||||||
|
; not
|
||||||
|
(assert (not false))
|
||||||
|
(assert (not nil))
|
||||||
|
(assert (not (not true)))
|
||||||
|
|
||||||
|
; or
|
||||||
|
(assert (not (or false)))
|
||||||
|
(assert (or 1))
|
||||||
|
(assert (or 1 nil false))
|
||||||
|
(assert (or 1 1 1))
|
||||||
|
(assert (or nil 1 false))
|
||||||
|
(assert (not (or nil false)))
|
||||||
|
(assert (not (or false nil)))
|
||||||
|
|
||||||
|
; and
|
||||||
|
(assert (and 1))
|
||||||
|
(assert (not (and nil)))
|
||||||
|
(assert (and 1 1 1))
|
||||||
|
(assert (not (and 1 nil false)))
|
||||||
|
(assert (not (and nil false)))
|
||||||
|
|
||||||
|
; xor
|
||||||
|
(assert (not (xor nil false nil)))
|
||||||
|
(assert (xor nil 1 nil false nil))
|
||||||
|
(assert (not (xor nil 1 false 1)))
|
||||||
|
(assert (not (xor 1 nil 1 1)))
|
||||||
Reference in New Issue
Block a user