diff --git a/NEWS.md b/NEWS.md index 41addc59..74ad1052 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # haven (development version) +* Fix bug in string variable width calculation that treated `NA` values as width + 2. `NA` values are now treated as blanks for width calculations (#699). + # haven 2.5.1 * All `labelled()` vectors now have left-aligned column headers when printing diff --git a/src/DfWriter.cpp b/src/DfWriter.cpp index a9a07ab5..562c0ada 100644 --- a/src/DfWriter.cpp +++ b/src/DfWriter.cpp @@ -19,6 +19,14 @@ inline const bool string_is_missing(SEXP x, int i) { return STRING_ELT(x, i) == NA_STRING; } +inline const int string_len_missing(SEXP x, int i) { + if (string_is_missing(x, i)) { + return 0; + } else { + return strlen(string_utf8(x, i)); + } +} + inline readstat_measure_e measureType(SEXP x) { if (Rf_inherits(x, "ordered")) { @@ -366,7 +374,7 @@ class Writer { int user_width = userWidth(x); int max_length = 1; for (int i = 0; i < x.size(); ++i) { - int length = strlen(string_utf8(x, i)); + int length = string_len_missing(x, i); if (length > max_length) max_length = length; } diff --git a/tests/testthat/_snaps/haven-sas.md b/tests/testthat/_snaps/haven-sas.md index 8f4e73d1..bfd55dd6 100644 --- a/tests/testthat/_snaps/haven-sas.md +++ b/tests/testthat/_snaps/haven-sas.md @@ -6,3 +6,11 @@ Error: ! Failed to create file: A provided name contains an illegal character. +# user width warns appropriately when data is wider than value + + Code + write_xpt(df, path) + Condition + Warning: + Column `b` contains string values longer than user width 1. Width set to 2 to accommodate. + diff --git a/tests/testthat/test-haven-sas.R b/tests/testthat/test-haven-sas.R index 1cc88223..003930f3 100644 --- a/tests/testthat/test-haven-sas.R +++ b/tests/testthat/test-haven-sas.R @@ -274,3 +274,15 @@ test_that("can roundtrip format attribute", { expect_identical(df, out) }) + +test_that("user width warns appropriately when data is wider than value", { + df <- tibble( + a = c("a", NA_character_), + b = c("b", "NA"), + ) + attr(df$a, "width") <- 1 + attr(df$b, "width") <- 1 + + path <- tempfile() + expect_snapshot(write_xpt(df, path)) +})