Repository: pharmaverse/aNCA
Pull request #343: Enhancement/add tests pivot wider pknca results (#287) & create fixture test datasets
Author: login: Gero1999
Created: 2025-04-14T09:31:31Z | Merged: 2025-05-07T07:43:53Z

Contributes to #287 

## Description
### Main implementation
* Added tests to `tests/testthat/test-pivot_wider_pknca_results.R` for 100% coverage (covr). Included checks for reshaping main intervals, columns, handling AUC intervals, rounding numeric values, adding appropriate labels, and handling exclude values correctly.
- Created new testing data for all cases and independent of package functions. 
- Found bug in bioavailability for created testing data. Needed to change `bioavailability.R`

### Additional modifications
* Updated the `@param myres` documentation to specify additional assumptions about the input data, such as CDISC denomination of time variables and the inclusion of specific columns like `type_interval`, `PPSTRES`, and `PPSTRESU`

* Added a new column `time_col` to handle time-related data more flexibly.

## Definition of Done

- [x] tests have a 100% coverage for `pivot_wider_pknca.R` (`covr`)
- [x] tests seem logical

## How to test
- check tests in file `tests/testthat/test-pivot_wider_pknca_results.R`

## Contributor checklist
- [x] Code passes lintr checks
- [x] Code passes all unit tests
- [x] New logic covered by unit tests
- [x] New logic is documented
- [ ] Package version is incremented

## Notes to reviewer

Anything that the reviewer should know before tacking the pull request?



Diff:
diff --git a/R/bioavailability.R b/R/bioavailability.R
index 237e212f4..97e3024c3 100644
--- a/R/bioavailability.R
+++ b/R/bioavailability.R
@@ -171,4 +171,4 @@ PKNCA_add_F <- function(res_nca, bioavailability) { # nolint: object_name_linter
   res_nca$result <- bind_rows(res_nca$result, f_results)
 
   res_nca
-}
+}
\ No newline at end of file
diff --git a/R/pivot_wider_pknca_results.R b/R/pivot_wider_pknca_results.R
index 5471558cd..2eebd9c8d 100644
--- a/R/pivot_wider_pknca_results.R
+++ b/R/pivot_wider_pknca_results.R
@@ -6,7 +6,15 @@
 #' each column name corresponds with a calculated parameter and between brackets its
 #' corresponding units. AUC intervals, if present, are be added as additional columns.
 #'
-#' @param myres The output of PKNCA::pk.nca
+#' @param myres The output of PKNCA::pk.nca. It makes some additional assumptions:
+#'   1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#'   2) Intervals must include a column (`type_interval`) to differentiate between the
+#'   custom AUC ranges ("manual") and main parameter calculations ("main").
+#'   3) Includes `PPSTRES` and `PPSTRESU` variables in results dataset.
+#'   4) Columns `start_dose` and `end_dose` must express the actual start and end times
+#'   of the dose, relative to the last reference dose.
+#'   5) Temporarily: CDISC denomination of PK parameters related to half-life: "LAMZNPT",
+#'   "LAMZLL", "LAMZ" Used to derive `LAMZNPT` and `LAMZMTD`.
 #'
 #' @returns A data frame which provides an easy overview on the results from the NCA
 #'          in each profile/subject and how it was computed lambda (half life) and the results
@@ -24,6 +32,7 @@ pivot_wider_pknca_results <- function(myres) {
   # Derive LAMZNPT & LAMZMTD
   # ToDo: At some point this will be integrated in PKNCA and will need to be removed//modified
   conc_groups <- unname(unlist(myres$data$conc$columns$groups))
+  time_col <- myres$data$conc$columns$time
   data_with_duplicates <- dose_profile_duplicates(
     myres$data$conc$data,
     c(unlist(unname(myres$data$conc$columns$groups)),
@@ -37,7 +46,7 @@ pivot_wider_pknca_results <- function(myres) {
     added_params <- myres$result %>%
       filter(PPTESTCD %in% c("LAMZNPT", "LAMZLL", "LAMZ"),
              type_interval == "main") %>%
-      select(conc_groups, PPTESTCD, PPSTRES, DOSNO, start, end) %>%
+      select(any_of(c(conc_groups, "PPTESTCD", "PPSTRES", "DOSNO", "start", "end"))) %>%
       unique() %>%
       pivot_wider(names_from = PPTESTCD, values_from = PPSTRES) %>%
       left_join(data_with_duplicates, by = intersect(names(.), names(data_with_duplicates))) %>%
@@ -48,11 +57,11 @@ pivot_wider_pknca_results <- function(myres) {
         any(is.excluded.hl) | any(is.included.hl), "Manual", "Best slope"
       )) %>%
       filter(!exclude_half.life | is.na(LAMZLL) | is.na(LAMZNPT)) %>%
-      filter(TIME >= (LAMZLL + start) | is.na(LAMZLL)) %>%
+      filter(!!sym(time_col) >= (LAMZLL + start) | is.na(LAMZLL)) %>%
       filter(row_number() <= LAMZNPT | is.na(LAMZNPT)) %>%
       mutate(LAMZIX = paste0(IX, collapse = ",")) %>%
       mutate(LAMZIX = ifelse(is.na(LAMZ), NA, LAMZIX)) %>%
-      select(conc_groups, DOSNO, start, end, LAMZIX, LAMZMTD) %>%
+      select(any_of(c(conc_groups, "DOSNO", "start", "end", "LAMZIX", "LAMZMTD"))) %>%
       unique()
   }
   ############################################################################################
diff --git a/R/zzz.R b/R/zzz.R
index f594b68a0..a155a8a7f 100644
--- a/R/zzz.R
+++ b/R/zzz.R
@@ -8,6 +8,7 @@
     "ARRLT",
     "AUC_EX",
     "AUC_IV",
+    "auc_type",
     "AVAL",
     "AVISIT",
     "CI_lower",
@@ -15,6 +16,8 @@
     "conv_factor",
     "Count.missing",
     "Count.total",
+    "Dose_IV",
+    "Dose_EX",
     "DFLAG",
     "DOSEA",
     "DOSNO",
@@ -22,8 +25,8 @@
     "Dataset",
     "Depends",
     "Dose",
-    "Dose_EX",
-    "Dose_IV",
+    "Dose_extravascular",
+    "Dose_intravascular",
     "DRUG",
     "Dataset",
     "EVID",
@@ -106,6 +109,7 @@
     "end_dose",
     "exclude",
     "exclude_half.life",
+    "f_auc",
     "format_fun",
     "id_list",
     "id_plot",
@@ -125,6 +129,8 @@
     "log10_Mean",
     "log10_SD",
     "log10_SE",
+    "Mean_Dose_IV",
+    "Mean_AUC_IV",
     "next_dose",
     "next_nom_dose",
     "nom_dose_time",
@@ -137,6 +143,9 @@
     "start_dose",
     "time_dose",
     "type_interval",
+    "vals",
+    "vals_extravascular",
+    "vals_intravascular",
     "var_name",
     "view",
     "VISIT",
diff --git a/inst/WORDLIST b/inst/WORDLIST
index 9cd9a91c5..ad79d834b 100644
--- a/inst/WORDLIST
+++ b/inst/WORDLIST
@@ -11,6 +11,9 @@ CDISC
 DOSEA
 DOSEU
 DOSNO
+LAMZ
+LAMZLL
+LAMZNPT
 MSCW
 NCA
 NFRLT
diff --git a/inst/shiny/modules/tab_nca/nca_results.R b/inst/shiny/modules/tab_nca/nca_results.R
index eb93ebcb7..169ee6b56 100644
--- a/inst/shiny/modules/tab_nca/nca_results.R
+++ b/inst/shiny/modules/tab_nca/nca_results.R
@@ -133,7 +133,7 @@ nca_results_server <- function(id, pknca_data, res_nca, rules, grouping_vars, au
                                col_names)
 
       final_results() %>%
-        select(c(all_of(col_names[!(col_base_names %in% params_rem_cols)])), -conc_groups)
+        select(c(all_of(col_names[!(col_base_names %in% params_rem_cols)])))
     })
 
     output$myresults <- reactable::renderReactable({
diff --git a/man/pivot_wider_pknca_results.Rd b/man/pivot_wider_pknca_results.Rd
index ea011e13a..23cdd77f8 100644
--- a/man/pivot_wider_pknca_results.Rd
+++ b/man/pivot_wider_pknca_results.Rd
@@ -7,7 +7,17 @@
 pivot_wider_pknca_results(myres)
 }
 \arguments{
-\item{myres}{The output of PKNCA::pk.nca}
+\item{myres}{The output of PKNCA::pk.nca. It makes some additional assumptions:
+\enumerate{
+\item CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+\item Intervals must include a column (\code{type_interval}) to differentiate between the
+custom AUC ranges ("manual") and main parameter calculations ("main").
+\item Includes \code{PPSTRES} and \code{PPSTRESU} variables in results dataset.
+\item Columns \code{start_dose} and \code{end_dose} must express the actual start and end times
+of the dose, relative to the last reference dose.
+\item Temporarily: CDISC denomination of PK parameters related to half-life: "LAMZNPT",
+"LAMZLL", "LAMZ" Used to derive \code{LAMZNPT} and \code{LAMZMTD}.
+}}
 }
 \value{
 A data frame which provides an easy overview on the results from the NCA
diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R
index 321cc860c..547b298d8 100644
--- a/tests/testthat/setup.R
+++ b/tests/testthat/setup.R
@@ -1,5 +1,326 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in FIXTURE_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+base::local({
+  # Create Testing Concentration Data
+  FIXTURE_CONC_DATA <<- data.frame(
+    # Columns that are mapped from the data
+    AVAL = c(                 # USUBJID.DOSNO
+      0:4,                    # 1.1 (Extravascular, linear & sample at dose)
+      c(1, 2, 1.5, 1, 0.5),   # 2.1 (Extravascular eq, with max)
+      c(1, 2, 1.5, 1, 0.5),   # 2.2 (Extravascular eq, 2nd dose)
+      5:1,                    # 3.1 (IV bolus)
+      5:1,                    # 3.2 (IV bolus, 2nd dose)
+      rep(2, 5),              # 4.1 (IV bolus, abnormal profile)
+      c(1, 2.5, 1, 0.7, 0.5), # 5.1 (Infusion)
+      5:1,                    # 6.1 (IV bolus, metabolite)
+      c(1:3, NA, 0.5)         # 7.1 (Extravascular, with NA)
+    ),
+    AFRLT = c(                # Assumption 1: CDISC time variables
+      0:4,                   # 1.1
+      seq(0.5, 4.5, 1),      # 2.1
+      seq(5.5, 9.5, 1),      # 2.2
+      seq(0.5, 4.5, 1),      # 3.1
+      seq(5.5, 9.5, 1),      # 3.2
+      seq(0.5, 4.5, 1),      # 4.1
+      seq(0.5, 4.5, 1),      # 5.1
+      seq(0.5, 4.5, 1),      # 6.1
+      seq(0.5, 4.5, 1)       # 7.1
+    ),
+    ARRLT = c(                # Assumption 1: CDISC time variables
+      0:4,                   # 1.1
+      seq(0.5, 4.5, 1),      # 2.1
+      seq(0.5, 4.5, 1),      # 2.2
+      seq(0.5, 4.5, 1),      # 3.1
+      seq(0.5, 4.5, 1),      # 3.2
+      seq(0.5, 4.5, 1),      # 4.1
+      seq(0.5, 4.5, 1),      # 5.1
+      seq(0.5, 4.5, 1),      # 6.1
+      seq(0.5, 4.5, 1)       # 7.1
+    ),
+    NFRLT = c(                # Assumption 1: CDISC time variables
+      0:4,                   # 1.1
+      seq(0.5, 4.5, 1),      # 2.1
+      seq(5.5, 9.5, 1),      # 2.2
+      seq(0.5, 4.5, 1),      # 3.1
+      seq(5.5, 9.5, 1),      # 3.2
+      seq(0.5, 4.5, 1),      # 4.1
+      seq(0.5, 4.5, 1),      # 5.1
+      seq(0.5, 4.5, 1),      # 6.1
+      seq(0.5, 4.5, 1)       # 7.1
+    ),
+    NRRLT = c(                # Assumption 1: CDISC time variables
+      0:4,                   # 1.1
+      seq(0.5, 4.5, 1),      # 2.1
+      seq(0.5, 4.5, 1),      # 2.2
+      seq(0.5, 4.5, 1),      # 3.1
+      seq(0.5, 4.5, 1),      # 3.2
+      seq(0.5, 4.5, 1),      # 4.1
+      seq(0.5, 4.5, 1),      # 5.1
+      seq(0.5, 4.5, 1),      # 6.1
+      seq(0.5, 4.5, 1)       # 7.1
+    ),
+    ROUTE = c(
+      rep("extravascular", 5 * 3), # 1.1 - 2.2
+      rep("intravascular", 5 * 6)  # 3.1 - 7.1
+    ),
+    PARAM = c(
+      rep("A", 5 * 7),          # 1.1 - 5.1
+      rep("B", 5 * 1),          # 6.1 (IV bolus, metabolite)
+      rep("A", 5 * 1)           # 7.1 (Extravascular, with NA)
+    ),
+    USUBJID = c(
+      rep(1, 5),
+      rep(2, 5 * 2),
+      rep(3, 5 * 2),
+      rep(4, 5),
+      rep(5, 5),
+      rep(6, 5),
+      rep(7, 5)
+    ),
+    DOSNO = c(
+      rep(1, 5),
+      rep(1:2, each = 5),
+      rep(1:2, each = 5),
+      rep(1, 5),
+      rep(1, 5),
+      rep(1, 5),
+      rep(1, 5)
+    ),
+    # Included by aNCA internally
+    is.excluded.hl = FALSE,
+    is.included.hl = FALSE,
+    exclude_half.life = FALSE,
+    # Units
+    AVALU = "mg/L",
+    RRLTU = "h"
+  )
+
+  # Create Testing Dose Data
+  FIXTURE_DOSE_DATA <<- data.frame(
+    AFRLT = c(
+      0,
+      c(0, 5),
+      c(0, 5),
+      0,
+      0,
+      0,
+      0
+    ),
+    ARRLT = c(
+      0,
+      c(0, 0),
+      c(0, 0),
+      0,
+      0,
+      0,
+      0
+    ),
+    NFRLT = c(
+      0,
+      c(0, 5),
+      c(0, 5),
+      0,
+      0,
+      0,
+      0
+    ),
+    NRRLT = c(
+      0,
+      c(0, 0),
+      c(0, 0),
+      0,
+      0,
+      0,
+      0
+    ),
+    ROUTE = c(
+      rep("extravascular", 3),
+      rep("intravascular", 5),
+      "extravascular"
+    ),
+    ADOSE = 1,
+    DRUG = "A",
+    ADOSEDUR = c(
+      rep(0, 6),
+      1,            # 5.1 (Infusion)
+      0,
+      0
+    ),
+    USUBJID = c(
+      1,
+      rep(2, 2),
+      rep(3, 2),
+      4,
+      5,
+      6,
+      7
+    ),
+    DOSNO = c(
+      1,
+      c(1, 2),
+      c(1, 2),
+      1,
+      1,
+      1,
+      1
+    )
+  )
+
+  # Perform NCA Analysis
+  all_params <- setdiff(names(PKNCA::get.interval.cols()),
+                        c("start", "end"))
+  main_intervals <- data.frame(
+    start = c(0, 5),
+    end = c(5, 10),
+    type_interval = "main",  # Assumption 2: Include type_interval column
+    DOSNO = c(1, 2)
+  ) %>%
+    left_join(
+      FIXTURE_DOSE_DATA %>%
+        select(USUBJID, DOSNO) %>%
+        unique()
+    )
+  main_intervals[, all_params] <- FALSE
+  main_intervals <- main_intervals %>%
+    mutate(
+      half.life = TRUE,
+      cmax = TRUE,
+      auclast = TRUE,
+      aucinf.obs = TRUE
+    )
+  auc_intervals <- data.frame(
+    # Intervals for AUC_0-2, AUC_2-4 in each dose
+    start = c(0, 2, 5, 7),
+    end = c(2, 4, 7, 9),
+    type_interval = "manual",  # Assumption 2: Include type_interval column
+    DOSNO = c(1, 1, 2, 2)
+  ) %>%
+    left_join(
+      FIXTURE_DOSE_DATA %>%
+        select(USUBJID, DOSNO) %>%
+        unique(),
+      by = "DOSNO",
+      relationship = "many-to-many"
+    )
+  auc_intervals[, all_params] <- FALSE
+  auc_intervals <- auc_intervals %>%
+    mutate(
+      aucint.last = TRUE
+    )
+  FIXTURE_INTERVALS <<- rbind(main_intervals, auc_intervals) %>%
+    mutate(impute = case_when(
+      USUBJID == 1 & DOSNO == 1 ~ NA_character_,
+      USUBJID == 2 & DOSNO == 1 ~ "start_conc0",
+      USUBJID == 2 & DOSNO == 2 ~ "start_predose",
+      USUBJID == 3 & DOSNO == 1 ~ "start_logslope",
+      USUBJID == 3 & DOSNO == 2 ~ "start_logslope",
+      USUBJID == 4 & DOSNO == 1 ~ "start_c1",
+      USUBJID == 4 & DOSNO == 2 ~ "start_c1",
+      USUBJID == 5 & DOSNO == 1 ~ "start_conc0",
+      USUBJID == 5 & DOSNO == 2 ~ "start_conc0",
+      USUBJID == 6 & DOSNO == 1 ~ "start_conc0",
+      USUBJID == 6 & DOSNO == 2 ~ "start_conc0",
+      USUBJID == 7 & DOSNO == 1 ~ "start_conc0",
+      USUBJID == 7 & DOSNO == 2 ~ "start_conc0",
+      TRUE ~ NA_character_
+    ))
+
+  FIXTURE_PKNCA_DATA <<- PKNCA::PKNCAdata(
+    data.conc = PKNCA::PKNCAconc(FIXTURE_CONC_DATA, AVAL ~ AFRLT | USUBJID / PARAM),
+    data.dose = PKNCA::PKNCAdose(FIXTURE_DOSE_DATA, ADOSE ~ AFRLT | USUBJID,
+                                 route = "ROUTE", duration = "ADOSEDUR",
+                                 time.nominal = "NFRLT"),
+    units = PKNCA::pknca_units_table(
+      concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+    )
+  )
+  FIXTURE_PKNCA_DATA$intervals <<- FIXTURE_INTERVALS
+  FIXTURE_PKNCA_DATA$options <<- list(keep_interval_cols = c("DOSNO", "type_interval"))
+
+  # Add start_dose and end_dose columns
+  FIXTURE_PKNCA_RES <<- withCallingHandlers(
+    PKNCA::pk.nca(FIXTURE_PKNCA_DATA),
+    warning = function(w) {
+      # Suppress warnings matching the regex "Too few points for half-life"
+      if (grepl("^Too few points for half-life", conditionMessage(w))) {
+        invokeRestart("muffleWarning")
+      }
+    }
+  )
+
+  #####################################################################
+  # Temporarily for some odd reason we cannot use keep_interval_cols,
+  # so we are manually making it
+  #
+  # TODO: Substitute this dirty hard coded trick with the proper way
+  FIXTURE_PKNCA_RES$result <<- FIXTURE_PKNCA_RES$result %>%
+    mutate(
+      type_interval = if ("type_interval" %in% names(.)) {
+        type_interval
+      } else {
+        ifelse((end - start) == 2, "manual", "main")
+      },
+      DOSNO = if ("DOSNO" %in% names(.)) {
+        DOSNO
+      } else {
+        ifelse(
+          start < 5,
+          1,
+          2
+        )
+      }
+    )
+  #####################################################################
+
+  dose_data_to_join_fixture <- select(
+    FIXTURE_PKNCA_RES$data$dose$data,
+    -exclude,
+    -FIXTURE_PKNCA_RES$data$dose$data$conc$columns$groups$group_analyte
+  )
+
+  FIXTURE_PKNCA_RES$result <<- FIXTURE_PKNCA_RES$result %>%
+    inner_join(
+      dose_data_to_join_fixture,
+      by = intersect(names(.), names(dose_data_to_join_fixture))
+    ) %>%
+    mutate(
+      # Assumption 4: start_dose &  end_dose relative to the dose time
+      start_dose = start - !!sym(FIXTURE_PKNCA_RES$data$dose$columns$time),
+      end_dose = end - !!sym(FIXTURE_PKNCA_RES$data$dose$columns$time),
+      # Assumption 3: PPSTRESU & PPSTRES are always in the results object
+      PPSTRESU = ifelse(PPORRESU %in% c("fraction", "unitless"), "", PPORRESU),
+      PPSTRES = PPORRES,
+      # Assumption 5: PPTESTCD column folllows CDISC format
+      PPTESTCD = translate_terms(PPTESTCD, "PKNCA", "PPTESTCD")
+    )
+})
+
+# Dummy data
 # Import dataset from testthat/data folder
 
+# ToDo (Gerardo): These fixtures are supporting still test-bioavailability.R
+# We need to substitute them with the previous ones for consistency
+
 DUMMY_DATA_FIXTURE <- read.csv(testthat::test_path("data", "adnca_dummy_sm_dataset.csv"))
 
 # Create PKNCAdata object
@@ -15,4 +336,12 @@ PKNCA_DATA_FIXTURE$intervals <- format_pkncadata_intervals(
 PKNCA_DATA_FIXTURE <- create_start_impute(PKNCA_DATA_FIXTURE)
 
 # Create NCA results
-PKNCA_RESULTS_FIXTURE <- PKNCA_calculate_nca(PKNCA_DATA_FIXTURE)
+PKNCA_RESULTS_FIXTURE <- withCallingHandlers(
+  PKNCA_calculate_nca(PKNCA_DATA_FIXTURE),
+  warning = function(w) {
+    # Suppress warnings matching the regex "Too few points for half-life"
+    if (grepl("^Too few points for half-life", conditionMessage(w))) {
+      invokeRestart("muffleWarning")
+    }
+  }
+)
diff --git a/tests/testthat/test-bioavailability.R b/tests/testthat/test-bioavailability.R
index fe1600821..9b04b126d 100644
--- a/tests/testthat/test-bioavailability.R
+++ b/tests/testthat/test-bioavailability.R
@@ -27,4 +27,4 @@ describe("calculate_F", {
 
     expect_true(any(is.na(result$f_auclast)) || any(result$f_auclast > 0))
   })
-})
+})
\ No newline at end of file
diff --git a/tests/testthat/test-create_start_impute.R b/tests/testthat/test-create_start_impute.R
index 81c06a35a..942ae937b 100644
--- a/tests/testthat/test-create_start_impute.R
+++ b/tests/testthat/test-create_start_impute.R
@@ -1,50 +1,16 @@
-# Create concentration, dose and interval datasets with all imputation cases
-conc_data <- data.frame(
-  conc = c(1:3, c(1, 2, 0.5), 1:3, 6:4, 6:4, rep(2, 3), 1:3, 6:4),
-  time = c(0:2, c(1, 2, 2.5), 4:6, c(1, 2, 2.5), 4:6, c(1, 2, 2.5), c(1, 2, 2.5), c(1, 2, 2.5)),
-  route = c(rep("extravascular", 9), rep("intravascular", 15)),
-  param = c(rep("A", 21), rep("B", 3)),
-  USUBJID = c(rep(1, 3), rep(2, 6), rep(3, 6), rep(4, 3), rep(5, 3), rep(6, 3)),
-  DOSNO = c(rep(1, 3), rep(rep(1:2, each = 3), 2), rep(1, 3), rep(1, 3), rep(1, 3))
-)
+pknca_data <- FIXTURE_PKNCA_DATA
 
