#![allow(clippy::unwrap_used)]
#![allow(unused_imports)]
use super::super::ast::Redirect;
use super::super::lexer::Lexer;
use super::super::parser::BashParser;
use super::super::semantic::SemanticAnalyzer;
use super::super::*;
#[test]
fn test_VAR_001_home_common_patterns() {
assert_tokenizes(
VAR_001_HOME_COMMON_PATTERNS_INPUT,
"HOME patterns should tokenize",
);
}
#[test]
fn test_VAR_001_home_vs_tilde() {
let home_vs_tilde = r#"
# Equivalent forms
cd ~
cd "$HOME"
cd ~/documents
cd "$HOME/documents"
# Tilde expansion variations
cd ~ # User's home
cd ~alice # Alice's home (not in POSIX, bash extension)
cd ~+ # Current directory (bash extension)
cd ~- # Previous directory (bash extension)
# Variable assignment
file1=~/document.txt # Tilde expands
file2="$HOME/document.txt" # HOME variable
# WRONG: Tilde in quotes doesn't expand
# file3="~/document.txt" # WRONG: literal "~/document.txt"
# Use this instead:
file3="$HOME/document.txt" # Correct
# HOME is more explicit in scripts
config_dir="$HOME/.config"
cache_dir="$HOME/.cache"
# Tilde is more readable interactively
# cd ~/projects/myapp
# cd ~/Downloads
# Subdirectories
mkdir -p "$HOME/backups"
mkdir -p ~/backups # Equivalent
"#;
let mut lexer = Lexer::new(home_vs_tilde);
match lexer.tokenize() {
Ok(tokens) => {
assert!(!tokens.is_empty(), "HOME vs tilde examples should tokenize");
let _ = tokens;
}
Err(_) => {
}
}
}
const VAR_001_HOME_BEST_PRACTICES_INPUT: &str = r#"
# BEST PRACTICE 1: Always quote HOME
cd "$HOME" # Correct
# cd $HOME # WRONG: breaks if HOME has spaces
# BEST PRACTICE 2: Check HOME is set
if [ -z "$HOME" ]; then
printf 'ERROR: HOME not set\n' >&2
exit 1
fi
# BEST PRACTICE 3: Check HOME directory exists
if [ ! -d "$HOME" ]; then
printf 'ERROR: HOME directory does not exist: %s\n' "$HOME" >&2
exit 1
fi
# BEST PRACTICE 4: Use HOME for user-specific files
config_file="$HOME/.config/app.conf"
cache_dir="$HOME/.cache/app"
data_dir="$HOME/.local/share/app"
# BEST PRACTICE 5: Never modify HOME
# HOME="/new/path" # WRONG: breaks system utilities
# Use a different variable instead:
APP_HOME="$HOME/myapp"
cd "$APP_HOME"
# BEST PRACTICE 6: Portable tilde usage
cd ~ # POSIX (portable)
cd ~/dir # POSIX (portable)
# cd ~alice # Bash extension (not portable)
# cd ~+ # Bash extension (not portable)
# BEST PRACTICE 7: Use $HOME in scripts, ~ interactively
# Scripts (explicit):
install_dir="$HOME/.local/bin"
mkdir -p "$install_dir"
# Interactive (readable):
# cd ~/projects
# ls ~/Downloads
# BEST PRACTICE 8: Portable home reference
# Don't hardcode:
# config="/home/alice/.config" # WRONG: not portable
# Use HOME:
config="$HOME/.config" # Correct: works for any user
"#;
#[test]
fn test_VAR_001_home_best_practices() {
assert_tokenizes(
VAR_001_HOME_BEST_PRACTICES_INPUT,
"best practices should tokenize",
);
}
const VAR_001_HOME_EDGE_CASES_INPUT: &str = r#"
# Edge case 1: HOME not set (rare)
if [ -z "$HOME" ]; then
printf 'ERROR: HOME environment variable not set\n' >&2
exit 1
fi
# Edge case 2: HOME directory doesn't exist
if [ ! -d "$HOME" ]; then
printf 'ERROR: HOME directory does not exist: %s\n' "$HOME" >&2
# Try to create it (last resort)
mkdir -p "$HOME" 2>/dev/null || exit 1
fi
# Edge case 3: HOME with spaces (must quote)
# HOME="/home/user name"
cd "$HOME" # Correct (quoted)
# cd $HOME # WRONG: would cd to "/home/user" (broken)
# Edge case 4: HOME not writable
if [ ! -w "$HOME" ]; then
printf 'WARNING: HOME not writable, using /tmp\n' >&2
APP_DATA="/tmp/app-data.$$"
else
APP_DATA="$HOME/.app-data"
fi
mkdir -p "$APP_DATA"
# Edge case 5: Root user (HOME=/)
if [ "$HOME" = "/" ]; then
printf 'Running as root (HOME=/)\n'
# Use /root/.app instead of /.app
config_dir="/root/.config"
else
config_dir="$HOME/.config"
fi
# Edge case 6: Fallback if HOME missing
fallback_home="${HOME:-/tmp}"
cd "$fallback_home"
# Edge case 7: Preserve original HOME
original_home="$HOME"
# ... potential HOME modification ...
HOME="$original_home" # Restore
"#;
#[test]
fn test_VAR_001_home_edge_cases() {
assert_tokenizes(VAR_001_HOME_EDGE_CASES_INPUT, "edge cases should tokenize");
}
#[test]
fn test_VAR_001_home_system_interaction() {
let system_interaction = r#"
# HOME is set at login from /etc/passwd
# No need to set it manually in scripts
printf 'Current HOME: %s\n' "$HOME"
printf 'Current user: %s\n' "$USER"
# cd with no arguments uses HOME
cd # Goes to $HOME
pwd # Shows $HOME
# Tilde expansion uses HOME
cd ~ # Same as cd "$HOME"
ls ~ # Same as ls "$HOME"
# User configuration files (rely on HOME)
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
if [ -f "$HOME/.profile" ]; then
. "$HOME/.profile"
fi
# Application config directories
config_dir="$HOME/.config/myapp"
mkdir -p "$config_dir"
cache_dir="$HOME/.cache/myapp"
mkdir -p "$cache_dir"
data_dir="$HOME/.local/share/myapp"
mkdir -p "$data_dir"
# SSH uses HOME
ssh_dir="$HOME/.ssh"
if [ -d "$ssh_dir" ]; then
printf 'SSH config found in %s\n' "$ssh_dir"
fi
# Git uses HOME
git_config="$HOME/.gitconfig"
if [ -f "$git_config" ]; then
printf 'Git config: %s\n' "$git_config"
fi
"#;
let mut lexer = Lexer::new(system_interaction);
match lexer.tokenize() {
Ok(tokens) => {
assert!(!tokens.is_empty(), "system interaction should tokenize");
let _ = tokens;
}
Err(_) => {
}
}
}
#[test]
fn test_VAR_001_home_security_considerations() {
let security_considerations = r#"
# SECURITY 1: Always quote HOME
cd "$HOME" # Safe (quoted)
# cd $HOME # Unsafe (word splitting, globbing)
# SECURITY 2: Validate HOME exists and is directory
if [ ! -d "$HOME" ]; then
printf 'ERROR: Invalid HOME: %s\n' "$HOME" >&2
exit 1
fi
# SECURITY 3: Check HOME ownership (optional, paranoid)
# home_owner=$(stat -c %U "$HOME" 2>/dev/null)
# if [ "$home_owner" != "$USER" ]; then
# printf 'WARNING: HOME owned by different user\n' >&2
# fi
# SECURITY 4: Use safe temp files
temp_file=$(mktemp) # Safe (system temp dir)
# Not: temp_file="$HOME/tmp/file.$$" # Less safe
# SECURITY 5: Avoid symlink attacks
config_dir="$HOME/.config/app"
mkdir -p "$config_dir"
# Verify it's a directory (not symlink to attacker's dir)
if [ ! -d "$config_dir" ] || [ -L "$config_dir" ]; then
printf 'WARNING: Config dir is symlink or missing\n' >&2
fi
# SECURITY 6: Safe file creation in HOME
data_file="$HOME/.app/data.conf"
# Create safely:
umask 077 # Restrict permissions
mkdir -p "$(dirname "$data_file")"
printf '%s\n' "data" > "$data_file"
# SECURITY 7: Don't trust HOME implicitly in privileged scripts
if [ "$(id -u)" -eq 0 ]; then
printf 'WARNING: Running as root with HOME=%s\n' "$HOME" >&2
# Be extra careful with file operations
fi
"#;
let mut lexer = Lexer::new(security_considerations);
match lexer.tokenize() {
Ok(tokens) => {
assert!(
!tokens.is_empty(),
"security considerations should tokenize"
);
let _ = tokens;
}
Err(_) => {
}
}
}
#[test]
include!("part4_8_var_001.rs");