blob: 933d3a2cb9dc267a7251cc75cd3ce5aa09393a6c [file] [log] [blame]
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07001/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -07006#include "cgpt_test.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -07007#include <string.h>
8#include "cgpt.h"
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -07009#include "cgpt_internal.h"
10#include "crc32.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070011#include "gpt.h"
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070012#include "quick_sort_test.h"
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070013#include "utility.h"
14
15/* Testing partition layout (sector_bytes=512)
16 *
17 * LBA Size Usage
18 * 0 1 PMBR
19 * 1 1 primary partition header
20 * 2 32 primary partition entries (128B * 128)
21 * 34 100 kernel A
22 * 134 100 kernel B
23 * 234 100 root A
24 * 334 100 root B
25 * 434 32 secondary partition entries
26 * 466 1 secondary partition header
27 * 467
28 */
29#define DEFAULT_SECTOR_SIZE 512
30#define MAX_SECTOR_SIZE 4096
31#define DEFAULT_DRIVE_SECTORS 467
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070032#define PARTITION_ENTRIES_SIZE TOTAL_ENTRIES_SIZE /* 16384 */
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070033
34/* Given a GptData pointer, first re-calculate entries CRC32 value,
35 * then reset header CRC32 value to 0, and calculate header CRC32 value.
36 * Both primary and secondary are updated. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070037void RefreshCrc32(GptData *gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070038 GptHeader *header, *header2;
39 GptEntry *entries, *entries2;
40
41 header = (GptHeader*)gpt->primary_header;
42 entries = (GptEntry*)gpt->primary_entries;
43 header2 = (GptHeader*)gpt->secondary_header;
44 entries2 = (GptEntry*)gpt->secondary_entries;
45
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070046 header->entries_crc32 =
47 Crc32((uint8_t*)entries,
48 header->number_of_entries * header->size_of_entry);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070049 header->header_crc32 = 0;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070050 header->header_crc32 = Crc32((uint8_t*)header, header->size);
51 header2->entries_crc32 =
52 Crc32((uint8_t*)entries2,
53 header2->number_of_entries * header2->size_of_entry);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070054 header2->header_crc32 = 0;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070055 header2->header_crc32 = Crc32((uint8_t*)header2, header2->size);
56}
57
58void ZeroHeaders(GptData* gpt) {
59 Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE);
60 Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE);
61}
62
63void ZeroEntries(GptData* gpt) {
64 Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE);
65 Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE);
66}
67
68void ZeroHeadersEntries(GptData* gpt) {
69 ZeroHeaders(gpt);
70 ZeroEntries(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070071}
72
73/* Returns a pointer to a static GptData instance (no free is required).
74 * All fields are zero except 4 pointers linking to header and entries.
75 * All content of headers and entries are zero. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070076GptData* GetEmptyGptData() {
77 static GptData gpt;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070078 static uint8_t primary_header[MAX_SECTOR_SIZE];
79 static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
80 static uint8_t secondary_header[MAX_SECTOR_SIZE];
81 static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
82
83 Memset(&gpt, 0, sizeof(gpt));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070084 gpt.primary_header = primary_header;
85 gpt.primary_entries = primary_entries;
86 gpt.secondary_header = secondary_header;
87 gpt.secondary_entries = secondary_entries;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070088 ZeroHeadersEntries(&gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070089
90 return &gpt;
91}
92
93/* Fills in most of fields and creates the layout described in the top of this
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -070094 * file. Before calling this function, primary/secondary header/entries must
95 * have been pointed to the buffer, say, a gpt returned from GetEmptyGptData().
96 * This function returns a good (valid) copy of GPT layout described in top of
97 * this file. */
98void BuildTestGptData(GptData *gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -070099 GptHeader *header, *header2;
100 GptEntry *entries, *entries2;
101 Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
102
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700103 gpt->sector_bytes = DEFAULT_SECTOR_SIZE;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700104 gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
105
106 /* build primary */
107 header = (GptHeader*)gpt->primary_header;
108 entries = (GptEntry*)gpt->primary_entries;
109 Memcpy(header->signature, GPT_HEADER_SIGNATURE, sizeof(GPT_HEADER_SIGNATURE));
110 header->revision = GPT_HEADER_REVISION;
111 header->size = sizeof(GptHeader) - sizeof(header->padding);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700112 header->reserved = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700113 header->my_lba = 1;
114 header->first_usable_lba = 34;
115 header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
116 header->entries_lba = 2;
117 header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */
118 header->size_of_entry = 128; /* bytes */
119 Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
120 entries[0].starting_lba = 34;
121 entries[0].ending_lba = 133;
122 Memcpy(&entries[1].type, &chromeos_kernel, sizeof(chromeos_kernel));
123 entries[1].starting_lba = 134;
124 entries[1].ending_lba = 233;
125 Memcpy(&entries[2].type, &chromeos_kernel, sizeof(chromeos_kernel));
126 entries[2].starting_lba = 234;
127 entries[2].ending_lba = 333;
128 Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
129 entries[3].starting_lba = 334;
130 entries[3].ending_lba = 433;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700131 header->padding = 0;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700132
133 /* build secondary */
134 header2 = (GptHeader*)gpt->secondary_header;
135 entries2 = (GptEntry*)gpt->secondary_entries;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700136 Memcpy(header2, header, sizeof(GptHeader));
137 Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700138 header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
139 header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
140
141 RefreshCrc32(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700142}
143
144/* Dumps memory starting from [vp] with [len] bytes.
145 * Prints [memo] if not NULL. Example output:
146 *
147 * 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f
148 * 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f
149 * ...
150 */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700151static void Dump(void *vp, int len, char* memo) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700152 uint8_t *start = vp;
153 int i;
154 if (memo) printf("--[%s]----------\n", memo);
155 for (i = 0; i < len; ++i) {
156 printf("%02x%s", start[i],
157 (!(~i & 15) ? "\n" :
158 !(~i & 7) ? " - ": " "));
159 }
160 if (i&15) printf("\n");
161}
162
163/* More formatted dump with GptData. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700164void DumpGptData(GptData *gpt) {
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700165 printf("DumpGptData(%p)...\n", gpt);
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700166 Dump(gpt, sizeof(gpt), NULL);
167 Dump(gpt->primary_header, sizeof(GptHeader), "Primary header");
168 Dump(gpt->primary_entries, sizeof(GptEntry) * 8, "Primary entries");
169 Dump(gpt->secondary_header, sizeof(GptHeader), "Secondary header");
170 Dump(gpt->secondary_entries, sizeof(GptEntry) * 8,
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700171 "Secondary entries");
172}
173
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700174/* Tests if the default structure returned by BuildTestGptData() is good. */
175int TestBuildTestGptData() {
176 GptData *gpt;
177 gpt = GetEmptyGptData();
178 BuildTestGptData(gpt);
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700179 EXPECT(GPT_SUCCESS == GptInit(gpt));
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700180 return TEST_OK;
181}
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700182
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700183/* Tests if wrong sector_bytes or drive_sectors is detected by GptInit().
184 * Currently we only support 512 bytes per sector.
185 * In the future, we may support other sizes.
186 * A too small drive_sectors should be rejected by GptInit(). */
187int ParameterTests() {
188 GptData *gpt;
189 struct {
190 uint32_t sector_bytes;
191 uint64_t drive_sectors;
192 int expected_retval;
193 } cases[] = {
194 {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS},
195 {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
196 {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER},
197 {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER},
198 {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 + GPT_ENTRIES_SECTORS * 2,
199 GPT_SUCCESS},
200 {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
201 };
202 int i;
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700203
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700204 gpt = GetEmptyGptData();
205 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
206 BuildTestGptData(gpt);
207 gpt->sector_bytes = cases[i].sector_bytes;
208 gpt->drive_sectors = cases[i].drive_sectors;
209 EXPECT(cases[i].expected_retval == CheckParameters(gpt));
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700210 }
211
212 return TEST_OK;
213}
214
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700215/* Tests if signature ("EFI PART") is checked. */
216int SignatureTest() {
217 int i;
218 GptData *gpt;
219 int test_mask;
220 GptHeader *headers[2];
221
222 gpt = GetEmptyGptData();
223 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
224 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
225
226 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
227 for (i = 0; i < 8; ++i) {
228 BuildTestGptData(gpt);
229 if (test_mask & MASK_PRIMARY)
230 headers[PRIMARY]->signature[i] ^= 0xff;
231 if (test_mask & MASK_SECONDARY)
232 headers[SECONDARY]->signature[i] ^= 0xff;
233 EXPECT((MASK_BOTH ^ test_mask) == CheckHeaderSignature(gpt));
234 }
235 }
236
237 return TEST_OK;
238}
239
240/* The revision we currently support is GPT_HEADER_REVISION.
241 * If the revision in header is not that, we expect the header is invalid. */
242int RevisionTest() {
243 GptData *gpt;
244 struct {
245 uint32_t value_to_test;
246 int is_valid_value;
247 } cases[] = {
248 {0x01000000, 0},
249 {0x00010000, 1}, /* GPT_HEADER_REVISION */
250 {0x00000100, 0},
251 {0x00000001, 0},
252 {0x23010456, 0},
253 };
254 int i;
255 int test_mask;
256 GptHeader *headers[2];
257 uint32_t valid_headers;
258
259 gpt = GetEmptyGptData();
260 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
261 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
262
263 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
264 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
265 BuildTestGptData(gpt);
266 if (test_mask & MASK_PRIMARY)
267 headers[PRIMARY]->revision = cases[i].value_to_test;
268 if (test_mask & MASK_SECONDARY)
269 headers[SECONDARY]->revision = cases[i].value_to_test;
270 valid_headers = CheckRevision(gpt);
271 if (cases[i].is_valid_value)
272 EXPECT(MASK_BOTH == valid_headers);
273 else
274 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
275 }
276 }
277 return TEST_OK;
278}
279
280int SizeTest() {
281 GptData *gpt;
282 struct {
283 uint32_t value_to_test;
284 int is_valid_value;
285 } cases[] = {
286 {91, 0},
287 {92, 1},
288 {93, 1},
289 {511, 1},
290 {512, 1},
291 {513, 0},
292 };
293 int i;
294 int test_mask;
295 GptHeader *headers[2];
296 uint32_t valid_headers;
297
298 gpt = GetEmptyGptData();
299 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
300 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
301
302 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
303 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
304 BuildTestGptData(gpt);
305 if (test_mask & MASK_PRIMARY)
306 headers[PRIMARY]->size = cases[i].value_to_test;
307 if (test_mask & MASK_SECONDARY)
308 headers[SECONDARY]->size = cases[i].value_to_test;
309 valid_headers = CheckSize(gpt);
310 if (cases[i].is_valid_value)
311 EXPECT(MASK_BOTH == valid_headers);
312 else
313 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
314 }
315 }
316 return TEST_OK;
317}
318
319/* Tests if reserved fields are checked.
320 * We'll try non-zero values to test. */
321int ReservedFieldsTest() {
322 GptData *gpt;
323 GptHeader *primary_header, *secondary_header;
324
325 gpt = GetEmptyGptData();
326 primary_header = (GptHeader*)gpt->primary_header;
327 secondary_header = (GptHeader*)gpt->secondary_header;
328
329 /* expect secondary is still valid. */
330 BuildTestGptData(gpt);
331 primary_header->reserved ^= 0x12345678; /* whatever random */
332 EXPECT(MASK_SECONDARY == CheckReservedFields(gpt));
333
334 /* expect secondary is still valid. */
335 BuildTestGptData(gpt);
336 primary_header->padding ^= 0x12345678; /* whatever random */
337 EXPECT(MASK_SECONDARY == CheckReservedFields(gpt));
338
339 /* expect primary is still valid. */
340 BuildTestGptData(gpt);
341 secondary_header->reserved ^= 0x12345678; /* whatever random */
342 EXPECT(MASK_PRIMARY == CheckReservedFields(gpt));
343
344 /* expect primary is still valid. */
345 BuildTestGptData(gpt);
346 secondary_header->padding ^= 0x12345678; /* whatever random */
347 EXPECT(MASK_PRIMARY == CheckReservedFields(gpt));
348
349 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700350}
351
352/* Tests if myLBA field is checked (1 for primary, last for secondary). */
353int MyLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700354 GptData *gpt;
355 int test_mask;
356 GptHeader *headers[2];
357 uint32_t valid_headers;
358
359 gpt = GetEmptyGptData();
360 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
361 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
362
363 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
364 BuildTestGptData(gpt);
365 if (test_mask & MASK_PRIMARY)
366 ++headers[PRIMARY]->my_lba;
367 if (test_mask & MASK_SECONDARY)
368 --headers[SECONDARY]->my_lba;
369 valid_headers = CheckMyLba(gpt);
370 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
371 }
372 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700373}
374
375/* Tests if SizeOfPartitionEntry is checked. SizeOfPartitionEntry must be
376 * between 128 and 512, and a multiple of 8. */
377int SizeOfPartitionEntryTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700378 GptData *gpt;
379 struct {
380 uint32_t value_to_test;
381 int is_valid_value;
382 } cases[] = {
383 {127, 0},
384 {128, 1},
385 {129, 0},
386 {130, 0},
387 {131, 0},
388 {132, 0},
389 {133, 0},
390 {134, 0},
391 {135, 0},
392 {136, 1},
393 {144, 1},
394 {160, 1},
395 {192, 1},
396 {256, 1},
397 {384, 1},
398 {504, 1},
399 {512, 1},
400 {513, 0},
401 {520, 0},
402 };
403 int i;
404 int test_mask;
405 GptHeader *headers[2];
406 uint32_t valid_headers;
407
408 gpt = GetEmptyGptData();
409 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
410 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
411
412 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
413 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
414 BuildTestGptData(gpt);
415 if (test_mask & MASK_PRIMARY) {
416 headers[PRIMARY]->size_of_entry = cases[i].value_to_test;
417 headers[PRIMARY]->number_of_entries =
418 TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
419 }
420 if (test_mask & MASK_SECONDARY) {
421 headers[SECONDARY]->size_of_entry = cases[i].value_to_test;
422 headers[SECONDARY]->number_of_entries =
423 TOTAL_ENTRIES_SIZE / cases[i].value_to_test;
424 }
425 valid_headers = CheckSizeOfPartitionEntry(gpt);
426 if (cases[i].is_valid_value)
427 EXPECT(MASK_BOTH == valid_headers);
428 else
429 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
430 }
431 }
432 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700433}
434
435/* Tests if NumberOfPartitionEntries is checes. NumberOfPartitionEntries must
436 * be between 32 and 512, and SizeOfPartitionEntry * NumberOfPartitionEntries
437 * must be 16384. */
438int NumberOfPartitionEntriesTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700439 GptData *gpt;
440 struct {
441 uint32_t size_of_entry;
442 uint32_t number_of_entries;
443 int is_valid_value;
444 } cases[] = {
445 {111, 147, 0},
446 {111, 149, 0},
447 {128, 32, 0},
448 {128, 64, 0},
449 {128, 127, 0},
450 {128, 128, 1},
451 {128, 129, 0},
452 {128, 256, 0},
453 {256, 32, 0},
454 {256, 64, 1},
455 {256, 128, 0},
456 {256, 256, 0},
457 {512, 32, 1},
458 {512, 64, 0},
459 {512, 128, 0},
460 {512, 256, 0},
461 {1024, 128, 0},
462 };
463 int i;
464 int test_mask;
465 GptHeader *headers[2];
466 uint32_t valid_headers;
467
468 gpt = GetEmptyGptData();
469 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
470 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
471
472 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
473 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
474 BuildTestGptData(gpt);
475 if (test_mask & MASK_PRIMARY) {
476 headers[PRIMARY]->size_of_entry = cases[i].size_of_entry;
477 headers[PRIMARY]->number_of_entries = cases[i].number_of_entries;
478 }
479 if (test_mask & MASK_SECONDARY) {
480 headers[SECONDARY]->size_of_entry = cases[i].size_of_entry;
481 headers[SECONDARY]->number_of_entries = cases[i].number_of_entries;
482 }
483 valid_headers = CheckNumberOfEntries(gpt);
484 if (cases[i].is_valid_value)
485 EXPECT(MASK_BOTH == valid_headers);
486 else
487 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
488 }
489 }
490 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700491}
492
493/* Tests if PartitionEntryLBA in primary/secondary headers is checked. */
494int PartitionEntryLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700495 GptData *gpt;
496 int test_mask;
497 GptHeader *headers[2];
498 uint32_t valid_headers;
499
500 gpt = GetEmptyGptData();
501 headers[PRIMARY] = (GptHeader*)gpt->primary_header;
502 headers[SECONDARY] = (GptHeader*)gpt->secondary_header;
503
504 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
505 BuildTestGptData(gpt);
506 if (test_mask & MASK_PRIMARY)
507 headers[PRIMARY]->entries_lba = 0;
508 if (test_mask & MASK_SECONDARY)
509 headers[SECONDARY]->entries_lba = DEFAULT_DRIVE_SECTORS - 31 - 1;
510 valid_headers = CheckEntriesLba(gpt);
511 EXPECT((MASK_BOTH ^ test_mask) == valid_headers);
512 }
513 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700514}
515
516/* Tests if FirstUsableLBA and LastUsableLBA are checked.
517 * FirstUsableLBA must be after the end of the primary GPT table array.
518 * LastUsableLBA must be before the start of the secondary GPT table array.
519 * FirstUsableLBA <= LastUsableLBA. */
520int FirstUsableLbaAndLastUsableLbaTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700521 GptData *gpt;
522 GptHeader *primary_header, *secondary_header;
523 uint32_t valid_headers;
524 int i;
525 struct {
526 uint64_t primary_entries_lba;
527 uint64_t primary_first_usable_lba;
528 uint64_t primary_last_usable_lba;
529 uint64_t secondary_first_usable_lba;
530 uint64_t secondary_last_usable_lba;
531 uint64_t secondary_entries_lba;
532 int expected_masks;
533 } cases[] = {
534 {2, 34, 433, 34, 433, 434, MASK_BOTH},
535 {2, 34, 432, 34, 430, 434, MASK_BOTH},
536 {2, 33, 433, 33, 433, 434, MASK_NONE},
537 {3, 34, 433, 35, 433, 434, MASK_SECONDARY},
538 {3, 35, 433, 33, 433, 434, MASK_PRIMARY},
539 {2, 34, 434, 34, 433, 434, MASK_SECONDARY},
540 {2, 34, 433, 34, 434, 434, MASK_PRIMARY},
541 {2, 35, 433, 35, 433, 434, MASK_BOTH},
542 {2, 433, 433, 433, 433, 434, MASK_BOTH},
543 {2, 434, 433, 434, 434, 434, MASK_NONE},
544 {2, 433, 34, 34, 433, 434, MASK_SECONDARY},
545 {2, 34, 433, 433, 34, 434, MASK_PRIMARY},
546 };
547
548 gpt = GetEmptyGptData();
549 primary_header = (GptHeader*)gpt->primary_header;
550 secondary_header = (GptHeader*)gpt->secondary_header;
551
552 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
553 BuildTestGptData(gpt);
554 primary_header->entries_lba = cases[i].primary_entries_lba;
555 primary_header->first_usable_lba = cases[i].primary_first_usable_lba;
556 primary_header->last_usable_lba = cases[i].primary_last_usable_lba;
557 secondary_header->entries_lba = cases[i].secondary_entries_lba;
558 secondary_header->first_usable_lba = cases[i].secondary_first_usable_lba;
559 secondary_header->last_usable_lba = cases[i].secondary_last_usable_lba;
560 valid_headers = CheckValidUsableLbas(gpt);
561 EXPECT(cases[i].expected_masks == valid_headers);
562 }
563
564 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700565}
566
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700567/* Tests if header CRC in two copies are calculated. */
568int HeaderCrcTest() {
569 GptData *gpt;
570 GptHeader *primary_header, *secondary_header;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700571
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700572 gpt = GetEmptyGptData();
573 primary_header = (GptHeader*)gpt->primary_header;
574 secondary_header = (GptHeader*)gpt->secondary_header;
575
576 /* Modify the first byte of primary header, and expect the CRC is wrong. */
577 BuildTestGptData(gpt);
578 gpt->primary_header[0] ^= 0xa5; /* just XOR a non-zero value */
579 EXPECT(MASK_SECONDARY == CheckHeaderCrc(gpt));
580
581 /* Modify the last byte of secondary header, and expect the CRC is wrong. */
582 BuildTestGptData(gpt);
583 gpt->secondary_header[secondary_header->size-1] ^= 0x5a;
584 EXPECT(MASK_PRIMARY == CheckHeaderCrc(gpt));
585
586 /* Modify out of CRC range, expect CRC is still right. */
587 BuildTestGptData(gpt);
588 gpt->primary_header[primary_header->size] ^= 0x87;
589 EXPECT(MASK_BOTH == CheckHeaderCrc(gpt));
590
591 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700592}
593
594/* Tests if PartitionEntryArrayCRC32 is checked.
595 * PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry *
596 * NumberOfPartitionEntries bytes.
597 */
598int EntriesCrcTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700599 GptData *gpt;
600
601 gpt = GetEmptyGptData();
602
603 /* Modify the first byte of primary entries, and expect the CRC is wrong. */
604 BuildTestGptData(gpt);
605 gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */
606 EXPECT(MASK_SECONDARY == CheckEntriesCrc(gpt));
607
608 /* Modify the last byte of secondary entries, and expect the CRC is wrong. */
609 BuildTestGptData(gpt);
610 gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a;
611 EXPECT(MASK_PRIMARY == CheckEntriesCrc(gpt));
612
613 return TEST_OK;
614}
615
616/* Tests if GptInit() handles non-identical partition entries well.
617 * Two copies of partition table entries must be identical. If not, we trust the
618 * primary table entries, and mark secondary as modified. */
619int IdenticalEntriesTest() {
620 GptData *gpt;
621
622 gpt = GetEmptyGptData();
623
624 /* Tests RepairEntries() first. */
625 BuildTestGptData(gpt);
626 EXPECT(0 == RepairEntries(gpt, MASK_BOTH));
627 gpt->secondary_entries[0] ^= 0xa5; /* XOR any number */
628 EXPECT(GPT_MODIFIED_ENTRIES2 == RepairEntries(gpt, MASK_BOTH));
629 EXPECT(GPT_MODIFIED_ENTRIES2 == RepairEntries(gpt, MASK_PRIMARY));
630 EXPECT(GPT_MODIFIED_ENTRIES1 == RepairEntries(gpt, MASK_SECONDARY));
631 EXPECT(0 == RepairEntries(gpt, MASK_NONE));
632
633 /* The first byte is different. We expect secondary entries is marked as
634 * modified. */
635 BuildTestGptData(gpt);
636 gpt->primary_entries[0] ^= 0xff;
637 RefreshCrc32(gpt);
638 EXPECT(GPT_SUCCESS == GptInit(gpt));
639 EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified);
640 EXPECT(0 == Memcmp(gpt->primary_entries, gpt->secondary_entries,
641 TOTAL_ENTRIES_SIZE));
642
643 /* The last byte is different, but the primary entries CRC is bad.
644 * We expect primary entries is marked as modified. */
645 BuildTestGptData(gpt);
646 gpt->primary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0xff;
647 EXPECT(GPT_SUCCESS == GptInit(gpt));
648 EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified);
649 EXPECT(0 == Memcmp(gpt->primary_entries, gpt->secondary_entries,
650 TOTAL_ENTRIES_SIZE));
651
652 return TEST_OK;
653}
654
655/* Tests if GptInit() handles synonymous headers well.
656 * Note that two partition headers are NOT bit-swise identical.
657 * For exmaple, my_lba must be different (pointing to respective self).
658 * So in normal case, they are synonymous, not identical.
659 * If not synonymous, we trust the primary partition header, and
660 * overwrite secondary, then mark secondary as modified.*/
661int SynonymousHeaderTest() {
662 GptData *gpt;
663 GptHeader *primary_header, *secondary_header;
664
665 gpt = GetEmptyGptData();
666 primary_header = (GptHeader*)gpt->primary_header;
667 secondary_header = (GptHeader*)gpt->secondary_header;
668
669 /* Tests RepairHeader() for synonymous cases first. */
670 BuildTestGptData(gpt);
671 EXPECT(0 == RepairHeader(gpt, MASK_BOTH));
672 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_PRIMARY));
673 EXPECT(GPT_MODIFIED_HEADER1 == RepairHeader(gpt, MASK_SECONDARY));
674 EXPECT(0 == RepairHeader(gpt, MASK_NONE));
675 /* Then tests non-synonymous cases. */
676 BuildTestGptData(gpt);
677 ++secondary_header->first_usable_lba; /* chnage any bit */
678 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
679 EXPECT(primary_header->first_usable_lba ==
680 secondary_header->first_usable_lba);
681 /* ---- */
682 BuildTestGptData(gpt);
683 --secondary_header->last_usable_lba;
684 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
685 EXPECT(primary_header->last_usable_lba == secondary_header->last_usable_lba);
686 /* ---- */
687 BuildTestGptData(gpt);
688 ++secondary_header->number_of_entries;
689 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
690 EXPECT(primary_header->number_of_entries ==
691 secondary_header->number_of_entries);
692 /* ---- */
693 BuildTestGptData(gpt);
694 --secondary_header->size_of_entry;
695 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
696 EXPECT(primary_header->size_of_entry ==
697 secondary_header->size_of_entry);
698 /* ---- */
699 BuildTestGptData(gpt);
700 secondary_header->disk_uuid.u.raw[0] ^= 0x56;
701 EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH));
702 EXPECT(0 == Memcmp(&primary_header->disk_uuid,
703 &secondary_header->disk_uuid, sizeof(Guid)));
704
705 /* Consider header repairing in GptInit(). */
706 BuildTestGptData(gpt);
707 ++secondary_header->first_usable_lba;
708 RefreshCrc32(gpt);
709 EXPECT(GPT_SUCCESS == GptInit(gpt));
710 EXPECT(GPT_MODIFIED_HEADER2 == gpt->modified);
711 EXPECT(primary_header->first_usable_lba ==
712 secondary_header->first_usable_lba);
713
714 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700715}
716
717/* Tests if partition geometry is checked.
718 * All active (non-zero PartitionTypeGUID) partition entries should have:
719 * entry.StartingLBA >= header.FirstUsableLBA
720 * entry.EndingLBA <= header.LastUsableLBA
721 * entry.StartingLBA <= entry.EndingLBA
722 */
723int ValidEntryTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700724 GptData *gpt;
725 GptHeader *primary_header, *secondary_header;
726 GptEntry *primary_entries, *secondary_entries;
727
728 gpt = GetEmptyGptData();
729 primary_header = (GptHeader*)gpt->primary_header;
730 secondary_header = (GptHeader*)gpt->secondary_header;
731 primary_entries = (GptEntry*)gpt->primary_entries;
732 secondary_entries = (GptEntry*)gpt->secondary_entries;
733
734 /* error case: entry.StartingLBA < header.FirstUsableLBA */
735 BuildTestGptData(gpt);
736 primary_entries[0].starting_lba = primary_header->first_usable_lba - 1;
737 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
738 secondary_entries[1].starting_lba = secondary_header->first_usable_lba - 1;
739 EXPECT(MASK_NONE == CheckValidEntries(gpt));
740
741 /* error case: entry.EndingLBA > header.LastUsableLBA */
742 BuildTestGptData(gpt);
743 primary_entries[2].ending_lba = primary_header->last_usable_lba + 1;
744 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
745 secondary_entries[3].ending_lba = secondary_header->last_usable_lba + 1;
746 EXPECT(MASK_NONE == CheckValidEntries(gpt));
747
748 /* error case: entry.StartingLBA > entry.EndingLBA */
749 BuildTestGptData(gpt);
750 primary_entries[3].starting_lba = primary_entries[3].ending_lba + 1;
751 EXPECT(MASK_SECONDARY == CheckValidEntries(gpt));
752 secondary_entries[1].starting_lba = secondary_entries[1].ending_lba + 1;
753 EXPECT(MASK_NONE == CheckValidEntries(gpt));
754
755 /* case: non active entry should be ignored. */
756 BuildTestGptData(gpt);
757 Memset(&primary_entries[1].type, 0, sizeof(primary_entries[1].type));
758 primary_entries[1].starting_lba = primary_entries[1].ending_lba + 1;
759 EXPECT(MASK_BOTH == CheckValidEntries(gpt));
760 Memset(&secondary_entries[2].type, 0, sizeof(secondary_entries[2].type));
761 secondary_entries[2].starting_lba = secondary_entries[2].ending_lba + 1;
762 EXPECT(MASK_BOTH == CheckValidEntries(gpt));
763
764 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700765}
766
767/* Tests if overlapped partition tables can be detected. */
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700768int OverlappedPartitionTest() {
769 GptData *gpt;
770 struct {
771 int overlapped;
772 struct {
773 int active;
774 uint64_t starting_lba;
775 uint64_t ending_lba;
776 } entries[16]; /* enough for testing. */
777 } cases[] = {
778 {0, {{0, 100, 199}, {0, 0, 0}}},
779 {0, {{1, 100, 199}, {0, 0, 0}}},
780 {0, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}, {0, 0, 0}}},
781 {1, {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}, {0, 0, 0}}},
782 {1, {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}, {0, 0, 0}}},
783 {0, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}, {0, 0, 0}}},
784 {1, {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}, {0, 0, 0}}},
785 {1, {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}, {0, 0, 0}}},
786 {1, {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}, {0, 0, 0}}},
787 {1, {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}, {0, 0, 0}}},
788 {1, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399},
789 {0, 0, 0}}},
790 {0, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399},
791 {0, 0, 0}}},
792 {1, {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400},
793 {0, 0, 0}}},
794 {1, {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400},
795 {0, 0, 0}}},
796 {0, {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400},
797 {0, 0, 0}}},
798 {1, {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}, {0, 0, 0}}},
799 {0, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}, {0, 0, 0}}},
800 {0, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}, {0, 0, 0}}},
801 {1, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
802 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
803 {1, 207, 207}, {1, 208, 208}, {1, 199, 199}, {0, 0, 0}}},
804 {0, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202},
805 {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206},
806 {1, 207, 207}, {1, 208, 208}, {0, 199, 199}, {0, 0, 0}}},
807 };
808 Guid any_type = GPT_ENT_TYPE_CHROMEOS_KERNEL;
809 int i, j;
810 int test_mask;
811 GptEntry *entries[2];
812
813 gpt = GetEmptyGptData();
814 entries[PRIMARY] = (GptEntry*)gpt->primary_entries;
815 entries[SECONDARY] = (GptEntry*)gpt->secondary_entries;
816
817 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
818 for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) {
819 BuildTestGptData(gpt);
820 ZeroEntries(gpt);
821 for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
822 if (!cases[i].entries[j].starting_lba) break;
823 if (test_mask & MASK_PRIMARY) {
824 if (cases[i].entries[j].active)
825 Memcpy(&entries[PRIMARY][j].type, &any_type, sizeof(any_type));
826 entries[PRIMARY][j].starting_lba = cases[i].entries[j].starting_lba;
827 entries[PRIMARY][j].ending_lba = cases[i].entries[j].ending_lba;
828 }
829 if (test_mask & MASK_SECONDARY) {
830 if (cases[i].entries[j].active)
831 Memcpy(&entries[SECONDARY][j].type, &any_type, sizeof(any_type));
832 entries[SECONDARY][j].starting_lba = cases[i].entries[j].starting_lba;
833 entries[SECONDARY][j].ending_lba = cases[i].entries[j].ending_lba;
834 }
835 }
836 EXPECT((cases[i].overlapped * test_mask) ==
837 (OverlappedEntries(entries[PRIMARY], j) |
838 (OverlappedEntries(entries[SECONDARY], j) << SECONDARY))
839 );
840
841 EXPECT((MASK_BOTH ^ (cases[i].overlapped * test_mask)) ==
842 CheckOverlappedPartition(gpt));
843 }
844 }
845 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700846}
847
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700848/* Tests if GptInit() can survive in different corrupt header/entries
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700849 * combinations, like:
850 * primary GPT header - valid
851 * primary partition table - invalid
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700852 * secondary GPT header - invalid
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700853 * secondary partition table - valid
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700854 */
855int CorruptCombinationTest() {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700856 GptData *gpt;
857 GptHeader *primary_header, *secondary_header;
858 GptEntry *primary_entries, *secondary_entries;
859
860 gpt = GetEmptyGptData();
861 primary_header = (GptHeader*)gpt->primary_header;
862 secondary_header = (GptHeader*)gpt->secondary_header;
863 primary_entries = (GptEntry*)gpt->primary_entries;
864 secondary_entries = (GptEntry*)gpt->secondary_entries;
865
866 /* Make primary entries and secondary header invalid, we expect GptInit()
867 * can recover them (returns GPT_SUCCESS and MODIFIED flasgs). */
868 BuildTestGptData(gpt);
869 primary_entries[0].type.u.raw[0] ^= 0x33;
870 secondary_header->header_crc32 ^= 0x55;
871 EXPECT(GPT_SUCCESS == GptInit(gpt));
872 EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified);
873 EXPECT(0 == Memcmp(primary_entries, secondary_entries, TOTAL_ENTRIES_SIZE));
874 /* We expect the modified header/entries can pass GptInit(). */
875 EXPECT(GPT_SUCCESS == GptInit(gpt));
876 EXPECT(0 == gpt->modified);
877
878 /* Make primary header invalid (the entries is not damaged actually). */
879 BuildTestGptData(gpt);
880 primary_header->entries_crc32 ^= 0x73;
881 EXPECT(GPT_SUCCESS == GptInit(gpt));
882 /* After header is repaired, the entries are valid actually. */
883 EXPECT((GPT_MODIFIED_HEADER1) == gpt->modified);
884 /* We expect the modified header/entries can pass GptInit(). */
885 EXPECT(GPT_SUCCESS == GptInit(gpt));
886 EXPECT(0 == gpt->modified);
887
888 return TEST_OK;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700889}
890
891int main(int argc, char *argv[]) {
892 int i;
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700893 int error_count = 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700894 struct {
895 char *name;
896 test_func fp;
897 int retval;
898 } test_cases[] = {
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700899 { TEST_CASE(TestBuildTestGptData), },
900 { TEST_CASE(ParameterTests), },
Louis Yung-Chieh Lo37f6b552010-04-22 21:22:22 -0700901 { TEST_CASE(SignatureTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700902 { TEST_CASE(RevisionTest), },
903 { TEST_CASE(SizeTest), },
904 { TEST_CASE(ReservedFieldsTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700905 { TEST_CASE(MyLbaTest), },
906 { TEST_CASE(SizeOfPartitionEntryTest), },
907 { TEST_CASE(NumberOfPartitionEntriesTest), },
908 { TEST_CASE(PartitionEntryLbaTest), },
909 { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700910 { TEST_CASE(HeaderCrcTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700911 { TEST_CASE(EntriesCrcTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700912 { TEST_CASE(IdenticalEntriesTest), },
913 { TEST_CASE(SynonymousHeaderTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700914 { TEST_CASE(ValidEntryTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700915 { TEST_CASE(OverlappedPartitionTest), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700916 { TEST_CASE(CorruptCombinationTest), },
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700917 { TEST_CASE(TestQuickSortFixed), },
918 { TEST_CASE(TestQuickSortRandom), },
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700919 };
920
921 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
922 printf("Running %s() ...\n", test_cases[i].name);
923 test_cases[i].retval = test_cases[i].fp();
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700924 if (test_cases[i].retval) {
925 printf(COL_RED "[ERROR]\n\n" COL_STOP);
926 ++error_count;
927 } else {
928 printf(COL_GREEN "[PASS]\n\n" COL_STOP);
929 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700930 }
931
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700932 if (error_count) {
933 printf("\n--------------------------------------------------\n");
934 printf(COL_RED "The following %d test cases are failed:\n" COL_STOP,
935 error_count);
936 for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
937 if (test_cases[i].retval)
938 printf(" %s()\n", test_cases[i].name);
939 }
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700940 }
941
Louis Yung-Chieh Lo49fa8e52010-04-30 16:10:48 -0700942 return (error_count) ? 1 : 0;
Louis Yung-Chieh Lo4bbf21e2010-04-21 17:29:05 -0700943}