这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ turborepo-process-serial = { max-threads = 1 }
# race conditions with binary detection and stdout/stderr capture
turborepo-integration-serial = { max-threads = 1 }

# turborepo-dirs tests should run serially to avoid race conditions
# with environment variable manipulation
turborepo-dirs-serial = { max-threads = 1 }

[[profile.default.overrides]]
# Run all tests in the turborepo-process crate serially
filter = 'package(turborepo-process)'
Expand All @@ -20,3 +24,9 @@ test-group = 'turborepo-process-serial'
# These tests spawn turbo processes and parse JSON from stdout
filter = 'package(turbo) and (test(boundaries) or test(query) or test(ls))'
test-group = 'turborepo-integration-serial'

[[profile.default.overrides]]
# Run all tests in the turborepo-dirs crate serially
# These tests manipulate environment variables
filter = 'package(turborepo-dirs)'
test-group = 'turborepo-dirs-serial'
12 changes: 1 addition & 11 deletions .github/actions/setup-capnproto/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,6 @@ runs:
/usr/bin/capnpc
key: ${{ runner.os }}-capnproto-0.11.2

- name: "Cache capnproto (Windows)"
if: runner.os == 'Windows' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
uses: actions/cache@v4
id: cache-capnp-windows
with:
path: |
C:\ProgramData\chocolatey\bin\capnp.exe
C:\ProgramData\chocolatey\bin\capnpc.exe
key: ${{ runner.os }}-capnproto-0.11.2

- name: "Setup capnproto for Linux"
if: runner.os == 'Linux' && (steps.cache-capnp-linux.outcome == 'skipped' || steps.cache-capnp-linux.outputs.cache-hit != 'true')
shell: bash
Expand All @@ -35,6 +25,6 @@ runs:
run: brew install capnp

- name: "Setup capnproto for Windows"
if: runner.os == 'Windows' && (steps.cache-capnp-windows.outcome == 'skipped' || steps.cache-capnp-windows.outputs.cache-hit != 'true')
if: runner.os == 'Windows'
shell: bash
run: choco install capnproto
235 changes: 235 additions & 0 deletions crates/turborepo-dirs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,238 @@ pub enum Error {
#[error("Config directory not found.")]
ConfigDirNotFound,
}

