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: 261 155 59.4 %
Date: 2014-06-18 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            1001 : static int TailGioCtor(struct TailGio *self) {
      33            1001 :   self->vtbl = &kTailGioVtbl;
      34            1001 :   self->num_bytes = 0;
      35            1001 :   self->total_output_bytes = 0;
      36            1001 :   return 1;
      37                 : }
      38                 : 
      39            1001 : static void TailGioDtor(struct Gio *vself) {
      40            2002 :   UNREFERENCED_PARAMETER(vself);
      41            1001 :   return;
      42                 : }
      43                 : 
      44               0 : static ssize_t TailGioRead(struct Gio *vself, void *buf, size_t count) {
      45               0 :   UNREFERENCED_PARAMETER(vself);
      46               0 :   UNREFERENCED_PARAMETER(buf);
      47               0 :   UNREFERENCED_PARAMETER(count);
      48               0 :   return 0;
      49                 : }
      50                 : 
      51           66716 : static ssize_t TailGioWrite(struct Gio *vself, void const *buf, size_t count) {
      52           66716 :   struct TailGio *self = (struct TailGio *) vself;
      53                 : 
      54           66716 :   if (count > NACL_ARRAY_SIZE(self->buffer)) {
      55               0 :     memcpy(self->buffer, (char *) buf + count - NACL_ARRAY_SIZE(self->buffer),
      56                 :            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           66716 :     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           66716 :     if (max_from_buffer < self->num_bytes) {
      65          108429 :       memmove(self->buffer,
      66                 :               self->buffer + self->num_bytes - max_from_buffer,
      67                 :               max_from_buffer);
      68          108429 :       memcpy(self->buffer + max_from_buffer,
      69                 :              buf, count);
      70           36143 :       self->num_bytes = NACL_ARRAY_SIZE(self->buffer);
      71           36143 :     } 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           91719 :       memcpy(self->buffer + self->num_bytes,
      80                 :              buf, count);
      81           30573 :       self->num_bytes += count;
      82                 :     }
      83                 :   }
      84           66716 :   self->total_output_bytes += count;
      85           66716 :   return count;
      86                 : }
      87                 : 
      88               0 : static off_t TailGioSeek(struct Gio *vself,
      89               0 :                   off_t offset,
      90               0 :                   int whence) {
      91               0 :   UNREFERENCED_PARAMETER(vself);
      92               0 :   UNREFERENCED_PARAMETER(offset);
      93               0 :   UNREFERENCED_PARAMETER(whence);
      94               0 :   return 0;
      95                 : }
      96                 : 
      97               0 : static int TailGioFlush(struct Gio *vself) {
      98               0 :   UNREFERENCED_PARAMETER(vself);
      99               0 :   return 0;
     100                 : }
     101                 : 
     102               0 : static int TailGioClose(struct Gio *vself) {
     103               0 :   UNREFERENCED_PARAMETER(vself);
     104               0 :   return 0;
     105                 : }
     106                 : 
     107                 : struct GioVtbl const kTailGioVtbl = {
     108                 :   TailGioDtor,
     109                 :   TailGioRead,
     110                 :   TailGioWrite,
     111                 :   TailGioSeek,
     112                 :   TailGioFlush,
     113                 :   TailGioClose,
     114                 : };
     115                 : 
     116                 : struct NaClErrorGio *TestGioFactory(void) {
     117            2002 :   struct TailGio *tgio = NULL;
     118            1001 :   struct NaClErrorGio *negio = NULL;
     119                 : 
     120            1001 :   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            1001 :   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            1001 :   if (!TailGioCtor(tgio)) {
     129               0 :     fprintf(stderr, "TestGioFactory: TailGioCtor failed\n");
     130               0 :     goto giveup;
     131                 :   }
     132            1001 :   if (!NaClErrorGioCtor(negio, (struct Gio *) tgio)) {
     133               0 :     fprintf(stderr, "TestGioFactory: NaClErrorGioCtor failed\n");
     134               0 :     goto giveup_dtor_tgio;
     135                 :   }
     136            1001 :   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            1001 : }
     145                 : 
     146            1001 : void TestGioRecycler(struct NaClErrorGio *trash) {
     147            1001 :   struct TailGio *tgio;
     148                 : 
     149            1001 :   if (NULL == trash) {
     150               0 :     return;
     151                 :   }
     152            1001 :   tgio = (struct TailGio *) trash->pass_through;
     153                 :   /* violate abstraction; this is test code */
     154            1001 :   (*NACL_VTBL(Gio, trash)->Dtor)((struct Gio *) trash);
     155            1001 :   free(trash);
     156            1001 :   (*NACL_VTBL(Gio, tgio)->Dtor)((struct Gio *) tgio);
     157            1001 :   free(tgio);
     158            2002 : }
     159                 : 
     160                 : size_t UnitTest_BasicCtorDtor(void) {
     161               1 :   struct NaClErrorGio neg;
     162               2 :   size_t num_errors = 0;
     163                 : 
     164               1 :   if (g_verbosity > 0) {
     165               0 :     printf("UnitTest_BasicCtorDtor\n");
     166               0 :   }
     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               0 :   }
     177               1 :   return num_errors;
     178                 : }
     179                 : 
     180                 : size_t UnitTest_WeirdBuffers(void) {
     181               1 :   struct NaClErrorGio *neg;
     182               2 :   size_t num_errors = 0;
     183               1 :   size_t written;
     184                 :   char const ktest_string[] = "123456789";
     185               1 :   size_t test_string_len = strlen(ktest_string);
     186               1 :   char small_buffer[1];
     187               1 :   char large_buffer[10 * NACL_ERROR_GIO_MAX_BYTES + 13];
     188                 :   /* a much larger buffer, in case indexing calculations go awry */
     189               1 :   size_t actual;
     190               1 :   size_t ix;
     191                 : 
     192               1 :   if (g_verbosity > 0) {
     193               0 :     printf("UnitTest_WeirdBuffers\n");
     194               0 :   }
     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               0 :     fprintf(stderr,
     204                 :             "UnitTest_WeirdBuffers: NULL buffer for NaClErrorGioGetOutput"
     205                 :             " failed\n");
     206               0 :     goto giveup;
     207                 :   }
     208               1 :   if (0 != NaClErrorGioGetOutput(neg,
     209                 :                                  small_buffer,
     210                 :                                  NACL_ARRAY_SIZE(small_buffer))) {
     211               0 :     ++num_errors;
     212               0 :     fprintf(stderr,
     213                 :             "UnitTest_WeirdBuffers: small buffer with no output failed\n");
     214               0 :     goto giveup;
     215                 :   }
     216                 : 
     217                 :   /* now make the buffer non-empty */
     218                 : 
     219               1 :   written = (*NACL_VTBL(Gio, neg)->Write)((struct Gio *) neg,
     220                 :                                           ktest_string, test_string_len);
     221               1 :   if (test_string_len != written) {
     222               0 :     ++num_errors;
     223               0 :     fprintf(stderr,
     224                 :             "UnitTest_WeirdBuffers: writing %"NACL_PRIuS" bytes failed?!?\n",
     225                 :             test_string_len);
     226               0 :     goto giveup;
     227                 :   }
     228               1 :   small_buffer[0] = 'x';  /* different from '1' */
     229               1 :   actual = NaClErrorGioGetOutput(neg,
     230                 :                                  small_buffer, NACL_ARRAY_SIZE(small_buffer));
     231               1 :   if (test_string_len != actual) {
     232               0 :     ++num_errors;
     233               0 :     fprintf(stderr,
     234                 :             ("UnitTest_WeirdBuffers: too small buffer did not report actual"
     235                 :              " required size, expected %"NACL_PRIuS", got %"NACL_PRIuS"\n"),
     236                 :             test_string_len, actual);
     237               0 :     goto giveup;
     238                 :   }
     239               1 :   if (small_buffer[0] != ktest_string[0]) {
     240               0 :     ++num_errors;
     241               0 :     fprintf(stderr,
     242                 :             ("UnitTest_WeirdBuffers: partial buffer not filled, expected"
     243                 :              " '1', got '%c'\n"),
     244                 :             small_buffer[0]);
     245               0 :     goto giveup;
     246                 :   }
     247               1 :   actual = NaClErrorGioGetOutput(neg,
     248                 :                                  large_buffer, NACL_ARRAY_SIZE(large_buffer));
     249               1 :   if (test_string_len != actual) {
     250               0 :     ++num_errors;
     251               0 :     fprintf(stderr,
     252                 :             ("UnitTest_WeirdBuffers: large buffer fill did not report actual"
     253                 :              " output size, expected %"NACL_PRIuS", got %"NACL_PRIuS"\n"),
     254                 :             test_string_len, actual);
     255               0 :     goto giveup;
     256                 :   }
     257              20 :   for (ix = 0; ix < test_string_len; ++ix) {
     258               9 :     if (large_buffer[ix] != ktest_string[ix]) {
     259               0 :       ++num_errors;
     260               0 :       fprintf(stderr,
     261                 :               ("UnitTest_WeirdBuffers: large buffer content wrong at ix %"
     262                 :                NACL_PRIuS": expected '%c', got '%c'\n"),
     263                 :               ix, 0xff & ktest_string[ix], 0xff & large_buffer[ix]);
     264               0 :     }
     265              10 :   }
     266                 :  giveup:
     267               1 :   TestGioRecycler(neg);
     268               1 :   if (g_verbosity) {
     269               0 :     printf("UnitTest_BasicCtorDtor: %"NACL_PRIuS" error(s)\n", num_errors);
     270               0 :   }
     271               1 :   return num_errors;
     272                 : }
     273                 : 
     274                 : size_t UnitTest_GenerateRandomOutput(void) {
     275            1000 :   struct NaClErrorGio *neg;
     276            2000 :   size_t num_errors = 0;
     277            1000 :   char output_tail[NACL_ERROR_GIO_MAX_BYTES];
     278            1000 :   size_t output_bytes;
     279            1000 :   size_t output_discarded_bytes;
     280            1000 :   size_t output_saved_tail_bytes;
     281            1000 :   size_t ix;
     282            1000 :   size_t write_chunk_size;
     283            1000 :   char write_chunk[MAX_WRITE_CHUNK_SIZE];
     284            1000 :   size_t jx;
     285            1000 :   ssize_t written;
     286            1000 :   char error_gio_content[NACL_ERROR_GIO_MAX_BYTES];
     287            1000 :   size_t error_gio_content_bytes;
     288                 : 
     289            1000 :   if (g_verbosity > 0) {
     290               0 :     printf("UnitTest_GenerateRandomOutput\n");
     291               0 :   }
     292                 : 
     293            1000 :   neg = TestGioFactory();
     294            1000 :   if (NULL == neg) {
     295               0 :     fprintf(stderr,
     296                 :             ("UnitTest_GenerateRandomOutput: TestGioFactory"
     297                 :              " construction failed\n"));
     298               0 :     ++num_errors;
     299               0 :     goto giveup;
     300                 :   }
     301                 : 
     302            1000 :   output_bytes = g_output_bytes_min +
     303            1000 :       (rand() % (g_output_bytes_max - g_output_bytes_min));
     304                 : 
     305            1000 :   if (output_bytes > NACL_ARRAY_SIZE(output_tail)) {
     306             743 :     output_saved_tail_bytes = NACL_ARRAY_SIZE(output_tail);
     307             743 :     output_discarded_bytes = output_bytes - output_saved_tail_bytes;
     308             743 :   } else {
     309             257 :     output_saved_tail_bytes = output_bytes;
     310             257 :     output_discarded_bytes = 0;
     311                 :   }
     312                 : 
     313           38744 :   for (ix = 0; ix < output_discarded_bytes; ) {
     314           36744 :     write_chunk_size = rand() % NACL_ARRAY_SIZE(write_chunk);
     315           36744 :     if (write_chunk_size > output_discarded_bytes - ix) {
     316             700 :       write_chunk_size = output_discarded_bytes - ix;
     317             700 :     }
     318         1197698 :     for (jx = 0; jx < write_chunk_size; ++jx) {
     319          562105 :       write_chunk[jx] = rand();  /* not efficient use of rng */
     320          562105 :     }
     321           36744 :     written = (*NACL_VTBL(Gio, neg)->Write)((struct Gio *) neg,
     322                 :                                             write_chunk, write_chunk_size);
     323           36744 :     if (written < 0) {
     324               0 :       ++num_errors;
     325               0 :       fprintf(stderr,
     326                 :               ("UnitTest_GenerateRandomOutput: Write method returned %"
     327                 :                NACL_PRIdS"\n"),
     328                 :               written);
     329               0 :       goto abort_test;
     330                 :     }
     331           36744 :     ix += (size_t) written;
     332           36744 :   }
     333           31971 :   for (ix = 0; ix < output_saved_tail_bytes; ) {
     334           29971 :     write_chunk_size = rand() % NACL_ARRAY_SIZE(write_chunk);
     335           29971 :     if (write_chunk_size > output_saved_tail_bytes - ix) {
     336             949 :       write_chunk_size = output_saved_tail_bytes - ix;
     337             949 :     }
     338          966010 :     for (jx = 0; jx < write_chunk_size; ++jx) {
     339          453034 :       write_chunk[jx] = rand();  /* not efficient use of rng */
     340          453034 :     }
     341           29971 :     written = (*NACL_VTBL(Gio, neg)->Write)((struct Gio *) neg,
     342                 :                                             write_chunk, write_chunk_size);
     343           29971 :     if (written < 0) {
     344               0 :       ++num_errors;
     345               0 :       fprintf(stderr,
     346                 :               ("UnitTest_GenerateRandomOutput: Write method returned %"
     347                 :                NACL_PRIdS"\n"),
     348                 :               written);
     349               0 :       goto abort_test;
     350                 :     }
     351          966010 :     for (jx = 0; jx < (size_t) written; ++jx) {
     352          453034 :       output_tail[ix + jx] = write_chunk[jx];
     353          453034 :     }
     354           29971 :     ix += (size_t) written;
     355           29971 :   }
     356                 :   /*
     357                 :    * Check that the final output Gio actually captured the number of bytes
     358                 :    * that we think should have been captured.
     359                 :    */
     360            1000 :   if (output_saved_tail_bytes !=
     361                 :       ((struct TailGio *) neg->pass_through)->num_bytes) {
     362               0 :     ++num_errors;
     363               0 :     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                 :             output_saved_tail_bytes);
     368               0 :   }
     369                 :   /*
     370                 :    * Check that the final output Gio actually saw the number of bytes
     371                 :    * that we think should have been output.
     372                 :    */
     373            1000 :   if (output_bytes !=
     374                 :       ((struct TailGio *) neg->pass_through)->total_output_bytes) {
     375               0 :     ++num_errors;
     376               0 :     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                 :             output_bytes);
     381               0 :   }
     382                 :   /*
     383                 :    * Compare output_tail with NaClErrorGioGetOutput output, and with
     384                 :    * TailGio buffer.
     385                 :    */
     386                 :   error_gio_content_bytes =
     387            1000 :       NaClErrorGioGetOutput(neg, error_gio_content,
     388                 :                             NACL_ARRAY_SIZE(error_gio_content));
     389            1000 :   if (output_saved_tail_bytes != error_gio_content_bytes) {
     390               0 :     ++num_errors;
     391               0 :     fprintf(stderr,
     392                 :             ("UnitTest_GenerateRandomOutput: NaClErrorGio buffer wrong size:"
     393                 :              " got %"NACL_PRIuS", expected %"NACL_PRIuS"!\n"),
     394                 :             error_gio_content_bytes, output_saved_tail_bytes);
     395               0 :   }
     396          908068 :   for (ix = 0; ix < error_gio_content_bytes; ++ix) {
     397          453034 :     if (output_tail[ix] != error_gio_content[ix]) {
     398               0 :       fprintf(stderr,
     399                 :               ("UnitTest_GenerateRandomOutput: byte %"NACL_PRIuS
     400                 :                ": wrote %02x, got %02x\n"),
     401                 :               ix, 0xff & output_tail[ix], 0xff & error_gio_content[ix]);
     402               0 :       ++num_errors;
     403               0 :     }
     404          453034 :     if (output_tail[ix] !=
     405                 :         ((struct TailGio *) neg->pass_through)->buffer[ix]) {
     406               0 :       fprintf(stderr,
     407                 :               ("UnitTest_GenerateRandomOutput: byte %"NACL_PRIuS
     408                 :                ": wrote %02x, wrote through %02x\n"),
     409                 :               ix, 0xff & output_tail[ix], 0xff & error_gio_content[ix]);
     410               0 :       ++num_errors;
     411               0 :     }
     412          454034 :   }
     413                 :  abort_test:
     414            1000 :   TestGioRecycler(neg);
     415                 :  giveup:
     416            1000 :   if (g_verbosity > 0) {
     417               0 :     printf("UnitTest_GenerateRandomOutput: %"NACL_PRIuS" error(s)\n",
     418                 :            num_errors);
     419               0 :   }
     420            1000 :   return num_errors;
     421                 : }
     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               1 :   int opt;
     443               1 :   size_t num_errors = 0;
     444               1 :   size_t num_iter = 100000;
     445               1 :   size_t iter;
     446               1 :   unsigned seed = (unsigned) time((time_t *) NULL);
     447                 : 
     448               3 :   while (-1 != (opt = getopt(ac, av, "b:B:n:s:v"))) {
     449               2 :     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               0 :         break;
     464                 :     }
     465               1 :   }
     466               1 :   if (g_output_bytes_max < g_output_bytes_min) {
     467               0 :     fprintf(stderr,
     468                 :             "nacl_error_gio_test: -b min_bytes value should not be larger"
     469                 :             " 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            2002 :   for (iter = 0; iter < num_iter; ++iter) {
     479            1000 :     num_errors += UnitTest_GenerateRandomOutput();
     480            1000 :   }
     481                 : 
     482               1 :   return num_errors;
     483               1 : }

Generated by: LCOV version 1.7