From 3ba8ce07e86abc2343149cedce9f11445a47f921 Mon Sep 17 00:00:00 2001 From: Philip Chase Date: Sat, 28 Dec 2024 00:27:57 -0500 Subject: [PATCH] Initial commit to redcapfiller Provides these functions: get_long_categorical_field_responses() get_long_categorical_field_response_values() get_one_rectangle_of_values() Tests for each of the 3 functions. Also provides a proof_of_concept.R script with write-back to a demonstration project and properly managed secrets. Supports filling of checkbox, dropdown, and radio field types on classic projects. --- .Rbuildignore | 6 + .gitignore | 5 + DESCRIPTION | 40 +++ LICENSE.md | 13 + NAMESPACE | 6 + ...t_long_categorical_field_response_values.R | 38 +++ R/get_long_categorical_field_responses.R | 62 +++++ R/get_one_rectangle_of_values.R | 53 ++++ example.env | 2 + ..._long_categorical_field_response_values.Rd | 25 ++ man/get_long_categorical_field_responses.Rd | 31 +++ man/get_one_rectangle_of_values.Rd | 33 +++ proof_of_concept.R | 101 +++++++ redcapfiller.Rproj | 22 ++ tests/testthat.R | 12 + .../input.rds | Bin 0 -> 1686 bytes .../make_test_data.R | 6 + .../metadata.csv | 21 ++ tests/testthat/helper.R | 4 + .../redcapfiller_sample_test_metadata.csv | 252 ++++++++++++++++++ ...t_long_categorical_field_response_values.R | 27 ++ ...est-get_long_categorical_field_responses.R | 40 +++ .../test-get_one_rectangle_of_values.R | 29 ++ 23 files changed, 828 insertions(+) create mode 100644 .Rbuildignore create mode 100644 .gitignore create mode 100644 DESCRIPTION create mode 100644 LICENSE.md create mode 100644 NAMESPACE create mode 100644 R/get_long_categorical_field_response_values.R create mode 100644 R/get_long_categorical_field_responses.R create mode 100644 R/get_one_rectangle_of_values.R create mode 100644 example.env create mode 100644 man/get_long_categorical_field_response_values.Rd create mode 100644 man/get_long_categorical_field_responses.Rd create mode 100644 man/get_one_rectangle_of_values.Rd create mode 100644 proof_of_concept.R create mode 100644 redcapfiller.Rproj create mode 100644 tests/testthat.R create mode 100644 tests/testthat/get_long_categorical_field_response_values/input.rds create mode 100644 tests/testthat/get_long_categorical_field_response_values/make_test_data.R create mode 100644 tests/testthat/get_long_categorical_field_responses/metadata.csv create mode 100644 tests/testthat/helper.R create mode 100644 tests/testthat/redcapfiller_sample_test_metadata.csv create mode 100644 tests/testthat/test-get_long_categorical_field_response_values.R create mode 100644 tests/testthat/test-get_long_categorical_field_responses.R create mode 100644 tests/testthat/test-get_one_rectangle_of_values.R diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..e439d5e --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,6 @@ +^.*\.Rproj$ +^\.Rproj\.user$ +^LICENSE\.md$ +.env +example.env +proof_of_concept.R diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c7b5fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.Rproj.user +.Rhistory +.RData +.Ruserdata +.env diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..374c132 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,40 @@ +Package: redcapfiller +Type: Package +Title: Fill a REDCap Project with Generated Data +Version: 0.1.0 +Authors@R: c( + person("Philip", "Chase", + email = "pbc@ufl.edu", + role = c("aut", "cre"), + comment=c(ORCID = "0000-0002-5318-9420")), + person("Sai Pavan", "Kamma", + email = "saipavankamma@ufl.edu", + role = "aut", + comment=c(ORCID = "0009-0004-4619-0409")), + person("Laurence", "James-Woodley", + email = "lawjames1@ufl.edu", + role = "aut", + comment=c(ORCID = "0000-0002-6418-2742")), + person("Taryn", "Stoffs", + email = "tls@ufl.edu", + role = "ctb", + comment=c(ORCID = "0000-0002-0830-8179")), + person("Christopher", "Barnes", + email = "cpb@ufl.edu", + role = "ctb", + comment=c(ORCID = "0000-0001-7114-1992")) + ) +Description: Fill a REDCap project with generated data based on the project design and a minimal set of inputs. +License: Apache License (>= 2) +Encoding: UTF-8 +LazyData: true +Suggests: + readr, + stringr, + testthat (>= 3.0.0) +Config/testthat/edition: 3 +Imports: + dplyr, + rlang, + tidyr +RoxygenNote: 7.3.2 diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..2f3e137 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,13 @@ +Copyright 2024 University of Florida + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..5974d5b --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,6 @@ +# Generated by roxygen2: do not edit by hand + +export(get_long_categorical_field_response_values) +export(get_long_categorical_field_responses) +export(get_one_rectangle_of_values) +importFrom(rlang,.data) diff --git a/R/get_long_categorical_field_response_values.R b/R/get_long_categorical_field_response_values.R new file mode 100644 index 0000000..e4e5bb1 --- /dev/null +++ b/R/get_long_categorical_field_response_values.R @@ -0,0 +1,38 @@ +#' @title generate categorical field response values +#' @description +#' Provide a set of response values for each categorical field in +#' `long_categorical_field_responses` +#' +#' @param long_categorical_field_responses a long data set of categorical +#' field response values and weights. +#' +#' @return a tall dataframe of categorical field response values with one +#' row for each value set. +#' @export +#' +#' @examples +#' \dontrun{ +#' get_long_categorical_field_response_values(long_categorical_field_responses) +#' } +get_long_categorical_field_response_values <- function(long_categorical_field_responses) { + single_value_responses <- long_categorical_field_responses |> + dplyr::filter(.data$field_type != "checkbox") |> + dplyr::group_by(.data$field_name) |> + dplyr::slice_sample(n = 1, weight_by = .data$weight) |> + dplyr::ungroup() + + multi_value_responses <- + long_categorical_field_responses |> + dplyr::filter(.data$field_type == "checkbox") |> + dplyr::group_by(.data$field_group) |> + dplyr::slice_sample(prop = 0.5, weight_by = .data$weight) |> + dplyr::ungroup() + + result <- dplyr::bind_rows( + single_value_responses, + multi_value_responses + ) |> + dplyr::select("field_name", value = "response_code") + + return(result) +} diff --git a/R/get_long_categorical_field_responses.R b/R/get_long_categorical_field_responses.R new file mode 100644 index 0000000..d02b725 --- /dev/null +++ b/R/get_long_categorical_field_responses.R @@ -0,0 +1,62 @@ +#' @title Get every categorical field response from a REDCap data dictionary +#' +#' @description +#' Given a REDCap data dictionary, enumerate every response value for every categorical field in that data dictionary +#' +#' @param metadata A REDCap data dictionary +#' +#' @returns a dataframe with these columns +#' \describe{ +#' \item{field_name}{First item} +#' \item{field_type}{Second item} +#' \item{response_code}{Second item} +#' \item{response_label}{Second item} +#' \item{field_group}{Second item} +#' \item{weight}{a set of uniform weights across the responses of each field} +#' } +#' @export +#' +#' @examples +#' \dontrun{ +#' long_categorical_field_responses <- +#' get_long_categorical_field_responses(metadata_to_populate) +#' } +get_long_categorical_field_responses <- function(metadata) { + balanced_responses <- + metadata |> + # include only categorical field types + dplyr::filter(.data$field_type %in% c("checkbox", "radio", "dropdown")) |> + # excluding anything displayed by branching logic + dplyr::filter(is.na(.data$branching_logic)) |> + # narrow our focus to the required columns + dplyr::select(c("field_name", "form_name", "field_type", "select_choices_or_calculations")) |> + # separate responses + tidyr::separate_longer_delim("select_choices_or_calculations", delim = " | ") |> + # separate response_codes from response_labels + tidyr::separate_wider_delim("select_choices_or_calculations", + delim = ", ", + names = c("response_code", "response_label"), + too_many = "merge", + too_few = "align_start" + ) |> + # apply one-hot encoding to checkbox fields, but leave others unmodified + dplyr::mutate( + field_group = .data$field_name, + field_name = dplyr::if_else( + .data$field_type == "checkbox", + paste0(.data$field_name, "___", .data$response_code), + .data$field_name + ), + response_code = dplyr::if_else( + .data$field_type == "checkbox", + "1", + .data$response_code + ) + ) |> + # set weights for each response + dplyr::group_by(.data$field_group) |> + dplyr::mutate(weight = round(100 / dplyr::n(), digits = 0)) |> + dplyr::ungroup() + + return(balanced_responses) +} diff --git a/R/get_one_rectangle_of_values.R b/R/get_one_rectangle_of_values.R new file mode 100644 index 0000000..b0d017d --- /dev/null +++ b/R/get_one_rectangle_of_values.R @@ -0,0 +1,53 @@ +#' Generate a rectangle of data for one record +#' +#' @param one_record_id a single record_id +#' @param record_id_name the column name the record_id should be returned in +#' @param forms_to_fill the forms to fill for this rectangle +#' @param long_categorical_field_responses the output of `get_long_categorical_field_responses()` +#' +#' @returns a rectangle of data with appropriate REDCap identifiers ready to write to REDCap +#' @export +#' @importFrom rlang .data +#' +#' @examples +#' \dontrun{ +#' get_one_rectangle_of_values(1, record_id_name, forms_to_fill) +#' } +get_one_rectangle_of_values <- function( + one_record_id = 1, + record_id_name, + forms_to_fill, + long_categorical_field_responses) { + # Build tibble of static REDCap identifiers + redcap_identifiers <- dplyr::tibble( + record_id = one_record_id + ) + + # fix the first column name + names(redcap_identifiers) <- record_id_name + + # pick values for one record on one event + # ...by binding the output of each field_type / field_validation function + all_responses <- dplyr::bind_rows( + get_long_categorical_field_response_values( + long_categorical_field_responses |> + dplyr::filter(.data$form_name %in% forms_to_fill) + ) + ) + + # prefix responses with redcap fields + long_result <- dplyr::bind_cols( + redcap_identifiers, + # later we will add redcap_event_name, redcap_repeat_instrument, dag_name, etc. where appropriate + all_responses + ) + + wide_result <- long_result |> + tidyr::pivot_wider( + id_cols = dplyr::any_of(names(redcap_identifiers)), + names_from = "field_name", + values_from = "value" + ) + + return(wide_result) +} diff --git a/example.env b/example.env new file mode 100644 index 0000000..fb58b06 --- /dev/null +++ b/example.env @@ -0,0 +1,2 @@ +filler_demo_pid=15321 +path_credential = ~/credentials.csv diff --git a/man/get_long_categorical_field_response_values.Rd b/man/get_long_categorical_field_response_values.Rd new file mode 100644 index 0000000..c6b8f00 --- /dev/null +++ b/man/get_long_categorical_field_response_values.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/get_long_categorical_field_response_values.R +\name{get_long_categorical_field_response_values} +\alias{get_long_categorical_field_response_values} +\title{generate categorical field response values} +\usage{ +get_long_categorical_field_response_values(long_categorical_field_responses) +} +\arguments{ +\item{long_categorical_field_responses}{a long data set of categorical +field response values and weights.} +} +\value{ +a tall dataframe of categorical field response values with one +row for each value set. +} +\description{ +Provide a set of response values for each categorical field in +`long_categorical_field_responses` +} +\examples{ +\dontrun{ +get_long_categorical_field_response_values(long_categorical_field_responses) +} +} diff --git a/man/get_long_categorical_field_responses.Rd b/man/get_long_categorical_field_responses.Rd new file mode 100644 index 0000000..b151ac5 --- /dev/null +++ b/man/get_long_categorical_field_responses.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/get_long_categorical_field_responses.R +\name{get_long_categorical_field_responses} +\alias{get_long_categorical_field_responses} +\title{Get every categorical field response from a REDCap data dictionary} +\usage{ +get_long_categorical_field_responses(metadata) +} +\arguments{ +\item{metadata}{A REDCap data dictionary} +} +\value{ +a dataframe with these columns +\describe{ + \item{field_name}{First item} + \item{field_type}{Second item} + \item{response_code}{Second item} + \item{response_label}{Second item} + \item{field_group}{Second item} + \item{weight}{a set of uniform weights across the responses of each field} +} +} +\description{ +Given a REDCap data dictionary, enumerate every response value for every categorical field in that data dictionary +} +\examples{ +\dontrun{ +long_categorical_field_responses <- + get_long_categorical_field_responses(metadata_to_populate) +} +} diff --git a/man/get_one_rectangle_of_values.Rd b/man/get_one_rectangle_of_values.Rd new file mode 100644 index 0000000..36e4538 --- /dev/null +++ b/man/get_one_rectangle_of_values.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/get_one_rectangle_of_values.R +\name{get_one_rectangle_of_values} +\alias{get_one_rectangle_of_values} +\title{Generate a rectangle of data for one record} +\usage{ +get_one_rectangle_of_values( + one_record_id = 1, + record_id_name, + forms_to_fill, + long_categorical_field_responses +) +} +\arguments{ +\item{one_record_id}{a single record_id} + +\item{record_id_name}{the column name the record_id should be returned in} + +\item{forms_to_fill}{the forms to fill for this rectangle} + +\item{long_categorical_field_responses}{the output of `get_long_categorical_field_responses()`} +} +\value{ +a rectangle of data with appropriate REDCap identifiers ready to write to REDCap +} +\description{ +Generate a rectangle of data for one record +} +\examples{ +\dontrun{ +get_one_rectangle_of_values(1, record_id_name, forms_to_fill) +} +} diff --git a/proof_of_concept.R b/proof_of_concept.R new file mode 100644 index 0000000..e0e13e5 --- /dev/null +++ b/proof_of_concept.R @@ -0,0 +1,101 @@ +library(tidyverse) +library(REDCapR) +# Read environment from ".env" in the project directory +library(dotenv) +load_dot_env(".env") + +# Load redcapfiller. Make sure you build it first or it won't load. +library(redcapfiller) + +# Create a credentials file if you don't already have one +# path_credential = Sys.getenv("path_credential") +# REDCapR::create_credential_local( +# path_credential +# ) +# Manually populate that + +# Get our credentials using environment variables to locate +# the credentials file and describe the project in it +path_credential <- Sys.getenv("path_credential") +credentials <- REDCapR::retrieve_credential_local( + path_credential, + project_id = Sys.getenv("filler_demo_pid") +) + +metadata <- REDCapR::redcap_metadata_read( + token = credentials$token, + redcap_uri = credentials$redcap_uri +)$data + +# identify the record_id column +record_id_name <- metadata |> + filter(row_number() == 1) |> + pull(field_name) + +# identify the forms to fill +forms_to_fill <- metadata |> + distinct(form_name) |> + filter(!form_name %in% c("randomization")) |> + pull(form_name) + +field_types_we_know_how_to_fill <- c( + "checkbox", + "dropdown", + # "notes", + "radio", + # "text", + "yesno" +) + +metadata_to_populate <- + metadata |> + # Filter for record ID and forms we want to fill + filter(field_name == record_id_name | + form_name %in% forms_to_fill) |> + # Exclude descriptive fields because they are not fillable + filter(field_type != "descriptive") |> + # Exclude calc fields because we don't control them + # (though we might strobe them to trigger writes in a future version) + filter(field_type != "calc") |> + # Exclude file fields + # (Eventually we'll add an option to populate them with a dummy file) + filter(field_type != "file") |> + # Filter for fields not hidden via branching logic. + filter(is.na(branching_logic)) |> + # filter for fields we no how to fill + filter(field_type %in% field_types_we_know_how_to_fill) + +# Make a vector of record IDs to populate +# Get highest existing id +read_result <- REDCapR::redcap_read( + token = credentials$token, + redcap_uri = credentials$redcap_uri +) + +if (read_result$success) { + max_existing_id <- max(read_result$data$record_id) +} else { + max_existing_id = 0 +} + +# choose which IDs to use +first_id <- max_existing_id + 1 +number_of_records_to_populate <- 5 +record_ids <- seq(first_id, first_id + number_of_records_to_populate) + +# get the categorical field responses in a long table and populate them +long_categorical_field_responses <- get_long_categorical_field_responses(metadata_to_populate) + +picked_values <- + purrr::map(record_ids, + get_one_rectangle_of_values, + record_id_name, + forms_to_fill, + long_categorical_field_responses + ) |> + bind_rows() + +picked_values |> REDCapR::redcap_write( + token = credentials$token, + redcap_uri = credentials$redcap_uri +) diff --git a/redcapfiller.Rproj b/redcapfiller.Rproj new file mode 100644 index 0000000..017453d --- /dev/null +++ b/redcapfiller.Rproj @@ -0,0 +1,22 @@ +Version: 1.0 +ProjectId: d86f3a60-d4cb-40b3-b540-c81b7e9b9fc5 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: knitr +LaTeX: pdfLaTeX + +AutoAppendNewline: Yes +StripTrailingWhitespace: Yes + +BuildType: Package +PackageUseDevtools: Yes +PackageInstallArgs: --no-multiarch --with-keep.source +PackageRoxygenize: rd,collate,namespace diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..afa6b1b --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(redcapfiller) + +test_check("redcapfiller") diff --git a/tests/testthat/get_long_categorical_field_response_values/input.rds b/tests/testthat/get_long_categorical_field_response_values/input.rds new file mode 100644 index 0000000000000000000000000000000000000000..7304e5e738e0ed84f0050d9e939d75e142f83f99 GIT binary patch literal 1686 zcmZw1c{mda003~g3-P=OnM}wzb9>I1Y|hAz9JzDPF@)(M%TaC2F}aH(pX*2PsmvDNOE4$HAiH|+nj z;Q0@1od=~EiN0Q{r5$wzJ?E!r{pO`>2jo6wdOhI?h(v2|&!#g7BqCJr^fQ=}qT-_Y z^Ewaf~Xx}lc$PUS<4-aDKd_Jw~Y7FdkmoF zUvd(X4NZI)fI2lqa*1`A*cT@jY^tl5gFT{z|6quP_UV+JC>r{liL``TZ;TYXl}M7u z_|05od3gWbjL}w2(JWr9Ayo#mId|EuYp6zzyG)%;8il3=)rYZ*2eV)| zV=Lw!avt%@>edh<+3F9rCW&z%=lb*ZKuo>|Kp(WoXYkjA>DEiE! z1RRW0lq{qO?oG&)ynLdXjPP|;6AJ^^LWRDBT;FbzzPPQ~E8QhomPVgMv2xv?xas{F zl+rZj;_f#Ua?{Rjh~+a}R-E;Ykd)a1%MVCEo(YS%1(65`FAOuS%nqoQ)kzc%`JCFi zz)9PY%No>8!gm|L>+G?OKR;L?tk%mEdXWjI!B#)^%*j|vr^PkAPrdH$(rFYkI^HtH z`Zuh+jL7g_8~x5~aTy=D$FkR|&9L3<*0>;S15Cl`+`o4}>ZqW-_N5| z>$`NUtq>f9hdBpG4M-39ACWe(O>xeVGAkwWK;f&D8xP;|)iP^+ljsB50Rb}!z&YNkfQa;sH^p%u7F>H~(DsQ#ZP{bUv&FSnj z$4#0{CLm!Qve|8Mj#_iIvj{2bq9BT44>i+04`FAS2U(I_TXrK)A2Qz>jrDo4`5E#n zmxAm$KG{LH8!(Rnq(bIU)aSS<37DAsdF0ucwm?-c!HQETFhk`SBrb$9@nKgf_kLqp zz2B0wZ5Kg?Ikh&n$%l4}o+^4IP6rH@RkXWGa0CsuHxZ69?R~GM`oo(~fWk;wI^%(8 z-b>h)L005ipy2zW?7mi^3V?LjnCaz#cOt>D{p}|oZ-AV#Up?j8|Ipw^0M^%SjLV>2 ze1$cB8%Ce%fYN(sq)#KZ4W74F3%wCA%e|;78UGrvl5$7@EtTEhp(JV~)NA8GbgbSr z8H)S2?rC+A!{|~E=nce8QLyV`^+isDo^O@f)qN-RqN1}EXVtgz~Q=TcU9nEZ9kNt-e|gY4PvZB*xE8U#KU8wCOM#46Hd{-QnqD z{9?ce*<7$Q5VM&3WD4RQcGE9Jk*~Z4Fb%bkRYWn$hF`Rv)4yGxKGu>m5h}O4@KeMW9%Y&Cb2mb^ z;h8AtVD2z`vfjk|e2|V}xdd{#LWow*ArUq%3K0sKsmm5@G{@X9T87K3W zHHeNoDAQOCy|ek4(n`{!_2LLyN)W8P7^7KF_;qn2zw1DD*xAn^8Jw6Dd+zSB(^~mH W_TCdE`6uZo0{ua$+zDkqzW)GBa5KFC literal 0 HcmV?d00001 diff --git a/tests/testthat/get_long_categorical_field_response_values/make_test_data.R b/tests/testthat/get_long_categorical_field_response_values/make_test_data.R new file mode 100644 index 0000000..dac6225 --- /dev/null +++ b/tests/testthat/get_long_categorical_field_response_values/make_test_data.R @@ -0,0 +1,6 @@ +metadata_file <- testthat::test_path("get_long_categorical_field_responses", "metadata.csv") +metadata <- readr::read_csv(metadata_file) + +long_categorical_field_responses <- get_long_categorical_field_responses(metadata) +long_categorical_field_responses |> + saveRDS(testthat::test_path("get_long_categorical_field_response_values", "input.rds")) diff --git a/tests/testthat/get_long_categorical_field_responses/metadata.csv b/tests/testthat/get_long_categorical_field_responses/metadata.csv new file mode 100644 index 0000000..696c23b --- /dev/null +++ b/tests/testthat/get_long_categorical_field_responses/metadata.csv @@ -0,0 +1,21 @@ +field_name,form_name,section_header,field_type,field_label,select_choices_or_calculations,field_note,text_validation_type_or_show_slider_number,text_validation_min,text_validation_max,identifier,branching_logic,required_field,custom_alignment,question_number,matrix_group_name,matrix_ranking,field_annotation +record_id,tests,,text,Record ID,,,,,,,,,,,,, +incl_visit_date,tests,,text,Visit date,,,date_mdy,,,,,,,,,, +incl_icf_date,tests,,text,Date subject provided informed consent:,,,date_mdy,,,,"[event-name] = ""initial_study_visi_arm_1""",,,,,, +incl_1,tests,,yesno,Female at least 18 years old,,,,,,,,,,,,,@DEFAULT='[screening_arm_1][incl_1:value]' +excl_1,tests,,yesno,"Any condition that at the discretion of the investigator, medical doctor, or designee will impact the safety of the subject or the scientific integrity of the trial",,,,,,,,,,,,,@DEFAULT='[screening_arm_1][excl_5:value]' +bl_date,tests,,text,Today's date,,,date_mdy,,,,,y,LV,,,,@TODAY +bl_treatments,tests,,checkbox,Do you regularly use any of the following on your torso/ bra area? Choose all that apply.,"1, Lotions | 2, Exfoliants | 3, Other skin treatments, please specify below. | 0, None",,,,,,,y,LV,,,,@NONEOFTHEABOVE='0' +bl_treatments_other,tests,,text,Specify Other,,,,,,,[bl_treatments(3)] = '1',y,LV,,,, +bl_exercise,tests,,checkbox,Regular exercise (3 times per week),"1, Never | 2, In the past | 3, Now",,,,,,,y,LV,,,,@NONEOFTHEABOVE='1' +bl_caffeine,tests,,checkbox,Daily caffeinated drink,"1, Never | 2, In the past | 3, Now",,,,,,,y,LV,,,,@NONEOFTHEABOVE='1' +fname,tests,,text,First name,,,,,,y,,y,LV,,,, +lname,tests,,text,Last name,,,,,,y,,y,LV,,,, +dob,tests,,text,Date of birth,,,date_mdy,,,y,,y,LV,,,,@HIDEBUTTON +age,tests,,calc,Age,"rounddown(datediff([dob],[bl_date],""y""))",,,,,,,,LV,,,, +state,tests,,dropdown,State,"1, Alabama | 2, Alaska | 3, Arizona | 4, Arkansas | 5, California | 6, Colorado | 7, Connecticut | 8, Delaware | 9, District of Columbia | 10, Florida | 11, Georgia | 12, Hawaii | 13, Idaho | 14, Illinois | 15, Indiana | 16, Iowa | 17, Kansas | 18, Kentucky | 19, Louisiana | 20, Maine | 21, Maryland | 22, Massachusetts | 23, Michigan | 24, Minnesota | 25, Mississippi | 26, Missouri | 27, Montana | 28, Nebraska | 29, Nevada | 30, New Hampshire | 31, New Jersey | 32, New Mexico | 33, New York | 34, North Carolina | 35, North Dakota | 36, Ohio | 37, Oklahoma | 38, Oregon | 39, Pennsylvania | 40, Rhode Island | 41, South Carolina | 42, South Dakota | 43, Tennessee | 44, Texas | 45, Utah | 46, Vermont | 47, Virginia | 48, Washington | 49, West Virginia | 50, Wisconsin | 51, Wyoming",,,,,y,,y,LV,,,, +ethnicity,tests,,radio,Which category best describes your ethnic group?,"1, Hispanic/Latino (Mexican, Cuban, Puerto Rican, South or Central American, or other Spanish culture) | 0, Not Hispanic or Latino",,,,,,,y,LV,,,, +race,tests,,radio,Which category best describes your racial group?,"1, American Indian or Alaskan Native (North, Central, and South America, who has a tribal affiliation) | 2, Asian (Far East, Southeast Asia, Cambodia, China, India, Japan, Korea, Malaysia, Pakistan, Philippine Islands, Thailand, and Vietnam) | 3, Black or African-American | 4, Native Hawaiian or Other Pacific Islander (Hawaii, Guam, Samoa, or other Pacific Islands) | 5, Caucasian (European, Central/South American, Puerto Rican, Cuban, Middle Eastern, or North African) | 6, Multi-racial (specify races below) | 99, Choose not to provide",,,,,,,y,LV,,,, +race_multi,tests,,checkbox,Which categories best describes your multi-racial groups?,"1, American Indian or Alaskan Native (North, Central, and South America, who has a tribal affiliation) | 2, Asian (Far East, Southeast Asia, Cambodia, China, India, Japan, Korea, Malaysia, Pakistan, Philippine Islands, Thailand, and Vietnam.) | 3, Black or African-American | 4, Native Hawaiian or Other Pacific Islander (Hawaii, Guam, Samoa, or other Pacific Islands) | 5, Caucasian (European, Central/South American, Puerto Rican, Cuban, Middle Eastern, or North African)",Check all that apply,,,,,[race] = '6',y,LV,,,, +occupation,tests,,radio,Occupation,"1, Homemaker, raising children, care of others | 2, Managerial, professional specialty (executive, managerial, administrative, teacher, guidance counselor, registered nurse, doctor, etc.) | 3, Operators, fabricators, and laborers (factory, transport, construction work, assembly, etc.) | 4, Service protective service (police, fire), health or food services, craft and repair, farming, etc. | 5, Technical, sales, and administrative support (technical, sales, administrative support, clerical work, etc.) | 6, Disabled/Unable to work | 7, Student | 8, Currently unemployed | 88, Other (specify below)",,,,,,,y,LV,,,, +occupation_other,tests,,text,Specify other occupation,,,,,,,[occupation] = '88',y,LV,,,, diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R new file mode 100644 index 0000000..e47fdea --- /dev/null +++ b/tests/testthat/helper.R @@ -0,0 +1,4 @@ +# write a dataframe, referenced by 'table_name' to tests/testthat/directory_under_test_path +write_rds_to_test_dir <- function(table_name, directory_under_test_path) { + get(table_name) |> saveRDS(testthat::test_path(directory_under_test_path, paste0(table_name, ".rds"))) +} diff --git a/tests/testthat/redcapfiller_sample_test_metadata.csv b/tests/testthat/redcapfiller_sample_test_metadata.csv new file mode 100644 index 0000000..89734f0 --- /dev/null +++ b/tests/testthat/redcapfiller_sample_test_metadata.csv @@ -0,0 +1,252 @@ +field_name,form_name,section_header,field_type,field_label,select_choices_or_calculations,field_note,text_validation_type_or_show_slider_number,text_validation_min,text_validation_max,identifier,branching_logic,required_field,custom_alignment,question_number,matrix_group_name,matrix_ranking,field_annotation +record_id,screening_for_inclusionexclusion_criteria,NA,text,Record ID,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +incl_visit_date,screening_for_inclusionexclusion_criteria,NA,text,Visit date,NA,NA,date_mdy,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +incl_icf_date,screening_for_inclusionexclusion_criteria,NA,text,Date subject provided informed consent:,NA,NA,date_mdy,NA,NA,NA,"[event-name] = ""initial_study_visi_arm_1""",NA,NA,NA,NA,NA,NA +incl_1,screening_for_inclusionexclusion_criteria,"INCLUSION CRITERIA / Verification of Inclusion Criteria + +If any NO box is ticked, the subject is not eligible for this study and must be withdrawn.",yesno,Female at least 18 years old,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][incl_1:value]' +incl_2,screening_for_inclusionexclusion_criteria,NA,yesno,Have known or suspected cardiovascular disease,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][incl_2:value]' +incl_3,screening_for_inclusionexclusion_criteria,NA,yesno,May be high risk for cardiovascular event or asymptomatic,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][incl_3:value]' +incl_4,screening_for_inclusionexclusion_criteria,NA,yesno,Be willing to remain within range of mobile device and Bluetooth connection for sufficient time to upload data daily (approximately 10 minutes/hour of data collection during CR),NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][incl_4:value]' +incl_5,screening_for_inclusionexclusion_criteria,NA,yesno,Have iOS device or be willing to carry one with her during the study period,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][incl_5:value]' +incl_6,screening_for_inclusionexclusion_criteria,NA,yesno,Have access to internet and is willing and able to connect study mobile device (smartphone or tablet) with home or work Wi-Fi,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][incl_6:value]' +excl_1,screening_for_inclusionexclusion_criteria,"EXCLUSION CRITERIA / Verification of Exclusion Criteria + +If any YES box is ticked, the subject is not eligible for this study and must be withdrawn.",yesno,Subject being pregnant,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][excl_1:value]' +excl_2,screening_for_inclusionexclusion_criteria,NA,radio,Skin sensitivity to silver metal,"1, Yes | 0, No | 99, Unknown (mark form as incomplete if so)",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][excl_2:value]' +excl_3,screening_for_inclusionexclusion_criteria,NA,yesno,"Subject has any battery-powered implanted medical devices (e.g., pacemaker or defibrillator)",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][excl_3:value]' +excl_4,screening_for_inclusionexclusion_criteria,NA,yesno,"Any condition that at the discretion of the investigator, medical doctor, or designee will impact the safety of the subject or the scientific integrity of the trial",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@DEFAULT='[screening_arm_1][excl_5:value]' +bl_date,participants_baseline_survey,NA,text,Today's date,NA,NA,date_mdy,NA,NA,NA,NA,y,LV,NA,NA,NA,@TODAY +bl_treatments,participants_baseline_survey,NA,checkbox,3) Do you regularly use any of the following on your torso/ bra area? Choose all that apply.,"1, Lotions | 2, Exfoliants | 3, Other skin treatments, please specify below. | 0, None",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,@NONEOFTHEABOVE='0' +bl_treatments_other,participants_baseline_survey,NA,text,Specify Other,NA,NA,NA,NA,NA,NA,[bl_treatments(3)] = '1',y,LV,NA,NA,NA,NA +bl_bra_sleep,participants_baseline_survey,NA,radio,4) Do you usually wear a bra to sleep?,"1, Always | 2, Sometimes | 3, Never",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +bl_act_none,participants_baseline_survey,5) Please describe your typical engagement in physical activities before being enrolled in the CR program.,checkbox,"If you typically engage in no activities, click here:","1,",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +bl_act_yoga,participants_baseline_survey,NA,radio,Yoga,"1, Twice/ week | 2, 3-4 times/ week | 3, Daily | 4, Weekly | 5, Every 2 weeks | 6, Monthly | 0, Never",NA,NA,NA,NA,NA,[bl_act_none(1)] = '0',y,LV,NA,NA,NA,NA +bl_act_walk,participants_baseline_survey,NA,radio,Walking,"1, Twice/ week | 2, 3-4 times/ week | 3, Daily | 4, Weekly | 5, Every 2 weeks | 6, Monthly | 0, Never",NA,NA,NA,NA,NA,[bl_act_none(1)] = '0',y,LV,NA,NA,NA,NA +bl_act_run,participants_baseline_survey,NA,radio,Running,"1, Twice/ week | 2, 3-4 times/ week | 3, Daily | 4, Weekly | 5, Every 2 weeks | 6, Monthly | 0, Never",NA,NA,NA,NA,NA,[bl_act_none(1)] = '0',y,LV,NA,NA,NA,NA +bl_act_swim,participants_baseline_survey,NA,radio,Swimming,"1, Twice/ week | 2, 3-4 times/ week | 3, Daily | 4, Weekly | 5, Every 2 weeks | 6, Monthly | 0, Never",NA,NA,NA,NA,NA,[bl_act_none(1)] = '0',y,LV,NA,NA,NA,NA +bl_act_weights,participants_baseline_survey,NA,radio,Weightlifting,"1, Twice/ week | 2, 3-4 times/ week | 3, Daily | 4, Weekly | 5, Every 2 weeks | 6, Monthly | 0, Never",NA,NA,NA,NA,NA,[bl_act_none(1)] = '0',y,LV,NA,NA,NA,NA +bl_act_other1,participants_baseline_survey,NA,radio,"Other, if so, specify: {bl_act_other1_spec}","1, Twice/ week | 2, 3-4 times/ week | 3, Daily | 4, Weekly | 5, Every 2 weeks | 6, Monthly | 0, Never",NA,NA,NA,NA,NA,[bl_act_none(1)] = '0',NA,LV,NA,NA,NA,NA +bl_act_other1_spec,participants_baseline_survey,NA,text,Specify Other:,NA,NA,NA,NA,NA,NA,"[bl_act_other1] <>""""",y,NA,NA,NA,NA,NA +bl_act_other2,participants_baseline_survey,NA,radio,"Other, if so, specify: {bl_act_other2_spec}","1, Twice/ week | 2, 3-4 times/ week | 3, Daily | 4, Weekly | 5, Every 2 weeks | 6, Monthly | 0, Never",NA,NA,NA,NA,NA,[bl_act_none(1)] = '0',NA,LV,NA,NA,NA,NA +bl_act_other2_spec,participants_baseline_survey,NA,text,Specify Other:,NA,NA,NA,NA,NA,NA,"[bl_act_other2] <>""""",y,NA,NA,NA,NA,NA +bl_exercise_bra,participants_baseline_survey,NA,radio,6) Do you wear a bra/ sports bra for exercising?,"1, Bra | 2, Sport Bra | 0, None | 88, Other, please specify below.",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +bl_exercise_bra_other,participants_baseline_survey,NA,text,Specify Other:,NA,NA,NA,NA,NA,NA,[bl_exercise_bra] = '88',y,LV,NA,NA,NA,NA +bl_health_monitor,participants_baseline_survey,NA,checkbox,7) Do you wear health monitor devices when exercising? Choose all that apply.,"1, Fitness tracker/ Smartwatches | 2, Heart Rate chest straps | 3, Prescribed/Doctor-recommended heart rhythm devices (e.g., ECG patch, handhelds, holter monitors) | 4, Others, please specify below.",NA,NA,NA,NA,NA,NA,NA,LV,NA,NA,NA,NA +bl_health_monitor_other,participants_baseline_survey,NA,text,Specify others:,NA,NA,NA,NA,NA,NA,[bl_health_monitor(4)] = '1',y,LV,NA,NA,NA,NA +bl_diet,participants_baseline_survey,"8) Lifestyle Habits +Please select all that apply:",checkbox,Diet low in fat & sodium,"1, Never | 2, In the past | 3, Now",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,@NONEOFTHEABOVE='1' +bl_exercise,participants_baseline_survey,NA,checkbox,Regular exercise (3 times per week),"1, Never | 2, In the past | 3, Now",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,@NONEOFTHEABOVE='1' +bl_caffeine,participants_baseline_survey,NA,checkbox,Daily caffeinated drink,"1, Never | 2, In the past | 3, Now",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,@NONEOFTHEABOVE='1' +fname,demographic_data,NA,text,First name,NA,NA,NA,NA,NA,y,NA,y,LV,NA,NA,NA,NA +lname,demographic_data,NA,text,Last name,NA,NA,NA,NA,NA,y,NA,y,LV,NA,NA,NA,NA +dob,demographic_data,NA,text,Date of birth,NA,NA,date_mdy,NA,NA,y,NA,y,LV,NA,NA,NA,@HIDEBUTTON +age,demographic_data,NA,calc,Age,"rounddown(datediff([dob],[bl_date],""y""))",NA,NA,NA,NA,NA,NA,NA,LV,NA,NA,NA,NA +street_address,demographic_data,NA,text,Street address,NA,"Street Address (include unit/apartment number, if applicable)",NA,NA,NA,y,NA,y,LV,NA,NA,NA,NA +city,demographic_data,NA,text,City,NA,NA,NA,NA,NA,y,NA,y,LV,NA,NA,NA,NA +state,demographic_data,NA,dropdown,State,"1, Alabama | 2, Alaska | 3, Arizona | 4, Arkansas | 5, California | 6, Colorado | 7, Connecticut | 8, Delaware | 9, District of Columbia | 10, Florida | 11, Georgia | 12, Hawaii | 13, Idaho | 14, Illinois | 15, Indiana | 16, Iowa | 17, Kansas | 18, Kentucky | 19, Louisiana | 20, Maine | 21, Maryland | 22, Massachusetts | 23, Michigan | 24, Minnesota | 25, Mississippi | 26, Missouri | 27, Montana | 28, Nebraska | 29, Nevada | 30, New Hampshire | 31, New Jersey | 32, New Mexico | 33, New York | 34, North Carolina | 35, North Dakota | 36, Ohio | 37, Oklahoma | 38, Oregon | 39, Pennsylvania | 40, Rhode Island | 41, South Carolina | 42, South Dakota | 43, Tennessee | 44, Texas | 45, Utah | 46, Vermont | 47, Virginia | 48, Washington | 49, West Virginia | 50, Wisconsin | 51, Wyoming",NA,NA,NA,NA,y,NA,y,LV,NA,NA,NA,NA +zipcode,demographic_data,NA,text,US residential Postal Code,NA,NA,zipcode,NA,NA,y,NA,y,LV,NA,NA,NA,NA +birth_place,demographic_data,NA,text,City and country of birth,NA,NA,NA,NA,NA,y,NA,y,LV,NA,NA,NA,NA +cellphone,demographic_data,NA,text,Cell phone number,NA,NA,phone,NA,NA,y,NA,y,LV,NA,NA,NA,NA +email,demographic_data,NA,text,Email address,NA,NA,email,NA,NA,y,NA,y,LV,NA,NA,NA,NA +ethnicity,demographic_data,NA,radio,Which category best describes your ethnic group?,"1, Hispanic/Latino (Mexican, Cuban, Puerto Rican, South or Central American, or other Spanish culture) | 0, Not Hispanic or Latino",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +race,demographic_data,NA,radio,Which category best describes your racial group?,"1, American Indian or Alaskan Native (North, Central, and South America, who has a tribal affiliation) | 2, Asian (Far East, Southeast Asia, Cambodia, China, India, Japan, Korea, Malaysia, Pakistan, Philippine Islands, Thailand, and Vietnam) | 3, Black or African-American | 4, Native Hawaiian or Other Pacific Islander (Hawaii, Guam, Samoa, or other Pacific Islands) | 5, Caucasian (European, Central/South American, Puerto Rican, Cuban, Middle Eastern, or North African) | 6, Multi-racial (specify races below) | 99, Choose not to provide",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +race_multi,demographic_data,NA,checkbox,Which categories best describes your multi-racial groups?,"1, American Indian or Alaskan Native (North, Central, and South America, who has a tribal affiliation) | 2, Asian (Far East, Southeast Asia, Cambodia, China, India, Japan, Korea, Malaysia, Pakistan, Philippine Islands, Thailand, and Vietnam.) | 3, Black or African-American | 4, Native Hawaiian or Other Pacific Islander (Hawaii, Guam, Samoa, or other Pacific Islands) | 5, Caucasian (European, Central/South American, Puerto Rican, Cuban, Middle Eastern, or North African)",Check all that apply,NA,NA,NA,NA,[race] = '6',y,LV,NA,NA,NA,NA +educational_level,demographic_data,NA,radio,Highest educational level,"1, Less than High School | 2, High School/GED | 3, Some college but no degree | 4, 2 year degree (Associates)/Trade school | 5, 4 year degree (Bachelors) | 6, Graduate Degree (Masters/Ph.D./JD)",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +occupation,demographic_data,NA,radio,Occupation,"1, Homemaker, raising children, care of others | 2, Managerial, professional specialty (executive, managerial, administrative, teacher, guidance counselor, registered nurse, doctor, etc.) | 3, Operators, fabricators, and laborers (factory, transport, construction work, assembly, etc.) | 4, Service protective service (police, fire), health or food services, craft and repair, farming, etc. | 5, Technical, sales, and administrative support (technical, sales, administrative support, clerical work, etc.) | 6, Disabled/Unable to work | 7, Student | 8, Currently unemployed | 88, Other (specify below)",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +occupation_other,demographic_data,NA,text,Specify other occupation,NA,NA,NA,NA,NA,NA,[occupation] = '88',y,LV,NA,NA,NA,NA +insurance,demographic_data,NA,checkbox,Type(s) of insurance ,"1, Federal/Military (CHAMPUS, TriCare, Administar Defense, etc.) | 2, Medicare | 3, None/self-pay | 4, Other public insurance (includes Medicaid) | 5, Private (HMO or PPO) | 6, VA",Check all that apply,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +income,demographic_data,NA,radio,Total family income (before taxes) from all sources within the household in the last year?,"1, Less that $20,000 | 2, $20,000 to $34,999 | 3, $35,000 to $49,999 | 4, $50,000 to $99,000 | 5, $100,000 or more | 99, Don't know | 77, Prefer not to answer",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +marital_status,demographic_data,NA,radio,Current marital status,"1, Divorced/Separated | 2, Living with significant other | 3, Married | 4, Never married/Single | 5, Widowed",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +survey_preference,demographic_data,NA,radio,How would you like to receive the weekly study-related surveys?,"EMAIL, Email | SMS_INVITE_WEB, SMS (Text message containing a survey link)",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +iphone,ios_verification,NA,yesno,Does the study participant have an Iphone? ,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +ios_version,ios_verification,NA,text,"If yes, record the iOS version",NA,NA,NA,NA,NA,NA,[iphone] = '1',NA,NA,NA,NA,NA,NA +study_phone,ios_verification,NA,yesno,"If no, is the subject willing to carry a study mobile device for the duration of the clinical trial?",NA,NA,NA,NA,NA,NA,[iphone] = '0',NA,NA,NA,NA,NA,NA +study_phone_sn,ios_verification,NA,text,Record the study mobile's serial number ,NA,NA,NA,NA,NA,NA,[study_phone] = '1',NA,NA,NA,NA,NA,NA +weight,physical_examination,This data should be taken from the patient's most recent medical record,text,Weight (kg),NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +height,physical_examination,NA,text,Height (cm),NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +bmi,physical_examination,NA,calc,BMI,[weight]*10000/([height]*[height]),NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +fat,physical_examination,NA,text,Fat (%),NA,NA,number,0,100,NA,NA,NA,NA,NA,NA,NA,NA +muscle_mass,physical_examination,NA,text,Muscle mass,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +bp_systolic,physical_examination,NA,text,Systolic Blood pressure,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +bp_diastolic,physical_examination,NA,text,Diastolic Blood pressure,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +temperature,physical_examination,NA,text,Temperature (C),NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +respiratory_rate,physical_examination,NA,text,Respiratory rate,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +heart_rate,physical_examination,NA,text,Heart Rate (bpm),NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +family_history,physical_examination,NA,checkbox,Family History,"1, Diabetes | 2, Obesity | 3, Blood Pressure | 4, Cancer | 5, CVD | 0, None of the above",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@NONEOFTHEABOVE='0' +cur_his_cond,medical_history,Medical History,checkbox,Has the participant's DOCTOR ever said that they have had any of the following:,"1, Angina (chest pain) | 2, Angioplasty or Stent | 3, Atrial Fibrillation | 4, Bleeding Tendencies | 5, Blood Disorders | 6, Cancer | 7, Cardiomyopathy | 8, Heart Failure | 25, History of elevated liver enzymes | 26, History of rhabdomyolysis | 9, Diabetes | 10, GERD | 11, Heart Attack | 12, Heart Surgery | 13, Hepatitis | 14, High Blood Pressure | 15, High Cholesterol | 16, High Triglycerides | 24, Inflammatory Bowel Disease | 17, Irregular Heart Rhythm | 18, Kidney Disease | 19, Pacemaker or AICD | 20, Perpherial Artery Disease | 21, Polycystic Ovary Disease | 22, Stroke | 23, Thyroid Disease",Check all that apply,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cur_his_card_fam,medical_history,NA,radio,Does the participant have a family history of heart disease?,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_smoke,medical_history,TOBACCO AND VAPING USE:,radio,Does the participant currently smoke or use tobacco products?,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_past_smoke,medical_history,NA,text,"If no, but smoked in the past, how long ago did she quit?",NA,Specify in number of years,number,0,999,NA,[cur_his_smoke] = '0',NA,NA,NA,NA,NA,NA +cur_his_pack_year,medical_history,NA,text,"",NA,Number of pack years,number,1,NA,NA,[cur_his_smoke] = '1',y,NA,NA,NA,NA,NA +cur_his_vape,medical_history,NA,radio,Participant's current vaping status:,"1, Former vaper | 2, Current vaper | 3, Never vaped",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_vaping_entry,medical_history,NA,text,Months the participant stopped vaping before study enrollment:,NA,# of months,number,NA,NA,NA,[cur_his_vape] = '1',y,NA,NA,NA,NA,NA +cur_his_vaping_years,medical_history,NA,text,How many years has (or did) the participant vaped?,NA,# of years,number,NA,NA,NA,([cur_his_vape] = '1' or [cur_his_vape] = '2'),y,NA,NA,NA,NA,NA +cur_his_vaping_mon,medical_history,NA,text,"On average, how many puffs did/does the participant inhale per day?",NA,# of puffs per day,number,1,NA,NA,([cur_his_vape] = '1' or [cur_his_vape] = '2'),y,NA,NA,NA,NA,NA +cur_his_alcohol,medical_history,Alcohol Use:,radio,Does the participant drink alcohol currently?,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_alcohol_week,medical_history,NA,text,"If yes, how many drinks per week is consumed on average?",NA,Number of drinks/week,number,1,50,NA,[cur_his_alcohol] = '1',y,NA,NA,NA,NA,NA +cur_his_menstruating,medical_history,Hormonal Status/Reproductive,text,At what age did you begin menstruating?,NA,in years,number,7,18,NA,NA,y,NA,NA,NA,NA,NA +cur_his_nat_mens,medical_history,NA,radio,Has the participant's natural menstruation stopped?,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_age_mens,medical_history,NA,text,"If yes, at what age did it stop?",NA,Number (age in years),number,1,70,NA,[cur_his_nat_mens] = '1',y,NA,NA,NA,NA,NA +cur_his_date_mens,medical_history,NA,text,What was the year of the last menstrual period?,NA,year,integer,1920,2024,NA,[cur_his_nat_mens] = '1',y,NA,NA,NA,NA,NA +cur_his_period_pattern,medical_history,NA,radio,"Currently, the pattern that best describes the participant's menstrual periods is:","3, Irregular menstrual periods | 1, No menstrual periods | 2, Regular menstrual periods | 4, Sometimes regular, sometimes irregular",NA,NA,NA,NA,NA,[cur_his_nat_mens] = '0',y,NA,NA,NA,NA,NA +cur_his_oral_contra,medical_history,NA,radio,Is the participant on an oral contraceptive or has she ever used oral contraception?,"1, Currently | 2, In the Past | 3, Never",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_age_contra,medical_history,NA,text,What age did the participant start taking oral contraception?,NA,Number (age in years),number,1,60,NA,[cur_his_oral_contra] = '1' and [cur_his_oral_contra] = '2',y,NA,NA,NA,NA,NA +cur_his_stop_contra,medical_history,NA,text,At what age did the participant stop taking oral contraception?,NA,"Number (age in years), if still taking use 99",number,1,70,NA,[cur_his_oral_contra] = '2',y,NA,NA,NA,NA,NA +cur_his_hyster_surg,medical_history,NA,checkbox,Has the participant had any of the following surgeries?,"1, Hysterectomy (removal of the uterus) | 2, Removal of one ovary | 3, Removal of both ovaries | 77, Not applicable",Check all that apply,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,"@NONEOFTHEABOVE=""77""" +cur_his_date_hyster,medical_history,NA,text,What was the year of the hysterectomy?,NA,year,integer,1920,2024,NA,[cur_his_hyster_surg(1)] = '1',y,NA,NA,NA,NA,NA +cur_his_why_hyster,medical_history,NA,checkbox,What is the reason(s) for the hysterectomy?,"1, Bleeding | 2, Cancer | 3, Endometriosis | 4, Tumors | 88, Other",check all that apply,NA,NA,NA,NA,[cur_his_hyster_surg(1)] = '1',y,NA,NA,NA,NA,NA +cur_his_mens_hyster,medical_history,NA,radio,Was the participant still having menstrual periods when she had her hysterectomy?,"1, Yes | 0, No",NA,NA,NA,NA,NA,[cur_his_hyster_surg(1)] = '1',y,NA,NA,NA,NA,NA +cur_his_date_ovar_surg,medical_history,NA,text,What is the year of the oophorectomy? ,NA,year,integer,1920,2024,NA,[cur_his_hyster_surg(2)] = '1' or [cur_his_hyster_surg(3)] = '1',y,NA,NA,NA,NA,NA +cur_his_why_ovar_remove,medical_history,NA,checkbox,What is the reason(s) for the oophorectomy?,"1, Ectopic pregnancy | 2, Cancer | 3, Endometriosis | 4, Polycystic Ovary Syndrome (PCOS) | 88, Other",check all that apply,NA,NA,NA,NA,[cur_his_hyster_surg(2)] = '1' or [cur_his_hyster_surg(3)] = '1',y,NA,NA,NA,NA,NA +cur_his_mens_ovar,medical_history,NA,radio,Was the participant still having menstrual periods when she had her oophorectomy?,"1, Yes | 0, No",NA,NA,NA,NA,NA,[cur_his_hyster_surg(2)] = '1' or [cur_his_hyster_surg(3)] = '1',y,NA,NA,NA,NA,NA +cur_his_hrt_therapy,medical_history,NA,radio,Has the participant ever used Hormone Replacement therapy?,"1, Currently | 2, In the Past | 3, Never",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_age_hrt_start,medical_history,NA,text,At what age did she start taking HRT therapy?,NA,Number (age in years),number,1,80,NA,[cur_his_hrt_therapy] = '1' or [cur_his_hrt_therapy] = '2',y,NA,NA,NA,NA,NA +cur_his_stop_hrt_therapy,medical_history,NA,text,At what age did she stop HRT therapy?,NA,Number (age in years),number,1,100,NA,[cur_his_hrt_therapy] = '2',y,NA,NA,NA,NA,NA +cur_his_type_hrt,medical_history,NA,checkbox,What type of HRT has the participant used?,"1, Estrogen | 3, Estrogen/progesterone combination | 2, Progesterone | 4, Testosterone | 5, Natural Supplement | 66, Other Supplement",Check all that apply,NA,NA,NA,NA,[cur_his_hrt_therapy] = '1' or [cur_his_hrt_therapy] = '2',y,NA,NA,NA,NA,NA +cur_his_hrt_other,medical_history,NA,text,Describe other supplements:,NA,NA,NA,NA,NA,NA,[cur_his_type_hrt(66)] = '1',NA,NA,NA,NA,NA,NA +cur_his_symp_mens,medical_history,NA,radio,"Does the participant have or ever had menopausal symptoms, such as hot flashes or night sweats?","1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_age_symp_mens,medical_history,NA,text,How old was the participant when the first symptoms of hot flashes or night sweats began?,NA,Number (age in years),number,1,100,NA,[cur_his_symp_mens] = '1',y,NA,NA,NA,NA,NA +cur_his_unwant_hair,medical_history,NA,radio,Does the participant have unwanted facial or body hair growth?,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_preg,medical_history,NA,radio,Has the participant ever been pregnant?,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cur_his_pregnancies,medical_history,NA,text,How many pregnancies?,NA,NA,number,1,20,NA,[cur_his_preg] = '1',y,NA,NA,NA,NA,NA +cur_his_adverse_preg,medical_history,NA,checkbox,"During pregnancy, did the participant experience any of the following adverse pregnancy outcomes?","4, Eclampsia | 1, Gestational Diabetes | 2, Gestational Hypertension | 3, Pre-Eclampsia | 66, None of the above",Check all that apply,NA,NA,NA,NA,[cur_his_preg] = '1',y,NA,NA,NA,NA,"@NONEOFTHEABOVE=""66""" +cur_his_term_preg,medical_history,NA,checkbox,Length of pregnancy,"1, Full-term | 2, Pre-term | 99, N/A - did not give birth",check all that apply,NA,NA,NA,NA,[cur_his_preg] = '1',y,NA,NA,NA,NA,NA +cur_his_del_preg,medical_history,NA,checkbox,Type of delivery,"1, C-section | 2, Natural | 99, N/A - did not give birth",check all that apply,NA,NA,NA,NA,[cur_his_preg] = '1',y,NA,NA,NA,NA,NA +cur_his_covid,medical_history,COVID-19:,yesno,Have you tested positive for COVID-19?,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cath_inquiry,cardiac_catheterization,NA,radio,Has the participant had a Cardiac Catheterization within the past five years?,"1, Yes | 2, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cath_date,cardiac_catheterization,NA,text,Date of most recent Cardiac Catheterization: ,NA,NA,date_mdy,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_lm,cardiac_catheterization,Please complete based upon the participant's Cardiac Catheterization report: ,radio,Left Main (LM):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_lm_steno,cardiac_catheterization,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cath_inquiry] = '1' and [cath_lm] = '77',y,NA,NA,NA,NA,NA +cath_lad,cardiac_catheterization,NA,radio,Left Anterior Descending (LAD): ,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_lad_steno,cardiac_catheterization,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cath_inquiry] = '1' and [cath_lad] = '77',y,NA,NA,NA,NA,NA +cath_lad_diag,cardiac_catheterization,NA,radio,LAD Diagonal Branch(s):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_lad_diag_steno,cardiac_catheterization,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cath_inquiry] = '1' and [cath_lad_diag] = '77',y,NA,NA,NA,NA,NA +cath_lad_post,cardiac_catheterization,NA,radio,LAD Posterior Descending Branch (if present):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_lad_post_stenp,cardiac_catheterization,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cath_inquiry] = '1' and [cath_lad_post] = '77',y,NA,NA,NA,NA,NA +cath_lcx,cardiac_catheterization,NA,radio,Left Circumflex (LCx): ,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_lcx_post,cardiac_catheterization,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cath_inquiry] = '1' and [cath_lcx] = '77',y,NA,NA,NA,NA,NA +cath_lcx_ob,cardiac_catheterization,NA,radio,LCx Obtuse Marginal and/or Posterior LV Branch(s):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_lcx_ob_steno,cardiac_catheterization,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cath_inquiry] = '1' and [cath_lcx_ob] = '77',y,NA,NA,NA,NA,NA +cath_rca,cardiac_catheterization,NA,radio,Right Coronary Artery (RCA):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_rca_steno,cardiac_catheterization,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cath_inquiry] = '1' and [cath_rca] = '77',y,NA,NA,NA,NA,NA +cath_rca_post,cardiac_catheterization,NA,radio,RCA Posterior Descending Branch (if present):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cath_inquiry] = '1',y,NA,NA,NA,NA,NA +cath_rca_post_steno,cardiac_catheterization,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cath_inquiry] = '1' and [cath_rca_post] = '77',y,NA,NA,NA,NA,NA +elig_ejection_fraction,cardiac_catheterization,NA,radio,"Ejection Fraction, if known: ","1, < 50% | 2, 50%-60% | 3, >60% | 999, Unknown",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cath_text_lvef,cardiac_catheterization,NA,descriptive,"The LVEF can be from above study or most recent echo, cMRI or nuclear study",NA,NA,NA,NA,NA,NA,[cath_inquiry] = '1',NA,NA,NA,NA,NA,NA +cath_upload,cardiac_catheterization,NA,file,Please upload redacted document,NA,NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cta_inquiry,coronary_ct_angiogram,NA,radio,Has the participant had a coronary CTA within the past five years?,"1, Yes | 2, No",NA,NA,NA,NA,NA,NA,y,NA,NA,NA,NA,NA +cta_date,coronary_ct_angiogram,NA,text,Date of most recent Coronary Angiogram: ,NA,NA,date_mdy,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_lm,coronary_ct_angiogram,Please complete based upon the participant's CTA report: ,radio,Left Main (LM):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_lm_steno,coronary_ct_angiogram,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cta_inquiry] = '1' and [cta_lm] = '77',y,NA,NA,NA,NA,NA +cta_lad,coronary_ct_angiogram,NA,radio,Left Anterior Descending (LAD): ,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_lad_steno,coronary_ct_angiogram,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cta_inquiry] = '1' and [cta_lad] = '77',y,NA,NA,NA,NA,NA +cta_lad_diag,coronary_ct_angiogram,NA,radio,LAD Diagonal Branch(s):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_lad_diag_steno,coronary_ct_angiogram,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cta_inquiry] = '1' and [cta_lad_diag] = '77',y,NA,NA,NA,NA,NA +cta_lad_post,coronary_ct_angiogram,NA,radio,LAD Posterior Descending Branch (if present):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_lad_post_steno,coronary_ct_angiogram,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cta_inquiry] = '1' and [cta_lad_post] = '77',y,NA,NA,NA,NA,NA +cta_lcx,coronary_ct_angiogram,NA,radio,Left Circumflex (LCx): ,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_lcx_steno,coronary_ct_angiogram,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cta_inquiry] = '1' and [cta_lcx] = '77',y,NA,NA,NA,NA,NA +cta_lcx_ob,coronary_ct_angiogram,NA,radio,LCx Obtuse Marginal and/or Posterior LV Branch(s):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_lcx_ob_steno,coronary_ct_angiogram,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cta_inquiry] = '1' and [cta_lcx_ob] = '77',y,NA,NA,NA,NA,NA +cta_rca,coronary_ct_angiogram,NA,radio,Right Coronary Artery (RCA):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_rca_steno,coronary_ct_angiogram,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cta_inquiry] = '1' and [cta_rca] = '77',y,NA,NA,NA,NA,NA +cta_rca_post,coronary_ct_angiogram,NA,radio,RCA Posterior Descending Branch (if present):,"1, Normal defined as no irregularities and 0% diameter reduction. | 2, Minor irregularities but < 20% diameter reduction. | 77, ___ % stenosis but < 50%. | 3, Not Done",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_rca_post_steno,coronary_ct_angiogram,NA,text,Percentage of stenosis: ,NA,percent,integer,20,49,NA,[cta_inquiry] = '1' and [cta_rca_post] = '77',y,NA,NA,NA,NA,NA +elig_ejection_fraction_2,coronary_ct_angiogram,NA,radio,Ejection Fraction if known: ,"1, < 50% | 2, 50%-60% | 3, >60% | 999, Unknown",NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +cta_text_lvef,coronary_ct_angiogram,NA,descriptive,"The LVEF can be from above study or most recent echo, cMRI or nuclear study",NA,NA,NA,NA,NA,NA,[cta_inquiry] = '1',NA,NA,NA,NA,NA,NA +cta_upload,coronary_ct_angiogram,NA,file,Please upload redacted document,NA,NA,NA,NA,NA,NA,[cta_inquiry] = '1',y,NA,NA,NA,NA,NA +ecg_results,other_imagingtests,NA,notes,ECG results (10 sec ECG),NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +ecg_report,other_imagingtests,NA,file,ECG (report),NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +stress_test_results,other_imagingtests,NA,notes,Stress test raw data ,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +stress_test_report,other_imagingtests,NA,file,Stress test report,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +amb_monitoring_results,other_imagingtests,NA,notes,Ambulatory monitoring (Holter and/ or patch) raw data ,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +amb_monitoring_report,other_imagingtests,NA,file,Ambulatory monitoring (Holter and/ or patch) report,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_sessions_total,document_prescribed_cr_visits,NA,text,What is the total number of prescribed CR sessions? ,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_sessions_insurance,document_approved_cr_sessions_by_insurance,NA,text,Total of CR sessions approved by insurance,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +ssc_q1,study_subject_certification,NA,radio,I have received the Bloomer TAG Instruction For Use/ Manual,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q2,study_subject_certification,NA,radio,I understand how to wear the Bloomer TAG,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q3,study_subject_certification,NA,radio,I understand how to connect the Bloomer TAG with my phone/ study phone,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q4,study_subject_certification,NA,radio,I understand how to open the Bloomer app and how to keep it running in the background all the time,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q5,study_subject_certification,NA,radio,I understand how to tag a symptom/ an activity to share later with my clinician,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q6,study_subject_certification,NA,radio,I understand how to sync the recorded data so it gets uploaded to the secure server,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q7,study_subject_certification,NA,radio,I understand that I need to wear the Bloomer TAG at least 3 hours around each exercise session and every time I come for the CR visits,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q8,study_subject_certification,NA,radio,I understand that I will be collecting more valuable personalized data if I wear the Bloomer TAG beyond the requested hours and even during my sleep I understand that I need to change the battery every 7 days,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q9,study_subject_certification,NA,radio,I understand that I shouldn't wear it in the shower,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q10,study_subject_certification,NA,radio,I understand how I can wipe clean the Bloomer TAG,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q11,study_subject_certification,NA,radio,I understand that I need to store the Bloomer TAG in its original package when not in use,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_q12,study_subject_certification,NA,radio,Bloomer TAG is an investigational medical device and it is my responsibility to take care of it and return it with all other components upon study termination,"1, Yes | 0, No",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +ssc_signature,study_subject_certification,NA,file,Study Subject signature:,NA,NA,signature,NA,NA,y,NA,y,LV,NA,NA,NA,NA +ssc_date,study_subject_certification,NA,text,Today's Date,NA,NA,date_mdy,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +cr_start_time,cr_session,CR session,text,Start Time,NA,NA,datetime_mdy,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_stop_time,cr_session,NA,text,Stop Time,NA,NA,datetime_mdy,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_heart_rate_prior,cr_session,Prior to Exercising,text,Heart rate,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_bp_systolic_prior,cr_session,NA,text,Systolic Blood pressure,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_bp_diastolic_prior,cr_session,NA,text,Diastolic Blood pressure,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_heart_rate_peak,cr_session,During exercises (at the peak),text,Heart rate,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_bp_systolic_peak,cr_session,NA,text,Systolic Blood pressure,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_bp_diastolic_peak,cr_session,NA,text,Diastolic Blood pressure,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_heart_rate_after,cr_session,After completing the exercises: ,text,Heart rate,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_bp_systolic_after,cr_session,NA,text,Systolic Blood pressure,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +cr_bp_diastolic_after,cr_session,NA,text,Diastolic Blood pressure,NA,NA,integer,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +em_header,cr_session, ,descriptive,"
Exercise modalities Order of the exercise modalities (1st, 2nd, etc.) Duration (in minutes)
Bike {bike_order} {bike_duration}
Treadmill {treadmill_order} {treadmill_duration}
Weight lifting {weight_lifting_order} {weight_lifting_duration}
Other: {other_specify} {other_order} {other_duration}
",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +bike_order,cr_session,NA,dropdown,Bike intensity,"1, 1st | 2, 2nd | 3, 3rd | 4, 4th | 5, 5th | 6, 6th",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +bike_duration,cr_session,NA,text,Bike duration,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +treadmill_order,cr_session,NA,dropdown,Treadmill intensity,"1, 1st | 2, 2nd | 3, 3rd | 4, 4th | 5, 5th | 6, 6th",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +treadmill_duration,cr_session,NA,text,Treadmill duration,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +weight_lifting_order,cr_session,NA,dropdown,Weight lifting intensity,"1, 1st | 2, 2nd | 3, 3rd | 4, 4th | 5, 5th | 6, 6th",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +weight_lifting_duration,cr_session,NA,text,Weight lifting duration,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +other_specify,cr_session,NA,text,Specify other,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +other_order,cr_session,NA,dropdown,Other intensity,"1, 1st | 2, 2nd | 3, 3rd | 4, 4th | 5, 5th | 6, 6th",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +other_duration,cr_session,NA,text,Other duration,NA,NA,number,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +session_complete,cr_session,NA,yesno,Was the subject able to complete the session?,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +session_complete_no_reason,cr_session,NA,text,Specify why not:,NA,NA,NA,NA,NA,NA,[session_complete] = '0',NA,NA,NA,NA,NA,NA +cr_complaints,cr_session,NA,notes,Record below any clinical symptoms or complaints during the session ,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +exercises_at_home,cr_session,NA,yesno,Was the subject recommended to do at-home exercises?,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +exercises_at_home_specify,cr_session,NA,notes,"If yes, specify",NA,NA,NA,NA,NA,NA,[exercises_at_home] = '1',NA,NA,NA,NA,NA,NA +pues_date,participants_user_experience_survey,NA,text,Today's date,NA,NA,date_mdy,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +pues_q1,participants_user_experience_survey,NA,text,1) What is your favorite feature in the Bloomer TAG platform?,NA,NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +pues_q2,participants_user_experience_survey,NA,text,2) What are other important features that you'd like to see in the future Bloomer TAG designs? ,NA,NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +pues_q3,participants_user_experience_survey,NA,radio,"3) Based on your CR experience, would you recommend the Bloomer TAG Platform for other patients or friends to support their CR journey?","1, I would highly recommend it | 2-, I would recommend it | 3, Neutral | 4, I would not recommend it | 5, I would strongly not recommend it",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +pues_q4,participants_user_experience_survey,NA,radio,4) Do you feel wearing the Bloomer TAG while exercising helped in managing any undesired anxiety?,"1, Yes, helpful | 2, Neutral | 3, Not helpful",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +pues_q5,participants_user_experience_survey,NA,checkbox,5) Which one/ ones of the following statements best describes your experience with the Bloomer TAG Platform. Select all that apply.,"1, Wearing the Bloomer TAG product made me feel assured and supervised | 2, The Bloomer TAG product helped in validating my efforts and supported me to reach my daily goals | 3, The Bloomer TAG Platform helped me in tracking important signs, symptoms, and activities | 4, Others (specify): {pues_q6_other} | 0, None of the above",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,@NONEOFTHEABOVE='0' +pues_q6_other,participants_user_experience_survey,NA,text,Specify other:,NA,NA,NA,NA,NA,NA,[pues_q5(4)] = '1',y,LV,NA,NA,NA,NA +crbs_q1,cardiac_rehabilitation_barriers_scale_crbs,"The following questions ask about some of the factors influencing your attendance at cardiac rehabilitation sessions. Please answer all of the questions on this page regardless of whether you attended or did not attend a cardiac rehabilitation program. + +I did not attend a cardiac rehabilitation program, or if I did attend, I missed some sessions because:",radio,"1) ...of distance (e.g., not located in your area, too far to travel)","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q2,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"2) ...of cost (e.g., parking, gas)","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q3,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"3) ...of transportation problems (e.g., access to car, public transportation)","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q4,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"4) ...of family responsibilities (e.g., caregiving)","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q5,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"5) ...I didn't know about cardiac rehab (e.g., doctor didn't tell me about it)","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q6,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"6) ...I don't need cardiac rehab (e.g., feel well, heart problems treated, not serious)","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q7,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"7) ...I already exercise at home, or in my community","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q8,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,8) ...severe weather,"1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q9,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,9) ...I find exercise tiring or painful,"1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q10,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"10) ...travel (e.g., holidays, business, cottage)","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q11,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"11) ...of time constraints (e.g., too busy, inconvenient class time)","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q12,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,12) ...of work responsibilities,"1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q13,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,13) ...I don't have the energy,"1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q14,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"14) ...other health problems prevent me from going (if so, specify): {crbs_q14_spec}","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,NA,LV,NA,NA,NA,NA +crbs_q14_spec,cardiac_rehabilitation_barriers_scale_crbs,NA,text,Specify,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +crbs_q15,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,15) ...I am too old,"1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q16,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,16) ...my doctor did not feel it was necessary,"1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q17,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"17) ...many people with heart problems don't go, and they are fine","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q18,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,18) ...I can manage my heart problem on my own,"1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q19,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"19) ...I think I was referred, but the rehab program didn't contact me","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q20,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,20) ...it took too long to get referred and into the program,"1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q21,cardiac_rehabilitation_barriers_scale_crbs,NA,radio,"21) ...I prefer to take care of my health alone, not in a group","1, Strongly Disagree | 2, Disagree | 3, Neither Agree or Disagree | 4, Agree | 5, Strongly Agree",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +crbs_q22,cardiac_rehabilitation_barriers_scale_crbs,NA,text,22) Other reason(s) for not attending a cardiac rehabilitation program:,NA,NA,NA,NA,NA,NA,NA,NA,LV,NA,NA,NA,NA +crbs_score,cardiac_rehabilitation_barriers_scale_crbs,NA,calc,CRBS score,"sum([crbs_q1],[crbs_q2],[crbs_q3],[crbs_q4],[crbs_q5],[crbs_q6],[crbs_q7],[crbs_q8],[crbs_q9],[crbs_q10],[crbs_q11],[crbs_q12],[crbs_q13],[crbs_q14],[crbs_q15],[crbs_q16],[crbs_q17],[crbs_q18],[crbs_q19],[crbs_q20],[crbs_q21])",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,@HIDDEN-SURVEY +htues_q1,healthcare_team_user_experience_survey,NA,radio,1) How would you rate your experience with using the Bloomer TAG platform as an aid device to collect heart-related physiological data from the study participants ,"1, Very dissatisfied | 2, Dissatisfied | 3, Neutral | 4, Satisfied | 5, Very satisfied",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +htues_q2,healthcare_team_user_experience_survey,NA,radio,2) How would you rate the importance/ significance of Bloomer TAG sensors' readouts?,"1, Poor | 2, Fair | 3, Good | 4, Very Good | 5, Excellent",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +htues_q3,healthcare_team_user_experience_survey,NA,radio,3) What other physiological data would you suggest adding it to the Bloomer report?,"1, Arrhythmia detection | 2, Food intake | 3, Period detector | 4, Hydrated/ dehydrated | 5, Hemodynamic readouts | 6, None of the above | 88, Others (specify)",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +htues_q3_other,healthcare_team_user_experience_survey,NA,text,3a) Specify other(s),NA,NA,NA,NA,NA,NA,[htues_q3] = '88',y,LV,NA,NA,NA,NA +htues_q4,healthcare_team_user_experience_survey,NA,yesno,4) Would you recommend employing the Bloomer TAG platform as a data collection device in other clinical trials to support the continuous collection of physiological data?,NA,NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,NA +htues_q4_reason,healthcare_team_user_experience_survey,NA,notes,4a) Why did you answer [htues_q4]?,NA,NA,NA,NA,NA,NA,[htues_q4] = '1' or [htues_q4] = '0',y,LV,NA,NA,NA,NA +htues_q5,healthcare_team_user_experience_survey,NA,checkbox,"5) If given the same data report, would you prefer the Bloomer TAG platform for your female patients over any of the following? (select all that apply)","1, Traditional Holter | 2, Extended Holter (i.e Zio patch, bardydx, etc) | 3, Mobile Cardiac Telemetry MCT (i.e Zio AT) | 4, Event monitor | 5, Implantable Loop recorder | 0, None | 88, Others (specify below)",NA,NA,NA,NA,NA,NA,y,LV,NA,NA,NA,@NONEOFTHEABOVE='0' +htues_q5_other,healthcare_team_user_experience_survey,NA,text,Specify other(s),NA,NA,NA,NA,NA,NA,[htues_q5(88)] = '1',y,LV,NA,NA,NA,NA +cr_visits_completed,study_conclusion,NA,yesno,Has the subject completed all CR visits?,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +date_of_study_completion,study_conclusion,NA,text,Date of study completion,NA,NA,date_mdy,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +date_of_early_withdrawal,study_conclusion,NA,text,Date of early withdrawal,NA,NA,date_mdy,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +date_of_last_clinic_visit,study_conclusion,NA,text,Date of last clinic visit,NA,NA,date_mdy,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA +early_withdrawal_reason,study_conclusion,NA,radio,Reason for early withdrawal. Please record only ONE PRIMARY reason for withdrawal:,"1, Pregnancy | 2, Adverse events (please ensure that Adverse event form is completed) | 3, Withdrawal of consent | 4, Death (please ensure that Adverse event form is completed) | 5, Lost to follow-up | 6, Lack of compliance with the protocol | 7, Administrative reasons",NA,NA,NA,NA,NA,NA,NA,LV,NA,NA,NA,NA diff --git a/tests/testthat/test-get_long_categorical_field_response_values.R b/tests/testthat/test-get_long_categorical_field_response_values.R new file mode 100644 index 0000000..7ff1534 --- /dev/null +++ b/tests/testthat/test-get_long_categorical_field_response_values.R @@ -0,0 +1,27 @@ +long_categorical_field_responses <- readRDS( + testthat::test_path("get_long_categorical_field_response_values", "input.rds") +) + +output <- get_long_categorical_field_response_values(long_categorical_field_responses) + +testthat::test_that("get_long_categorical_field_response_values: ethnicity, occupation, race, and state are represented", { + testthat::expect_true(all.equal( + output |> + dplyr::filter(field_name %in% c("ethnicity", "occupation", "race", "state")) |> + dplyr::arrange(field_name) |> + dplyr::pull(field_name), + c("ethnicity", "occupation", "race", "state") + )) +}) + +testthat::test_that("get_long_categorical_field_response_values: bl_caffeine, bl_exercise, and bl_treatments are represented", { + testthat::expect_true(all.equal( + output |> + dplyr::filter(stringr::str_detect(field_name, "bl_caffeine|bl_exercise|bl_treatments")) |> + dplyr::mutate(field_group = stringr::str_replace(field_name, "___.*", "")) |> + dplyr::distinct(field_group) |> + dplyr::arrange(field_group) |> + dplyr::pull(field_group), + c("bl_caffeine", "bl_exercise", "bl_treatments") + )) +}) diff --git a/tests/testthat/test-get_long_categorical_field_responses.R b/tests/testthat/test-get_long_categorical_field_responses.R new file mode 100644 index 0000000..9afbe0d --- /dev/null +++ b/tests/testthat/test-get_long_categorical_field_responses.R @@ -0,0 +1,40 @@ +metadata_file <- testthat::test_path("get_long_categorical_field_responses", "metadata.csv") +metadata <- readr::read_csv(metadata_file) + +output <- get_long_categorical_field_responses(metadata) + +testthat::test_that("get_long_categorical_field_responses: processes only checkbox, dropdown, and radio", { + testthat::expect_equal( + output |> + dplyr::distinct(field_type) |> + dplyr::arrange(field_type) |> + dplyr::pull(field_type), + c("checkbox", "dropdown", "radio") + ) +}) + +testthat::test_that("get_long_categorical_field_responses: checkbox responses are all 1", { + testthat::expect_equal(output |> + dplyr::filter(field_type == "checkbox") |> + dplyr::distinct(response_code) |> + dplyr::pull(response_code), "1") +}) + +testthat::test_that("get_long_categorical_field_responses: non-checkbox responses are distinct within each field", { + testthat::expect_equal(output |> + dplyr::filter(field_type != "checkbox") |> + dplyr::group_by(field_name) |> + dplyr::count(response_code) |> + dplyr::ungroup() |> + dplyr::distinct(n) |> + dplyr::pull(n), 1) +}) + +testthat::test_that("get_long_categorical_field_responses: weights are balanced", { + testthat::expect_true(output |> + dplyr::group_by(field_group) |> + dplyr::summarise(balanced = (min(weight) == max(weight))) |> + dplyr::ungroup() |> + dplyr::distinct(balanced) |> + dplyr::pull(balanced)) +}) diff --git a/tests/testthat/test-get_one_rectangle_of_values.R b/tests/testthat/test-get_one_rectangle_of_values.R new file mode 100644 index 0000000..215fb7b --- /dev/null +++ b/tests/testthat/test-get_one_rectangle_of_values.R @@ -0,0 +1,29 @@ +long_categorical_field_responses <- readRDS( + testthat::test_path("get_long_categorical_field_response_values", "input.rds") +) + +output <- get_one_rectangle_of_values( + one_record_id = 1, + record_id_name = "record_id", + forms_to_fill = "tests", + long_categorical_field_responses +) + +output_with_special_record_id <- get_one_rectangle_of_values( + one_record_id = 1, + record_id_name = "special_id", + forms_to_fill = "tests", + long_categorical_field_responses +) + +testthat::test_that("get_one_rectangle_of_values: ethnicity, occupation, race, and state are represented in the columns", { + testthat::expect_true(all(c("record_id", "ethnicity", "occupation", "race", "state") %in% names(output))) +}) + +testthat::test_that("get_one_rectangle_of_values: bl_caffeine, bl_exercise, and bl_treatments are represented in the columns", { + testthat::expect_true(all(c("bl_caffeine", "bl_exercise", "bl_treatments") %in% gsub("___.*", "", names(output)))) +}) + +testthat::test_that("get_one_rectangle_of_values: special_id is in the record_id position", { + testthat::expect_equal(names(output_with_special_record_id)[[1]], "special_id") +})