Skip to content

Commit

Permalink
Handle trailing newline in REDCap checkbox options
Browse files Browse the repository at this point in the history
fixes OuhscBbmc#501

- Modified pattern_checkboxes regular expression to allow for case where
  there is no space in front of the pipe character in the Lookbehind and
  Lookahead expressions, and allow the space(s) after the comma to be
  optional.

- Created test case to verify correct handling when a checkbox options
  has a trailing newline.

- Created test case to verify correct handling when the space is missing
  after the comma for an option.
  • Loading branch information
BlairCooper committed Jul 15, 2023
1 parent 1bdde82 commit 0cc2f24
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 1 deletion.
20 changes: 19 additions & 1 deletion R/metadata-utilities.R
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,25 @@ regex_named_captures <- function(pattern, text, perl = TRUE) {
checkbox_choices <- function(select_choices) {
checkmate::assert_character(select_choices, any.missing=FALSE, len=1, min.chars=1)

pattern_checkboxes <- "(?<=\\A| \\| |\\| )(?<id>\\d{1,}), (?<label>[^|]{1,}?)(?= \\| |\\| |\\Z)"
# Pattern consists of four capture groups:
# (?<=\\A| \\| |\\| | \\|) :
# At the start of a string (\A) OR
# A space, a pipe and a space ( \| ) OR
# A pipe and a space (\| ) OR
# A space and a pipe ( \|)
# (?<id>\\d{1,}) :
# A named (id) capture of one or more decimals
# , ? :
# A comma followed by 0 or more spaces
# (?<label>[^|]{1,}?) :
# A named (label) capture one or more characters that aren't a pipe
# (lazily captured to avoid grabbing a space a the end)
# (?= \\| |\\| | \\||\\Z)
# A space, a pipe and a space ( \| ) OR
# A pipe and a space (\| ) OR
# A space and a pipe ( \|) OR
# At the end of a string (\Z)
pattern_checkboxes <- "(?<=\\A| \\| |\\| | \\|)(?<id>\\d{1,}), ?(?<label>[^|]{1,}?)(?= \\| |\\| | \\||\\Z)"

regex_named_captures(pattern = pattern_checkboxes, text = select_choices)
}
65 changes: 65 additions & 0 deletions tests/testthat/test-metadata-utilities.R
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,68 @@ test_that("checkbox choices with errant space", {
expect_equal(ds_boxes, expected=ds_expected, label="The returned data.frame should be correct")
expect_s3_class(ds_boxes, "tbl")
})

###############################################################################
# Test case where a trailing newline at the end of checkbox options results in
# the choices string containing a blank option at the end.
#
# Options set in REDCap, note leading space on option 3
# 1, PCM
# 2, NCM
# 3, BH
# 4, OPT
# (blank line here)
#
# Previous behavior would result in option 4 missing.
#
# Seen specifically in REDCap 13.7.5 but likely the same behavior in other
# REDCap versions
###############################################################################
test_that("checkbox choices with errant newline at end", {
choices_1 <- "1, PCM | 2, NCM | 3, BH | 4, OPT |"
ds_boxes <- checkbox_choices(select_choices=choices_1)

ds_expected <- structure(
list(
id = c("1", "2", "3", "4"),
label = c("PCM", "NCM", "BH", "OPT")
),
class = c("tbl_df", "tbl", "data.frame"),
row.names = c(NA, -4L)
)

expect_equal(ds_boxes, expected=ds_expected, label="The returned data.frame should be correct")
expect_s3_class(ds_boxes, "tbl")
})

###############################################################################
# Test case where missing space after the comma results in the option being
# omitted.
#
# Options set in REDCap, note missing space on option 2
# 1, 1
# 2,2
# 3, 3
# 4, 4
#
# Previous behavior would result in option 2 missing.
#
# Seen specifically in REDCap 13.7.5 but likely the same behavior in other
# REDCap versions
###############################################################################
test_that("checkbox choices with missing space after comma", {
choices_1 <- "1, 1 | 2,2 | 3, 3 | 4, 4"
ds_boxes <- checkbox_choices(select_choices=choices_1)

ds_expected <- structure(
list(
id = c("1", "2", "3", "4"),
label = c("1", "2", "3", "4")
),
class = c("tbl_df", "tbl", "data.frame"),
row.names = c(NA, -4L)
)

expect_equal(ds_boxes, expected=ds_expected, label="The returned data.frame should be correct")
expect_s3_class(ds_boxes, "tbl")
})

0 comments on commit 0cc2f24

Please sign in to comment.