tests/testthat/test_NIflow.R

context("NIflow")

expect_works <- function(object) testthat::expect_error(object, NA)


test_that("NIflow initializes as expected", {

  # Create flow
  flow <- NIflow$new(name = "foo", inputs = c("A", "B"))

  # Expectations
  # Class
  expect_is(flow, "NIflow")

  # Correct name
  expect_true(flow$name() == "foo")

  # Retrieving inputs
  expect_identical(sort(flow$get_inputs()), c("A", "B"))

  # No outputs at the beginning
  expect_identical(setdiff(flow$get_outputs(), flow$get_inputs()), character(0))

  # Get tempdir and clean it
  expect_works(flow$get_workdir())
  expect_works(flow$clean_workdir())

})

test_that("NIflow adds inputs", {

  # Create flow
  flow <- NIflow$new(name = "foo", inputs = c("A", "B"))
  original_inputs <- flow$get_inputs()

  # Add a new input
  flow$add(inputs = "C")

  # Expect we have the new input added
  expect_identical(setdiff(flow$get_inputs(), original_inputs), "C")

})

test_that("A NIflow can do basic operations (plot and subset)", {

  f <- function(...) {

    L <- list(...);

    unlist(L)

  }

  flow <- NIflow$new(name = "test", inputs = c(A, B))

  flow$add(what = f, inputs = c(A, B), output = suma)
  flow$add(inputs = C)
  flow$add(what = f, inputs = c(B, C), output = suma2)
  flow$add(what = f, inputs = c(suma, C), output = suma3)
  flow$add(what = f, inputs = c(suma3, C), output = suma4)

  # Plot
  expect_works(flow$plot())

  expect_works(flow %>% plot(to_file = tempfile(fileext = ".png")))

  # Subset
  expect_works(new_flow <- flow$subset(outputs = "suma3"))
  expect_works(new_flow$plot())

  # Memory used
  expect_works(flow$memory_used())

  # Deep Clone
  # expect_works(new_flow <- flow$deep_clone())

})


test_that(desc = "A NIflow can be executed", code = {

  f <- function(...) {

    L <- list(...);

    unlist(L)

  }

  flow <- NIflow$new(name = "test", inputs = c(A, B))

  flow$add(what = f, inputs = c(A, B), output = suma)
  flow$add(inputs = C)

  flow %>%
    add(what = f, inputs = c("B", "C"), output = suma2) %>%
    add(what = f, inputs = c(suma, C), output = "suma3") %>%
    add(what = f, inputs = c(suma3, C), output = suma4)

  # Execute the flow
  expect_works(res <- flow$execute(inputs = list(A = 1, B = 2, C = 3),
                                   desired_outputs = c(suma, suma2, suma3)))

  expect_works(res <- flow$compute(from = list(A = 1, B = 2, C = 3),
                                   what = c(suma, suma2, suma3),
                                   verbose = FALSE))


  # Should return a list with named components
  expect_is(res, "list")
  expect_named(res, expected = c("suma", "suma2", "suma3"))

  # The same for function "run" instead of "execute"
  expect_works(res <- flow$run(inputs = list(A = 1, B = 2, C = 3),
                               desired_outputs = c(suma, suma2, suma3)))

  expect_is(res, "list")
  expect_named(res, expected = c("suma", "suma2", "suma3"))

  # Unavailable outputs should warn the user
  expect_warning(flow$execute(inputs = list(A = 1, B = 2, c = 3),
                              desired_outputs = suma6))

})


test_that(desc = "A NIflow can be exported and imported", code = {

  f <- function(...) {

    L <- list(...);

    unlist(L)

  }

  flow <- NIflow$new(name = "test", inputs = c(A, B))

  flow$add(what = f, inputs = c(A, B), output = suma)
  flow$add(inputs = C)
  flow$add(what = f, inputs = c(B, C), output = suma2)
  flow$add(what = f, inputs = c(suma, C), output = suma3)
  flow$add(what = f, inputs = c(suma3, C), output = suma4)

  # Save and load
  path <- tempdir()
  file_prefix <- basename(tempfile())
  expect_works(flow$save(path = path, file_prefix = file_prefix))

  expect_works(flow$load(filename = file.path(path, paste0(file_prefix, ".zip"))))

})

