mongodb 0.2.3

A native MongoDB driver developed under MongoDB labs.
Documentation
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();
    }};
}