-dose_data <- data.frame(
-  time = c(0, 0, 3, 0, 3, 0, 0, 0),
-  route = c(rep("extravascular", 3), rep("intravascular", 5)),
-  dose = 1,
-  DRUG = "A",
-  duration = c(0, 0, 0, 0, 0, 0, 1, 0),
-  USUBJID = c(1, rep(2, 2), rep(3, 2), 4, 5, 6),
-  DOSNO = c(1, c(1, 2), c(1, 2), 1, 1, 1)
-)
-
-intervals_data <- data.frame(
-  start = c(0, 0, 3, 0, 3, 0, 0, 0),
-  end =   c(3, 3, 6, 3, 6, 3, 3, 3),
-  USUBJID =  c(1, rep(2, 2), rep(3, 2), 4, 5, 6),
-  DOSNO = c(1, 1, 2, 1, 2, 1, 1, 1),  # Include second dose profile for USUBJID 6
-  tmax = TRUE,
-  auclast = TRUE,
-  aucinf.pred = TRUE
-)
-
-conc_obj <- PKNCA::PKNCAconc(conc_data, conc ~ time | USUBJID + DOSNO / param)
-dose_obj <- PKNCA::PKNCAdose(dose_data, dose ~ time | USUBJID + DOSNO,
-                             duration = "duration", route = "route")
-mydata <- PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals_data)
-
-# Apply the function
 describe("create_start_impute", {
   it("works without issue", {
     expect_no_error({
-      result <- create_start_impute(mydata)
+      result <- create_start_impute(pknca_data)
     })
   })
 
-  result <- create_start_impute(mydata)
+  result <- create_start_impute(pknca_data)
 
   it("provides a warning when data$intervals is empty or has no rows", {
-    mydata_noints <- mydata
+    mydata_noints <- pknca_data
     mydata_noints$intervals <- data.frame()
     mydata_noints_res <- suppressWarnings(create_start_impute(mydata_noints))
     expect_warning(create_start_impute(mydata_noints), "No intervals provided. No modification")
@@ -52,56 +18,56 @@ describe("create_start_impute", {
 
   it("does not add impute (NA) when start is in PKNCAconc", {
     not_imputed <- result$intervals %>%
-      dplyr::filter(USUBJID == 1, DOSNO == 1) %>%
+      dplyr::filter(USUBJID == 1, DOSNO == 1, type_interval == "main") %>%
       dplyr::pull(impute)
     expect_equal(not_imputed, NA_character_)
   })
 
   it("sets conc0 when route is extravascular (first dose)", {
     expect_equal(result$intervals %>%
-                   dplyr::filter(USUBJID == 2, DOSNO == 1) %>%
+                   dplyr::filter(USUBJID == 2, DOSNO == 1,  type_interval == "main") %>%
                    dplyr::pull(impute),
                  "start_conc0")
   })
 
   it("sets predose when route is extravascular (later dose)", {
     expect_equal(result$intervals %>%
-                   dplyr::filter(USUBJID == 2, DOSNO == 2) %>%
+                   dplyr::filter(USUBJID == 2, DOSNO == 2, type_interval == "main") %>%
                    dplyr::pull(impute),
                  "start_predose")
   })
 
   it("sets logslope when route is IV bolus (first dose)", {
     expect_equal(result$intervals %>%
-                   dplyr::filter(USUBJID == 3, DOSNO == 1) %>%
+                   dplyr::filter(USUBJID == 3, DOSNO == 1, type_interval == "main") %>%
                    dplyr::pull(impute),
                  "start_logslope")
   })
 
   it("sets logslope when route is IV bolus (later dose)", {
     expect_equal(result$intervals %>%
-                   dplyr::filter(USUBJID == 3, DOSNO == 2) %>%
+                   dplyr::filter(USUBJID == 3, DOSNO == 2, type_interval == "main") %>%
                    dplyr::pull(impute),
                  "start_logslope")
   })
 
   it("sets c1 when route is IV bolus not monodecaying (first dose)", {
     expect_equal(result$intervals %>%
-                   dplyr::filter(USUBJID == 4, DOSNO == 1) %>%
+                   dplyr::filter(USUBJID == 4, DOSNO == 1, type_interval == "main") %>%
                    dplyr::pull(impute),
                  "start_c1")
   })
 
   it("sets conc0 when route is IV bolus not monodecaying (first dose)", {
     expect_equal(result$intervals %>%
-                   dplyr::filter(USUBJID == 5, DOSNO == 1) %>%
+                   dplyr::filter(USUBJID == 5, DOSNO == 1, type_interval == "main") %>%
                    dplyr::pull(impute),
                  "start_conc0")
   })
 
   it("sets conc0 when route is IV bolus not monodecaying (first dose)", {
     expect_equal(result$intervals %>%
-                   dplyr::filter(USUBJID == 6, DOSNO == 1) %>%
+                   dplyr::filter(USUBJID == 6, DOSNO == 1, type_interval == "main") %>%
                    dplyr::pull(impute),
                  "start_conc0")
   })
diff --git a/tests/testthat/test-lambda_slope_plot.R b/tests/testthat/test-lambda_slope_plot.R
index 24855036c..10d789e05 100644
--- a/tests/testthat/test-lambda_slope_plot.R
+++ b/tests/testthat/test-lambda_slope_plot.R
@@ -1,15 +1,24 @@
 describe("lambda_slope_plot", {
 
-  conc_pknca_df <- PKNCA_DATA_FIXTURE$conc$data
-  myres <- PKNCA_RESULTS_FIXTURE
-
-  valid_row <- myres$result %>%
-    filter(PPTESTCD == "half.life") %>%
-    slice(1)
-
-  row_values <- valid_row %>%
-    select(any_of(c("USUBJID", "STUDYID", "DOSE", "DOSEU"))) %>%
-    as.list()
+  conc_pknca_df <- FIXTURE_PKNCA_DATA$conc$data %>%
+    # ToDo: The currerent lambda_slope_plot
+    # has additional non-neccesary assumptions
+    mutate(TIME = AFRLT,
+           PCSTRESU = AVALU)
+
+  myres <- FIXTURE_PKNCA_RES
+  myres$result <- myres$result %>%
+    mutate(PPTESTCD = translate_terms(
+      PPTESTCD, "PPTESTCD", "PKNCA"
+    ))
+
+  row_values <- myres$data$intervals %>%
+    filter(half.life) %>%
+    select(any_of(c(
+      unname(unlist(myres$data$conc$columns$groups)),
+      "DOSNO"
+    ))) %>%
+    filter(USUBJID == 5)
 
   it("returns a plotly object with valid input", {
     plotly_output <- lambda_slope_plot(
@@ -31,8 +40,7 @@ describe("lambda_slope_plot", {
       mutate(
         PPSTRES = ifelse(
           PPTESTCD == "lambda.z.n.points" &
-            USUBJID == row_values$USUBJID &
-            STUDYID == row_values$STUDYID,
+            USUBJID == row_values$USUBJID,
           NA_real_,
           PPSTRES
         )
@@ -65,8 +73,7 @@ describe("lambda_slope_plot", {
     conc_modified <- conc_pknca_df %>%
       mutate(
         AVAL = ifelse(
-          USUBJID == row_values$USUBJID &
-            STUDYID == row_values$STUDYID,
+          USUBJID == row_values$USUBJID,
           -1,
           AVAL
         )
@@ -88,10 +95,13 @@ describe("lambda_slope_plot", {
     myres_modified <- myres
 
     # Use the same subject for consistency
-    test_id <- myres_modified$result %>%
-      filter(PPTESTCD == "cmax") %>%
-      slice(1) %>%
-      select(any_of(c("USUBJID", "STUDYID")))
+    test_id  <- myres$data$intervals %>%
+      filter(half.life) %>%
+      select(any_of(c(
+        unname(unlist(myres$data$conc$columns$groups)),
+        "DOSNO"
+      ))) %>%
+      filter(USUBJID == 5)
 
     row_values <- test_id %>% as.list()
 
@@ -99,8 +109,7 @@ describe("lambda_slope_plot", {
     tmax_value <- myres_modified$result %>%
       filter(PPTESTCD == "tmax") %>%
       filter(
-        USUBJID == row_values$USUBJID,
-        STUDYID == row_values$STUDYID
+        USUBJID == row_values$USUBJID
       ) %>%
       pull(PPSTRES)
 
@@ -109,8 +118,7 @@ describe("lambda_slope_plot", {
       mutate(
         PPSTRES = ifelse(
           PPTESTCD == "lambda.z.time.first" &
-            USUBJID == row_values$USUBJID &
-            STUDYID == row_values$STUDYID,
+            USUBJID == row_values$USUBJID,
           tmax_value,
           PPSTRES
         )
diff --git a/tests/testthat/test-pivot_wider_pknca_results.R b/tests/testthat/test-pivot_wider_pknca_results.R
new file mode 100644
index 000000000..d6d0edbae
--- /dev/null
+++ b/tests/testthat/test-pivot_wider_pknca_results.R
@@ -0,0 +1,188 @@
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `pknca_res` object.
+#'
+#' @param pknca_res The original PKNCA results object.
+#' @param pivoted_res The pivoted results from `pivot_wider_pknca_results`.
+#' @returns A logical value indicating whether all checks passed.
+.validate_pknca_params <- function(pknca_res, pivoted_res) {
+
+  # Extract unique parameter names with units
+  names_params <- pknca_res$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start_dose, "-", end_dose, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- pknca_res$result %>%
+        filter(
+          start_dose == auc_start,
+          end_dose == auc_end,
+          type_interval == "manual"
+        )
+      reshaped_data <- pivoted_res %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- pknca_res$result
+      reshaped_data <- pivoted_res
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+}
+
+
+describe("pivot_wider_pknca_results", {
+
+  pivoted_res <- expect_no_error(pivot_wider_pknca_results(FIXTURE_PKNCA_RES))
+
+  it("produces a data.frame", {
+    expect_s3_class(pivoted_res, "data.frame")
+  })
+
+  it("produces a data.frame with expected format when only reshaping main intervals", {
+    res_only_main <- FIXTURE_PKNCA_RES
+    res_only_main$result <- FIXTURE_PKNCA_RES$result  %>%
+      filter(type_interval == "main")
+    pivoted_res_only_main <- pivot_wider_pknca_results(res_only_main)
+    expect_s3_class(pivoted_res_only_main, "data.frame")
+
+    # Check that the result contains expected columns
+    group_columns <- PKNCA::getGroups(res_only_main$data$conc)
+    expected_colnames <- c(
+      "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "AUCLST[hr*ng/mL]", "AUCIFO[hr*ng/mL]", "CLST[ng/mL]",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX",
+      "LAMZMTD", "Exclude",
+      colnames(group_columns),
+      intersect(colnames(res_only_main$data$dose$data), colnames(pivoted_res_only_main))
+    )
+    expect_setequal(colnames(pivoted_res_only_main), expected_colnames)
+
+    # Check number of rows is the expected (each dose has 1 row in the pivoted data)
+    expect_equal(nrow(pivoted_res_only_main), nrow(res_only_main$data$dose$data))
+
+    # Check parameter values match the ones in the PKNCA results object
+    expect_no_error(.validate_pknca_params(res_only_main, pivoted_res_only_main))
+  })
+
+  it("reshapes PKNCA results correctly when also considering AUC intervals", {
+    # Check that the result is a data frame
+    expect_s3_class(pivoted_res, "data.frame")
+
+    # Check that the result contains expected columns
+    group_columns <- PKNCA::getGroups(FIXTURE_PKNCA_RES$data$conc)
+    expected_colnames <- c(
+      "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "AUCLST[hr*ng/mL]", "AUCIFO[hr*ng/mL]", "CLST[ng/mL]",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX", "LAMZMTD", "Exclude",
+      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]",
+      colnames(group_columns),
+      intersect(colnames(FIXTURE_PKNCA_RES$data$dose$data), colnames(pivoted_res))
+    )
+    expect_setequal(colnames(pivoted_res), expected_colnames)
+    expect_equal(nrow(pivoted_res), nrow(FIXTURE_PKNCA_RES$data$dose$data))
+
+    expect_no_error(.validate_pknca_params(FIXTURE_PKNCA_RES, pivoted_res))
+  })
+
+  it("rounds numeric values to three decimals", {
+    expected_num_param_cols <- c(
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]", "LAMZNPT[count]", "LAMZSPN",
+      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]"
+    )
+    actual_values <- pivoted_res[, expected_num_param_cols]
+    expected_values <- round(actual_values, 3)
+    diff_values <- actual_values - expected_values
+
+    all_non_nan_values_are_rounded <- all(is.na(diff_values) | diff_values == 0)
+    expect_true(all_non_nan_values_are_rounded)
+  })
+
+  it("adds appropriate labels to columns (CDISC PPTEST)", {
+    labels <- formatters::var_labels(pivoted_res)
+    expected_labels <- c(
+      USUBJID = NA, PARAM = NA, start = NA, end = NA, DOSNO = NA, AFRLT = NA, ARRLT = NA,
+      NFRLT = NA, NRRLT = NA, ROUTE = NA, ADOSE = NA, DRUG = NA, ADOSEDUR = NA,
+      `AUCLST[hr*ng/mL]` = "AUC to Last Nonzero Conc",
+      `CMAX[ng/mL]` = "Max Conc",
+      `TMAX[hr]` = "Time of CMAX",
+      `TLST[hr]` = "Time of Last Nonzero Conc",
+      `CLST[ng/mL]` = "Last Nonzero Conc",
+      `LAMZ[1/hr]` = "Lambda z",
+      `R2` = "R Squared",
+      `R2ADJ` = "R Squared Adjusted",
+      `LAMZLL[hr]` = "Lambda z Lower Limit",
+      `LAMZNPT[count]` = "Number of Points for Lambda z",
+      `CLSTP[ng/mL]` = "Clast pred",
+      `LAMZHL[hr]` = "Half-Life Lambda z",
+      `LAMZSPN` = "Lambda z Span",
+      `AUCIFO[hr*ng/mL]` = "AUC Infinity Obs",
+      `AUCINT_0-2[hr*ng/mL]` = "AUC from T1 to T2",
+      `AUCINT_2-4[hr*ng/mL]` = "AUC from T1 to T2",
+      `LAMZIX` = NA, `LAMZMTD` = NA, `Exclude` = NA
+    )
+    expect_equal(labels, expected_labels)
+  })
+
+  it("handles exclude values correctly", {
+    # Modify FIXTURE_PKNCA_RES$result to include exclude values
+    res_with_exclude <- FIXTURE_PKNCA_RES
+    res_with_exclude$result <- res_with_exclude$result %>%
+      mutate(
+        exclude = ifelse(USUBJID == 1 & DOSNO == 1, "Reason 1; Reason 2", NA_character_)
+      )
+
+    # Apply pivot_wider_pknca_results
+    result <- pivot_wider_pknca_results(res_with_exclude)
+
+    # Check that the Exclude column combines and deduplicates exclude values
+    exclude_values <- result %>% filter(USUBJID == 1 & DOSNO == 1) %>% pull(Exclude)
+    expect_equal(exclude_values, "Reason 1, Reason 2")
+
+    # Check that rows without exclude values have NA in the Exclude column
+    exclude_values_na <- result %>% filter(USUBJID == 2 & DOSNO == 2) %>% pull(Exclude)
+    expect_true(all(is.na(exclude_values_na)))
+  })
+})


Reviews:
user: login: js3110
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-14T11:13:54Z
user: login: m-kolomanski
body: Hey, the tests generate warnings for me - those seem like an easy fix, I would consider doing that within the scope of this PR.

```R
Using an external vector in selections was deprecated in tidyselect 1.1.0.
i Please use `all_of()` or `any_of()` instead.
```
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-15T15:02:08Z
user: login: Gero1999
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-16T08:51:53Z
user: login: m-kolomanski
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-16T15:00:02Z
user: login: js3110
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-24T12:55:25Z
user: login: Gero1999
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-24T15:19:38Z
user: login: m-kolomanski
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-04-25T06:53:02Z
user: login: Gero1999
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-25T07:57:49Z
user: login: Gero1999
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-25T15:01:21Z
user: login: Gero1999
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-25T16:04:39Z
user: login: m-kolomanski
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T05:51:32Z
user: login: js3110
body: I added some comments :)
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-04-29T08:51:11Z
user: login: js3110
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-02T08:21:48Z
user: login: Gero1999
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-02T08:57:36Z
user: login: m-kolomanski
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-05T06:46:29Z
user: login: js3110
body: lgtm :)
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-05T11:48:38Z
user: login: m-kolomanski
body: Thank you for the changes, the setup and the tests look great!
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-07T05:58:12Z

Review comments:
diff_hunk: @@ -6,7 +6,15 @@
 #' each column name corresponds with a calculated parameter and between brackets its
 #' corresponding units. AUC intervals, if present, are be added as additional columns.
 #'
-#' @param myres The output of PKNCA::pk.nca
+#' @param myres The output of PKNCA::pk.nca. It makes some additional assumptions:
+#'   1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#'   2) Intervals must include a column (`type_interval`) to differentiate between the
+#'   custom AUC ranges ("manual") and main parameter calculations ("main").
+#'   3) Includes `PPSTRES` and `PPSTRESU` variables in results dataset.
+#'   4) Columns `start_dose` and `end_dose` must express the actual start and end times
path: R/pivot_wider_pknca_results.R
user: login: js3110
body: `start_dose` and `end_dose` are the start and end time relative to the most recent dose, whereas `start` and `end` are the times relative to the first dose
created_at: 2025-04-14T11:10:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,200 @@
+# Create PKNCA results object from 0 with sample concentration and dose datasets
+# Additional conditions to PKNCA assumptions need to be made:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT)
+# 2) For the intervals create a column (type_interval) that differentiates between
+# custom AUC ranges ("manual") and main parameter calculations ("main")
+# 3) There are PPSTRES and PPSTRESU variables in the PKNCA results output
+# 4) start_dose & end_dose columns expressing when the actual start and actual end
+# of the dose happened. The time reference is the first dose given to the subject.
+# 5) CDISC denomination of PK parameters (needed temporarily to derive LAMZNPT & LAMZMTD)
+conc_data <- data.frame(
+  ID = rep(1:2, each = 10), # Adjusted for 5 points per ID/DOSNO combination
+  DOSNO = rep(rep(1:2, each = 5), 2),
+  AFRLT = rep(1:10, 2),
+  ARRLT = rep(1:5, 4),
+  NFRLT = rep(1:10, 2),
+  NRRLT = rep(1:5, 4),
+  AVAL = c(c(10, 8, 6, 4, 2),
+           c(10, 8, 6, 4, 2),
+           c(100, 80, 60, 40, 20),
+           c(100, 80, 60, 40, 20)),
+  # Function assumes these custom additional columns are present
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE
+)
+
+dose_data <- data.frame(
+  ID = rep(1:2, each = 2),
+  DOSNO = rep(1:2, 2),
+  AFRLT = rep(c(0, 5), 2), # Aligned with conc_data AFRLT start and end times
+  ARRLT = rep(0, 4),
+  NFRLT = rep(c(0, 5), 2), # Aligned with conc_data NFRLT start and end times
+  NRRLT = rep(0, 4),
+  DOSE = c(rep(10, 2), rep(100, 2))
+)
+
+# Perform NCA analysis
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = TRUE,
+  cmax = TRUE,
+  aucint.last = FALSE,
+  type_interval = "main",
+  DOSNO = c(1, 2)
+)
+auc_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = FALSE,
+  cmax = FALSE,
+  aucint.last = TRUE,
+  type_interval = "manual",
+  DOSNO = c(1, 2)
+)
+options <- PKNCA::PKNCA.options()
+options$keep_interval_cols <- c("DOSNO", "type_interval")
+
+myres <- PKNCA::pk.nca(
+  PKNCA::PKNCAdata(
+    data.conc = PKNCA::PKNCAconc(conc_data, AVAL ~ AFRLT | ID),
+    data.dose = PKNCA::PKNCAdose(dose_data, DOSE ~ AFRLT | ID),
+    intervals = rbind(
+      main_intervals,
+      auc_intervals
+    ),
+    options = options,
+    units = PKNCA::pknca_units_table(
+      concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+    )
+  )
+)
+# Make preparations done by PKNCA_calculate_nca
+dose_data_to_join <- select(
+  myres$data$dose$data,
+  -exclude,
+  -myres$data$dose$data$conc$columns$groups$group_analyte
+)
+myres$result <- myres$result %>%
+  # Function assumes dose time information is added to PKNCA results
+  inner_join(
+    dose_data_to_join,
+    by = intersect(names(.), names(dose_data_to_join))
+  ) %>%
+  # Function assumes start_dose, end_dose, PPSTRES, PPSTRESU
+  mutate(
+    start_dose = start - !!sym(myres$data$dose$columns$time),
+    end_dose = end - !!sym(myres$data$dose$columns$time),
+    PPSTRESU = PPORRESU,
+    PPSTRES = PPORRES,
+    # Function assumes PPTESTCD is following CDISC standards
+    PPTESTCD = translate_terms(PPTESTCD, "PKNCA", "PPTESTCD")
+  )
+
+describe("pivot_wider_pknca_results", {
+
+  it("produces a data.frame when only reshaping main intervals", {
+    myres_only_main <- myres
+    myres_only_main$result <- myres$result  %>%
+      filter(type_interval == "main")
+    result <- pivot_wider_pknca_results(myres_only_main)
+    expect_s3_class(result, "data.frame")
+  })
+
+  it("reshapes PKNCA results correctly when also considering AUC intervals", {
+    # Apply pivot_wider_pknca_results
+    result <- pivot_wider_pknca_results(myres)
+
+    # Check that the result is a data frame
+    expect_s3_class(result, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "ID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "DOSE", "route", "duration",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2[unitless]", "R2ADJ[unitless]", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN[fraction]", "AUCINT_0-5", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(result)))
+
+    # Check that the result contains expected values for a few key columns
+    id_and_dosnos <- result  %>%
+      select(ID, DOSNO) %>%
+      distinct()
+    for (i in seq_len(nrow(id_and_dosnos))) {
+      id <- id_and_dosnos$ID[i]
+      dosno <- id_and_dosnos$DOSNO[i]
+
+      # Make a loop of the different id and dosno to check if the results are the expected
+      sub_conc_data <- conc_data  %>%
+        filter(ID == id, DOSNO == dosno)
+
+      actual_result <- result %>%
+        filter(ID == id, DOSNO == dosno) %>%
+        formatters::var_labels_remove()
+
+      expect_equal(actual_result[["CMAX[ng/mL]"]], max(sub_conc_data$AVAL))
+      expect_equal(actual_result[["TMAX[hr]"]], sub_conc_data$ARRLT[which.max(sub_conc_data$AVAL)])
+      expect_equal(actual_result[["LAMZ[1/hr]"]],
+                   PKNCA::pk.calc.half.life(sub_conc_data$AVAL, sub_conc_data$AFRLT)$lambda.z,
+                   tolerance = 1e-3)
+    }
+  })
+
+  it("handles manual AUC intervals correctly", {
+    # Check if manual AUC intervals are included
+    result <- pivot_wider_pknca_results(myres)
+    manual_auc_columns <- grep("^AUCINT_", colnames(result), value = TRUE)
+    expect_true(length(manual_auc_columns) > 0)
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: question: Are we able to check the exact length here based on testing data, instead of just checking if there are _any_ results?
created_at: 2025-04-15T14:50:35Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,200 @@
+# Create PKNCA results object from 0 with sample concentration and dose datasets
+# Additional conditions to PKNCA assumptions need to be made:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT)
+# 2) For the intervals create a column (type_interval) that differentiates between
+# custom AUC ranges ("manual") and main parameter calculations ("main")
+# 3) There are PPSTRES and PPSTRESU variables in the PKNCA results output
+# 4) start_dose & end_dose columns expressing when the actual start and actual end
+# of the dose happened. The time reference is the first dose given to the subject.
+# 5) CDISC denomination of PK parameters (needed temporarily to derive LAMZNPT & LAMZMTD)
+conc_data <- data.frame(
+  ID = rep(1:2, each = 10), # Adjusted for 5 points per ID/DOSNO combination
+  DOSNO = rep(rep(1:2, each = 5), 2),
+  AFRLT = rep(1:10, 2),
+  ARRLT = rep(1:5, 4),
+  NFRLT = rep(1:10, 2),
+  NRRLT = rep(1:5, 4),
+  AVAL = c(c(10, 8, 6, 4, 2),
+           c(10, 8, 6, 4, 2),
+           c(100, 80, 60, 40, 20),
+           c(100, 80, 60, 40, 20)),
+  # Function assumes these custom additional columns are present
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE
+)
+
+dose_data <- data.frame(
+  ID = rep(1:2, each = 2),
+  DOSNO = rep(1:2, 2),
+  AFRLT = rep(c(0, 5), 2), # Aligned with conc_data AFRLT start and end times
+  ARRLT = rep(0, 4),
+  NFRLT = rep(c(0, 5), 2), # Aligned with conc_data NFRLT start and end times
+  NRRLT = rep(0, 4),
+  DOSE = c(rep(10, 2), rep(100, 2))
+)
+
+# Perform NCA analysis
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = TRUE,
+  cmax = TRUE,
+  aucint.last = FALSE,
+  type_interval = "main",
+  DOSNO = c(1, 2)
+)
+auc_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = FALSE,
+  cmax = FALSE,
+  aucint.last = TRUE,
+  type_interval = "manual",
+  DOSNO = c(1, 2)
+)
+options <- PKNCA::PKNCA.options()
+options$keep_interval_cols <- c("DOSNO", "type_interval")
+
+myres <- PKNCA::pk.nca(
+  PKNCA::PKNCAdata(
+    data.conc = PKNCA::PKNCAconc(conc_data, AVAL ~ AFRLT | ID),
+    data.dose = PKNCA::PKNCAdose(dose_data, DOSE ~ AFRLT | ID),
+    intervals = rbind(
+      main_intervals,
+      auc_intervals
+    ),
+    options = options,
+    units = PKNCA::pknca_units_table(
+      concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+    )
+  )
+)
+# Make preparations done by PKNCA_calculate_nca
+dose_data_to_join <- select(
+  myres$data$dose$data,
+  -exclude,
+  -myres$data$dose$data$conc$columns$groups$group_analyte
+)
+myres$result <- myres$result %>%
+  # Function assumes dose time information is added to PKNCA results
+  inner_join(
+    dose_data_to_join,
+    by = intersect(names(.), names(dose_data_to_join))
+  ) %>%
+  # Function assumes start_dose, end_dose, PPSTRES, PPSTRESU
+  mutate(
+    start_dose = start - !!sym(myres$data$dose$columns$time),
+    end_dose = end - !!sym(myres$data$dose$columns$time),
+    PPSTRESU = PPORRESU,
+    PPSTRES = PPORRES,
+    # Function assumes PPTESTCD is following CDISC standards
+    PPTESTCD = translate_terms(PPTESTCD, "PKNCA", "PPTESTCD")
+  )
+
+describe("pivot_wider_pknca_results", {
+
+  it("produces a data.frame when only reshaping main intervals", {
+    myres_only_main <- myres
+    myres_only_main$result <- myres$result  %>%
+      filter(type_interval == "main")
+    result <- pivot_wider_pknca_results(myres_only_main)
+    expect_s3_class(result, "data.frame")
+  })
+
+  it("reshapes PKNCA results correctly when also considering AUC intervals", {
+    # Apply pivot_wider_pknca_results
+    result <- pivot_wider_pknca_results(myres)
+
+    # Check that the result is a data frame
+    expect_s3_class(result, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "ID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "DOSE", "route", "duration",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2[unitless]", "R2ADJ[unitless]", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN[fraction]", "AUCINT_0-5", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(result)))
+
+    # Check that the result contains expected values for a few key columns
+    id_and_dosnos <- result  %>%
+      select(ID, DOSNO) %>%
+      distinct()
+    for (i in seq_len(nrow(id_and_dosnos))) {
+      id <- id_and_dosnos$ID[i]
+      dosno <- id_and_dosnos$DOSNO[i]
+
+      # Make a loop of the different id and dosno to check if the results are the expected
+      sub_conc_data <- conc_data  %>%
+        filter(ID == id, DOSNO == dosno)
+
+      actual_result <- result %>%
+        filter(ID == id, DOSNO == dosno) %>%
+        formatters::var_labels_remove()
+
+      expect_equal(actual_result[["CMAX[ng/mL]"]], max(sub_conc_data$AVAL))
+      expect_equal(actual_result[["TMAX[hr]"]], sub_conc_data$ARRLT[which.max(sub_conc_data$AVAL)])
+      expect_equal(actual_result[["LAMZ[1/hr]"]],
+                   PKNCA::pk.calc.half.life(sub_conc_data$AVAL, sub_conc_data$AFRLT)$lambda.z,
+                   tolerance = 1e-3)
+    }
+  })
+
+  it("handles manual AUC intervals correctly", {
+    # Check if manual AUC intervals are included
+    result <- pivot_wider_pknca_results(myres)
+    manual_auc_columns <- grep("^AUCINT_", colnames(result), value = TRUE)
+    expect_true(length(manual_auc_columns) > 0)
+  })
+
+  it("rounds numeric values to three decimals", {
+    result <- pivot_wider_pknca_results(myres)
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: nitpick: We are generating the same results over and over - we could set this up within `describe()` and then reuse:
```R
describe("pivot_wider_pknca_results", {
  result <- pivot_wider_pknca_results(myres)
  ...
}
```
just make sure that in a case we are generating results specific to a given test (like with main intervals) the variable names do not overlap.
created_at: 2025-04-15T14:53:19Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,200 @@
+# Create PKNCA results object from 0 with sample concentration and dose datasets
+# Additional conditions to PKNCA assumptions need to be made:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT)
+# 2) For the intervals create a column (type_interval) that differentiates between
+# custom AUC ranges ("manual") and main parameter calculations ("main")
+# 3) There are PPSTRES and PPSTRESU variables in the PKNCA results output
+# 4) start_dose & end_dose columns expressing when the actual start and actual end
+# of the dose happened. The time reference is the first dose given to the subject.
+# 5) CDISC denomination of PK parameters (needed temporarily to derive LAMZNPT & LAMZMTD)
+conc_data <- data.frame(
+  ID = rep(1:2, each = 10), # Adjusted for 5 points per ID/DOSNO combination
+  DOSNO = rep(rep(1:2, each = 5), 2),
+  AFRLT = rep(1:10, 2),
+  ARRLT = rep(1:5, 4),
+  NFRLT = rep(1:10, 2),
+  NRRLT = rep(1:5, 4),
+  AVAL = c(c(10, 8, 6, 4, 2),
+           c(10, 8, 6, 4, 2),
+           c(100, 80, 60, 40, 20),
+           c(100, 80, 60, 40, 20)),
+  # Function assumes these custom additional columns are present
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE
+)
+
+dose_data <- data.frame(
+  ID = rep(1:2, each = 2),
+  DOSNO = rep(1:2, 2),
+  AFRLT = rep(c(0, 5), 2), # Aligned with conc_data AFRLT start and end times
+  ARRLT = rep(0, 4),
+  NFRLT = rep(c(0, 5), 2), # Aligned with conc_data NFRLT start and end times
+  NRRLT = rep(0, 4),
+  DOSE = c(rep(10, 2), rep(100, 2))
+)
+
+# Perform NCA analysis
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = TRUE,
+  cmax = TRUE,
+  aucint.last = FALSE,
+  type_interval = "main",
+  DOSNO = c(1, 2)
+)
+auc_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = FALSE,
+  cmax = FALSE,
+  aucint.last = TRUE,
+  type_interval = "manual",
+  DOSNO = c(1, 2)
+)
+options <- PKNCA::PKNCA.options()
+options$keep_interval_cols <- c("DOSNO", "type_interval")
+
+myres <- PKNCA::pk.nca(
+  PKNCA::PKNCAdata(
+    data.conc = PKNCA::PKNCAconc(conc_data, AVAL ~ AFRLT | ID),
+    data.dose = PKNCA::PKNCAdose(dose_data, DOSE ~ AFRLT | ID),
+    intervals = rbind(
+      main_intervals,
+      auc_intervals
+    ),
+    options = options,
+    units = PKNCA::pknca_units_table(
+      concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+    )
+  )
+)
+# Make preparations done by PKNCA_calculate_nca
+dose_data_to_join <- select(
+  myres$data$dose$data,
+  -exclude,
+  -myres$data$dose$data$conc$columns$groups$group_analyte
+)
+myres$result <- myres$result %>%
+  # Function assumes dose time information is added to PKNCA results
+  inner_join(
+    dose_data_to_join,
+    by = intersect(names(.), names(dose_data_to_join))
+  ) %>%
+  # Function assumes start_dose, end_dose, PPSTRES, PPSTRESU
+  mutate(
+    start_dose = start - !!sym(myres$data$dose$columns$time),
+    end_dose = end - !!sym(myres$data$dose$columns$time),
+    PPSTRESU = PPORRESU,
+    PPSTRES = PPORRES,
+    # Function assumes PPTESTCD is following CDISC standards
+    PPTESTCD = translate_terms(PPTESTCD, "PKNCA", "PPTESTCD")
+  )
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: question: Are we able to re-use the dummy data that we are creating in `setup.R`?  If not, is there a way we could adjust the dummy data so that it works for multiple tests?
created_at: 2025-04-15T14:55:37Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,200 @@
+# Create PKNCA results object from 0 with sample concentration and dose datasets
+# Additional conditions to PKNCA assumptions need to be made:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT)
+# 2) For the intervals create a column (type_interval) that differentiates between
+# custom AUC ranges ("manual") and main parameter calculations ("main")
+# 3) There are PPSTRES and PPSTRESU variables in the PKNCA results output
+# 4) start_dose & end_dose columns expressing when the actual start and actual end
+# of the dose happened. The time reference is the first dose given to the subject.
+# 5) CDISC denomination of PK parameters (needed temporarily to derive LAMZNPT & LAMZMTD)
+conc_data <- data.frame(
+  ID = rep(1:2, each = 10), # Adjusted for 5 points per ID/DOSNO combination
+  DOSNO = rep(rep(1:2, each = 5), 2),
+  AFRLT = rep(1:10, 2),
+  ARRLT = rep(1:5, 4),
+  NFRLT = rep(1:10, 2),
+  NRRLT = rep(1:5, 4),
+  AVAL = c(c(10, 8, 6, 4, 2),
+           c(10, 8, 6, 4, 2),
+           c(100, 80, 60, 40, 20),
+           c(100, 80, 60, 40, 20)),
+  # Function assumes these custom additional columns are present
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE
+)
+
+dose_data <- data.frame(
+  ID = rep(1:2, each = 2),
+  DOSNO = rep(1:2, 2),
+  AFRLT = rep(c(0, 5), 2), # Aligned with conc_data AFRLT start and end times
+  ARRLT = rep(0, 4),
+  NFRLT = rep(c(0, 5), 2), # Aligned with conc_data NFRLT start and end times
+  NRRLT = rep(0, 4),
+  DOSE = c(rep(10, 2), rep(100, 2))
+)
+
+# Perform NCA analysis
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = TRUE,
+  cmax = TRUE,
+  aucint.last = FALSE,
+  type_interval = "main",
+  DOSNO = c(1, 2)
+)
+auc_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = FALSE,
+  cmax = FALSE,
+  aucint.last = TRUE,
+  type_interval = "manual",
+  DOSNO = c(1, 2)
+)
+options <- PKNCA::PKNCA.options()
+options$keep_interval_cols <- c("DOSNO", "type_interval")
+
+myres <- PKNCA::pk.nca(
+  PKNCA::PKNCAdata(
+    data.conc = PKNCA::PKNCAconc(conc_data, AVAL ~ AFRLT | ID),
+    data.dose = PKNCA::PKNCAdose(dose_data, DOSE ~ AFRLT | ID),
+    intervals = rbind(
+      main_intervals,
+      auc_intervals
+    ),
+    options = options,
+    units = PKNCA::pknca_units_table(
+      concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+    )
+  )
+)
+# Make preparations done by PKNCA_calculate_nca
+dose_data_to_join <- select(
+  myres$data$dose$data,
+  -exclude,
+  -myres$data$dose$data$conc$columns$groups$group_analyte
+)
+myres$result <- myres$result %>%
+  # Function assumes dose time information is added to PKNCA results
+  inner_join(
+    dose_data_to_join,
+    by = intersect(names(.), names(dose_data_to_join))
+  ) %>%
+  # Function assumes start_dose, end_dose, PPSTRES, PPSTRESU
+  mutate(
+    start_dose = start - !!sym(myres$data$dose$columns$time),
+    end_dose = end - !!sym(myres$data$dose$columns$time),
+    PPSTRESU = PPORRESU,
+    PPSTRES = PPORRES,
+    # Function assumes PPTESTCD is following CDISC standards
+    PPTESTCD = translate_terms(PPTESTCD, "PKNCA", "PPTESTCD")
+  )
+
+describe("pivot_wider_pknca_results", {
+
+  it("produces a data.frame when only reshaping main intervals", {
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: issue/question: Can we check if the result is valid, apart from just checking the class? For all we know, the function might return empty table and this would pass. Can we check the number of rows or some key specific values?
created_at: 2025-04-15T14:57:10Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,200 @@
+# Create PKNCA results object from 0 with sample concentration and dose datasets
+# Additional conditions to PKNCA assumptions need to be made:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT)
+# 2) For the intervals create a column (type_interval) that differentiates between
+# custom AUC ranges ("manual") and main parameter calculations ("main")
+# 3) There are PPSTRES and PPSTRESU variables in the PKNCA results output
+# 4) start_dose & end_dose columns expressing when the actual start and actual end
+# of the dose happened. The time reference is the first dose given to the subject.
+# 5) CDISC denomination of PK parameters (needed temporarily to derive LAMZNPT & LAMZMTD)
+conc_data <- data.frame(
+  ID = rep(1:2, each = 10), # Adjusted for 5 points per ID/DOSNO combination
+  DOSNO = rep(rep(1:2, each = 5), 2),
+  AFRLT = rep(1:10, 2),
+  ARRLT = rep(1:5, 4),
+  NFRLT = rep(1:10, 2),
+  NRRLT = rep(1:5, 4),
+  AVAL = c(c(10, 8, 6, 4, 2),
+           c(10, 8, 6, 4, 2),
+           c(100, 80, 60, 40, 20),
+           c(100, 80, 60, 40, 20)),
+  # Function assumes these custom additional columns are present
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE
+)
+
+dose_data <- data.frame(
+  ID = rep(1:2, each = 2),
+  DOSNO = rep(1:2, 2),
+  AFRLT = rep(c(0, 5), 2), # Aligned with conc_data AFRLT start and end times
+  ARRLT = rep(0, 4),
+  NFRLT = rep(c(0, 5), 2), # Aligned with conc_data NFRLT start and end times
+  NRRLT = rep(0, 4),
+  DOSE = c(rep(10, 2), rep(100, 2))
+)
+
+# Perform NCA analysis
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = TRUE,
+  cmax = TRUE,
+  aucint.last = FALSE,
+  type_interval = "main",
+  DOSNO = c(1, 2)
+)
+auc_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = FALSE,
+  cmax = FALSE,
+  aucint.last = TRUE,
+  type_interval = "manual",
+  DOSNO = c(1, 2)
+)
+options <- PKNCA::PKNCA.options()
+options$keep_interval_cols <- c("DOSNO", "type_interval")
+
+myres <- PKNCA::pk.nca(
+  PKNCA::PKNCAdata(
+    data.conc = PKNCA::PKNCAconc(conc_data, AVAL ~ AFRLT | ID),
+    data.dose = PKNCA::PKNCAdose(dose_data, DOSE ~ AFRLT | ID),
+    intervals = rbind(
+      main_intervals,
+      auc_intervals
+    ),
+    options = options,
+    units = PKNCA::pknca_units_table(
+      concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+    )
+  )
+)
+# Make preparations done by PKNCA_calculate_nca
+dose_data_to_join <- select(
+  myres$data$dose$data,
+  -exclude,
+  -myres$data$dose$data$conc$columns$groups$group_analyte
+)
+myres$result <- myres$result %>%
+  # Function assumes dose time information is added to PKNCA results
+  inner_join(
+    dose_data_to_join,
+    by = intersect(names(.), names(dose_data_to_join))
+  ) %>%
+  # Function assumes start_dose, end_dose, PPSTRES, PPSTRESU
+  mutate(
+    start_dose = start - !!sym(myres$data$dose$columns$time),
+    end_dose = end - !!sym(myres$data$dose$columns$time),
+    PPSTRESU = PPORRESU,
+    PPSTRES = PPORRES,
+    # Function assumes PPTESTCD is following CDISC standards
+    PPTESTCD = translate_terms(PPTESTCD, "PKNCA", "PPTESTCD")
+  )
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: Gero1999
body: @m-kolomanski  Two questions regarding this:

1) The dummy example used in `setup.R` is unfortunately very limited for most tests, but if I edit it maybe here can do the trick. Alternatively, for the matter of other tests perhaps I can make a new one more complex using as reference the one in `test-interval_helpers.R`. Would that work and do you think would be worthy?

2) Should we make this `setup.R` used for all tests dependent on the functions `PKNCA_create_data_object`, `PKNCA_update_data_object`,  `PKNCA_calculate_nca`. Is that ok? 

created_at: 2025-04-16T08:51:53Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,200 @@
+# Create PKNCA results object from 0 with sample concentration and dose datasets
+# Additional conditions to PKNCA assumptions need to be made:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT)
+# 2) For the intervals create a column (type_interval) that differentiates between
+# custom AUC ranges ("manual") and main parameter calculations ("main")
+# 3) There are PPSTRES and PPSTRESU variables in the PKNCA results output
+# 4) start_dose & end_dose columns expressing when the actual start and actual end
+# of the dose happened. The time reference is the first dose given to the subject.
+# 5) CDISC denomination of PK parameters (needed temporarily to derive LAMZNPT & LAMZMTD)
+conc_data <- data.frame(
+  ID = rep(1:2, each = 10), # Adjusted for 5 points per ID/DOSNO combination
+  DOSNO = rep(rep(1:2, each = 5), 2),
+  AFRLT = rep(1:10, 2),
+  ARRLT = rep(1:5, 4),
+  NFRLT = rep(1:10, 2),
+  NRRLT = rep(1:5, 4),
+  AVAL = c(c(10, 8, 6, 4, 2),
+           c(10, 8, 6, 4, 2),
+           c(100, 80, 60, 40, 20),
+           c(100, 80, 60, 40, 20)),
+  # Function assumes these custom additional columns are present
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE
+)
+
+dose_data <- data.frame(
+  ID = rep(1:2, each = 2),
+  DOSNO = rep(1:2, 2),
+  AFRLT = rep(c(0, 5), 2), # Aligned with conc_data AFRLT start and end times
+  ARRLT = rep(0, 4),
+  NFRLT = rep(c(0, 5), 2), # Aligned with conc_data NFRLT start and end times
+  NRRLT = rep(0, 4),
+  DOSE = c(rep(10, 2), rep(100, 2))
+)
+
+# Perform NCA analysis
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = TRUE,
+  cmax = TRUE,
+  aucint.last = FALSE,
+  type_interval = "main",
+  DOSNO = c(1, 2)
+)
+auc_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  half.life = FALSE,
+  cmax = FALSE,
+  aucint.last = TRUE,
+  type_interval = "manual",
+  DOSNO = c(1, 2)
+)
+options <- PKNCA::PKNCA.options()
+options$keep_interval_cols <- c("DOSNO", "type_interval")
+
+myres <- PKNCA::pk.nca(
+  PKNCA::PKNCAdata(
+    data.conc = PKNCA::PKNCAconc(conc_data, AVAL ~ AFRLT | ID),
+    data.dose = PKNCA::PKNCAdose(dose_data, DOSE ~ AFRLT | ID),
+    intervals = rbind(
+      main_intervals,
+      auc_intervals
+    ),
+    options = options,
+    units = PKNCA::pknca_units_table(
+      concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+    )
+  )
+)
+# Make preparations done by PKNCA_calculate_nca
+dose_data_to_join <- select(
+  myres$data$dose$data,
+  -exclude,
+  -myres$data$dose$data$conc$columns$groups$group_analyte
+)
+myres$result <- myres$result %>%
+  # Function assumes dose time information is added to PKNCA results
+  inner_join(
+    dose_data_to_join,
+    by = intersect(names(.), names(dose_data_to_join))
+  ) %>%
+  # Function assumes start_dose, end_dose, PPSTRES, PPSTRESU
+  mutate(
+    start_dose = start - !!sym(myres$data$dose$columns$time),
+    end_dose = end - !!sym(myres$data$dose$columns$time),
+    PPSTRESU = PPORRESU,
+    PPSTRES = PPORRES,
+    # Function assumes PPTESTCD is following CDISC standards
+    PPTESTCD = translate_terms(PPTESTCD, "PKNCA", "PPTESTCD")
+  )
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: 2 is a very good point that I have completely overlooked - we should not rely on functions in the package to create testing data for the package. In the testing pipeline, `setup.R` is run first, technically we have not tested those functions yet, so they might generate invalid results, which will then to incorrect tests. Thank you for bringing this up.

This setup will need to be reworked.

Creating global testing object would be optimal, but if we require a lot of customizations between tests, then it makes sense to go the bespoke route and setup the data before every test, so we have greater control over it.
created_at: 2025-04-16T15:00:02Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,312 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
path: tests/testthat/setup_testing_data.R
user: login: js3110
body: Question: why can we not use the dummy data already in the test/setup.R file?

Also would be good to have both in the same file to avoid confusion of having two setup files
created_at: 2025-04-24T12:55:25Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,312 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
path: tests/testthat/setup_testing_data.R
user: login: Gero1999
body: just to produce a testing dataset that covers a variety of PKNCA data scenarios and is independent from other aNCA functions
created_at: 2025-04-24T15:19:38Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,312 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
path: tests/testthat/setup_testing_data.R
user: login: m-kolomanski
body: I agree with @js3110 - we should keep all the pre-testing setup to a single `setup.R` file and consolidate testing data.
created_at: 2025-04-25T06:28:37Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,165 @@
+# Use the testing data to produce results
+pwres <- pivot_wider_pknca_results(TEST_PKNCA_RES)
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: issue: We should not run the tested function outside of the testing suite. I think in this case, we should also test if the output is any valid before going into more detailed tests. It should look something like this:

```R
describe("pivot_wider_pknca_results", {
  pwres <- expect_no_error(pivot_wider_pknca_results(TEST_PKNCA_RES))

  it("produces a data.frame", {
    expect_s3_class(pwres, "data.frame")
  })
  ...
```
created_at: 2025-04-25T06:41:10Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,165 @@
+# Use the testing data to produce results
+pwres <- pivot_wider_pknca_results(TEST_PKNCA_RES)
+
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @return A logical value indicating whether all checks passed.
+#' @export
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: issue: `@returns`
issue: `@export` is not needed, this is not a package function. In addition, this clashes semantically - functions with `.` should be local functions, so by definition not exported anywhere else.
created_at: 2025-04-25T06:43:28Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,165 @@
+# Use the testing data to produce results
+pwres <- pivot_wider_pknca_results(TEST_PKNCA_RES)
+
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @return A logical value indicating whether all checks passed.
+#' @export
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
+
+  # Extract unique parameter names with units
+  names_params <- TEST_PKNCA_RES$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start, "-", end, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- TEST_PKNCA_RES$result %>%
+        filter(start == auc_start,
+               end == auc_end)
+      reshaped_data <- pwres %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- TEST_PKNCA_RES$result
+      reshaped_data <- pwres
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+
+  # If all checks pass, return TRUE
+  TRUE
+}
+
+
+describe("pivot_wider_pknca_results", {
+
+  it("produces a data.frame with expected format when only reshaping main intervals", {
+    res_only_main <- TEST_PKNCA_RES
+    res_only_main$result <- TEST_PKNCA_RES$result  %>%
+      filter(type_interval == "main")
+    pwres_only_main <- pivot_wider_pknca_results(res_only_main)
+    expect_s3_class(pwres_only_main, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres_only_main)))
+
+    # Check number of rows is the expected (each dose has 1 row in the pivoted data)
+    expect_true(nrow(pwres_only_main) == nrow(res_only_main$data$dose$data))
+
+    # Check parameter values match the ones in the PKNCA results object
+    expect_true(.validate_pknca_params(res_only_main, pwres_only_main))
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: issue: Should be more like
```suggestion
    expect_no_error(.validate_pknca_params(res_only_main, pwres_only_main))
```
since if there is an issue, the validate function will throw an error - and this is what we want to have reported. Then the validate function can return whatever (or nothing) and the test will still be as informative. The returned value is not relevant in the context of testing - the errors are.
created_at: 2025-04-25T06:46:46Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,165 @@
+# Use the testing data to produce results
+pwres <- pivot_wider_pknca_results(TEST_PKNCA_RES)
+
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @return A logical value indicating whether all checks passed.
+#' @export
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
+
+  # Extract unique parameter names with units
+  names_params <- TEST_PKNCA_RES$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start, "-", end, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- TEST_PKNCA_RES$result %>%
+        filter(start == auc_start,
+               end == auc_end)
+      reshaped_data <- pwres %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- TEST_PKNCA_RES$result
+      reshaped_data <- pwres
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+
+  # If all checks pass, return TRUE
+  TRUE
+}
+
+
+describe("pivot_wider_pknca_results", {
+
+  it("produces a data.frame with expected format when only reshaping main intervals", {
+    res_only_main <- TEST_PKNCA_RES
+    res_only_main$result <- TEST_PKNCA_RES$result  %>%
+      filter(type_interval == "main")
+    pwres_only_main <- pivot_wider_pknca_results(res_only_main)
+    expect_s3_class(pwres_only_main, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres_only_main)))
+
+    # Check number of rows is the expected (each dose has 1 row in the pivoted data)
+    expect_true(nrow(pwres_only_main) == nrow(res_only_main$data$dose$data))
+
+    # Check parameter values match the ones in the PKNCA results object
+    expect_true(.validate_pknca_params(res_only_main, pwres_only_main))
+  })
+
+  it("reshapes PKNCA results correctly when also considering AUC intervals", {
+    # Check that the result is a data frame
+    expect_s3_class(pwres, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX", "LAMZMTD", "Exclude",
+      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres)))
+
+    expect_true(.validate_pknca_params(TEST_PKNCA_RES, pwres))
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: ```suggestion
    expect_no_error(.validate_pknca_params(TEST_PKNCA_RES, pwres))
```
created_at: 2025-04-25T06:47:04Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,165 @@
+# Use the testing data to produce results
+pwres <- pivot_wider_pknca_results(TEST_PKNCA_RES)
+
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @return A logical value indicating whether all checks passed.
+#' @export
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
+
+  # Extract unique parameter names with units
+  names_params <- TEST_PKNCA_RES$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start, "-", end, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- TEST_PKNCA_RES$result %>%
+        filter(start == auc_start,
+               end == auc_end)
+      reshaped_data <- pwres %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- TEST_PKNCA_RES$result
+      reshaped_data <- pwres
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+
+  # If all checks pass, return TRUE
+  TRUE
+}
+
+
+describe("pivot_wider_pknca_results", {
+
+  it("produces a data.frame with expected format when only reshaping main intervals", {
+    res_only_main <- TEST_PKNCA_RES
+    res_only_main$result <- TEST_PKNCA_RES$result  %>%
+      filter(type_interval == "main")
+    pwres_only_main <- pivot_wider_pknca_results(res_only_main)
+    expect_s3_class(pwres_only_main, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres_only_main)))
+
+    # Check number of rows is the expected (each dose has 1 row in the pivoted data)
+    expect_true(nrow(pwres_only_main) == nrow(res_only_main$data$dose$data))
+
+    # Check parameter values match the ones in the PKNCA results object
+    expect_true(.validate_pknca_params(res_only_main, pwres_only_main))
+  })
+
+  it("reshapes PKNCA results correctly when also considering AUC intervals", {
+    # Check that the result is a data frame
+    expect_s3_class(pwres, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX", "LAMZMTD", "Exclude",
+      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres)))
+
+    expect_true(.validate_pknca_params(TEST_PKNCA_RES, pwres))
+  })
+
+  it("rounds numeric values to three decimals", {
+    expected_num_param_cols <- c(
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]", "LAMZNPT[count]", "LAMZSPN",
+      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]"
+    )
+    rounded_values <- pwres[, expected_num_param_cols]
+    expect_true(all(apply(rounded_values, 2,
+                          function(x) all(na.omit(abs(x - round(x, 3))) < 1e-9))))
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: issue: This should be part of the setup. No need to split the setup in two parts, makes the check itself seem more complicated than it is.

```suggestion
    rounded_values <- pwres[, expected_num_param_cols] |>
      apply(2, function(x) all(na.omit(abs(x - round(x, 3))) < 1e-9))
    expect_true(all(rounded_values))
```
created_at: 2025-04-25T06:49:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,165 @@
+# Use the testing data to produce results
+pwres <- pivot_wider_pknca_results(TEST_PKNCA_RES)
+
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @return A logical value indicating whether all checks passed.
+#' @export
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
+
+  # Extract unique parameter names with units
+  names_params <- TEST_PKNCA_RES$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start, "-", end, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- TEST_PKNCA_RES$result %>%
+        filter(start == auc_start,
+               end == auc_end)
+      reshaped_data <- pwres %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- TEST_PKNCA_RES$result
+      reshaped_data <- pwres
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+
+  # If all checks pass, return TRUE
+  TRUE
+}
+
+
+describe("pivot_wider_pknca_results", {
+
+  it("produces a data.frame with expected format when only reshaping main intervals", {
+    res_only_main <- TEST_PKNCA_RES
+    res_only_main$result <- TEST_PKNCA_RES$result  %>%
+      filter(type_interval == "main")
+    pwres_only_main <- pivot_wider_pknca_results(res_only_main)
+    expect_s3_class(pwres_only_main, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres_only_main)))
+
+    # Check number of rows is the expected (each dose has 1 row in the pivoted data)
+    expect_true(nrow(pwres_only_main) == nrow(res_only_main$data$dose$data))
+
+    # Check parameter values match the ones in the PKNCA results object
+    expect_true(.validate_pknca_params(res_only_main, pwres_only_main))
+  })
+
+  it("reshapes PKNCA results correctly when also considering AUC intervals", {
+    # Check that the result is a data frame
+    expect_s3_class(pwres, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX", "LAMZMTD", "Exclude",
+      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres)))
+
+    expect_true(.validate_pknca_params(TEST_PKNCA_RES, pwres))
+  })
+
+  it("rounds numeric values to three decimals", {
+    expected_num_param_cols <- c(
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]", "LAMZNPT[count]", "LAMZSPN",
+      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]"
+    )
+    rounded_values <- pwres[, expected_num_param_cols]
+    expect_true(all(apply(rounded_values, 2,
+                          function(x) all(na.omit(abs(x - round(x, 3))) < 1e-9))))
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: Gero1999
body: @m-kolomanski  I refactored to this, hopefully looks more clear. Let me know if not!

```
  it("rounds numeric values to three decimals", {
    expected_num_param_cols <- c(
      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
      "R2", "R2ADJ", "LAMZLL[hr]", "LAMZNPT[count]", "LAMZSPN",
      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]"
    )
    actual_values <- pwres[, expected_num_param_cols]
    expected_values <- round(actual_values, 3)
    diff_values <- actual_values - expected_values
    
    all_non_nan_values_are_rounded <- all(is.na(diff_values) | diff_values == 0)
    expect_true(all_non_nan_values_are_rounded)
  })
```
created_at: 2025-04-25T07:57:49Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,312 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
path: tests/testthat/setup_testing_data.R
user: login: Gero1999
body: ok I will work on consolidating this new testing data with the bioavailability tests so we can rely on them for `setup.R`
created_at: 2025-04-25T15:01:21Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,312 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
path: tests/testthat/setup_testing_data.R
user: login: Gero1999
body: @js3110 @m-kolomanski while doing this I found an issue/bug when using the testing data on the `calculate_F()` for `bioavailability.R`. I solved it in the last commit, all tests keep passing and results are the same. I did it in the last commit so let me know if you think would be worthy to open this in a new branch or solve it directly here! 
created_at: 2025-04-25T16:04:39Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,312 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
path: tests/testthat/setup_testing_data.R
user: login: m-kolomanski
body: _Technically_, I think the changes are significant enough that they should be in separate PR, BUT I understand that the work has already been done and it will take time to revert it and create a separate PR, so as long as the changes are described in the PR I am fine with it.
created_at: 2025-04-28T05:51:32Z
author_association: COLLABORATOR
diff_hunk: @@ -88,7 +97,7 @@ pivot_wider_pknca_results <- function(myres) {
       filter(type_interval == "manual", startsWith(PPTESTCD, "AUCINT")) %>%
       mutate(
         interval_name = paste0(
-          signif(start_dose), "-", signif(end_dose),
+          signif(start), "-", signif(end),
path: R/pivot_wider_pknca_results.R
user: login: js3110
body: I would say we should keep this relevant to ref dose, not from first dose
created_at: 2025-04-29T08:47:45Z
author_association: COLLABORATOR
diff_hunk: @@ -1,18 +1,314 @@
-# Import dataset from testthat/data folder
-
-DUMMY_DATA_FIXTURE <- read.csv(testthat::test_path("data", "adnca_dummy_sm_dataset.csv"))
path: tests/testthat/setup.R
user: login: js3110
body: I think its still worth keeping this dummy data, as its more representative of real life data rather than the manual made dataset. We just can remove the processing of it using our functions, and process it manually instead. Not necessarily for this specific PR but its good to keep it for future tests.
created_at: 2025-04-29T08:50:56Z
author_association: COLLABORATOR
diff_hunk: @@ -88,7 +97,7 @@ pivot_wider_pknca_results <- function(myres) {
       filter(type_interval == "manual", startsWith(PPTESTCD, "AUCINT")) %>%
       mutate(
         interval_name = paste0(
-          signif(start_dose), "-", signif(end_dose),
+          signif(start), "-", signif(end),
path: R/pivot_wider_pknca_results.R
user: login: js3110
body: otherwise there will be a separate column for every dose, which doesn't look great and is not so useful for the User. 
created_at: 2025-05-02T08:21:48Z
author_association: COLLABORATOR
diff_hunk: @@ -88,7 +97,7 @@ pivot_wider_pknca_results <- function(myres) {
       filter(type_interval == "manual", startsWith(PPTESTCD, "AUCINT")) %>%
       mutate(
         interval_name = paste0(
-          signif(start_dose), "-", signif(end_dose),
+          signif(start), "-", signif(end),
path: R/pivot_wider_pknca_results.R
user: login: Gero1999
body: ups I agree this should be by reference, thanks for the catch!
created_at: 2025-05-02T08:57:36Z
author_association: COLLABORATOR
diff_hunk: @@ -1,3 +1,320 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
path: tests/testthat/setup.R
user: login: m-kolomanski
body: nitpick: I think a better name would be `CONC_DATA_FIXTURE`.
created_at: 2025-05-05T06:27:45Z
author_association: COLLABORATOR
diff_hunk: @@ -1,3 +1,320 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
+  # Columns that are mapped from the data
+  AVAL = c(                 # USUBJID.DOSNO
+    0:4,                    # 1.1 (Extravascular, linear & sample at dose)
+    c(1, 2, 1.5, 1, 0.5),   # 2.1 (Extravascular eq, with max)
+    c(1, 2, 1.5, 1, 0.5),   # 2.2 (Extravascular eq, 2nd dose)
+    5:1,                    # 3.1 (IV bolus)
+    5:1,                    # 3.2 (IV bolus, 2nd dose)
+    rep(2, 5),              # 4.1 (IV bolus, abnormal profile)
+    c(1, 2.5, 1, 0.7, 0.5), # 5.1 (Infusion)
+    5:1,                    # 6.1 (IV bolus, metabolite)
+    c(1:3, NA, 0.5)         # 7.1 (Extravascular, with NA)
+  ),
+  AFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ARRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NRRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ROUTE = c(
+    rep("extravascular", 5 * 3), # 1.1 - 2.2
+    rep("intravascular", 5 * 6)  # 3.1 - 7.1
+  ),
+  PARAM = c(
+    rep("A", 5 * 7),          # 1.1 - 5.1
+    rep("B", 5 * 1),          # 6.1 (IV bolus, metabolite)
+    rep("A", 5 * 1)           # 7.1 (Extravascular, with NA)
+  ),
+  USUBJID = c(
+    rep(1, 5),
+    rep(2, 5 * 2),
+    rep(3, 5 * 2),
+    rep(4, 5),
+    rep(5, 5),
+    rep(6, 5),
+    rep(7, 5)
+  ),
+  DOSNO = c(
+    rep(1, 5),
+    rep(1:2, each = 5),
+    rep(1:2, each = 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5)
+  ),
+  # Included by aNCA internally
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE,
+  # Units
+  AVALU = "mg/L",
+  RRLTU = "h"
+)
+
+# Create Testing Dose Data
+TEST_DOSE_DATA <- data.frame(
path: tests/testthat/setup.R
user: login: m-kolomanski
body: nitpick: Same as above, `DOSE_DATA_FIXTURE`
created_at: 2025-05-05T06:28:02Z
author_association: COLLABORATOR
diff_hunk: @@ -1,3 +1,320 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
+  # Columns that are mapped from the data
+  AVAL = c(                 # USUBJID.DOSNO
+    0:4,                    # 1.1 (Extravascular, linear & sample at dose)
+    c(1, 2, 1.5, 1, 0.5),   # 2.1 (Extravascular eq, with max)
+    c(1, 2, 1.5, 1, 0.5),   # 2.2 (Extravascular eq, 2nd dose)
+    5:1,                    # 3.1 (IV bolus)
+    5:1,                    # 3.2 (IV bolus, 2nd dose)
+    rep(2, 5),              # 4.1 (IV bolus, abnormal profile)
+    c(1, 2.5, 1, 0.7, 0.5), # 5.1 (Infusion)
+    5:1,                    # 6.1 (IV bolus, metabolite)
+    c(1:3, NA, 0.5)         # 7.1 (Extravascular, with NA)
+  ),
+  AFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ARRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NRRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ROUTE = c(
+    rep("extravascular", 5 * 3), # 1.1 - 2.2
+    rep("intravascular", 5 * 6)  # 3.1 - 7.1
+  ),
+  PARAM = c(
+    rep("A", 5 * 7),          # 1.1 - 5.1
+    rep("B", 5 * 1),          # 6.1 (IV bolus, metabolite)
+    rep("A", 5 * 1)           # 7.1 (Extravascular, with NA)
+  ),
+  USUBJID = c(
+    rep(1, 5),
+    rep(2, 5 * 2),
+    rep(3, 5 * 2),
+    rep(4, 5),
+    rep(5, 5),
+    rep(6, 5),
+    rep(7, 5)
+  ),
+  DOSNO = c(
+    rep(1, 5),
+    rep(1:2, each = 5),
+    rep(1:2, each = 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5)
+  ),
+  # Included by aNCA internally
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE,
+  # Units
+  AVALU = "mg/L",
+  RRLTU = "h"
+)
+
+# Create Testing Dose Data
+TEST_DOSE_DATA <- data.frame(
+  AFRLT = c(
+    0,
+    c(0, 5),
+    c(0, 5),
+    0,
+    0,
+    0,
+    0
+  ),
+  ARRLT = c(
+    0,
+    c(0, 0),
+    c(0, 0),
+    0,
+    0,
+    0,
+    0
+  ),
+  NFRLT = c(
+    0,
+    c(0, 5),
+    c(0, 5),
+    0,
+    0,
+    0,
+    0
+  ),
+  NRRLT = c(
+    0,
+    c(0, 0),
+    c(0, 0),
+    0,
+    0,
+    0,
+    0
+  ),
+  ROUTE = c(
+    rep("extravascular", 3),
+    rep("intravascular", 5),
+    "extravascular"
+  ),
+  ADOSE = 1,
+  DRUG = "A",
+  ADOSEDUR = c(
+    rep(0, 6),
+    1,            # 5.1 (Infusion)
+    0,
+    0
+  ),
+  USUBJID = c(
+    1,
+    rep(2, 2),
+    rep(3, 2),
+    4,
+    5,
+    6,
+    7
+  ),
+  DOSNO = c(
+    1,
+    c(1, 2),
+    c(1, 2),
+    1,
+    1,
+    1,
+    1
+  )
+)
+
+# Perform NCA Analysis
+all_params <- setdiff(names(PKNCA::get.interval.cols()),
+                      c("start", "end"))
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  type_interval = "main",  # Assumption 2: Include type_interval column
+  DOSNO = c(1, 2)
+) %>%
+  left_join(
+    TEST_DOSE_DATA %>%
+      select(USUBJID, DOSNO) %>%
+      unique()
+  )
+main_intervals[, all_params] <- FALSE
+main_intervals <- main_intervals %>%
+  mutate(
+    half.life = TRUE,
+    cmax = TRUE,
+    auclast = TRUE,
+    aucinf.obs = TRUE
+  )
+auc_intervals <- data.frame(
+  # Intervals for AUC_0-2, AUC_2-4 in each dose
+  start = c(0, 2, 5, 7),
+  end = c(2, 4, 7, 9),
+  type_interval = "manual",  # Assumption 2: Include type_interval column
+  DOSNO = c(1, 1, 2, 2)
+) %>%
+  left_join(
+    TEST_DOSE_DATA %>%
+      select(USUBJID, DOSNO) %>%
+      unique(),
+    by = "DOSNO",
+    relationship = "many-to-many"
+  )
+auc_intervals[, all_params] <- FALSE
+auc_intervals <- auc_intervals %>%
+  mutate(
+    aucint.last = TRUE
+  )
+INTERVALS <- rbind(main_intervals, auc_intervals) %>%
path: tests/testthat/setup.R
user: login: m-kolomanski
body: nitpick: Similarly, `INTERVALS_FIXTURE`
created_at: 2025-05-05T06:29:21Z
author_association: COLLABORATOR
diff_hunk: @@ -1,3 +1,320 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
+  # Columns that are mapped from the data
+  AVAL = c(                 # USUBJID.DOSNO
+    0:4,                    # 1.1 (Extravascular, linear & sample at dose)
+    c(1, 2, 1.5, 1, 0.5),   # 2.1 (Extravascular eq, with max)
+    c(1, 2, 1.5, 1, 0.5),   # 2.2 (Extravascular eq, 2nd dose)
+    5:1,                    # 3.1 (IV bolus)
+    5:1,                    # 3.2 (IV bolus, 2nd dose)
+    rep(2, 5),              # 4.1 (IV bolus, abnormal profile)
+    c(1, 2.5, 1, 0.7, 0.5), # 5.1 (Infusion)
+    5:1,                    # 6.1 (IV bolus, metabolite)
+    c(1:3, NA, 0.5)         # 7.1 (Extravascular, with NA)
+  ),
+  AFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ARRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NRRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ROUTE = c(
+    rep("extravascular", 5 * 3), # 1.1 - 2.2
+    rep("intravascular", 5 * 6)  # 3.1 - 7.1
+  ),
+  PARAM = c(
+    rep("A", 5 * 7),          # 1.1 - 5.1
+    rep("B", 5 * 1),          # 6.1 (IV bolus, metabolite)
+    rep("A", 5 * 1)           # 7.1 (Extravascular, with NA)
+  ),
+  USUBJID = c(
+    rep(1, 5),
+    rep(2, 5 * 2),
+    rep(3, 5 * 2),
+    rep(4, 5),
+    rep(5, 5),
+    rep(6, 5),
+    rep(7, 5)
+  ),
+  DOSNO = c(
+    rep(1, 5),
+    rep(1:2, each = 5),
+    rep(1:2, each = 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5)
+  ),
+  # Included by aNCA internally
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE,
+  # Units
+  AVALU = "mg/L",
+  RRLTU = "h"
+)
+
+# Create Testing Dose Data
+TEST_DOSE_DATA <- data.frame(
+  AFRLT = c(
+    0,
+    c(0, 5),
+    c(0, 5),
+    0,
+    0,
+    0,
+    0
+  ),
+  ARRLT = c(
+    0,
+    c(0, 0),
+    c(0, 0),
+    0,
+    0,
+    0,
+    0
+  ),
+  NFRLT = c(
+    0,
+    c(0, 5),
+    c(0, 5),
+    0,
+    0,
+    0,
+    0
+  ),
+  NRRLT = c(
+    0,
+    c(0, 0),
+    c(0, 0),
+    0,
+    0,
+    0,
+    0
+  ),
+  ROUTE = c(
+    rep("extravascular", 3),
+    rep("intravascular", 5),
+    "extravascular"
+  ),
+  ADOSE = 1,
+  DRUG = "A",
+  ADOSEDUR = c(
+    rep(0, 6),
+    1,            # 5.1 (Infusion)
+    0,
+    0
+  ),
+  USUBJID = c(
+    1,
+    rep(2, 2),
+    rep(3, 2),
+    4,
+    5,
+    6,
+    7
+  ),
+  DOSNO = c(
+    1,
+    c(1, 2),
+    c(1, 2),
+    1,
+    1,
+    1,
+    1
+  )
+)
+
+# Perform NCA Analysis
+all_params <- setdiff(names(PKNCA::get.interval.cols()),
+                      c("start", "end"))
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  type_interval = "main",  # Assumption 2: Include type_interval column
+  DOSNO = c(1, 2)
+) %>%
+  left_join(
+    TEST_DOSE_DATA %>%
+      select(USUBJID, DOSNO) %>%
+      unique()
+  )
+main_intervals[, all_params] <- FALSE
+main_intervals <- main_intervals %>%
+  mutate(
+    half.life = TRUE,
+    cmax = TRUE,
+    auclast = TRUE,
+    aucinf.obs = TRUE
+  )
+auc_intervals <- data.frame(
+  # Intervals for AUC_0-2, AUC_2-4 in each dose
+  start = c(0, 2, 5, 7),
+  end = c(2, 4, 7, 9),
+  type_interval = "manual",  # Assumption 2: Include type_interval column
+  DOSNO = c(1, 1, 2, 2)
+) %>%
+  left_join(
+    TEST_DOSE_DATA %>%
+      select(USUBJID, DOSNO) %>%
+      unique(),
+    by = "DOSNO",
+    relationship = "many-to-many"
+  )
+auc_intervals[, all_params] <- FALSE
+auc_intervals <- auc_intervals %>%
+  mutate(
+    aucint.last = TRUE
+  )
+INTERVALS <- rbind(main_intervals, auc_intervals) %>%
+  mutate(impute = case_when(
+    USUBJID == 1 & DOSNO == 1 ~ NA_character_,
+    USUBJID == 2 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 2 & DOSNO == 2 ~ "start_predose",
+    USUBJID == 3 & DOSNO == 1 ~ "start_logslope",
+    USUBJID == 3 & DOSNO == 2 ~ "start_logslope",
+    USUBJID == 4 & DOSNO == 1 ~ "start_c1",
+    USUBJID == 4 & DOSNO == 2 ~ "start_c1",
+    USUBJID == 5 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 5 & DOSNO == 2 ~ "start_conc0",
+    USUBJID == 6 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 6 & DOSNO == 2 ~ "start_conc0",
+    USUBJID == 7 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 7 & DOSNO == 2 ~ "start_conc0",
+    TRUE ~ NA_character_
+  ))
+
+TEST_PKNCA_DATA <- PKNCA::PKNCAdata(
path: tests/testthat/setup.R
user: login: m-kolomanski
body: nitpick: PKNCA_DATA_FIXTURE.
created_at: 2025-05-05T06:29:39Z
author_association: COLLABORATOR
diff_hunk: @@ -1,3 +1,320 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
+  # Columns that are mapped from the data
+  AVAL = c(                 # USUBJID.DOSNO
+    0:4,                    # 1.1 (Extravascular, linear & sample at dose)
+    c(1, 2, 1.5, 1, 0.5),   # 2.1 (Extravascular eq, with max)
+    c(1, 2, 1.5, 1, 0.5),   # 2.2 (Extravascular eq, 2nd dose)
+    5:1,                    # 3.1 (IV bolus)
+    5:1,                    # 3.2 (IV bolus, 2nd dose)
+    rep(2, 5),              # 4.1 (IV bolus, abnormal profile)
+    c(1, 2.5, 1, 0.7, 0.5), # 5.1 (Infusion)
+    5:1,                    # 6.1 (IV bolus, metabolite)
+    c(1:3, NA, 0.5)         # 7.1 (Extravascular, with NA)
+  ),
+  AFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ARRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NRRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ROUTE = c(
+    rep("extravascular", 5 * 3), # 1.1 - 2.2
+    rep("intravascular", 5 * 6)  # 3.1 - 7.1
+  ),
+  PARAM = c(
+    rep("A", 5 * 7),          # 1.1 - 5.1
+    rep("B", 5 * 1),          # 6.1 (IV bolus, metabolite)
+    rep("A", 5 * 1)           # 7.1 (Extravascular, with NA)
+  ),
+  USUBJID = c(
+    rep(1, 5),
+    rep(2, 5 * 2),
+    rep(3, 5 * 2),
+    rep(4, 5),
+    rep(5, 5),
+    rep(6, 5),
+    rep(7, 5)
+  ),
+  DOSNO = c(
+    rep(1, 5),
+    rep(1:2, each = 5),
+    rep(1:2, each = 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5)
+  ),
+  # Included by aNCA internally
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE,
+  # Units
+  AVALU = "mg/L",
+  RRLTU = "h"
+)
+
+# Create Testing Dose Data
+TEST_DOSE_DATA <- data.frame(
+  AFRLT = c(
+    0,
+    c(0, 5),
+    c(0, 5),
+    0,
+    0,
+    0,
+    0
+  ),
+  ARRLT = c(
+    0,
+    c(0, 0),
+    c(0, 0),
+    0,
+    0,
+    0,
+    0
+  ),
+  NFRLT = c(
+    0,
+    c(0, 5),
+    c(0, 5),
+    0,
+    0,
+    0,
+    0
+  ),
+  NRRLT = c(
+    0,
+    c(0, 0),
+    c(0, 0),
+    0,
+    0,
+    0,
+    0
+  ),
+  ROUTE = c(
+    rep("extravascular", 3),
+    rep("intravascular", 5),
+    "extravascular"
+  ),
+  ADOSE = 1,
+  DRUG = "A",
+  ADOSEDUR = c(
+    rep(0, 6),
+    1,            # 5.1 (Infusion)
+    0,
+    0
+  ),
+  USUBJID = c(
+    1,
+    rep(2, 2),
+    rep(3, 2),
+    4,
+    5,
+    6,
+    7
+  ),
+  DOSNO = c(
+    1,
+    c(1, 2),
+    c(1, 2),
+    1,
+    1,
+    1,
+    1
+  )
+)
+
+# Perform NCA Analysis
+all_params <- setdiff(names(PKNCA::get.interval.cols()),
+                      c("start", "end"))
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  type_interval = "main",  # Assumption 2: Include type_interval column
+  DOSNO = c(1, 2)
+) %>%
+  left_join(
+    TEST_DOSE_DATA %>%
+      select(USUBJID, DOSNO) %>%
+      unique()
+  )
+main_intervals[, all_params] <- FALSE
+main_intervals <- main_intervals %>%
+  mutate(
+    half.life = TRUE,
+    cmax = TRUE,
+    auclast = TRUE,
+    aucinf.obs = TRUE
+  )
+auc_intervals <- data.frame(
+  # Intervals for AUC_0-2, AUC_2-4 in each dose
+  start = c(0, 2, 5, 7),
+  end = c(2, 4, 7, 9),
+  type_interval = "manual",  # Assumption 2: Include type_interval column
+  DOSNO = c(1, 1, 2, 2)
+) %>%
+  left_join(
+    TEST_DOSE_DATA %>%
+      select(USUBJID, DOSNO) %>%
+      unique(),
+    by = "DOSNO",
+    relationship = "many-to-many"
+  )
+auc_intervals[, all_params] <- FALSE
+auc_intervals <- auc_intervals %>%
+  mutate(
+    aucint.last = TRUE
+  )
+INTERVALS <- rbind(main_intervals, auc_intervals) %>%
+  mutate(impute = case_when(
+    USUBJID == 1 & DOSNO == 1 ~ NA_character_,
+    USUBJID == 2 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 2 & DOSNO == 2 ~ "start_predose",
+    USUBJID == 3 & DOSNO == 1 ~ "start_logslope",
+    USUBJID == 3 & DOSNO == 2 ~ "start_logslope",
+    USUBJID == 4 & DOSNO == 1 ~ "start_c1",
+    USUBJID == 4 & DOSNO == 2 ~ "start_c1",
+    USUBJID == 5 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 5 & DOSNO == 2 ~ "start_conc0",
+    USUBJID == 6 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 6 & DOSNO == 2 ~ "start_conc0",
+    USUBJID == 7 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 7 & DOSNO == 2 ~ "start_conc0",
+    TRUE ~ NA_character_
+  ))
+
+TEST_PKNCA_DATA <- PKNCA::PKNCAdata(
+  data.conc = PKNCA::PKNCAconc(TEST_CONC_DATA, AVAL ~ AFRLT | USUBJID / PARAM),
+  data.dose = PKNCA::PKNCAdose(TEST_DOSE_DATA, ADOSE ~ AFRLT | USUBJID,
+                               route = "ROUTE", duration = "ADOSEDUR",
+                               time.nominal = "NFRLT"),
+  units = PKNCA::pknca_units_table(
+    concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+  )
+)
+TEST_PKNCA_DATA$intervals <- INTERVALS
+TEST_PKNCA_DATA$options <- list(keep_interval_cols = c("DOSNO", "type_interval"))
+
+# Add start_dose and end_dose columns
+TEST_PKNCA_RES <- withCallingHandlers(
path: tests/testthat/setup.R
user: login: m-kolomanski
body: nitpick: `PKNCA_RES_FIXTURE`
created_at: 2025-05-05T06:30:13Z
author_association: COLLABORATOR
diff_hunk: @@ -1,3 +1,320 @@
+# Global Testing Data for aNCA Package
+# ------------------------------------
+# This file creates global testing datasets that can be used across all testthat tests.
+# Developers can either:
+# 1) Modify this file to add new cases as new lines in TEST_CONC_DATA & TEST_DOSE_DATA.
+# 2) Modify the testing file directly there, to derive the PKNCA objects for particular cases.
+#
+# The App currently performs certain modification on the PKNCA objects, numbered here:
+# Assumptions and Modifications:
+# 1) CDISC denomination of actual and nominal time variables (AFRLT, ARRLT, NFRLT, NRRLT).
+#    - Relevant for functions that rely on time variables (e.g., interval calculations).
+# 2) Intervals include a column (`type_interval`) differentiating custom AUC ("manual")
+#    and main parameter calculations ("main").
+#    - Relevant for interval-related functions.
+# 3) PKNCA results include `PPSTRES` and `PPSTRESU` variables.
+#    - Ensures compatibility with CDISC standards.
+# 4) `start_dose` and `end_dose` columns express the actual start and end times of the dose,
+#    relative to the first dose given to the subject.
+#    - Used for dose interval calculations.
+# 5) CDISC denomination of PK parameters (e.g., LAMZNPT, LAMZLL, LAMZ).
+#    - Temporarily needed to derive LAMZNPT and LAMZMTD.
+
+# Create Testing Concentration Data
+TEST_CONC_DATA <- data.frame(
+  # Columns that are mapped from the data
+  AVAL = c(                 # USUBJID.DOSNO
+    0:4,                    # 1.1 (Extravascular, linear & sample at dose)
+    c(1, 2, 1.5, 1, 0.5),   # 2.1 (Extravascular eq, with max)
+    c(1, 2, 1.5, 1, 0.5),   # 2.2 (Extravascular eq, 2nd dose)
+    5:1,                    # 3.1 (IV bolus)
+    5:1,                    # 3.2 (IV bolus, 2nd dose)
+    rep(2, 5),              # 4.1 (IV bolus, abnormal profile)
+    c(1, 2.5, 1, 0.7, 0.5), # 5.1 (Infusion)
+    5:1,                    # 6.1 (IV bolus, metabolite)
+    c(1:3, NA, 0.5)         # 7.1 (Extravascular, with NA)
+  ),
+  AFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ARRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NFRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(5.5, 9.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(5.5, 9.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  NRRLT = c(                # Assumption 1: CDISC time variables
+    0:4,                   # 1.1
+    seq(0.5, 4.5, 1),      # 2.1
+    seq(0.5, 4.5, 1),      # 2.2
+    seq(0.5, 4.5, 1),      # 3.1
+    seq(0.5, 4.5, 1),      # 3.2
+    seq(0.5, 4.5, 1),      # 4.1
+    seq(0.5, 4.5, 1),      # 5.1
+    seq(0.5, 4.5, 1),      # 6.1
+    seq(0.5, 4.5, 1)       # 7.1
+  ),
+  ROUTE = c(
+    rep("extravascular", 5 * 3), # 1.1 - 2.2
+    rep("intravascular", 5 * 6)  # 3.1 - 7.1
+  ),
+  PARAM = c(
+    rep("A", 5 * 7),          # 1.1 - 5.1
+    rep("B", 5 * 1),          # 6.1 (IV bolus, metabolite)
+    rep("A", 5 * 1)           # 7.1 (Extravascular, with NA)
+  ),
+  USUBJID = c(
+    rep(1, 5),
+    rep(2, 5 * 2),
+    rep(3, 5 * 2),
+    rep(4, 5),
+    rep(5, 5),
+    rep(6, 5),
+    rep(7, 5)
+  ),
+  DOSNO = c(
+    rep(1, 5),
+    rep(1:2, each = 5),
+    rep(1:2, each = 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5),
+    rep(1, 5)
+  ),
+  # Included by aNCA internally
+  is.excluded.hl = FALSE,
+  is.included.hl = FALSE,
+  exclude_half.life = FALSE,
+  # Units
+  AVALU = "mg/L",
+  RRLTU = "h"
+)
+
+# Create Testing Dose Data
+TEST_DOSE_DATA <- data.frame(
+  AFRLT = c(
+    0,
+    c(0, 5),
+    c(0, 5),
+    0,
+    0,
+    0,
+    0
+  ),
+  ARRLT = c(
+    0,
+    c(0, 0),
+    c(0, 0),
+    0,
+    0,
+    0,
+    0
+  ),
+  NFRLT = c(
+    0,
+    c(0, 5),
+    c(0, 5),
+    0,
+    0,
+    0,
+    0
+  ),
+  NRRLT = c(
+    0,
+    c(0, 0),
+    c(0, 0),
+    0,
+    0,
+    0,
+    0
+  ),
+  ROUTE = c(
+    rep("extravascular", 3),
+    rep("intravascular", 5),
+    "extravascular"
+  ),
+  ADOSE = 1,
+  DRUG = "A",
+  ADOSEDUR = c(
+    rep(0, 6),
+    1,            # 5.1 (Infusion)
+    0,
+    0
+  ),
+  USUBJID = c(
+    1,
+    rep(2, 2),
+    rep(3, 2),
+    4,
+    5,
+    6,
+    7
+  ),
+  DOSNO = c(
+    1,
+    c(1, 2),
+    c(1, 2),
+    1,
+    1,
+    1,
+    1
+  )
+)
+
+# Perform NCA Analysis
+all_params <- setdiff(names(PKNCA::get.interval.cols()),
+                      c("start", "end"))
+main_intervals <- data.frame(
+  start = c(0, 5),
+  end = c(5, 10),
+  type_interval = "main",  # Assumption 2: Include type_interval column
+  DOSNO = c(1, 2)
+) %>%
+  left_join(
+    TEST_DOSE_DATA %>%
+      select(USUBJID, DOSNO) %>%
+      unique()
+  )
+main_intervals[, all_params] <- FALSE
+main_intervals <- main_intervals %>%
+  mutate(
+    half.life = TRUE,
+    cmax = TRUE,
+    auclast = TRUE,
+    aucinf.obs = TRUE
+  )
+auc_intervals <- data.frame(
+  # Intervals for AUC_0-2, AUC_2-4 in each dose
+  start = c(0, 2, 5, 7),
+  end = c(2, 4, 7, 9),
+  type_interval = "manual",  # Assumption 2: Include type_interval column
+  DOSNO = c(1, 1, 2, 2)
+) %>%
+  left_join(
+    TEST_DOSE_DATA %>%
+      select(USUBJID, DOSNO) %>%
+      unique(),
+    by = "DOSNO",
+    relationship = "many-to-many"
+  )
+auc_intervals[, all_params] <- FALSE
+auc_intervals <- auc_intervals %>%
+  mutate(
+    aucint.last = TRUE
+  )
+INTERVALS <- rbind(main_intervals, auc_intervals) %>%
+  mutate(impute = case_when(
+    USUBJID == 1 & DOSNO == 1 ~ NA_character_,
+    USUBJID == 2 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 2 & DOSNO == 2 ~ "start_predose",
+    USUBJID == 3 & DOSNO == 1 ~ "start_logslope",
+    USUBJID == 3 & DOSNO == 2 ~ "start_logslope",
+    USUBJID == 4 & DOSNO == 1 ~ "start_c1",
+    USUBJID == 4 & DOSNO == 2 ~ "start_c1",
+    USUBJID == 5 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 5 & DOSNO == 2 ~ "start_conc0",
+    USUBJID == 6 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 6 & DOSNO == 2 ~ "start_conc0",
+    USUBJID == 7 & DOSNO == 1 ~ "start_conc0",
+    USUBJID == 7 & DOSNO == 2 ~ "start_conc0",
+    TRUE ~ NA_character_
+  ))
+
+TEST_PKNCA_DATA <- PKNCA::PKNCAdata(
+  data.conc = PKNCA::PKNCAconc(TEST_CONC_DATA, AVAL ~ AFRLT | USUBJID / PARAM),
+  data.dose = PKNCA::PKNCAdose(TEST_DOSE_DATA, ADOSE ~ AFRLT | USUBJID,
+                               route = "ROUTE", duration = "ADOSEDUR",
+                               time.nominal = "NFRLT"),
+  units = PKNCA::pknca_units_table(
+    concu = "ng/mL", doseu = "mg/kg", amountu = "mg", timeu = "hr"
+  )
+)
+TEST_PKNCA_DATA$intervals <- INTERVALS
+TEST_PKNCA_DATA$options <- list(keep_interval_cols = c("DOSNO", "type_interval"))
+
+# Add start_dose and end_dose columns
+TEST_PKNCA_RES <- withCallingHandlers(
+  PKNCA::pk.nca(TEST_PKNCA_DATA),
+  warning = function(w) {
+    # Suppress warnings matching the regex "Too few points for half-life"
+    if (grepl("^Too few points for half-life", conditionMessage(w))) {
+      invokeRestart("muffleWarning")
+    }
+  }
+)
+
+#####################################################################
+# Temporarily for some odd reason we cannot use keep_interval_cols,
+# so we are manually making it
+#
+# TODO: Substitute this dirty hard coded trick with the proper way
+TEST_PKNCA_RES$result <- TEST_PKNCA_RES$result %>%
+  mutate(
+    type_interval = if ("type_interval" %in% names(.)) {
+      type_interval
+    } else {
+      ifelse(end %in% c(2, 4), "manual", "main")
+    },
+    DOSNO = if ("type_interval" %in% names(.)) {
+      DOSNO
+    } else {
+      ifelse(
+        end %in% c(2, 5),
+        1,
+        2
+      )
+    }
+  )
+#####################################################################
+
+TEST_DOSE_DATA_TO_JOIN <- select(
path: tests/testthat/setup.R
user: login: m-kolomanski
body: nitpick: I am presuming this variable will not be used in actual tests? If so, I would suggest using lowercase name.
created_at: 2025-05-05T06:31:50Z
author_association: COLLABORATOR
diff_hunk: @@ -15,4 +332,12 @@ PKNCA_DATA_FIXTURE$intervals <- format_pkncadata_intervals(
 PKNCA_DATA_FIXTURE <- create_start_impute(PKNCA_DATA_FIXTURE)
 
 # Create NCA results
-PKNCA_RESULTS_FIXTURE <- PKNCA_calculate_nca(PKNCA_DATA_FIXTURE)
+PKNCA_RESULTS_FIXTURE <- withCallingHandlers(
+  PKNCA_calculate_nca(PKNCA_DATA_FIXTURE),
+  warning = function(w) {
+    # Suppress warnings matching the regex "Too few points for half-life"
+    if (grepl("^Too few points for half-life", conditionMessage(w))) {
+      invokeRestart("muffleWarning")
+    }
+  }
+)
path: tests/testthat/setup.R
user: login: m-kolomanski
body: question: Would we be able to get rid of this with the implementation of proper fixtures in this PR? I am guessing this part stays in for support of older tests that use it and we will update those test to use new fixtures in separate PRs?

I would love to have a `#TODO` comment added here, explaining why we have two `PKNCA_RESULTS` object fixtures.
created_at: 2025-05-05T06:34:45Z
author_association: COLLABORATOR
diff_hunk: @@ -1,107 +1,73 @@
-# Create concentration, dose and interval datasets with all imputation cases
-conc_data <- data.frame(
-  conc = c(1:3, c(1, 2, 0.5), 1:3, 6:4, 6:4, rep(2, 3), 1:3, 6:4),
-  time = c(0:2, c(1, 2, 2.5), 4:6, c(1, 2, 2.5), 4:6, c(1, 2, 2.5), c(1, 2, 2.5), c(1, 2, 2.5)),
-  route = c(rep("extravascular", 9), rep("intravascular", 15)),
-  param = c(rep("A", 21), rep("B", 3)),
-  USUBJID = c(rep(1, 3), rep(2, 6), rep(3, 6), rep(4, 3), rep(5, 3), rep(6, 3)),
-  DOSNO = c(rep(1, 3), rep(rep(1:2, each = 3), 2), rep(1, 3), rep(1, 3), rep(1, 3))
-)
+pknca_data <- TEST_PKNCA_DATA
path: tests/testthat/test-create_start_impute.R
user: login: m-kolomanski
body: question: Do we need to _localize_ the fixture, can't we just use it directly in tests?
created_at: 2025-05-05T06:35:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,182 @@
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @returns A logical value indicating whether all checks passed.
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: issue: Arguments to functions probably should not be uppercase, since they are not constant by definition.
created_at: 2025-05-05T06:37:29Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,182 @@
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @returns A logical value indicating whether all checks passed.
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
+
+  # Extract unique parameter names with units
+  names_params <- TEST_PKNCA_RES$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start_dose, "-", end_dose, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- TEST_PKNCA_RES$result %>%
+        filter(
+          start_dose == auc_start,
+          end_dose == auc_end,
+          type_interval == "manual"
+        )
+      reshaped_data <- pwres %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- TEST_PKNCA_RES$result
+      reshaped_data <- pwres
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+
+  # If all checks pass, return TRUE
+  TRUE
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: nitpick: No need to return anything in this function.
created_at: 2025-05-05T06:38:48Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,182 @@
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @returns A logical value indicating whether all checks passed.
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
+
+  # Extract unique parameter names with units
+  names_params <- TEST_PKNCA_RES$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start_dose, "-", end_dose, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- TEST_PKNCA_RES$result %>%
+        filter(
+          start_dose == auc_start,
+          end_dose == auc_end,
+          type_interval == "manual"
+        )
+      reshaped_data <- pwres %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- TEST_PKNCA_RES$result
+      reshaped_data <- pwres
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+
+  # If all checks pass, return TRUE
+  TRUE
+}
+
+
+describe("pivot_wider_pknca_results", {
+
+  pwres <- expect_no_error(pivot_wider_pknca_results(TEST_PKNCA_RES))
+
+  it("produces a data.frame", {
+    expect_s3_class(pwres, "data.frame")
+  })
+
+  it("produces a data.frame with expected format when only reshaping main intervals", {
+    res_only_main <- TEST_PKNCA_RES
+    res_only_main$result <- TEST_PKNCA_RES$result  %>%
+      filter(type_interval == "main")
+    pwres_only_main <- pivot_wider_pknca_results(res_only_main)
+    expect_s3_class(pwres_only_main, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres_only_main)))
+
+    # Check number of rows is the expected (each dose has 1 row in the pivoted data)
+    expect_true(nrow(pwres_only_main) == nrow(res_only_main$data$dose$data))
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: nitpick:
```suggestion
    expect_equal(nrow(pwres_only_main), nrow(res_only_main$data$dose$data))
```
created_at: 2025-05-05T06:39:10Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,182 @@
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @returns A logical value indicating whether all checks passed.
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
+
+  # Extract unique parameter names with units
+  names_params <- TEST_PKNCA_RES$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start_dose, "-", end_dose, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- TEST_PKNCA_RES$result %>%
+        filter(
+          start_dose == auc_start,
+          end_dose == auc_end,
+          type_interval == "manual"
+        )
+      reshaped_data <- pwres %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- TEST_PKNCA_RES$result
+      reshaped_data <- pwres
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+
+  # If all checks pass, return TRUE
+  TRUE
+}
+
+
+describe("pivot_wider_pknca_results", {
+
+  pwres <- expect_no_error(pivot_wider_pknca_results(TEST_PKNCA_RES))
+
+  it("produces a data.frame", {
+    expect_s3_class(pwres, "data.frame")
+  })
+
+  it("produces a data.frame with expected format when only reshaping main intervals", {
+    res_only_main <- TEST_PKNCA_RES
+    res_only_main$result <- TEST_PKNCA_RES$result  %>%
+      filter(type_interval == "main")
+    pwres_only_main <- pivot_wider_pknca_results(res_only_main)
+    expect_s3_class(pwres_only_main, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres_only_main)))
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: question: Do we expect some more columns to be created in the process? This test would ignore them. Do we want that? Maybe a better test would be
```R
expect_setequal(expected_columns, colnames(pwres_only_main))
```
created_at: 2025-05-05T06:43:46Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,182 @@
+#' Validate PKNCA Parameters
+#'
+#' This function validates that the reshaped PKNCA results contain the expected values
+#' for each parameter based on the original `TEST_PKNCA_RES` object.
+#'
+#' @param TEST_PKNCA_RES The original PKNCA results object.
+#' @param pwres The pivoted results from `pivot_wider_pknca_results`.
+#' @returns A logical value indicating whether all checks passed.
+.validate_pknca_params <- function(TEST_PKNCA_RES, pwres) {
+
+  # Extract unique parameter names with units
+  names_params <- TEST_PKNCA_RES$result %>%
+    mutate(
+      PPSTRESU2 = ifelse(
+        PPSTRESU %in% c("", "unitless", "fraction"),
+        "",
+        paste0("[", PPSTRESU, "]")
+      ),
+      PPTESTCD2 = ifelse(
+        type_interval == "manual",
+        paste0(PPTESTCD, "_", start_dose, "-", end_dose, PPSTRESU2),
+        paste0(PPTESTCD, PPSTRESU2)
+      ),
+    ) %>%
+    pull(PPTESTCD2) %>%
+    unique()
+
+  # Iterate over each parameter and validate values
+  for (param_col in names_params) {
+    pptestcd <- gsub("\\[.*\\]", "", param_col)  # Remove units from parameter name
+
+    if (grepl("AUCINT_[0-9]+\\-[0-9]", param_col)) {
+      auc_start <- gsub("AUCINT_([0-9]+)\\-[0-9]", "\\1", pptestcd)
+      auc_end <- gsub("AUCINT_[0-9]+\\-([0-9]+)", "\\1", pptestcd)
+      pptestcd <- gsub("_[0-9]+\\-[0-9]", "", pptestcd)
+
+      original_data <- TEST_PKNCA_RES$result %>%
+        filter(
+          start_dose == auc_start,
+          end_dose == auc_end,
+          type_interval == "manual"
+        )
+      reshaped_data <- pwres %>%
+        filter(!is.na(!!sym(param_col)))
+    } else {
+      original_data <- TEST_PKNCA_RES$result
+      reshaped_data <- pwres
+    }
+
+    original_vals <- original_data %>%
+      formatters::var_labels_remove() %>%
+      filter(PPTESTCD == pptestcd) %>%
+      pull(PPSTRES)
+    result_vals <- reshaped_data %>%
+      formatters::var_labels_remove() %>%
+      pull(param_col)
+
+    have_similar_vals <- all(round(result_vals, 3) %in% round(original_vals, 3))
+    have_same_length <- length(result_vals) == length(original_vals)
+    if (!(have_similar_vals && have_same_length)) {
+      stop(paste("Mismatch in values for parameter:", param_col))
+    }
+  }
+
+  # If all checks pass, return TRUE
+  TRUE
+}
+
+
+describe("pivot_wider_pknca_results", {
+
+  pwres <- expect_no_error(pivot_wider_pknca_results(TEST_PKNCA_RES))
+
+  it("produces a data.frame", {
+    expect_s3_class(pwres, "data.frame")
+  })
+
+  it("produces a data.frame with expected format when only reshaping main intervals", {
+    res_only_main <- TEST_PKNCA_RES
+    res_only_main$result <- TEST_PKNCA_RES$result  %>%
+      filter(type_interval == "main")
+    pwres_only_main <- pivot_wider_pknca_results(res_only_main)
+    expect_s3_class(pwres_only_main, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX",
+      "LAMZMTD", "Exclude"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres_only_main)))
+
+    # Check number of rows is the expected (each dose has 1 row in the pivoted data)
+    expect_true(nrow(pwres_only_main) == nrow(res_only_main$data$dose$data))
+
+    # Check parameter values match the ones in the PKNCA results object
+    expect_no_error(.validate_pknca_params(res_only_main, pwres_only_main))
+  })
+
+  it("reshapes PKNCA results correctly when also considering AUC intervals", {
+    # Check that the result is a data frame
+    expect_s3_class(pwres, "data.frame")
+
+    # Check that the result contains expected columns
+    expected_columns <- c(
+      "USUBJID", "start", "end", "DOSNO", "AFRLT", "ARRLT",
+      "NFRLT", "NRRLT", "ADOSE", "ROUTE", "ADOSEDUR",
+      "CMAX[ng/mL]", "TMAX[hr]", "TLST[hr]", "LAMZ[1/hr]",
+      "R2", "R2ADJ", "LAMZLL[hr]",
+      "LAMZNPT[count]", "CLSTP[ng/mL]", "LAMZHL[hr]",
+      "LAMZSPN", "LAMZIX", "LAMZMTD", "Exclude",
+      "AUCINT_0-2[hr*ng/mL]", "AUCINT_2-4[hr*ng/mL]"
+    )
+    expect_true(all(expected_columns %in% colnames(pwres)))
path: tests/testthat/test-pivot_wider_pknca_results.R
user: login: m-kolomanski
body: question: Same question as before with the expected columns.
question: Previous test had `nrow()` check, should this be included here as well?
created_at: 2025-05-05T06:45:28Z
author_association: COLLABORATOR

PR comments:
user: login: Gero1999
created_at: 2025-04-24T12:49:08Z
body: hey @js3110 @m-kolomanski I created the global testing objects, hopefully they are complex enough for most tests! If possible, give priority to this PR over the others so I can use the testing data asap on the others! 
author_association: COLLABORATOR
user: login: js3110
created_at: 2025-04-29T08:44:29Z
body: Hi @Gero1999 , what was the bug in bioavailability?
This new version doesn't work and crashes the app when I try with data for bioavailability (eg DummyRO_MRoutes)

I would suggest to just revert the changes, and keep the dummy test data it used as well for now, then it can be modified in a separate issue.
author_association: COLLABORATOR
user: login: m-kolomanski
created_at: 2025-05-05T06:48:54Z
body: Hey, forgot to write in my review that this overall looks very nice, I only have some minor nitpick and questions regarding some test and the naming conventions for the fixtures - generally, it would be good to have the word `FIXTURE` in the names to signify that this data is fixed for the testing suite, as opposed to `TEST` data that suggest that it might be generated on per-test basis.
author_association: COLLABORATOR
user: login: m-kolomanski
created_at: 2025-05-05T07:06:11Z
body: Also, I am now thinking that we are creating a lot of intermediate variables when generating the fixtures. I think it might be worth to consider wrapping everything in `base::local({})` to stop those variables that are not needed bleeding into testing environments:
```R
# test-*.R currently
print(TEST_CONC_DATA) # prints the data
print(all_params) # prints all params

# setup.R
base::local({
  # global assignment for fixtures that will be used in tests
  TEST_CONC_DATA <<- data.frame( 
    ...
  )
  # local assignment for variables that are only used for creating fixtures, but not relevant to tests
  all_params <- setdiff(names(PKNCA::get.interval.cols()),
                        c("start", "end"))
})

# test-*.R
print(TEST_CONC_DATA) # prints the data
print(all_params) # Error: object `all_params` not found
```
author_association: COLLABORATOR
user: login: Gero1999
created_at: 2025-05-05T09:21:50Z
body: > generally, it would be good to have the word `FIXTURE` in the names to signify that this data is fixed for the testing suite, as opposed to `TEST` data that suggest that it might be generated on per-test basis.

Hey @m-kolomanski  maybe it is just me but I always found easier to identify the var in the env if it has a common prefix rather than a suffix. Perhaps would you be ok with using `FIXTURE_*` instead of `*_FIXTURE` ?
author_association: COLLABORATOR
user: login: m-kolomanski
created_at: 2025-05-05T11:51:07Z
body: @Gero1999 Prefix is absolutely fine as well.
author_association: COLLABORATOR
user: login: Gero1999
created_at: 2025-05-06T08:10:52Z
body: Hey @m-kolomanski I think I worked it out with all your comments, lmk if something does not seem right! ;) 
author_association: COLLABORATOR