tests/testthat/test-schema.R

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"))
})
frictionlessdata/tableschema-r documentation built on Oct. 1, 2022, 11:44 a.m.