move tests
parent
1eec1374ba
commit
d57224aa87
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2022, The Cozo Project Authors.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
* If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use crate::data::json::JsonValue;
|
||||
use crate::data::value::DataValue;
|
||||
|
||||
#[test]
|
||||
fn bad_values() {
|
||||
println!("{}", json!(f64::INFINITY));
|
||||
println!("{}", JsonValue::from(DataValue::from(f64::INFINITY)));
|
||||
println!("{}", JsonValue::from(DataValue::from(f64::NEG_INFINITY)));
|
||||
println!("{}", JsonValue::from(DataValue::from(f64::NAN)));
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2022, The Cozo Project Authors.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
* If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
use smartstring::SmartString;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::data::memcmp::{decode_bytes, MemCmpEncoder};
|
||||
use crate::data::value::{DataValue, Num, UuidWrapper};
|
||||
|
||||
#[test]
|
||||
fn encode_decode_num() {
|
||||
use rand::prelude::*;
|
||||
|
||||
let n = i64::MAX;
|
||||
let mut collected = vec![];
|
||||
|
||||
let mut test_num = |n: Num| {
|
||||
let mut encoder = vec![];
|
||||
encoder.encode_num(n);
|
||||
let (decoded, rest) = Num::decode_from_key(&encoder);
|
||||
assert_eq!(decoded, n);
|
||||
assert!(rest.is_empty());
|
||||
collected.push(encoder);
|
||||
};
|
||||
for i in 0..54 {
|
||||
for j in 0..1000 {
|
||||
let vb = (n >> i) - j;
|
||||
for v in [vb, -vb - 1] {
|
||||
test_num(Num::Int(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
test_num(Num::Float(f64::INFINITY));
|
||||
test_num(Num::Float(f64::NEG_INFINITY));
|
||||
test_num(Num::Float(f64::NAN));
|
||||
for _ in 0..100000 {
|
||||
let f = (thread_rng().gen::<f64>() - 0.5) * 2.0;
|
||||
test_num(Num::Float(f));
|
||||
test_num(Num::Float(1. / f));
|
||||
}
|
||||
let mut collected_copy = collected.clone();
|
||||
collected.sort();
|
||||
collected_copy.sort_by_key(|c| Num::decode_from_key(c).0);
|
||||
assert_eq!(collected, collected_copy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_decode_uuid() {
|
||||
let uuid = DataValue::Uuid(UuidWrapper(
|
||||
Uuid::parse_str("dd85b19a-5fde-11ed-a88e-1774a7698039").unwrap(),
|
||||
));
|
||||
let mut encoder = vec![];
|
||||
encoder.encode_datavalue(&uuid);
|
||||
let (decoded, remaining) = DataValue::decode_from_key(&encoder);
|
||||
assert_eq!(decoded, uuid);
|
||||
assert!(remaining.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_decode_bytes() {
|
||||
let target = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit...";
|
||||
for i in 0..target.len() {
|
||||
let bs = &target[i..];
|
||||
let mut encoder: Vec<u8> = vec![];
|
||||
encoder.encode_bytes(bs);
|
||||
let (decoded, remaining) = decode_bytes(&encoder);
|
||||
assert!(remaining.is_empty());
|
||||
assert_eq!(bs, decoded);
|
||||
|
||||
let mut encoder: Vec<u8> = vec![];
|
||||
encoder.encode_bytes(target);
|
||||
encoder.encode_bytes(bs);
|
||||
encoder.encode_bytes(bs);
|
||||
encoder.encode_bytes(target);
|
||||
|
||||
let (decoded, remaining) = decode_bytes(&encoder);
|
||||
assert_eq!(&target[..], decoded);
|
||||
|
||||
let (decoded, remaining) = decode_bytes(remaining);
|
||||
assert_eq!(bs, decoded);
|
||||
|
||||
let (decoded, remaining) = decode_bytes(remaining);
|
||||
assert_eq!(bs, decoded);
|
||||
|
||||
let (decoded, remaining) = decode_bytes(remaining);
|
||||
assert_eq!(&target[..], decoded);
|
||||
assert!(remaining.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn specific_encode() {
|
||||
let mut encoder = vec![];
|
||||
encoder.encode_datavalue(&DataValue::from(2095));
|
||||
// println!("e1 {:?}", encoder);
|
||||
encoder.encode_datavalue(&DataValue::Str(SmartString::from("MSS")));
|
||||
// println!("e2 {:?}", encoder);
|
||||
let (a, remaining) = DataValue::decode_from_key(&encoder);
|
||||
// println!("r {:?}", remaining);
|
||||
let (b, remaining) = DataValue::decode_from_key(remaining);
|
||||
assert!(remaining.is_empty());
|
||||
assert_eq!(a, DataValue::from(2095));
|
||||
assert_eq!(b, DataValue::Str(SmartString::from("MSS")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_decode_datavalues() {
|
||||
let mut dv = vec![
|
||||
DataValue::Null,
|
||||
DataValue::Bool(false),
|
||||
DataValue::Bool(true),
|
||||
DataValue::from(1),
|
||||
DataValue::from(1.0),
|
||||
DataValue::from(i64::MAX),
|
||||
DataValue::from(i64::MAX - 1),
|
||||
DataValue::from(i64::MAX - 2),
|
||||
DataValue::from(i64::MIN),
|
||||
DataValue::from(i64::MIN + 1),
|
||||
DataValue::from(i64::MIN + 2),
|
||||
DataValue::from(f64::INFINITY),
|
||||
DataValue::from(f64::NEG_INFINITY),
|
||||
DataValue::List(vec![]),
|
||||
];
|
||||
dv.push(DataValue::List(dv.clone()));
|
||||
dv.push(DataValue::List(dv.clone()));
|
||||
let mut encoded = vec![];
|
||||
let v = DataValue::List(dv);
|
||||
encoded.encode_datavalue(&v);
|
||||
let (decoded, remaining) = DataValue::decode_from_key(&encoded);
|
||||
assert!(remaining.is_empty());
|
||||
assert_eq!(decoded, v);
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2022, The Cozo Project Authors.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
* If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::mem::size_of;
|
||||
|
||||
use smartstring::SmartString;
|
||||
|
||||
use crate::data::symb::Symbol;
|
||||
use crate::data::value::DataValue;
|
||||
|
||||
#[test]
|
||||
fn show_size() {
|
||||
dbg!(size_of::<DataValue>());
|
||||
dbg!(size_of::<Symbol>());
|
||||
dbg!(size_of::<String>());
|
||||
dbg!(size_of::<HashMap<String, String>>());
|
||||
dbg!(size_of::<BTreeMap<String, String>>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn utf8() {
|
||||
let c = char::from_u32(0x10FFFF).unwrap();
|
||||
let mut s = String::new();
|
||||
s.push(c);
|
||||
println!("{}", s);
|
||||
println!(
|
||||
"{:b} {:b} {:b} {:b}",
|
||||
s.as_bytes()[0],
|
||||
s.as_bytes()[1],
|
||||
s.as_bytes()[2],
|
||||
s.as_bytes()[3]
|
||||
);
|
||||
dbg!(s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_datavalues() {
|
||||
println!("{}", DataValue::Null);
|
||||
println!("{}", DataValue::Bool(true));
|
||||
println!("{}", DataValue::from(-1));
|
||||
println!("{}", DataValue::from(-1121212121.331212121));
|
||||
println!("{}", DataValue::from(f64::NAN));
|
||||
println!("{}", DataValue::from(f64::NEG_INFINITY));
|
||||
println!(
|
||||
"{}",
|
||||
DataValue::List(vec![
|
||||
DataValue::Bool(false),
|
||||
DataValue::Str(SmartString::from(r###"abc"你"好'啊👌"###)),
|
||||
DataValue::from(f64::NEG_INFINITY),
|
||||
])
|
||||
);
|
||||
}
|
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright 2022, The Cozo Project Authors.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
* If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
use itertools::Itertools;
|
||||
use log::debug;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::new_cozo_mem;
|
||||
|
||||
#[test]
|
||||
fn test_limit_offset() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db
|
||||
.run_script("?[a] := a in [5,3,1,2,4] :limit 2", Default::default())
|
||||
.unwrap()
|
||||
.rows
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect_vec();
|
||||
assert_eq!(json!(res), json!([3, 5]));
|
||||
let res = db
|
||||
.run_script(
|
||||
"?[a] := a in [5,3,1,2,4] :limit 2 :offset 1",
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect_vec();
|
||||
assert_eq!(json!(res), json!([1, 3]));
|
||||
let res = db
|
||||
.run_script(
|
||||
"?[a] := a in [5,3,1,2,4] :limit 2 :offset 4",
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect_vec();
|
||||
assert_eq!(json!(res), json!([4]));
|
||||
let res = db
|
||||
.run_script(
|
||||
"?[a] := a in [5,3,1,2,4] :limit 2 :offset 5",
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect_vec();
|
||||
assert_eq!(json!(res), json!([]));
|
||||
}
|
||||
#[test]
|
||||
fn test_normal_aggr_empty() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db
|
||||
.run_script("?[count(a)] := a in []", Default::default())
|
||||
.unwrap()
|
||||
.rows;
|
||||
assert_eq!(res, vec![vec![json!(0)]]);
|
||||
}
|
||||
#[test]
|
||||
fn test_meet_aggr_empty() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db
|
||||
.run_script("?[min(a)] := a in []", Default::default())
|
||||
.unwrap()
|
||||
.rows;
|
||||
assert_eq!(res, vec![vec![json!(null)]]);
|
||||
|
||||
let res = db
|
||||
.run_script("?[min(a), count(a)] := a in []", Default::default())
|
||||
.unwrap()
|
||||
.rows;
|
||||
assert_eq!(res, vec![vec![json!(null), json!(0)]]);
|
||||
}
|
||||
#[test]
|
||||
fn test_layers() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db
|
||||
.run_script(
|
||||
r#"
|
||||
y[a] := a in [1,2,3]
|
||||
x[sum(a)] := y[a]
|
||||
x[sum(a)] := a in [4,5,6]
|
||||
?[sum(a)] := x[a]
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows;
|
||||
assert_eq!(res[0][0], json!(21.))
|
||||
}
|
||||
#[test]
|
||||
fn test_conditions() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
let db = new_cozo_mem().unwrap();
|
||||
db.run_script(
|
||||
r#"
|
||||
{
|
||||
?[code] <- [['a'],['b'],['c']]
|
||||
:create airport {code}
|
||||
}
|
||||
{
|
||||
?[fr, to, dist] <- [['a', 'b', 1.1], ['a', 'c', 0.5], ['b', 'c', 9.1]]
|
||||
:create route {fr, to => dist}
|
||||
}
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
debug!("real test begins");
|
||||
let res = db
|
||||
.run_script(
|
||||
r#"
|
||||
r[code, dist] := *airport{code}, *route{fr: code, dist};
|
||||
?[dist] := r['a', dist], dist > 0.5, dist <= 1.1;
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows;
|
||||
assert_eq!(res[0][0], json!(1.1))
|
||||
}
|
||||
#[test]
|
||||
fn test_classical() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db
|
||||
.run_script(
|
||||
r#"
|
||||
parent[] <- [['joseph', 'jakob'],
|
||||
['jakob', 'issac'],
|
||||
['issac', 'abraham']]
|
||||
grandparent[gcld, gp] := parent[gcld, p], parent[p, gp]
|
||||
?[who] := grandparent[who, 'abraham']
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows;
|
||||
println!("{:?}", res);
|
||||
assert_eq!(res[0][0], json!("jakob"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_columns() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
|
||||
db.run_script(
|
||||
r#"
|
||||
:create status {uid: String, ts default now() => quitted: Bool, mood: String}
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
db.run_script(
|
||||
r#"
|
||||
?[uid, quitted, mood] <- [['z', true, 'x']]
|
||||
:put status {uid => quitted, mood}
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rm_does_not_need_all_keys() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
db.run_script(":create status {uid => mood}", Default::default())
|
||||
.unwrap();
|
||||
assert!(db
|
||||
.run_script(
|
||||
"?[uid, mood] <- [[1, 2]] :put status {uid => mood}",
|
||||
Default::default()
|
||||
)
|
||||
.is_ok());
|
||||
assert!(db
|
||||
.run_script(
|
||||
"?[uid, mood] <- [[2]] :put status {uid}",
|
||||
Default::default()
|
||||
)
|
||||
.is_err());
|
||||
assert!(db
|
||||
.run_script(
|
||||
"?[uid, mood] <- [[3, 2]] :rm status {uid => mood}",
|
||||
Default::default()
|
||||
)
|
||||
.is_ok());
|
||||
assert!(db
|
||||
.run_script("?[uid] <- [[1]] :rm status {uid}", Default::default())
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strict_checks_for_fixed_rules_args() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db.run_script(
|
||||
r#"
|
||||
r[] <- [[1, 2]]
|
||||
?[] <~ PageRank(r[_, _])
|
||||
"#,
|
||||
Default::default(),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db.run_script(
|
||||
r#"
|
||||
r[] <- [[1, 2]]
|
||||
?[] <~ PageRank(r[a, b])
|
||||
"#,
|
||||
Default::default(),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db.run_script(
|
||||
r#"
|
||||
r[] <- [[1, 2]]
|
||||
?[] <~ PageRank(r[a, a])
|
||||
"#,
|
||||
Default::default(),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn do_not_unify_underscore() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db
|
||||
.run_script(
|
||||
r#"
|
||||
r1[] <- [[1, 'a'], [2, 'b']]
|
||||
r2[] <- [[2, 'B'], [3, 'C']]
|
||||
|
||||
?[l1, l2] := r1[_ , l1], r2[_ , l2]
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows;
|
||||
assert_eq!(res.len(), 4);
|
||||
|
||||
let res = db.run_script(
|
||||
r#"
|
||||
?[_] := _ = 1
|
||||
"#,
|
||||
Default::default(),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
|
||||
let res = db
|
||||
.run_script(
|
||||
r#"
|
||||
?[x] := x = 1, _ = 1, _ = 2
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows;
|
||||
|
||||
assert_eq!(res.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returning_relations() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
let res = db
|
||||
.run_script(
|
||||
r#"
|
||||
{
|
||||
?[] <- [[1,2,3]]
|
||||
:yield nxt
|
||||
}
|
||||
{
|
||||
?[a,b,c] := nxt[a, b, c]
|
||||
}
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows;
|
||||
assert_eq!(json!(res), json!([[1, 2, 3]]));
|
||||
|
||||
let res = db
|
||||
.run_script(
|
||||
r#"
|
||||
{
|
||||
?[a] <- [[1]]
|
||||
:yield first_yield
|
||||
}
|
||||
{
|
||||
?[a] := first_yield[b], a = b + 1
|
||||
:yield second_yield
|
||||
}
|
||||
{
|
||||
?[a] := first_yield[a]
|
||||
?[a] := second_yield[a]
|
||||
}
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.rows;
|
||||
assert_eq!(json!(res), json!([[1], [2]]));
|
||||
|
||||
let res = db.run_script(
|
||||
r#"
|
||||
{
|
||||
?[] <- [[1,2,3]]
|
||||
:yield nxt
|
||||
}
|
||||
{
|
||||
nxt[] <- [[2, 3, 5]]
|
||||
?[a,b,c] := nxt[a, b, c]
|
||||
}
|
||||
"#,
|
||||
Default::default(),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trigger() {
|
||||
let db = new_cozo_mem().unwrap();
|
||||
db.run_script(":create friends {fr: Int, to: Int}", Default::default())
|
||||
.unwrap();
|
||||
db.run_script(":create friends.rev {to: Int, fr: Int}", Default::default())
|
||||
.unwrap();
|
||||
db.run_script(
|
||||
r#"
|
||||
::set_triggers friends
|
||||
|
||||
on put {
|
||||
?[fr, to] := _new[fr, to]
|
||||
|
||||
:put friends.rev{ to, fr }
|
||||
}
|
||||
on rm {
|
||||
?[fr, to] := _old[fr, to]
|
||||
|
||||
:rm friends.rev{ to, fr }
|
||||
}
|
||||
"#,
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
db.run_script(
|
||||
r"?[fr, to] <- [[1,2]] :put friends {fr, to}",
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
let ret = db
|
||||
.export_relations(["friends", "friends.rev"].into_iter())
|
||||
.unwrap();
|
||||
let frs = ret.get("friends").unwrap();
|
||||
assert_eq!(vec![json!(1), json!(2)], frs.rows[0]);
|
||||
|
||||
let frs_rev = ret.get("friends.rev").unwrap();
|
||||
assert_eq!(vec![json!(2), json!(1)], frs_rev.rows[0]);
|
||||
}
|
Loading…
Reference in New Issue