Skip to content

Commit

Permalink
BSON roundtripping tweaks and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jeroen committed Dec 21, 2016
1 parent c591844 commit 19bafb7
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "tests/testthat/specifications"]
path = tests/testthat/specifications
url = https://github.com/mongodb/specifications
23 changes: 21 additions & 2 deletions src/bson.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ SEXP ConvertValue(bson_iter_t* iter);
SEXP ConvertBinary(bson_iter_t* iter);
SEXP ConvertDate(bson_iter_t* iter);
SEXP ConvertDec128(bson_iter_t* iter);
SEXP ConvertTimestamp(bson_iter_t* iter);

SEXP R_json_to_bson(SEXP json){
bson_t *b;
Expand Down Expand Up @@ -43,7 +44,8 @@ SEXP R_bson_to_list(SEXP ptr) {

SEXP ConvertValue(bson_iter_t* iter){
if(BSON_ITER_HOLDS_INT32(iter)){
return ScalarInteger(bson_iter_int32(iter));
int res = bson_iter_int32(iter);
return res == NA_INTEGER ? ScalarReal(res) : ScalarInteger(res);
} else if(BSON_ITER_HOLDS_NULL(iter)){
return R_NilValue;
} else if(BSON_ITER_HOLDS_BOOL(iter)){
Expand All @@ -62,6 +64,8 @@ SEXP ConvertValue(bson_iter_t* iter){
return ConvertDate(iter);
} else if(BSON_ITER_HOLDS_DECIMAL128(iter)){
return ConvertDec128(iter);
} else if(BSON_ITER_HOLDS_TIMESTAMP(iter)){
return ConvertTimestamp(iter);
} else if(BSON_ITER_HOLDS_OID(iter)){
const bson_oid_t *val = bson_iter_oid(iter);
char str[25];
Expand All @@ -84,6 +88,21 @@ SEXP ConvertValue(bson_iter_t* iter){
}
}

SEXP ConvertTimestamp(bson_iter_t* iter){
uint32_t timestamp;
uint32_t increment;
bson_iter_timestamp(iter, &timestamp, &increment);
SEXP res = PROTECT(allocVector(VECSXP, 2));
SET_VECTOR_ELT(res, 0, ScalarInteger(timestamp));
SET_VECTOR_ELT(res, 1, ScalarInteger(increment));
SEXP names = PROTECT(allocVector(STRSXP, 2));
SET_STRING_ELT(names, 0, Rf_mkChar("t"));
SET_STRING_ELT(names, 1, Rf_mkChar("i"));
setAttrib(res, R_NamesSymbol, names);
UNPROTECT(2);
return res;
}

SEXP ConvertDate(bson_iter_t* iter){
SEXP list = PROTECT(allocVector(VECSXP, 1));
SET_VECTOR_ELT(list, 0, ScalarReal((double) bson_iter_date_time(iter)));
Expand Down Expand Up @@ -111,7 +130,7 @@ SEXP ConvertBinary(bson_iter_t* iter){
for (int i = 0; i < binary_len; i++) {
RAW(out)[i] = binary[i];
}
setAttrib(out, install("subtype"), ScalarInteger(subtype));
setAttrib(out, install("type"), ScalarRaw(subtype));
UNPROTECT(1);
return out;

Expand Down
1 change: 1 addition & 0 deletions tests/testthat/specifications
Submodule specifications added at 1b4159
68 changes: 68 additions & 0 deletions tests/testthat/test-bson.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
context("specifications")

roundtrip_json <- function(testdata){
extjson <- na.omit(testdata$valid$extjson)
m <- mongo(verbose = FALSE)
on.exit(try(m$drop(), silent = TRUE))
m$insert(extjson)
out <- m$find()
jsonlite::toJSON(out, raw = "mongo", collapse = FALSE, always_decimal = TRUE, digits = NA)
}

roundtrip_test <- function(testdata){
json <- roundtrip_json(testdata)
for(i in seq_along(json)){
x <- jsonlite::fromJSON(testdata$valid$extjson[i], simplifyVector = FALSE)
y <- jsonlite::fromJSON(json[i], simplifyVector = FALSE)
expect_equal(x, y)
}
}

test_that("roundtrip array", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/array.json")
roundtrip_test(testdata)
})

test_that("roundtrip binary", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/binary.json")
roundtrip_test(testdata)
})

test_that("roundtrip boolean", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/boolean.json")
roundtrip_test(testdata)
})

test_that("roundtrip datetime", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/datetime.json")
roundtrip_test(testdata)
})

test_that("roundtrip document", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/document.json")
# Remove test with empty column name.
testdata$valid = testdata$valid[-2,]
roundtrip_test(testdata)
})

test_that("roundtrip double", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/double.json")
roundtrip_test(testdata)
})

test_that("roundtrip int32", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/int32.json")
roundtrip_test(testdata)
})

test_that("roundtrip string", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/string.json")
roundtrip_test(testdata)
})

test_that("roundtrip timestamp", {
testdata <- jsonlite::fromJSON("specifications/source/bson-corpus/tests/timestamp.json")
a <- jsonlite::fromJSON(testdata$valid$extjson)$a[["$timestamp"]]
b <- jsonlite::fromJSON(roundtrip_json(testdata))$a
expect_equal(a, b)
})

0 comments on commit 19bafb7

Please sign in to comment.