Nothing
test_that(".env file parsing preserves structure", {
# Create temp path for test
project_dir <- tempfile("framework_test_")
on.exit(unlink(project_dir, recursive = TRUE), add = TRUE)
suppressMessages({
result <- framework::project_create(
name = "EnvTest",
location = project_dir,
type = "project",
git = list(use_git = FALSE)
)
})
project_path <- result$path
# Create .env file with specific structure and comments
original_content <- c(
"# Important database configuration",
"DB_HOST=localhost",
"# Port number",
"DB_PORT=5432",
"",
"# API credentials",
"API_KEY=secret123",
"# End of file"
)
writeLines(original_content, file.path(project_path, ".env"))
# Read the file back
read_content <- readLines(file.path(project_path, ".env"))
# Verify structure preserved
expect_equal(read_content, original_content)
expect_true(any(grepl("# Important database", read_content)))
expect_true(any(grepl("# Port number", read_content)))
expect_true(any(grepl("# End of file", read_content)))
})
test_that(".env file with dotenv_location in parent directory", {
# Create parent and project directories
parent_dir <- tempfile("framework_test_parent_")
dir.create(parent_dir, recursive = TRUE)
project_dir <- file.path(parent_dir, "myproject")
on.exit(unlink(parent_dir, recursive = TRUE), add = TRUE)
suppressMessages({
result <- framework::project_create(
name = "EnvTest",
location = project_dir,
type = "project",
git = list(use_git = FALSE)
)
})
# Remove .env that project_create() may have created
if (file.exists(file.path(project_dir, ".env"))) {
file.remove(file.path(project_dir, ".env"))
}
# Create settings.yml with dotenv_location pointing to parent
settings_content <- c(
"default:",
" project_type: project",
" project_name: EnvTest",
" dotenv_location: \"../\""
)
writeLines(settings_content, file.path(project_dir, "settings.yml"))
# Create .env in parent directory
env_content <- c("PARENT_VAR=fromparent")
writeLines(env_content, file.path(parent_dir, ".env"))
# Verify .env exists in parent but not in project
expect_true(file.exists(file.path(parent_dir, ".env")))
expect_false(file.exists(file.path(project_dir, ".env")))
# Read settings to verify dotenv_location
settings <- yaml::read_yaml(file.path(project_dir, "settings.yml"))
expect_equal(settings$default$dotenv_location, "../")
})
test_that(".env file handles special characters in values", {
# Create temp path for test
project_dir <- tempfile("framework_test_")
on.exit(unlink(project_dir, recursive = TRUE), add = TRUE)
suppressMessages({
result <- framework::project_create(
name = "EnvTest",
location = project_dir,
type = "project",
git = list(use_git = FALSE)
)
})
project_path <- result$path
# Create .env with various special cases
env_content <- c(
'SIMPLE=value',
'WITH_SPACES="value with spaces"',
'WITH_EQUALS=key=value',
'EMPTY=',
'WITH_QUOTES="value with \\"quotes\\""'
)
writeLines(env_content, file.path(project_path, ".env"))
# Read back
read_content <- readLines(file.path(project_path, ".env"))
# Verify content preserved
expect_true(any(grepl('SIMPLE=value', read_content)))
expect_true(any(grepl('WITH_SPACES=', read_content)))
expect_true(any(grepl('WITH_EQUALS=', read_content)))
expect_true(any(grepl('EMPTY=', read_content)))
})
test_that(".env file grouping by prefix works", {
# Create temp path for test
project_dir <- tempfile("framework_test_")
on.exit(unlink(project_dir, recursive = TRUE), add = TRUE)
suppressMessages({
result <- framework::project_create(
name = "EnvTest",
location = project_dir,
type = "project",
git = list(use_git = FALSE)
)
})
project_path <- result$path
# Create .env with mixed prefixes
env_content <- c(
"API_KEY=key1",
"DB_HOST=localhost",
"API_SECRET=secret1",
"DB_PORT=5432",
"NAS_PATH=/mnt/nas",
"OTHER_VAR=value"
)
writeLines(env_content, file.path(project_path, ".env"))
# Parse and group by prefix
lines <- readLines(file.path(project_path, ".env"))
vars <- list()
for (line in lines) {
if (grepl("^\\s*#", line) || grepl("^\\s*$", line)) next
if (grepl("=", line)) {
parts <- strsplit(line, "=", fixed = TRUE)[[1]]
if (length(parts) >= 2) {
key <- trimws(parts[1])
value <- paste(parts[-1], collapse = "=")
value <- gsub('^"(.*)"$', '\\1', value) # Remove quotes
vars[[key]] <- value
}
}
}
# Group by prefix
get_prefix <- function(key) {
parts <- strsplit(key, "_")[[1]]
if (length(parts) > 1) parts[1] else "OTHER"
}
prefixes <- sapply(names(vars), get_prefix)
unique_prefixes <- unique(prefixes)
# Verify grouping
expect_true("API" %in% unique_prefixes)
expect_true("DB" %in% unique_prefixes)
expect_true("NAS" %in% unique_prefixes)
expect_true("OTHER" %in% unique_prefixes)
# Count variables in each group
api_vars <- sum(prefixes == "API")
db_vars <- sum(prefixes == "DB")
nas_vars <- sum(prefixes == "NAS")
other_vars <- sum(prefixes == "OTHER")
expect_equal(api_vars, 2)
expect_equal(db_vars, 2)
expect_equal(nas_vars, 1)
expect_equal(other_vars, 1)
})
test_that(".env scanning for env() usage in R files", {
# Create temp path for test
project_dir <- tempfile("framework_test_")
on.exit(unlink(project_dir, recursive = TRUE), add = TRUE)
suppressMessages({
result <- framework::project_create(
name = "EnvTest",
location = project_dir,
type = "project",
directories = list(functions = "functions"),
git = list(use_git = FALSE)
)
})
project_path <- result$path
# Create R file with env() calls
r_code <- c(
'db_host <- env("DB_HOST")',
'db_port <- env("DB_PORT")',
'api_key <- env("API_KEY")',
'# Comment with env("FAKE_VAR")',
"another <- env('NAS_PATH')"
)
writeLines(r_code, file.path(project_path, "functions", "config.R"))
# Scan for env() usage
content <- readLines(file.path(project_path, "functions", "config.R"))
content_str <- paste(content, collapse = "\n")
# Find env("VARIABLE") or env('VARIABLE') patterns
matches <- gregexpr('env\\(["\']([^"\']+)["\']', content_str, perl = TRUE)
match_data <- regmatches(content_str, matches)[[1]]
# Extract variable names
var_names <- gsub('env\\(["\']([^"\']+)["\']', '\\1', match_data, perl = TRUE)
# Verify found variables
expect_true("DB_HOST" %in% var_names)
expect_true("DB_PORT" %in% var_names)
expect_true("API_KEY" %in% var_names)
expect_true("NAS_PATH" %in% var_names)
expect_true("FAKE_VAR" %in% var_names) # Even in comments
expect_equal(length(var_names), 5)
})
test_that(".env file edge cases", {
# Create temp path for test
project_dir <- tempfile("framework_test_")
on.exit(unlink(project_dir, recursive = TRUE), add = TRUE)
suppressMessages({
result <- framework::project_create(
name = "EnvTest",
location = project_dir,
type = "project",
git = list(use_git = FALSE)
)
})
project_path <- result$path
# Test empty .env file
writeLines("", file.path(project_path, ".env"))
expect_true(file.exists(file.path(project_path, ".env")))
# Test .env with only comments
writeLines(c("# Comment 1", "# Comment 2"), file.path(project_path, ".env"))
content <- readLines(file.path(project_path, ".env"))
expect_equal(length(content), 2)
expect_true(all(grepl("^#", content)))
# Test .env with blank lines
writeLines(c("VAR1=value1", "", "VAR2=value2", ""), file.path(project_path, ".env"))
content <- readLines(file.path(project_path, ".env"))
expect_equal(length(content), 4)
# Test malformed lines (missing equals)
writeLines(c(
"VALID=value",
"INVALID_NO_EQUALS",
"ALSO_VALID=foo"
), file.path(project_path, ".env"))
content <- readLines(file.path(project_path, ".env"))
# Parse only valid lines
vars <- list()
for (line in content) {
if (grepl("=", line) && !grepl("^\\s*#", line)) {
parts <- strsplit(line, "=", fixed = TRUE)[[1]]
if (length(parts) >= 2) {
vars[[parts[1]]] <- paste(parts[-1], collapse = "=")
}
}
}
expect_equal(length(vars), 2)
expect_equal(vars$VALID, "value")
expect_equal(vars$ALSO_VALID, "foo")
expect_null(vars$INVALID_NO_EQUALS)
})
test_that(".env regrouping creates proper structure", {
# Create temp path for test
project_dir <- tempfile("framework_test_")
on.exit(unlink(project_dir, recursive = TRUE), add = TRUE)
suppressMessages({
result <- framework::project_create(
name = "EnvTest",
location = project_dir,
type = "project",
git = list(use_git = FALSE)
)
})
project_path <- result$path
# Simulate regrouping logic
vars <- list(
API_KEY = "key1",
DB_HOST = "localhost",
API_SECRET = "secret1",
DB_PORT = "5432",
OTHER_VAR = "value"
)
# Extract prefixes
get_prefix <- function(key) {
parts <- strsplit(key, "_")[[1]]
if (length(parts) > 1) parts[1] else "OTHER"
}
prefixes <- sapply(names(vars), get_prefix)
unique_prefixes <- unique(prefixes)
# Sort prefixes, with OTHER last
unique_prefixes <- c(sort(unique_prefixes[unique_prefixes != "OTHER"]), "OTHER")
unique_prefixes <- unique_prefixes[unique_prefixes %in% prefixes]
# Build lines
lines <- c("# Environment Variables", "# Grouped by prefix", "")
for (prefix in unique_prefixes) {
keys_in_prefix <- names(vars)[prefixes == prefix]
if (length(keys_in_prefix) > 0) {
# Add section header
if (prefix == "OTHER") {
lines <- c(lines, "# Other Variables")
} else {
lines <- c(lines, sprintf("# %s Variables", toupper(prefix)))
}
# Add variables (sorted)
for (key in sort(keys_in_prefix)) {
value <- vars[[key]]
if (grepl(" ", value)) {
lines <- c(lines, sprintf('%s="%s"', key, value))
} else {
lines <- c(lines, sprintf('%s=%s', key, value))
}
}
lines <- c(lines, "")
}
}
# Write regrouped file
writeLines(lines, file.path(project_path, ".env"))
# Read back and verify
content <- readLines(file.path(project_path, ".env"))
# Verify headers exist
expect_true(any(grepl("# API Variables", content)))
expect_true(any(grepl("# DB Variables", content)))
expect_true(any(grepl("# Other Variables", content)))
# Verify order (API before DB before OTHER)
api_header_line <- which(grepl("# API Variables", content))
db_header_line <- which(grepl("# DB Variables", content))
other_header_line <- which(grepl("# Other Variables", content))
expect_true(api_header_line < db_header_line)
expect_true(db_header_line < other_header_line)
# Verify variables are grouped correctly
api_key_line <- which(grepl("^API_KEY=", content))
api_secret_line <- which(grepl("^API_SECRET=", content))
db_host_line <- which(grepl("^DB_HOST=", content))
db_port_line <- which(grepl("^DB_PORT=", content))
# All API vars should be before all DB vars
expect_true(max(c(api_key_line, api_secret_line)) < min(c(db_host_line, db_port_line)))
})
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.