LCOV - code coverage report
Current view: directory - src/trusted/interval_multiset - nacl_interval_test.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 191 145 75.9 %
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/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            7736 : void StripComment(char *line) {
      66            7736 :   char *comment;
      67            7736 :   if (NULL != (comment = strchr(line, '#'))) {
      68              20 :     *comment = '\0';
      69              20 :   }
      70            7736 : }
      71                 : 
      72            7736 : int LineContainsOnlyWhitespace(char *line) {
      73           15492 :   while ('\0' != *line) {
      74            7720 :     switch (*line) {
      75                 :       case ' ':
      76                 :       case '\t':
      77                 :       case '\n':
      78              20 :         ++line;
      79              20 :         continue;
      80                 :       default:
      81            7700 :         return 0;
      82                 :     }
      83                 :   }
      84              36 :   return 1;
      85            7736 : }
      86                 : 
      87            7704 : int ReadOp(struct Op *op, FILE *iob) {
      88            7704 :   char line[MAX_INPUT_LINE_LENGTH];
      89            7704 :   int  line_num = 0;
      90                 : 
      91            7704 :   for (;;) {
      92            7740 :     ++line_num;
      93            7740 :     if (!fgets(line, sizeof line, iob)) {
      94               4 :       return 0;
      95                 :     }
      96            7736 :     StripComment(line);
      97            7736 :     if (LineContainsOnlyWhitespace(line)) {
      98              36 :       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            7700 :     if (4 == sscanf(line, "%d%u%u%d",
     107                 :                     &op->opcode, &op->first_val, &op->last_val,
     108                 :                     &op->expected_output)) {
     109            7700 :       return 1;
     110                 :     }
     111               0 :     fprintf(stderr, "op syntax error in line %d, ignoring\n", line_num);
     112               0 :     exit(1);
     113                 :   }
     114            7704 : }
     115                 : 
     116               0 : void WriteOp(FILE *iob, struct Op *op) {
     117               0 :   fprintf(iob, "%d %"NACL_PRIu32" %"NACL_PRIu32" %d\n",
     118                 :           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          210276 : void AddInterval(struct Op const *op) {
     126          210276 :   size_t target_num;
     127                 : 
     128          210276 :   if (num_extant_intervals == size_extant_intervals) {
     129               9 :     target_num = 2 * size_extant_intervals;
     130               9 :     if (target_num == 0) {
     131               2 :       target_num = 32;
     132               2 :     }
     133               9 :     extant_intervals = (struct Op *) realloc(
     134                 :         extant_intervals,
     135                 :         target_num * sizeof *extant_intervals);
     136               9 :     if (NULL == extant_intervals) {
     137               0 :       NaClLog(LOG_FATAL,
     138                 :               "nacl_interval_test: no memory for extant intervals\n");
     139               0 :     }
     140               9 :     size_extant_intervals = target_num;
     141               9 :   }
     142          210276 :   NaClLog(2, ("adding at %"NACL_PRIuS" [%u,%u], size %"NACL_PRIuS"\n"),
     143                 :           num_extant_intervals,
     144                 :           op->first_val, op->last_val,
     145                 :           size_extant_intervals);
     146          210276 :   extant_intervals[num_extant_intervals++] = *op;
     147          210276 : }
     148                 : 
     149          210026 : void RemoveIntervalAtIndex(size_t ix) {
     150          210026 :   NaClLog(2, "removing ix %"NACL_PRIuS", contents [%u,%u]\n",
     151                 :           ix, extant_intervals[ix].first_val, extant_intervals[ix].last_val);
     152          210026 :   extant_intervals[ix] = extant_intervals[--num_extant_intervals];
     153          210026 : }
     154                 : 
     155         2100000 : void GenerateRandomOp(struct Op *op) {
     156         2100000 :   switch (rand() % 5) {
     157                 :     case 0:
     158          210085 :       op->opcode = OP_ADD;
     159          210085 :       break;
     160                 :     case 1:
     161          210217 :       op->opcode = OP_REMOVE;
     162          210217 :       break;
     163                 :     case 2:
     164                 :     case 3:
     165                 :     case 4:
     166          629698 :       op->opcode = OP_PROBE;
     167          629698 :       break;
     168                 :   }
     169         1260217 :   if (op->opcode == OP_REMOVE && num_extant_intervals == 0) {
     170             191 :     op->opcode = OP_ADD;
     171             191 :   }
     172         1050000 :   if (op->opcode != OP_REMOVE) {
     173          839974 :     op->expected_output = -1;
     174          839974 :     do {
     175          839974 :       op->first_val = rand();
     176          839974 :       op->last_val = op->first_val + (rand() % g_max_random_region_size);
     177         1679948 :     } while (op->first_val > op->last_val);
     178          839974 :   }
     179         1050000 :   if (op->opcode == OP_ADD) {
     180          210276 :     AddInterval(op);
     181         1050000 :   } else if (op->opcode == OP_REMOVE) {
     182          210026 :     size_t ix = rand() % num_extant_intervals;
     183          210026 :     op->first_val = extant_intervals[ix].first_val;
     184          210026 :     op->last_val = extant_intervals[ix].last_val;
     185          210026 :     op->expected_output = -1;
     186          210026 :     RemoveIntervalAtIndex(ix);
     187          210026 :   }
     188         1050000 :   NaClLog(3, "Gen (%d, %u, %u, %d)\n",
     189                 :           op->opcode, op->first_val, op->last_val, op->expected_output);
     190         1050000 : }
     191                 : 
     192               6 : int main(int ac, char **av) {
     193               6 :   int count = -1;  /* until EOF if a file is specified */
     194               6 :   unsigned seed = (unsigned) time((time_t *) NULL);
     195               6 :   FILE *out_file = NULL;
     196               6 :   FILE *in_file = NULL;
     197               6 :   char const *default_kinds[] = {
     198                 :     "NaClIntervalListMultiset",
     199                 :     "NaClIntervalRangeTree",
     200                 :   };
     201               6 :   char const *kind[MAX_INTERVAL_TREE_KINDS];
     202               6 :   size_t num_kinds = 0;
     203               6 :   int opt;
     204               6 :   size_t ix;
     205               6 :   int iter;
     206               6 :   struct Op oper;
     207               6 :   size_t error_count = 0;
     208               6 :   struct NaClIntervalMultiset *nis[MAX_INTERVAL_TREE_KINDS];
     209               6 :   int result;
     210                 : 
     211               6 :   NaClPlatformInit();
     212                 : 
     213              12 :   CHECK(NACL_ARRAY_SIZE(default_kinds) <= NACL_ARRAY_SIZE(kind));
     214                 : 
     215              26 :   while (-1 != (opt = getopt(ac, av, "c:i:k:m:o:s:v"))) {
     216              14 :     switch (opt) {
     217                 :       case 'c':
     218               2 :         count = strtoul(optarg, (char **) NULL, 0);
     219               2 :         break;
     220                 :       case 'i':
     221               4 :         in_file = fopen(optarg, "r");
     222               4 :         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               4 :         break;
     228                 :       case 'k':
     229               8 :         if (num_kinds == MAX_INTERVAL_TREE_KINDS) {
     230               0 :           fprintf(stderr, "too many interval tree kinds specified\n");
     231               0 :           return 2;
     232                 :         }
     233               8 :         kind[num_kinds++] = optarg;
     234               8 :         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               0 :         fprintf(stderr,
     254                 :                 "Usage: nacl_interval_test [-s seed] [-c count]\n"
     255                 :                 "         [-i test_input_file] [-o test_output_file]\n");
     256               0 :         return 4;
     257                 :     }
     258              14 :   }
     259                 : 
     260               6 :   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               0 :   }
     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               6 :   setvbuf(stdout, NULL, _IONBF, 0);
     279               6 :   setvbuf(stderr, NULL, _IONBF, 0);
     280                 : 
     281               6 :   srand(seed);
     282               8 :   if (NULL == in_file && -1 == count) {
     283               0 :     count = DEFAULT_COUNT_WHEN_RANDOM;
     284               0 :   }
     285               6 :   if (NULL != out_file) {
     286               0 :     fprintf(out_file, "# seed %u\n", seed);
     287               0 :   }
     288                 :   /* always print to stdout so test framework can capture and log it */
     289               6 :   if (NULL == in_file) {
     290               2 :     printf("# seed %u\n", seed);
     291               2 :   } else {
     292               4 :     printf("# input file used, not randomly generated test cases.\n");
     293                 :   }
     294               6 :   fflush(stdout);
     295                 :   /* ensure seed is always visible, even if setvbuf above is later deleted */
     296                 : 
     297              28 :   for (ix = 0; ix < num_kinds; ++ix) {
     298               8 :     nis[ix] = NaClIntervalMultisetFactory(kind[ix]);
     299               8 :     if (NULL == nis[ix]) {
     300               0 :       fprintf(stderr,
     301                 :               "NaClIntervalMultisetFactory(%s) yielded NULL\n", kind[ix]);
     302               0 :       return 5;
     303                 :     }
     304               8 :   }
     305                 : 
     306         4223120 :   for (iter = 0; (-1 == count) || (iter < count); ++iter) {
     307         1057704 :     if (NULL == in_file) {
     308         1050000 :       GenerateRandomOp(&oper);
     309         1050000 :     } else {
     310            7704 :       if (!ReadOp(&oper, in_file)) {
     311               4 :         break;
     312                 :       }
     313                 :     }
     314         1057700 :     NaClLog(3, "Processing (%d, %u, %u, %d)\n",
     315                 :           oper.opcode, oper.first_val, oper.last_val, oper.expected_output);
     316         6330800 :     for (ix = 0; ix < num_kinds; ++ix) {
     317         2107700 :       switch (oper.opcode) {
     318                 :         case OP_ADD:
     319          422128 :           (*nis[ix]->vtbl->AddInterval)(nis[ix],
     320                 :                                         oper.first_val,
     321                 :                                         oper.last_val);
     322          422128 :           break;
     323                 :         case OP_REMOVE:
     324          421558 :           (*nis[ix]->vtbl->RemoveInterval)(nis[ix],
     325                 :                                            oper.first_val,
     326                 :                                            oper.last_val);
     327          421558 :           break;
     328                 :         case OP_PROBE:
     329         1264014 :           result = (*nis[ix]->vtbl->OverlapsWith)(nis[ix],
     330                 :                                                   oper.first_val,
     331                 :                                                   oper.last_val);
     332         1898330 :           if (oper.expected_output != -1 &&
     333                 :               oper.expected_output != result) {
     334               0 :             printf("OverlapsWith(%d,%d)=%d, expected %d\n",
     335                 :                    oper.first_val, oper.last_val, result, oper.expected_output);
     336               0 :             printf("FAIL\n");
     337               0 :             if (0 == ++error_count) ++error_count;
     338               0 :           }
     339         1264014 :           oper.expected_output = result;
     340         1264014 :           break;
     341                 :         default:
     342               0 :           WriteOp(stderr, &oper);
     343               0 :           NaClLog(LOG_FATAL, "nacl_interval_test: internal error\n");
     344               0 :       }
     345         2107700 :     }
     346         1057700 :     if (NULL != out_file) {
     347               0 :       WriteOp(out_file, &oper);
     348               0 :     }
     349         1057700 :   }
     350                 : 
     351               6 :   printf("%"NACL_PRIuS" errors\n", error_count);
     352                 : 
     353              28 :   for (ix = 0; ix < num_kinds; ++ix) {
     354               8 :     NaClIntervalMultisetDelete(nis[ix]);
     355               8 :     nis[ix] = NULL;
     356               8 :   }
     357                 : 
     358               6 :   NaClPlatformFini();
     359               6 :   return error_count != 0;
     360               6 : }

Generated by: LCOV version 1.7