a73x

internal/names/names_test.go

Ref:   Size: 3.3 KiB   History

package names

import (
	"os"
	"path/filepath"
	"strings"
	"testing"
)

// TestIsNetworkName exercises the network-name grammar's boundaries directly
// against the implementation: the length limits, the leading/trailing-hyphen
// rule, the reserved "nat" word, and the lowercase-alnum-and-hyphen charset.
func TestIsNetworkName(t *testing.T) {
	valid := []string{"lan", "lab-2", "a", strings.Repeat("x", 32)}
	invalid := []string{"", "nat", "LAN", "l_n", "-lan", "lan-", strings.Repeat("x", 33), "br0.7"}
	for _, s := range valid {
		if !IsNetworkName(s) {
			t.Errorf("IsNetworkName(%q) = false, want true", s)
		}
	}
	for _, s := range invalid {
		if IsNetworkName(s) {
			t.Errorf("IsNetworkName(%q) = true, want false", s)
		}
	}
}

// TestDocsMatchNetworkNameGrammar is the docs-match tripwire for the network-
// name grammar. IsNetworkName is the one home for the rule (see its doc
// comment), but the agent's flag parser (internal/agent/run/cli.go) and
// docs/networking.md both restate it in prose for a human reader, in a form
// that cannot import the Go function. This test reads the quickstart prose
// and fails if its load-bearing fragments go missing, and separately proves
// the stated bounds still match IsNetworkName's behavior — so a change to
// the grammar cannot silently leave the docs describing the old rule.
func TestDocsMatchNetworkNameGrammar(t *testing.T) {
	quickstart := readRepoFile(t, "docs/networking.md")
	for _, want := range []string{
		"1–32 of `[a-z0-9-]`",
		"no leading",
		"or trailing hyphen",
		"`nat` is reserved",
	} {
		if !strings.Contains(quickstart, want) {
			t.Errorf("docs/networking.md is missing %q — the network-name grammar prose drifted from IsNetworkName", want)
		}
	}

	// Behavioral half: the bounds the prose claims (1-32 chars, no
	// leading/trailing hyphen, "nat" reserved) must match what the code
	// actually accepts. TestIsNetworkName already covers this in depth;
	// these three checks pin the specific numbers the doc sentence quotes.
	if !IsNetworkName(strings.Repeat("x", 32)) {
		t.Error("IsNetworkName rejects a 32-char name — docs/networking.md's \"1–32\" would be wrong")
	}
	if IsNetworkName(strings.Repeat("x", 33)) {
		t.Error("IsNetworkName accepts a 33-char name — docs/networking.md's \"1–32\" would be wrong")
	}
	if IsNetworkName("nat") {
		t.Error("IsNetworkName accepts \"nat\" — docs/networking.md's \"nat is reserved\" would be wrong")
	}
}

// TestOSServesNamedNetworks pins the one platform this fact is true for today
// and confirms it is a real comparison, not a stub that always answers true.
func TestOSServesNamedNetworks(t *testing.T) {
	if !OSServesNamedNetworks("linux") {
		t.Error("OSServesNamedNetworks(\"linux\") = false, want true")
	}
	for _, goos := range []string{"darwin", "windows", ""} {
		if OSServesNamedNetworks(goos) {
			t.Errorf("OSServesNamedNetworks(%q) = true, want false", goos)
		}
	}
}

// readRepoFile reads a repo-root-relative path, locating the root by walking
// up from this test file's own location so the result does not depend on the
// working directory the test is run from.
func readRepoFile(t *testing.T, rel string) string {
	t.Helper()
	b, err := os.ReadFile(filepath.Join("..", "..", rel))
	if err != nil {
		t.Fatalf("reading %s: %v", rel, err)
	}
	return string(b)
}