LCOV - code coverage report
Current view: top level - tests/cframework - tests.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 157 223 70.4 %
Date: 2019-09-12 12:28:41 Functions: 16 24 66.7 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include <string.h>
      10             : #include <tests.h>
      11             : 
      12             : #ifdef HAVE_UNISTD_H
      13             : #include <unistd.h>
      14             : #endif
      15             : 
      16             : #ifdef HAVE_TIME_H
      17             : #include <time.h>
      18             : #endif
      19             : 
      20             : #ifdef HAVE_LOCALE_H
      21             : #include <locale.h>
      22             : #endif
      23             : 
      24             : #ifdef USE_NFTW
      25             : #include <ftw.h>
      26             : #include <stdlib.h>
      27             : #define NOPENFD 20
      28             : #endif
      29             : 
      30             : #include <regex.h>
      31             : 
      32             : #include <kdbinternal.h>
      33             : 
      34             : #ifdef __cplusplus
      35             : extern "C" {
      36             : #endif
      37             : 
      38             : int nbError;
      39             : int nbTest;
      40             : 
      41             : char file[KDB_MAX_PATH_LENGTH];
      42             : char srcdir[KDB_MAX_PATH_LENGTH + 1];
      43             : 
      44             : char * tmpfilename;
      45             : char * tempHome;
      46             : int tempHomeLen;
      47             : char * tempHomeConf;
      48             : 
      49             : /**Does some useful startup.
      50             :  */
      51         189 : int init (int argc, char ** argv)
      52             : {
      53             :         char * tmpvar;
      54             :         int fd;
      55             : 
      56         189 :         if (argc > 1)
      57             :         {
      58         189 :                 strncpy (srcdir, argv[1], sizeof (srcdir) - 1);
      59             :         }
      60             :         else
      61             :         {
      62           0 :                 strncpy (srcdir, BUILTIN_DATA_FOLDER, sizeof (srcdir) - 1);
      63             :         }
      64             : 
      65         189 :         tmpvar = getenv ("TMPDIR");
      66         189 :         if (!tmpvar)
      67             :         {
      68         189 :                 tmpvar = "/tmp";
      69             :         }
      70             :         // check tempvar for trailing slash /
      71         189 :         if (strlen (tmpvar) > 2)
      72             :         {
      73         189 :                 if (tmpvar[strlen (tmpvar) - 1] == '/')
      74             :                 {
      75           0 :                         tmpvar[strlen (tmpvar) - 1] = '\0';
      76             :                 }
      77             :         }
      78             : 
      79         189 :         tempHomeLen = strlen (tmpvar) + 1 + 13 + 6 + 1;
      80         189 :         tempHome = elektraMalloc (tempHomeLen);
      81         189 :         tempHomeConf = elektraMalloc (tempHomeLen + strlen (KDB_DB_USER) + 2);
      82         189 :         succeed_if (tempHome != 0, "elektraMalloc failed");
      83         189 :         snprintf (tempHome, tempHomeLen, "%s/elektra-test.XXXXXX", tmpvar);
      84         189 :         snprintf (tempHomeConf, tempHomeLen, "%s/elektra-test.XXXXXX/" KDB_DB_USER, tmpvar);
      85         189 :         succeed_if (mkdtemp (tempHome) != 0, "mkdtemp failed");
      86         189 :         setenv ("HOME", tempHome, 1);
      87             : 
      88         189 :         atexit (clean_temp_home);
      89             : 
      90         189 :         int tmpfilenameLen = tempHomeLen + 1 + 12 + 6 + 1;
      91         189 :         tmpfilename = elektraMalloc (tmpfilenameLen);
      92         189 :         succeed_if (tmpfilenameLen != 0, "elektraMalloc failed");
      93         189 :         snprintf (tmpfilename, tmpfilenameLen, "%s/elektra-tmp.XXXXXX", tempHome);
      94         189 :         fd = mkstemp (tmpfilename);
      95         189 :         succeed_if (fd != -1, "mkstemp failed");
      96         189 :         close (fd);
      97             : 
      98         189 :         return 0;
      99             : }
     100             : 
     101             : /**Create a root key for a backend.
     102             :  *
     103             :  * @return an allocated root key */
     104           0 : Key * create_root_key (const char * backendName)
     105             : {
     106           0 :         Key * root = keyNew ("user/tests", KEY_END);
     107             :         /*Make mountpoint beneath root, and do all tests here*/
     108           0 :         keyAddBaseName (root, backendName);
     109           0 :         keySetString (root, backendName);
     110           0 :         keySetString (root, backendName);
     111           0 :         return root;
     112             : }
     113             : 
     114             : /**Create a configuration keyset for a backend.
     115             :  *
     116             :  * @return an allocated configuration keyset for a backend*/
     117           0 : KeySet * create_conf (const char * filename)
     118             : {
     119           0 :         return ksNew (2, keyNew ("system/path", KEY_VALUE, filename, KEY_END), KS_END);
     120             : }
     121             : 
     122             : 
     123         125 : int compare_line_files_fun (const char * filename, const char * genfilename, int (*cmpFun) (const char *, const char *, size_t n))
     124             : {
     125             :         FILE *forg, *fgen;
     126             :         char bufferorg[BUFFER_LENGTH + 1];
     127             :         char buffergen[BUFFER_LENGTH + 1];
     128         125 :         char * org = 0;
     129         125 :         char * gen = 0;
     130         125 :         int line = 0;
     131         125 :         int remainingBufferLength = BUFFER_LENGTH;
     132             : 
     133         125 :         forg = fopen (filename, "r");
     134         125 :         fgen = fopen (genfilename, "r");
     135             : 
     136         125 :         strncpy (bufferorg, "could not open file, orig: ", BUFFER_LENGTH);
     137         125 :         remainingBufferLength -= strlen ("could not open file, orig: ");
     138         125 :         strncat (bufferorg, filename, remainingBufferLength);
     139         125 :         remainingBufferLength -= strlen (filename);
     140         125 :         strncat (bufferorg, " gen: ", remainingBufferLength);
     141         125 :         remainingBufferLength -= strlen (" gen: ");
     142         125 :         strncat (bufferorg, genfilename, remainingBufferLength);
     143             : 
     144         125 :         exit_if_fail (forg && fgen, bufferorg);
     145             : 
     146        2121 :         while ((org = fgets (bufferorg, BUFFER_LENGTH, forg)) && (gen = fgets (buffergen, BUFFER_LENGTH, fgen)))
     147             :         {
     148        1996 :                 line++;
     149        1996 :                 if ((*cmpFun) (bufferorg, buffergen, BUFFER_LENGTH))
     150             :                 {
     151           0 :                         printf ("Compare <%s>, with <%s>\n", bufferorg, buffergen);
     152           0 :                         printf ("in file %s, line %d.\n", filename, line);
     153           0 :                         succeed_if (0, "comparing lines failed");
     154             :                         goto error;
     155             :                 }
     156             :         }
     157             : 
     158         125 :         if (org || fgets (buffergen, BUFFER_LENGTH, fgen))
     159             :         {
     160           0 :                 printf ("The files do not have same number of lines (%d): %s.\n", line, filename);
     161           0 :                 succeed_if (0, "comparing files failed");
     162             :                 goto error;
     163             :         }
     164             : 
     165         125 :         fclose (forg);
     166         125 :         fclose (fgen);
     167         125 :         return 1;
     168             : 
     169             : error:
     170           0 :         fclose (forg);
     171           0 :         fclose (fgen);
     172           0 :         return 0;
     173             : }
     174             : 
     175             : 
     176             : /**
     177             :  * @brief Compare two files line by line
     178             :  *
     179             :  * @param filename first file
     180             :  * @param genfilename file to compare with
     181             :  *
     182             :  * @retval 0 on errors (succeed_if already executed)
     183             :  * @retval 1 on success
     184             :  */
     185         123 : int compare_line_files (const char * filename, const char * genfilename)
     186             : {
     187         123 :         return compare_line_files_fun (filename, genfilename, &strncmp);
     188             : }
     189             : 
     190             : 
     191             : /**
     192             :  * @brief Compare regex in pattern to str
     193             :  *
     194             :  * @param pattern char * representing a regex pattern
     195             :  * @param str char * we compare the pattern to
     196             :  *
     197             :  * @retval 1 if pattern is invalid or does not match str
     198             :  * @retval 0 on success
     199             :  */
     200           4 : int regexcmp (const char * pattern, const char * str, size_t n ELEKTRA_UNUSED)
     201             : {
     202             :         int status;
     203             :         regex_t re;
     204             : 
     205           4 :         if (regcomp (&re, pattern, REG_EXTENDED | REG_NOSUB) != 0)
     206             :         {
     207             :                 return (1);
     208             :         }
     209           4 :         status = regexec (&re, str, (size_t) 0, NULL, 0);
     210           4 :         regfree (&re);
     211           4 :         return status;
     212             : }
     213             : 
     214             : /**
     215             :  * @brief Compare two files line by line where the original file is made up of
     216             :  *        regex
     217             :  *
     218             :  * @param filename first file, containing regex patterns
     219             :  * @param genfilename file to compare with
     220             :  *
     221             :  * @retval 0 on errors (succeed_if already executed)
     222             :  * @retval 1 on success
     223             :  */
     224           2 : int compare_regex_to_line_files (const char * filename, const char * genfilename)
     225             : {
     226           2 :         return compare_line_files_fun (filename, genfilename, &regexcmp);
     227             : }
     228             : 
     229             : 
     230             : /**Compare two files line by line.
     231             :  *
     232             :  * Fails when there are any differences.
     233             :  *
     234             :  * The original file is passed as parameter.
     235             :  * It will be compared with the file -gen.
     236             :  *
     237             :  * file.xml -> file-gen.xml (xml comparator)
     238             :  * file.txt -> file-gen.txt (line comparator)
     239             :  * file.c -> file-gen.c (c comparator)
     240             :  *
     241             :  */
     242           0 : int compare_files (const char * filename)
     243             : {
     244             :         char genfilename[KDB_MAX_PATH_LENGTH];
     245           0 :         char * dot = strrchr (filename, '.');
     246             : 
     247           0 :         exit_if_fail (dot != 0, "could not find extension in file");
     248             : 
     249           0 :         strncpy (genfilename, filename, dot - filename);
     250             :         /* does not terminate string, but strcat need it, so: */
     251           0 :         genfilename[dot - filename] = 0;
     252           0 :         strcat (genfilename, "-gen");
     253           0 :         if (!strcmp (dot, ".xml"))
     254             :         {
     255           0 :                 strcat (genfilename, ".xml");
     256             :         }
     257           0 :         else if (!strcmp (dot, ".txt"))
     258             :         {
     259           0 :                 strcat (genfilename, ".txt");
     260             :         }
     261           0 :         else if (!strcmp (dot, ".c"))
     262             :         {
     263           0 :                 strcat (genfilename, ".c");
     264             :         }
     265             : 
     266           0 :         return compare_line_files (filename, genfilename);
     267             : }
     268             : 
     269             : 
     270             : /* return file name in srcdir.
     271             :  * No bound checking on file size, may overflow. */
     272         562 : char * srcdir_file (const char * fileName)
     273             : {
     274         562 :         strcpy (file, srcdir);
     275         562 :         strcat (file, "/");
     276         562 :         strcat (file, fileName);
     277         562 :         return file;
     278             : }
     279             : 
     280         713 : const char * elektraFilename (void)
     281             : {
     282         713 :         return tmpfilename;
     283             : }
     284             : 
     285          81 : void elektraUnlink (const char * filename)
     286             : {
     287         270 :         unlink (filename);
     288          81 : }
     289             : 
     290          12 : void clear_sync (KeySet * ks)
     291             : {
     292             :         Key * k;
     293          12 :         ksRewind (ks);
     294          88 :         while ((k = ksNext (ks)) != 0)
     295          64 :                 keyClearSync (k);
     296          12 : }
     297             : 
     298           7 : void output_meta (Key * k)
     299             : {
     300             :         const Key * meta;
     301             : 
     302           7 :         keyRewindMeta (k);
     303          20 :         while ((meta = keyNextMeta (k)) != 0)
     304             :         {
     305           6 :                 printf (", %s: %s", keyName (meta), (const char *) keyValue (meta));
     306             :         }
     307           7 :         printf ("\n");
     308           7 : }
     309             : 
     310           7 : void output_key (Key * k)
     311             : {
     312             :         // output_meta will print endline
     313           7 :         printf ("%p key: %s, string: %s", (void *) k, keyName (k), keyString (k));
     314           7 :         output_meta (k);
     315           7 : }
     316             : 
     317           3 : void output_keyset (KeySet * ks)
     318             : {
     319             :         Key * k;
     320           3 :         ksRewind (ks);
     321          13 :         while ((k = ksNext (ks)) != 0)
     322             :         {
     323           7 :                 output_key (k);
     324             :         }
     325           3 : }
     326             : 
     327           0 : void output_plugin (Plugin * plugin)
     328             : {
     329           0 :         if (!plugin) return;
     330             : 
     331           0 :         printf ("Name: %s [%zu]\n", plugin->name, plugin->refcounter);
     332           0 :         output_keyset (plugin->config);
     333             : }
     334             : 
     335           0 : void output_backend (Backend * backend)
     336             : {
     337           0 :         if (!backend) return;
     338             : 
     339           0 :         printf ("us: %zd, ss: %zd\n", backend->usersize, backend->systemsize);
     340           0 :         output_key (backend->mountpoint);
     341             : }
     342             : 
     343           0 : void output_trie (Trie * trie)
     344             : {
     345             :         int i;
     346           0 :         for (i = 0; i < KDB_MAX_UCHAR; ++i)
     347             :         {
     348           0 :                 if (trie->value[i])
     349             :                 {
     350           0 :                         printf ("output_trie: %p, mp: %s %s [%d]\n", (void *) trie->value[i], keyName (trie->value[i]->mountpoint),
     351           0 :                                 keyString (trie->value[i]->mountpoint), i);
     352             :                 }
     353           0 :                 if (trie->children[i]) output_trie (trie->children[i]);
     354             :         }
     355           0 :         if (trie->empty_value)
     356             :         {
     357           0 :                 printf ("empty_value: %p, mp: %s %s\n", (void *) trie->empty_value, keyName (trie->empty_value->mountpoint),
     358           0 :                         keyString (trie->empty_value->mountpoint));
     359             :         }
     360           0 : }
     361             : 
     362           0 : void output_split (Split * split)
     363             : {
     364           0 :         printf ("Split - size: %zu, alloc: %zu\n", split->size, split->alloc);
     365           0 :         for (size_t i = 0; i < split->size; ++i)
     366             :         {
     367           0 :                 if (split->handles[i])
     368             :                 {
     369           0 :                         printf ("split #%zu size: %zd, handle: %p, sync: %d, parent: %s (%s), spec: %zd, dir: %zd, user: %zd, system: "
     370             :                                 "%zd\n",
     371           0 :                                 i, ksGetSize (split->keysets[i]), (void *) split->handles[i], split->syncbits[i],
     372           0 :                                 keyName (split->parents[i]), keyString (split->parents[i]), split->handles[i]->specsize,
     373             :                                 split->handles[i]->dirsize, split->handles[i]->usersize, split->handles[i]->systemsize);
     374             :                 }
     375             :                 else
     376             :                 {
     377           0 :                         printf ("split #%zu, size: %zd, default split, sync: %d\n", i, ksGetSize (split->keysets[i]), split->syncbits[i]);
     378             :                 }
     379             :         }
     380           0 : }
     381             : 
     382           0 : void generate_split (Split * split)
     383             : {
     384           0 :         printf ("succeed_if (split->size == %zu, \"size of split not correct\");\n", split->size);
     385           0 :         for (size_t i = 0; i < split->size; ++i)
     386             :         {
     387           0 :                 printf ("succeed_if (split->syncbits[%zu]== %d, \"size of split not correct\");\n", i, split->syncbits[i]);
     388           0 :                 printf ("succeed_if (ksGetSize(split->keysets[%zu]) == %zd, \"wrong size\");\n", i, ksGetSize (split->keysets[i]));
     389             :         }
     390           0 : }
     391             : 
     392             : /**
     393             :  * @brief Output warnings if present
     394             :  *
     395             :  * To check for warnings use:
     396             :  * succeed_if(output_warnings(parentKey), "warning(s) found");
     397             :  *
     398             :  * @param warningKey the key to retrieve metadata from
     399             :  *
     400             :  * @see check_for_errors_and_warnings if you want errors to have a test case failed without output
     401             :  *
     402             :  * @retval 1 if no warnings (can be used within succeed_if)
     403             :  */
     404        2586 : int output_warnings (Key * warningKey)
     405             : {
     406             :         //! [warnings]
     407        2586 :         const Key * metaWarnings = keyGetMeta (warningKey, "warnings");
     408        2586 :         if (!metaWarnings) return 1; /* There are no current warnings */
     409             : 
     410          34 :         int nrWarnings = atoi (keyString (metaWarnings));
     411             : 
     412          17 :         printf ("There are %d warnings\n", nrWarnings + 1);
     413          38 :         for (int i = 0; i <= nrWarnings; ++i)
     414             :         {
     415          21 :                 char buffer[] = "warnings/#00\0description";
     416          21 :                 buffer[10] = i / 10 % 10 + '0';
     417          21 :                 buffer[11] = i % 10 + '0';
     418          21 :                 printf ("buffer is: %s\n", buffer);
     419          21 :                 strncat (buffer, "/number", sizeof (buffer) - strlen (buffer) - 1);
     420          21 :                 printf ("number: %s\n", keyString (keyGetMeta (warningKey, buffer)));
     421          21 :                 buffer[12] = '\0';
     422          21 :                 strncat (buffer, "/description", sizeof (buffer) - strlen (buffer) - 1);
     423          21 :                 printf ("description: %s\n", keyString (keyGetMeta (warningKey, buffer)));
     424          21 :                 buffer[12] = '\0';
     425          21 :                 strncat (buffer, "/module", sizeof (buffer) - strlen (buffer) - 1);
     426          21 :                 keyGetMeta (warningKey, buffer);
     427          21 :                 printf ("module: %s\n", keyString (keyGetMeta (warningKey, buffer)));
     428          21 :                 buffer[12] = '\0';
     429          21 :                 strncat (buffer, "/file", sizeof (buffer) - strlen (buffer) - 1);
     430          21 :                 keyGetMeta (warningKey, buffer);
     431          21 :                 printf ("file: %s\n", keyString (keyGetMeta (warningKey, buffer)));
     432          21 :                 buffer[12] = '\0';
     433          21 :                 strncat (buffer, "/line", sizeof (buffer) - strlen (buffer) - 1);
     434          21 :                 keyGetMeta (warningKey, buffer);
     435          21 :                 printf ("line: %s\n", keyString (keyGetMeta (warningKey, buffer)));
     436          21 :                 buffer[12] = '\0';
     437          21 :                 strncat (buffer, "/reason", sizeof (buffer) - strlen (buffer) - 1);
     438          21 :                 keyGetMeta (warningKey, buffer);
     439          21 :                 printf ("reason: %s\n", keyString (keyGetMeta (warningKey, buffer)));
     440          21 :                 buffer[12] = '\0';
     441          21 :                 strncat (buffer, "/mountpoint", sizeof (buffer) - strlen (buffer) - 1);
     442          21 :                 keyGetMeta (warningKey, buffer);
     443          21 :                 printf ("reason: %s\n", keyString (keyGetMeta (warningKey, buffer)));
     444          21 :                 buffer[12] = '\0';
     445          21 :                 strncat (buffer, "/configfile", sizeof (buffer) - strlen (buffer) - 1);
     446          21 :                 keyGetMeta (warningKey, buffer);
     447          21 :                 printf ("reason: %s\n", keyString (keyGetMeta (warningKey, buffer)));
     448             :         }
     449             :         //! [warnings]
     450             : 
     451             :         return 0;
     452             : }
     453             : 
     454             : /**
     455             :  * @brief Output the error if present
     456             :  *
     457             :  * To check for error use:
     458             :  * succeed_if(output_error(parentKey), "error found");
     459             :  *
     460             :  * @param errorKey keys to retrieve errors from
     461             :  *
     462             :  * @retval 1 if no error (can be used within succeed_if)
     463             :  */
     464        2590 : int output_error (Key * errorKey)
     465             : {
     466             :         //! [error]
     467        2590 :         const Key * metaError = keyGetMeta (errorKey, "error");
     468        2590 :         if (!metaError) return 1; /* There is no current error */
     469             : 
     470          10 :         printf ("number: %s\n", keyString (keyGetMeta (errorKey, "error/number")));
     471          10 :         printf ("description: : %s\n", keyString (keyGetMeta (errorKey, "error/description")));
     472          10 :         printf ("module: : %s\n", keyString (keyGetMeta (errorKey, "error/module")));
     473          10 :         printf ("at: %s:%s\n", keyString (keyGetMeta (errorKey, "error/file")), keyString (keyGetMeta (errorKey, "error/line")));
     474          10 :         printf ("reason: : %s\n", keyString (keyGetMeta (errorKey, "error/reason")));
     475          10 :         printf ("mountpoint: : %s\n", keyString (keyGetMeta (errorKey, "error/mountpoint")));
     476          10 :         printf ("configfile: : %s\n", keyString (keyGetMeta (errorKey, "error/configfile")));
     477             :         //! [error]
     478             : 
     479          10 :         return 0;
     480             : }
     481             : 
     482             : #ifdef USE_NFTW
     483         198 : static int rm_all (const char * fpath, const struct stat * sb ELEKTRA_UNUSED, int tflag, struct FTW * ftwbuf ELEKTRA_UNUSED)
     484             : {
     485         198 :         if (tflag == FTW_F)
     486             :         {
     487           6 :                 unlink (fpath);
     488             :         }
     489         192 :         else if (tflag == FTW_D || tflag == FTW_DP)
     490             :         {
     491         192 :                 rmdir (fpath);
     492             :         }
     493             :         else
     494             :         {
     495             :                 // not a file or dir we can delete
     496           0 :                 printf ("unexpected flag: %d\n", tflag);
     497           0 :                 return 1;
     498             :         }
     499             :         return 0;
     500             : }
     501             : #endif
     502             : 
     503         189 : void clean_temp_home (void)
     504             : {
     505         189 :         if (tmpfilename)
     506             :         {
     507         378 :                 elektraUnlink (tmpfilename);
     508         189 :                 elektraFree (tmpfilename);
     509         189 :                 tmpfilename = NULL;
     510             :         }
     511             : 
     512         189 :         if (tempHomeConf)
     513             :         {
     514         189 :                 rmdir (tempHomeConf);
     515         189 :                 elektraFree (tempHomeConf);
     516         189 :                 tempHomeConf = NULL;
     517             :         }
     518             : 
     519         189 :         if (tempHome)
     520             :         {
     521             : #ifdef USE_NFTW
     522         189 :                 int nftw_flags = FTW_DEPTH | FTW_PHYS;
     523         189 :                 succeed_if (nftw (tempHome, rm_all, NOPENFD, nftw_flags) == 0, "Could not delete TMPHOME via nftw");
     524             : #else
     525             :                 size_t fileToCleanLen = tempHomeLen + 30;
     526             :                 char * fileToClean = elektraMalloc (fileToCleanLen);
     527             :                 snprintf (fileToClean, fileToCleanLen, "%s/.gnupg/random_seed", tempHome);
     528             :                 unlink (fileToClean);
     529             :                 snprintf (fileToClean, fileToCleanLen, "%s/.gnupg/trustdb.gpg", tempHome);
     530             :                 unlink (fileToClean);
     531             :                 snprintf (fileToClean, fileToCleanLen, "%s/.gnupg/pubring.kbx~", tempHome);
     532             :                 unlink (fileToClean);
     533             :                 snprintf (fileToClean, fileToCleanLen, "%s/.gnupg/pubring.kbx", tempHome);
     534             :                 unlink (fileToClean);
     535             :                 snprintf (fileToClean, fileToCleanLen, "%s/.gnupg", tempHome);
     536             :                 rmdir (fileToClean);
     537             :                 elektraFree (fileToClean);
     538             : 
     539             :                 succeed_if (rmdir (tempHome) == 0, "Could not delete TMPHOME manually");
     540             : #endif
     541         189 :                 elektraFree (tempHome);
     542         189 :                 tempHome = NULL;
     543         189 :                 tempHomeLen = 0;
     544             :         }
     545         189 : }
     546             : 
     547             : #ifdef __cplusplus
     548             : } // end extern "C"
     549             : #endif

Generated by: LCOV version 1.13