diff --git a/DESCRIPTION b/DESCRIPTION index 7a2a9477..2b048886 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: mrgsolve Title: Simulate from ODE-Based Models -Version: 1.0.6 +Version: 1.0.7 Authors@R: c(person(given = "Kyle T", family = "Baron", role = c("aut", "cre"), @@ -65,7 +65,7 @@ Encoding: UTF-8 Language: en-US LazyLoad: yes NeedsCompilation: yes -RoxygenNote: 7.2.0 +RoxygenNote: 7.2.3 SystemRequirements: C++11 Collate: 'RcppExports.R' diff --git a/NAMESPACE b/NAMESPACE index 344f8ebc..6569a47e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -269,6 +269,8 @@ importFrom(tibble,as_tibble) importFrom(tibble,tibble) importFrom(tidyselect,everything) importFrom(tidyselect,vars_select) +importFrom(tools,file_path_sans_ext) +importFrom(tools,md5sum) importFrom(utils,.DollarNames) importFrom(utils,assignInMyNamespace) importFrom(utils,capture.output) diff --git a/NEWS.md b/NEWS.md index c4b0110d..acdb17f4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,22 @@ +# mrgsolve 1.0.7 + +- `$NMXML` and `$NMEXT` now accept the `run` argument set to `"@cppstem"` (i.e + `run = "@cppstem"`); in this case, the stem of the NONMEM run will be assumed + to be the same as the stem of the mrgsolve model file (#1025). + +- Missing values (`NA`) in input data sets will be replaced with 0 for the + following columns: `AMT`, `CMT`, `EVID`, `II`, `ADDL`, `RATE`, `SS` as well as + their lower case counterparts (#1030). + +- Refactored include order when building a model; this is an internal update and + not expected to be visible to the user (#1038). + +## Bugs Fixed + +- Fix bug in generating certain model definitions when using the `nm-vars` + plugin; the bug would have resulted in a warning from the pre-processor and + did not affect function of the model (#1039). + # mrgsolve 1.0.6 ## Bugs Fixed diff --git a/R/Aaaa.R b/R/Aaaa.R index e8b017a6..a9a354c3 100644 --- a/R/Aaaa.R +++ b/R/Aaaa.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2020 Metrum Research Group +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # @@ -33,6 +33,7 @@ #' @importFrom lifecycle deprecate_soft deprecate_warn #' @importFrom glue glue #' @importFrom Rcpp evalCpp +#' @importFrom tools md5sum file_path_sans_ext # @importFrom RcppArmadillo armadillo_version #' @include Aaaa.R @@ -65,8 +66,12 @@ GLOBALS$CARRY_TRAN_UC <- c("AMT", "CMT", "EVID", "II", "ADDL", "RATE", "SS") GLOBALS$CARRY_TRAN_LC <- tolower(GLOBALS[["CARRY_TRAN_UC"]]) GLOBALS$CARRY_TRAN <- c("a.u.g", GLOBALS[["CARRY_TRAN_UC"]], GLOBALS[["CARRY_TRAN_LC"]]) GLOBALS$PKMODEL_NOT_FOUND <- "Required PK parameters not found: " -GLOBALS$TRAN_UPPER <- c("AMT", "II", "SS", "CMT", "ADDL", "RATE", "EVID","TIME") +GLOBALS$TRAN_UPPER <- c("AMT", "II", "SS", "CMT", "ADDL", "RATE", "EVID", "TIME") GLOBALS$TRAN_LOWER <- tolower(GLOBALS$TRAN_UPPER) +GLOBALS$TRAN_FILL_NA <- c( + "AMT", "CMT", "EVID", "II", "ADDL", "RATE", "SS", + "amt", "cmt", "evid", "ii", "addl", "rate", "ss" +) GLOBALS[["version"]] <- utils::packageVersion("mrgsolve") block_list <- c("ENV", "PROB", "PARAM", "INIT", diff --git a/R/class_build.R b/R/class_build.R index a7c40b64..8698bcc5 100644 --- a/R/class_build.R +++ b/R/class_build.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2022 Metrum Research Group +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # @@ -50,6 +50,7 @@ new_build <- function(file=NULL, model, project, soloc=getwd(), code = NULL, env$win <- .Platform$OS.type=="windows" + ## Both project and soloc get normalized if(!file_writeable(soloc)) { if(file_writeable(dirname(soloc))) { @@ -93,8 +94,10 @@ new_build <- function(file=NULL, model, project, soloc=getwd(), code = NULL, } } - env$md5 <- tools::md5sum(env$modfile) + env$md5 <- md5sum(env$modfile) + env$root <- file_path_sans_ext(basename(env$modfile)) + env$package <- ifelse(udll, rfile(model), new_model) env$compfile <- compfile(new_model) diff --git a/R/modspec.R b/R/modspec.R index 4bde3205..9bc20c33 100644 --- a/R/modspec.R +++ b/R/modspec.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2021 Metrum Research Group +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # @@ -630,10 +630,9 @@ scrape_and_call <- function(x,env,pass,...) { do.call(pass,o) } -dump_opts <- function(x,env,block,...) { - hasopt <- unique(c(grep(">>", x, fixed=TRUE),grep("@", x, fixed=TRUE))) +dump_opts <- function(x, env, block, ...) { + hasopt <- grep("^\\s*(>>|@)", x, perl = TRUE) if(length(hasopt)==0) return(x) - hasopt <- grep("^\\s*(>>|@)", x[hasopt], perl=TRUE) x[-hasopt] } @@ -650,10 +649,12 @@ eval_ENV_block <- function(x,where,envir=new.env(),...) { return(envir) } -parse_env <- function(spec, incoming_names = names(spec),project,ENV=new.env()) { +parse_env <- function(spec, incoming_names = names(spec),build,ENV=new.env()) { n <- length(spec) mread.env <- new.env() - mread.env$project <- project + mread.env$project <- build[["project"]] + mread.env$root <- build[["root"]] + mread.env$ext <- build[["ext"]] mread.env$param <- vector("list", n) mread.env$fixed <- vector("list", n) mread.env$init <- vector("list", n) diff --git a/R/mread.R b/R/mread.R index a6531f10..2a1e374a 100644 --- a/R/mread.R +++ b/R/mread.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2021 Metrum Research Group +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # @@ -214,7 +214,7 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), mread.env <- parse_env( spec, incoming_block_names, - project = build[["project"]], + build, ENV ) @@ -476,7 +476,8 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), } cat( - paste0("// Source MD5: ", build[["md5"]], "\n"), + paste0("// Source MD5: ", build[["md5"]]), + "\n// PLUGINS:", plugin_code(plugin), ## This should get moved to rd "\n// FIXED:", @@ -488,9 +489,9 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), "\n// MODEL HEADER FILES:", incl("mrgsolv.h"), incl("modelheader.h"), - "\n//INCLUDE databox functions:", + "\n// INCLUDE databox functions:", incl("databox_cpp.h"), - "\n//USING plugins", + "\n// USING plugins:", plugin_using(plugin), "\n// GLOBAL CODE BLOCK:", "// GLOBAL VARS FROM BLOCKS & TYPEDEFS:", diff --git a/R/mrgindata.R b/R/mrgindata.R index 37eee2a5..f7762d37 100644 --- a/R/mrgindata.R +++ b/R/mrgindata.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2021 Metrum Research Group +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # @@ -180,7 +180,11 @@ valid_data_set <- function(x, m = NULL, verbose = FALSE, quiet = FALSE) { signal_drop(dm, x, to_signal, context = "[data-set]") } - check_data_set_na(dm,m) + has_na <- check_data_set_na(dm,m) + + if(has_na) { + dm <- fill_tran_na(dm) + } dm <- cbind(dm, matrix(0, ncol=1, @@ -224,7 +228,7 @@ valid_idata_set <- function(x, m, verbose = FALSE, quiet = FALSE) { stop("ID is a required column for idata_set.",call.=FALSE) } - if(any(duplicated(x[["ID"]]))) { + if(anyDuplicated(x[["ID"]])) { stop("Duplicate IDs not allowed in idata_set.",call.=FALSE) } @@ -241,8 +245,8 @@ valid_idata_set <- function(x, m, verbose = FALSE, quiet = FALSE) { dm } -##' @rdname valid_data_set -##' @export +#' @rdname valid_data_set +#' @export valid_data_set.matrix <- function(x,verbose=FALSE) { if(is.valid_data_set(x)) return(x) if(is.numeric(x)) { @@ -252,44 +256,46 @@ valid_data_set.matrix <- function(x,verbose=FALSE) { } check_data_set_na <- function(data,m) { - if(!anyNA(data)) return(invisible(NULL)) + if(!anyNA(data)) return(invisible(FALSE)) err <- FALSE - flagged <- check_column_na( - data, - Pars(m) - ) + flagged <- check_column_na(data, Pars(m)) for(col in flagged) { warning( "Parameter column ", col, " must not contain missing values.", call.=FALSE, immediate.=TRUE ) } - flagged <- check_column_na( - data, - c("ID","TIME", "time", "RATE", "rate") - ) + flagged <- check_column_na(data, c("ID", "TIME", "time")) for(col in flagged) { message( col, " column must not contain missing values.", - call.=FALSE,immediate.=TRUE + call.=FALSE, immediate.=TRUE ) err <- TRUE } if(err) stop("Found missing values in input data.", call.=FALSE) - return(invisible(NULL)) + return(invisible(TRUE)) +} + +#' Look for TRAN columns replace NA with 0 +#' Columns to scan are found in `GLOBALS$TRAN_FILL_NA` +#' @noRd +fill_tran_na <- function(data) { + cols_to_zero <- check_column_na(data, GLOBALS[["TRAN_FILL_NA"]]) + data[, cols_to_zero][is.na(data[, cols_to_zero])] <- 0 + data } check_column_na <- function(data, cols) { - check <- unique(cols[cols %in% dimnames(data)[[2]]]) - if(length(check)==0) return(character(0)) - if(!anyNA(data[,check])) return(character(0)) + to_check <- unique(cols[cols %in% dimnames(data)[[2L]]]) + if(length(to_check)==0L) return(character(0)) + if(!anyNA(data[,to_check])) return(character(0)) flagged <- character(0) - for(col in check) { + for(col in to_check) { if(anyNA(data[,col])) { - flagged <- c(flagged,col) + flagged <- c(flagged, col) } } - return(flagged) + flagged } - diff --git a/R/nm-mode.R b/R/nm-mode.R index acb9d937..82884a19 100644 --- a/R/nm-mode.R +++ b/R/nm-mode.R @@ -35,6 +35,7 @@ find_nm_vars <- function(spec) { is_frda <- as.integer(m[["prefix"]] %in% FRDA) m <- m[order(is_frda, m[["prefix"]], m[["cmt"]]),, drop = FALSE] ans[["frda"]] <- m[m[["prefix"]] %in% FRDA,,drop=FALSE] + ans[["found_frda"]] <- nrow(ans[["frda"]]) > 0 rownames(m) <- NULL ans[["match"]] <- m ans[["cmtn"]] <- sort(unique(m[["cmt"]])) @@ -64,7 +65,7 @@ find_nm_vars_impl <- function(code) { } generate_nmdefs <- function(x) { - if(isFALSE(x[["found_any"]])) return(NULL) + if(isFALSE(x[["found_frda"]])) return(NULL) ans <- paste0( "#define ", x[["frda"]][["match"]], diff --git a/R/nmxml.R b/R/nmxml.R index 4d733afa..3fdeb8e1 100644 --- a/R/nmxml.R +++ b/R/nmxml.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2020 Metrum Research Group +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # @@ -95,13 +95,16 @@ nmxml <- function(run = numeric(0), project = character(0), on.exit(setwd(cwd)) setwd(env[["project"]]) } - + if(!missing(path)) { target <- path } else { if(missing(run) | missing(project)) { wstop("both file and run or project are missing") } + if(run=="@cppstem") { + run <- env$root + } target <- file.path(project, run, paste0(run, ".xml")) } @@ -243,6 +246,10 @@ nmext <- function(run = NA_real_, project = getwd(), setwd(env[["project"]]) } + if(run=="@cppstem") { + run <- env$root + } + ans <- read_nmext( run = run, project = project, diff --git a/R/utils.R b/R/utils.R index 77b0ce19..3149ccae 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2022 Metrum Research Group +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # diff --git a/inst/WORDLIST b/inst/WORDLIST index 621479b1..fc73b270 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -146,3 +146,4 @@ KA pkgdown Rcpp df +MPN diff --git a/inst/base/databox_cpp.h b/inst/base/databox_cpp.h index f82935ca..2a8ccd3c 100644 --- a/inst/base/databox_cpp.h +++ b/inst/base/databox_cpp.h @@ -1,4 +1,4 @@ -// Copyright (C) 2013 - 2020 Metrum Research Group +// Copyright (C) 2013 - 2023 Metrum Research Group // // This file is part of mrgsolve. // @@ -15,6 +15,10 @@ // You should have received a copy of the GNU General Public License // along with mrgsolve. If not, see . + +#ifndef DATABOX_CPP_H +#define DATABOX_CPP_H + void databox::mevent(double time, int evid) { mrgsolve::evdata ev(time,evid); mevector.push_back(ev); @@ -39,3 +43,5 @@ double databox::tad() { if((evid == 1) || (evid == 4)) told = time; return told < 0 ? -1.0 : time - told; } + +#endif diff --git a/inst/base/mrgsolv.h b/inst/base/mrgsolv.h index d44d99ce..53d222c2 100644 --- a/inst/base/mrgsolv.h +++ b/inst/base/mrgsolv.h @@ -1,4 +1,4 @@ -// Copyright (C) 2013 - 2019 Metrum Research Group, LLC +// Copyright (C) 2013 - 2023 Metrum Research Group // // This file is part of mrgsolve. // @@ -77,6 +77,7 @@ namespace mrg = mrgsolve; //! member functions mevent and tad come in via housemodel; see inst/base/databox.cpp + /** * Model data passed to the model. * diff --git a/inst/maintenance/build_housemodel.R b/inst/maintenance/build_housemodel.R index cfabeca5..2255bc95 100644 --- a/inst/maintenance/build_housemodel.R +++ b/inst/maintenance/build_housemodel.R @@ -2,6 +2,7 @@ suppressPackageStartupMessages(library(dplyr)) suppressPackageStartupMessages(library(methods)) suppressPackageStartupMessages(library(glue)) +suppressPackageStartupMessages(library(tools)) fun <- function() { setClass("mrgsims") source("R/utils.R") diff --git a/inst/maintenance/tests.R b/inst/maintenance/tests.R index cd296b9c..bf4d8f8a 100644 --- a/inst/maintenance/tests.R +++ b/inst/maintenance/tests.R @@ -9,10 +9,7 @@ a$result <- NULL message("\ninst/maintenance/unit") b <- test_dir("inst/maintenance/unit/") b$result <- NULL -message("\ninst/validation") -c <- test_dir("inst/validation/") -c$result <- NULL -results <- dplyr::bind_rows(as_tibble(a),as_tibble(b),as_tibble(c)) +results <- dplyr::bind_rows(as_tibble(a),as_tibble(b)) results$user <- NULL results$system <- NULL results$real <- NULL diff --git a/inst/maintenance/unit/test-nm-vars.R b/inst/maintenance/unit/test-nm-vars.R index 7d2cb463..35cfdaac 100644 --- a/inst/maintenance/unit/test-nm-vars.R +++ b/inst/maintenance/unit/test-nm-vars.R @@ -219,3 +219,14 @@ test_that("nm-vars functional test", { expect_equal(out2$b[1], log(mod2$VC), tolerance = 1e-3) expect_equal(out2$c[1], sqrt(mod2$KA), tolerance = 1e-3) }) + +test_that("nm-vars no frda items", { + code <- ' + $plugin nm-vars + $cmt A1 + $main A_0(1) = 1; +' + mod <- mcode("u229", code, compile = FALSE) + a <- readLines(file.path(soloc(mod), "u229-mread-header.h")) + expect_false(any(grepl("#define __[]", a, fixed = TRUE))) +}) diff --git a/inst/models/1005.cpp b/inst/models/1005.cpp index 2bdc5f18..a83105b1 100644 --- a/inst/models/1005.cpp +++ b/inst/models/1005.cpp @@ -17,7 +17,7 @@ Updated 10 Jan 2022 to use autodec and nm-vars plugins. [ NMXML ] project = system.file("nonmem", package = "mrgsolve") -run = 1005 +run = "@cppstem" [ PK ] CL = THETA(1)*exp(ETA(1)) * pow(THETA(6),SEX) * pow(WT/70.0,THETA(7)); diff --git a/inst/mrgx/mrgx.h b/inst/mrgx/mrgx.h index f8426e50..1cec37d2 100644 --- a/inst/mrgx/mrgx.h +++ b/inst/mrgx/mrgx.h @@ -1,4 +1,4 @@ -// Copyright (C) 2013 - 2022 Metrum Research Group +// Copyright (C) 2013 - 2023 Metrum Research Group // // This file is part of mrgsolve. // @@ -22,7 +22,7 @@ #ifndef MRGX_H #define MRGX_H -#include "modelheader.h" +#include "mrgsolv.h" /** * @defgroup mrgx mrgx functions @@ -216,4 +216,3 @@ Rcpp::Function mt_fun() { } #endif - diff --git a/inst/stories.yaml b/inst/stories.yaml index 0668c20c..ef4acf35 100644 --- a/inst/stories.yaml +++ b/inst/stories.yaml @@ -1,4 +1,21 @@ # Please add stories at the top ------------------------------------------ +SLV-0010: + name: share root with NONMEM + description: > + As a user, I want to ask NMXML and NMEXT blocks to infer the root of the + NONMEM control stream from the root of the mrgsolve file. + ProductRisk: low-risk + tests: + - SLV-TEST-0021 + - SLV-TEST-0022 +SLV-0009: + name: Convert NMTRAN colums to NA + description: > + As a user, I want mrgsolve to convert NA values in select input data set + columns to 0. + ProductRisk: low-risk + tests: + - SLV-TEST-0020 SLV-0008: name: Dose and reset description: > @@ -69,4 +86,4 @@ SLV-S001: tests: - SLV-TEST-0004 - SLV-TEST-0005 - - SLV-TEST-0006 + - SLV-TEST-0006 \ No newline at end of file diff --git a/src/housemodel-mread-header.h b/src/housemodel-mread-header.h index c4e4dfe0..43d44596 100644 --- a/src/housemodel-mread-header.h +++ b/src/housemodel-mread-header.h @@ -1,5 +1,6 @@ // Source MD5: 509e24de6401c4c7d8c72c3487b55e52 +// PLUGINS: // FIXED: // No fixed parameters. @@ -13,10 +14,10 @@ #include "mrgsolv.h" #include "modelheader.h" -//INCLUDE databox functions: +// INCLUDE databox functions: #include "databox_cpp.h" -//USING plugins +// USING plugins: // GLOBAL CODE BLOCK: // GLOBAL VARS FROM BLOCKS & TYPEDEFS: diff --git a/tests/testthat.R b/tests/testthat.R index c47dca2c..23796e40 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2019 Metrum Research Group, LLC +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # @@ -19,6 +19,6 @@ Sys.setenv("R_TESTS" = "") library(magrittr) library(mrgsolve) library(testthat) -test_check("mrgsolve", reporter="summary") +test_check("mrgsolve", reporter="summary") diff --git a/tests/testthat/nm/cppstem-nmext/1005.cpp b/tests/testthat/nm/cppstem-nmext/1005.cpp new file mode 100644 index 00000000..7a1e7e14 --- /dev/null +++ b/tests/testthat/nm/cppstem-nmext/1005.cpp @@ -0,0 +1,4 @@ +[ nmext ] +run = "@cppstem" +project = "../nonmem" +root = "cppfile" diff --git a/tests/testthat/nm/cppstem-nmxml/1005.cpp b/tests/testthat/nm/cppstem-nmxml/1005.cpp new file mode 100644 index 00000000..5101a734 --- /dev/null +++ b/tests/testthat/nm/cppstem-nmxml/1005.cpp @@ -0,0 +1,4 @@ +[ nmxml ] +run = "@cppstem" +project = "../nonmem" +root = "cppfile" diff --git a/tests/testthat/test-modspec.R b/tests/testthat/test-modspec.R index c1e6c1fb..c1414034 100644 --- a/tests/testthat/test-modspec.R +++ b/tests/testthat/test-modspec.R @@ -25,6 +25,11 @@ context("test-modspec") options(mrgsolve_mread_quiet=TRUE) +new_test_build <- function(model = "pk1", project = tempdir()) { + file.copy(file.path(modlib(), paste0(model, ".cpp")), project, overwrite = TRUE) + mrgsolve:::new_build(model = model, project = project) +} + mtemp <- function(...) { mcode(model=basename(tempfile()),..., compile=FALSE) } @@ -249,7 +254,8 @@ $CMT @object pcmt }) test_that("parse content using low-level handlers - PARAM", { - env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), project = '.') + build <- new_test_build() + env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), build = build) sup <- suppressMessages input <- "c(1,2,3)" @@ -281,7 +287,8 @@ test_that("parse content using low-level handlers - PARAM", { }) test_that("parse content using low-level handlers - THETA", { - env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), project = '.') + build <- new_test_build() + env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), build = build) sup <- suppressMessages input <- "list(1,2,3)" @@ -307,7 +314,8 @@ test_that("parse content using low-level handlers - THETA", { }) test_that("parse content using low-level handlers - CMT", { - env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), project = '.') + build <- new_test_build() + env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), build = build) sup <- suppressMessages input <- "c(2,2,3)" @@ -333,7 +341,8 @@ test_that("parse content using low-level handlers - CMT", { }) test_that("parse content using low-level handlers - INIT", { - env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), project = '.') + build <- new_test_build() + env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), build = build) sup <- suppressMessages input <- "c(2,2,3)" @@ -360,7 +369,8 @@ test_that("parse content using low-level handlers - INIT", { }) test_that("parse content using low-level handlers - OMEGA, SIGMA", { - env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), project = '.') + build <- new_test_build() + env <- mrgsolve:::parse_env(vector(mode = "list", length = 20), build = build) sup <- suppressMessages input <- "c(1,2,3)" diff --git a/tests/testthat/test-mrgindata.R b/tests/testthat/test-mrgindata.R index df1efd68..e0611c88 100644 --- a/tests/testthat/test-mrgindata.R +++ b/tests/testthat/test-mrgindata.R @@ -194,3 +194,27 @@ test_that("integer64 columns are dropped from idata_set [SLV-TEST-0012]", { fixed = TRUE ) }) + +test_that("NA in nm-tran data items are converted to zeros [SLV-TEST-0020]", { + data <- expand.ev(amt = 100, ii = 12, addl = 2, rate = 5, ss = 1, ID = 1:2) + tmp <- data + tmp$ss[2] <- NA_real_ + + flagged <- mrgsolve:::check_column_na(tmp, c("ss", "aa", "II", "SS")) + expect_equal(flagged, "ss") + + tst <- valid_data_set(tmp, house()) + expect_equal(tst[, "ss"], c(1, 0)) + + tmp2 <- tmp + tmp2$FOO <- NA_real_ + flagged <- mrgsolve:::check_column_na(tmp2, mrgsolve:::GLOBALS$TRAN_FILL_NA) + expect_equal(flagged, "ss") + + for(col in c("AMT", "cmt", "ii", "SS", "RATE", "evid")) { + tmp <- data + tmp[[col]] <- c(1, NA_real_) + ans <- mrgsolve:::fill_tran_na(tmp) + expect_equal(ans[[col]], c(1, 0)) + } +}) diff --git a/tests/testthat/test-nmxml.R b/tests/testthat/test-nmxml.R index be858a34..d7ed1844 100644 --- a/tests/testthat/test-nmxml.R +++ b/tests/testthat/test-nmxml.R @@ -28,7 +28,7 @@ if(!requireNamespace("xml2",quietly=TRUE)) skip("xml2 is not installed.") code <- ' $NMXML -project=file.path(path.package("mrgsolve"), "nonmem") +project = file.path(path.package("mrgsolve"), "nonmem") run = 1005 oname="OMEGA", sname="SIGMA" sigma=TRUE @@ -353,3 +353,19 @@ test_that("nm source file is available via as.list", { expect_equal(basename(list2[["nm_import"]]), ans[2]) expect_equal(basename(list3[["nm_import"]]), ans) }) + +test_that("use cpp file stem as nm run number nmext [SLV-TEST-0021]", { + skip_if_not(file.exists("nm/cppstem-nmext/1005.cpp")) + mod <- mread("1005", project = "nm/cppstem-nmext") + expect_is(mod, "mrgmod") + nmext_file <- basename(as.list(mod)[["nm_import"]]) + expect_equal(nmext_file, "1005.ext") +}) + +test_that("use cpp file stem as nm run number nmxml [SLV-TEST-0022]", { + skip_if_not(file.exists("nm/cppstem-nmxml/1005.cpp")) + mod <- mread("1005", project = "nm/cppstem-nmxml") + expect_is(mod, "mrgmod") + nmxml_file <- basename(as.list(mod)[["nm_import"]]) + expect_equal(nmxml_file, "1005.xml") +}) diff --git a/tests/testthat/test-opts.R b/tests/testthat/test-opts.R index 89592813..90148564 100644 --- a/tests/testthat/test-opts.R +++ b/tests/testthat/test-opts.R @@ -21,6 +21,11 @@ library(dplyr) Sys.setenv(R_TESTS="") options("mrgsolve_mread_quiet"=TRUE) +new_test_build <- function(model = "pk1", project = tempdir()) { + file.copy(file.path(modlib(), paste0(model, ".cpp")), project, overwrite = TRUE) + mrgsolve:::new_build(model = model, project = project) +} + context("test-opts") test_that("Options where they don't belong", { @@ -45,7 +50,8 @@ test_that("Scrape and call", { >> d = 2 CL=1, V=2, KA=3 ' - e <- mrgsolve:::parse_env(spec=1,project=tempdir()) + + e <- mrgsolve:::parse_env(spec=1, build = new_test_build()) code <- trimws(unlist(strsplit(code, "\n"))) @@ -58,4 +64,12 @@ test_that("Scrape and call", { }) - +test_that("dump options from block code", { + code <- c("foo", "@bar") + ans <- mrgsolve:::dump_opts(code) + expect_equal(ans, "foo") + + code <- c("foo", "bar @yak") + ans <- mrgsolve:::dump_opts(code) + expect_equal(ans, code) +}) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 52092009..3fa0bcdb 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2020 Metrum Research Group +# Copyright (C) 2013 - 2023 Metrum Research Group # # This file is part of mrgsolve. # @@ -174,3 +174,4 @@ test_that("gregexecdf", { expect_equal(nrow(ans), 0) expect_equal(ncol(ans), 0) }) +