A simple test infrastructure -- idea stolen from Gaurav.

Review URL: http://codereview.chromium.org/1761004
diff --git a/cgptlib/cgpt.c b/cgptlib/cgpt.c
index 7f18a1c..4504a61 100644
--- a/cgptlib/cgpt.c
+++ b/cgptlib/cgpt.c
@@ -9,19 +9,19 @@
 static int start[] = { 34, 10034 };
 
 int GPTInit(GPTData_t *gpt) {
-        gpt->current_kernel = 1;
-        return 0;
+  gpt->current_kernel = 1;
+  return 0;
 }
 
 int GPTNextKernelEntry(GPTData_t *gpt, uint64_t *start_sector, uint64_t *size) {
-        gpt->current_kernel ^= 1;
-        if (start_sector) *start_sector = start[gpt->current_kernel];
-        if (size) *size = 10000;
-        return 0;
+  gpt->current_kernel ^= 1;
+  if (start_sector) *start_sector = start[gpt->current_kernel];
+  if (size) *size = 10000;
+  return 0;
 }
 
 int GPTUpdateKernelEntry(GPTData_t *gpt, uint32_t update_type) {
-        gpt->modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) <<
-                         gpt->current_kernel;
-        return 0;
+  gpt->modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) <<
+                   gpt->current_kernel;
+  return 0;
 }
diff --git a/cgptlib/cgpt.h b/cgptlib/cgpt.h
index acc1ec9..c9cd04d 100644
--- a/cgptlib/cgpt.h
+++ b/cgptlib/cgpt.h
@@ -9,10 +9,11 @@
 #include <stdint.h>
 
 enum {
-        GPT_ERROR_INVALID_HEADERS = 1,
-        GPT_ERROR_INVALID_ENTRIES,
-        GPT_ERROR_INVALID_SECTOR_SIZE,
-        GPT_ERROR_INVALID_SECTOR_NUMBER,
+  GPT_ERROR_NO_VALID_KERNEL = 1,
+  GPT_ERROR_INVALID_HEADERS,
+  GPT_ERROR_INVALID_ENTRIES,
+  GPT_ERROR_INVALID_SECTOR_SIZE,
+  GPT_ERROR_INVALID_SECTOR_NUMBER,
 };
 
 #define GPT_MODIFIED_HEADER1 0x01
@@ -28,27 +29,27 @@
    * invalid. */
 
 struct GPTData {
-        /* Fill in the following fields before calling GPTInit() */
-        uint8_t *header1;       /* GPT primary header, from sector 1 of disk
-                                 *   (size: 512 bytes) */
-	uint8_t *header2;       /* GPT secondary header, from last sector of
-                                 *   disk (size: 512 bytes) */
-	uint8_t *entries1;      /* primary GPT table, follows primary header
-                                 *   (size: 16 KB) */
-	uint8_t *entries2;      /* secondary GPT table, precedes secondary
-                                 *   header (size: 16 KB) */
-	uint32_t sector_bytes;  /* Size of a LBA sector, in bytes */
-	uint64_t drive_sectors; /* Size of drive in LBA sectors, in sectors */
+  /* Fill in the following fields before calling GPTInit() */
+  uint8_t *header1;       /* GPT primary header, from sector 1 of disk
+                           *   (size: 512 bytes) */
+  uint8_t *header2;       /* GPT secondary header, from last sector of
+                           *   disk (size: 512 bytes) */
+  uint8_t *entries1;      /* primary GPT table, follows primary header
+                           *   (size: 16 KB) */
+  uint8_t *entries2;      /* secondary GPT table, precedes secondary
+                           *   header (size: 16 KB) */
+  uint32_t sector_bytes;  /* Size of a LBA sector, in bytes */
+  uint64_t drive_sectors; /* Size of drive in LBA sectors, in sectors */
 
-	/* Outputs */
-	uint8_t modified;       /* Which inputs have been modified?
-	                         * 0x01 = header1
-	                         * 0x02 = header2
-	                         * 0x04 = table1
-	                         * 0x08 = table2  */
+  /* Outputs */
+  uint8_t modified;       /* Which inputs have been modified?
+                           * 0x01 = header1
+                           * 0x02 = header2
+                           * 0x04 = table1
+                           * 0x08 = table2  */
 
-        /* Internal state */
-        uint8_t current_kernel; // the current kernel index
+  /* Internal state */
+  uint8_t current_kernel; // the current kernel index
 };
 typedef struct GPTData GPTData_t;
 
@@ -74,7 +75,8 @@
  * for the start of the kernel partition, and the size parameter contains the
  * size of the kernel partition in LBA sectors.
  *
- * Returns 0 if successful, 1 if error or no more sectors.  */
+ * Returns 0 if successful, else
+ *   GPT_ERROR_NO_VALID_KERNEL, no avaliable kernel, enters recovery mode */
 
 int GPTUpdateKernelEntry(GPTData_t *gpt, uint32_t update_type);
 /* Updates the kernel entry with the specified index, using the specified type
@@ -85,4 +87,4 @@
  *
  * Returns 0 if successful, 1 if error. */
 
