library(stringr)
library(tableschema.r)
library(testthat)
library(future)
SCHEMA_MIN <- '{
"fields": [
{"name": "id"},
{"name": "height"}
]
}'
SCHEMA <- '{
"fields": [
{"name": "id", "type": "string", "constraints": {"required": true}},
{"name": "height", "type": "number"},
{"name": "age", "type": "integer"},
{"name": "name", "type": "string", "constraints": {"required": true}},
{"name": "occupation", "type": "string"}
]
}'
testthat::context("Schema")
test_that("have a correct number of fields", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
lng <- length(schema$fields)
expect_equal(5, lng)
})
#
test_that("have correct field names", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
lng <- length(schema$fieldNames)
expect_equal(schema$fieldNames, list('id', 'height', 'age', 'name', 'occupation'))
})
test_that("raise exception when invalid json passed as schema in strict mode", {
def <- Schema.load('bad descriptor', list(strict = TRUE))
expect_error(future::value(def))
})
test_that("raise exception when invalid format schema passed", {
def <- Schema.load('[]', list(strict = TRUE))
expect_error(future::value(def), ".*validation errors.*")
})
test_that("set default types if not provided", {
def <- Schema.load(SCHEMA_MIN)
schema <- future::value(def)
expect_equal(schema$fields[[1]]$type, 'string')
expect_equal(schema$fields[[2]]$type, 'string')
})
test_that("fields are not required by default", {
def <- Schema.load(SCHEMA_MIN)
schema <- future::value(def)
expect_equal(schema$fields[[1]]$required, FALSE)
expect_equal(schema$fields[[2]]$required, FALSE)
})
test_that("initial descriptor should not be mutated", {
descriptor <- '{"fields": [{ "name": "id" }]}'
def <- Schema.load(descriptor)
schema <- future::value(def)
expect_failure(expect_equivalent(schema$descriptor, descriptor))
})
test_that("should return null if field name does not exists", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
expect_equal(schema$getField('non-existent'), NULL)
})
test_that("should load local json file", {
descriptor <- readLines('inst/extdata/schema2.json')
def <- Schema.load(descriptor)
schema <- future::value(def)
expect_equivalent(schema$fieldNames, list('id', 'capital', 'url'))
})
test_that("convert row", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
row <- list('string', '10.0', '1', 'string', 'string')
castRow <- schema$castRow(row)
expect_equivalent(castRow, list('string', 10, 1, 'string', 'string'))
})
test_that("shouldn\'t convert row with less items than fields count", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
row <- list('string', '10.0', '1', 'string')
expect_error(
schema$castRow(row),
'.*fields dimension.*'
)
})
test_that("shouldn\'t convert row with too many items", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
row <- list('string', '10.0', '1', 'string', 'string', 'string')
expect_error(
schema$castRow(row),
'.*fields dimension.*'
)
})
test_that("shouldn\'t convert row with wrong type (fail fast)", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
row <- list('string', 'notdecimal', '10.6', 'string', 'string')
expect_error(
schema$castRow(items = row, failFast = TRUE),
'.*type.*'
)
})
test_that("shouldn\'t convert row with wrong type multiple errors", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
row <- list('string', 'notdecimal', '10.6', 'string', 'string')
expect_error(
schema$castRow(items = row),
'.*cast errors.*type.*'
)
})
test_that("should allow pattern format for date", {
descriptor <- '{"fields": [{"name": "year", "format": "%Y", "type": "date"}]}'
def <- Schema.load(descriptor)
schema <- future::value(def)
row <- list('2005')
castRow <- schema$castRow(row)
expect_identical(castRow[[1]], lubridate::make_date(2005,1,1))
})
test_that("should work in strict mode", {
descriptor <- '{"fields": [{"name": "name", "type": "string"}]}'
def <- Schema.load(descriptor, TRUE)
schema <- future::value(def)
expect_identical(schema$valid, TRUE)
expect_identical(schema$errors, list())
})
test_that("should work in non-strict mode", {
descriptor <- '{"fields": [{"name": "name", "type": "bad"}]}'
def <- Schema.load(descriptor)
schema <- future::value(def)
expect_identical(schema$valid, FALSE)
expect_equal(length(schema$errors), 1)
})
test_that("should infer itself from given rows", {
schema <- Schema$new()
rows <- list(
list('Alex', 21),
list('Joe', 38)
)
schema$infer(rows, list('name', 'age'))
expect_equal(schema$infer(rows, list('name', 'age')),
list(fields = list(list(name = "name",type = "string"), list(name = "age",type = "integer"))))
expect_identical(schema$valid, TRUE)
expect_equivalent(schema$fieldNames, list('name', 'age'))
expect_identical(schema$getField('name')$type, 'string')
expect_identical(schema$getField('age')$type, 'integer')
expect_identical(schema$getField('age')$name, 'age')
schema$removeField("name")
expect_null(schema$getField('name'))
})
test_that("should work with primary/foreign keys as arrays", {
descriptor <- '{
"fields": [{"name": "name"}],
"primaryKey": ["name"],
"foreignKeys": [{
"fields": ["parent_id"],
"reference": {"resource": "resource", "fields": ["id"]}
}]
}'
def <- Schema.load(descriptor)
schema <- future::value(def)
expect_equivalent(schema$primaryKey, list("name"))
expect_equivalent(schema$foreignKeys, list(list(fields = list("parent_id"), reference = list(resource = "resource", fields = list("id")))))
})
test_that("should work with primary/foreign keys as string", {
descriptor <- '{
"fields": [{"name": "name"}],
"primaryKey": "name",
"foreignKeys": [{
"fields": "parent_id",
"reference": {"resource": "resource", "fields": "id"}
}]
}'
def <- Schema.load(descriptor)
schema <- future::value(def)
expect_equivalent(schema$primaryKey, list("name"))
expect_equivalent(schema$foreignKeys, list(list(fields = list("parent_id"), reference = list(resource = "resource", fields = list("id")))))
})
testthat::context("Schema #save")
test_that("general", {
def <- Schema.load(SCHEMA)
schema <- future::value(def)
schema$save("inst/extdata")
expect_true(file.exists("inst/extdata/schema.json"))
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.