use std::sync::Arc;
use cljrs_reader::Parser;
use cljrs_runtime::env::env::{Env, GlobalEnv};
use cljrs_value::Value;
fn make_env() -> (Arc<GlobalEnv>, Env) {
let globals = cljrs_runtime::Runtime::builder()
.execution_mode(cljrs_runtime::ExecutionMode::TreeWalk)
.build()
.expect("runtime")
.into_globals();
let env = Env::new(globals.clone(), "user");
(globals, env)
}
fn eval_pr(src: &str) -> String {
let (_globals, mut env) = make_env();
let mut parser = Parser::new(src.to_string(), "<test>".to_string());
let forms = parser.parse_all().expect("parse error");
let mut result = Value::Nil;
for form in forms {
result = cljrs_runtime::interp::eval::eval(&form, &mut env).expect("eval error");
}
match result {
Value::Str(s) => s.get().as_str().to_string(),
other => panic!("expected a string from pr-str, got a {}", other.type_name()),
}
}
const PRELUDE: &str = "(ns mini.proto)
(defprotocol IThing (-describe [this]))
(ns user)
(alias 'mp 'mini.proto)
";
#[test]
fn defrecord_implements_a_protocol_from_another_namespace() {
assert_eq!(
eval_pr(&format!(
"{PRELUDE}
(defrecord R [n] mp/IThing (-describe [_] [:record n]))
(pr-str (mp/-describe (->R 1)))"
)),
"[:record 1]"
);
}
#[test]
fn deftype_implements_a_protocol_from_another_namespace() {
assert_eq!(
eval_pr(&format!(
"{PRELUDE}
(deftype T [n] mp/IThing (-describe [_] [:type n]))
(pr-str (mp/-describe (->T 2)))"
)),
"[:type 2]"
);
}
#[test]
fn reify_implements_a_protocol_from_another_namespace() {
assert_eq!(
eval_pr(&format!(
"{PRELUDE}
(pr-str (mp/-describe (reify mp/IThing (-describe [_] :reified))))"
)),
":reified"
);
}
#[test]
fn extend_type_names_a_protocol_from_another_namespace() {
assert_eq!(
eval_pr(&format!(
"{PRELUDE}
(extend-type String mp/IThing (-describe [s] [:string s]))
(pr-str (mp/-describe \"hi\"))"
)),
"[:string \"hi\"]"
);
}
#[test]
fn extend_protocol_names_a_protocol_from_another_namespace() {
assert_eq!(
eval_pr(&format!(
"{PRELUDE}
(extend-protocol mp/IThing Long (-describe [n] [:long n]))
(pr-str (mp/-describe 7))"
)),
"[:long 7]"
);
}
#[test]
fn a_fully_qualified_protocol_name_resolves_without_an_alias() {
assert_eq!(
eval_pr(
"(ns mini.proto)
(defprotocol IThing (-describe [this]))
(ns user)
(defrecord R [] mini.proto/IThing (-describe [_] :qualified))
(pr-str (mini.proto/-describe (->R)))"
),
":qualified"
);
}
#[test]
fn an_unqualified_protocol_name_still_resolves_in_the_current_ns() {
assert_eq!(
eval_pr(
"(defprotocol P (-describe [this]))
(defrecord R [] P (-describe [_] :same-ns))
(pr-str (-describe (->R)))"
),
":same-ns"
);
}