From: Nicolas Luck Date: Wed, 12 Jul 2023 09:57:53 +0000 (+0200) Subject: Add test for programatic queries X-Git-Tag: remove^2~64 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=c0dd94c8a3c4bf37961575324a7bd21792845088;p=scryer-prolog.git Add test for programatic queries --- diff --git a/Cargo.lock b/Cargo.lock index 05e54911..29cf7f67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1004,6 +1004,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "markup5ever" version = "0.8.1" @@ -1833,6 +1839,7 @@ dependencies = [ "lazy_static", "lexical", "libc", + "maplit", "modular-bitfield", "native-tls", "ordered-float", diff --git a/Cargo.toml b/Cargo.toml index 6e42de23..a6f97b04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ futures = "0.3" assert_cmd = "1.0.3" predicates-core = "1.0.2" serial_test = "0.5.1" +maplit = "1.0.2" [patch.crates-io] modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } diff --git a/src/lib.rs b/src/lib.rs index 2846fd0e..d643296f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ #[macro_use] extern crate static_assertions; +#[cfg(test)] +#[macro_use] extern crate maplit; #[macro_use] pub mod macros; diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 1aca907f..c45d7cb4 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -936,3 +936,40 @@ impl Machine { } } } + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn programatic_query() { + let mut machine = Machine::with_test_streams(); + + machine.load_module_string("facts", String::from(r#" + triple("a", "p1", "b"). + triple("a", "p2", "b"). + "#)); + + let query = String::from(r#"triple("a",P,"b")."#); + let output = machine.run_query(query); + assert_eq!(output, QueryResult::Matches(vec![ + QueryMatch::from(btreemap!{ + "P" => Value::from("p1"), + }), + QueryMatch::from(btreemap!{ + "P" => Value::from("p2"), + }), + ])); + + assert_eq!( + machine.run_query(String::from(r#"triple("a","p1","b")."#)), + QueryResult::True + ); + + assert_eq!( + machine.run_query(String::from(r#"triple("x","y","z")."#)), + QueryResult::False + ); + } +} diff --git a/src/machine/parsed_results.rs b/src/machine/parsed_results.rs index 3b47ad6b..984c7439 100644 --- a/src/machine/parsed_results.rs +++ b/src/machine/parsed_results.rs @@ -8,7 +8,12 @@ use crate::atom_table::*; pub enum QueryResult { True, False, - Matches(Vec), + Matches(Vec), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct QueryMatch { + pub bindings: BTreeMap } #[derive(Debug, Clone, PartialEq, Eq)] @@ -30,6 +35,24 @@ pub enum Value { Var, } +impl From> for QueryMatch { + fn from(bindings: BTreeMap<&str, Value>) -> Self { + QueryMatch { + bindings: bindings.into_iter() + .map(|(k, v)| (k.to_string(), v)) + .collect::>() + } + } +} + +impl From> for QueryMatch { + fn from(bindings: BTreeMap) -> Self { + QueryMatch { + bindings + } + } +} + impl From> for QueryResult { fn from(query_result_lines: Vec) -> Self { // If there is only one line, and it is true or false, return that. @@ -50,14 +73,21 @@ impl From> for QueryResult { } // If there is at least one match, return all matches. - if query_result_lines.iter().any(|l| { - if let &QueryResultLine::Match(_) = l { true } else { false } - }) { - let all_matches = query_result_lines.into_iter() - .filter(|l| { - if let &QueryResultLine::Match(_) = l { true } else { false } - }) - .collect::>(); + let all_matches = query_result_lines.into_iter() + .filter(|l| { + if let &QueryResultLine::Match(_) = l { true } else { false } + }) + .map(|l| { + match l { + QueryResultLine::Match(m) => { + QueryMatch::from(m) + }, + _ => unreachable!() + } + }) + .collect::>(); + + if !all_matches.is_empty() { return QueryResult::Matches(all_matches); } @@ -145,4 +175,10 @@ impl TryFrom for Value { Err(()) } } +} + +impl From<&str> for Value { + fn from(str: &str) -> Self { + Value::String(str.to_string()) + } } \ No newline at end of file