|
1 | 1 | package vm |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "io" |
| 5 | + "os" |
| 6 | + "strings" |
4 | 7 | "testing" |
5 | 8 | "time" |
6 | 9 |
|
7 | 10 | "github.com/cocoonstack/cocoon/types" |
8 | 11 | ) |
9 | 12 |
|
| 13 | +// captureStdout swaps os.Stdout for a pipe, runs fn, returns what fn wrote. |
| 14 | +func captureStdout(t *testing.T, fn func()) string { |
| 15 | + t.Helper() |
| 16 | + orig := os.Stdout |
| 17 | + r, w, err := os.Pipe() |
| 18 | + if err != nil { |
| 19 | + t.Fatalf("pipe: %v", err) |
| 20 | + } |
| 21 | + os.Stdout = w |
| 22 | + fn() |
| 23 | + _ = w.Close() |
| 24 | + os.Stdout = orig |
| 25 | + buf, _ := io.ReadAll(r) |
| 26 | + return string(buf) |
| 27 | +} |
| 28 | + |
10 | 29 | func TestMatchesFilter(t *testing.T) { |
11 | 30 | vm := &types.VM{ |
12 | 31 | ID: "abcdef123456", |
@@ -85,3 +104,83 @@ func TestVMIPsAndSort(t *testing.T) { |
85 | 104 | t.Fatalf("takeSnapshot() = %+v", snap) |
86 | 105 | } |
87 | 106 | } |
| 107 | + |
| 108 | +func TestRenderVMList(t *testing.T) { |
| 109 | + vm := &types.VM{ |
| 110 | + ID: "abc", |
| 111 | + Config: types.VMConfig{Name: "demo", Config: types.Config{CPU: 1, Memory: 1 << 30, Image: "img"}}, |
| 112 | + CreatedAt: time.Now(), |
| 113 | + } |
| 114 | + |
| 115 | + tests := []struct { |
| 116 | + name string |
| 117 | + vms []*types.VM |
| 118 | + format string |
| 119 | + want string |
| 120 | + notWant string |
| 121 | + }{ |
| 122 | + {name: "empty table → No VMs found", vms: nil, format: "", want: "No VMs found."}, |
| 123 | + {name: "empty json → null", vms: nil, format: "json", want: "null"}, |
| 124 | + {name: "table with vm contains name", vms: []*types.VM{vm}, format: "", want: "demo"}, |
| 125 | + {name: "json with vm contains id", vms: []*types.VM{vm}, format: "json", want: `"id": "abc"`}, |
| 126 | + {name: "table mode skips json marker", vms: []*types.VM{vm}, format: "", notWant: `"id":`}, |
| 127 | + } |
| 128 | + |
| 129 | + for _, tt := range tests { |
| 130 | + t.Run(tt.name, func(t *testing.T) { |
| 131 | + out := captureStdout(t, func() { |
| 132 | + if err := renderVMList(tt.vms, tt.format); err != nil { |
| 133 | + t.Fatalf("renderVMList: %v", err) |
| 134 | + } |
| 135 | + }) |
| 136 | + if tt.want != "" && !strings.Contains(out, tt.want) { |
| 137 | + t.Errorf("output %q does not contain %q", out, tt.want) |
| 138 | + } |
| 139 | + if tt.notWant != "" && strings.Contains(out, tt.notWant) { |
| 140 | + t.Errorf("output %q unexpectedly contains %q", out, tt.notWant) |
| 141 | + } |
| 142 | + }) |
| 143 | + } |
| 144 | +} |
| 145 | + |
| 146 | +func TestApplyFilters(t *testing.T) { |
| 147 | + vms := []*types.VM{ |
| 148 | + {ID: "abcdef123456", Config: types.VMConfig{Name: "alpha"}}, |
| 149 | + {ID: "beadbeef0000", Config: types.VMConfig{Name: "beta"}}, |
| 150 | + } |
| 151 | + tests := []struct { |
| 152 | + name string |
| 153 | + filters []string |
| 154 | + wantIDs []string |
| 155 | + }{ |
| 156 | + {name: "no filter returns all", filters: nil, wantIDs: []string{"abcdef123456", "beadbeef0000"}}, |
| 157 | + {name: "exact name", filters: []string{"alpha"}, wantIDs: []string{"abcdef123456"}}, |
| 158 | + {name: "id prefix", filters: []string{"bead"}, wantIDs: []string{"beadbeef0000"}}, |
| 159 | + {name: "multi filter union", filters: []string{"alpha", "bead"}, wantIDs: []string{"abcdef123456", "beadbeef0000"}}, |
| 160 | + {name: "no match", filters: []string{"zzz"}, wantIDs: nil}, |
| 161 | + } |
| 162 | + for _, tt := range tests { |
| 163 | + t.Run(tt.name, func(t *testing.T) { |
| 164 | + got := applyFilters(vms, tt.filters) |
| 165 | + gotIDs := make([]string, 0, len(got)) |
| 166 | + for _, vm := range got { |
| 167 | + gotIDs = append(gotIDs, vm.ID) |
| 168 | + } |
| 169 | + if !equalStrings(gotIDs, tt.wantIDs) { |
| 170 | + t.Errorf("applyFilters(%v) = %v, want %v", tt.filters, gotIDs, tt.wantIDs) |
| 171 | + } |
| 172 | + }) |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +func equalStrings(a, b []string) bool { |
| 177 | + if len(a) != len(b) { |
| 178 | + return false |
| 179 | + } |
| 180 | + for i := range a { |
| 181 | + if a[i] != b[i] { |
| 182 | + return false |
| 183 | + } |
| 184 | + } |
| 185 | + return true |
| 186 | +} |
0 commit comments