aiken/crates/aiken-lang/src/tests/check.rs

258 lines
5.0 KiB
Rust

use crate::{
ast::{ModuleKind, TypedModule, UntypedModule},
builtins, parser,
tipo::error::{Error, Warning},
IdGenerator,
};
use std::collections::HashMap;
fn parse(source_code: &str) -> UntypedModule {
let kind = ModuleKind::Lib;
let (ast, _) = parser::module(source_code, kind).expect("Failed to parse module");
ast
}
fn check_module(
ast: UntypedModule,
kind: ModuleKind,
) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
let id_gen = IdGenerator::new();
let mut warnings = vec![];
let mut module_types = HashMap::new();
module_types.insert("aiken".to_string(), builtins::prelude(&id_gen));
module_types.insert("aiken/builtin".to_string(), builtins::plutus(&id_gen));
let result = ast.infer(&id_gen, kind, "test/project", &module_types, &mut warnings);
result
.map(|o| (warnings.clone(), o))
.map_err(|e| (warnings, e))
}
fn check(ast: UntypedModule) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
check_module(ast, ModuleKind::Lib)
}
fn check_validator(
ast: UntypedModule,
) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
check_module(ast, ModuleKind::Validator)
}
#[test]
fn validator_illegal_return_type() {
let source_code = r#"
validator foo {
fn(d, r, c) {
1
}
}
"#;
assert!(matches!(
check_validator(parse(source_code)),
Err((_, Error::ValidatorMustReturnBool { .. }))
))
}
#[test]
fn validator_illegal_arity() {
let source_code = r#"
validator foo {
fn(c) {
True
}
}
"#;
assert!(matches!(
check_validator(parse(source_code)),
Err((_, Error::IncorrectValidatorArity { .. }))
))
}
#[test]
fn validator_correct_form() {
let source_code = r#"
validator foo {
fn(d, r, c) {
True
}
}
"#;
assert!(check_validator(parse(source_code)).is_ok())
}
#[test]
fn validator_in_lib_warning() {
let source_code = r#"
validator foo {
fn(c) {
True
}
}
"#;
let (warnings, _) = check(parse(source_code)).unwrap();
assert!(matches!(
warnings[0],
Warning::ValidatorInLibraryModule { .. }
))
}
#[test]
fn if_scoping() {
let source_code = r#"
pub fn foo(c) {
if c {
let bar = 1
bar
} else if !c {
bar
} else {
bar
}
}
"#;
assert!(matches!(
check_validator(parse(source_code)),
Err((_, Error::UnknownVariable { .. }))
))
}
#[test]
fn list_pattern_1() {
let source_code = r#"
test foo() {
let xs = [1, 2, 3]
let [x] = xs
x == 1
}
"#;
assert!(matches!(
check(parse(source_code)),
Err((_, Error::NotExhaustivePatternMatch { .. }))
))
}
#[test]
fn list_pattern_2() {
let source_code = r#"
test foo() {
let xs = [1, 2, 3]
let x = when xs is {
[x] -> x
}
x == 1
}
"#;
assert!(matches!(
check(parse(source_code)),
Err((_, Error::NotExhaustivePatternMatch { .. }))
))
}
#[test]
fn list_pattern_3() {
let source_code = r#"
test foo() {
let xs = [1, 2, 3]
let x = when xs is {
[x] -> x
[x, ..] -> x
}
x == 1
}
"#;
assert!(matches!(
check(parse(source_code)),
Err((_, Error::NotExhaustivePatternMatch { .. }))
))
}
#[test]
fn list_pattern_4() {
let source_code = r#"
test foo() {
let xs = [1, 2, 3]
let x = when xs is {
[] -> 1
[x] -> x
[x, ..] if x > 10 -> x
}
x == 1
}
"#;
assert!(matches!(
check(parse(source_code)),
Err((_, Error::NotExhaustivePatternMatch { .. }))
))
}
#[test]
fn list_pattern_5() {
let source_code = r#"
test foo() {
let xs = [1, 2, 3]
let x = when xs is {
[] -> 1
[_, ..] -> 1
}
x == 1
}
"#;
assert!(check(parse(source_code)).is_ok())
}
#[test]
fn list_pattern_6() {
let source_code = r#"
test foo() {
let xs = [1, 2, 3]
let x = when xs is {
[x, ..] -> 1
_ -> 1
}
x == 1
}
"#;
assert!(check(parse(source_code)).is_ok())
}
#[test]
fn trace_strings() {
let source_code = r#"
fn bar() {
"BAR"
}
test foo() {
let msg1 = "FOO"
trace("INLINE")
trace(msg1)
trace(bar())
True
}
"#;
assert!(check(parse(source_code)).is_ok())
}
#[test]
fn trace_non_strings() {
let source_code = r#"
test foo() {
trace(14 + 42)
True
}
"#;
assert!(matches!(
check(parse(source_code)),
Err((_, Error::CouldNotUnify { .. }))
))
}