test_that(desc = "NIflow get/sets", code = {

  f <- function(...) {

    L <- list(...);

    unlist(L)

  }

  flow <- NIflow$new(name = "test", inputs = c(A, B))

  flow$add(what = f, inputs = c(A, B), output = suma)
  flow$add(inputs = C)
  flow$add(what = f, inputs = c(B, C), output = suma2)
  flow$add(what = f, inputs = c(suma, C), output = suma3)
  flow$add(what = f, inputs = c(suma3, C), output = suma4)

  # Change name
  expect_works(flow$set_name("test2"))
  expect_equivalent(flow$name(), expected = "test2")

  # Get process by id
  expect_works(f2 <- flow$get_process(suma))
  expect_identical(object = f2, expected = f)

  # Get list of required inputs for given outputs
  expect_works(res <- flow$get_required_inputs(c(suma, suma3, suma2)))
  expect_is(res, "list")
  expect_named(res, expected = c("suma", "suma3", "suma2"))
  expect_equivalent(res, list(suma = c("A", "B"), suma3 = c("A", "B", "C"), suma2 = c("B", "C")))

  # Get and check dependencies
  expect_works(flow$get_dependencies())
  expect_works(flow$check_dependencies())

  # Replace function
  f3 <- function(...) {L <- list(...); unlist(rev(L))}

  expect_works(flow$replace(output = suma, with = f3))
  expect_works(f2 <- flow$get_process(suma))
  expect_identical(object = f2, expected = f2)

})

test_that(desc = "A Niflow logs things", code = {

  f <- function(...) {

    L <- list(...);

    unlist(L)

  }

  flow <- NIflow$new(name = "test", inputs = c(A, B))

  flow$add(what = f, inputs = c(A, B), output = suma)
  flow$add(inputs = C)
  flow$add(what = f, inputs = c(B, C), output = suma2)
  flow$add(what = f, inputs = c(suma, C), output = suma3)
  flow$add(what = f, inputs = c(suma3, C), output = suma4)

  res <- flow$execute(inputs = list(A = 1, B = 2, C = 3),
                      desired_outputs = c(suma, suma2, suma3))

  # Printing log
  expect_works(capture.output(flow$print_log()))
  expect_works(capture.output(flow$errors()))
  expect_works(capture.output(flow$warnings()))

  # Adding to log
  flow$log(level = "DEBUG", message = "TEST")

  # Saving log
  path <- tempfile()
  expect_works(flow$save_log(filename = path))
  expect_true(file.exists(path))

})

test_that(desc = "A NIflow has a graph representation", code = {

  f <- function(...) {

    L <- list(...);

    unlist(L)

  }

  flow <- NIflow$new(name = "test", inputs = c(A, B))

  flow$add(what = f, inputs = c(A, B), output = suma)
  flow$add(inputs = C)
  flow$add(what = f, inputs = c(B, C), output = suma2)
  flow$add(what = f, inputs = c(suma, C), output = suma3)
  flow$add(what = f, inputs = c(suma3, C), output = suma4)

  # Obtain the graph
  expect_works(g <- flow$graph())

  # Is it actually a graph?
  expect_is(g, "igraph")

})

test_that(desc = "A NIflow accepts parameterizable functions", code = {

  # Parameter b in f1 can be adjusted
  f1 <- function(v, b = 2) {v + b}
  f2 <- function(v) {2 * v}

  flow <- NIflow$new(name = "test", inputs = c(A, B))

  # It is b = 0
  flow$add(what = f1, inputs = A, output = F1, b = 0)
  flow$add(what = f2, inputs = A, output = F2)
  flow$add(what = f1, inputs = A, output = F15, b = 5) # b = 5 in this case

  expect_works(res <- flow$execute(inputs = list(A = 1), desired_outputs = c(F1, F2, F15)))

  # Expected results
  expect_is(res, "list")
  expect_named(res, expected = c("F1", "F2", "F15"))
  expect_equivalent(res, expected =  list(F1 = 1, F2 = 2, F15 = 6))

})

