1package disk
2
3import (
4 "testing"
5)
6
7// TestDeterminePartitionPath tests partition path determination
8func TestDeterminePartitionPath(t *testing.T) {
9 tests := []struct {
10 name string
11 diskPath string
12 partitionNumber int
13 expected string
14 shouldErr bool
15 }{
16 // SATA/SSD cases
17 {"SATA partition 1", "/dev/sda", 1, "/dev/sda1", false},
18 {"SATA partition 2", "/dev/sda", 2, "/dev/sda2", false},
19 {"SDB partition 1", "/dev/sdb", 1, "/dev/sdb1", false},
20 // NVMe cases
21 {"NVMe partition 1", "/dev/nvme0n1", 1, "/dev/nvme0n1p1", false},
22 {"NVMe partition 2", "/dev/nvme0n1", 2, "/dev/nvme0n1p2", false},
23 {"NVMe 1 partition 1", "/dev/nvme1n1", 1, "/dev/nvme1n1p1", false},
24 // MMC cases
25 {"MMC partition 1", "/dev/mmcblk0", 1, "/dev/mmcblk0p1", false},
26 {"MMC partition 2", "/dev/mmcblk0", 2, "/dev/mmcblk0p2", false},
27 // Virtio cases
28 {"Virtio partition 1", "/dev/vda", 1, "/dev/vda1", false},
29 {"Virtio partition 2", "/dev/vda", 2, "/dev/vda2", false},
30 // Error cases
31 {"empty disk path", "", 1, "", true},
32 {"partition number 0", "/dev/sda", 0, "", true},
33 {"partition number negative", "/dev/sda", -1, "", true},
34 {"partition number too large", "/dev/sda", 129, "", true},
35 {"invalid disk path", "sda", 1, "", true},
36 }
37
38 for _, tt := range tests {
39 t.Run(tt.name, func(t *testing.T) {
40 result, err := DeterminePartitionPath(tt.diskPath, tt.partitionNumber)
41
42 if (err != nil) != tt.shouldErr {
43 t.Errorf("got error %v, expected error=%v", err, tt.shouldErr)
44 }
45
46 if !tt.shouldErr && result != tt.expected {
47 t.Errorf("got %q, want %q", result, tt.expected)
48 }
49 })
50 }
51}
52
53// TestValidateDiskPath tests disk path validation
54func TestValidateDiskPath(t *testing.T) {
55 tests := []struct {
56 name string
57 diskPath string
58 shouldErr bool
59 }{
60 {"valid SATA", "/dev/sda", false},
61 {"valid SDB", "/dev/sdb", false},
62 {"valid NVMe", "/dev/nvme0n1", false},
63 {"valid MMC", "/dev/mmcblk0", false},
64 {"valid Virtio", "/dev/vda", false},
65 {"valid IDE", "/dev/hda", false},
66 {"empty", "", true},
67 {"no /dev/ prefix", "sda", true},
68 {"invalid prefix", "/dev/xda", true},
69 {"too long", "/dev/" + string(make([]byte, 60)), true},
70 }
71
72 for _, tt := range tests {
73 t.Run(tt.name, func(t *testing.T) {
74 err := ValidateDiskPath(tt.diskPath)
75 if (err != nil) != tt.shouldErr {
76 t.Errorf("got error %v, expected error=%v", err, tt.shouldErr)
77 }
78 })
79 }
80}
81
82// TestValidatePartitionPath tests partition path validation
83func TestValidatePartitionPath(t *testing.T) {
84 tests := []struct {
85 name string
86 partitionPath string
87 shouldErr bool
88 }{
89 {"valid SATA partition", "/dev/sda1", false},
90 {"valid NVMe partition", "/dev/nvme0n1p1", false},
91 {"valid MMC partition", "/dev/mmcblk0p1", false},
92 {"valid Virtio partition", "/dev/vda1", false},
93 {"empty", "", true},
94 {"no /dev/ prefix", "sda1", true},
95 {"too long", "/dev/" + string(make([]byte, 60)), true},
96 }
97
98 for _, tt := range tests {
99 t.Run(tt.name, func(t *testing.T) {
100 err := ValidatePartitionPath(tt.partitionPath)
101 if (err != nil) != tt.shouldErr {
102 t.Errorf("got error %v, expected error=%v", err, tt.shouldErr)
103 }
104 })
105 }
106}
107
108// TestIsDiskPath tests disk vs partition detection
109func TestIsDiskPath(t *testing.T) {
110 tests := []struct {
111 name string
112 path string
113 expected bool
114 }{
115 // Disks
116 {"SATA disk", "/dev/sda", true},
117 {"SDB disk", "/dev/sdb", true},
118 {"NVMe disk", "/dev/nvme0n1", true},
119 {"MMC disk", "/dev/mmcblk0", true},
120 {"Virtio disk", "/dev/vda", true},
121 // Partitions
122 {"SATA partition", "/dev/sda1", false},
123 {"NVMe partition", "/dev/nvme0n1p1", false},
124 {"MMC partition", "/dev/mmcblk0p1", false},
125 {"Virtio partition", "/dev/vda1", false},
126 // Edge cases
127 {"empty", "", false},
128 }
129
130 for _, tt := range tests {
131 t.Run(tt.name, func(t *testing.T) {
132 result := IsDiskPath(tt.path)
133 if result != tt.expected {
134 t.Errorf("got %v, want %v", result, tt.expected)
135 }
136 })
137 }
138}
139
140// TestExtractDiskFromPartition tests extracting disk path from partition
141func TestExtractDiskFromPartition(t *testing.T) {
142 tests := []struct {
143 name string
144 partitionPath string
145 expected string
146 shouldErr bool
147 }{
148 // SATA/SSD
149 {"SATA partition 1", "/dev/sda1", "/dev/sda", false},
150 {"SATA partition 10", "/dev/sda10", "/dev/sda", false},
151 {"SDB partition 1", "/dev/sdb1", "/dev/sdb", false},
152 // NVMe
153 {"NVMe partition 1", "/dev/nvme0n1p1", "/dev/nvme0n1", false},
154 {"NVMe partition 10", "/dev/nvme0n1p10", "/dev/nvme0n1", false},
155 {"NVMe 1 partition 1", "/dev/nvme1n1p1", "/dev/nvme1n1", false},
156 // MMC
157 {"MMC partition 1", "/dev/mmcblk0p1", "/dev/mmcblk0", false},
158 {"MMC partition 10", "/dev/mmcblk0p10", "/dev/mmcblk0", false},
159 // Virtio
160 {"Virtio partition 1", "/dev/vda1", "/dev/vda", false},
161 {"Virtio partition 10", "/dev/vda10", "/dev/vda", false},
162 // Already disk paths (should return as-is)
163 {"SATA disk", "/dev/sda", "/dev/sda", false},
164 {"NVMe disk", "/dev/nvme0n1", "/dev/nvme0n1", false},
165 // Error cases
166 {"empty", "", "", true},
167 }
168
169 for _, tt := range tests {
170 t.Run(tt.name, func(t *testing.T) {
171 result, err := ExtractDiskFromPartition(tt.partitionPath)
172
173 if (err != nil) != tt.shouldErr {
174 t.Errorf("got error %v, expected error=%v", err, tt.shouldErr)
175 }
176
177 if !tt.shouldErr && result != tt.expected {
178 t.Errorf("got %q, want %q", result, tt.expected)
179 }
180 })
181 }
182}
183
184// TestDeterminePartitionPathConsistency tests consistency between DeterminePartitionPath and ExtractDiskFromPartition
185func TestDeterminePartitionPathConsistency(t *testing.T) {
186 disks := []string{
187 "/dev/sda",
188 "/dev/sdb",
189 "/dev/nvme0n1",
190 "/dev/nvme1n1",
191 "/dev/mmcblk0",
192 "/dev/vda",
193 }
194
195 for _, disk := range disks {
196 for partNum := 1; partNum <= 5; partNum++ {
197 // Determine partition path
198 partPath, err := DeterminePartitionPath(disk, partNum)
199 if err != nil {
200 t.Fatalf("DeterminePartitionPath(%q, %d) failed: %v", disk, partNum, err)
201 }
202
203 // Extract disk from partition path
204 extractedDisk, err := ExtractDiskFromPartition(partPath)
205 if err != nil {
206 t.Fatalf("ExtractDiskFromPartition(%q) failed: %v", partPath, err)
207 }
208
209 // Should match original disk
210 if extractedDisk != disk {
211 t.Errorf("Inconsistency for %q partition %d: determined %q, extracted %q",
212 disk, partNum, partPath, extractedDisk)
213 }
214 }
215 }
216}
217
218// TestValidateDiskPathErrors tests error messages
219func TestValidateDiskPathErrors(t *testing.T) {
220 tests := []struct {
221 name string
222 diskPath string
223 errSubstr string
224 }{
225 {"empty", "", "cannot be empty"},
226 {"no /dev/", "sda", "must start with /dev/"},
227 {"invalid type", "/dev/xda", "unrecognized disk device type"},
228 }
229
230 for _, tt := range tests {
231 t.Run(tt.name, func(t *testing.T) {
232 err := ValidateDiskPath(tt.diskPath)
233 if err == nil {
234 t.Fatal("expected error, got nil")
235 }
236 if !contains(err.Error(), tt.errSubstr) {
237 t.Errorf("error %q does not contain %q", err.Error(), tt.errSubstr)
238 }
239 })
240 }
241}
242
243// TestValidatePartitionPathErrors tests error messages
244func TestValidatePartitionPathErrors(t *testing.T) {
245 tests := []struct {
246 name string
247 partitionPath string
248 errSubstr string
249 }{
250 {"empty", "", "cannot be empty"},
251 {"no /dev/", "sda1", "must start with /dev/"},
252 }
253
254 for _, tt := range tests {
255 t.Run(tt.name, func(t *testing.T) {
256 err := ValidatePartitionPath(tt.partitionPath)
257 if err == nil {
258 t.Fatal("expected error, got nil")
259 }
260 if !contains(err.Error(), tt.errSubstr) {
261 t.Errorf("error %q does not contain %q", err.Error(), tt.errSubstr)
262 }
263 })
264 }
265}
266
267// TestDeterminePartitionPathErrors tests error messages
268func TestDeterminePartitionPathErrors(t *testing.T) {
269 tests := []struct {
270 name string
271 diskPath string
272 partitionNumber int
273 errSubstr string
274 }{
275 {"empty disk", "", 1, "cannot be empty"},
276 {"invalid partition 0", "/dev/sda", 0, "between 1 and 128"},
277 {"invalid partition negative", "/dev/sda", -1, "between 1 and 128"},
278 {"invalid partition large", "/dev/sda", 129, "between 1 and 128"},
279 {"no /dev/ prefix", "sda", 1, "must start with /dev/"},
280 }
281
282 for _, tt := range tests {
283 t.Run(tt.name, func(t *testing.T) {
284 _, err := DeterminePartitionPath(tt.diskPath, tt.partitionNumber)
285 if err == nil {
286 t.Fatal("expected error, got nil")
287 }
288 if !contains(err.Error(), tt.errSubstr) {
289 t.Errorf("error %q does not contain %q", err.Error(), tt.errSubstr)
290 }
291 })
292 }
293}