Nothing
test_that("settings_read reads configuration from YAML file", {
test_dir <- create_test_project()
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
config <- settings_read()
expect_type(config, "list")
expect_true("data" %in% names(config))
expect_true("packages" %in% names(config))
expect_true("connections" %in% names(config))
expect_true("options" %in% names(config))
})
test_that("settings_read handles missing config file", {
test_dir <- create_test_dir()
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
expect_error(settings_read("nonexistent.yml"))
})
test_that("settings_write writes configuration to file", {
test_dir <- create_test_dir()
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
test_config <- list(
data = list(example = "data/example.csv"),
packages = c("dplyr", "ggplot2")
)
settings_write(test_config, settings_file = "test_config.yml")
expect_true(file.exists("test_config.yml"))
# Read it back using yaml::read_yaml (gets raw structure with "default" wrapper)
config_raw <- yaml::read_yaml("test_config.yml")
expect_equal(config_raw$default$data$example, "data/example.csv")
expect_equal(config_raw$default$packages, c("dplyr", "ggplot2"))
# Read back with settings_read
cfg_back <- settings_read(settings_file = "test_config.yml")
expect_equal(cfg_back$data$example, "data/example.csv")
# Packages are a character vector when written as simple strings
expect_equal(cfg_back$packages, c("dplyr", "ggplot2"))
})
# ============================================================================
# Config Resolution and settings() Helper Tests
# ============================================================================
test_that("settings() helper with flat config accesses directories correctly", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
config_content <- "default:
project_type: project
directories:
notebooks: my_notebooks
scripts: my_scripts
functions: my_functions
cache: my_cache
"
writeLines(config_content, "config.yml")
# Test direct access to directories
expect_equal(settings("directories.notebooks"), "my_notebooks")
expect_equal(settings("directories.scripts"), "my_scripts")
expect_equal(settings("directories.functions"), "my_functions")
# Test smart lookup (single key checks directories first)
expect_equal(settings("notebooks"), "my_notebooks")
expect_equal(settings("scripts"), "my_scripts")
expect_equal(settings("functions"), "my_functions")
# Test project_type access
expect_equal(settings("project_type"), "project")
# Test default values
expect_equal(settings("nonexistent"), NULL)
expect_equal(settings("nonexistent", default = "fallback"), "fallback")
})
test_that("settings() helper handles legacy options structure", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
# Create legacy config with options$notebook_dir
config_content <- "default:
options:
notebook_dir: legacy_notebooks
script_dir: legacy_scripts
"
writeLines(config_content, "config.yml")
# Smart lookup should find legacy keys
expect_equal(settings("notebook"), "legacy_notebooks")
expect_equal(settings("script"), "legacy_scripts")
})
test_that("settings() prioritizes directories over legacy options", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
# Config with BOTH new and legacy structures
config_content <- "default:
directories:
notebooks: new_notebooks
options:
notebook_dir: legacy_notebooks
"
writeLines(config_content, "config.yml")
# Should prefer directories structure
expect_equal(settings("notebooks"), "new_notebooks")
# Explicit path still works
expect_equal(settings("options.notebook_dir"), "legacy_notebooks")
})
test_that("settings_read() merges directories correctly", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
config_content <- "default:
directories:
notebooks: notebooks
scripts: scripts
cache: outputs/private/cache
"
writeLines(config_content, "config.yml")
cfg <- settings_read()
# Check structure
expect_true(!is.null(cfg$directories))
expect_equal(cfg$directories$notebooks, "notebooks")
expect_equal(cfg$directories$scripts, "scripts")
expect_equal(cfg$directories$cache, "outputs/private/cache")
})
test_that("split file config with inline directories works", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
dir.create("settings", showWarnings = FALSE)
# Main config with inline directories and split data
config_content <- "default:
project_type: project
directories:
notebooks: notebooks
scripts: scripts
cache: outputs/private/cache
data: settings/data.yml
"
writeLines(config_content, "config.yml")
# Create data settings file
data_content <- "data:
example:
path: data/example.csv
type: csv
"
writeLines(data_content, "settings/data.yml")
# Test config resolution
cfg <- settings_read()
# Directories should be inline
expect_equal(cfg$directories$notebooks, "notebooks")
expect_equal(cfg$directories$scripts, "scripts")
# Data should come from split file
expect_true(!is.null(cfg$data$example))
expect_equal(cfg$data$example$path, "data/example.csv")
# Test via settings() helper
expect_equal(settings("notebooks"), "notebooks")
expect_equal(settings("data.example.path"), "data/example.csv")
})
test_that("make_notebook() uses new directories config", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
# Create config with custom notebook directory
config_content <- "default:
directories:
notebooks: custom_notebooks
"
writeLines(config_content, "config.yml")
# Directory detection should use config
result <- framework:::.get_notebook_dir_from_config()
expect_equal(result, "custom_notebooks")
})
test_that("settings() handles nested paths correctly", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
config_content <- "default:
connections:
db:
driver: postgresql
host: localhost
port: 5432
database: mydb
"
writeLines(config_content, "config.yml")
# Test deep nesting
expect_equal(settings("connections.db.driver"), "postgresql")
expect_equal(settings("connections.db.host"), "localhost")
expect_equal(settings("connections.db.port"), 5432)
# Test partial paths
db_config <- settings("connections.db")
expect_true(is.list(db_config))
expect_equal(db_config$driver, "postgresql")
expect_equal(db_config$host, "localhost")
})
test_that("settings_read() initializes all standard sections", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
# Minimal config
config_content <- "default:
project_type: project
"
writeLines(config_content, "config.yml")
cfg <- settings_read()
# All standard sections should exist (may be empty lists)
expect_true(!is.null(cfg$data))
expect_true(!is.null(cfg$connections))
expect_true(!is.null(cfg$git))
expect_true(!is.null(cfg$security))
expect_true(!is.null(cfg$packages))
expect_true(!is.null(cfg$directories))
expect_true(!is.null(cfg$options))
})
test_that("settings() returns NULL for missing keys", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
config_content <- "default:
directories:
notebooks: notebooks
"
writeLines(config_content, "config.yml")
# Non-existent keys
expect_null(settings("nonexistent"))
expect_null(settings("directories.nonexistent"))
expect_null(settings("deeply.nested.nonexistent"))
# With defaults
expect_equal(settings("nonexistent", default = "default_value"), "default_value")
})
test_that("config system handles all three project types", {
# Test project type
tmp1 <- tempfile()
dir.create(tmp1)
old_wd <- getwd()
setwd(tmp1)
config_content <- "default:
project_type: project
directories:
notebooks: notebooks
scripts: scripts
outputs_public: outputs/public
"
writeLines(config_content, "config.yml")
expect_equal(settings("project_type"), "project")
expect_equal(settings("scripts"), "scripts")
setwd(old_wd)
unlink(tmp1, recursive = TRUE)
# Test course type
tmp2 <- tempfile()
dir.create(tmp2)
setwd(tmp2)
config_content <- "default:
project_type: course
directories:
notebooks: notebooks
presentations: presentations
"
writeLines(config_content, "config.yml")
expect_equal(settings("project_type"), "course")
expect_equal(settings("presentations"), "presentations")
setwd(old_wd)
unlink(tmp2, recursive = TRUE)
# Test presentation type
tmp3 <- tempfile()
dir.create(tmp3)
setwd(tmp3)
config_content <- "default:
project_type: presentation
directories:
functions: functions
cache: outputs/private/cache
"
writeLines(config_content, "config.yml")
expect_equal(settings("project_type"), "presentation")
expect_equal(settings("cache"), "outputs/private/cache")
setwd(old_wd)
unlink(tmp3, recursive = TRUE)
})
# ============================================================================
# Config Conflict and Scoped Include Tests
# ============================================================================
# Test removed - format changed: split files now wrap content under section key
# Old format had unexpected keys at root level, new format wraps everything under connections:
test_that("conflict between main config and split file triggers warning", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
dir.create("settings", showWarnings = FALSE)
# Main config with default_connection
config_content <- "default:
connections: settings/connections.yml
default_connection: from_main
"
writeLines(config_content, "config.yml")
# Split file ALSO has default_connection (conflict!)
connections_content <- "connections:
db:
host: localhost
default_connection: from_split # CONFLICT!
"
writeLines(connections_content, "settings/connections.yml")
# Should warn about conflict AND scoped include violation
expect_warning(
cfg <- settings_read(),
"default_connection.*defined in both"
)
# Main file should win
expect_equal(cfg$default_connection, "from_main")
})
# Test removed - format changed: split files now have section-specific structure
# Old format: connections file could have options:, new format: just connections: wrapper
test_that("main file value takes precedence over split file", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
dir.create("settings", showWarnings = FALSE)
# Main config with explicit value
config_content <- "default:
project_type: project
data: settings/data.yml
cache_enabled: true
"
writeLines(config_content, "config.yml")
# Split file trying to override (bad practice, should warn)
data_content <- "data:
example:
path: data/example.csv
cache_enabled: false # Trying to override!
"
writeLines(data_content, "settings/data.yml")
# Should warn
expect_warning(
cfg <- settings_read(),
"cache_enabled.*defined in both"
)
# Main file wins
expect_true(cfg$cache_enabled)
})
test_that("multiple split files can coexist without conflicts", {
tmp <- tempfile()
dir.create(tmp)
old_wd <- getwd()
setwd(tmp)
on.exit({
setwd(old_wd)
unlink(tmp, recursive = TRUE)
})
dir.create("settings", showWarnings = FALSE)
# Main config with multiple split files
config_content <- "default:
connections: settings/connections.yml
data: settings/data.yml
"
writeLines(config_content, "config.yml")
# Connections file (clean)
connections_content <- "connections:
db:
host: localhost
"
writeLines(connections_content, "settings/connections.yml")
# Data file (clean)
data_content <- "data:
example:
path: data/example.csv
"
writeLines(data_content, "settings/data.yml")
# Should not warn (both files are clean)
expect_no_warning(
cfg <- settings_read()
)
# Both sections should be merged
expect_equal(cfg$connections$db$host, "localhost")
expect_equal(cfg$data$example$path, "data/example.csv")
})
# ---- settings() Helper Tests ----
test_that("settings() returns entire config when no key provided", {
test_dir <- create_test_project()
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
cfg <- settings()
expect_type(cfg, "list")
expect_true("directories" %in% names(cfg))
expect_true("packages" %in% names(cfg))
})
test_that("settings() accesses nested values with dot notation", {
test_dir <- create_test_project(type = "project")
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
# Test nested access - get whatever directories exist
dirs <- settings("directories")
if (length(dirs) > 0) {
first_key <- names(dirs)[1]
first_value <- settings(paste0("directories.", first_key))
expect_equal(first_value, dirs[[first_key]])
}
})
test_that("settings() returns default for missing keys", {
test_dir <- create_test_project()
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
# Missing key with default
result <- settings("missing.key", default = "fallback")
expect_equal(result, "fallback")
# Missing key without default
result <- settings("missing.key")
expect_null(result)
})
test_that("settings() returns entire sections as lists", {
test_dir <- create_test_project(type = "project")
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
# Get entire directories section
dirs <- settings("directories")
expect_type(dirs, "list")
expect_true(length(dirs) > 0) # Should have at least some directories
})
test_that("settings() handles smart directory lookups", {
test_dir <- create_test_project(type = "project")
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
# Single-word key should check directories section
# Get whatever directories exist and test smart lookup
dirs <- settings("directories")
if (length(dirs) > 0) {
first_key <- names(dirs)[1]
# Smart lookup (no "directories." prefix)
smart_result <- settings(first_key)
# Should match the direct access
expect_equal(smart_result, dirs[[first_key]])
}
})
test_that("settings() returns raw values in non-interactive mode", {
test_dir <- create_test_project()
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
# Tests run in non-interactive mode
# Should return raw list, not invisible
dirs <- settings("directories")
expect_type(dirs, "list")
expect_visible(dirs)
})
test_that("settings() works with deep nesting", {
test_dir <- create_test_dir()
old_wd <- getwd()
on.exit({
setwd(old_wd)
cleanup_test_dir(test_dir)
})
setwd(test_dir)
# Create config with deep nesting
yaml::write_yaml(list(
default = list(
level1 = list(
level2 = list(
level3 = list(
value = "deep_value"
)
)
)
)
), "config.yml")
# Access deep value
result <- settings("level1.level2.level3.value")
expect_equal(result, "deep_value")
# Access intermediate level
level2 <- settings("level1.level2")
expect_type(level2, "list")
expect_true("level3" %in% names(level2))
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.