23dcfb393f
Implements the design in claude.md as a building skeleton: pure Go, no cgo, cross-compiles to a single Windows .exe from Linux. Architecture follows the spec's deliberate split. The fast path is native — tray icon, grouped submenus, a Win32 MessageBox showing a live before/after diff, then netsh. The slow path is an embedded web editor served on a random loopback port and opened in the default browser. Two decisions worth recording: Reads use GetAdaptersAddresses, writes use netsh. The spec left the enumeration mechanism open; parsing `netsh show config` breaks on a non-English Windows because the output is localised. DNS static-vs-DHCP origin is not exposed by that API, so it comes from one registry read. The netsh command plan is built in portable code. That puts the delete-every- existing-address step — the one that stops secondary addresses leaking across switches — under test without needing a Windows box. The editor requires the session token in a header for mutations, not just the cookie: any page in the browser can make it POST to 127.0.0.1 with the cookie attached, but it cannot set a header. The updater refuses to install a release that publishes no SHA256. Not yet done: no group picker for export (the API supports it), no single-instance guard, and internal/server/web/app.css is reconstructed from the description in claude.md rather than the canonical apointless.css. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
67 lines
1.4 KiB
Go
67 lines
1.4 KiB
Go
package preset
|
|
|
|
import "testing"
|
|
|
|
func TestParsePrefix(t *testing.T) {
|
|
ok := []struct {
|
|
in string
|
|
want int
|
|
}{
|
|
{"24", 24},
|
|
{"/24", 24},
|
|
{" /24 ", 24},
|
|
{"255.255.255.0", 24},
|
|
{"255.255.255.255", 32},
|
|
{"0.0.0.0", 0},
|
|
{"255.255.254.0", 23},
|
|
{"128.0.0.0", 1},
|
|
{"32", 32},
|
|
{"0", 0},
|
|
}
|
|
for _, tc := range ok {
|
|
got, err := ParsePrefix(tc.in)
|
|
if err != nil {
|
|
t.Errorf("ParsePrefix(%q) returned error: %v", tc.in, err)
|
|
continue
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("ParsePrefix(%q) = %d, want %d", tc.in, got, tc.want)
|
|
}
|
|
}
|
|
|
|
bad := []string{"", "33", "-1", "255.255.0.255", "1.2.3", "abc", "255.0.255.0", "/", "24.5"}
|
|
for _, in := range bad {
|
|
if got, err := ParsePrefix(in); err == nil {
|
|
t.Errorf("ParsePrefix(%q) = %d, want error", in, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMaskStringRoundTrip(t *testing.T) {
|
|
for p := 0; p <= 32; p++ {
|
|
got, err := ParsePrefix(MaskString(p))
|
|
if err != nil {
|
|
t.Fatalf("ParsePrefix(MaskString(%d)) errored: %v", p, err)
|
|
}
|
|
if got != p {
|
|
t.Errorf("round trip of /%d gave /%d (mask %s)", p, got, MaskString(p))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMaskStringKnown(t *testing.T) {
|
|
cases := map[int]string{
|
|
0: "0.0.0.0",
|
|
8: "255.0.0.0",
|
|
16: "255.255.0.0",
|
|
24: "255.255.255.0",
|
|
30: "255.255.255.252",
|
|
32: "255.255.255.255",
|
|
}
|
|
for prefix, want := range cases {
|
|
if got := MaskString(prefix); got != want {
|
|
t.Errorf("MaskString(%d) = %s, want %s", prefix, got, want)
|
|
}
|
|
}
|
|
}
|