use asdi::features::{ FeatureSet, FEATURE_COMPARISONS, FEATURE_CONSTRAINTS, FEATURE_DISJUNCTION, FEATURE_NEGATION, }; use asdi::Program; mod common; use common::{quick_parser_check, quick_parser_check_with_options}; // ------------------------------------------------------------------------------------------------ // Success cases // ------------------------------------------------------------------------------------------------ #[test] fn test_parse_comments() { quick_parser_check( r#".infer ancestor(string,string). % Here's a comment ?- ancestor(xerces, X). % and another "#, None, ); } #[test] fn test_parse_nothing() { quick_parser_check("", Program::default()); } #[test] fn test_parse_string_fact() { quick_parser_check("human(\"Socrates\").", None); } #[test] fn test_parse_number_fact() { quick_parser_check("age(socrates, 42).", None); } #[test] fn test_parse_boolean_fact_t() { quick_parser_check("deceased(socrates, true).", None); } #[test] fn test_parse_boolean_fact_f() { quick_parser_check("deceased(socrates, false).", None); } #[test] fn test_parse_identifier_fact() { quick_parser_check("edge(a, b).", None); } #[test] fn test_parse_one_rule_turnstile() { quick_parser_check("mortal(X) :- human(X).", None); } #[test] #[should_panic] fn test_parse_rule_expression_fail() { quick_parser_check("old(X) :- human(X), X > 50.", None); } #[test] fn test_parse_one_rule_unicode_arrow() { quick_parser_check("mortal(X) ⟵ human(X).", None); } #[test] fn test_parse_one_rule_ascii_arrow() { quick_parser_check("mortal(X) <- human(X).", None); } #[test] fn test_parse_one_rule_multiples_unicode_and() { quick_parser_check("path(X, Y) ⟵ edge(X, Z) ∧ path(Z, Y).", None); } #[test] fn test_parse_one_rule_multiples_comma() { quick_parser_check("path(X, Y) ⟵ edge(X, Z), path(Z, Y).", None); } #[test] fn test_parse_one_rule_multiples_ampersand() { quick_parser_check("path(X, Y) ⟵ edge(X, Z) & path(Z, Y).", None); } #[test] fn test_parse_one_rule_multiples_and() { quick_parser_check("path(X, Y) ⟵ edge(X, Z) AND path(Z, Y).", None); } #[test] fn test_parse_query_prefixed() { quick_parser_check(".infer path(string, string). ?- path(X, Y).", None); } #[test] fn test_parse_query_suffixed() { quick_parser_check(".infer path(string, string). path(X, Y)?", None); } #[test] fn test_parse_pragma_assert() { quick_parser_check(r#".assert human(string)."#, None); } #[test] fn test_parse_pragma_assert_named() { quick_parser_check(r#".assert human(name: string)."#, None); } // ------------------------------------------------------------------------------------------------ // Feature-gated success cases // ------------------------------------------------------------------------------------------------ #[test] fn test_parse_rule_expression_negated_term() { quick_parser_check_with_options( "alien(X) :- living(X), ! human(X).", FeatureSet::default().add_support_for(&FEATURE_NEGATION), None, ); } #[test] fn test_parse_rule_with_comparison() { quick_parser_check_with_options( "old(X) :- human(X), X > 50.", FeatureSet::default().add_support_for(&FEATURE_COMPARISONS), None, ); } #[test] fn test_parse_rule_with_unicode_comparison() { quick_parser_check_with_options( r#"old(X) :- human(X), X ≛ "$xerc.*"."#, FeatureSet::default().add_support_for(&FEATURE_COMPARISONS), None, ); } #[test] fn test_parse_constraint_rule() { quick_parser_check_with_options( "⊥ :- dead(X) AND alive(X).", FeatureSet::default().add_support_for(&FEATURE_CONSTRAINTS), None, ); quick_parser_check_with_options( ":- dead(X) AND alive(X).", FeatureSet::default().add_support_for(&FEATURE_CONSTRAINTS), None, ); } #[test] fn test_parse_rule_with_disjunction() { quick_parser_check_with_options( "mother(X); father(X) :- parent(X).", FeatureSet::default().add_support_for(&FEATURE_DISJUNCTION), None, ); quick_parser_check_with_options( "mother(X) | father(X) :- parent(X).", FeatureSet::default().add_support_for(&FEATURE_DISJUNCTION), None, ); quick_parser_check_with_options( "mother(X) OR father(X) :- parent(X).", FeatureSet::default().add_support_for(&FEATURE_DISJUNCTION), None, ); quick_parser_check_with_options( "mother(X) ∨ father(X) :- parent(X).", FeatureSet::default().add_support_for(&FEATURE_DISJUNCTION), None, ); } // ------------------------------------------------------------------------------------------------ // Should panic cases // ------------------------------------------------------------------------------------------------ #[test] #[should_panic] fn test_fail_disabled_negated_term() { quick_parser_check("alien(X) :- ! human(X).", None); } #[test] #[should_panic] fn test_fail_not_well_formed_1() { quick_parser_check("mortal(X, Y) :- human(X).", None); } #[test] #[should_panic] fn test_fail_not_well_formed_2() { quick_parser_check_with_options( "alien(X) :- ! human(X).", FeatureSet::default().add_support_for(&FEATURE_NEGATION), None, ); } #[cfg(test_old)] mod tests { use super::*; use crate::parse::parse_str; #[test] fn test_well_formed() { let program = parse_str(r#"reachable(n1,n3) :- link(n1,n2), reachable(n2,n3)."#); assert!(program.is_ok()); let well_formed = WellFormedValidator::default().validate(&program.unwrap().into_parsed()); assert!(well_formed.is_ok()) } #[test] fn test_not_well_formed() { let program = parse_str(r#"reachable(n1,n3) :- link(n1,n2), reachable(n1,n2)."#); assert!(program.is_ok()); let well_formed = WellFormedValidator::default().validate(&program.unwrap().into_parsed()); assert_eq!( well_formed.err().unwrap().to_string(), String::from("Atom 'reachable', [line 1, column 1]: the variables 'n3' in the head do not appear in any positive form in the body.") ); } #[test] #[ignore] fn test_well_formed_negative() { let program = parse_str(r#"moreThanOneHop(n1,n2) :‐ reachable(n1,n2), !link(n1,n2)."#); assert!(program.is_ok()); let well_formed = WellFormedValidator::default().validate(&program.unwrap().into_parsed()); assert!(well_formed.is_ok()) } #[test] #[ignore] fn test_not_well_formed_negative() { let program = parse_str(r#"moreThanOneHop(n1,n2) :‐ !link(n1,n2)."#); assert!(program.is_ok()); let well_formed = WellFormedValidator::default().validate(&program.unwrap().into_parsed()); assert!(well_formed.is_ok()) } }