//go:build linux || freebsd // +build linux freebsd package config import ( "strings" "testing" "time" "codeberg.org/petrbalvin/interpres" ) func TestDefaultConfig(t *testing.T) { cfg := DefaultConfig() if cfg.Timeout != 30*time.Minute { t.Errorf("Expected default timeout 30m, got %v", cfg.Timeout) } if cfg.Parallel != 0 { t.Errorf("Expected default parallel 0, got %d", cfg.Parallel) } if cfg.Verbose != true { t.Errorf("Expected default verbose true, got %v", cfg.Verbose) } if cfg.AutoDecompress != true { t.Errorf("Expected default auto decompress true, got %v", cfg.AutoDecompress) } if cfg.ChecksumAlgo != "sha256" { t.Errorf("Expected default checksum algo sha256, got %s", cfg.ChecksumAlgo) } } func TestConfigMerge(t *testing.T) { cfg := DefaultConfig() cfg.Merge(&CLIFlags{ Timeout: 1 * time.Hour, Parallel: 4, Verbose: true, Debug: false, MaxSpeed: 1024 * 1024, Proxy: "http://proxy", NoIPv4: false, NoDecompress: false, Username: "user", Password: "pass", CookieJar: "", Recursive: false, MaxDepth: 0, FollowExternal: false, ExcludePatterns: nil, Extract: false, ExtractDir: "", StripComponents: 0, }) if cfg.Timeout != 1*time.Hour { t.Errorf("Expected timeout 1h, got %v", cfg.Timeout) } if cfg.Parallel != 4 { t.Errorf("Expected parallel 4, got %d", cfg.Parallel) } if cfg.Proxy != "http://proxy" { t.Errorf("Expected proxy http://proxy, got %s", cfg.Proxy) } if cfg.Auth.Username != "user" { t.Errorf("Expected username user, got %s", cfg.Auth.Username) } } func TestGetEffectiveTimeout(t *testing.T) { cfg := DefaultConfig() // User override timeout := cfg.GetEffectiveTimeout(1000000, 1*time.Hour) if timeout != 1*time.Hour { t.Errorf("Expected 1h with user override, got %v", timeout) } // Auto calculation for known size timeout = cfg.GetEffectiveTimeout(100*1024*1024, 0) if timeout < 30*time.Second { t.Errorf("Expected at least 30s for auto timeout, got %v", timeout) } // Unknown size timeout = cfg.GetEffectiveTimeout(-1, 0) if timeout != 30*time.Minute { t.Errorf("Expected 30m for unknown size, got %v", timeout) } } func TestGetParallelConnections(t *testing.T) { cfg := DefaultConfig() // Explicit parallel cfg.Parallel = 8 if cfg.GetParallelConnections(1000) != 8 { t.Errorf("Expected 8 explicit connections, got %d", cfg.GetParallelConnections(1000)) } // Auto for large file cfg.Parallel = 0 if cfg.GetParallelConnections(200*1024*1024) != 4 { t.Errorf("Expected 4 auto connections for large file, got %d", cfg.GetParallelConnections(200*1024*1024)) } // Auto for small file if cfg.GetParallelConnections(1024) != 1 { t.Errorf("Expected 1 connection for small file, got %d", cfg.GetParallelConnections(1024)) } } func TestShouldUseColors(t *testing.T) { cfg := DefaultConfig() // Always cfg.Color = "always" if !cfg.ShouldUseColors() { t.Error("Expected colors with always setting") } // Never cfg.Color = "never" if cfg.ShouldUseColors() { t.Error("Expected no colors with never setting") } // Auto (default) cfg.Color = "auto" // Can't test environment in unit tests, but verify it doesn't panic _ = cfg.ShouldUseColors() } func TestIsExcluded(t *testing.T) { cfg := DefaultConfig() cfg.Recursive.ExcludePatterns = []string{"example.com", "test.org"} if !cfg.IsExcluded("https://example.com/file.zip") { t.Error("Expected example.com to be excluded") } if !cfg.IsExcluded("https://test.org/file.zip") { t.Error("Expected test.org to be excluded") } if cfg.IsExcluded("https://other.com/file.zip") { t.Error("Expected other.com to not be excluded") } } func TestGetRecursiveDelay(t *testing.T) { cfg := DefaultConfig() delay := cfg.GetRecursiveDelay() if delay != 100*time.Millisecond { t.Errorf("Expected default delay 100ms, got %v", delay) } cfg.Recursive.Delay = "500ms" delay = cfg.GetRecursiveDelay() if delay != 500*time.Millisecond { t.Errorf("Expected delay 500ms, got %v", delay) } // Invalid delay should fall back to default cfg.Recursive.Delay = "invalid" delay = cfg.GetRecursiveDelay() if delay != 100*time.Millisecond { t.Errorf("Expected default delay for invalid value, got %v", delay) } } func TestGetExtractOutputDir(t *testing.T) { cfg := DefaultConfig() // Empty config should return default dir := cfg.GetExtractOutputDir("/default") if dir != "/default" { t.Errorf("Expected /default, got %s", dir) } // Config with output dir cfg.Extract.OutputDir = "/custom" dir = cfg.GetExtractOutputDir("/default") if dir != "/custom" { t.Errorf("Expected /custom, got %s", dir) } } func TestParseSpeed(t *testing.T) { tests := []struct { input string expected int64 }{ {"", 0}, {"0", 0}, {"100", 100}, {"100B/s", 100}, {"1KB/s", 1000}, {"1MB/s", 1000000}, {"1GB/s", 1000000000}, {"10MB/s", 10000000}, {"100 KB/s", 100000}, } for _, test := range tests { result := ParseSpeed(test.input) if result != test.expected { t.Errorf("ParseSpeed(%s) = %d, expected %d", test.input, result, test.expected) } } } func TestExpandTilde(t *testing.T) { // Test with tilde path := expandTilde("~/test/file.txt") if path == "~/test/file.txt" { t.Error("Expected tilde to be expanded") } // Test without tilde path = expandTilde("/absolute/path/file.txt") if path != "/absolute/path/file.txt" { t.Errorf("Expected unchanged path, got %s", path) } } func TestConfigSave(t *testing.T) { cfg := DefaultConfig() cfg.Verbose = true cfg.Parallel = 4 // Save should not fail (may create directories) err := cfg.Save() // We can't test the actual file creation in unit tests without a temp dir // but we verify the method doesn't panic _ = err } func TestLoadNonExistentConfig(t *testing.T) { cfg, err := Load("/nonexistent/path/config.toml") if err != nil { t.Fatalf("Expected no error for non-existent config, got %v", err) } if cfg == nil { t.Fatal("Expected default config for non-existent file") } } func TestMarshalUnmarshalTOML(t *testing.T) { cfg := DefaultConfig() cfg.Parallel = 4 cfg.Verbose = true cfg.Timeout = 5 * time.Minute cfg.Auth.Username = "testuser" cfg.Auth.AuthType = "basic" cfg.Recursive.Enabled = true cfg.Recursive.MaxDepth = 5 cfg.DNSServers = []string{"1.1.1.1", "8.8.8.8"} data, err := interpres.Marshal(*cfg) if err != nil { t.Fatalf("interpres.Marshal failed: %v", err) } tomlStr := string(data) // Verify key elements are present if !strings.Contains(tomlStr, "parallel = 4") { t.Errorf("expected 'parallel = 4' in TOML output, got:\n%s", tomlStr) } if !strings.Contains(tomlStr, "verbose = true") { t.Errorf("expected 'verbose = true' in TOML output, got:\n%s", tomlStr) } if !strings.Contains(tomlStr, "[auth]") { t.Errorf("expected '[auth]' section in TOML output, got:\n%s", tomlStr) } if !strings.Contains(tomlStr, "username = \"testuser\"") { t.Errorf("expected 'username = \"testuser\"' in TOML output, got:\n%s", tomlStr) } if !strings.Contains(tomlStr, "[recursive]") { t.Errorf("expected '[recursive]' section in TOML output, got:\n%s", tomlStr) } if !strings.Contains(tomlStr, "dns_servers = [") { t.Errorf("expected 'dns_servers' array in TOML output, got:\n%s", tomlStr) } // Roundtrip: unmarshal back and verify var cfg2 Config if err := interpres.Unmarshal(data, &cfg2); err != nil { t.Fatalf("interpres.Unmarshal failed: %v", err) } if cfg2.Parallel != 4 { t.Errorf("roundtrip: expected Parallel 4, got %d", cfg2.Parallel) } if cfg2.Verbose != true { t.Errorf("roundtrip: expected Verbose true, got %v", cfg2.Verbose) } if cfg2.Auth.Username != "testuser" { t.Errorf("roundtrip: expected Auth.Username testuser, got %s", cfg2.Auth.Username) } if cfg2.Recursive.MaxDepth != 5 { t.Errorf("roundtrip: expected Recursive.MaxDepth 5, got %d", cfg2.Recursive.MaxDepth) } if len(cfg2.DNSServers) != 2 || cfg2.DNSServers[0] != "1.1.1.1" { t.Errorf("roundtrip: expected DNSServers [1.1.1.1, 8.8.8.8], got %v", cfg2.DNSServers) } } func TestMarshalTOMLDefaultConfig(t *testing.T) { cfg := DefaultConfig() data, err := interpres.Marshal(*cfg) if err != nil { t.Fatalf("interpres.Marshal with default config failed: %v", err) } if len(data) == 0 { t.Error("expected non-empty TOML output for default config") } // Verify it can be parsed back var cfg2 Config if err := interpres.Unmarshal(data, &cfg2); err != nil { t.Fatalf("interpres.Unmarshal of default output failed: %v", err) } if cfg2.OutputDir != "." { t.Errorf("expected OutputDir '.', got %s", cfg2.OutputDir) } if cfg2.ChecksumAlgo != "sha256" { t.Errorf("expected ChecksumAlgo sha256, got %s", cfg2.ChecksumAlgo) } } func TestConfigPath(t *testing.T) { cfg := DefaultConfig() path := cfg.Path() // Path should be empty when loaded with DefaultConfig _ = path }