use std::time::Duration;
use bson::{Bson, Document};
use serde::Deserialize;
use crate::{
error::Error,
options::{Acknowledgment, WriteConcern},
test::run_spec_test,
};
#[derive(Debug, Deserialize)]
struct TestFile {
pub tests: Vec<TestCase>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct TestCase {
pub description: String,
pub valid: bool,
pub write_concern: Option<Document>,
pub write_concern_document: Option<Document>,
pub read_concern: Option<Document>,
pub read_concern_document: Option<Document>,
pub is_acknowledged: Option<bool>,
}
fn write_concern_from_document(write_concern_doc: Document) -> Option<WriteConcern> {
let mut write_concern = WriteConcern::default();
for (key, value) in write_concern_doc {
match (&key[..], value) {
("w", Bson::I64(i)) => {
write_concern.w = Some(Acknowledgment::from(i as i32));
}
("w", Bson::String(s)) => {
write_concern.w = Some(Acknowledgment::from(s));
}
("journal", Bson::Boolean(b)) => {
write_concern.journal = Some(b);
}
("wtimeoutMS", Bson::I64(i)) if i > 0 => {
write_concern.w_timeout = Some(Duration::from_millis(i as u64));
}
("wtimeoutMS", Bson::I64(_)) => {
return None;
}
_ => {}
};
}
Some(write_concern)
}
fn normalize_write_concern_doc(write_concern_doc: Document) -> Document {
write_concern_doc
.into_iter()
.map(|(key, mut val)| {
if key == "w" {
if let Bson::I32(i) = val {
val = Bson::I64(i64::from(i));
}
}
(key, val)
})
.collect()
}
fn run_document_test(test_file: TestFile) {
for test_case in test_file.tests {
if let Some(specified_write_concern) = test_case.write_concern {
let wc = write_concern_from_document(specified_write_concern).map(|write_concern| {
write_concern.validate().map_err(Error::from).and_then(|_| {
let doc = bson::to_bson(&write_concern)?;
Ok(doc)
})
});
let actual_write_concern = match wc {
Some(Ok(Bson::Document(write_concern))) => {
assert!(test_case.valid, "{}", &test_case.description);
write_concern
}
Some(Ok(x)) => panic!("wat: {:?}", x),
Some(Err(_)) => {
assert!(!test_case.valid, "{}", &test_case.description);
continue;
}
None => {
continue;
}
};
if let Some(expected_write_concern) = test_case.write_concern_document {
assert_eq!(
normalize_write_concern_doc(actual_write_concern),
normalize_write_concern_doc(expected_write_concern),
"{}",
&test_case.description
);
}
}
}
}
#[test]
fn run() {
run_spec_test(&["read-write-concern", "document"], run_document_test);
}