diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..53c0587 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,32 @@ +name: tests + +on: + push: + branches: [main, dev] + pull_request: + branches: [main, dev] + +permissions: + contents: read + +jobs: + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Parse environment.json and set Docker image + id: docker_image + run: | + IMAGE=$(jq -r '.base_image' .codeocean/environment.json) + IMAGE=${IMAGE//codeocean/nciccbr} + echo "image=$IMAGE" >> $GITHUB_OUTPUT + echo "Using Docker image: $IMAGE" + + - name: Run tests in Docker + run: | + docker run --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace \ + ${{ steps.docker_image.outputs.image }} \ + Rscript tests/testthat.R diff --git a/README.md b/README.md index 5f08688..efcd214 100644 --- a/README.md +++ b/README.md @@ -2,5 +2,7 @@ Code Ocean capsule: MOSuite - plot expression heatmap +[![tests](https://github.com/NIDAP-Community/MOSuite-plot-expr-heatmap/actions/workflows/tests.yml/badge.svg)](https://github.com/NIDAP-Community/MOSuite-plot-expr-heatmap/actions/workflows/tests.yml) + - [Code Ocean Capsule](https://poc-nci.codeocean.io/capsule/6385174/tree) | [Latest Release](https://poc-nci.codeocean.io/capsule/0936928/tree/latest) - [MOSuite R package docs](https://ccbr.github.io/MOSuite/) \ No newline at end of file diff --git a/tests/test-setup.R b/tests/test-setup.R new file mode 100644 index 0000000..32c6e1b --- /dev/null +++ b/tests/test-setup.R @@ -0,0 +1,28 @@ +testthat::test_that("basic test setup is valid", { + cwd <- getwd() + repo_root_script <- normalizePath(dirname(cwd)) + + fixture_file <- file.path( + repo_root_script, + "..", + "code", + "MOSuite", + "tests", + "testthat", + "data", + "moo.rds" + ) + + code_main <- file.path(repo_root_script, "..", "code", "main.R") + code_run <- file.path(repo_root_script, "..", "code", "run") + + testthat::expect_true(file.exists(fixture_file)) + testthat::expect_true(file.exists(code_main)) + testthat::expect_true(file.exists(code_run)) + + testthat::skip_if_not_installed("readr") + testthat::expect_no_error({ + moo <- readr::read_rds(fixture_file) + testthat::expect_gt(length(class(moo)), 0) + }) +}) diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..f86f3ba --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,2 @@ +library(testthat) +test_dir(here::here('tests/testthat/')) diff --git a/tests/testthat/helper-cli.R b/tests/testthat/helper-cli.R new file mode 100644 index 0000000..658b2b5 --- /dev/null +++ b/tests/testthat/helper-cli.R @@ -0,0 +1,75 @@ +setup_cli_workspace <- function(prefix = "mosuite_plot_expr_heatmap_test_") { + workspace <- tempfile(prefix) + dir.create(workspace) + + code_dir <- file.path(workspace, "code") + data_dir <- file.path(workspace, "data") + results_dir <- file.path(workspace, "results") + dir.create(code_dir, recursive = TRUE) + dir.create(data_dir, recursive = TRUE) + dir.create(file.path(results_dir, "figures"), recursive = TRUE) + dir.create(file.path(results_dir, "moo"), recursive = TRUE) + + repo_root <- normalizePath( + file.path(testthat::test_path(), "..", ".."), + mustWork = TRUE + ) + + test_data_file <- file.path( + repo_root, + "code", + "MOSuite", + "tests", + "testthat", + "data", + "moo.rds" + ) + + expect_true( + file.exists(test_data_file), + info = paste("Test data file should exist at", test_data_file) + ) + file.copy(test_data_file, file.path(data_dir, "moo.rds"), overwrite = TRUE) + + file.copy( + file.path(repo_root, "code", "main.R"), + file.path(code_dir, "main.R"), + overwrite = TRUE + ) + + # Keep main.R behavior the same while pointing to this checkout's MOSuite package. + main_copy <- file.path(code_dir, "main.R") + main_lines <- readLines(main_copy) + main_lines <- gsub( + 'devtools::load_all("/code/MOSuite")', + sprintf( + 'devtools::load_all("%s")', + file.path(repo_root, "code", "MOSuite") + ), + main_lines, + fixed = TRUE + ) + writeLines(main_lines, main_copy) + + list( + workspace = workspace, + code_dir = code_dir, + results_dir = results_dir, + repo_root = repo_root + ) +} + +expect_plot_created <- function(results_dir) { + plot_path <- file.path(results_dir, "figures", "heatmap", "expr_heatmap.png") + expect_true(file.exists(plot_path), info = "Heatmap plot should be created") + expect_true( + file.info(plot_path)$size > 0, + info = "Heatmap plot should be non-empty" + ) +} + +common_cli_args <- c( + "--count_type=clean", + "--display_gene_names=FALSE", + "--display_sample_names=TRUE" +) diff --git a/tests/testthat/test-main.R b/tests/testthat/test-main.R new file mode 100644 index 0000000..5b25f8d --- /dev/null +++ b/tests/testthat/test-main.R @@ -0,0 +1,33 @@ +test_that("main.R CLI creates expression heatmap plot", { + setup <- setup_cli_workspace("mosuite_plot_expr_heatmap_test_") + on.exit(unlink(setup$workspace, recursive = TRUE), add = TRUE) + + old_wd <- getwd() + setwd(setup$code_dir) + on.exit(setwd(old_wd), add = TRUE) + + exit_code <- system2("Rscript", args = c("main.R", common_cli_args)) + expect_equal(exit_code, 0, info = "main.R should execute without error") + + expect_plot_created(setup$results_dir) +}) + +test_that("run wrapper executes and creates expression heatmap plot", { + setup <- setup_cli_workspace("mosuite_plot_expr_heatmap_run_test_") + on.exit(unlink(setup$workspace, recursive = TRUE), add = TRUE) + + file.copy( + file.path(setup$repo_root, "code", "run"), + file.path(setup$code_dir, "run"), + overwrite = TRUE + ) + + old_wd <- getwd() + setwd(setup$code_dir) + on.exit(setwd(old_wd), add = TRUE) + + exit_code <- system2("bash", args = c("run", common_cli_args)) + expect_equal(exit_code, 0, info = "run script should execute without error") + + expect_plot_created(setup$results_dir) +})