From 93b276875e10697ebcd272f4600edb78b6581986 Mon Sep 17 00:00:00 2001 From: mAi Date: Sat, 16 May 2026 02:04:20 +0200 Subject: [PATCH] =?UTF-8?q?feat(catalog):=20migration=20005=20=E2=80=94=20?= =?UTF-8?q?power-distribution=20devices?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds 5 built-in device_types (project_id NULL, built_in=1): - Multi-plug 3/4/5/6 (kind=hub, 🔌) — Power × N+1 (1 in + N out) - Wifi-plug (kind=accessory, 📶) — Power × 2 pass-through outlet The solver treats every Power port identically regardless of in/out direction; m knows which end is which from the physical setup. Tests: - TestSeed_BuiltInDeviceTypes: built-in count rises from 16 → 21. - TestSeed_PortProfiles: new entries' port totals. - TestSeed_PowerCatalog (new, table-driven): asserts kind, icon, and the single Power port row for each of the 5 new types. --- internal/db/device_types_test.go | 69 +++++++++++++++++++- internal/db/migrations/005_catalog_power.sql | 32 +++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 internal/db/migrations/005_catalog_power.sql diff --git a/internal/db/device_types_test.go b/internal/db/device_types_test.go index 869596f..fad9925 100644 --- a/internal/db/device_types_test.go +++ b/internal/db/device_types_test.go @@ -17,6 +17,7 @@ func TestSeed_BuiltInDeviceTypes(t *testing.T) { "NAS", "PC", "Mac", "Notebook", "TV", "Soundbar", "Switch", "fritz", "ChromeCast", "SteamLink", "IOx-3", "IOx-6", "IOx-8", "Screen", "Keyboard", "Mouse", + "Multi-plug 3", "Multi-plug 4", "Multi-plug 5", "Multi-plug 6", "Wifi-plug", } if len(got) != len(want) { t.Fatalf("built-in count = %d, want %d", len(got), len(want)) @@ -57,9 +58,14 @@ func TestSeed_PortProfiles(t *testing.T) { "IOx-3": {4}, // Power 1 + USB 3 "IOx-6": {7}, // Power 1 + USB 6 "IOx-8": {9}, // Power 1 + USB 8 - "Screen": {2}, // Power 1 + HDMI 1 - "Keyboard": {1}, // USB 1 - "Mouse": {1}, // USB 1 + "Screen": {2}, // Power 1 + HDMI 1 + "Keyboard": {1}, // USB 1 + "Mouse": {1}, // USB 1 + "Multi-plug 3": {4}, // Power 4 + "Multi-plug 4": {5}, // Power 5 + "Multi-plug 5": {6}, // Power 6 + "Multi-plug 6": {7}, // Power 7 + "Wifi-plug": {2}, // Power 2 } for name, want := range cases { dt, ok := byName[name] @@ -77,6 +83,63 @@ func TestSeed_PortProfiles(t *testing.T) { } } +// TestSeed_PowerCatalog locks down migration 005: the 5 power-distribution +// device types are present with the expected kind/icon/port profile, and +// the total built-in count rose from 16 to 21. +func TestSeed_PowerCatalog(t *testing.T) { + s := newTestStore(t) + all, err := s.ListBuiltInDeviceTypes() + if err != nil { + t.Fatalf("list: %v", err) + } + if len(all) != 21 { + t.Errorf("built-in count = %d, want 21 (16 from v4 + 5 from v5)", len(all)) + } + byName := map[string]DeviceType{} + for _, d := range all { + byName[d.Name] = d + } + cases := []struct { + name string + kind string + icon string + powerPort int // count on the single Power port row + }{ + {"Multi-plug 3", "hub", "🔌", 4}, + {"Multi-plug 4", "hub", "🔌", 5}, + {"Multi-plug 5", "hub", "🔌", 6}, + {"Multi-plug 6", "hub", "🔌", 7}, + {"Wifi-plug", "accessory", "📶", 2}, + } + for _, c := range cases { + dt, ok := byName[c.name] + if !ok { + t.Errorf("missing %q", c.name) + continue + } + if !dt.BuiltIn { + t.Errorf("%s: built_in should be true", c.name) + } + if dt.ProjectID != nil { + t.Errorf("%s: project_id should be nil", c.name) + } + if dt.Kind != c.kind { + t.Errorf("%s: kind = %q, want %q", c.name, dt.Kind, c.kind) + } + if dt.Icon == nil || *dt.Icon != c.icon { + t.Errorf("%s: icon = %v, want %q", c.name, dt.Icon, c.icon) + } + if len(dt.Ports) != 1 { + t.Errorf("%s: expected 1 port-profile row, got %d", c.name, len(dt.Ports)) + continue + } + p := dt.Ports[0] + if p.CableTypeID != 1 || p.Count != c.powerPort || p.Edge != "bottom" || p.LabelPrefix != "Power" { + t.Errorf("%s: port profile mismatch: %+v", c.name, p) + } + } +} + // -------------------------------------------------------- CRUD (custom rows) func TestCreateDeviceType_CustomBasic(t *testing.T) { diff --git a/internal/db/migrations/005_catalog_power.sql b/internal/db/migrations/005_catalog_power.sql new file mode 100644 index 0000000..222f63c --- /dev/null +++ b/internal/db/migrations/005_catalog_power.sql @@ -0,0 +1,32 @@ +-- mCables v5 — catalog: power-distribution devices. +-- Adds 5 built-in device_types (project_id NULL, built_in=1). +-- +-- Multi-plug N exposes Power × (N+1) ports — one input + N outputs. The +-- solver treats every Power port identically regardless of in/out +-- direction; m knows which end is which from the physical setup. +-- +-- Wifi-plug is a pass-through outlet (Power × 2: one in, one out). + +INSERT INTO device_types (name, kind, icon, built_in, description) VALUES + ('Multi-plug 3', 'hub', '🔌', 1, '3-way power strip (1 in + 3 out)'), + ('Multi-plug 4', 'hub', '🔌', 1, '4-way power strip (1 in + 4 out)'), + ('Multi-plug 5', 'hub', '🔌', 1, '5-way power strip (1 in + 5 out)'), + ('Multi-plug 6', 'hub', '🔌', 1, '6-way power strip (1 in + 6 out)'), + ('Wifi-plug', 'accessory', '📶', 1, 'WiFi-controllable pass-through outlet'); + +-- Port profiles. cable_types id 1 = Power (seeded in 001). + +INSERT INTO device_type_ports (device_type_id, cable_type_id, label_prefix, count, edge, sort_order) + SELECT id, 1, 'Power', 4, 'bottom', 0 FROM device_types WHERE name='Multi-plug 3' AND project_id IS NULL; + +INSERT INTO device_type_ports (device_type_id, cable_type_id, label_prefix, count, edge, sort_order) + SELECT id, 1, 'Power', 5, 'bottom', 0 FROM device_types WHERE name='Multi-plug 4' AND project_id IS NULL; + +INSERT INTO device_type_ports (device_type_id, cable_type_id, label_prefix, count, edge, sort_order) + SELECT id, 1, 'Power', 6, 'bottom', 0 FROM device_types WHERE name='Multi-plug 5' AND project_id IS NULL; + +INSERT INTO device_type_ports (device_type_id, cable_type_id, label_prefix, count, edge, sort_order) + SELECT id, 1, 'Power', 7, 'bottom', 0 FROM device_types WHERE name='Multi-plug 6' AND project_id IS NULL; + +INSERT INTO device_type_ports (device_type_id, cable_type_id, label_prefix, count, edge, sort_order) + SELECT id, 1, 'Power', 2, 'bottom', 0 FROM device_types WHERE name='Wifi-plug' AND project_id IS NULL;