use oso::{ClassBuilder, Oso, PolarClass};
use polar_core::error::{ErrorKind, PolarError, RuntimeError};
macro_rules! res {
($res:expr) => {
$res.unwrap().next().unwrap().unwrap();
};
(@not $res:expr) => {
assert!($res.unwrap().next().is_none());
};
}
#[derive(Clone)]
struct A {
x: String,
}
impl PolarClass for A {}
impl A {
pub fn new(x: String) -> Self {
Self { x }
}
pub fn foo(&self) -> i32 {
-1
}
}
pub mod b {
#[derive(Clone, Default)]
pub struct C {
pub y: String,
}
impl C {
pub fn new(y: String) -> Self {
Self { y }
}
pub fn foo(&self) -> i32 {
-1
}
}
impl oso::PolarClass for C {}
}
#[test]
fn test() {
let mut oso = Oso::new();
tracing_subscriber::fmt::init();
oso.register_class(
ClassBuilder::with_constructor(A::new)
.name("A")
.add_attribute_getter("x", |a_self: &A| a_self.x.clone())
.add_method("foo", A::foo)
.build(),
)
.unwrap();
oso.register_class(
ClassBuilder::with_constructor(b::C::new)
.name("C")
.add_attribute_getter("y", |c: &b::C| c.y.clone())
.add_method("foo", b::C::foo)
.build(),
)
.unwrap();
assert_eq!(
oso.load_str("missingSemicolon()").unwrap_err().to_string(),
"hit the end of the file unexpectedly. Did you forget a semi-colon at line 1, column 19:\n\t001: missingSemicolon()\n\t ^\n"
);
oso.load_str(r#"?= x = "hello world!" and x.ends_with("world!");"#)
.unwrap();
oso.clear_rules().unwrap();
let polar_file = std::env::var("CARGO_MANIFEST_DIR").unwrap() + "/../../../test/test.polar";
println!("Loading: {}", polar_file);
oso.load_files(vec![&polar_file]).unwrap();
assert!(oso.is_allowed("a", "b", "c").unwrap());
res!(oso.query_rule("floatLists", ()));
res!(oso.query_rule("intDicts", ()));
res!(oso.query_rule("comparisons", ()));
res!(oso.query_rule("testForall", ()));
res!(oso.query_rule("testRest", ()));
let a = A::new("hello".to_string());
res!(oso.query_rule("testMatches", (a.clone(),)));
let c = b::C::new("hello".to_string());
res!(oso.query_rule("testMethodCalls", (a, c)));
res!(oso.query_rule("testOr", ()));
res!(@not oso.query_rule("testCut", ()));
res!(oso.query(r#"builtinSpecializers(true, "Boolean")"#));
res!(@not oso.query(r#"builtinSpecializers(false, "Boolean")"#));
res!(oso.query(r#"builtinSpecializers(2, "Integer")"#));
res!(oso.query(r#"builtinSpecializers(1, "Integer")"#));
res!(@not oso.query(r#"builtinSpecializers(0, "Integer")"#));
res!(@not oso.query(r#"builtinSpecializers(-1, "Integer")"#));
res!(oso.query(r#"builtinSpecializers(1.0, "Float")"#));
res!(@not oso.query(r#"builtinSpecializers(0.0, "Float")"#));
res!(@not oso.query(r#"builtinSpecializers(-1.0, "Float")"#));
res!(oso.query(r#"builtinSpecializers(["foo", "bar", "baz"], "List")"#));
res!(@not oso.query(r#"builtinSpecializers(["bar", "foo", "baz"], "List")"#));
res!(oso.query(r#"builtinSpecializers({foo: "foo"}, "Dictionary")"#));
res!(@not oso.query(r#"builtinSpecializers({foo: "bar"}, "Dictionary")"#));
res!(oso.query(r#"builtinSpecializers("foo", "String")"#));
res!(@not oso.query(r#"builtinSpecializers("bar", "String")"#));
res!(@not oso.query(r#"builtinSpecializers(2, "IntegerWithGarbageFields")"#));
res!(@not oso.query(r#"builtinSpecializers({}, "DictionaryWithFields")"#));
res!(@not oso.query(r#"builtinSpecializers({z: 1}, "DictionaryWithFields")"#));
res!(oso.query(r#"builtinSpecializers({y: 1}, "DictionaryWithFields")"#));
let res = oso.query("testUnhandledPartial()").unwrap().next().unwrap();
assert!(
matches!(
res,
Err(oso::OsoError::Polar(PolarError(ErrorKind::Runtime(
RuntimeError::UnhandledPartial { .. }
)))),
),
"Expected unhandled partial error, got: {:#?}",
res
)
}