LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - nacl_error_gio_test.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 226 139 61.5 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : #include <stdio.h>
       8                 : #include <stdlib.h>
       9                 : #include <string.h>
      10                 : #include <time.h>
      11                 : 
      12                 : #include "native_client/src/include/nacl_macros.h"
      13                 : #include "native_client/src/include/portability.h"
      14                 : #include "native_client/src/trusted/nacl_base/nacl_refcount.h"
      15                 : #include "native_client/src/trusted/service_runtime/nacl_error_gio.h"
      16                 : 
      17                 : #define MAX_WRITE_CHUNK_SIZE  32
      18                 : 
      19                 : static int g_verbosity = 0;
      20                 : static size_t g_output_bytes_min = 32;
      21                 : static size_t g_output_bytes_max = 2048;
      22                 : 
      23                 : struct TailGio {
      24                 :   struct GioVtbl const *vtbl;
      25                 :   char buffer[NACL_ERROR_GIO_MAX_BYTES];
      26                 :   size_t num_bytes;
      27                 :   size_t total_output_bytes;
      28                 : };
      29                 : 
      30                 : struct GioVtbl const kTailGioVtbl;
      31                 : 
      32               1 : static int TailGioCtor(struct TailGio *self) {
      33               1 :   self->vtbl = &kTailGioVtbl;
      34               1 :   self->num_bytes = 0;
      35               1 :   self->total_output_bytes = 0;
      36               1 :   return 1;
      37               1 : }
      38                 : 
      39               1 : static void TailGioDtor(struct Gio *vself) {
      40                 :   UNREFERENCED_PARAMETER(vself);
      41                 :   return;
      42               1 : }
      43                 : 
      44               0 : static ssize_t TailGioRead(struct Gio *vself, void *buf, size_t count) {
      45                 :   UNREFERENCED_PARAMETER(vself);
      46                 :   UNREFERENCED_PARAMETER(buf);
      47                 :   UNREFERENCED_PARAMETER(count);
      48               0 :   return 0;
      49               0 : }
      50                 : 
      51               1 : static ssize_t TailGioWrite(struct Gio *vself, void const *buf, size_t count) {
      52               1 :   struct TailGio *self = (struct TailGio *) vself;
      53                 : 
      54               1 :   if (count > NACL_ARRAY_SIZE(self->buffer)) {
      55                 :     memcpy(self->buffer, (char *) buf + count - NACL_ARRAY_SIZE(self->buffer),
      56               0 :            NACL_ARRAY_SIZE(self->buffer));
      57               0 :     self->num_bytes = NACL_ARRAY_SIZE(self->buffer);
      58               0 :   } else {
      59                 :     /* 0 <= count <= NACL_ARRAY_SIZE(self->buffer) */
      60               1 :     size_t max_from_buffer = NACL_ARRAY_SIZE(self->buffer) - count;
      61                 : 
      62                 :     /* count + max_from_buffer == NACL_ARRAY_SIZE(self->buffer) */
      63                 :     /* 0 <= max_from_buffer <= NACL_ARRAY_SIZE(self->buffer) */
      64               1 :     if (max_from_buffer < self->num_bytes) {
      65                 :       memmove(self->buffer,
      66                 :               self->buffer + self->num_bytes - max_from_buffer,
      67               1 :               max_from_buffer);
      68                 :       memcpy(self->buffer + max_from_buffer,
      69               1 :              buf, count);
      70               1 :       self->num_bytes = NACL_ARRAY_SIZE(self->buffer);
      71               1 :     } else {
      72                 :       /*
      73                 :        * might still be a partial buffer:
      74                 :        *
      75                 :        * self->num_bytes <= max_from_buffer
      76                 :        * count == NACL_ARRAY_SIZE(self->buffer) - max_from_buffer
      77                 :        * therefore self->num_bytes + count <= NACL_ARRAY_SIZE(self->buffer)
      78                 :        */
      79                 :       memcpy(self->buffer + self->num_bytes,
      80               1 :              buf, count);
      81               1 :       self->num_bytes += count;
      82                 :     }
      83                 :   }
      84               1 :   self->total_output_bytes += count;
      85               1 :   return count;
      86               1 : }
      87                 : 
      88                 : static off_t TailGioSeek(struct Gio *vself,
      89                 :                   off_t offset,
      90               0 :                   int whence) {
      91                 :   UNREFERENCED_PARAMETER(vself);
      92                 :   UNREFERENCED_PARAMETER(offset);
      93                 :   UNREFERENCED_PARAMETER(whence);
      94               0 :   return 0;
      95               0 : }
      96                 : 
      97               0 : static int TailGioFlush(struct Gio *vself) {
      98                 :   UNREFERENCED_PARAMETER(vself);
      99               0 :   return 0;
     100               0 : }
     101                 : 
     102               0 : static int TailGioClose(struct Gio *vself) {
     103                 :   UNREFERENCED_PARAMETER(vself);
     104               0 :   return 0;
     105               0 : }
     106                 : 
     107                 : struct GioVtbl const kTailGioVtbl = {
     108                 :   TailGioDtor,
     109                 :   TailGioRead,
     110                 :   TailGioWrite,
     111                 :   TailGioSeek,
     112                 :   TailGioFlush,
     113                 :   TailGioClose,
     114                 : };
     115                 : 
     116               1 : struct NaClErrorGio *TestGioFactory(void) {
     117               1 :   struct TailGio *tgio = NULL;
     118               1 :   struct NaClErrorGio *negio = NULL;
     119                 : 
     120               1 :   if (NULL == (tgio = (struct TailGio *) malloc(sizeof *tgio))) {
     121               0 :     fprintf(stderr, "TestGioFactory: Out of memory for tgio\n");
     122               0 :     goto giveup;
     123                 :   }
     124               1 :   if (NULL == (negio = (struct NaClErrorGio *) malloc(sizeof *negio))) {
     125               0 :     fprintf(stderr, "TestGioFactory: Out of memory for negio\n");
     126               0 :     goto giveup;
     127                 :   }
     128               1 :   if (!TailGioCtor(tgio)) {
     129               0 :     fprintf(stderr, "TestGioFactory: TailGioCtor failed\n");
     130               0 :     goto giveup;
     131                 :   }
     132               1 :   if (!NaClErrorGioCtor(negio, (struct Gio *) tgio)) {
     133               0 :     fprintf(stderr, "TestGioFactory: NaClErrorGioCtor failed\n");
     134               0 :     goto giveup_dtor_tgio;
     135                 :   }
     136               1 :   return negio;
     137                 : 
     138                 :  giveup_dtor_tgio:
     139               0 :   (*NACL_VTBL(Gio, tgio)->Dtor)((struct Gio *) tgio);
     140                 :  giveup:
     141               0 :   free(negio);
     142               0 :   free(tgio);
     143               0 :   return NULL;
     144               1 : }
     145                 : 
     146               1 : void TestGioRecycler(struct NaClErrorGio *trash) {
     147                 :   struct TailGio *tgio;
     148                 : 
     149               1 :   if (NULL == trash) {
     150               0 :     return;
     151                 :   }
     152               1 :   tgio = (struct TailGio *) trash->pass_through;
     153                 :   /* violate abstraction; this is test code */
     154               1 :   (*NACL_VTBL(Gio, trash)->Dtor)((struct Gio *) trash);
     155               1 :   free(trash);
     156               1 :   (*NACL_VTBL(Gio, tgio)->Dtor)((struct Gio *) tgio);
     157               1 :   free(tgio);
     158               1 : }
     159                 : 
     160               1 : size_t UnitTest_BasicCtorDtor(void) {
     161                 :   struct NaClErrorGio neg;
     162               1 :   size_t num_errors = 0;
     163                 : 
     164               1 :   if (g_verbosity > 0) {
     165               0 :     printf("UnitTest_BasicCtorDtor\n");
     166                 :   }
     167               1 :   if (!NaClErrorGioCtor(&neg, NULL)) {
     168               0 :     ++num_errors;
     169               0 :     fprintf(stderr, "UnitTest_BasicCtorDtor: could not construct\n");
     170               0 :     goto giveup;
     171                 :   }
     172               1 :   (*NACL_VTBL(Gio, &neg)->Dtor)((struct Gio *) &neg);
     173                 :  giveup:
     174               1 :   if (g_verbosity) {
     175               0 :     printf("UnitTest_BasicCtorDtor: %"NACL_PRIuS" error(s)\n", num_errors);
     176                 :   }
     177               1 :   return num_errors;
     178               1 : }
     179                 : 
     180               1 : size_t UnitTest_WeirdBuffers(void) {
     181                 :   struct NaClErrorGio *neg;
     182               1 :   size_t num_errors = 0;
     183                 :   size_t written;
     184               1 :   char const ktest_string[] = "123456789";
     185               1 :   size_t test_string_len = strlen(ktest_string);
     186                 :   char small_buffer[1];
     187                 :   char large_buffer[10 * NACL_ERROR_GIO_MAX_BYTES + 13];
     188                 :   /* a much larger buffer, in case indexing calculations go awry */
     189                 :   size_t actual;
     190                 :   size_t ix;
     191                 : 
     192               1 :   if (g_verbosity > 0) {
     193               0 :     printf("UnitTest_WeirdBuffers\n");
     194                 :   }
     195               1 :   neg = TestGioFactory();
     196               1 :   if (NULL == neg) {
     197               0 :     ++num_errors;
     198               0 :     fprintf(stderr, "UnitTest_WeirdBuffers: could not construct\n");
     199               0 :     goto giveup;
     200                 :   }
     201               1 :   if (0 != NaClErrorGioGetOutput(neg, (char *) NULL, 0)) {
     202               0 :     ++num_errors;
     203                 :     fprintf(stderr,
     204                 :             "UnitTest_WeirdBuffers: NULL buffer for NaClErrorGioGetOutput"
     205               0 :             " failed\n");
     206               0 :     goto giveup;
     207                 :   }
     208                 :   if (0 != NaClErrorGioGetOutput(neg,
     209                 :                                  small_buffer,
     210               1 :                                  NACL_ARRAY_SIZE(small_buffer))) {
     211               0 :     ++num_errors;
     212                 :     fprintf(stderr,
     213               0 :             "UnitTest_WeirdBuffers: small buffer with no output failed\n");
     214               0 :     goto giveup;
     215                 :   }
     216                 : 
     217                 :   /* now make the buffer non-empty */
     218                 : 
     219                 :   written = (*NACL_VTBL(Gio, neg)->Write)((struct Gio *) neg,
     220               1 :                                           ktest_string, test_string_len);
     221               1 :   if (test_string_len != written) {
     222               0 :     ++num_errors;
     223                 :     fprintf(stderr,
     224                 :             "UnitTest_WeirdBuffers: writing %"NACL_PRIuS" bytes failed?!?\n",
     225               0 :             test_string_len);
     226               0 :     goto giveup;
     227                 :   }
     228               1 :   small_buffer[0] = 'x';  /* different from '1' */
     229                 :   actual = NaClErrorGioGetOutput(neg,
     230               1 :                                  small_buffer, NACL_ARRAY_SIZE(small_buffer));
     231               1 :   if (test_string_len != actual) {
     232               0 :     ++num_errors;
     233                 :     fprintf(stderr,
     234                 :             ("UnitTest_WeirdBuffers: too small buffer did not report actual"
     235                 :              " required size, expected %"NACL_PRIuS", got %"NACL_PRIuS"\n"),
     236               0 :             test_string_len, actual);
     237               0 :     goto giveup;
     238                 :   }
     239               1 :   if (small_buffer[0] != ktest_string[0]) {
     240               0 :     ++num_errors;
     241                 :     fprintf(stderr,
     242                 :             ("UnitTest_WeirdBuffers: partial buffer not filled, expected"
     243                 :              " '1', got '%c'\n"),
     244               0 :             small_buffer[0]);
     245               0 :     goto giveup;
     246                 :   }
     247                 :   actual = NaClErrorGioGetOutput(neg,
     248               1 :                                  large_buffer, NACL_ARRAY_SIZE(large_buffer));
     249               1 :   if (test_string_len != actual) {
     250               0 :     ++num_errors;
     251                 :     fprintf(stderr,
     252                 :             ("UnitTest_WeirdBuffers: large buffer fill did not report actual"
     253                 :              " output size, expected %"NACL_PRIuS", got %"NACL_PRIuS"\n"),
     254               0 :             test_string_len, actual);
     255               0 :     goto giveup;
     256                 :   }
     257               1 :   for (ix = 0; ix < test_string_len; ++ix) {
     258               1 :     if (large_buffer[ix] != ktest_string[ix]) {
     259               0 :       ++num_errors;
     260                 :       fprintf(stderr,
     261                 :               ("UnitTest_WeirdBuffers: large buffer content wrong at ix %"
     262                 :                NACL_PRIuS": expected '%c', got '%c'\n"),
     263               0 :               ix, 0xff & ktest_string[ix], 0xff & large_buffer[ix]);
     264                 :     }
     265               1 :   }
     266                 :  giveup:
     267               1 :   TestGioRecycler(neg);
     268               1 :   if (g_verbosity) {
     269               0 :     printf("UnitTest_BasicCtorDtor: %"NACL_PRIuS" error(s)\n", num_errors);
     270                 :   }
     271               1 :   return num_errors;
     272               1 : }
     273                 : 
     274               1 : size_t UnitTest_GenerateRandomOutput(void) {
     275                 :   struct NaClErrorGio *neg;
     276               1 :   size_t num_errors = 0;
     277                 :   char output_tail[NACL_ERROR_GIO_MAX_BYTES];
     278                 :   size_t output_bytes;
     279                 :   size_t output_discarded_bytes;
     280                 :   size_t output_saved_tail_bytes;
     281                 :   size_t ix;
     282                 :   size_t write_chunk_size;
     283                 :   char write_chunk[MAX_WRITE_CHUNK_SIZE];
     284                 :   size_t jx;
     285                 :   ssize_t written;
     286                 :   char error_gio_content[NACL_ERROR_GIO_MAX_BYTES];
     287                 :   size_t error_gio_content_bytes;
     288                 : 
     289               1 :   if (g_verbosity > 0) {
     290               0 :     printf("UnitTest_GenerateRandomOutput\n");
     291                 :   }
     292                 : 
     293               1 :   neg = TestGioFactory();
     294               1 :   if (NULL == neg) {
     295                 :     fprintf(stderr,
     296                 :             ("UnitTest_GenerateRandomOutput: TestGioFactory"
     297               0 :              " construction failed\n"));
     298               0 :     ++num_errors;
     299               0 :     goto giveup;
     300                 :   }
     301                 : 
     302                 :   output_bytes = g_output_bytes_min +
     303               1 :       (rand() % (g_output_bytes_max - g_output_bytes_min));
     304                 : 
     305               1 :   if (output_bytes > NACL_ARRAY_SIZE(output_tail)) {
     306               1 :     output_saved_tail_bytes = NACL_ARRAY_SIZE(output_tail);
     307               1 :     output_discarded_bytes = output_bytes - output_saved_tail_bytes;
     308               1 :   } else {
     309               1 :     output_saved_tail_bytes = output_bytes;
     310               1 :     output_discarded_bytes = 0;
     311                 :   }
     312                 : 
     313               1 :   for (ix = 0; ix < output_discarded_bytes; ) {
     314               1 :     write_chunk_size = rand() % NACL_ARRAY_SIZE(write_chunk);
     315               1 :     if (write_chunk_size > output_discarded_bytes - ix) {
     316               1 :       write_chunk_size = output_discarded_bytes - ix;
     317                 :     }
     318               1 :     for (jx = 0; jx < write_chunk_size; ++jx) {
     319               1 :       write_chunk[jx] = rand();  /* not efficient use of rng */
     320               1 :     }
     321                 :     written = (*NACL_VTBL(Gio, neg)->Write)((struct Gio *) neg,
     322               1 :                                             write_chunk, write_chunk_size);
     323               1 :     if (written < 0) {
     324               0 :       ++num_errors;
     325                 :       fprintf(stderr,
     326                 :               ("UnitTest_GenerateRandomOutput: Write method returned %"
     327                 :                NACL_PRIdS"\n"),
     328               0 :               written);
     329               0 :       goto abort_test;
     330                 :     }
     331               1 :     ix += (size_t) written;
     332               1 :   }
     333               1 :   for (ix = 0; ix < output_saved_tail_bytes; ) {
     334               1 :     write_chunk_size = rand() % NACL_ARRAY_SIZE(write_chunk);
     335               1 :     if (write_chunk_size > output_saved_tail_bytes - ix) {
     336               1 :       write_chunk_size = output_saved_tail_bytes - ix;
     337                 :     }
     338               1 :     for (jx = 0; jx < write_chunk_size; ++jx) {
     339               1 :       write_chunk[jx] = rand();  /* not efficient use of rng */
     340               1 :     }
     341                 :     written = (*NACL_VTBL(Gio, neg)->Write)((struct Gio *) neg,
     342               1 :                                             write_chunk, write_chunk_size);
     343               1 :     if (written < 0) {
     344               0 :       ++num_errors;
     345                 :       fprintf(stderr,
     346                 :               ("UnitTest_GenerateRandomOutput: Write method returned %"
     347                 :                NACL_PRIdS"\n"),
     348               0 :               written);
     349               0 :       goto abort_test;
     350                 :     }
     351               1 :     for (jx = 0; jx < (size_t) written; ++jx) {
     352               1 :       output_tail[ix + jx] = write_chunk[jx];
     353               1 :     }
     354               1 :     ix += (size_t) written;
     355               1 :   }
     356                 :   /*
     357                 :    * Check that the final output Gio actually captured the number of bytes
     358                 :    * that we think should have been captured.
     359                 :    */
     360                 :   if (output_saved_tail_bytes !=
     361               1 :       ((struct TailGio *) neg->pass_through)->num_bytes) {
     362               0 :     ++num_errors;
     363                 :     fprintf(stderr,
     364                 :             ("UnitTest_GenerateRandomOutput: TailGio buffer wrong captured"
     365                 :              " size: got %"NACL_PRIuS", expected %"NACL_PRIuS"!\n"),
     366                 :             ((struct TailGio *) neg->pass_through)->num_bytes,
     367               0 :             output_saved_tail_bytes);
     368                 :   }
     369                 :   /*
     370                 :    * Check that the final output Gio actually saw the number of bytes
     371                 :    * that we think should have been output.
     372                 :    */
     373                 :   if (output_bytes !=
     374               1 :       ((struct TailGio *) neg->pass_through)->total_output_bytes) {
     375               0 :     ++num_errors;
     376                 :     fprintf(stderr,
     377                 :             ("UnitTest_GenerateRandomOutput: TailGio buffer wrong total"
     378                 :              " output size: got %"NACL_PRIuS", expected %"NACL_PRIuS"!\n"),
     379                 :             ((struct TailGio *) neg->pass_through)->total_output_bytes,
     380               0 :             output_bytes);
     381                 :   }
     382                 :   /*
     383                 :    * Compare output_tail with NaClErrorGioGetOutput output, and with
     384                 :    * TailGio buffer.
     385                 :    */
     386                 :   error_gio_content_bytes =
     387                 :       NaClErrorGioGetOutput(neg, error_gio_content,
     388               1 :                             NACL_ARRAY_SIZE(error_gio_content));
     389               1 :   if (output_saved_tail_bytes != error_gio_content_bytes) {
     390               0 :     ++num_errors;
     391                 :     fprintf(stderr,
     392                 :             ("UnitTest_GenerateRandomOutput: NaClErrorGio buffer wrong size:"
     393                 :              " got %"NACL_PRIuS", expected %"NACL_PRIuS"!\n"),
     394               0 :             error_gio_content_bytes, output_saved_tail_bytes);
     395                 :   }
     396               1 :   for (ix = 0; ix < error_gio_content_bytes; ++ix) {
     397               1 :     if (output_tail[ix] != error_gio_content[ix]) {
     398                 :       fprintf(stderr,
     399                 :               ("UnitTest_GenerateRandomOutput: byte %"NACL_PRIuS
     400                 :                ": wrote %02x, got %02x\n"),
     401               0 :               ix, 0xff & output_tail[ix], 0xff & error_gio_content[ix]);
     402               0 :       ++num_errors;
     403                 :     }
     404                 :     if (output_tail[ix] !=
     405               1 :         ((struct TailGio *) neg->pass_through)->buffer[ix]) {
     406                 :       fprintf(stderr,
     407                 :               ("UnitTest_GenerateRandomOutput: byte %"NACL_PRIuS
     408                 :                ": wrote %02x, wrote through %02x\n"),
     409               0 :               ix, 0xff & output_tail[ix], 0xff & error_gio_content[ix]);
     410               0 :       ++num_errors;
     411                 :     }
     412               1 :   }
     413                 :  abort_test:
     414               1 :   TestGioRecycler(neg);
     415                 :  giveup:
     416               1 :   if (g_verbosity > 0) {
     417                 :     printf("UnitTest_GenerateRandomOutput: %"NACL_PRIuS" error(s)\n",
     418               0 :            num_errors);
     419                 :   }
     420               1 :   return num_errors;
     421               1 : }
     422                 : 
     423                 : /*
     424                 :  * This test could use gtest, but does not.  Here is why:
     425                 :  *
     426                 :  * gtest does not have a way to specify a test parameter such as an
     427                 :  * RNG seed from the command line -- except by using internal APIs to
     428                 :  * specify a --gtest_<foo> flag, or by a side channel such as using an
     429                 :  * environment variable.  This makes randomized tests that can serve
     430                 :  * to do API fuzzing during development as well as act as a quick
     431                 :  * unittest more awkward to implement.  Additionally, while gtest
     432                 :  * itself has the ability to set an RNG seed, it is gtest's RNG for
     433                 :  * shuffling the order of tests to be run -- there shouldn't be
     434                 :  * interactions between gtest's RNG usage and the test's RNG usage, so
     435                 :  * sharing the RNG and making use of gtest's ability to set RNG seed
     436                 :  * is not a great idea.  Furthermore, this test should *never* fail --
     437                 :  * the xml output for getting test history (e.g., to deal with flaky
     438                 :  * tests) is useless: if this test fails, somebody must have modified
     439                 :  * the code in an erroneous way, and the change should be rolled back.
     440                 :  */
     441               1 : int main(int ac, char **av) {
     442                 :   int opt;
     443               1 :   size_t num_errors = 0;
     444               1 :   size_t num_iter = 100000;
     445                 :   size_t iter;
     446               1 :   unsigned seed = (unsigned) time((time_t *) NULL);
     447                 : 
     448               1 :   while (-1 != (opt = getopt(ac, av, "b:B:n:s:v"))) {
     449               1 :     switch (opt) {
     450                 :       case 'b':
     451               0 :         g_output_bytes_min = strtoul(optarg, (char **) NULL, 0);
     452               0 :         break;
     453                 :       case 'B':
     454               0 :         g_output_bytes_max = strtoul(optarg, (char **) NULL, 0);
     455               0 :         break;
     456                 :       case 'n':
     457               1 :         num_iter = strtoul(optarg, (char **) NULL, 0);
     458               1 :         break;
     459                 :       case 's':
     460               0 :         seed = strtoul(optarg, (char **) NULL, 0);
     461                 :       case 'v':
     462               0 :         ++g_verbosity;
     463                 :         break;
     464                 :     }
     465               1 :   }
     466               1 :   if (g_output_bytes_max < g_output_bytes_min) {
     467                 :     fprintf(stderr,
     468                 :             "nacl_error_gio_test: -b min_bytes value should not be larger"
     469               0 :             " than -B max_bytes value\n");
     470               0 :     return 1;
     471                 :   }
     472               1 :   srand(seed);
     473               1 :   printf("seed %u\n", seed);
     474                 : 
     475               1 :   num_errors += UnitTest_BasicCtorDtor();
     476               1 :   num_errors += UnitTest_WeirdBuffers();
     477                 : 
     478               1 :   for (iter = 0; iter < num_iter; ++iter) {
     479               1 :     num_errors += UnitTest_GenerateRandomOutput();
     480               1 :   }
     481                 : 
     482               1 :   return num_errors;
     483               1 : }

Generated by: LCOV version 1.7