blob_test.c revision 7ec681f3
17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2014 Intel Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg/* A collection of unit tests for blob.c */
257ec681f3Smrg
267ec681f3Smrg#include <inttypes.h>
277ec681f3Smrg#include <stdio.h>
287ec681f3Smrg#include <stdlib.h>
297ec681f3Smrg#include <stdbool.h>
307ec681f3Smrg#include <string.h>
317ec681f3Smrg#ifdef _MSC_VER
327ec681f3Smrg#include <BaseTsd.h>
337ec681f3Smrgtypedef SSIZE_T ssize_t;
347ec681f3Smrg#endif
357ec681f3Smrg
367ec681f3Smrg#include "util/ralloc.h"
377ec681f3Smrg#include "blob.h"
387ec681f3Smrg
397ec681f3Smrg#define bytes_test_str     "bytes_test"
407ec681f3Smrg#define reserve_test_str   "reserve_test"
417ec681f3Smrg
427ec681f3Smrg/* This placeholder must be the same length as the next overwrite_test_str */
437ec681f3Smrg#define placeholder_str    "XXXXXXXXXXXXXX"
447ec681f3Smrg#define overwrite_test_str "overwrite_test"
457ec681f3Smrg#define uint32_test        0x12345678
467ec681f3Smrg#define uint32_placeholder 0xDEADBEEF
477ec681f3Smrg#define uint32_overwrite   0xA1B2C3D4
487ec681f3Smrg#define uint64_test        0x1234567890ABCDEF
497ec681f3Smrg#define string_test_str    "string_test"
507ec681f3Smrg
517ec681f3Smrgbool error = false;
527ec681f3Smrg
537ec681f3Smrgstatic void
547ec681f3Smrgexpect_equal(uint64_t expected, uint64_t actual, const char *test)
557ec681f3Smrg{
567ec681f3Smrg   if (actual != expected) {
577ec681f3Smrg      fprintf(stderr,
587ec681f3Smrg              "Error: Test '%s' failed: "
597ec681f3Smrg              "Expected=%" PRIu64 ", "
607ec681f3Smrg              "Actual=%" PRIu64 "\n",
617ec681f3Smrg               test, expected, actual);
627ec681f3Smrg      error = true;
637ec681f3Smrg   }
647ec681f3Smrg}
657ec681f3Smrg
667ec681f3Smrgstatic void
677ec681f3Smrgexpect_unequal(uint64_t expected, uint64_t actual, const char *test)
687ec681f3Smrg{
697ec681f3Smrg   if (actual == expected) {
707ec681f3Smrg      fprintf(stderr,
717ec681f3Smrg              "Error: Test '%s' failed: Result=%" PRIu64 ", "
727ec681f3Smrg              "but expected something different.\n",
737ec681f3Smrg               test, actual);
747ec681f3Smrg      error = true;
757ec681f3Smrg   }
767ec681f3Smrg}
777ec681f3Smrg
787ec681f3Smrgstatic void
797ec681f3Smrgexpect_equal_str(const char *expected, const char *actual, const char *test)
807ec681f3Smrg{
817ec681f3Smrg   if (strcmp(expected, actual)) {
827ec681f3Smrg      fprintf (stderr, "Error: Test '%s' failed:\n\t"
837ec681f3Smrg               "Expected=\"%s\", Actual=\"%s\"\n",
847ec681f3Smrg               test, expected, actual);
857ec681f3Smrg      error = true;
867ec681f3Smrg   }
877ec681f3Smrg}
887ec681f3Smrg
897ec681f3Smrgstatic void
907ec681f3Smrgexpect_equal_bytes(uint8_t *expected, const uint8_t *actual,
917ec681f3Smrg                   size_t num_bytes, const char *test)
927ec681f3Smrg{
937ec681f3Smrg   size_t i;
947ec681f3Smrg
957ec681f3Smrg   if (memcmp(expected, actual, num_bytes)) {
967ec681f3Smrg      fprintf (stderr, "Error: Test '%s' failed:\n\t", test);
977ec681f3Smrg
987ec681f3Smrg      fprintf (stderr, "Expected=[");
997ec681f3Smrg      for (i = 0; i < num_bytes; i++) {
1007ec681f3Smrg         if (i != 0)
1017ec681f3Smrg            fprintf(stderr, ", ");
1027ec681f3Smrg         fprintf(stderr, "0x%02x", expected[i]);
1037ec681f3Smrg      }
1047ec681f3Smrg      fprintf (stderr, "]");
1057ec681f3Smrg
1067ec681f3Smrg      fprintf (stderr, "Actual=[");
1077ec681f3Smrg      for (i = 0; i < num_bytes; i++) {
1087ec681f3Smrg         if (i != 0)
1097ec681f3Smrg            fprintf(stderr, ", ");
1107ec681f3Smrg         fprintf(stderr, "0x%02x", actual[i]);
1117ec681f3Smrg      }
1127ec681f3Smrg      fprintf (stderr, "]\n");
1137ec681f3Smrg
1147ec681f3Smrg      error = true;
1157ec681f3Smrg   }
1167ec681f3Smrg}
1177ec681f3Smrg
1187ec681f3Smrg/* Test at least one call of each blob_write_foo and blob_read_foo function,
1197ec681f3Smrg * verifying that we read out everything we wrote, that every bytes is
1207ec681f3Smrg * consumed, and that the overrun bit is not set.
1217ec681f3Smrg */
1227ec681f3Smrgstatic void
1237ec681f3Smrgtest_write_and_read_functions (void)
1247ec681f3Smrg{
1257ec681f3Smrg   struct blob blob;
1267ec681f3Smrg   struct blob_reader reader;
1277ec681f3Smrg   ssize_t reserved;
1287ec681f3Smrg   size_t str_offset, uint_offset;
1297ec681f3Smrg   uint8_t reserve_buf[sizeof(reserve_test_str)];
1307ec681f3Smrg
1317ec681f3Smrg   blob_init(&blob);
1327ec681f3Smrg
1337ec681f3Smrg   /*** Test blob by writing one of every possible kind of value. */
1347ec681f3Smrg
1357ec681f3Smrg   blob_write_bytes(&blob, bytes_test_str, sizeof(bytes_test_str));
1367ec681f3Smrg
1377ec681f3Smrg   reserved = blob_reserve_bytes(&blob, sizeof(reserve_test_str));
1387ec681f3Smrg   blob_overwrite_bytes(&blob, reserved, reserve_test_str, sizeof(reserve_test_str));
1397ec681f3Smrg
1407ec681f3Smrg   /* Write a placeholder, (to be replaced later via overwrite_bytes) */
1417ec681f3Smrg   str_offset = blob.size;
1427ec681f3Smrg   blob_write_bytes(&blob, placeholder_str, sizeof(placeholder_str));
1437ec681f3Smrg
1447ec681f3Smrg   blob_write_uint32(&blob, uint32_test);
1457ec681f3Smrg
1467ec681f3Smrg   /* Write a placeholder, (to be replaced later via overwrite_uint32) */
1477ec681f3Smrg   uint_offset = blob.size;
1487ec681f3Smrg   blob_write_uint32(&blob, uint32_placeholder);
1497ec681f3Smrg
1507ec681f3Smrg   blob_write_uint64(&blob, uint64_test);
1517ec681f3Smrg
1527ec681f3Smrg   blob_write_intptr(&blob, (intptr_t) &blob);
1537ec681f3Smrg
1547ec681f3Smrg   blob_write_string(&blob, string_test_str);
1557ec681f3Smrg
1567ec681f3Smrg   /* Finally, overwrite our placeholders. */
1577ec681f3Smrg   blob_overwrite_bytes(&blob, str_offset, overwrite_test_str,
1587ec681f3Smrg                        sizeof(overwrite_test_str));
1597ec681f3Smrg   blob_overwrite_uint32(&blob, uint_offset, uint32_overwrite);
1607ec681f3Smrg
1617ec681f3Smrg   /*** Now read each value and verify. */
1627ec681f3Smrg   blob_reader_init(&reader, blob.data, blob.size);
1637ec681f3Smrg
1647ec681f3Smrg   expect_equal_str(bytes_test_str,
1657ec681f3Smrg                    blob_read_bytes(&reader, sizeof(bytes_test_str)),
1667ec681f3Smrg                    "blob_write/read_bytes");
1677ec681f3Smrg
1687ec681f3Smrg   blob_copy_bytes(&reader, reserve_buf, sizeof(reserve_buf));
1697ec681f3Smrg   expect_equal_str(reserve_test_str, (char *) reserve_buf,
1707ec681f3Smrg                    "blob_reserve_bytes/blob_copy_bytes");
1717ec681f3Smrg
1727ec681f3Smrg   expect_equal_str(overwrite_test_str,
1737ec681f3Smrg                    blob_read_bytes(&reader, sizeof(overwrite_test_str)),
1747ec681f3Smrg                    "blob_overwrite_bytes");
1757ec681f3Smrg
1767ec681f3Smrg   expect_equal(uint32_test, blob_read_uint32(&reader),
1777ec681f3Smrg                "blob_write/read_uint32");
1787ec681f3Smrg   expect_equal(uint32_overwrite, blob_read_uint32(&reader),
1797ec681f3Smrg                "blob_overwrite_uint32");
1807ec681f3Smrg   expect_equal(uint64_test, blob_read_uint64(&reader),
1817ec681f3Smrg                "blob_write/read_uint64");
1827ec681f3Smrg   expect_equal((intptr_t) &blob, blob_read_intptr(&reader),
1837ec681f3Smrg                "blob_write/read_intptr");
1847ec681f3Smrg   expect_equal_str(string_test_str, blob_read_string(&reader),
1857ec681f3Smrg                    "blob_write/read_string");
1867ec681f3Smrg
1877ec681f3Smrg   expect_equal(reader.end - reader.data, reader.current - reader.data,
1887ec681f3Smrg                "read_consumes_all_bytes");
1897ec681f3Smrg   expect_equal(false, reader.overrun, "read_does_not_overrun");
1907ec681f3Smrg
1917ec681f3Smrg   blob_finish(&blob);
1927ec681f3Smrg}
1937ec681f3Smrg
1947ec681f3Smrg/* Test that data values are written and read with proper alignment. */
1957ec681f3Smrgstatic void
1967ec681f3Smrgtest_alignment(void)
1977ec681f3Smrg{
1987ec681f3Smrg   struct blob blob;
1997ec681f3Smrg   struct blob_reader reader;
2007ec681f3Smrg   uint8_t bytes[] = "ABCDEFGHIJKLMNOP";
2017ec681f3Smrg   size_t delta, last, num_bytes;
2027ec681f3Smrg
2037ec681f3Smrg   blob_init(&blob);
2047ec681f3Smrg
2057ec681f3Smrg   /* First, write an intptr value to the blob and capture that size. This is
2067ec681f3Smrg    * the expected offset between any pair of intptr values (if written with
2077ec681f3Smrg    * alignment).
2087ec681f3Smrg    */
2097ec681f3Smrg   blob_write_intptr(&blob, (intptr_t) &blob);
2107ec681f3Smrg
2117ec681f3Smrg   delta = blob.size;
2127ec681f3Smrg   last = blob.size;
2137ec681f3Smrg
2147ec681f3Smrg   /* Then loop doing the following:
2157ec681f3Smrg    *
2167ec681f3Smrg    *   1. Write an unaligned number of bytes
2177ec681f3Smrg    *   2. Verify that write results in an unaligned size
2187ec681f3Smrg    *   3. Write an intptr_t value
2197ec681f3Smrg    *   2. Verify that that write results in an aligned size
2207ec681f3Smrg    */
2217ec681f3Smrg   for (num_bytes = 1; num_bytes < sizeof(intptr_t); num_bytes++) {
2227ec681f3Smrg      blob_write_bytes(&blob, bytes, num_bytes);
2237ec681f3Smrg
2247ec681f3Smrg      expect_unequal(delta, blob.size - last, "unaligned write of bytes");
2257ec681f3Smrg
2267ec681f3Smrg      blob_write_intptr(&blob, (intptr_t) &blob);
2277ec681f3Smrg
2287ec681f3Smrg      expect_equal(2 * delta, blob.size - last, "aligned write of intptr");
2297ec681f3Smrg
2307ec681f3Smrg      last = blob.size;
2317ec681f3Smrg   }
2327ec681f3Smrg
2337ec681f3Smrg   /* Finally, test that reading also does proper alignment. Since we know
2347ec681f3Smrg    * that values were written with all the right alignment, all we have to do
2357ec681f3Smrg    * here is verify that correct values are read.
2367ec681f3Smrg    */
2377ec681f3Smrg   blob_reader_init(&reader, blob.data, blob.size);
2387ec681f3Smrg
2397ec681f3Smrg   expect_equal((intptr_t) &blob, blob_read_intptr(&reader),
2407ec681f3Smrg                "read of initial, aligned intptr_t");
2417ec681f3Smrg
2427ec681f3Smrg   for (num_bytes = 1; num_bytes < sizeof(intptr_t); num_bytes++) {
2437ec681f3Smrg      expect_equal_bytes(bytes, blob_read_bytes(&reader, num_bytes),
2447ec681f3Smrg                         num_bytes, "unaligned read of bytes");
2457ec681f3Smrg      expect_equal((intptr_t) &blob, blob_read_intptr(&reader),
2467ec681f3Smrg                   "aligned read of intptr_t");
2477ec681f3Smrg   }
2487ec681f3Smrg
2497ec681f3Smrg   blob_finish(&blob);
2507ec681f3Smrg}
2517ec681f3Smrg
2527ec681f3Smrg/* Test that we detect overrun. */
2537ec681f3Smrgstatic void
2547ec681f3Smrgtest_overrun(void)
2557ec681f3Smrg{
2567ec681f3Smrg   struct blob blob;
2577ec681f3Smrg   struct blob_reader reader;
2587ec681f3Smrg   uint32_t value = 0xdeadbeef;
2597ec681f3Smrg
2607ec681f3Smrg   blob_init(&blob);
2617ec681f3Smrg
2627ec681f3Smrg   blob_write_uint32(&blob, value);
2637ec681f3Smrg
2647ec681f3Smrg   blob_reader_init(&reader, blob.data, blob.size);
2657ec681f3Smrg
2667ec681f3Smrg   expect_equal(value, blob_read_uint32(&reader), "read before overrun");
2677ec681f3Smrg   expect_equal(false, reader.overrun, "overrun flag not set");
2687ec681f3Smrg   expect_equal(0, blob_read_uint32(&reader), "read at overrun");
2697ec681f3Smrg   expect_equal(true, reader.overrun, "overrun flag set");
2707ec681f3Smrg
2717ec681f3Smrg   blob_finish(&blob);
2727ec681f3Smrg}
2737ec681f3Smrg
2747ec681f3Smrg/* Test that we can read and write some large objects, (exercising the code in
2757ec681f3Smrg * the blob_write functions to realloc blob->data.
2767ec681f3Smrg */
2777ec681f3Smrgstatic void
2787ec681f3Smrgtest_big_objects(void)
2797ec681f3Smrg{
2807ec681f3Smrg   void *ctx = ralloc_context(NULL);
2817ec681f3Smrg   struct blob blob;
2827ec681f3Smrg   struct blob_reader reader;
2837ec681f3Smrg   int size = 1000;
2847ec681f3Smrg   int count = 1000;
2857ec681f3Smrg   size_t i;
2867ec681f3Smrg   char *buf;
2877ec681f3Smrg
2887ec681f3Smrg   blob_init(&blob);
2897ec681f3Smrg
2907ec681f3Smrg   /* Initialize our buffer. */
2917ec681f3Smrg   buf = ralloc_size(ctx, size);
2927ec681f3Smrg   for (i = 0; i < size; i++) {
2937ec681f3Smrg      buf[i] = i % 256;
2947ec681f3Smrg   }
2957ec681f3Smrg
2967ec681f3Smrg   /* Write it many times. */
2977ec681f3Smrg   for (i = 0; i < count; i++) {
2987ec681f3Smrg      blob_write_bytes(&blob, buf, size);
2997ec681f3Smrg   }
3007ec681f3Smrg
3017ec681f3Smrg   blob_reader_init(&reader, blob.data, blob.size);
3027ec681f3Smrg
3037ec681f3Smrg   /* Read and verify it many times. */
3047ec681f3Smrg   for (i = 0; i < count; i++) {
3057ec681f3Smrg      expect_equal_bytes((uint8_t *) buf, blob_read_bytes(&reader, size), size,
3067ec681f3Smrg                         "read of large objects");
3077ec681f3Smrg   }
3087ec681f3Smrg
3097ec681f3Smrg   expect_equal(reader.end - reader.data, reader.current - reader.data,
3107ec681f3Smrg                "number of bytes read reading large objects");
3117ec681f3Smrg
3127ec681f3Smrg   expect_equal(false, reader.overrun,
3137ec681f3Smrg                "overrun flag not set reading large objects");
3147ec681f3Smrg
3157ec681f3Smrg   blob_finish(&blob);
3167ec681f3Smrg   ralloc_free(ctx);
3177ec681f3Smrg}
3187ec681f3Smrg
3197ec681f3Smrgint
3207ec681f3Smrgmain (void)
3217ec681f3Smrg{
3227ec681f3Smrg   test_write_and_read_functions ();
3237ec681f3Smrg   test_alignment ();
3247ec681f3Smrg   test_overrun ();
3257ec681f3Smrg   test_big_objects ();
3267ec681f3Smrg
3277ec681f3Smrg   return error ? 1 : 0;
3287ec681f3Smrg}
329