test_that(desc = "A NIflow accepts strings as input names", code = {

  # Use of programatically defined variable names
  a <- "A1"
  b <- "B1"
  expect_works(flow <- NIflow$new(name = "test", inputs = c(a, b)))

  expect_equivalent(flow$get_inputs(), expected = c("A1", "B1"))

  # Use of mixed variable names
  expect_works(flow <- NIflow$new(name = "test", inputs = c(a, r)))

  expect_equivalent(flow$get_inputs(), expected = c("A1", "r"))

})

test_that(desc = "A NIflow can be exported to an R package", code = {

  # Auxiliary functions
  f <- function(...) {

    L <- list(...);

    unlist(L)

  }

  # Test flow
  flow <- NIflow$new(name = "test", inputs = c(A, B))

  flow$add(what = f, inputs = c(A, B), output = suma)
  flow$add(inputs = C)
  flow$add(what = f, inputs = c(B, C), output = suma2)
  flow$add(what = f, inputs = c(suma, C), output = suma3)
  flow$add(what = f, inputs = c(suma3, C), output = suma4)

  # Exporting to a package
  path <- tempdir()
  expect_works(flow$to_package(path = path))

  # Was the export successful?
  expect_true(file.exists(file.path(path, flow$name())))
  expect_works(res <- devtools::as.package(x = file.path(path, flow$name())))
  expect_is(res, "package")

})

test_that(desc = "NIflow can read NIFTI(gz) files as input", code = {

  # Create temporal nifti file
  A <- array(0, dim = c(10, 10, 10))
  t1_file <- neurobase::checkimg(A, allow_array = TRUE)

  # Sample flow
  flow <- NIflow$new(name = "test", inputs = T1)
  flow$add(what = function(I) {-I}, inputs = T1, output = negT1)

  # Input is a filename (.nii.gz)
  expect_works(res <- flow$execute(inputs = list(T1 = t1_file),
                                   desired_outputs = negT1))

  # Is the result as expected?
  expect_is(res, "list")
  expect_named(res, expected = c("negT1"))
  expect_is(res$negT1, "array")

  unlink(t1_file)

})

test_that(desc = "NIflow can read RDS files as input", code = {

  # Create temporal nifti file
  A <- array(0, dim = c(10, 10, 10))
  t1_file <- tempfile(fileext = ".rds")
  saveRDS(object = A, file = t1_file)

  # Sample flow
  flow <- NIflow$new(name = "test", inputs = T1)
  flow$add(what = function(I) {-I}, inputs = T1, output = negT1)

  # Input is a filename (.rds)
  expect_works(res <- flow$execute(inputs = list(T1 = t1_file),
                                   desired_outputs = negT1))

  # Is the result as expected?
  expect_is(res, "list")
  expect_named(res, expected = c("negT1"))
  expect_is(res$negT1, "array")

  unlink(t1_file)

})

test_that(desc = "NIflow can read uncompressed NIFTI files as input", code = {

  # Create temporal nifti file
  A <- array(0, dim = c(10, 10, 10))
  t1_file <- neurobase::checkimg(A, allow_array = TRUE, gzipped = FALSE)

  # Sample flow
  flow <- NIflow$new(name = "test", inputs = T1)
  flow$add(what = function(I) {-I}, inputs = T1, output = negT1)

  # Input is a filename (.nii)
  expect_works(res <- flow$execute(inputs = list(T1 = t1_file),
                                   desired_outputs = negT1))

  # Is the result as expected?
  expect_is(res, "list")
  expect_named(res, expected = c("negT1"))
  expect_is(res$negT1, "array")

  unlink(t1_file)

})
neuroimaginador/wf4ni documentation built on Oct. 15, 2019, 9:26 a.m.