-#endif  // VBOOT_REFERENCE_CGPT_H_
+#endif  /* VBOOT_REFERENCE_CGPT_H_ */
diff --git a/cgptlib/tests/cgpt_test.c b/cgptlib/tests/cgpt_test.c
new file mode 100644
index 0000000..b5b26e7
--- /dev/null
+++ b/cgptlib/tests/cgpt_test.c
@@ -0,0 +1,136 @@
+/* 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 "cgpt.h"
+#include "cgpt_test.h"
+
+#define TEST_CASE(func) #func, func
+typedef int (*test_func)(void);
+
+/* Tests if header CRC in two copies are calculated. */
+int HeaderCrcTest() {
+  return TEST_FAIL;
+}
+
+/* Tests if myLBA field is checked (1 for primary, last for secondary). */
+int MyLbaTest() {
+  return TEST_FAIL;
+}
+
+/* Tests if SizeOfPartitionEntry is checked. SizeOfPartitionEntry must be
+ * between 128 and 512, and a multiple of 8. */
+int SizeOfPartitionEntryTest() {
+  return TEST_FAIL;
+}
+
+/* Tests if NumberOfPartitionEntries is checes. NumberOfPartitionEntries must
+ * be between 32 and 512, and SizeOfPartitionEntry * NumberOfPartitionEntries
+ * must be 16384. */
+int NumberOfPartitionEntriesTest() {
+  return TEST_FAIL;
+}
+
+/* Tests if PartitionEntryLBA in primary/secondary headers is checked. */
+int PartitionEntryLbaTest() {
+  return TEST_FAIL;
+}
+
+/* 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() {
+  return TEST_FAIL;
+}
+
+/* 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 (see Caller's write-
+ * back order below). */
+int IdenticalEntriesTest() {
+  return TEST_FAIL;
+}
+
+/* Tests if GPTInit() handles non-identical headers well.
+ * Two partition headers must be identical. If not, we trust the primary
+ * partition header, and mark secondary as modified (see Caller's write-back
+ * order below). */
+int IdenticalHeaderTest() {
+  return TEST_FAIL;
+}
+
+/* Tests if PartitionEntryArrayCRC32 is checked.
+ * PartitionEntryArrayCRC32 must be calculated over SizeOfPartitionEntry *
+ * NumberOfPartitionEntries bytes.
+ */
+int EntriesCrcTest() {
+  return TEST_FAIL;
+}
+
+/* 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() {
+  return TEST_FAIL;
+}
+
+/* Tests if overlapped partition tables can be detected. */
+int NoOverlappedPartitionTest() {
+  return TEST_FAIL;
+}
+
+/* Tests if GPTNextKernelEntry() can survive in different corrupt header/entries
+ * combinations, like:
+ *   primary GPT header         - valid
+ *   primary partition table    - invalid
+ *   secondary partition table  - valid
+ *   secondary GPT header       - invalid
+ */
+int CorruptCombinationTest() {
+  return TEST_FAIL;
+}
+
+int main(int argc, char *argv[]) {
+  int i;
+  struct {
+    char *name;
+    test_func fp;
+    int retval;
+  } test_cases[] = {
+    { TEST_CASE(HeaderCrcTest), },
+    { TEST_CASE(MyLbaTest), },
+    { TEST_CASE(SizeOfPartitionEntryTest), },
+    { TEST_CASE(NumberOfPartitionEntriesTest), },
+    { TEST_CASE(PartitionEntryLbaTest), },
+    { TEST_CASE(FirstUsableLbaAndLastUsableLbaTest), },
+    { TEST_CASE(IdenticalEntriesTest), },
+    { TEST_CASE(IdenticalHeaderTest), },
+    { TEST_CASE(EntriesCrcTest), },
+    { TEST_CASE(ValidEntryTest), },
+    { TEST_CASE(NoOverlappedPartitionTest), },
+    { TEST_CASE(CorruptCombinationTest), },
+  };
+
+  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]" COL_STOP " %s()\n\n", test_cases[i].name);
+    else
+      printf(COL_GREEN "[PASS]" COL_STOP " %s()\n\n", test_cases[i].name);
+  }
+
+  printf("\n--------------------------------------------------\n");
+  printf("The following test cases are failed:\n");
+  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 0;
+}
diff --git a/cgptlib/tests/cgpt_test.h b/cgptlib/tests/cgpt_test.h
new file mode 100644
index 0000000..0dcb637
--- /dev/null
+++ b/cgptlib/tests/cgpt_test.h
@@ -0,0 +1,24 @@
+/* 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.
+ */
+#ifndef VBOOT_REFERENCE_CGPTLIB_TESTS_CGPT_TEST_H_
+#define VBOOT_REFERENCE_CGPTLIB_TESTS_CGPT_TEST_H_
+
+#include <stdio.h>
+
+#define TEST_FAIL -1
+
+/* ANSI Color coding sequences. */
+#define COL_GREEN "\e[1;32m"
+#define COL_RED "\e[0;31m"
+#define COL_STOP "\e[m"
+
+#define EXPECT(expr) \
+  if (!expr) { \
+    printf(COL_RED " fail " COL_STOP "in expression %s in %s() line %d\n",\
+           #expr, __FUNCTION__, __LINE__); \
+    return TEST_FAIL; \
+  }
+
+#endif  /* VBOOT_REFERENCE_CGPTLIB_TESTS_CGPT_TEST_H_ */