internal/config/config_test.go

package config

import (
	"strings"
	"testing"
	"time"

	"github.com/mercemay/portr/internal/config/target"
)

func TestDefaults(t *testing.T) {
	d := Defaults()
	if d.Concurrency != 16 {
		t.Errorf("concurrency = %d, want 16", d.Concurrency)
	}
	if d.Timeout != 2*time.Second {
		t.Errorf("timeout = %v, want 2s", d.Timeout)
	}
	if !d.Output.Table {
		t.Errorf("default table output should be on")
	}
}

func TestValidate(t *testing.T) {
	good := []target.Target{{Host: "host1", Port: 22}}
	tests := []struct {
		name    string
		mutate  func(*Config)
		wantErr string
	}{
		{"ok", func(c *Config) { c.Targets = good }, ""},
		{"no targets", func(c *Config) { c.Targets = nil }, "no targets"},
		{"bad concurrency", func(c *Config) {
			c.Targets = good
			c.Concurrency = 0
		}, "concurrency"},
		{"bad timeout", func(c *Config) {
			c.Targets = good
			c.Timeout = 0
		}, "timeout"},
		{"bad retries", func(c *Config) {
			c.Targets = good
			c.Retries = -1
		}, "retries"},
		{"no output sink", func(c *Config) {
			c.Targets = good
			c.Output = OutputConfig{}
		}, "no output sink"},
		{"duplicate", func(c *Config) {
			c.Targets = []target.Target{
				{Host: "h", Port: 22},
				{Host: "h", Port: 22},
			}
		}, "duplicate"},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			c := Defaults()
			tc.mutate(&c)
			err := c.Validate()
			if tc.wantErr == "" {
				if err != nil {
					t.Fatalf("unexpected error: %v", err)
				}
				return
			}
			if err == nil {
				t.Fatalf("expected error containing %q, got nil", tc.wantErr)
			}
			if !strings.Contains(err.Error(), tc.wantErr) {
				t.Errorf("error %q does not contain %q", err, tc.wantErr)
			}
		})
	}
}