Search code examples
rtestthat

How to change LC_COLLATE=C globally for all tests in testhat?


Added some time later: we now choose to option 2 from here instead of changing the test. Looking back, cross-platform reproducibility is more important ;-)


As described here, the sort logics changed. My question is, how I could make the following test pass on a LC_COLLATE=German_Switzerland.1252?

Reproducible example: create a package, call it testsort, add test-environment using usethis::use_testthat() and add a file "test-sort.R" in /testsort/tests/testthat/

test_that("test sort", {
  xx <- c("Schaffhausen", "Schwyz", "Seespital", "SRZ")
  expect_equal(sort(xx), c("Schaffhausen", "Schwyz", "Seespital", "SRZ")) # fails with new sort
})

Backround: We have many projects where we always work on LC_COLLATE=German_Switzerland.1252 and do sorting / comparing of German names, see also here. In our logics "R" is after "c" and we would like to test, what we have / expect in our projects, thus the question. Furthermore, we would like to minimize dependencies on other package, e.g. avoid the use of stringr::str_sort(, locale = ...), if possible.


It seems the crucial part happens only, when testthat/ testthat::test_dir is called:

withr::with_collate("C", # new code
                    withr::with_options(c(useFancyQuotes = FALSE), # new code
                                        withr::with_envvar(c(r_env_vars(), TESTTHAT_PKG = pkg$package), # code
                                                           do.call(testthat::test_dir, testthat_args))))

From the docs:

Temporarily change collation order by changing the value of the LC_COLLATE locale.
Usage with_collate(new, code)

Temporarily change global options.
Usage with_options(new, code)

Temporarily change system environment variables.
Usage with_envvar(new, code, action = "replace")


Solution

  • What about

    test_that("test sort", {
      # capture current locale
      locale <- Sys.getlocale("LC_COLLATE")
    
      # set desired locale for test (eg English)
      if (.Platform$OS.type == "windows") {
        invisible(Sys.setlocale("LC_COLLATE", "English")) 
      } else {
        invisible(Sys.setlocale("LC_COLLATE", "en_US.UTF-8")) 
      }
      
      # run test 
      xx <- c("Schaffhausen", "Schwyz", "Seespital", "SRZ")
      expect_equal(sort(xx), c("Schaffhausen", "Schwyz", "Seespital", "SRZ")) 
    
      # return to original locale  
      invisible(Sys.setlocale("LC_COLLATE", locale))
    })