diff options
author | Randall Spangler <rspangler@chromium.org> | 2010-05-27 09:20:11 -0700 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2010-05-27 09:20:11 -0700 |
commit | 3003c1dd5048dde791e69850333539edc1c767eb (patch) | |
tree | 1186ae21f50e258ddd9b701b69fe1499de499f78 /tests/cgptlib_test.c | |
parent | 418ad3b620fe71fa26c1f04154497b4b450c3923 (diff) | |
download | vboot-3003c1dd5048dde791e69850333539edc1c767eb.tar.gz |
Moved cgptlib into vboot_firmware
Moved cgptlib tests into tests
Review URL: http://codereview.chromium.org/2303003
Diffstat (limited to 'tests/cgptlib_test.c')
-rw-r--r-- | tests/cgptlib_test.c | 1190 |
1 files changed, 1190 insertions, 0 deletions
diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c new file mode 100644 index 00000000..72fb5e6c --- /dev/null +++ b/tests/cgptlib_test.c @@ -0,0 +1,1190 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "cgptlib_test.h" +#include <string.h> +#include "cgptlib.h" +#include "cgptlib_internal.h" +#include "crc32.h" +#include "crc32_test.h" +#include "gpt.h" +#include "quick_sort_test.h" +#include "utility.h" + +/* Testing partition layout (sector_bytes=512) + * + * LBA Size Usage + * --------------------------------------------------------- + * 0 1 PMBR + * 1 1 primary partition header + * 2 32 primary partition entries (128B * 128) + * 34 100 kernel A (index: 0) + * 134 100 root A (index: 1) + * 234 100 root B (index: 2) + * 334 100 kernel B (index: 3) + * 434 32 secondary partition entries + * 466 1 secondary partition header + * 467 + */ +#define KERNEL_A 0 +#define ROOTFS_A 1 +#define ROOTFS_B 2 +#define KERNEL_B 3 + +#define DEFAULT_SECTOR_SIZE 512 +#define MAX_SECTOR_SIZE 4096 +#define DEFAULT_DRIVE_SECTORS 467 +#define PARTITION_ENTRIES_SIZE TOTAL_ENTRIES_SIZE /* 16384 */ + +/* Given a GptData pointer, first re-calculate entries CRC32 value, + * then reset header CRC32 value to 0, and calculate header CRC32 value. + * Both primary and secondary are updated. */ +void RefreshCrc32(GptData *gpt) { + GptHeader *header, *header2; + GptEntry *entries, *entries2; + + header = (GptHeader*)gpt->primary_header; + entries = (GptEntry*)gpt->primary_entries; + header2 = (GptHeader*)gpt->secondary_header; + entries2 = (GptEntry*)gpt->secondary_entries; + + header->entries_crc32 = + Crc32((uint8_t*)entries, + header->number_of_entries * header->size_of_entry); + header->header_crc32 = 0; + header->header_crc32 = Crc32((uint8_t*)header, header->size); + header2->entries_crc32 = + Crc32((uint8_t*)entries2, + header2->number_of_entries * header2->size_of_entry); + header2->header_crc32 = 0; + header2->header_crc32 = Crc32((uint8_t*)header2, header2->size); +} + +void ZeroHeaders(GptData* gpt) { + Memset(gpt->primary_header, 0, MAX_SECTOR_SIZE); + Memset(gpt->secondary_header, 0, MAX_SECTOR_SIZE); +} + +void ZeroEntries(GptData* gpt) { + Memset(gpt->primary_entries, 0, PARTITION_ENTRIES_SIZE); + Memset(gpt->secondary_entries, 0, PARTITION_ENTRIES_SIZE); +} + +void ZeroHeadersEntries(GptData* gpt) { + ZeroHeaders(gpt); + ZeroEntries(gpt); +} + +/* Returns a pointer to a static GptData instance (no free is required). + * All fields are zero except 4 pointers linking to header and entries. + * All content of headers and entries are zero. */ +GptData* GetEmptyGptData() { + static GptData gpt; + static uint8_t primary_header[MAX_SECTOR_SIZE]; + static uint8_t primary_entries[PARTITION_ENTRIES_SIZE]; + static uint8_t secondary_header[MAX_SECTOR_SIZE]; + static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE]; + + Memset(&gpt, 0, sizeof(gpt)); + gpt.primary_header = primary_header; + gpt.primary_entries = primary_entries; + gpt.secondary_header = secondary_header; + gpt.secondary_entries = secondary_entries; + ZeroHeadersEntries(&gpt); + + /* Initialize GptData internal states. */ + gpt.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND; + + return &gpt; +} + +/* Fills in most of fields and creates the layout described in the top of this + * file. Before calling this function, primary/secondary header/entries must + * have been pointed to the buffer, say, a gpt returned from GetEmptyGptData(). + * This function returns a good (valid) copy of GPT layout described in top of + * this file. */ +void BuildTestGptData(GptData *gpt) { + GptHeader *header, *header2; + GptEntry *entries, *entries2; + Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; + Guid chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS; + + gpt->sector_bytes = DEFAULT_SECTOR_SIZE; + gpt->drive_sectors = DEFAULT_DRIVE_SECTORS; + gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND; + gpt->valid_headers = MASK_BOTH; + gpt->valid_entries = MASK_BOTH; + + /* build primary */ + header = (GptHeader*)gpt->primary_header; + entries = (GptEntry*)gpt->primary_entries; + Memcpy(header->signature, GPT_HEADER_SIGNATURE, sizeof(GPT_HEADER_SIGNATURE)); + header->revision = GPT_HEADER_REVISION; + header->size = sizeof(GptHeader) - sizeof(header->padding); + header->reserved = 0; + header->my_lba = 1; + header->first_usable_lba = 34; + header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */ + header->entries_lba = 2; + header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */ + header->size_of_entry = 128; /* bytes */ + Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel)); + entries[0].starting_lba = 34; + entries[0].ending_lba = 133; + Memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs)); + entries[1].starting_lba = 134; + entries[1].ending_lba = 233; + Memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs)); + entries[2].starting_lba = 234; + entries[2].ending_lba = 333; + Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel)); + entries[3].starting_lba = 334; + entries[3].ending_lba = 433; + header->padding = 0; + + /* build secondary */ + header2 = (GptHeader*)gpt->secondary_header; + entries2 = (GptEntry*)gpt->secondary_entries; + Memcpy(header2, header, sizeof(GptHeader)); + Memcpy(entries2, entries, PARTITION_ENTRIES_SIZE); + header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */ + header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */ + + RefreshCrc32(gpt); +} + +/* Dumps memory starting from [vp] with [len] bytes. + * Prints [memo] if not NULL. Example output: + * + * 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f + * 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f + * ... + */ +static void Dump(void *vp, int len, char* memo) { + uint8_t *start = vp; + int i; + if (memo) printf("--[%s]----------\n", memo); + for (i = 0; i < len; ++i) { + printf("%02x%s", start[i], + (!(~i & 15) ? "\n" : + !(~i & 7) ? " - ": " ")); + } + if (i&15) printf("\n"); +} + +/* More formatted dump with GptData. */ +void DumpGptData(GptData *gpt) { + printf("DumpGptData(%p)...\n", gpt); + Dump(gpt, sizeof(gpt), NULL); + Dump(gpt->primary_header, sizeof(GptHeader), "Primary header"); + Dump(gpt->primary_entries, sizeof(GptEntry) * 8, "Primary entries"); + Dump(gpt->secondary_header, sizeof(GptHeader), "Secondary header"); + Dump(gpt->secondary_entries, sizeof(GptEntry) * 8, + "Secondary entries"); +} + +/* Tests if the default structure returned by BuildTestGptData() is good. */ +int TestBuildTestGptData() { + GptData *gpt; + gpt = GetEmptyGptData(); + BuildTestGptData(gpt); + EXPECT(GPT_SUCCESS == GptInit(gpt)); + return TEST_OK; +} + +/* Tests if wrong sector_bytes or drive_sectors is detected by GptInit(). + * Currently we only support 512 bytes per sector. + * In the future, we may support other sizes. + * A too small drive_sectors should be rejected by GptInit(). */ +int ParameterTests() { + GptData *gpt; + struct { + uint32_t sector_bytes; + uint64_t drive_sectors; + int expected_retval; + } cases[] = { + {512, DEFAULT_DRIVE_SECTORS, GPT_SUCCESS}, + {520, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE}, + {512, 0, GPT_ERROR_INVALID_SECTOR_NUMBER}, + {512, 66, GPT_ERROR_INVALID_SECTOR_NUMBER}, + {512, GPT_PMBR_SECTOR + GPT_HEADER_SECTOR * 2 + GPT_ENTRIES_SECTORS * 2, + GPT_SUCCESS}, + {4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE}, + }; + int i; + + gpt = GetEmptyGptData(); + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + BuildTestGptData(gpt); + gpt->sector_bytes = cases[i].sector_bytes; + gpt->drive_sectors = cases[i].drive_sectors; + EXPECT(cases[i].expected_retval == CheckParameters(gpt)); + } + + return TEST_OK; +} + +/* Tests if signature ("EFI PART") is checked. */ +int SignatureTest() { + int i; + GptData *gpt; + int test_mask; + GptHeader *headers[2]; + + gpt = GetEmptyGptData(); + headers[PRIMARY] = (GptHeader*)gpt->primary_header; + headers[SECONDARY] = (GptHeader*)gpt->secondary_header; + + for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) { + for (i = 0; i < 8; ++i) { + BuildTestGptData(gpt); + if (test_mask & MASK_PRIMARY) + headers[PRIMARY]->signature[i] ^= 0xff; + if (test_mask & MASK_SECONDARY) + headers[SECONDARY]->signature[i] ^= 0xff; + EXPECT((MASK_BOTH ^ test_mask) == CheckHeaderSignature(gpt)); + } + } + + return TEST_OK; +} + +/* The revision we currently support is GPT_HEADER_REVISION. + * If the revision in header is not that, we expect the header is invalid. */ +int RevisionTest() { + GptData *gpt; + struct { + uint32_t value_to_test; + int is_valid_value; + } cases[] = { + {0x01000000, 0}, + {0x00010000, 1}, /* GPT_HEADER_REVISION */ + {0x00000100, 0}, + {0x00000001, 0}, + {0x23010456, 0}, + }; + int i; + int test_mask; + GptHeader *headers[2]; + uint32_t valid_headers; + + gpt = GetEmptyGptData(); + headers[PRIMARY] = (GptHeader*)gpt->primary_header; + headers[SECONDARY] = (GptHeader*)gpt->secondary_header; + + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) { + BuildTestGptData(gpt); + if (test_mask & MASK_PRIMARY) + headers[PRIMARY]->revision = cases[i].value_to_test; + if (test_mask & MASK_SECONDARY) + headers[SECONDARY]->revision = cases[i].value_to_test; + valid_headers = CheckRevision(gpt); + if (cases[i].is_valid_value) + EXPECT(MASK_BOTH == valid_headers); + else + EXPECT((MASK_BOTH ^ test_mask) == valid_headers); + } + } + return TEST_OK; +} + +int SizeTest() { + GptData *gpt; + struct { + uint32_t value_to_test; + int is_valid_value; + } cases[] = { + {91, 0}, + {92, 1}, + {93, 1}, + {511, 1}, + {512, 1}, + {513, 0}, + }; + int i; + int test_mask; + GptHeader *headers[2]; + uint32_t valid_headers; + + gpt = GetEmptyGptData(); + headers[PRIMARY] = (GptHeader*)gpt->primary_header; + headers[SECONDARY] = (GptHeader*)gpt->secondary_header; + + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) { + BuildTestGptData(gpt); + if (test_mask & MASK_PRIMARY) + headers[PRIMARY]->size = cases[i].value_to_test; + if (test_mask & MASK_SECONDARY) + headers[SECONDARY]->size = cases[i].value_to_test; + valid_headers = CheckSize(gpt); + if (cases[i].is_valid_value) + EXPECT(MASK_BOTH == valid_headers); + else + EXPECT((MASK_BOTH ^ test_mask) == valid_headers); + } + } + return TEST_OK; +} + +/* Tests if reserved fields are checked. + * We'll try non-zero values to test. */ +int ReservedFieldsTest() { + GptData *gpt; + GptHeader *primary_header, *secondary_header; + + gpt = GetEmptyGptData(); + primary_header = (GptHeader*)gpt->primary_header; + secondary_header = (GptHeader*)gpt->secondary_header; + + /* expect secondary is still valid. */ + BuildTestGptData(gpt); + primary_header->reserved ^= 0x12345678; /* whatever random */ + EXPECT(MASK_SECONDARY == CheckReservedFields(gpt)); + + /* expect secondary is still valid. */ + BuildTestGptData(gpt); + primary_header->padding ^= 0x12345678; /* whatever random */ + EXPECT(MASK_SECONDARY == CheckReservedFields(gpt)); + + /* expect primary is still valid. */ + BuildTestGptData(gpt); + secondary_header->reserved ^= 0x12345678; /* whatever random */ + EXPECT(MASK_PRIMARY == CheckReservedFields(gpt)); + + /* expect primary is still valid. */ + BuildTestGptData(gpt); + secondary_header->padding ^= 0x12345678; /* whatever random */ + EXPECT(MASK_PRIMARY == CheckReservedFields(gpt)); + + return TEST_OK; +} + +/* Tests if myLBA field is checked (1 for primary, last for secondary). */ +int MyLbaTest() { + GptData *gpt; + int test_mask; + GptHeader *headers[2]; + uint32_t valid_headers; + + gpt = GetEmptyGptData(); + headers[PRIMARY] = (GptHeader*)gpt->primary_header; + headers[SECONDARY] = (GptHeader*)gpt->secondary_header; + + for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) { + BuildTestGptData(gpt); + if (test_mask & MASK_PRIMARY) + ++headers[PRIMARY]->my_lba; + if (test_mask & MASK_SECONDARY) + --headers[SECONDARY]->my_lba; + valid_headers = CheckMyLba(gpt); + EXPECT((MASK_BOTH ^ test_mask) == valid_headers); + } + return TEST_OK; +} + +/* Tests if SizeOfPartitionEntry is checked. SizeOfPartitionEntry must be + * between 128 and 512, and a multiple of 8. */ +int SizeOfPartitionEntryTest() { + GptData *gpt; + struct { + uint32_t value_to_test; + int is_valid_value; + } cases[] = { + {127, 0}, + {128, 1}, + {129, 0}, + {130, 0}, + {131, 0}, + {132, 0}, + {133, 0}, + {134, 0}, + {135, 0}, + {136, 1}, + {144, 1}, + {160, 1}, + {192, 1}, + {256, 1}, + {384, 1}, + {504, 1}, + {512, 1}, + {513, 0}, + {520, 0}, + }; + int i; + int test_mask; + GptHeader *headers[2]; + uint32_t valid_headers; + + gpt = GetEmptyGptData(); + headers[PRIMARY] = (GptHeader*)gpt->primary_header; + headers[SECONDARY] = (GptHeader*)gpt->secondary_header; + + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) { + BuildTestGptData(gpt); + if (test_mask & MASK_PRIMARY) { + headers[PRIMARY]->size_of_entry = cases[i].value_to_test; + headers[PRIMARY]->number_of_entries = + TOTAL_ENTRIES_SIZE / cases[i].value_to_test; + } + if (test_mask & MASK_SECONDARY) { + headers[SECONDARY]->size_of_entry = cases[i].value_to_test; + headers[SECONDARY]->number_of_entries = + TOTAL_ENTRIES_SIZE / cases[i].value_to_test; + } + valid_headers = CheckSizeOfPartitionEntry(gpt); + if (cases[i].is_valid_value) + EXPECT(MASK_BOTH == valid_headers); + else + EXPECT((MASK_BOTH ^ test_mask) == valid_headers); + } + } + return TEST_OK; +} + +/* Tests if NumberOfPartitionEntries is checes. NumberOfPartitionEntries must + * be between 32 and 512, and SizeOfPartitionEntry * NumberOfPartitionEntries + * must be 16384. */ +int NumberOfPartitionEntriesTest() { + GptData *gpt; + struct { + uint32_t size_of_entry; + uint32_t number_of_entries; + int is_valid_value; + } cases[] = { + {111, 147, 0}, + {111, 149, 0}, + {128, 32, 0}, + {128, 64, 0}, + {128, 127, 0}, + {128, 128, 1}, + {128, 129, 0}, + {128, 256, 0}, + {256, 32, 0}, + {256, 64, 1}, + {256, 128, 0}, + {256, 256, 0}, + {512, 32, 1}, + {512, 64, 0}, + {512, 128, 0}, + {512, 256, 0}, + {1024, 128, 0}, + }; + int i; + int test_mask; + GptHeader *headers[2]; + uint32_t valid_headers; + + gpt = GetEmptyGptData(); + headers[PRIMARY] = (GptHeader*)gpt->primary_header; + headers[SECONDARY] = (GptHeader*)gpt->secondary_header; + + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) { + BuildTestGptData(gpt); + if (test_mask & MASK_PRIMARY) { + headers[PRIMARY]->size_of_entry = cases[i].size_of_entry; + headers[PRIMARY]->number_of_entries = cases[i].number_of_entries; + } + if (test_mask & MASK_SECONDARY) { + headers[SECONDARY]->size_of_entry = cases[i].size_of_entry; + headers[SECONDARY]->number_of_entries = cases[i].number_of_entries; + } + valid_headers = CheckNumberOfEntries(gpt); + if (cases[i].is_valid_value) + EXPECT(MASK_BOTH == valid_headers); + else + EXPECT((MASK_BOTH ^ test_mask) == valid_headers); + } + } + return TEST_OK; +} + +/* Tests if PartitionEntryLBA in primary/secondary headers is checked. */ +int PartitionEntryLbaTest() { + GptData *gpt; + int test_mask; + GptHeader *headers[2]; + uint32_t valid_headers; + + gpt = GetEmptyGptData(); + headers[PRIMARY] = (GptHeader*)gpt->primary_header; + headers[SECONDARY] = (GptHeader*)gpt->secondary_header; + + for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) { + BuildTestGptData(gpt); + if (test_mask & MASK_PRIMARY) + headers[PRIMARY]->entries_lba = 0; + if (test_mask & MASK_SECONDARY) + headers[SECONDARY]->entries_lba = DEFAULT_DRIVE_SECTORS - 31 - 1; + valid_headers = CheckEntriesLba(gpt); + EXPECT((MASK_BOTH ^ test_mask) == valid_headers); + } + return TEST_OK; +} + +/* Tests if FirstUsableLBA and LastUsableLBA are checked. + * FirstUsableLBA must be after the end of the primary GPT table array. + * LastUsableLBA must be before the start of the secondary GPT table array. + * FirstUsableLBA <= LastUsableLBA. */ +int FirstUsableLbaAndLastUsableLbaTest() { + GptData *gpt; + GptHeader *primary_header, *secondary_header; + uint32_t valid_headers; + int i; + struct { + uint64_t primary_entries_lba; + uint64_t primary_first_usable_lba; + uint64_t primary_last_usable_lba; + uint64_t secondary_first_usable_lba; + uint64_t secondary_last_usable_lba; + uint64_t secondary_entries_lba; + int expected_masks; + } cases[] = { + {2, 34, 433, 34, 433, 434, MASK_BOTH}, + {2, 34, 432, 34, 430, 434, MASK_BOTH}, + {2, 33, 433, 33, 433, 434, MASK_NONE}, + {3, 34, 433, 35, 433, 434, MASK_SECONDARY}, + {3, 35, 433, 33, 433, 434, MASK_PRIMARY}, + {2, 34, 434, 34, 433, 434, MASK_SECONDARY}, + {2, 34, 433, 34, 434, 434, MASK_PRIMARY}, + {2, 35, 433, 35, 433, 434, MASK_BOTH}, + {2, 433, 433, 433, 433, 434, MASK_BOTH}, + {2, 434, 433, 434, 434, 434, MASK_NONE}, + {2, 433, 34, 34, 433, 434, MASK_SECONDARY}, + {2, 34, 433, 433, 34, 434, MASK_PRIMARY}, + }; + + gpt = GetEmptyGptData(); + primary_header = (GptHeader*)gpt->primary_header; + secondary_header = (GptHeader*)gpt->secondary_header; + + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + BuildTestGptData(gpt); + primary_header->entries_lba = cases[i].primary_entries_lba; + primary_header->first_usable_lba = cases[i].primary_first_usable_lba; + primary_header->last_usable_lba = cases[i].primary_last_usable_lba; + secondary_header->entries_lba = cases[i].secondary_entries_lba; + secondary_header->first_usable_lba = cases[i].secondary_first_usable_lba; + secondary_header->last_usable_lba = cases[i].secondary_last_usable_lba; + valid_headers = CheckValidUsableLbas(gpt); + EXPECT(cases[i].expected_masks == valid_headers); + } + + return TEST_OK; +} + +/* Tests if header CRC in two copies are calculated. */ +int HeaderCrcTest() { + GptData *gpt; + GptHeader *primary_header, *secondary_header; + + gpt = GetEmptyGptData(); + primary_header = (GptHeader*)gpt->primary_header; + secondary_header = (GptHeader*)gpt->secondary_header; + + /* Modify the first byte of primary header, and expect the CRC is wrong. */ + BuildTestGptData(gpt); + gpt->primary_header[0] ^= 0xa5; /* just XOR a non-zero value */ + EXPECT(MASK_SECONDARY == CheckHeaderCrc(gpt)); + + /* Modify the last byte of secondary header, and expect the CRC is wrong. */ + BuildTestGptData(gpt); + gpt->secondary_header[secondary_header->size-1] ^= 0x5a; + EXPECT(MASK_PRIMARY == CheckHeaderCrc(gpt)); + + /* Modify out of CRC range, expect CRC is still right. */ + BuildTestGptData(gpt); + gpt->primary_header[primary_header->size] ^= 0x87; + EXPECT(MASK_BOTH == CheckHeaderCrc(gpt)); + + /* Very long header (actually invalid header). Expect will be ignored. */ + primary_header->size = 0x12345678; + secondary_header->size = 0x87654321; + gpt->valid_headers = MASK_NONE; + EXPECT(MASK_NONE == CheckHeaderCrc(gpt)); + + return TEST_OK; +} + +/* Tests if PartitionEntryArrayCRC32 is checked. + * PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry * + * NumberOfPartitionEntries bytes. + */ +int EntriesCrcTest() { + GptData *gpt; + + gpt = GetEmptyGptData(); + + /* Modify the first byte of primary entries, and expect the CRC is wrong. */ + BuildTestGptData(gpt); + gpt->primary_entries[0] ^= 0xa5; /* just XOR a non-zero value */ + EXPECT(MASK_SECONDARY == CheckEntriesCrc(gpt)); + + /* Modify the last byte of secondary entries, and expect the CRC is wrong. */ + BuildTestGptData(gpt); + gpt->secondary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0x5a; + EXPECT(MASK_PRIMARY == CheckEntriesCrc(gpt)); + + return TEST_OK; +} + +/* Tests if GptInit() handles non-identical partition entries well. + * Two copies of partition table entries must be identical. If not, we trust the + * primary table entries, and mark secondary as modified. */ +int IdenticalEntriesTest() { + GptData *gpt; + + gpt = GetEmptyGptData(); + + /* Tests RepairEntries() first. */ + BuildTestGptData(gpt); + EXPECT(0 == RepairEntries(gpt, MASK_BOTH)); + gpt->secondary_entries[0] ^= 0xa5; /* XOR any number */ + EXPECT(GPT_MODIFIED_ENTRIES2 == RepairEntries(gpt, MASK_BOTH)); + EXPECT(GPT_MODIFIED_ENTRIES2 == RepairEntries(gpt, MASK_PRIMARY)); + EXPECT(GPT_MODIFIED_ENTRIES1 == RepairEntries(gpt, MASK_SECONDARY)); + EXPECT(0 == RepairEntries(gpt, MASK_NONE)); + + /* The first byte is different. We expect secondary entries is marked as + * modified. */ + BuildTestGptData(gpt); + gpt->primary_entries[0] ^= 0xff; + RefreshCrc32(gpt); + EXPECT(GPT_SUCCESS == GptInit(gpt)); + EXPECT(GPT_MODIFIED_ENTRIES2 == gpt->modified); + EXPECT(0 == Memcmp(gpt->primary_entries, gpt->secondary_entries, + TOTAL_ENTRIES_SIZE)); + + /* The last byte is different, but the primary entries CRC is bad. + * We expect primary entries is marked as modified. */ + BuildTestGptData(gpt); + gpt->primary_entries[TOTAL_ENTRIES_SIZE-1] ^= 0xff; + EXPECT(GPT_SUCCESS == GptInit(gpt)); + EXPECT(GPT_MODIFIED_ENTRIES1 == gpt->modified); + EXPECT(0 == Memcmp(gpt->primary_entries, gpt->secondary_entries, + TOTAL_ENTRIES_SIZE)); + + return TEST_OK; +} + +/* Tests if GptInit() handles synonymous headers well. + * Note that two partition headers are NOT bit-swise identical. + * For exmaple, my_lba must be different (pointing to respective self). + * So in normal case, they are synonymous, not identical. + * If not synonymous, we trust the primary partition header, and + * overwrite secondary, then mark secondary as modified.*/ +int SynonymousHeaderTest() { + GptData *gpt; + GptHeader *primary_header, *secondary_header; + + gpt = GetEmptyGptData(); + primary_header = (GptHeader*)gpt->primary_header; + secondary_header = (GptHeader*)gpt->secondary_header; + + /* Tests RepairHeader() for synonymous cases first. */ + BuildTestGptData(gpt); + EXPECT(0 == RepairHeader(gpt, MASK_BOTH)); + EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_PRIMARY)); + EXPECT(GPT_MODIFIED_HEADER1 == RepairHeader(gpt, MASK_SECONDARY)); + EXPECT(0 == RepairHeader(gpt, MASK_NONE)); + /* Then tests non-synonymous cases. */ + BuildTestGptData(gpt); + ++secondary_header->first_usable_lba; /* chnage any bit */ + EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH)); + EXPECT(primary_header->first_usable_lba == + secondary_header->first_usable_lba); + /* ---- */ + BuildTestGptData(gpt); + --secondary_header->last_usable_lba; + EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH)); + EXPECT(primary_header->last_usable_lba == secondary_header->last_usable_lba); + /* ---- */ + BuildTestGptData(gpt); + ++secondary_header->number_of_entries; + EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH)); + EXPECT(primary_header->number_of_entries == + secondary_header->number_of_entries); + /* ---- */ + BuildTestGptData(gpt); + --secondary_header->size_of_entry; + EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH)); + EXPECT(primary_header->size_of_entry == + secondary_header->size_of_entry); + /* ---- */ + BuildTestGptData(gpt); + secondary_header->disk_uuid.u.raw[0] ^= 0x56; + EXPECT(GPT_MODIFIED_HEADER2 == RepairHeader(gpt, MASK_BOTH)); + EXPECT(0 == Memcmp(&primary_header->disk_uuid, + &secondary_header->disk_uuid, sizeof(Guid))); + + /* Consider header repairing in GptInit(). */ + BuildTestGptData(gpt); + ++secondary_header->first_usable_lba; + RefreshCrc32(gpt); + EXPECT(GPT_SUCCESS == GptInit(gpt)); + EXPECT((gpt->modified & (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_HEADER2)) == + GPT_MODIFIED_HEADER2); + EXPECT(primary_header->first_usable_lba == + secondary_header->first_usable_lba); + + return TEST_OK; +} + +/* Tests if partition geometry is checked. + * All active (non-zero PartitionTypeGUID) partition entries should have: + * entry.StartingLBA >= header.FirstUsableLBA + * entry.EndingLBA <= header.LastUsableLBA + * entry.StartingLBA <= entry.EndingLBA + */ +int ValidEntryTest() { + GptData *gpt; + GptHeader *primary_header, *secondary_header; + GptEntry *primary_entries, *secondary_entries; + + gpt = GetEmptyGptData(); + primary_header = (GptHeader*)gpt->primary_header; + secondary_header = (GptHeader*)gpt->secondary_header; + primary_entries = (GptEntry*)gpt->primary_entries; + secondary_entries = (GptEntry*)gpt->secondary_entries; + + /* error case: entry.StartingLBA < header.FirstUsableLBA */ + BuildTestGptData(gpt); + primary_entries[0].starting_lba = primary_header->first_usable_lba - 1; + EXPECT(MASK_SECONDARY == CheckValidEntries(gpt)); + secondary_entries[1].starting_lba = secondary_header->first_usable_lba - 1; + EXPECT(MASK_NONE == CheckValidEntries(gpt)); + + /* error case: entry.EndingLBA > header.LastUsableLBA */ + BuildTestGptData(gpt); + primary_entries[2].ending_lba = primary_header->last_usable_lba + 1; + EXPECT(MASK_SECONDARY == CheckValidEntries(gpt)); + secondary_entries[3].ending_lba = secondary_header->last_usable_lba + 1; + EXPECT(MASK_NONE == CheckValidEntries(gpt)); + + /* error case: entry.StartingLBA > entry.EndingLBA */ + BuildTestGptData(gpt); + primary_entries[3].starting_lba = primary_entries[3].ending_lba + 1; + EXPECT(MASK_SECONDARY == CheckValidEntries(gpt)); + secondary_entries[1].starting_lba = secondary_entries[1].ending_lba + 1; + EXPECT(MASK_NONE == CheckValidEntries(gpt)); + + /* case: non active entry should be ignored. */ + BuildTestGptData(gpt); + Memset(&primary_entries[1].type, 0, sizeof(primary_entries[1].type)); + primary_entries[1].starting_lba = primary_entries[1].ending_lba + 1; + EXPECT(MASK_BOTH == CheckValidEntries(gpt)); + Memset(&secondary_entries[2].type, 0, sizeof(secondary_entries[2].type)); + secondary_entries[2].starting_lba = secondary_entries[2].ending_lba + 1; + EXPECT(MASK_BOTH == CheckValidEntries(gpt)); + + return TEST_OK; +} + +/* Tests if overlapped partition tables can be detected. */ +int OverlappedPartitionTest() { + GptData *gpt; + struct { + int overlapped; + struct { + int active; + uint64_t starting_lba; + uint64_t ending_lba; + } entries[16]; /* enough for testing. */ + } cases[] = { + {0, {{0, 100, 199}, {0, 0, 0}}}, + {0, {{1, 100, 199}, {0, 0, 0}}}, + {0, {{1, 100, 150}, {1, 200, 250}, {1, 300, 350}, {0, 0, 0}}}, + {1, {{1, 200, 299}, {1, 100, 199}, {1, 100, 100}, {0, 0, 0}}}, + {1, {{1, 200, 299}, {1, 100, 199}, {1, 299, 299}, {0, 0, 0}}}, + {0, {{1, 300, 399}, {1, 200, 299}, {1, 100, 199}, {0, 0, 0}}}, + {1, {{1, 100, 199}, {1, 199, 299}, {1, 299, 399}, {0, 0, 0}}}, + {1, {{1, 100, 199}, {1, 200, 299}, {1, 75, 399}, {0, 0, 0}}}, + {1, {{1, 100, 199}, {1, 75, 250}, {1, 200, 299}, {0, 0, 0}}}, + {1, {{1, 75, 150}, {1, 100, 199}, {1, 200, 299}, {0, 0, 0}}}, + {1, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {1, 100, 399}, + {0, 0, 0}}}, + {0, {{1, 200, 299}, {1, 100, 199}, {1, 300, 399}, {0, 100, 399}, + {0, 0, 0}}}, + {1, {{1, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}, + {0, 0, 0}}}, + {1, {{0, 200, 300}, {1, 100, 200}, {1, 100, 400}, {1, 300, 400}, + {0, 0, 0}}}, + {0, {{1, 200, 300}, {1, 100, 199}, {0, 100, 400}, {0, 300, 400}, + {0, 0, 0}}}, + {1, {{1, 200, 299}, {1, 100, 199}, {1, 199, 199}, {0, 0, 0}}}, + {0, {{1, 200, 299}, {0, 100, 199}, {1, 199, 199}, {0, 0, 0}}}, + {0, {{1, 200, 299}, {1, 100, 199}, {0, 199, 199}, {0, 0, 0}}}, + {1, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202}, + {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206}, + {1, 207, 207}, {1, 208, 208}, {1, 199, 199}, {0, 0, 0}}}, + {0, {{1, 199, 199}, {1, 200, 200}, {1, 201, 201}, {1, 202, 202}, + {1, 203, 203}, {1, 204, 204}, {1, 205, 205}, {1, 206, 206}, + {1, 207, 207}, {1, 208, 208}, {0, 199, 199}, {0, 0, 0}}}, + }; + Guid any_type = GPT_ENT_TYPE_CHROMEOS_KERNEL; + int i, j; + int test_mask; + GptEntry *entries[2]; + + gpt = GetEmptyGptData(); + entries[PRIMARY] = (GptEntry*)gpt->primary_entries; + entries[SECONDARY] = (GptEntry*)gpt->secondary_entries; + + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + for (test_mask = MASK_PRIMARY; test_mask <= MASK_BOTH; ++test_mask) { + BuildTestGptData(gpt); + ZeroEntries(gpt); + for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) { + if (!cases[i].entries[j].starting_lba) break; + if (test_mask & MASK_PRIMARY) { + if (cases[i].entries[j].active) + Memcpy(&entries[PRIMARY][j].type, &any_type, sizeof(any_type)); + entries[PRIMARY][j].starting_lba = cases[i].entries[j].starting_lba; + entries[PRIMARY][j].ending_lba = cases[i].entries[j].ending_lba; + } + if (test_mask & MASK_SECONDARY) { + if (cases[i].entries[j].active) + Memcpy(&entries[SECONDARY][j].type, &any_type, sizeof(any_type)); + entries[SECONDARY][j].starting_lba = cases[i].entries[j].starting_lba; + entries[SECONDARY][j].ending_lba = cases[i].entries[j].ending_lba; + } + } + EXPECT((cases[i].overlapped * test_mask) == + (OverlappedEntries(entries[PRIMARY], j) | + (OverlappedEntries(entries[SECONDARY], j) << SECONDARY)) + ); + + EXPECT((MASK_BOTH ^ (cases[i].overlapped * test_mask)) == + CheckOverlappedPartition(gpt)); + } + } + return TEST_OK; +} + +/* Tests if GptInit() can survive in different corrupt header/entries + * combinations, like: + * primary GPT header - valid + * primary partition table - invalid + * secondary GPT header - invalid + * secondary partition table - valid + */ +int CorruptCombinationTest() { + GptData *gpt; + GptHeader *primary_header, *secondary_header; + GptEntry *primary_entries, *secondary_entries; + + gpt = GetEmptyGptData(); + primary_header = (GptHeader*)gpt->primary_header; + secondary_header = (GptHeader*)gpt->secondary_header; + primary_entries = (GptEntry*)gpt->primary_entries; + secondary_entries = (GptEntry*)gpt->secondary_entries; + + /* Make primary entries and secondary header invalid, we expect GptInit() + * can recover them (returns GPT_SUCCESS and MODIFIED flasgs). */ + BuildTestGptData(gpt); + primary_entries[0].type.u.raw[0] ^= 0x33; + secondary_header->header_crc32 ^= 0x55; + EXPECT(GPT_SUCCESS == GptInit(gpt)); + EXPECT((GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES1) == gpt->modified); + EXPECT(0 == Memcmp(primary_entries, secondary_entries, TOTAL_ENTRIES_SIZE)); + /* We expect the modified header/entries can pass GptInit(). */ + EXPECT(GPT_SUCCESS == GptInit(gpt)); + EXPECT(0 == gpt->modified); + + /* Make primary header invalid (the entries is not damaged actually). */ + BuildTestGptData(gpt); + primary_header->entries_crc32 ^= 0x73; + EXPECT(GPT_SUCCESS == GptInit(gpt)); + /* After header is repaired, the entries are valid actually. */ + EXPECT((gpt->modified & (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_HEADER2)) == + GPT_MODIFIED_HEADER1); + /* We expect the modified header/entries can pass GptInit(). */ + EXPECT(GPT_SUCCESS == GptInit(gpt)); + EXPECT(0 == gpt->modified); + + return TEST_OK; +} + +/* Invalidate all kernel entries and expect GptNextKernelEntry() cannot find + * any usable kernel entry. + */ +int NoValidKernelEntryTest() { + GptData *gpt; + GptEntry *entries, *entries2; + + gpt = GetEmptyGptData(); + entries = (GptEntry*)gpt->primary_entries; + entries2 = (GptEntry*)gpt->secondary_entries; + + BuildTestGptData(gpt); + entries[KERNEL_A].attributes |= CGPT_ATTRIBUTE_BAD_MASK; + Memset(&entries[KERNEL_B].type, 0, sizeof(Guid)); + RefreshCrc32(gpt); + + EXPECT(GPT_ERROR_NO_VALID_KERNEL == GptNextKernelEntry(gpt, NULL, NULL)); + + return TEST_OK; +} + +/* This is the combination test. Both kernel A and B could be either inactive + * or invalid. We expect GptNextKetnelEntry() returns good kernel or + * GPT_ERROR_NO_VALID_KERNEL if no kernel is available. */ +enum FAILURE_MASK { + MASK_INACTIVE = 1, + MASK_BAD_ENTRY = 2, + MASK_FAILURE_BOTH = 3, +}; +void BreakAnEntry(GptEntry *entry, enum FAILURE_MASK failure) { + if (failure & MASK_INACTIVE) + Memset(&entry->type, 0, sizeof(Guid)); + if (failure & MASK_BAD_ENTRY) + entry->attributes |= CGPT_ATTRIBUTE_BAD_MASK; +} + +int CombinationalNextKernelEntryTest() { + GptData *gpt; + enum { + MASK_KERNEL_A = 1, + MASK_KERNEL_B = 2, + MASK_KERNEL_BOTH = 3, + } kernel; + enum FAILURE_MASK failure; + uint64_t start_sector, size; + int retval; + + for (kernel = MASK_KERNEL_A; kernel <= MASK_KERNEL_BOTH; ++kernel) { + for (failure = MASK_INACTIVE; failure < MASK_FAILURE_BOTH; ++failure) { + gpt = GetEmptyGptData(); + BuildTestGptData(gpt); + + if (kernel & MASK_KERNEL_A) + BreakAnEntry(GetEntry(gpt, PRIMARY, KERNEL_A), failure); + if (kernel & MASK_KERNEL_B) + BreakAnEntry(GetEntry(gpt, PRIMARY, KERNEL_B), failure); + + retval = GptNextKernelEntry(gpt, &start_sector, &size); + + if (kernel == MASK_KERNEL_A) { + EXPECT(retval == GPT_SUCCESS); + EXPECT(start_sector == 334); + } else if (kernel == MASK_KERNEL_B) { + EXPECT(retval == GPT_SUCCESS); + EXPECT(start_sector == 34); + } else { /* MASK_KERNEL_BOTH */ + EXPECT(retval == GPT_ERROR_NO_VALID_KERNEL); + } + } + } + return TEST_OK; +} + +/* Increase tries value from zero, expect it won't explode/overflow after + * CGPT_ATTRIBUTE_TRIES_MASK. + */ +/* Tries would not count up after CGPT_ATTRIBUTE_MAX_TRIES. */ +#define EXPECTED_TRIES(tries) \ + ((tries >= CGPT_ATTRIBUTE_MAX_TRIES) ? CGPT_ATTRIBUTE_MAX_TRIES \ + : tries) +int IncreaseTriesTest() { + GptData *gpt; + int kernel_index[] = { + KERNEL_B, + KERNEL_A, + }; + int i, tries, j; + + gpt = GetEmptyGptData(); + for (i = 0; i < ARRAY_SIZE(kernel_index); ++i) { + GptEntry *entries[2] = { + (GptEntry*)gpt->primary_entries, + (GptEntry*)gpt->secondary_entries, + }; + int current; + + BuildTestGptData(gpt); + current = gpt->current_kernel = kernel_index[i]; + + for (tries = 0; tries < 2 * CGPT_ATTRIBUTE_MAX_TRIES; ++tries) { + for (j = 0; j < ARRAY_SIZE(entries); ++j) { + EXPECT(EXPECTED_TRIES(tries) == + ((entries[j][current].attributes & CGPT_ATTRIBUTE_TRIES_MASK) >> + CGPT_ATTRIBUTE_TRIES_OFFSET)); + } + + EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY)); + /* The expected tries value will be checked in next iteration. */ + + if (tries < CGPT_ATTRIBUTE_MAX_TRIES) + EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | + GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified); + gpt->modified = 0; /* reset before next test */ + EXPECT(0 == + Memcmp(entries[PRIMARY], entries[SECONDARY], TOTAL_ENTRIES_SIZE)); + } + } + return TEST_OK; +} + +/* Mark a kernel as bad. Expect: + * 1. the both bad bits of kernel A in primary and secondary entries are set. + * 2. headers and entries are marked as modified. + * 3. primary and secondary entries are identical. + */ +int MarkBadKernelEntryTest() { + GptData *gpt; + GptEntry *entries, *entries2; + + gpt = GetEmptyGptData(); + entries = (GptEntry*)gpt->primary_entries; + entries2 = (GptEntry*)gpt->secondary_entries; + + BuildTestGptData(gpt); + gpt->current_kernel = KERNEL_A; + EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD)); + EXPECT((GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | + GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2) == gpt->modified); + EXPECT(entries[KERNEL_A].attributes & CGPT_ATTRIBUTE_BAD_MASK); + EXPECT(entries2[KERNEL_A].attributes & CGPT_ATTRIBUTE_BAD_MASK); + EXPECT(0 == Memcmp(entries, entries2, TOTAL_ENTRIES_SIZE)); + + return TEST_OK; +} + +/* Given an invalid kernel type, and expect GptUpdateKernelEntry() returns + * GPT_ERROR_INVALID_UPDATE_TYPE. */ +int UpdateInvalidKernelTypeTest() { + GptData *gpt; + + gpt = GetEmptyGptData(); + BuildTestGptData(gpt); + gpt->current_kernel = 0; /* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */ + EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE == + GptUpdateKernelEntry(gpt, 99)); /* any invalid update_type value */ + + return TEST_OK; +} + +/* A normal boot case: + * GptInit() + * GptNextKernelEntry() + * GptUpdateKernelEntry() + */ +int NormalBootCase() { + GptData *gpt; + GptEntry *entries; + uint64_t start_sector, size; + + gpt = GetEmptyGptData(); + entries = (GptEntry*)gpt->primary_entries; + BuildTestGptData(gpt); + + EXPECT(GPT_SUCCESS == GptInit(gpt)); + EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start_sector, &size)); + EXPECT(start_sector == 34); /* Kernel A, see top of this file. */ + EXPECT(size == 100); + + EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY)); + EXPECT(((entries[KERNEL_A].attributes & CGPT_ATTRIBUTE_TRIES_MASK) >> + CGPT_ATTRIBUTE_TRIES_OFFSET) == 1); + + return TEST_OK; +} + +/* Higher priority kernel should boot first. + * KERNEL_A is low priority + * KERNEL_B is high priority. + * We expect KERNEL_B is selected in first run, and then KERNEL_A. + * We also expect the GptNextKernelEntry() wraps back to KERNEL_B if it's called + * after twice. + */ +int HigherPriorityTest() { + GptData *gpt; + GptEntry *entries; + + gpt = GetEmptyGptData(); + entries = (GptEntry*)gpt->primary_entries; + BuildTestGptData(gpt); + + SetPriority(gpt, PRIMARY, KERNEL_A, 0); + SetPriority(gpt, PRIMARY, KERNEL_B, 1); + RefreshCrc32(gpt); + + EXPECT(GPT_SUCCESS == GptInit(gpt)); + EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL)); + EXPECT(KERNEL_B == gpt->current_kernel); + + EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL)); + EXPECT(KERNEL_A == gpt->current_kernel); + + EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, NULL, NULL)); + EXPECT(KERNEL_B == gpt->current_kernel); + + return TEST_OK; +} + +int main(int argc, char *argv[]) { + int i; + int error_count = 0; + struct { + char *name; + test_func fp; + int retval; + } test_cases[] = { + { TEST_CASE(TestBuildTestGptData), }, + { TEST_CASE(ParameterTests), }, + { TEST_CASE(SignatureTest), }, + { TEST_CASE(RevisionTest), }, + { TEST_CASE(SizeTest), }, + { TEST_CASE(ReservedFieldsTest), }, + { TEST_CASE(MyLbaTest), }, + { TEST_CASE(SizeOfPartitionEntryTest), }, + { TEST_CASE(NumberOfPartitionEntriesTest), }, + { TEST_CASE(PartitionEntryLbaTest), }, + { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), }, + { TEST_CASE(HeaderCrcTest), }, + { TEST_CASE(EntriesCrcTest), }, + { TEST_CASE(IdenticalEntriesTest), }, + { TEST_CASE(SynonymousHeaderTest), }, + { TEST_CASE(ValidEntryTest), }, + { TEST_CASE(OverlappedPartitionTest), }, + { TEST_CASE(CorruptCombinationTest), }, + { TEST_CASE(TestQuickSortFixed), }, + { TEST_CASE(TestQuickSortRandom), }, + { TEST_CASE(NoValidKernelEntryTest), }, + { TEST_CASE(CombinationalNextKernelEntryTest), }, + { TEST_CASE(IncreaseTriesTest), }, + { TEST_CASE(MarkBadKernelEntryTest), }, + { TEST_CASE(UpdateInvalidKernelTypeTest), }, + { TEST_CASE(NormalBootCase), }, + { TEST_CASE(HigherPriorityTest), }, + { TEST_CASE(TestCrc32TestVectors), }, + }; + + for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) { + printf("Running %s() ...\n", test_cases[i].name); + test_cases[i].retval = test_cases[i].fp(); + if (test_cases[i].retval) { + printf(COL_RED "[ERROR]\n\n" COL_STOP); + ++error_count; + } else { + printf(COL_GREEN "[PASS]\n\n" COL_STOP); + } + } + + if (error_count) { + printf("\n--------------------------------------------------\n"); + printf(COL_RED "The following %d test cases are failed:\n" COL_STOP, + error_count); + for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) { + if (test_cases[i].retval) + printf(" %s()\n", test_cases[i].name); + } + } + + return (error_count) ? 1 : 0; +} |