Breaking changes
to_df()andto_lst()now error if extra arguments are passed in.... Previously, these extra arguments were silently discarded (#200).to_chr()now converts named functions to a string representing their name instead of erroring. Package functions are returned as"pkg::fn"(e.g.,to_chr(mean)returns"base::mean"). Anonymous functions still produce an informative error. This behavior extends toto_chr_scalar(),stabilize_chr(), andstabilize_chr_scalar()(#251).
New functions
- New
pkg_inform()andpkg_warn()signal classed messages and warnings, respectively, with an opinionated class hierarchy, mirroringpkg_abort(). Newexpect_pkg_message_classes()andexpect_pkg_warning_classes()test that the expected classes are thrown, andexpect_pkg_message_snapshot()andexpect_pkg_warning_snapshot()snapshot-test the full output in one step (#213). - New function
to()coercesxto the type of its.toargument.stbl_to()is also registered as a C callable in a new public C API (#182). - New
to_fn(),are_fn_ish(), andis_fn_ish()add thefntype family to stbl.to_fn()coerces strings and symbols to functions.is_fn_ish()checks whether a single object can be safely coerced to a function.are_fn_ish()checks each element of a character vector for syntactic fn-ishness (bare name or"pkg::fn"form) (#250).
Bug fixes
expect_pkg_error_snapshot(),expect_pkg_message_snapshot(), andexpect_pkg_warning_snapshot()now produce stable snapshots when run underdevtools::test_coverage_active_file().specify_cls()and relatedspecify_*()functions now also produce stable function-body snapshots under coverage (#253).expect_pkg_message_classes()andexpect_pkg_warning_classes()now support assignments insideobject(e.g.result <- fn_that_warns()).expect_pkg_message_snapshot()andexpect_pkg_warning_snapshot()inherit the same fix (#234).
Other changes
are_*_ish(),to_*(),stabilize_dbl(), andstabilize_int()are all significantly faster for large vectors, with benchmarks showing roughly 3–20× throughput improvements (#217, #218, #219, #220, #221, #226, #239).- The
are_*_ish(),to_*(), and range-check functions are now registered as C callables, as are the*_to_chrand*_to_fctfamilies (stbl_chr_to_fct(),stbl_dbl_to_chr(),stbl_dbl_are_chrish(),stbl_fct_to_chr(),stbl_fct_are_chrish(),stbl_int_to_chr(),stbl_int_are_chrish(),stbl_int_to_fct(),stbl_lgl_to_chr(), andstbl_lgl_are_chrish()) (#235, #237, #241). is_fct_ish()now accepts amax_levelsargument to limit the number of unique non-NAlevels (#231).
{qcthat} Reports
Milestone
✅ A qcthat issue test matrix with 1 milestone, 18 issues, and 262 tests
└─█─Milestone: v0.4.0 (18 issues, 262 tests)
├─☑️─Bug 253: `expect_pkg_error_snapshot()` vs coverage
│ ├─✅─.is_covr_count_call() identifies covr counter calls (#253)
│ └─✅─.strip_covr_from_expr() removes covr counter wrappers (#253)
├─☑️─Task 226: chore: complete C optimization for are_*_ish() and to_*() methods
│ ├─✅─.dbl_to_lgl() converts 0 to FALSE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() converts non-zero to TRUE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() passes NA and NaN through; valid always TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() handles integer input; valid always TRUE (#226, #237)
│ ├─✅─.int_to_dbl() converts integers to doubles; valid always TRUE (#226, #237)
│ ├─✅─.int_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.int_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts TRUE to 1.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts FALSE to 0.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lgl_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts TRUE to 1L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts FALSE to 0L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.cpx_to_dbl() extracts real part when Im is zero (#226, #237)
│ ├─✅─.cpx_to_dbl() passes NA complex through as NA_real; valid TRUE (#226, #237)
│ ├─✅─.cpx_to_dbl() returns real part and valid FALSE for non-zero Im (#226, #237)
│ ├─✅─.cpx_to_int() converts whole-number complex with Im 0 (#226, #237)
│ ├─✅─.cpx_to_int() passes NA complex through; flags FALSE (#226, #237)
│ ├─✅─.cpx_to_int() marks non-zero Im as non_number (#226, #237)
│ ├─✅─.cpx_to_int() marks fractional real part as bad_precision (#226, #237)
│ ├─✅─.fct_to_dbl() converts numeric factor levels to doubles (#226, #237)
│ ├─✅─.fct_to_dbl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_dbl() marks non-numeric levels as not valid (#226, #237)
│ ├─✅─.fct_to_int() converts whole-number factor levels to integers (#226, #237)
│ ├─✅─.fct_to_int() passes NA factor element through; flags FALSE (#226, #237)
│ ├─✅─.fct_to_int() marks non-integer levels correctly (#226, #237)
│ ├─✅─.fct_to_lgl() converts TRUE/FALSE levels (#226, #237)
│ ├─✅─.fct_to_lgl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_lgl() marks non-logical levels as not valid (#226, #237)
│ ├─✅─.chr_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.chr_are_fctish() checks membership in levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats to_na values as fctish (#226, #237)
│ ├─✅─.fct_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.fct_are_fctish() checks factor level membership in target levels (#226, #237)
│ ├─✅─.fct_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.lst_to_dbl() converts a flat list of numeric/lgl/int scalars (#226, #237)
│ ├─✅─.lst_to_dbl() converts numeric character strings (#226, #237)
│ ├─✅─.lst_to_dbl() marks non-parseable character strings as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts complex with Im == 0 (#226, #237)
│ ├─✅─.lst_to_dbl() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts a flat list of integer/logical scalars (#226, #237)
│ ├─✅─.lst_to_int() converts whole-number doubles (#226, #237)
│ ├─✅─.lst_to_int() converts integer-valued character strings (#226, #237)
│ ├─✅─.lst_to_int() marks fractional character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-number character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts complex with Im == 0 and whole Re (#226, #237)
│ ├─✅─.lst_to_int() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() marks fractional doubles as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts a flat list of lgl/int/dbl scalars (#226, #237)
│ ├─✅─.lst_to_lgl() converts lgl-ish character strings (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-lgl character strings as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_chr() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() converts non-character atomic scalars to strings (#226, #237, #239)
│ ├─✅─.lst_to_chr() converts factor elements via their level labels (#226, #237, #239)
│ ├─✅─.lst_to_chr() marks non-character single-element vectors as not valid (#226, #237)
│ ├─✅─.lst_to_chr() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_fct() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() marks non-character scalars as not valid (#226, #237)
│ ├─✅─.lst_to_fct() marks factor elements as valid (#226, #237)
│ ├─✅─.lst_to_fct() marks non-character/factor single-element vectors as not valid (#226, #237)
│ └─✅─.lst_to_fct() marks non-scalar elements in multi-element lists as not valid (#226, #237)
├─☑️─Issue 221: C optimization: .are_not_dbl_ish_chr() — single-pass character-to-double failure detector
│ ├─✅─.chr_to_dbl() converts numeric strings (#221, #237)
│ ├─✅─.chr_to_dbl() converts Inf strings (#221, #237)
│ ├─✅─.chr_to_dbl() passes NA through as valid (#221, #237)
│ └─✅─.chr_to_dbl() marks invalid strings as not valid (#221, #237)
├─☑️─Task 220: C optimization: .find_failures() / %&&% — inline min/max range checks
│ ├─✅─.check_min_dbl() returns NULL when all values pass (#220)
│ ├─✅─.check_min_dbl() returns failure indices for values below min (#220)
│ ├─✅─.check_min_dbl() treats NA as passing (#220)
│ ├─✅─.check_min_dbl() handles integer input (#220)
│ ├─✅─.check_max_dbl() returns NULL when all values pass (#220)
│ ├─✅─.check_max_dbl() returns failure indices for values above max (#220)
│ ├─✅─.check_max_dbl() treats NA as passing (#220)
│ └─✅─.check_max_dbl() handles integer input (#220)
├─☑️─Issue 219: C optimization: are_int_ish.character() / to_int.character() — single-pass C checker
│ ├─✅─.chr_to_int() converts integer strings (#219, #237)
│ ├─✅─.chr_to_int() converts whole-number double strings (#219, #237)
│ ├─✅─.chr_to_int() passes NA through (#219, #237)
│ ├─✅─.chr_to_int() marks fractional strings as bad_precision (#219, #237)
│ ├─✅─.chr_to_int() marks non-number strings as non_number (#219, #237)
│ └─✅─.chr_to_int() marks Inf strings as bad_precision (#219, #237)
├─☑️─Feature 218: C optimization: are_lgl_ish.character() / to_lgl.character() — eliminate duplicate toupper() call
│ ├─✅─.chr_to_lgl() converts TRUE/T strings to TRUE (#218, #237)
│ ├─✅─.chr_to_lgl() converts FALSE/F strings to FALSE (#218, #237)
│ ├─✅─.chr_to_lgl() passes NA through as valid (#218, #237)
│ ├─✅─.chr_to_lgl() converts numeric strings (#218, #237)
│ ├─✅─.chr_to_lgl() marks invalid strings as not valid (#218, #237)
│ └─✅─.dbl_are_lglish() returns all TRUE (#218, #237)
├─☑️─Issue 217: C optimization: are_int_ish.double() — replace multi-vector arithmetic with single-pass C loop
│ ├─✅─are_int_ish() works for doubles (#93, #217)
│ ├─✅─.dbl_to_int() converts integer-valued doubles (#217, #237)
│ ├─✅─.dbl_to_int() passes NA and NaN through as not bad_precision (#217, #237)
│ ├─✅─.dbl_to_int() marks fractional doubles as bad_precision (#217, #237)
│ ├─✅─.dbl_to_int() marks Inf and out-of-range values as bad_precision (#217, #237)
│ └─✅─to_int() errors for dbls that would lose precision (#2, #217)
├─☑️─Feature 213: `pkg_warn()` and `pkg_inform()`
│ ├─✅─.stbl_warn() throws the expected warning (#213)
│ ├─✅─.stbl_inform() throws the expected message (#213)
│ ├─✅─.compile_pkg_message_classes() compiles message class chains (#213)
│ ├─✅─pkg_inform() signals the expected message (#213)
│ ├─✅─pkg_inform() uses parent when provided (#213)
│ ├─✅─pkg_inform() uses message_env when provided (#213)
│ ├─✅─expect_pkg_message_classes() tests expressions for classes (#213)
│ ├─✅─expect_pkg_message_snapshot() snapshots message class and message (#213)
│ ├─✅─expect_pkg_message_snapshot() works with multiple class components (#213)
│ ├─✅─expect_pkg_message_snapshot() works from an env without stbl attached (#213)
│ ├─✅─expect_pkg_message_classes() works from an env without stbl attached (#213)
│ ├─✅─.compile_pkg_warning_classes() compiles warning class chains (#213)
│ ├─✅─pkg_warn() signals the expected warning (#213)
│ ├─✅─pkg_warn() uses parent when provided (#213)
│ ├─✅─pkg_warn() passes dots to cli_warn() (#213)
│ ├─✅─pkg_warn() uses message_env when provided (#213)
│ ├─✅─expect_pkg_warning_classes() tests expressions for classes (#213)
│ ├─✅─expect_pkg_warning_snapshot() snapshots warning class and message (#213)
│ ├─✅─expect_pkg_warning_snapshot() works with multiple class components (#213)
│ ├─✅─expect_pkg_warning_snapshot() works from an env without stbl attached (#213)
│ ├─✅─expect_pkg_warning_classes() works from an env without stbl attached (#213)
│ ├─✅─.compile_dash() pastes with a dash separator (#213)
│ ├─✅─.collapse_dash() collapses a vector with dashes (#213)
│ └─✅─.compile_pkg_condition_classes() compiles condition class chains (#213)
├─☑️─Feature 200: feat: dots in `to_lst()` and `to_df()`
│ ├─✅─to_df() rejects unused dots for methods that ignore them (#200)
│ └─✅─to_lst() rejects unused dots for methods that ignore them (#200)
├─☑️─Feature 182: Implement `to()`
│ ├─✅─to() returns logical unchanged (#182)
│ ├─✅─to() returns integer unchanged (#182)
│ ├─✅─to() returns double unchanged (#182)
│ ├─✅─to() returns character unchanged (#182)
│ ├─✅─to() passes NULL through unchanged (#182)
│ ├─✅─to() converts integer to logical (#182)
│ ├─✅─to() converts double to logical (#182)
│ ├─✅─to() converts character to logical (#182)
│ ├─✅─to() errors for incompatible character -> logical (#182)
│ ├─✅─to() converts factor to logical (#182)
│ ├─✅─to() errors for incompatible factor -> logical (#182)
│ ├─✅─to() converts list to logical (#182)
│ ├─✅─to() converts logical to integer (#182)
│ ├─✅─to() converts double to integer (#182)
│ ├─✅─to() errors for double -> integer with precision loss (#182)
│ ├─✅─to() converts character to integer (#182)
│ ├─✅─to() errors for incompatible character -> integer (#182)
│ ├─✅─to() converts factor to integer (#182)
│ ├─✅─to() converts list to integer (#182)
│ ├─✅─to() converts integer to double (#182)
│ ├─✅─to() converts logical to double (#182)
│ ├─✅─to() converts character to double (#182)
│ ├─✅─to() errors for incompatible character -> double (#182)
│ ├─✅─to() converts factor to double (#182)
│ ├─✅─to() converts list to double (#182)
│ ├─✅─to() converts integer to character (#182)
│ ├─✅─to() converts double to character (#182)
│ ├─✅─to() converts logical to character (#182)
│ ├─✅─to() converts factor to character (#182)
│ ├─✅─to() converts list to character (#182)
│ ├─✅─to() converts character to factor using .to levels (#182)
│ ├─✅─to() converts integer to factor using .to levels (#182)
│ ├─✅─to() passes levels through from factor .to (#182)
│ ├─✅─to() respects explicit levels argument in to.factor (#182)
│ ├─✅─to() respects to_na argument in to.factor (#182)
│ ├─✅─to() converts to list (#182)
│ ├─✅─to() returns NULL by default when x is NULL (#182)
│ ├─✅─to() errors when x is NULL and allow_null = FALSE (#182)
│ ├─✅─to() passes data frame through unchanged with data frame target (#182)
│ ├─✅─to() converts list to data frame (#182)
│ ├─✅─to() converts vector to data frame (#182)
│ ├─✅─to() returns NULL when .to is NULL (#182)
│ ├─✅─to() errors when .to is NULL and allow_null = FALSE (#182)
│ ├─✅─to() respects coerce_character = FALSE for integer target (#182)
│ ├─✅─to() respects coerce_character = FALSE for double target (#182)
│ └─✅─to() errors for unsupported target types (#182)
├─☑️─Feature 251: `to_chr.function()`
│ ├─✅─to_chr() converts named functions (#251)
│ └─✅─to_chr() errors for anonymous functions (#251)
├─☑️─Feature 250: `to_fn()`
│ ├─✅─is_fn_ish() returns TRUE for functions (#250)
│ ├─✅─is_fn_ish() returns TRUE for formulas (#250)
│ ├─✅─is_fn_ish() returns TRUE for length-1 character strings (#250)
│ ├─✅─is_fn_ish() returns FALSE for NULL (#250)
│ ├─✅─is_fn_ish() returns FALSE for non-character vectors (#250)
│ ├─✅─is_fn_ish() returns FALSE for length != 1 character (#250)
│ ├─✅─is_fn_ish() returns FALSE with bad ':' usage (#250)
│ ├─✅─is_function_ish() exists (#250)
│ ├─✅─are_fn_ish() returns TRUE for functions (#250)
│ ├─✅─are_fn_ish() returns TRUE for formulas (#250)
│ ├─✅─are_fn_ish() does element-wise check for character (#250)
│ ├─✅─are_fn_ish() returns logical(0) for NULL (#250)
│ ├─✅─are_fn_ish() returns FALSE for non-fn-ish types (#250)
│ ├─✅─are_function_ish() is a synonym of are_fn_ish() (#250)
│ ├─✅─to_fn() works for functions (#250)
│ ├─✅─to_fn() works for lambda functions (#250)
│ ├─✅─to_fn() works for NULL (#250)
│ ├─✅─to_fn() respects allow_null for NULL input (#250)
│ ├─✅─to_fn() works for simple character names (#250)
│ ├─✅─to_fn() works for namespaced character names (#250)
│ ├─✅─to_fn() fails cleanly for weird ':' use in character names (#250)
│ ├─✅─to_fn() respects definition_env for character input (#250)
│ ├─✅─to_fn() errors informatively for unknown character names (#250)
│ ├─✅─to_fn() errors for length > 1 character input (#250)
│ ├─✅─to_fn() respects allow_null for length-0 character input (#250)
│ ├─✅─to_fn() errors informatively for bad namespaced names (#250)
│ ├─✅─to_fn() errors informatively for non-coercible types (#250)
│ ├─✅─to_function() exists (#250)
│ ├─✅─.chr_to_fn() works via C callable (#250)
│ ├─✅─.chr_are_fnish() works via C callable (#250)
│ ├─✅─to() converts character to function (#250)
│ ├─✅─to() passes function through unchanged (#250)
│ ├─✅─to() converts formula to function (#250)
│ └─✅─to() errors for non-coercible types to function (#250)
├─☑️─Feature 241: Add `*_to_chr` and `*_to_fct` to the C API
│ ├─✅─to_chr() works for ints via C (#241)
│ ├─✅─to_chr() works for lgls via C (#241)
│ ├─✅─to_chr() works for dbls via C (#241)
│ ├─✅─to_chr() works for fcts via C (#241)
│ ├─✅─to_fct() works for ints via C (#241)
│ ├─✅─to_fct() errors for ints with unexpected levels (#241)
│ └─✅─to_fct() sorts integer levels numerically not lexicographically (#241)
├─☑️─Feature 239: Replace all `to_*.list()` methods with C routines
│ ├─✅─.lst_to_dbl() unwraps singly-nested lists (#239)
│ ├─✅─.lst_to_dbl() marks multiply-nested lists as not valid (#239)
│ ├─✅─.lst_to_int() unwraps singly-nested lists (#239)
│ ├─✅─.lst_to_int() marks multiply-nested lists as not valid (#239)
│ ├─✅─.lst_to_lgl() unwraps singly-nested lists (#239)
│ ├─✅─.lst_to_lgl() marks multiply-nested lists as not valid (#239)
│ ├─✅─.lst_to_chr() converts non-character atomic scalars to strings (#226, #237, #239)
│ ├─✅─.lst_to_chr() converts factor elements via their level labels (#226, #237, #239)
│ ├─✅─.lst_to_chr() unwraps singly-nested lists (#239)
│ ├─✅─.lst_to_chr() marks multiply-nested lists as not valid (#239)
│ ├─✅─.lst_to_fct() unwraps singly-nested lists (#239)
│ └─✅─.lst_to_fct() marks multiply-nested lists as not valid (#239)
├─☑️─Feature 237: Standardize callable C API: stbl_*_to_* should always return result + valid list
│ ├─✅─.chr_to_lgl() converts TRUE/T strings to TRUE (#218, #237)
│ ├─✅─.chr_to_lgl() converts FALSE/F strings to FALSE (#218, #237)
│ ├─✅─.chr_to_lgl() passes NA through as valid (#218, #237)
│ ├─✅─.chr_to_lgl() converts numeric strings (#218, #237)
│ ├─✅─.chr_to_lgl() marks invalid strings as not valid (#218, #237)
│ ├─✅─.chr_to_int() converts integer strings (#219, #237)
│ ├─✅─.chr_to_int() converts whole-number double strings (#219, #237)
│ ├─✅─.chr_to_int() passes NA through (#219, #237)
│ ├─✅─.chr_to_int() marks fractional strings as bad_precision (#219, #237)
│ ├─✅─.chr_to_int() marks non-number strings as non_number (#219, #237)
│ ├─✅─.chr_to_int() marks Inf strings as bad_precision (#219, #237)
│ ├─✅─.chr_to_dbl() converts numeric strings (#221, #237)
│ ├─✅─.chr_to_dbl() converts Inf strings (#221, #237)
│ ├─✅─.chr_to_dbl() passes NA through as valid (#221, #237)
│ ├─✅─.chr_to_dbl() marks invalid strings as not valid (#221, #237)
│ ├─✅─.dbl_to_int() converts integer-valued doubles (#217, #237)
│ ├─✅─.dbl_to_int() passes NA and NaN through as not bad_precision (#217, #237)
│ ├─✅─.dbl_to_int() marks fractional doubles as bad_precision (#217, #237)
│ ├─✅─.dbl_to_int() marks Inf and out-of-range values as bad_precision (#217, #237)
│ ├─✅─.dbl_to_lgl() converts 0 to FALSE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() converts non-zero to TRUE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() passes NA and NaN through; valid always TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() handles integer input; valid always TRUE (#226, #237)
│ ├─✅─.dbl_are_lglish() returns all TRUE (#218, #237)
│ ├─✅─.int_to_dbl() converts integers to doubles; valid always TRUE (#226, #237)
│ ├─✅─.int_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.int_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts TRUE to 1.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts FALSE to 0.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lgl_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts TRUE to 1L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts FALSE to 0L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lgl_are_intish() returns all TRUE (#237)
│ ├─✅─.cpx_to_dbl() extracts real part when Im is zero (#226, #237)
│ ├─✅─.cpx_to_dbl() passes NA complex through as NA_real; valid TRUE (#226, #237)
│ ├─✅─.cpx_to_dbl() returns real part and valid FALSE for non-zero Im (#226, #237)
│ ├─✅─.cpx_to_int() converts whole-number complex with Im 0 (#226, #237)
│ ├─✅─.cpx_to_int() passes NA complex through; flags FALSE (#226, #237)
│ ├─✅─.cpx_to_int() marks non-zero Im as non_number (#226, #237)
│ ├─✅─.cpx_to_int() marks fractional real part as bad_precision (#226, #237)
│ ├─✅─.fct_to_dbl() converts numeric factor levels to doubles (#226, #237)
│ ├─✅─.fct_to_dbl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_dbl() marks non-numeric levels as not valid (#226, #237)
│ ├─✅─.fct_to_int() converts whole-number factor levels to integers (#226, #237)
│ ├─✅─.fct_to_int() passes NA factor element through; flags FALSE (#226, #237)
│ ├─✅─.fct_to_int() marks non-integer levels correctly (#226, #237)
│ ├─✅─.fct_to_lgl() converts TRUE/FALSE levels (#226, #237)
│ ├─✅─.fct_to_lgl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_lgl() marks non-logical levels as not valid (#226, #237)
│ ├─✅─.chr_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.chr_are_fctish() checks membership in levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats to_na values as fctish (#226, #237)
│ ├─✅─.fct_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.fct_are_fctish() checks factor level membership in target levels (#226, #237)
│ ├─✅─.fct_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.lst_to_dbl() converts a flat list of numeric/lgl/int scalars (#226, #237)
│ ├─✅─.lst_to_dbl() converts numeric character strings (#226, #237)
│ ├─✅─.lst_to_dbl() marks non-parseable character strings as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts complex with Im == 0 (#226, #237)
│ ├─✅─.lst_to_dbl() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() unpacks a one-element list with a double vector (#237)
│ ├─✅─.lst_to_dbl() unpacks a one-element list with an integer vector (#237)
│ ├─✅─.lst_to_dbl() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_dbl() marks non-coercible single-element as not valid (#237)
│ ├─✅─.lst_to_dbl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts a flat list of integer/logical scalars (#226, #237)
│ ├─✅─.lst_to_int() converts whole-number doubles (#226, #237)
│ ├─✅─.lst_to_int() converts integer-valued character strings (#226, #237)
│ ├─✅─.lst_to_int() marks fractional character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-number character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts complex with Im == 0 and whole Re (#226, #237)
│ ├─✅─.lst_to_int() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() marks fractional doubles as not valid (#226, #237)
│ ├─✅─.lst_to_int() unpacks a one-element list with an integer vector (#237)
│ ├─✅─.lst_to_int() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_int() unpacks a one-element list with a double vector (#237)
│ ├─✅─.lst_to_int() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts a flat list of lgl/int/dbl scalars (#226, #237)
│ ├─✅─.lst_to_lgl() converts lgl-ish character strings (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-lgl character strings as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() unpacks a one-element list with a logical vector (#237)
│ ├─✅─.lst_to_lgl() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_lgl() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_chr() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() converts non-character atomic scalars to strings (#226, #237, #239)
│ ├─✅─.lst_to_chr() converts factor elements via their level labels (#226, #237, #239)
│ ├─✅─.lst_to_chr() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_chr() marks non-character single-element vectors as not valid (#226, #237)
│ ├─✅─.lst_to_chr() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_fct() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() marks non-character scalars as not valid (#226, #237)
│ ├─✅─.lst_to_fct() marks factor elements as valid (#226, #237)
│ ├─✅─.lst_to_fct() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_fct() unpacks a one-element list with a factor (#237)
│ ├─✅─.lst_to_fct() marks non-character/factor single-element vectors as not valid (#226, #237)
│ └─✅─.lst_to_fct() marks non-scalar elements in multi-element lists as not valid (#226, #237)
├─☑️─Feature 235: Callable C Functions
│ ├─✅─inst/include/stbl.h is installed (#235)
│ ├─✅─inst/include/stbl.c is installed (#235)
│ ├─✅─stbl.h declares all expected function pointers (#235)
│ ├─✅─stbl.h declares stbl_init_api() (#235)
│ ├─✅─stbl.c assigns all expected callables via R_GetCCallable (#235)
│ ├─✅─stbl.c defines stbl_init_api() (#235)
│ └─✅─src/init.c registers all expected C callables (#235)
├─☑️─Bug 234: Allow users to define objects inside `expect_pkg_*_snapshot()`
│ ├─✅─expect_pkg_message_snapshot() allows object definition inside expression (#234)
│ ├─✅─expect_pkg_warning_snapshot() allows object definition inside expression (#234)
│ ├─✅─.capture_first_pkg_condition() captures a condition and returns it invisibly (#234)
│ ├─✅─.capture_first_pkg_condition() returns NULL when no condition is signalled (#234)
│ └─✅─.capture_first_pkg_condition() evaluates obj_expr in env (#234)
└─☑️─Feature 231: feat: add `max_levels` argument to `is_fct_ish()`
└─✅─is_fct_ish() supports max_levels (#231)
# Issue state: 📥 = open, ☑️ = closed (completed), ⛔ = closed (won't fix)
# Test disposition: ✅ = passed, ❌ = failed, 🚫 = skipped
🟢 All issues have at least one test
🙈 5 issues with label "qcthat-nocov" were ignored
Completed Issues
✅ A qcthat issue test matrix with 4 milestones, 70 issues, and 647 tests
├─█─Milestone: v0.1 (17 issues, 93 tests)
│ ├─☑️─Feature 64: Explicitly error to_fct for list and data.frame
│ │ └─✅─to_fct() works for lists (#64)
│ ├─☑️─Feature 21: to_lgl()
│ │ ├─✅─to_lgl() works for lgls (#21)
│ │ ├─✅─to_lgl() works for NULL (#21)
│ │ ├─✅─to_lgl() respects allow_null (#21)
│ │ ├─✅─to_lgl() works for integers (#21)
│ │ ├─✅─to_lgl() works for doubles (#21)
│ │ ├─✅─to_lgl works for characters (#21)
│ │ ├─✅─to_lgl() errors for bad characters (#21)
│ │ ├─✅─to_lgl works for factors (#21)
│ │ ├─✅─to_lgl errors for bad factors (#21)
│ │ ├─✅─to_lgl() works for lists (#21)
│ │ └─✅─to_lgl() errors for other types (#21)
│ ├─☑️─Feature 14: coerce argument(s)
│ │ ├─✅─to_int() respects coerce_character (#14)
│ │ └─✅─to_int() respects coerce_factor (#14)
│ ├─☑️─Feature 12: Scalar
│ │ ├─✅─stabilize_arg_scalar() allows length-1 args through (#12)
│ │ ├─✅─stabilize_arg_scalar() errors for non-scalars (#12, #58)
│ │ ├─✅─stabilize_arg_scalar() respects allow_null (#12, #58)
│ │ ├─✅─stabilize_arg_scalar() errors on weird internal arg values (#12, #58)
│ │ ├─✅─stabilize_int_scalar() allows length-1 ints through (#12, #189)
│ │ ├─✅─stabilize_int_scalar() respects allow_null (#12, #189)
│ │ ├─✅─stabilize_int_scalar() errors on non-scalars (#12)
│ │ ├─✅─to_int_scalar() allows length-1 ints through (#12)
│ │ ├─✅─to_int_scalar() provides informative error messages (#12)
│ │ ├─✅─to_int_scalar() respects allow_null (#12, #189)
│ │ └─✅─to_int_scalar respects allow_zero_length (#12, #43, #45, #189)
│ ├─☑️─Feature 11: Rename then export .return_if_clear()
│ │ ├─✅─stabilize_arg() returns its inputs for default settings (#11)
│ │ ├─✅─stabilize_arg() complains about weird args (#11, #58, #99)
│ │ ├─✅─stabilize_arg() rejects NULLs when asked (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks NAs (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks size args (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks min_size (#11, #58, #99)
│ │ └─✅─stabilize_arg() checks max_size (#11, #58)
│ ├─☑️─Feature 6: to_int_simple() (or something)
│ │ ├─✅─stabilize_int() checks min_value (#2, #6, #176)
│ │ └─✅─to_int() works for ints (#2, #6)
│ ├─☑️─Feature 5: Implement allow_empty
│ │ └─✅─stabilize_int() checks max_value (#5, #176)
│ ├─☑️─Feature 4: Factors to int
│ │ ├─✅─to_int() works for factors (#4)
│ │ └─✅─to_int() errors informatively for bad factors (#4)
│ ├─☑️─Feature 2: Implement to_int()
│ │ ├─✅─stabilize_int() checks min_value (#2, #6, #176)
│ │ ├─✅─to_int() works for ints (#2, #6)
│ │ ├─✅─to_int() works for NULL (#2)
│ │ ├─✅─to_int() respects allow_null (#2)
│ │ ├─✅─to_int() works for lgls (#2)
│ │ ├─✅─to_int() works for dbls (#2)
│ │ ├─✅─to_int() errors for dbls that would lose precision (#2, #217)
│ │ ├─✅─to_int() works for chrs (#2)
│ │ ├─✅─to_int() errors informatively for bad chrs (#2)
│ │ ├─✅─to_int() works for complexes (#2)
│ │ ├─✅─to_int() errors informatively for bad complexes (#2)
│ │ ├─✅─to_int() works for lists (#2)
│ │ └─✅─to_int() errors properly for other types (#2)
│ ├─☑️─Feature 62: stabilize_fct
│ │ ├─✅─stabilize_fct() works (#62)
│ │ ├─✅─stabilize_fct() throws errors for bad levels (#62, #67)
│ │ ├─✅─stabilize_fct_scalar() works (#62, #189)
│ │ ├─✅─stabilize_fct_scalar() respects allow_null (#62, #189)
│ │ ├─✅─stabilize_fct_scalar() errors for non-scalars (#62)
│ │ ├─✅─to_fct() works for fcts (#62)
│ │ ├─✅─to_fct() deals with levels of fcts (#62)
│ │ ├─✅─to_fct() throws errors for bad levels (#62, #67, #177)
│ │ ├─✅─to_fct() works for chrs (#62)
│ │ ├─✅─to_fct() works for NULL (#62)
│ │ ├─✅─to_fct() respects allow_null (#62)
│ │ ├─✅─to_fct() errors for things that can't be coerced (#62)
│ │ ├─✅─to_fct() treats numbers as text (#62)
│ │ ├─✅─to_fct_scalar() allows length-1 fcts through (#62)
│ │ ├─✅─to_fct_scalar() provides informative error messages (#62)
│ │ └─✅─to_fct_scalar respects allow_zero_length (#62, #43, #45, #189)
│ ├─☑️─Task 58: Error classes
│ │ ├─✅─stabilize_arg() complains about weird args (#11, #58, #99)
│ │ ├─✅─stabilize_arg() rejects NULLs when asked (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks NAs (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks size args (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks min_size (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks max_size (#11, #58)
│ │ ├─✅─stabilize_arg_scalar() errors for non-scalars (#12, #58)
│ │ ├─✅─stabilize_arg_scalar() respects allow_null (#12, #58)
│ │ └─✅─stabilize_arg_scalar() errors on weird internal arg values (#12, #58)
│ ├─☑️─Feature 45: empty vs NULL
│ │ ├─✅─to_chr_scalar respects allow_zero_length (#22, #43, #45, #189)
│ │ ├─✅─to_dbl_scalar respects allow_zero_length (#23, #43, #45, #189)
│ │ ├─✅─to_fct_scalar respects allow_zero_length (#62, #43, #45, #189)
│ │ └─✅─to_int_scalar respects allow_zero_length (#12, #43, #45, #189)
│ ├─☑️─Feature 43: Empty input
│ │ ├─✅─to_chr_scalar respects allow_zero_length (#22, #43, #45, #189)
│ │ ├─✅─to_dbl_scalar respects allow_zero_length (#23, #43, #45, #189)
│ │ ├─✅─to_fct_scalar respects allow_zero_length (#62, #43, #45, #189)
│ │ └─✅─to_int_scalar respects allow_zero_length (#12, #43, #45, #189)
│ ├─☑️─Feature 32: to_lgl_scalar()
│ │ ├─✅─to_lgl_scalar() allows length-1 lgls through (#32, #189)
│ │ ├─✅─to_lgl_scalar() errors for non-scalars (#32)
│ │ ├─✅─to_lgl_scalar() errors for bad characters (#32)
│ │ └─✅─to_lgl_scalar() respects allow_null (#32, #189)
│ ├─☑️─Feature 28: stabilize_lgl()
│ │ ├─✅─stabilize_lgl() works on happy path (#28)
│ │ ├─✅─stabilize_lgl() checks NAs (#28)
│ │ ├─✅─stabilize_lgl() checks min_size (#28)
│ │ ├─✅─stabilize_lgl() checks max_size (#28)
│ │ ├─✅─stabilize_lgl_scalar() allows length-1 lgls through (#28, #189)
│ │ ├─✅─stabilize_lgl_scalar() respects allow_null (#28, #189)
│ │ └─✅─stabilize_lgl_scalar() errors on non-scalars (#28)
│ ├─☑️─Feature 27: regex arg
│ │ ├─✅─stabilize_chr() works on happy path (#22, #27, #52)
│ │ ├─✅─stabilize_chr() errors for bad regex matches (#27, #52)
│ │ └─✅─stabilize_chr works with NA and regex pattern (#27, #52)
│ └─☑️─Feature 22: *_chr*()
│ ├─✅─stabilize_chr() works on happy path (#22, #27, #52)
│ ├─✅─stabilize_chr_scalar() allows length-1 chrs through (#22, #189)
│ ├─✅─stabilize_chr_scalar() respects allow_null (#22, #189)
│ ├─✅─stabilize_chr_scalar() errors for non-scalars (#22)
│ ├─✅─to_chr() works for chrs (#22)
│ ├─✅─to_chr() works for NULL (#22)
│ ├─✅─to_chr() respects allow_null (#22)
│ ├─✅─to_chr() works for other things (#22)
│ ├─✅─to_chr() tries to flatten lists (#22)
│ ├─✅─to_chr() fails gracefully for weird cases (#22)
│ ├─✅─to_chr_scalar() allows length-1 chrs through (#22, #189)
│ ├─✅─to_chr_scalar() errors for non-scalars (#22)
│ ├─✅─to_chr_scalar() errors for uncoerceable types (#22)
│ ├─✅─to_chr_scalar() respects allow_null (#22, #189)
│ └─✅─to_chr_scalar respects allow_zero_length (#22, #43, #45, #189)
├─█─Milestone: v0.2 (13 issues, 124 tests)
│ ├─☑️─Task 129: Rename `to_null()` to `.to_null()`
│ │ ├─✅─.to_null() works on the happy path (#129)
│ │ ├─✅─.to_null() errors when NULL isn't allowed (#129)
│ │ ├─✅─.to_null() coerces anything to NULL (#129)
│ │ ├─✅─.to_null() errors for bad allow_null (#129)
│ │ └─✅─.to_null() errors informatively for missing value (#129)
│ ├─☑️─Feature 67: to_fct: Enumerate options
│ │ ├─✅─stabilize_fct() throws errors for bad levels (#62, #67)
│ │ └─✅─to_fct() throws errors for bad levels (#62, #67, #177)
│ ├─☑️─Feature 52: regex error is useless
│ │ ├─✅─regex_must_match() works as expected (#52, #89)
│ │ ├─✅─regex_must_match() deals with characters for glue (#52, #89)
│ │ ├─✅─stabilize_chr() works on happy path (#22, #27, #52)
│ │ ├─✅─stabilize_chr() errors for bad regex matches (#27, #52)
│ │ ├─✅─stabilize_chr() works with complex url regex (#52)
│ │ ├─✅─stabilize_chr() allows for customized error messages (#52)
│ │ ├─✅─stabilize_chr() works with regex that contains braces (#52)
│ │ ├─✅─stabilize_chr works with NA and regex pattern (#27, #52)
│ │ └─✅─stabilize_chr_scalar() works with regex that contains braces (#52)
│ ├─☑️─Feature 30: to_lgl.character(): "0" and "1"
│ │ ├─✅─are_lgl_ish() works for characters (#93, #30)
│ │ ├─✅─are_lgl_ish() works for factors (#93, #30)
│ │ └─✅─are_lgl_ish() works for lists (#93, #30)
│ ├─☑️─Feature 23: dbl
│ │ ├─✅─are_dbl_ish() works for dbls (#23)
│ │ ├─✅─are_dbl_ish() works for ints (#23)
│ │ ├─✅─are_dbl_ish() works for NULL (#23)
│ │ ├─✅─are_dbl_ish() works for logicals (#23)
│ │ ├─✅─are_dbl_ish() works for characters (#23)
│ │ ├─✅─are_dbl_ish() respects coerce_character (#23)
│ │ ├─✅─are_dbl_ish() works for factors (#23)
│ │ ├─✅─are_dbl_ish() respects coerce_factor (#23)
│ │ ├─✅─are_dbl_ish() works for complex (#23)
│ │ ├─✅─are_dbl_ish() works for lists (#23)
│ │ ├─✅─are_dbl_ish() returns FALSE for non-vectors (#23)
│ │ ├─✅─is_dbl_ish() works (#23)
│ │ ├─✅─.to_cls_from_fct() works (#23)
│ │ ├─✅─.to_num_from_complex() works (#23)
│ │ ├─✅─stabilize_dbl() checks min_value (#23, #176)
│ │ ├─✅─stabilize_dbl() checks max_value (#23, #176)
│ │ ├─✅─stabilize_dbl_scalar() allows length-1 dbls through (#23, #189)
│ │ ├─✅─stabilize_dbl_scalar() respects allow_null (#23, #189)
│ │ ├─✅─stabilize_dbl_scalar() errors on non-scalars (#23)
│ │ ├─✅─to_dbl() works for dbls (#23)
│ │ ├─✅─to_dbl() works for ints (#23)
│ │ ├─✅─to_dbl() works for NULL (#23)
│ │ ├─✅─to_dbl() respects allow_null (#23)
│ │ ├─✅─to_dbl() works for lgls (#23)
│ │ ├─✅─to_dbl() works for chrs (#23)
│ │ ├─✅─to_dbl() respects coerce_character (#23)
│ │ ├─✅─to_dbl() errors informatively for bad chrs (#23)
│ │ ├─✅─to_dbl() works for complexes (#23)
│ │ ├─✅─to_dbl() errors informatively for bad complexes (#23)
│ │ ├─✅─to_dbl() works for factors (#23)
│ │ ├─✅─to_dbl() respects coerce_factor (#23)
│ │ ├─✅─to_dbl() errors informatively for bad factors (#23)
│ │ ├─✅─to_dbl() errors properly for other types (#23)
│ │ ├─✅─to_dbl_scalar() allows length-1 dbls through (#23)
│ │ ├─✅─to_dbl_scalar() provides informative error messages (#23)
│ │ ├─✅─to_dbl_scalar() respects allow_null (#23, #189)
│ │ └─✅─to_dbl_scalar respects allow_zero_length (#23, #43, #45, #189)
│ ├─☑️─Bug 128: Ensure `are_*_ish()` and `to_*()` are consistent
│ │ ├─✅─are_chr_ish() works for lists and data.frames (#93, #128)
│ │ ├─✅─are_int_ish() works for lists (#93, #128)
│ │ └─✅─to_dbl() works for lists (#128)
│ ├─☑️─Task 99: Standardize error class checks in all test files
│ │ ├─✅─stabilize_arg() complains about weird args (#11, #58, #99)
│ │ ├─✅─stabilize_arg() rejects NULLs when asked (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks NAs (#11, #58, #99)
│ │ ├─✅─stabilize_arg() checks size args (#11, #58, #99)
│ │ └─✅─stabilize_arg() checks min_size (#11, #58, #99)
│ ├─☑️─Task 95: Standardize Error Messages
│ │ ├─✅─.stbl_abort() throws the expected error (#95)
│ │ ├─✅─.stop_cant_coerce() throws the expected error (#95)
│ │ ├─✅─.stop_cant_coerce() uses additional_msg when provided (#95)
│ │ ├─✅─.stop_must() throws the expected error (#95)
│ │ ├─✅─.stop_must() handles subclasses (#95)
│ │ ├─✅─.stop_must() uses additional_msg when provided (#95)
│ │ ├─✅─.define_main_msg() works (#95)
│ │ ├─✅─.stop_null() throws the expected error (#95)
│ │ ├─✅─.stop_null() passes dots (#95)
│ │ ├─✅─.stop_incompatible() throws the expected error (#95)
│ │ ├─✅─.stop_incompatible() passes dots (#95)
│ │ ├─✅─.check_na() works (#95)
│ │ ├─✅─.check_size() works (#95)
│ │ ├─✅─.check_scalar() works (#95)
│ │ ├─✅─.check_x_no_more_than_y() works (#95)
│ │ └─✅─object_type returns expected types (#95)
│ ├─☑️─Feature 93: `are_*_ish()` functions
│ │ ├─✅─are_chr_ish() returns TRUE for every element of a chr (#93)
│ │ ├─✅─are_chr_ish() works for NULL (#93)
│ │ ├─✅─are_chr_ish() returns TRUE for every element of other atomics (#93)
│ │ ├─✅─are_chr_ish() works for lists and data.frames (#93, #128)
│ │ ├─✅─are_chr_ish() returns unnamed vectors (#93)
│ │ ├─✅─are_chr_ish() returns FALSE for non-vectors (#93)
│ │ ├─✅─is_chr_ish() returns a single TRUE for coercible objects (#93)
│ │ ├─✅─is_chr_ish() works for NULL (#93)
│ │ ├─✅─is_chr_ish() returns FALSE for uncoercibles (#93)
│ │ ├─✅─are_fct_ish() is TRUE for atomics when levels is NULL (#93)
│ │ ├─✅─are_fct_ish() works for NULL (#93)
│ │ ├─✅─are_fct_ish() works when levels are provided (#93)
│ │ ├─✅─are_fct_ish() works with to_na (#93)
│ │ ├─✅─.are_not_fct_ish_chr() works (#93)
│ │ ├─✅─are_fct_ish() works for lists (#93)
│ │ ├─✅─are_fct_ish() returns FALSE for non-vectors (#93)
│ │ ├─✅─are_fct_ish() deals with factor-ish S3 objects (#93)
│ │ ├─✅─is_fct_ish() works (#93)
│ │ ├─✅─are_int_ish() works for ints (#93)
│ │ ├─✅─are_int_ish() works for NULL (#93)
│ │ ├─✅─are_int_ish() works for logicals (#93)
│ │ ├─✅─are_int_ish() works for doubles (#93, #217)
│ │ ├─✅─are_int_ish() works for characters (#93)
│ │ ├─✅─are_int_ish() respects coerce_character (#93)
│ │ ├─✅─are_int_ish() works for factors (#93)
│ │ ├─✅─are_int_ish() respects coerce_factor (#93)
│ │ ├─✅─are_int_ish() works for complex (#93)
│ │ ├─✅─are_int_ish() works for lists (#93, #128)
│ │ ├─✅─are_int_ish() returns FALSE for non-vectors (#93)
│ │ ├─✅─are_int_ish() returns FALSE for unhandled S3 objects (#93)
│ │ ├─✅─is_int_ish() works (#93)
│ │ ├─✅─are_lgl_ish() works for logicals (#93)
│ │ ├─✅─are_lgl_ish() works for NULL (#93)
│ │ ├─✅─are_lgl_ish() works for numerics (#93)
│ │ ├─✅─are_lgl_ish() works for characters (#93, #30)
│ │ ├─✅─are_lgl_ish() works for factors (#93, #30)
│ │ ├─✅─are_lgl_ish() works for lists (#93, #30)
│ │ ├─✅─are_lgl_ish() returns FALSE for non-vectors (#93)
│ │ ├─✅─are_lgl_ish() returns FALSE for unhandled S3 objects (#93)
│ │ ├─✅─is_lgl_ish() works (#93)
│ │ └─✅─.elements_are_cls_ish() works (#93)
│ ├─☑️─Feature 89: cli formatting of regex patterns in errors
│ │ ├─✅─regex_must_match() works as expected (#52, #89)
│ │ ├─✅─regex_must_match() deals with characters for glue (#52, #89)
│ │ ├─✅─regex_must_match() handles negation (#85, #89)
│ │ ├─✅─regex_must_not_match() works as expected (#85, #89)
│ │ └─✅─regex_must_not_match() doesn't freak out about pre-set negation (#85, #89)
│ ├─☑️─Feature 87: Support {stringr} pattern-modifier functions
│ │ ├─✅─stabilize_chr() works with stringr::fixed() (#87)
│ │ ├─✅─stabilize_chr() works with stringr::coll() (#87)
│ │ └─✅─stabilize_chr() works with stringr::regex() (#87)
│ ├─☑️─Feature 86: Allow `stabilize_chr()` to accept multiple regex rules
│ │ └─✅─stabilize_chr() accepts multiple regex rules (#86, #85)
│ └─☑️─Feature 85: regex_must_not_match
│ ├─✅─regex_must_match() handles negation (#85, #89)
│ ├─✅─regex_must_not_match() works as expected (#85, #89)
│ ├─✅─regex_must_not_match() doesn't freak out about pre-set negation (#85, #89)
│ ├─✅─stabilize_chr() accepts negated regex args (#85)
│ └─✅─stabilize_chr() accepts multiple regex rules (#86, #85)
├─█─Milestone: v0.3.0 (22 issues, 206 tests)
│ ├─☑️─Bug 204: bug: `stabilize_lst()` with nested list
│ │ ├─✅─specify_df() accepts columns named 'x_arg', 'call', 'x_class' (#204)
│ │ ├─✅─specify_lst() accepts elements named 'x_arg', 'call', 'x_class' (#204)
│ │ └─✅─stabilize_lst() with nested specify_lst() propagates errors correctly (#204)
│ ├─☑️─Task 166: Make to_lst() the primary spelling
│ │ ├─✅─to_lst() works for lists (#157, #166)
│ │ └─✅─to_list() exists (#157, #166)
│ ├─☑️─Feature 164: Add spelled-out aliases for all functions
│ │ ├─✅─are_character_ish() exists (#164)
│ │ ├─✅─is_character_ish() exists (#164)
│ │ ├─✅─are_double_ish() exists (#164)
│ │ ├─✅─is_double_ish() exists (#164)
│ │ ├─✅─are_factor_ish() exists (#164)
│ │ ├─✅─is_factor_ish() exists (#164)
│ │ ├─✅─are_integer_ish() exists (#164)
│ │ ├─✅─is_integer_ish() exists (#164)
│ │ ├─✅─are_logical_ish() exists (#164)
│ │ ├─✅─is_logical_ish() exists (#164)
│ │ ├─✅─specify_character() exists (#164)
│ │ ├─✅─stabilize_character_scalar() exists (#164)
│ │ ├─✅─specify_double() exists (#164)
│ │ ├─✅─stabilize_double_scalar() exists (#164)
│ │ ├─✅─specify_factor() exists (#164)
│ │ ├─✅─stabilize_factor_scalar() exists (#164)
│ │ ├─✅─specify_integer() exists (#164)
│ │ ├─✅─stabilize_integer_scalar() exists (#164)
│ │ ├─✅─specify_logical() exists (#164)
│ │ ├─✅─stabilize_logical_scalar() exists (#164)
│ │ ├─✅─stabilize_character() exists (#164)
│ │ ├─✅─stabilize_character_scalar() exists (#164)
│ │ ├─✅─stabilize_double() exists (#164)
│ │ ├─✅─stabilize_double_scalar() exists (#164)
│ │ ├─✅─stabilize_factor() exists (#164)
│ │ ├─✅─stabilize_factor_scalar() exists (#164)
│ │ ├─✅─stabilize_integer() exists (#164)
│ │ ├─✅─stabilize_integer_scalar() exists (#164)
│ │ ├─✅─stabilize_logical() exists (#164)
│ │ ├─✅─stabilize_logical_scalar() exists (#164)
│ │ ├─✅─to_character() exists (#164)
│ │ ├─✅─to_character_scalar() exists (#164)
│ │ ├─✅─to_double() exists (#164)
│ │ ├─✅─to_double_scalar() exists (#164)
│ │ ├─✅─to_factor() exists (#164)
│ │ ├─✅─to_factor_scalar() exists (#164)
│ │ ├─✅─to_integer() exists (#164)
│ │ ├─✅─to_integer_scalar() exists (#164)
│ │ ├─✅─to_logical() exists (#164)
│ │ └─✅─to_logical_scalar() exists (#164)
│ ├─☑️─Feature 161: Show actual args in `specify_*()`
│ │ ├─✅─specify_cls builds the expected function with at least one arg (#150, #161)
│ │ ├─✅─specify_cls builds the expected function snapshot with at least one arg (#150, #161)
│ │ └─✅─The function built via specify_cls errors informatively for duplicated args (#150, #153, #161)
│ ├─☑️─Feature 157: Implement `to_list()`
│ │ ├─✅─to_lst() works for lists (#157, #166)
│ │ ├─✅─to_lst() works for NULL (#157)
│ │ ├─✅─to_lst() respects allow_null (#157)
│ │ ├─✅─to_lst() works for character vectors (#157)
│ │ ├─✅─to_lst() errors by default for functions (#157)
│ │ ├─✅─to_lst() works for functions with coerce_function = TRUE (#157)
│ │ ├─✅─to_lst() errors informatively for primitives (#157)
│ │ └─✅─to_list() exists (#157, #166)
│ ├─☑️─Feature 153: Better handling of `...` in `specify_*()`
│ │ └─✅─The function built via specify_cls errors informatively for duplicated args (#150, #153, #161)
│ ├─☑️─Feature 151: Implement `specify_lgl()`
│ │ ├─✅─specify_lgl can build a checker (#151)
│ │ └─✅─specify_lgl_scalar can build a value checker (#151)
│ ├─☑️─Feature 150: Implement `specify_fct()`
│ │ ├─✅─specify_cls builds the expected function with no args (#150)
│ │ ├─✅─specify_cls builds the expected function snapshot with no args (#150)
│ │ ├─✅─specify_cls builds the expected function with at least one arg (#150, #161)
│ │ ├─✅─specify_cls builds the expected function snapshot with at least one arg (#150, #161)
│ │ ├─✅─The function built via specify_cls errors informatively for duplicated args (#150, #153, #161)
│ │ ├─✅─specify_cls can build a scalar specifier (#150)
│ │ ├─✅─specify_cls builds the expected scalar function snapshot (#150)
│ │ ├─✅─specify_fct can build a level checker (#150)
│ │ └─✅─specify_fct_scalar can build a level checker (#150)
│ ├─☑️─Feature 149: Implement `specify_int()`
│ │ ├─✅─specify_int can build a value checker (#149)
│ │ └─✅─specify_int_scalar can build a value checker (#149)
│ ├─☑️─Feature 148: Implement `specify_dbl()`
│ │ ├─✅─specify_dbl can build a value checker (#148)
│ │ └─✅─specify_dbl_scalar can build a value checker (#148)
│ ├─☑️─Feature 147: Implement `specify_chr()`
│ │ ├─✅─specify_chr can build a regex checker (#147)
│ │ └─✅─specify_chr_scalar can build a regex checker (#147)
│ ├─☑️─Feature 203: feat: better `to_df()`
│ │ ├─✅─.check_all_named() works (#203)
│ │ ├─✅─.check_not_jagged() works (#203)
│ │ ├─✅─to_df() errors for an unnamed list (#203)
│ │ ├─✅─to_df() coerces named vector types to a data frame (#203)
│ │ └─✅─to_df() errors for inline vector expressions (#203)
│ ├─☑️─Feature 142: Implement `stabilize_df()`
│ │ ├─✅─specify_df() creates a working validator (#142)
│ │ ├─✅─specify_df() errors when required column is missing (#142)
│ │ ├─✅─specify_df() passes through .min_rows, .max_rows (#142)
│ │ ├─✅─specify_df() passes through .col_names (#142)
│ │ ├─✅─specify_df() allows additional specs via ... (#142)
│ │ ├─✅─specify_data_frame() exists (#142)
│ │ ├─✅─stabilize_df() returns NULL for NULL input by default (#142)
│ │ ├─✅─stabilize_df() respects .allow_null (#142)
│ │ ├─✅─stabilize_df() errors for non-coercible input (#142)
│ │ ├─✅─stabilize_df() coerces a named list to a data frame (#142)
│ │ ├─✅─stabilize_df() returns a valid data frame unchanged (#142)
│ │ ├─✅─stabilize_df() coerces compatible column types (#142)
│ │ ├─✅─stabilize_df() errors when required column is missing (#142)
│ │ ├─✅─stabilize_df() errors informatively when column fails validation (#142)
│ │ ├─✅─stabilize_df() errors on extra columns by default (#142)
│ │ ├─✅─stabilize_df() allows extra columns with .extra_cols (#142)
│ │ ├─✅─stabilize_df() validates extra columns with .extra_cols (#142)
│ │ ├─✅─stabilize_df() enforces .min_rows (#142)
│ │ ├─✅─stabilize_df() enforces .min_rows (snapshot) (#142)
│ │ ├─✅─stabilize_df() enforces .max_rows (#142)
│ │ ├─✅─stabilize_df() enforces .max_rows (snapshot) (#142)
│ │ ├─✅─stabilize_df() passes with valid row counts (#142)
│ │ ├─✅─stabilize_df() enforces .col_names (#142)
│ │ ├─✅─stabilize_df() enforces .col_names (snapshot) (#142)
│ │ ├─✅─stabilize_df() allows .col_names alongside ... specs (#142)
│ │ ├─✅─stabilize_df() preserves data frame class after column coercion (#142)
│ │ ├─✅─stabilize_df() works with no column specs and .extra_cols (#142)
│ │ ├─✅─stabilize_df() with unnamed specs errors informatively (#142)
│ │ ├─✅─stabilise_df() exists (#142)
│ │ ├─✅─stabilize_data_frame() exists (#142)
│ │ └─✅─stabilise_data_frame() exists (#142)
│ ├─☑️─Feature 136: Export error functions
│ │ ├─✅─.compile_pkg_condition_classes() compiles condition class chains (#136)
│ │ ├─✅─.compile_pkg_error_classes() compiles error class chains (#136)
│ │ ├─✅─pkg_abort() throws the expected error (#136)
│ │ ├─✅─pkg_abort() uses parent when provided (#136)
│ │ ├─✅─pkg_abort() passes dots to cli_abort() (#136)
│ │ ├─✅─pkg_abort() uses message_env when provided (#136)
│ │ └─✅─expect_pkg_error_classes() tests expressions for classes (#136)
│ ├─☑️─Feature 110: Implement `stabilize_lst()`
│ │ ├─✅─specify_lst() creates a working specifier (#110)
│ │ ├─✅─specify_lst() respects pre-configured element specs (#110)
│ │ ├─✅─specify_lst() supports element specs named 'x' and 'y' (#110)
│ │ ├─✅─specify_lst() passes through additional element specs from ... (#110)
│ │ ├─✅─specify_lst() respects .min_size (#110)
│ │ ├─✅─specify_lst() respects .allow_null (#110)
│ │ ├─✅─specify_list() exists (#110)
│ │ ├─✅─stabilize_lst() returns NULL for NULL input by default (#110)
│ │ ├─✅─stabilize_lst() respects .allow_null (#110)
│ │ ├─✅─stabilize_lst() returns a valid list unchanged (#110)
│ │ ├─✅─stabilize_lst() validates required named elements (#110)
│ │ ├─✅─stabilize_lst() errors when required named element is missing (#110)
│ │ ├─✅─stabilize_lst() errors informatively when element fails validation (#110)
│ │ ├─✅─stabilize_lst() errors on extra named elements by default (#110)
│ │ ├─✅─stabilize_lst() validates extra named elements with .named (#110)
│ │ ├─✅─stabilize_lst() errors on unnamed elements by default (#110)
│ │ ├─✅─stabilize_lst() validates unnamed elements with .unnamed (#110)
│ │ ├─✅─stabilize_lst() handles mixed named/unnamed lists (#110)
│ │ ├─✅─stabilize_lst() enforces .min_size (#110)
│ │ ├─✅─stabilize_lst() enforces .max_size (#110)
│ │ ├─✅─stabilize_lst() validates nested lists (#110)
│ │ ├─✅─stabilize_lst() with unnamed specs errors informatively (#110)
│ │ ├─✅─.check_duplicate_names(): errors on duplicate names by default (#110)
│ │ ├─✅─.check_duplicate_names(): allows duplicates with .allow_duplicate_names = TRUE (#110)
│ │ ├─✅─.check_duplicate_names(): reports all duplicate name groups (#110)
│ │ ├─✅─.check_duplicate_names(): unnamed elements do not count as duplicates (#110)
│ │ ├─✅─stabilize_list() exists (#110)
│ │ ├─✅─stabilise_lst() exists (#110)
│ │ ├─✅─stabilise_list() exists (#110)
│ │ ├─✅─stabilize_present() returns any non-NULL value unchanged (#110)
│ │ ├─✅─stabilize_present() errors for NULL (#110)
│ │ └─✅─stabilize_present() works as an element spec in stabilize_lst() (#110)
│ ├─☑️─Feature 201: feat: `to_df()`
│ │ ├─✅─to_df() returns a data frame unchanged (#201)
│ │ ├─✅─to_df() returns NULL for NULL input by default (#201)
│ │ ├─✅─to_df() respects allow_null (#201)
│ │ ├─✅─to_df() coerces a named list to a data frame (#201)
│ │ ├─✅─to_df() coerces a list of equal-length vectors to a data frame (#201)
│ │ ├─✅─to_df() errors for a list with incompatible column lengths (#201)
│ │ ├─✅─to_df() errors for non-coercible types (#201)
│ │ ├─✅─to_df.default() errors for non-coercible types (#201)
│ │ └─✅─to_data_frame() exists (#201)
│ ├─☑️─Bug 197: Update `specify_*_scalar()` defaults to match `stabilize_*_scalar()`
│ │ ├─✅─specify_chr_scalar defaults to allow_null = FALSE (#197)
│ │ ├─✅─specify_chr_scalar defaults to allow_zero_length = FALSE (#197)
│ │ ├─✅─specify_dbl_scalar defaults to allow_null = FALSE (#197)
│ │ ├─✅─specify_dbl_scalar defaults to allow_zero_length = FALSE (#197)
│ │ ├─✅─specify_fct_scalar defaults to allow_null = FALSE (#197)
│ │ ├─✅─specify_fct_scalar defaults to allow_zero_length = FALSE (#197)
│ │ ├─✅─specify_int_scalar defaults to allow_null = FALSE (#197)
│ │ ├─✅─specify_int_scalar defaults to allow_zero_length = FALSE (#197)
│ │ ├─✅─specify_lgl_scalar defaults to allow_null = FALSE (#197)
│ │ └─✅─specify_lgl_scalar defaults to allow_zero_length = FALSE (#197)
│ ├─☑️─Issue 189: feat: `to_*_scalar()` default arguments
│ │ ├─✅─stabilize_chr_scalar() allows length-1 chrs through (#22, #189)
│ │ ├─✅─stabilize_chr_scalar() respects allow_null (#22, #189)
│ │ ├─✅─stabilize_dbl_scalar() allows length-1 dbls through (#23, #189)
│ │ ├─✅─stabilize_dbl_scalar() respects allow_null (#23, #189)
│ │ ├─✅─stabilize_fct_scalar() works (#62, #189)
│ │ ├─✅─stabilize_fct_scalar() respects allow_null (#62, #189)
│ │ ├─✅─stabilize_int_scalar() allows length-1 ints through (#12, #189)
│ │ ├─✅─stabilize_int_scalar() respects allow_null (#12, #189)
│ │ ├─✅─stabilize_lgl_scalar() allows length-1 lgls through (#28, #189)
│ │ ├─✅─stabilize_lgl_scalar() respects allow_null (#28, #189)
│ │ ├─✅─to_chr_scalar() allows length-1 chrs through (#22, #189)
│ │ ├─✅─to_chr_scalar() respects allow_null (#22, #189)
│ │ ├─✅─to_chr_scalar respects allow_zero_length (#22, #43, #45, #189)
│ │ ├─✅─to_dbl_scalar() respects allow_null (#23, #189)
│ │ ├─✅─to_dbl_scalar respects allow_zero_length (#23, #43, #45, #189)
│ │ ├─✅─to_fct_scalar respects allow_zero_length (#62, #43, #45, #189)
│ │ ├─✅─to_int_scalar() respects allow_null (#12, #189)
│ │ ├─✅─to_int_scalar respects allow_zero_length (#12, #43, #45, #189)
│ │ ├─✅─to_lgl_scalar() allows length-1 lgls through (#32, #189)
│ │ └─✅─to_lgl_scalar() respects allow_null (#32, #189)
│ ├─☑️─Feature 188: feat: expect_pkg_error_snapshot()
│ │ ├─✅─expect_pkg_error_snapshot() snapshots error class and message (#188)
│ │ ├─✅─expect_pkg_error_snapshot() works with multiple class components (#188)
│ │ ├─✅─expect_pkg_error_snapshot() works from an env without stbl attached (#188)
│ │ └─✅─expect_pkg_error_classes() works from an env without stbl attached (#188)
│ ├─☑️─Feature 177: Don't mention levels/to_na in factor message?
│ │ └─✅─to_fct() throws errors for bad levels (#62, #67, #177)
│ ├─☑️─Feature 176: Better error messages
│ │ ├─✅─stabilize_dbl() checks min_value (#23, #176)
│ │ ├─✅─stabilize_dbl() checks max_value (#23, #176)
│ │ ├─✅─stabilize_int() checks min_value (#2, #6, #176)
│ │ └─✅─stabilize_int() checks max_value (#5, #176)
│ └─☑️─Feature 167: Add stabilise_*() aliases
│ ├─✅─stabilise_chr() exists (#167)
│ ├─✅─stabilise_character() exists (#167)
│ ├─✅─stabilise_chr_scalar() exists (#167)
│ ├─✅─stabilise_character_scalar() exists (#167)
│ ├─✅─stabilise_dbl() exists (#167)
│ ├─✅─stabilise_double() exists (#167)
│ ├─✅─stabilise_dbl_scalar() exists (#167)
│ ├─✅─stabilise_double_scalar() exists (#167)
│ ├─✅─stabilise_fct() exists (#167)
│ ├─✅─stabilise_factor() exists (#167)
│ ├─✅─stabilise_fct_scalar() exists (#167)
│ ├─✅─stabilise_factor_scalar() exists (#167)
│ ├─✅─stabilise_int() exists (#167)
│ ├─✅─stabilise_integer() exists (#167)
│ ├─✅─stabilise_int_scalar() exists (#167)
│ ├─✅─stabilise_integer_scalar() exists (#167)
│ ├─✅─stabilise_lgl() exists (#167)
│ ├─✅─stabilise_logical() exists (#167)
│ ├─✅─stabilise_lgl_scalar() exists (#167)
│ └─✅─stabilise_logical_scalar() exists (#167)
└─█─Milestone: v0.4.0 (18 issues, 262 tests)
├─☑️─Bug 253: `expect_pkg_error_snapshot()` vs coverage
│ ├─✅─.is_covr_count_call() identifies covr counter calls (#253)
│ └─✅─.strip_covr_from_expr() removes covr counter wrappers (#253)
├─☑️─Task 226: chore: complete C optimization for are_*_ish() and to_*() methods
│ ├─✅─.dbl_to_lgl() converts 0 to FALSE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() converts non-zero to TRUE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() passes NA and NaN through; valid always TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() handles integer input; valid always TRUE (#226, #237)
│ ├─✅─.int_to_dbl() converts integers to doubles; valid always TRUE (#226, #237)
│ ├─✅─.int_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.int_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts TRUE to 1.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts FALSE to 0.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lgl_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts TRUE to 1L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts FALSE to 0L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.cpx_to_dbl() extracts real part when Im is zero (#226, #237)
│ ├─✅─.cpx_to_dbl() passes NA complex through as NA_real; valid TRUE (#226, #237)
│ ├─✅─.cpx_to_dbl() returns real part and valid FALSE for non-zero Im (#226, #237)
│ ├─✅─.cpx_to_int() converts whole-number complex with Im 0 (#226, #237)
│ ├─✅─.cpx_to_int() passes NA complex through; flags FALSE (#226, #237)
│ ├─✅─.cpx_to_int() marks non-zero Im as non_number (#226, #237)
│ ├─✅─.cpx_to_int() marks fractional real part as bad_precision (#226, #237)
│ ├─✅─.fct_to_dbl() converts numeric factor levels to doubles (#226, #237)
│ ├─✅─.fct_to_dbl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_dbl() marks non-numeric levels as not valid (#226, #237)
│ ├─✅─.fct_to_int() converts whole-number factor levels to integers (#226, #237)
│ ├─✅─.fct_to_int() passes NA factor element through; flags FALSE (#226, #237)
│ ├─✅─.fct_to_int() marks non-integer levels correctly (#226, #237)
│ ├─✅─.fct_to_lgl() converts TRUE/FALSE levels (#226, #237)
│ ├─✅─.fct_to_lgl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_lgl() marks non-logical levels as not valid (#226, #237)
│ ├─✅─.chr_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.chr_are_fctish() checks membership in levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats to_na values as fctish (#226, #237)
│ ├─✅─.fct_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.fct_are_fctish() checks factor level membership in target levels (#226, #237)
│ ├─✅─.fct_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.lst_to_dbl() converts a flat list of numeric/lgl/int scalars (#226, #237)
│ ├─✅─.lst_to_dbl() converts numeric character strings (#226, #237)
│ ├─✅─.lst_to_dbl() marks non-parseable character strings as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts complex with Im == 0 (#226, #237)
│ ├─✅─.lst_to_dbl() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts a flat list of integer/logical scalars (#226, #237)
│ ├─✅─.lst_to_int() converts whole-number doubles (#226, #237)
│ ├─✅─.lst_to_int() converts integer-valued character strings (#226, #237)
│ ├─✅─.lst_to_int() marks fractional character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-number character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts complex with Im == 0 and whole Re (#226, #237)
│ ├─✅─.lst_to_int() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() marks fractional doubles as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts a flat list of lgl/int/dbl scalars (#226, #237)
│ ├─✅─.lst_to_lgl() converts lgl-ish character strings (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-lgl character strings as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_chr() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() converts non-character atomic scalars to strings (#226, #237, #239)
│ ├─✅─.lst_to_chr() converts factor elements via their level labels (#226, #237, #239)
│ ├─✅─.lst_to_chr() marks non-character single-element vectors as not valid (#226, #237)
│ ├─✅─.lst_to_chr() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_fct() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() marks non-character scalars as not valid (#226, #237)
│ ├─✅─.lst_to_fct() marks factor elements as valid (#226, #237)
│ ├─✅─.lst_to_fct() marks non-character/factor single-element vectors as not valid (#226, #237)
│ └─✅─.lst_to_fct() marks non-scalar elements in multi-element lists as not valid (#226, #237)
├─☑️─Issue 221: C optimization: .are_not_dbl_ish_chr() — single-pass character-to-double failure detector
│ ├─✅─.chr_to_dbl() converts numeric strings (#221, #237)
│ ├─✅─.chr_to_dbl() converts Inf strings (#221, #237)
│ ├─✅─.chr_to_dbl() passes NA through as valid (#221, #237)
│ └─✅─.chr_to_dbl() marks invalid strings as not valid (#221, #237)
├─☑️─Task 220: C optimization: .find_failures() / %&&% — inline min/max range checks
│ ├─✅─.check_min_dbl() returns NULL when all values pass (#220)
│ ├─✅─.check_min_dbl() returns failure indices for values below min (#220)
│ ├─✅─.check_min_dbl() treats NA as passing (#220)
│ ├─✅─.check_min_dbl() handles integer input (#220)
│ ├─✅─.check_max_dbl() returns NULL when all values pass (#220)
│ ├─✅─.check_max_dbl() returns failure indices for values above max (#220)
│ ├─✅─.check_max_dbl() treats NA as passing (#220)
│ └─✅─.check_max_dbl() handles integer input (#220)
├─☑️─Issue 219: C optimization: are_int_ish.character() / to_int.character() — single-pass C checker
│ ├─✅─.chr_to_int() converts integer strings (#219, #237)
│ ├─✅─.chr_to_int() converts whole-number double strings (#219, #237)
│ ├─✅─.chr_to_int() passes NA through (#219, #237)
│ ├─✅─.chr_to_int() marks fractional strings as bad_precision (#219, #237)
│ ├─✅─.chr_to_int() marks non-number strings as non_number (#219, #237)
│ └─✅─.chr_to_int() marks Inf strings as bad_precision (#219, #237)
├─☑️─Feature 218: C optimization: are_lgl_ish.character() / to_lgl.character() — eliminate duplicate toupper() call
│ ├─✅─.chr_to_lgl() converts TRUE/T strings to TRUE (#218, #237)
│ ├─✅─.chr_to_lgl() converts FALSE/F strings to FALSE (#218, #237)
│ ├─✅─.chr_to_lgl() passes NA through as valid (#218, #237)
│ ├─✅─.chr_to_lgl() converts numeric strings (#218, #237)
│ ├─✅─.chr_to_lgl() marks invalid strings as not valid (#218, #237)
│ └─✅─.dbl_are_lglish() returns all TRUE (#218, #237)
├─☑️─Issue 217: C optimization: are_int_ish.double() — replace multi-vector arithmetic with single-pass C loop
│ ├─✅─are_int_ish() works for doubles (#93, #217)
│ ├─✅─.dbl_to_int() converts integer-valued doubles (#217, #237)
│ ├─✅─.dbl_to_int() passes NA and NaN through as not bad_precision (#217, #237)
│ ├─✅─.dbl_to_int() marks fractional doubles as bad_precision (#217, #237)
│ ├─✅─.dbl_to_int() marks Inf and out-of-range values as bad_precision (#217, #237)
│ └─✅─to_int() errors for dbls that would lose precision (#2, #217)
├─☑️─Feature 213: `pkg_warn()` and `pkg_inform()`
│ ├─✅─.stbl_warn() throws the expected warning (#213)
│ ├─✅─.stbl_inform() throws the expected message (#213)
│ ├─✅─.compile_pkg_message_classes() compiles message class chains (#213)
│ ├─✅─pkg_inform() signals the expected message (#213)
│ ├─✅─pkg_inform() uses parent when provided (#213)
│ ├─✅─pkg_inform() uses message_env when provided (#213)
│ ├─✅─expect_pkg_message_classes() tests expressions for classes (#213)
│ ├─✅─expect_pkg_message_snapshot() snapshots message class and message (#213)
│ ├─✅─expect_pkg_message_snapshot() works with multiple class components (#213)
│ ├─✅─expect_pkg_message_snapshot() works from an env without stbl attached (#213)
│ ├─✅─expect_pkg_message_classes() works from an env without stbl attached (#213)
│ ├─✅─.compile_pkg_warning_classes() compiles warning class chains (#213)
│ ├─✅─pkg_warn() signals the expected warning (#213)
│ ├─✅─pkg_warn() uses parent when provided (#213)
│ ├─✅─pkg_warn() passes dots to cli_warn() (#213)
│ ├─✅─pkg_warn() uses message_env when provided (#213)
│ ├─✅─expect_pkg_warning_classes() tests expressions for classes (#213)
│ ├─✅─expect_pkg_warning_snapshot() snapshots warning class and message (#213)
│ ├─✅─expect_pkg_warning_snapshot() works with multiple class components (#213)
│ ├─✅─expect_pkg_warning_snapshot() works from an env without stbl attached (#213)
│ ├─✅─expect_pkg_warning_classes() works from an env without stbl attached (#213)
│ ├─✅─.compile_dash() pastes with a dash separator (#213)
│ ├─✅─.collapse_dash() collapses a vector with dashes (#213)
│ └─✅─.compile_pkg_condition_classes() compiles condition class chains (#213)
├─☑️─Feature 200: feat: dots in `to_lst()` and `to_df()`
│ ├─✅─to_df() rejects unused dots for methods that ignore them (#200)
│ └─✅─to_lst() rejects unused dots for methods that ignore them (#200)
├─☑️─Feature 182: Implement `to()`
│ ├─✅─to() returns logical unchanged (#182)
│ ├─✅─to() returns integer unchanged (#182)
│ ├─✅─to() returns double unchanged (#182)
│ ├─✅─to() returns character unchanged (#182)
│ ├─✅─to() passes NULL through unchanged (#182)
│ ├─✅─to() converts integer to logical (#182)
│ ├─✅─to() converts double to logical (#182)
│ ├─✅─to() converts character to logical (#182)
│ ├─✅─to() errors for incompatible character -> logical (#182)
│ ├─✅─to() converts factor to logical (#182)
│ ├─✅─to() errors for incompatible factor -> logical (#182)
│ ├─✅─to() converts list to logical (#182)
│ ├─✅─to() converts logical to integer (#182)
│ ├─✅─to() converts double to integer (#182)
│ ├─✅─to() errors for double -> integer with precision loss (#182)
│ ├─✅─to() converts character to integer (#182)
│ ├─✅─to() errors for incompatible character -> integer (#182)
│ ├─✅─to() converts factor to integer (#182)
│ ├─✅─to() converts list to integer (#182)
│ ├─✅─to() converts integer to double (#182)
│ ├─✅─to() converts logical to double (#182)
│ ├─✅─to() converts character to double (#182)
│ ├─✅─to() errors for incompatible character -> double (#182)
│ ├─✅─to() converts factor to double (#182)
│ ├─✅─to() converts list to double (#182)
│ ├─✅─to() converts integer to character (#182)
│ ├─✅─to() converts double to character (#182)
│ ├─✅─to() converts logical to character (#182)
│ ├─✅─to() converts factor to character (#182)
│ ├─✅─to() converts list to character (#182)
│ ├─✅─to() converts character to factor using .to levels (#182)
│ ├─✅─to() converts integer to factor using .to levels (#182)
│ ├─✅─to() passes levels through from factor .to (#182)
│ ├─✅─to() respects explicit levels argument in to.factor (#182)
│ ├─✅─to() respects to_na argument in to.factor (#182)
│ ├─✅─to() converts to list (#182)
│ ├─✅─to() returns NULL by default when x is NULL (#182)
│ ├─✅─to() errors when x is NULL and allow_null = FALSE (#182)
│ ├─✅─to() passes data frame through unchanged with data frame target (#182)
│ ├─✅─to() converts list to data frame (#182)
│ ├─✅─to() converts vector to data frame (#182)
│ ├─✅─to() returns NULL when .to is NULL (#182)
│ ├─✅─to() errors when .to is NULL and allow_null = FALSE (#182)
│ ├─✅─to() respects coerce_character = FALSE for integer target (#182)
│ ├─✅─to() respects coerce_character = FALSE for double target (#182)
│ └─✅─to() errors for unsupported target types (#182)
├─☑️─Feature 251: `to_chr.function()`
│ ├─✅─to_chr() converts named functions (#251)
│ └─✅─to_chr() errors for anonymous functions (#251)
├─☑️─Feature 250: `to_fn()`
│ ├─✅─is_fn_ish() returns TRUE for functions (#250)
│ ├─✅─is_fn_ish() returns TRUE for formulas (#250)
│ ├─✅─is_fn_ish() returns TRUE for length-1 character strings (#250)
│ ├─✅─is_fn_ish() returns FALSE for NULL (#250)
│ ├─✅─is_fn_ish() returns FALSE for non-character vectors (#250)
│ ├─✅─is_fn_ish() returns FALSE for length != 1 character (#250)
│ ├─✅─is_fn_ish() returns FALSE with bad ':' usage (#250)
│ ├─✅─is_function_ish() exists (#250)
│ ├─✅─are_fn_ish() returns TRUE for functions (#250)
│ ├─✅─are_fn_ish() returns TRUE for formulas (#250)
│ ├─✅─are_fn_ish() does element-wise check for character (#250)
│ ├─✅─are_fn_ish() returns logical(0) for NULL (#250)
│ ├─✅─are_fn_ish() returns FALSE for non-fn-ish types (#250)
│ ├─✅─are_function_ish() is a synonym of are_fn_ish() (#250)
│ ├─✅─to_fn() works for functions (#250)
│ ├─✅─to_fn() works for lambda functions (#250)
│ ├─✅─to_fn() works for NULL (#250)
│ ├─✅─to_fn() respects allow_null for NULL input (#250)
│ ├─✅─to_fn() works for simple character names (#250)
│ ├─✅─to_fn() works for namespaced character names (#250)
│ ├─✅─to_fn() fails cleanly for weird ':' use in character names (#250)
│ ├─✅─to_fn() respects definition_env for character input (#250)
│ ├─✅─to_fn() errors informatively for unknown character names (#250)
│ ├─✅─to_fn() errors for length > 1 character input (#250)
│ ├─✅─to_fn() respects allow_null for length-0 character input (#250)
│ ├─✅─to_fn() errors informatively for bad namespaced names (#250)
│ ├─✅─to_fn() errors informatively for non-coercible types (#250)
│ ├─✅─to_function() exists (#250)
│ ├─✅─.chr_to_fn() works via C callable (#250)
│ ├─✅─.chr_are_fnish() works via C callable (#250)
│ ├─✅─to() converts character to function (#250)
│ ├─✅─to() passes function through unchanged (#250)
│ ├─✅─to() converts formula to function (#250)
│ └─✅─to() errors for non-coercible types to function (#250)
├─☑️─Feature 241: Add `*_to_chr` and `*_to_fct` to the C API
│ ├─✅─to_chr() works for ints via C (#241)
│ ├─✅─to_chr() works for lgls via C (#241)
│ ├─✅─to_chr() works for dbls via C (#241)
│ ├─✅─to_chr() works for fcts via C (#241)
│ ├─✅─to_fct() works for ints via C (#241)
│ ├─✅─to_fct() errors for ints with unexpected levels (#241)
│ └─✅─to_fct() sorts integer levels numerically not lexicographically (#241)
├─☑️─Feature 239: Replace all `to_*.list()` methods with C routines
│ ├─✅─.lst_to_dbl() unwraps singly-nested lists (#239)
│ ├─✅─.lst_to_dbl() marks multiply-nested lists as not valid (#239)
│ ├─✅─.lst_to_int() unwraps singly-nested lists (#239)
│ ├─✅─.lst_to_int() marks multiply-nested lists as not valid (#239)
│ ├─✅─.lst_to_lgl() unwraps singly-nested lists (#239)
│ ├─✅─.lst_to_lgl() marks multiply-nested lists as not valid (#239)
│ ├─✅─.lst_to_chr() converts non-character atomic scalars to strings (#226, #237, #239)
│ ├─✅─.lst_to_chr() converts factor elements via their level labels (#226, #237, #239)
│ ├─✅─.lst_to_chr() unwraps singly-nested lists (#239)
│ ├─✅─.lst_to_chr() marks multiply-nested lists as not valid (#239)
│ ├─✅─.lst_to_fct() unwraps singly-nested lists (#239)
│ └─✅─.lst_to_fct() marks multiply-nested lists as not valid (#239)
├─☑️─Feature 237: Standardize callable C API: stbl_*_to_* should always return result + valid list
│ ├─✅─.chr_to_lgl() converts TRUE/T strings to TRUE (#218, #237)
│ ├─✅─.chr_to_lgl() converts FALSE/F strings to FALSE (#218, #237)
│ ├─✅─.chr_to_lgl() passes NA through as valid (#218, #237)
│ ├─✅─.chr_to_lgl() converts numeric strings (#218, #237)
│ ├─✅─.chr_to_lgl() marks invalid strings as not valid (#218, #237)
│ ├─✅─.chr_to_int() converts integer strings (#219, #237)
│ ├─✅─.chr_to_int() converts whole-number double strings (#219, #237)
│ ├─✅─.chr_to_int() passes NA through (#219, #237)
│ ├─✅─.chr_to_int() marks fractional strings as bad_precision (#219, #237)
│ ├─✅─.chr_to_int() marks non-number strings as non_number (#219, #237)
│ ├─✅─.chr_to_int() marks Inf strings as bad_precision (#219, #237)
│ ├─✅─.chr_to_dbl() converts numeric strings (#221, #237)
│ ├─✅─.chr_to_dbl() converts Inf strings (#221, #237)
│ ├─✅─.chr_to_dbl() passes NA through as valid (#221, #237)
│ ├─✅─.chr_to_dbl() marks invalid strings as not valid (#221, #237)
│ ├─✅─.dbl_to_int() converts integer-valued doubles (#217, #237)
│ ├─✅─.dbl_to_int() passes NA and NaN through as not bad_precision (#217, #237)
│ ├─✅─.dbl_to_int() marks fractional doubles as bad_precision (#217, #237)
│ ├─✅─.dbl_to_int() marks Inf and out-of-range values as bad_precision (#217, #237)
│ ├─✅─.dbl_to_lgl() converts 0 to FALSE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() converts non-zero to TRUE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() passes NA and NaN through; valid always TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() handles integer input; valid always TRUE (#226, #237)
│ ├─✅─.dbl_are_lglish() returns all TRUE (#218, #237)
│ ├─✅─.int_to_dbl() converts integers to doubles; valid always TRUE (#226, #237)
│ ├─✅─.int_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.int_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts TRUE to 1.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts FALSE to 0.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lgl_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts TRUE to 1L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts FALSE to 0L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lgl_are_intish() returns all TRUE (#237)
│ ├─✅─.cpx_to_dbl() extracts real part when Im is zero (#226, #237)
│ ├─✅─.cpx_to_dbl() passes NA complex through as NA_real; valid TRUE (#226, #237)
│ ├─✅─.cpx_to_dbl() returns real part and valid FALSE for non-zero Im (#226, #237)
│ ├─✅─.cpx_to_int() converts whole-number complex with Im 0 (#226, #237)
│ ├─✅─.cpx_to_int() passes NA complex through; flags FALSE (#226, #237)
│ ├─✅─.cpx_to_int() marks non-zero Im as non_number (#226, #237)
│ ├─✅─.cpx_to_int() marks fractional real part as bad_precision (#226, #237)
│ ├─✅─.fct_to_dbl() converts numeric factor levels to doubles (#226, #237)
│ ├─✅─.fct_to_dbl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_dbl() marks non-numeric levels as not valid (#226, #237)
│ ├─✅─.fct_to_int() converts whole-number factor levels to integers (#226, #237)
│ ├─✅─.fct_to_int() passes NA factor element through; flags FALSE (#226, #237)
│ ├─✅─.fct_to_int() marks non-integer levels correctly (#226, #237)
│ ├─✅─.fct_to_lgl() converts TRUE/FALSE levels (#226, #237)
│ ├─✅─.fct_to_lgl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_lgl() marks non-logical levels as not valid (#226, #237)
│ ├─✅─.chr_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.chr_are_fctish() checks membership in levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats to_na values as fctish (#226, #237)
│ ├─✅─.fct_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.fct_are_fctish() checks factor level membership in target levels (#226, #237)
│ ├─✅─.fct_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.lst_to_dbl() converts a flat list of numeric/lgl/int scalars (#226, #237)
│ ├─✅─.lst_to_dbl() converts numeric character strings (#226, #237)
│ ├─✅─.lst_to_dbl() marks non-parseable character strings as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts complex with Im == 0 (#226, #237)
│ ├─✅─.lst_to_dbl() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() unpacks a one-element list with a double vector (#237)
│ ├─✅─.lst_to_dbl() unpacks a one-element list with an integer vector (#237)
│ ├─✅─.lst_to_dbl() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_dbl() marks non-coercible single-element as not valid (#237)
│ ├─✅─.lst_to_dbl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts a flat list of integer/logical scalars (#226, #237)
│ ├─✅─.lst_to_int() converts whole-number doubles (#226, #237)
│ ├─✅─.lst_to_int() converts integer-valued character strings (#226, #237)
│ ├─✅─.lst_to_int() marks fractional character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-number character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts complex with Im == 0 and whole Re (#226, #237)
│ ├─✅─.lst_to_int() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() marks fractional doubles as not valid (#226, #237)
│ ├─✅─.lst_to_int() unpacks a one-element list with an integer vector (#237)
│ ├─✅─.lst_to_int() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_int() unpacks a one-element list with a double vector (#237)
│ ├─✅─.lst_to_int() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts a flat list of lgl/int/dbl scalars (#226, #237)
│ ├─✅─.lst_to_lgl() converts lgl-ish character strings (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-lgl character strings as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() unpacks a one-element list with a logical vector (#237)
│ ├─✅─.lst_to_lgl() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_lgl() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_chr() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() converts non-character atomic scalars to strings (#226, #237, #239)
│ ├─✅─.lst_to_chr() converts factor elements via their level labels (#226, #237, #239)
│ ├─✅─.lst_to_chr() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_chr() marks non-character single-element vectors as not valid (#226, #237)
│ ├─✅─.lst_to_chr() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_fct() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() marks non-character scalars as not valid (#226, #237)
│ ├─✅─.lst_to_fct() marks factor elements as valid (#226, #237)
│ ├─✅─.lst_to_fct() unpacks a one-element list with a character vector (#237)
│ ├─✅─.lst_to_fct() unpacks a one-element list with a factor (#237)
│ ├─✅─.lst_to_fct() marks non-character/factor single-element vectors as not valid (#226, #237)
│ └─✅─.lst_to_fct() marks non-scalar elements in multi-element lists as not valid (#226, #237)
├─☑️─Feature 235: Callable C Functions
│ ├─✅─inst/include/stbl.h is installed (#235)
│ ├─✅─inst/include/stbl.c is installed (#235)
│ ├─✅─stbl.h declares all expected function pointers (#235)
│ ├─✅─stbl.h declares stbl_init_api() (#235)
│ ├─✅─stbl.c assigns all expected callables via R_GetCCallable (#235)
│ ├─✅─stbl.c defines stbl_init_api() (#235)
│ └─✅─src/init.c registers all expected C callables (#235)
├─☑️─Bug 234: Allow users to define objects inside `expect_pkg_*_snapshot()`
│ ├─✅─expect_pkg_message_snapshot() allows object definition inside expression (#234)
│ ├─✅─expect_pkg_warning_snapshot() allows object definition inside expression (#234)
│ ├─✅─.capture_first_pkg_condition() captures a condition and returns it invisibly (#234)
│ ├─✅─.capture_first_pkg_condition() returns NULL when no condition is signalled (#234)
│ └─✅─.capture_first_pkg_condition() evaluates obj_expr in env (#234)
└─☑️─Feature 231: feat: add `max_levels` argument to `is_fct_ish()`
└─✅─is_fct_ish() supports max_levels (#231)
# Issue state: 📥 = open, ☑️ = closed (completed), ⛔ = closed (won't fix)
# Test disposition: ✅ = passed, ❌ = failed, 🚫 = skipped
🟢 All issues have at least one test
🙈 28 issues with label "qcthat-nocov" were ignored
This report was generated by this GitHub Actions job.
Reports generated: 2026-07-28 14:18:43 UTC
Session Info
─ Session info ───────────────────────────────────────────────────────────────setting value
version R version 4.6.1 (2026-06-24)
os Ubuntu 24.04.4 LTS
system x86_64, linux-gnu
ui X11
language (EN)
collate C.UTF-8
ctype C.UTF-8
tz UTC
date 2026-07-28
pandoc 3.8.3 @ /opt/hostedtoolcache/pandoc/3.8.3/x64/pandoc
quarto 1.10.18 @ /usr/local/bin/quarto
─ Packages ───────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
askpass 1.2.1 2024-10-04 [1] RSPM
astgrepr 0.1.1 2025-06-07 [1] RSPM
backports 1.5.1 2026-04-03 [1] RSPM
base * 4.6.1 2026-06-24 [3] local
base64enc 0.1-6 2026-02-02 [1] RSPM
boot 1.3-32 2025-08-29 [3] CRAN (R 4.6.1)
brio 1.1.5 2024-04-24 [1] RSPM
bslib 0.11.0 2026-05-16 [1] RSPM
cachem 1.1.0 2024-05-16 [1] RSPM
callr 3.8.0 2026-06-05 [1] RSPM
checkmate 2.3.4 2026-02-03 [1] RSPM
class 7.3-23 2025-01-01 [3] CRAN (R 4.6.1)
cli 3.6.6 2026-04-09 [1] RSPM
clipr 0.8.1 2026-05-25 [1] RSPM
cluster 2.1.8.2 2026-02-05 [3] CRAN (R 4.6.1)
codetools 0.2-20 2024-03-31 [3] CRAN (R 4.6.1)
compiler 4.6.1 2026-06-24 [3] local
covr 3.6.5 2025-11-09 [1] RSPM
crayon 1.5.3 2024-06-20 [1] RSPM
credentials 2.0.3 2025-09-12 [1] RSPM
curl 7.1.0 2026-04-22 [1] RSPM
datasets * 4.6.1 2026-06-24 [3] local
desc 1.4.3 2023-12-10 [1] RSPM
diffobj 0.3.8 2026-07-17 [1] RSPM
digest 0.6.39 2025-11-19 [1] RSPM
downlit 0.4.5 2025-11-14 [1] RSPM
dplyr 1.2.1 2026-04-03 [1] RSPM
emoji 16.0.0 2024-10-28 [1] RSPM
evaluate 1.0.5 2025-08-27 [1] RSPM
fansi 1.0.7 2025-11-19 [1] RSPM
fastmap 1.2.0 2024-05-15 [1] RSPM
fontawesome 0.5.3 2024-11-16 [1] RSPM
foreign 0.8-91 2026-01-29 [3] CRAN (R 4.6.1)
fs 2.1.0 2026-04-18 [1] RSPM
generics 0.1.4 2025-05-09 [1] RSPM
gert 2.4.0 2026-07-22 [1] RSPM
gh 1.6.1.9000 2026-07-28 [1] Github (r-lib/gh@31b775a)
git2r 0.36.2 2025-03-29 [1] RSPM
gitcreds 0.1.2 2022-09-08 [1] RSPM
glue 1.8.1 2026-04-17 [1] RSPM
graphics * 4.6.1 2026-06-24 [3] local
grDevices * 4.6.1 2026-06-24 [3] local
grid 4.6.1 2026-06-24 [3] local
gsm.utils 0.4.0 2026-07-14 [1] Github (Gilead-Public/gsm.utils@b020480)
highr 0.12 2026-03-06 [1] RSPM
htmltools 0.5.9 2025-12-04 [1] RSPM
httr 1.4.8 2026-02-13 [1] RSPM
httr2 1.3.0 2026-07-13 [1] RSPM
ini 0.3.1 2018-05-20 [1] RSPM
jquerylib 0.1.4 2021-04-26 [1] RSPM
jsonlite 2.0.0 2025-03-27 [1] RSPM
KernSmooth 2.23-26 2025-01-01 [3] CRAN (R 4.6.1)
knitr 1.51 2025-12-20 [1] RSPM
later 1.4.8 2026-03-05 [1] RSPM
lattice 0.22-9 2026-02-09 [3] CRAN (R 4.6.1)
lifecycle 1.0.5 2026-01-08 [1] RSPM
magrittr 2.0.5 2026-04-04 [1] RSPM
MASS 7.3-65 2025-02-28 [3] CRAN (R 4.6.1)
Matrix 1.7-5 2026-03-21 [3] CRAN (R 4.6.1)
memoise 2.0.1 2021-11-26 [1] RSPM
methods * 4.6.1 2026-06-24 [3] local
mgcv 1.9-4 2025-11-07 [3] CRAN (R 4.6.1)
mime 0.13 2025-03-17 [1] RSPM
nlme 3.1-169 2026-03-27 [3] CRAN (R 4.6.1)
nnet 7.3-20 2025-01-01 [3] CRAN (R 4.6.1)
openssl 2.4.2 2026-06-09 [1] RSPM
otel 0.2.0 2025-08-29 [1] RSPM
pak 0.11.1 2026-07-22 [2] local
parallel 4.6.1 2026-06-24 [3] local
pillar 1.11.1 2025-09-17 [1] RSPM
pkgbuild 1.4.8 2025-05-26 [1] RSPM
pkgconfig 2.0.3 2019-09-22 [1] RSPM
pkgdown 2.2.1 2026-07-07 [1] RSPM
pkgload 1.5.3 2026-06-15 [1] RSPM
praise 1.0.0 2015-08-11 [1] RSPM
processx 3.9.0 2026-04-22 [1] RSPM
ps 1.9.3 2026-04-20 [1] RSPM
purrr 1.2.2 2026-04-10 [1] RSPM
qcthat 1.1.3 2026-07-28 [1] Github (Gilead-Public/qcthat@e627805)
quarto 1.5.1 2025-09-04 [1] RSPM
R6 2.6.1 2025-02-15 [1] RSPM
ragg 1.5.2 2026-03-23 [1] RSPM
rappdirs 0.3.4 2026-01-17 [1] RSPM
Rcpp 1.1.2 2026-07-05 [1] RSPM
remotes 2.5.0 2024-03-17 [1] RSPM (R 4.6.0)
rex 1.2.2 2026-03-28 [1] RSPM
rlang 1.3.0 2026-07-05 [1] RSPM
rmarkdown 2.31 2026-03-26 [1] RSPM
rpart 4.1.27 2026-03-27 [3] CRAN (R 4.6.1)
rprojroot 2.1.1 2025-08-26 [1] RSPM
rrapply 1.2.8 2025-11-25 [1] RSPM
rstudioapi 0.19.0 2026-06-11 [1] RSPM
rvest 1.0.5 2025-08-29 [1] RSPM
sass 0.4.10 2025-04-11 [1] RSPM
selectr 0.6-0 2026-06-23 [1] RSPM
sessioninfo 1.2.4 2026-06-04 [1] any (@1.2.4)
spatial 7.3-18 2025-01-01 [3] CRAN (R 4.6.1)
splines 4.6.1 2026-06-24 [3] local
stats * 4.6.1 2026-06-24 [3] local
stats4 4.6.1 2026-06-24 [3] local
stbl 0.4.0 2026-07-28 [1] local
stringi 1.8.7 2025-03-27 [1] RSPM
stringr 1.6.0 2025-11-04 [1] RSPM
survival 3.8-6 2026-01-16 [3] CRAN (R 4.6.1)
sys 3.4.3 2024-10-04 [1] RSPM
systemfonts 1.3.2 2026-03-05 [1] RSPM
tcltk 4.6.1 2026-06-24 [3] local
testthat 3.3.2 2026-01-11 [1] RSPM
textshaping 1.0.5 2026-03-06 [1] RSPM
tibble 3.3.1 2026-01-11 [1] RSPM
tidyr 1.3.2 2025-12-19 [1] RSPM
tidyselect 1.2.1 2024-03-11 [1] RSPM
tinytex 0.60 2026-06-16 [1] RSPM
tools 4.6.1 2026-06-24 [3] local
usethis 3.2.1 2025-09-06 [1] RSPM
utf8 1.2.6 2025-06-08 [1] RSPM
utils * 4.6.1 2026-06-24 [3] local
vctrs 0.7.3 2026-04-11 [1] RSPM
waldo 0.6.2 2025-07-11 [1] RSPM
whisker 0.4.1 2022-12-05 [1] RSPM
withr 3.0.3 2026-06-19 [1] RSPM
xfun 0.60 2026-07-09 [1] RSPM
xml2 1.6.0 2026-06-22 [1] RSPM
yaml 2.3.12 2025-12-10 [1] RSPM
zip 3.0.1 2026-07-13 [1] RSPM
[1] /home/runner/work/_temp/Library
[2] /opt/R/4.6.1/lib/R/site-library
[3] /opt/R/4.6.1/lib/R/library
- ── Packages attached to the search path.
──────────────────────────────────────────────────────────────────────────────