LCOV - code coverage report
Current view: directory - src/trusted/interval_multiset - nacl_interval_test.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 166 127 76.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/trusted/interval_multiset/nacl_interval_multiset.h"
      13                 : #include "native_client/src/trusted/interval_multiset/nacl_interval_list.h"
      14                 : 
      15                 : #include "native_client/src/include/nacl_macros.h"
      16                 : #include "native_client/src/include/portability.h"
      17                 : #include "native_client/src/shared/platform/platform_init.h"
      18                 : #include "native_client/src/shared/platform/nacl_check.h"
      19                 : #include "native_client/src/shared/platform/nacl_log.h"
      20                 : 
      21                 : #define MAX_INTERVAL_TREE_KINDS     8
      22                 : #define MAX_INPUT_LINE_LENGTH       4096
      23                 : #define DEFAULT_COUNT_WHEN_RANDOM   8192
      24                 : 
      25                 : #define OP_ADD      0
      26                 : #define OP_REMOVE   1
      27                 : #define OP_PROBE    2
      28                 : /*
      29                 :  * Input/Output format:
      30                 :  *
      31                 :  * If a line contains #, it and all characters following to the
      32                 :  * newline are discarded.  Lines containing only space and tabs are
      33                 :  * ignored.  (Manually generated test inputs can have comments.)
      34                 :  * Maximum line length is MAX_INPUT_LINE_LENGTH.
      35                 :  *
      36                 :  * All other lines should be four integers of the form:
      37                 :  *
      38                 :  *   op first_val last_val expected_output
      39                 :  *
      40                 :  * "op" specifies which virtual function to invoke and is interpreted
      41                 :  * as per the OP_* defines above.
      42                 :  *
      43                 :  * For Add and Remove, "expected_output" is don't-care (ignored). For
      44                 :  * OverlapsWith, "expected_output" is the expected return value (since
      45                 :  * it's C-style bool, encoded as 0 or 1).  When random operations are
      46                 :  * generated, we encode "unknown" or "don't care" as -1 in
      47                 :  * "expected_output" for use OverlapsWith, since we don't otherwise
      48                 :  * compute separately what the expected output should be.
      49                 :  *
      50                 :  * For the output case, e.g., generated with randomly chosen calls and
      51                 :  * parameters, "expected_output" is the actual return value from
      52                 :  * OverlapsWith.  An initial comment line contains the random seed
      53                 :  * used.
      54                 :  */
      55                 : 
      56                 : uint32_t g_max_random_region_size = 8 << 20;
      57                 : 
      58                 : struct Op {
      59                 :   int opcode;
      60                 :   uint32_t first_val;
      61                 :   uint32_t last_val;
      62                 :   int expected_output;
      63                 : };
      64                 : 
      65               1 : void StripComment(char *line) {
      66                 :   char *comment;
      67               1 :   if (NULL != (comment = strchr(line, '#'))) {
      68               1 :     *comment = '\0';
      69                 :   }
      70               1 : }
      71                 : 
      72               1 : int LineContainsOnlyWhitespace(char *line) {
      73               1 :   while ('\0' != *line) {
      74               1 :     switch (*line) {
      75                 :       case ' ':
      76                 :       case '\t':
      77                 :       case '\n':
      78               1 :         ++line;
      79               1 :         continue;
      80                 :       default:
      81               1 :         return 0;
      82                 :     }
      83                 :   }
      84               1 :   return 1;
      85               1 : }
      86                 : 
      87               1 : int ReadOp(struct Op *op, FILE *iob) {
      88                 :   char line[MAX_INPUT_LINE_LENGTH];
      89               1 :   int  line_num = 0;
      90                 : 
      91                 :   for (;;) {
      92               1 :     ++line_num;
      93               1 :     if (!fgets(line, sizeof line, iob)) {
      94               1 :       return 0;
      95                 :     }
      96               1 :     StripComment(line);
      97               1 :     if (LineContainsOnlyWhitespace(line)) {
      98               1 :       continue;
      99                 :     }
     100                 :     /*
     101                 :      * we cheat -- NACL_SCNu32 macros are not defined, and we know
     102                 :      * that the printf format specifier won't work for scanf since on
     103                 :      * windows we use the I32 notation for windows printf, but windows
     104                 :      * scanf doesn't understand that notation.
     105                 :      */
     106                 :     if (4 == sscanf(line, "%d%u%u%d",
     107                 :                     &op->opcode, &op->first_val, &op->last_val,
     108               1 :                     &op->expected_output)) {
     109               1 :       return 1;
     110                 :     }
     111               0 :     fprintf(stderr, "op syntax error in line %d, ignoring\n", line_num);
     112               0 :     exit(1);
     113                 :   }
     114               1 : }
     115                 : 
     116               0 : void WriteOp(FILE *iob, struct Op *op) {
     117                 :   fprintf(iob, "%d %"NACL_PRIu32" %"NACL_PRIu32" %d\n",
     118               0 :           op->opcode, op->first_val, op->last_val, op->expected_output);
     119               0 : }
     120                 : 
     121                 : struct Op *extant_intervals = NULL;
     122                 : size_t num_extant_intervals = 0;
     123                 : size_t size_extant_intervals = 0;
     124                 : 
     125               1 : void AddInterval(struct Op const *op) {
     126                 :   size_t target_num;
     127                 : 
     128               1 :   if (num_extant_intervals == size_extant_intervals) {
     129               1 :     target_num = 2 * size_extant_intervals;
     130               1 :     if (target_num == 0) {
     131               1 :       target_num = 32;
     132                 :     }
     133                 :     extant_intervals = (struct Op *) realloc(
     134                 :         extant_intervals,
     135               1 :         target_num * sizeof *extant_intervals);
     136               1 :     if (NULL == extant_intervals) {
     137                 :       NaClLog(LOG_FATAL,
     138               0 :               "nacl_interval_test: no memory for extant intervals\n");
     139                 :     }
     140               1 :     size_extant_intervals = target_num;
     141                 :   }
     142                 :   NaClLog(2, ("adding at %"NACL_PRIuS" [%u,%u], size %"NACL_PRIuS"\n"),
     143                 :           num_extant_intervals,
     144                 :           op->first_val, op->last_val,
     145               1 :           size_extant_intervals);
     146               1 :   extant_intervals[num_extant_intervals++] = *op;
     147               1 : }
     148                 : 
     149               1 : void RemoveIntervalAtIndex(size_t ix) {
     150                 :   NaClLog(2, "removing ix %"NACL_PRIuS", contents [%u,%u]\n",
     151               1 :           ix, extant_intervals[ix].first_val, extant_intervals[ix].last_val);
     152               1 :   extant_intervals[ix] = extant_intervals[--num_extant_intervals];
     153               1 : }
     154                 : 
     155               1 : void GenerateRandomOp(struct Op *op) {
     156               1 :   switch (rand() % 5) {
     157                 :     case 0:
     158               1 :       op->opcode = OP_ADD;
     159               1 :       break;
     160                 :     case 1:
     161               1 :       op->opcode = OP_REMOVE;
     162               1 :       break;
     163                 :     case 2:
     164                 :     case 3:
     165                 :     case 4:
     166               1 :       op->opcode = OP_PROBE;
     167                 :       break;
     168                 :   }
     169               1 :   if (op->opcode == OP_REMOVE && num_extant_intervals == 0) {
     170               1 :     op->opcode = OP_ADD;
     171                 :   }
     172               1 :   if (op->opcode != OP_REMOVE) {
     173               1 :     op->expected_output = -1;
     174                 :     do {
     175               1 :       op->first_val = rand();
     176               1 :       op->last_val = op->first_val + (rand() % g_max_random_region_size);
     177               1 :     } while (op->first_val > op->last_val);
     178                 :   }
     179               1 :   if (op->opcode == OP_ADD) {
     180               1 :     AddInterval(op);
     181               1 :   } else if (op->opcode == OP_REMOVE) {
     182               1 :     size_t ix = rand() % num_extant_intervals;
     183               1 :     op->first_val = extant_intervals[ix].first_val;
     184               1 :     op->last_val = extant_intervals[ix].last_val;
     185               1 :     op->expected_output = -1;
     186               1 :     RemoveIntervalAtIndex(ix);
     187                 :   }
     188                 :   NaClLog(3, "Gen (%d, %u, %u, %d)\n",
     189               1 :           op->opcode, op->first_val, op->last_val, op->expected_output);
     190               1 : }
     191                 : 
     192               1 : int main(int ac, char **av) {
     193               1 :   int count = -1;  /* until EOF if a file is specified */
     194               1 :   unsigned seed = (unsigned) time((time_t *) NULL);
     195               1 :   FILE *out_file = NULL;
     196               1 :   FILE *in_file = NULL;
     197                 :   char const *default_kinds[] = {
     198               1 :     "NaClIntervalListMultiset",
     199               1 :     "NaClIntervalRangeTree",
     200                 :   };
     201                 :   char const *kind[MAX_INTERVAL_TREE_KINDS];
     202               1 :   size_t num_kinds = 0;
     203                 :   int opt;
     204                 :   size_t ix;
     205                 :   int iter;
     206                 :   struct Op oper;
     207               1 :   size_t error_count = 0;
     208                 :   struct NaClIntervalMultiset *nis[MAX_INTERVAL_TREE_KINDS];
     209                 :   int result;
     210                 : 
     211               1 :   NaClPlatformInit();
     212                 : 
     213               1 :   CHECK(NACL_ARRAY_SIZE(default_kinds) <= NACL_ARRAY_SIZE(kind));
     214                 : 
     215               1 :   while (-1 != (opt = getopt(ac, av, "c:i:k:m:o:s:v"))) {
     216               1 :     switch (opt) {
     217                 :       case 'c':
     218               1 :         count = strtoul(optarg, (char **) NULL, 0);
     219               1 :         break;
     220                 :       case 'i':
     221               1 :         in_file = fopen(optarg, "r");
     222               1 :         if (NULL == in_file) {
     223               0 :           perror("nacl_interval_test");
     224               0 :           fprintf(stderr, "Could not open \"%s\" as input file\n", optarg);
     225               0 :           return 1;
     226                 :         }
     227               1 :         break;
     228                 :       case 'k':
     229               1 :         if (num_kinds == MAX_INTERVAL_TREE_KINDS) {
     230               0 :           fprintf(stderr, "too many interval tree kinds specified\n");
     231               0 :           return 2;
     232                 :         }
     233               1 :         kind[num_kinds++] = optarg;
     234               1 :         break;
     235                 :       case 'm':
     236               0 :         g_max_random_region_size = strtoul(optarg, (char **) NULL, 0);
     237               0 :         break;
     238                 :       case 'o':
     239               0 :         out_file = fopen(optarg, "w");
     240               0 :         if (NULL == out_file) {
     241               0 :           perror("nacl_interval_test");
     242               0 :           fprintf(stderr, "Could not open \"%s\" as output file\n", optarg);
     243               0 :           return 3;
     244                 :         }
     245               0 :         break;
     246                 :       case 's':
     247               0 :         seed = strtoul(optarg, (char **) NULL, 0);
     248               0 :         break;
     249                 :       case 'v':
     250               0 :         NaClLogIncrVerbosity();
     251               0 :         break;
     252                 :       default:
     253                 :         fprintf(stderr,
     254                 :                 "Usage: nacl_interval_test [-s seed] [-c count]\n"
     255               0 :                 "         [-i test_input_file] [-o test_output_file]\n");
     256               0 :         return 4;
     257                 :     }
     258               1 :   }
     259                 : 
     260               1 :   if (0 == num_kinds) {
     261               0 :     for (ix = 0; ix < NACL_ARRAY_SIZE(default_kinds); ++ix) {
     262               0 :       kind[ix] = default_kinds[ix];
     263               0 :     }
     264               0 :     num_kinds = NACL_ARRAY_SIZE(default_kinds);
     265                 :   }
     266                 : 
     267                 :   /*
     268                 :    * When there are bugs that corrupt recursive data structures and
     269                 :    * printing them involve recursive routines that do not flush
     270                 :    * buffers (even if line buffered, do not always output a newline),
     271                 :    * it is a good idea to unbuffer output so that the output just
     272                 :    * before a crash is visible.  This is a general debugging strategy
     273                 :    * -- this test code served both as a debugging aid when bringing up
     274                 :    * new data structures and as a unit / regression test, and while
     275                 :    * its role as a unit / regression test probably doesn't require
     276                 :    * unbuffered output, we leave this in.
     277                 :    */
     278               1 :   setvbuf(stdout, NULL, _IONBF, 0);
     279               1 :   setvbuf(stderr, NULL, _IONBF, 0);
     280                 : 
     281               1 :   srand(seed);
     282               1 :   if (NULL == in_file && -1 == count) {
     283               0 :     count = DEFAULT_COUNT_WHEN_RANDOM;
     284                 :   }
     285               1 :   if (NULL != out_file) {
     286               0 :     fprintf(out_file, "# seed %u\n", seed);
     287                 :   }
     288                 :   /* always print to stdout so test framework can capture and log it */
     289               1 :   if (NULL == in_file) {
     290               1 :     printf("# seed %u\n", seed);
     291               1 :   } else {
     292               1 :     printf("# input file used, not randomly generated test cases.\n");
     293                 :   }
     294               1 :   fflush(stdout);
     295                 :   /* ensure seed is always visible, even if setvbuf above is later deleted */
     296                 : 
     297               1 :   for (ix = 0; ix < num_kinds; ++ix) {
     298               1 :     nis[ix] = NaClIntervalMultisetFactory(kind[ix]);
     299               1 :     if (NULL == nis[ix]) {
     300                 :       fprintf(stderr,
     301               0 :               "NaClIntervalMultisetFactory(%s) yielded NULL\n", kind[ix]);
     302               0 :       return 5;
     303                 :     }
     304               1 :   }
     305                 : 
     306               1 :   for (iter = 0; (-1 == count) || (iter < count); ++iter) {
     307               1 :     if (NULL == in_file) {
     308               1 :       GenerateRandomOp(&oper);
     309               1 :     } else {
     310               1 :       if (!ReadOp(&oper, in_file)) {
     311               1 :         break;
     312                 :       }
     313                 :     }
     314                 :     NaClLog(3, "Processing (%d, %u, %u, %d)\n",
     315               1 :           oper.opcode, oper.first_val, oper.last_val, oper.expected_output);
     316               1 :     for (ix = 0; ix < num_kinds; ++ix) {
     317               1 :       switch (oper.opcode) {
     318                 :         case OP_ADD:
     319                 :           (*nis[ix]->vtbl->AddInterval)(nis[ix],
     320                 :                                         oper.first_val,
     321               1 :                                         oper.last_val);
     322               1 :           break;
     323                 :         case OP_REMOVE:
     324                 :           (*nis[ix]->vtbl->RemoveInterval)(nis[ix],
     325                 :                                            oper.first_val,
     326               1 :                                            oper.last_val);
     327               1 :           break;
     328                 :         case OP_PROBE:
     329                 :           result = (*nis[ix]->vtbl->OverlapsWith)(nis[ix],
     330                 :                                                   oper.first_val,
     331               1 :                                                   oper.last_val);
     332                 :           if (oper.expected_output != -1 &&
     333               1 :               oper.expected_output != result) {
     334                 :             printf("OverlapsWith(%d,%d)=%d, expected %d\n",
     335               0 :                    oper.first_val, oper.last_val, result, oper.expected_output);
     336               0 :             printf("FAIL\n");
     337               0 :             if (0 == ++error_count) ++error_count;
     338                 :           }
     339               1 :           oper.expected_output = result;
     340               1 :           break;
     341                 :         default:
     342               0 :           WriteOp(stderr, &oper);
     343               0 :           NaClLog(LOG_FATAL, "nacl_interval_test: internal error\n");
     344                 :       }
     345               1 :     }
     346               1 :     if (NULL != out_file) {
     347               0 :       WriteOp(out_file, &oper);
     348                 :     }
     349               1 :   }
     350                 : 
     351               1 :   printf("%"NACL_PRIuS" errors\n", error_count);
     352                 : 
     353               1 :   for (ix = 0; ix < num_kinds; ++ix) {
     354               1 :     NaClIntervalMultisetDelete(nis[ix]);
     355               1 :     nis[ix] = NULL;
     356               1 :   }
     357                 : 
     358               1 :   NaClPlatformFini();
     359               1 :   return error_count != 0;
     360               1 : }

Generated by: LCOV version 1.7