#[cfg(test)]
mod tests {
use std::env;

use super::*;

#[test]
fn test_config_dir_with_env_var() {
// Set TURBO_CONFIG_DIR_PATH to an absolute path
let test_path = if cfg!(windows) {
"C:\\test\\config"
} else {
"/test/config"
};

unsafe {
env::set_var("TURBO_CONFIG_DIR_PATH", test_path);
}

let result = config_dir();
assert!(result.is_ok());
let path = result.unwrap();
assert!(path.is_some());
assert_eq!(path.unwrap().as_str(), test_path);

unsafe {
env::remove_var("TURBO_CONFIG_DIR_PATH");
}
}

#[test]
fn test_config_dir_with_invalid_env_var() {
// Set TURBO_CONFIG_DIR_PATH to a relative path (invalid)
unsafe {
env::set_var("TURBO_CONFIG_DIR_PATH", "relative/path");
}

let result = config_dir();
assert!(result.is_err());

unsafe {
env::remove_var("TURBO_CONFIG_DIR_PATH");
}
}

#[test]
fn test_config_dir_without_env_var() {
// Ensure TURBO_CONFIG_DIR_PATH is not set
unsafe {
env::remove_var("TURBO_CONFIG_DIR_PATH");
}

let result = config_dir();
assert!(result.is_ok());
// On most systems, config_dir should return Some path
// We can't assert the exact path since it's platform-specific
let path = result.unwrap();
if let Some(p) = path {
// Verify it's an absolute path
assert!(p.as_path().is_absolute());
}
}

#[test]
fn test_vercel_config_dir_with_env_var() {
// Set VERCEL_CONFIG_DIR_PATH to an absolute path
let test_path = if cfg!(windows) {
"C:\\vercel\\config"
} else {
"/vercel/config"
};

unsafe {
env::set_var("VERCEL_CONFIG_DIR_PATH", test_path);
}

let result = vercel_config_dir();
assert!(result.is_ok());
let path = result.unwrap();
assert!(path.is_some());
assert_eq!(path.unwrap().as_str(), test_path);

unsafe {
env::remove_var("VERCEL_CONFIG_DIR_PATH");
}
}

#[test]
fn test_vercel_config_dir_with_invalid_env_var() {
// Set VERCEL_CONFIG_DIR_PATH to a relative path (invalid)
unsafe {
env::set_var("VERCEL_CONFIG_DIR_PATH", "relative/path");
}

let result = vercel_config_dir();
assert!(result.is_err());

unsafe {
env::remove_var("VERCEL_CONFIG_DIR_PATH");
}
}

#[test]
fn test_vercel_config_dir_without_env_var() {
// Ensure VERCEL_CONFIG_DIR_PATH is not set
unsafe {
env::remove_var("VERCEL_CONFIG_DIR_PATH");
}

let result = vercel_config_dir();
assert!(result.is_ok());
// On most systems, config_dir should return Some path
// We can't assert the exact path since it's platform-specific
let path = result.unwrap();
if let Some(p) = path {
// Verify it's an absolute path
assert!(p.as_path().is_absolute());
}
}

#[test]
fn test_config_dir_empty_env_var() {
// Set TURBO_CONFIG_DIR_PATH to empty string
unsafe {
env::set_var("TURBO_CONFIG_DIR_PATH", "");
}

let result = config_dir();
// Empty string should be invalid as it's not an absolute path
assert!(result.is_err());

unsafe {
env::remove_var("TURBO_CONFIG_DIR_PATH");
}
}

#[test]
fn test_vercel_config_dir_empty_env_var() {
// Set VERCEL_CONFIG_DIR_PATH to empty string
unsafe {
env::set_var("VERCEL_CONFIG_DIR_PATH", "");
}

let result = vercel_config_dir();
// Empty string should be invalid as it's not an absolute path
assert!(result.is_err());

unsafe {
env::remove_var("VERCEL_CONFIG_DIR_PATH");
}
}

#[test]
fn test_config_dir_and_vercel_config_dir_independence() {
// Test that TURBO_CONFIG_DIR_PATH doesn't affect vercel_config_dir
// Use a path that would be created by dirs_config_dir to ensure both succeed
let turbo_path = if cfg!(windows) {
"C:\\Users\\test\\config"
} else {
"/Users/test/config"
};

unsafe {
env::set_var("TURBO_CONFIG_DIR_PATH", turbo_path);
env::remove_var("VERCEL_CONFIG_DIR_PATH");
}

let turbo_result = config_dir();
let vercel_result = vercel_config_dir();

assert!(turbo_result.is_ok(), "turbo_result should be ok");
let turbo_path_result = turbo_result.unwrap();
assert!(turbo_path_result.is_some(), "turbo path should be some");
assert_eq!(turbo_path_result.unwrap().as_str(), turbo_path);

assert!(vercel_result.is_ok(), "vercel_result should be ok");
// vercel_config_dir should return the default, not turbo_path
if let Some(vercel_path) = vercel_result.unwrap() {
assert_ne!(vercel_path.as_str(), turbo_path);
}

unsafe {
env::remove_var("TURBO_CONFIG_DIR_PATH");
}
}

#[test]
fn test_vercel_config_dir_and_config_dir_independence() {
// Test that VERCEL_CONFIG_DIR_PATH doesn't affect config_dir
let vercel_path = if cfg!(windows) {
"C:\\Users\\test\\vercel"
} else {
"/Users/test/vercel"
};

unsafe {
env::set_var("VERCEL_CONFIG_DIR_PATH", vercel_path);
env::remove_var("TURBO_CONFIG_DIR_PATH");
}

let vercel_result = vercel_config_dir();
let turbo_result = config_dir();

assert!(vercel_result.is_ok(), "vercel_result should be ok");
let vercel_path_result = vercel_result.unwrap();
assert!(vercel_path_result.is_some(), "vercel path should be some");
assert_eq!(vercel_path_result.unwrap().as_str(), vercel_path);

assert!(turbo_result.is_ok(), "turbo_result should be ok");
// config_dir should return the default, not vercel_path
if let Some(turbo_path) = turbo_result.unwrap() {
assert_ne!(turbo_path.as_str(), vercel_path);
}

unsafe {
env::remove_var("VERCEL_CONFIG_DIR_PATH");
}
}

#[test]
fn test_error_display() {
// Test that the Error enum formats correctly
let error = Error::ConfigDirNotFound;
assert_eq!(error.to_string(), "Config directory not found.");
}

#[test]
fn test_error_debug() {
// Test that the Error enum can be debug formatted
let error = Error::ConfigDirNotFound;
let debug_str = format!("{:?}", error);
assert!(debug_str.contains("ConfigDirNotFound"));
}
}
Loading