mod common;
use common::OsoTest;
use oso::errors::polar::{ErrorKind, PolarError, RuntimeError};
use oso::{Oso, OsoError, PolarClass, PolarValue};
#[test]
fn test_unify_external_not_supported() -> oso::Result<()> {
common::setup();
#[derive(PolarClass)]
struct Foo(pub i64);
let mut oso = OsoTest::new();
oso.oso.register_class(Foo::get_polar_class())?;
oso.load_str("unify(x, y) if x = y;");
let mut query = oso.oso.query_rule("unify", (Foo(1), Foo(1)))?;
let error = query.next().unwrap().unwrap_err();
assert!(
matches!(
&error,
OsoError::UnsupportedOperation {
operation,
type_name
} if operation == "equals" && type_name == "Foo"),
"{} doesn't match expected error",
error
);
Ok(())
}
#[test]
fn test_failing_inline_query() {
common::setup();
let mut oso = Oso::new();
let result = oso.load_str("?= 1 == 1;\n?= 1 == 0;");
match result {
Ok(_) => panic!("failed to detect failure of inline query"),
Err(e @ OsoError::InlineQueryFailedError { .. }) => {
assert_eq!(
format!("{}", e),
"Inline query failed 1 == 0 at line 2, column 4"
)
}
Err(_) => panic!("returned unexpected error"),
}
}
#[test]
fn test_attribute_does_not_exist() -> oso::Result<()> {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo;
oso.oso.register_class(Foo::get_polar_class())?;
oso.load_str("getattr(x, y, val) if val = x.(y);");
let mut query = oso.oso.query_rule(
"getattr",
(Foo, "bar", PolarValue::Variable("a".to_owned())),
)?;
let error = query.next().unwrap().unwrap_err();
if let OsoError::Polar(PolarError(ErrorKind::Runtime(RuntimeError::Application {
msg, ..
}))) = &error
{
assert_eq!(msg, "Attribute bar not found on type Foo.");
} else {
panic!("Error {} doesn't match expected type", error);
}
Ok(())
}
#[test]
fn test_method_does_not_exist() -> oso::Result<()> {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo;
impl Foo {
fn a(&self) -> i64 {
1
}
}
let foo_class = Foo::get_polar_class_builder()
.add_method("a", Foo::a)
.build();
oso.oso.register_class(foo_class)?;
oso.load_str("getmethod_b(x, val) if val = x.b();");
let mut query = oso.oso.query_rule("getmethod_b", (Foo, 1))?;
let error = query.next().unwrap().unwrap_err();
if let OsoError::Polar(PolarError(ErrorKind::Runtime(RuntimeError::Application {
msg, ..
}))) = &error
{
assert_eq!(msg, "Method b not found on type Foo.");
} else {
panic!("Error {} was not the expected type", error);
}
Ok(())
}
#[test]
fn test_class_method_does_not_exist() -> oso::Result<()> {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo;
impl Foo {
fn a() -> i64 {
1
}
}
let foo_class = Foo::get_polar_class_builder()
.add_class_method("a", Foo::a)
.build();
oso.oso.register_class(foo_class)?;
oso.load_str("getmethod_b(val) if val = Foo.b();");
let mut query = oso.oso.query_rule("getmethod_b", (1,))?;
let error = query.next().unwrap().unwrap_err();
if let OsoError::Polar(PolarError(ErrorKind::Runtime(RuntimeError::Application {
msg, ..
}))) = &error
{
assert_eq!(msg, "Class method b not found on type Foo.");
} else {
panic!("Error {} was not the expected type", error);
}
Ok(())
}
#[test]
fn test_wrong_argument_types() {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo;
impl Foo {
fn a(&self) -> i64 {
1
}
fn bar(&self, _bar: Bar) -> i64 {
2
}
fn bar_x(&self, _x: i64, _bar: Bar) -> i64 {
3
}
fn int(&self, _x: u8) -> i64 {
4
}
}
#[derive(PolarClass, Clone)]
struct Bar;
#[derive(PolarClass)]
struct Unregistered;
let foo_class = Foo::get_polar_class_builder()
.add_method("a", Foo::a)
.add_method("bar", Foo::bar)
.add_method("bar_x", Foo::bar_x)
.add_method("int", Foo::int)
.build();
oso.oso.register_class(foo_class).unwrap();
oso.oso.register_class(Bar::get_polar_class()).unwrap();
oso.load_str(
r#"a(f, v) if v = f.a();
bar(f, arg) if _v = f.bar(arg);
bar_x(f, arg, arg1) if _v = f.bar_x(arg, arg1);
int(f, arg) if _v = f.int(arg);"#,
);
let mut query = oso.oso.query_rule("a", (Foo, 1)).unwrap();
assert_eq!(query.next().unwrap().unwrap().keys().count(), 0);
let mut query = oso.oso.query_rule("bar", (Foo, Bar)).unwrap();
assert_eq!(query.next().unwrap().unwrap().keys().count(), 0);
let mut query = oso.oso.query_rule("bar", (Foo, 1)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("bar", (Foo, Foo)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("bar", (Foo, Unregistered)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("bar_x", (Foo, 1, Bar)).unwrap();
assert_eq!(query.next().unwrap().unwrap().keys().count(), 0);
let mut query = oso.oso.query_rule("bar_x", (Foo, Foo, 1)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("bar_x", (Foo, Bar, 1)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("bar_x", (Foo, Bar, Bar)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso
.oso
.query_rule("bar_x", (Foo, Bar, Unregistered))
.unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("int", (Foo, 0)).unwrap();
assert_eq!(query.next().unwrap().unwrap().keys().count(), 0);
let mut query = oso.oso.query_rule("int", (Foo, Bar)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("int", (Foo, 0.)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("int", (Foo, i64::MAX)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("int", (Foo, -1_i8)).unwrap();
assert!(query.next().unwrap().is_err());
}
#[test]
fn test_wrong_argument_types_constructor() {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo;
#[derive(PolarClass, Clone)]
struct Bar;
impl Foo {
fn new(_bar: Bar) -> Self {
Foo
}
}
let foo_class = Foo::get_polar_class_builder()
.set_constructor(Foo::new)
.build();
oso.oso.register_class(foo_class).unwrap();
oso.oso.register_class(Bar::get_polar_class()).unwrap();
oso.load_str("new_foo(val) if _v = new Foo(val);");
let mut query = oso.oso.query_rule("new_foo", (Bar,)).unwrap();
assert_eq!(query.next().unwrap().unwrap().keys().count(), 0);
let mut query = oso.oso.query_rule("new_foo", (1,)).unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("new_foo", (Foo,)).unwrap();
assert!(query.next().unwrap().is_err());
}
#[test]
fn test_match_attribute_does_not_exist() {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo {
#[polar(attribute)]
x: i64,
}
impl Foo {
fn new() -> Self {
Foo { x: 1 }
}
}
let foo_class = Foo::get_polar_class_builder()
.set_constructor(Foo::new)
.build();
oso.oso.register_class(foo_class).unwrap();
oso.load_str(
r#"foo(d) if d matches Foo{x: 1};
no_match_foo(d) if not d matches Foo{not_an_attr: 1};"#,
);
oso.qeval("foo(new Foo())");
oso.qeval("no_match_foo(new Foo())");
}
#[test]
fn test_match_non_existent_class() {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo {
#[polar(attribute)]
x: i64,
}
impl Foo {
fn new() -> Self {
Foo { x: 1 }
}
}
let foo_class = Foo::get_polar_class_builder()
.set_constructor(Foo::new)
.build();
oso.oso.register_class(foo_class).unwrap();
oso.load_str("foo(d) if d matches Bar{x: 1};");
oso.query_err("foo(new Foo())");
}
#[test]
fn test_wrong_argument_arity() -> oso::Result<()> {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo;
impl Foo {
fn a(&self, x: i64) -> i64 {
x
}
}
let foo_class = Foo::get_polar_class_builder()
.add_method("a", Foo::a)
.build();
oso.oso.register_class(foo_class)?;
oso.load_str(
r#"getmethod_a1(x, val) if val = x.a(val);
getmethod_a2(x, val, val2) if val = x.a(val, val2);
getmethod_a0(x) if x.a();"#,
);
let mut query = oso.oso.query_rule("getmethod_a1", (Foo, 1))?;
assert_eq!(query.next().unwrap().unwrap().keys().count(), 0);
let mut query = oso.oso.query_rule("getmethod_a2", (Foo, 1, 2))?;
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query_rule("getmethod_a0", (Foo,))?;
assert!(query.next().unwrap().is_err());
Ok(())
}
#[test]
fn test_class_does_not_exist() {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo {
#[polar(attribute)]
x: i64,
}
impl Foo {
fn new() -> Self {
Foo { x: 1 }
}
}
let foo_class = Foo::get_polar_class_builder()
.set_constructor(Foo::new)
.build();
oso.oso.register_class(foo_class).unwrap();
oso.load_str("bar(b) if b = new Bar();");
let mut query = oso.oso.query("bar(b)").unwrap();
assert!(query.next().unwrap().is_err());
}
#[test]
fn test_constructor_keyword_arguments_error() {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo {
#[polar(attribute)]
x: i64,
}
impl Foo {
fn new(x: i64) -> Self {
Foo { x }
}
}
let foo_class = Foo::get_polar_class_builder()
.set_constructor(Foo::new)
.build();
oso.oso.register_class(foo_class).unwrap();
let mut query = oso.oso.query("x = new Foo(1)").unwrap();
assert_eq!(query.next().unwrap().unwrap().keys().count(), 1);
let mut query = oso.oso.query("x = new Foo(x: 1)").unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query("x = new Foo(1, x: 1)").unwrap();
assert!(query.next().unwrap().is_err());
}
#[test]
fn test_method_keyword_arguments_error() -> oso::Result<()> {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass)]
struct Foo {
#[polar(attribute)]
x: i64,
}
impl Foo {
fn new() -> Self {
Foo { x: 1 }
}
fn a(&self, x: i64) -> i64 {
x
}
}
let foo_class = Foo::get_polar_class_builder()
.set_constructor(Foo::new)
.add_method("a", Foo::a)
.build();
oso.oso.register_class(foo_class)?;
let mut query = oso.oso.query("x = new Foo().a(1)").unwrap();
assert_eq!(query.next().unwrap().unwrap().get_typed::<i64>("x")?, 1);
let mut query = oso.oso.query("x = new Foo().a(x: 1)").unwrap();
assert!(query.next().unwrap().is_err());
let mut query = oso.oso.query("x = new Foo().a(1, x: 1)").unwrap();
assert!(query.next().unwrap().is_err());
Ok(())
}
#[test]
fn test_operator_unimplemented() -> oso::Result<()> {
common::setup();
let mut oso = OsoTest::new();
#[derive(PolarClass, PartialOrd, PartialEq)]
struct Foo(i64);
let foo_class = Foo::get_polar_class_builder().with_equality_check().build();
oso.oso.register_class(foo_class)?;
oso.load_str("lt(a, b) if a < b;");
oso.qeval("lt(1, 2)");
assert!(Foo(0) < Foo(1));
let mut query = oso.oso.query_rule("lt", (Foo(0), Foo(1))).unwrap();
assert!(query.next().unwrap().is_err());
Ok(())
}