macro_rules! run_aggregate_test {
( $db:expr, $coll:expr, $pipeline:expr, $opt:expr, $out:expr, $outcome:expr ) => {{
let mut cursor = $coll.aggregate($pipeline, $opt).unwrap();
if !$out {
let array = match $outcome.result {
Bson::Array(ref arr) => arr.clone(),
_ => panic!("Invalid `result` of aggregate test")
};
for bson in array {
let b2 = &Bson::Document(cursor.next().unwrap().unwrap());
assert!(eq::bson_eq(&bson, b2));
}
assert!(!cursor.has_next().expect("Failed to execute 'has_next()' on cursor"));
}
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_count_test {
( $db:expr, $coll:expr, $filter:expr, $opt:expr, $outcome:expr ) => {{
let n = $coll.count($filter, $opt).unwrap();
assert!($outcome.result.int_eq(n));
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_delete_test {
( $db:expr, $coll:expr, $filter:expr, $outcome:expr, $many:expr ) => {{
let count = if $many {
$coll.delete_many($filter, None)
} else {
$coll.delete_one($filter, None)
};
let expected = count.unwrap().deleted_count;
let actual = match $outcome.result {
Bson::Document(ref doc) => doc.get("deletedCount").unwrap(),
_ => panic!("`delete` test result should be a document")
};
assert!(actual.int_eq(expected as i64));
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_distinct_test {
( $db:expr, $coll:expr, $field_name:expr, $filter:expr, $outcome:expr ) => {{
let actual = $coll.distinct(&$field_name, $filter, None).unwrap();
let expected = match $outcome.result {
Bson::Array(ref arr) => arr.clone(),
_ => panic!("Invalid `result` of distinct test")
};
assert_eq!(actual.len(), expected.len());
for i in 0..actual.len() {
assert!(eq::bson_eq(&actual[i], &expected[i]));
}
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_find_one_and_delete_test {
( $db:expr, $coll:expr, $filter:expr, $opt:expr, $outcome:expr ) => {{
let doc_opt = $coll.find_one_and_delete($filter, $opt).unwrap();
let bson = match doc_opt {
Some(ref doc) => Bson::Document(doc.clone()),
None => Bson::Null
};
assert!(eq::bson_eq(&bson, &$outcome.result));
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_find_one_and_replace_test {
( $db:expr, $coll:expr, $filter:expr, $replacement:expr, $opt:expr,
$outcome:expr ) => {{
let doc_opt = $coll.find_one_and_replace($filter, $replacement,
$opt).unwrap();
let bson = match doc_opt {
Some(ref doc) => Bson::Document(doc.clone()),
None => Bson::Null
};
assert!(eq::bson_eq(&bson, &$outcome.result));
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_find_one_and_update_test {
( $db:expr, $coll:expr, $filter:expr, $update:expr, $opt:expr,
$outcome:expr ) => {{
let doc_opt = $coll.find_one_and_update($filter, $update, $opt).unwrap();
let bson = match doc_opt {
Some(ref doc) => Bson::Document(doc.clone()),
None => Bson::Null
};
assert!(eq::bson_eq(&bson, &$outcome.result));
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_find_test {
( $db:expr, $coll:expr, $filter:expr, $opt:expr, $outcome:expr ) => {{
let mut cursor = $coll.find($filter, $opt).unwrap();
let array = match $outcome.result {
Bson::Array(ref arr) => arr.clone(),
_ => panic!("Invalid `result` of find test")
};
for bson in array {
assert!(eq::bson_eq(&bson, &Bson::Document(cursor.next().unwrap().unwrap())));
}
assert!(!cursor.has_next().expect("Failed to execute 'has_next()' on cursor"));
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_insert_many_test {
( $db:expr, $coll:expr, $docs:expr, $outcome:expr ) => {{
let options = Some(InsertManyOptions::new());
let inserted = $coll.insert_many($docs, options).unwrap().inserted_ids.unwrap();
let ids_bson = match $outcome.result {
Bson::Document(ref doc) => doc.get("insertedIds").unwrap(),
_ => panic!("`insert_many` test result should be a document")
};
let ids = match *ids_bson {
Bson::Array(ref arr) => arr.into_iter(),
_ => panic!("`insertedIds` test result should be an array")
};
let mut actual_ids = inserted.values();
for expected_id in ids {
assert!(eq::bson_eq(&expected_id, actual_ids.next().unwrap()));
}
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_insert_one_test {
( $db:expr, $coll:expr, $doc:expr, $outcome:expr ) => {{
let inserted = $coll.insert_one($doc, None).unwrap().inserted_id.unwrap();
let id = match $outcome.result {
Bson::Document(ref doc) => doc.get("insertedId").unwrap(),
_ => panic!("`insert_one` test result should be a document")
};
assert!(eq::bson_eq(&id, &inserted));
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_replace_one_test {
( $db:expr, $coll:expr, $filter:expr, $replacement:expr, $upsert:expr,
$outcome:expr ) => {{
let options = ReplaceOptions { upsert: $upsert, write_concern: None };
let actual = $coll.replace_one($filter, $replacement, Some(options)).unwrap();
let (matched, modified, upserted) = match $outcome.result {
Bson::Document(ref doc) => (
doc.get("matchedCount").unwrap(),
doc.get("modifiedCount").unwrap(),
doc.get("upsertedId"),
),
_ => panic!("`delete` test result should be a document")
};
assert!(matched.int_eq(actual.matched_count as i64));
assert!(modified.int_eq(actual.modified_count as i64));
let id = match actual.upserted_id {
Some(Bson::Document(ref doc)) => doc.get("_id"),
_ => None
};
match (upserted, id) {
(None, None) => (),
(Some(ref bson1), Some(ref bson2)) =>
assert!(eq::bson_eq(&bson1, &bson2)),
_ => panic!("Wrong `upsertedId` returned")
};
check_coll!($db, $coll, $outcome.collection);
}};
}
macro_rules! run_update_test {
( $db:expr, $coll:expr, $filter:expr, $update:expr, $options:expr,
$many:expr, $outcome:expr ) => {{
let result = if $many {
$coll.update_many($filter, $update, $options)
} else {
$coll.update_one($filter, $update, $options)
};
let actual = result.unwrap();
let (matched, modified, upserted) = match $outcome.result {
Bson::Document(ref doc) => (
doc.get("matchedCount").unwrap(),
doc.get("modifiedCount").unwrap(),
doc.get("upsertedId"),
),
_ => panic!("`update` test result should be a document")
};
assert!(matched.int_eq(actual.matched_count as i64));
assert!(modified.int_eq(actual.modified_count as i64));
let id = match actual.upserted_id {
Some(Bson::Document(ref doc)) => doc.get("_id"),
_ => None
};
match (upserted, id) {
(None, None) => (),
(Some(ref bson1), Some(ref bson2)) =>
assert!(eq::bson_eq(&bson1, &bson2)),
_ => panic!("Wrong `upsertedId` returned")
};
check_coll!($db, $coll, $outcome.collection);
}};
}
#[macro_export]
macro_rules! run_suite {
( $file:expr, $coll:expr ) => {{
let json = Value::from_file($file).unwrap();
let suite = json.get_suite().unwrap();
let client = Client::connect("localhost", 27017).unwrap();
let db = client.db("test");
let coll = db.collection($coll);
for test in suite.tests {
coll.drop().unwrap();
let options = Some(InsertManyOptions::new());
coll.insert_many(suite.data.clone(), options).unwrap();
match test.operation {
Arguments::Aggregate { pipeline, options, out } =>
run_aggregate_test!(db, coll, pipeline, Some(options), out,
test.outcome),
Arguments::Count { filter, options } =>
run_count_test!(db, coll, filter, Some(options), test.outcome),
Arguments::Delete { filter, many } =>
run_delete_test!(db, coll, filter, test.outcome, many),
Arguments::Distinct { field_name, filter } =>
run_distinct_test!(db, coll, field_name, filter, test.outcome),
Arguments::Find { filter, options } =>
run_find_test!(db, coll, filter, Some(options), test.outcome),
Arguments::FindOneAndDelete { filter, options } =>
run_find_one_and_delete_test!(db, coll, filter, Some(options), test.outcome),
Arguments::FindOneAndReplace { filter, replacement, options } =>
run_find_one_and_replace_test!(db, coll, filter, replacement, Some(options), test.outcome),
Arguments::FindOneAndUpdate { filter, update, options } =>
run_find_one_and_update_test!(db, coll, filter, update, Some(options), test.outcome),
Arguments::InsertMany { documents } =>
run_insert_many_test!(db, coll, documents, test.outcome),
Arguments::InsertOne { document } =>
run_insert_one_test!(db, coll, document, test.outcome),
Arguments::ReplaceOne { filter, replacement, upsert } =>
run_replace_one_test!(db, coll, filter, replacement, Some(upsert), test.outcome),
Arguments::Update { filter, update, upsert, many } => {
let options = UpdateOptions { upsert: Some(upsert), ..Default::default() };
run_update_test!(db, coll, filter, update, Some(options), many, test.outcome)
}
};
}
}};
}
#[macro_export]
macro_rules! check_coll {
( $db:expr, $coll:expr, $coll_opt:expr ) => {{
let outcome_coll = match $coll_opt {
Some(ref coll) => coll.clone(),
None => continue
};
let coll = match outcome_coll.name {
Some(ref str) => $db.collection(&str),
None => $db.collection(&$coll.name())
};
let mut cursor = coll.find(None, None).unwrap();
for doc in &outcome_coll.data {
assert!(eq::bson_eq(&Bson::Document(doc.clone()),
&Bson::Document(cursor.next().unwrap().unwrap())));
}
assert!(!cursor.has_next().expect("Failed to execute 'has_next()' on cursor"));
$coll.drop().unwrap();
}};
}