1 /*
2      This file is part of libextractor.
3      Copyright (C) 2012 Vidyut Samanta and Christian Grothoff
4 
5      libextractor is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9 
10      libextractor is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14 
15      You should have received a copy of the GNU General Public License
16      along with libextractor; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file plugins/test_lib.c
22  * @brief helper library for writing testcases
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "test_lib.h"
27 #include <sys/types.h>
28 #include <regex.h>
29 #include <signal.h>
30 
31 /**
32  * Function that libextractor calls for each
33  * meta data item found.
34  *
35  * @param cls closure the 'struct SolutionData' we are currently working on
36  * @param plugin_name should be "test"
37  * @param type should be "COMMENT"
38  * @param format should be "UTF8"
39  * @param data_mime_type should be "<no mime>"
40  * @param data hello world or good bye
41  * @param data_len number of bytes in data
42  * @return 0 (always)
43  */
44 static int
process_replies(void * cls,const char * plugin_name,enum EXTRACTOR_MetaType type,enum EXTRACTOR_MetaFormat format,const char * data_mime_type,const char * data,size_t data_len)45 process_replies (void *cls,
46                  const char *plugin_name,
47                  enum EXTRACTOR_MetaType type,
48                  enum EXTRACTOR_MetaFormat format,
49                  const char *data_mime_type,
50                  const char *data,
51                  size_t data_len)
52 {
53   struct SolutionData *sd = cls;
54   unsigned int i;
55 
56   for (i = 0; -1 != sd[i].solved; i++)
57   {
58     if ( (0 != sd[i].solved) ||
59          (sd[i].type != type) ||
60          (sd[i].format != format) )
61       continue;
62     if ( (sd[i].regex) &&
63          (EXTRACTOR_METAFORMAT_BINARY != format) )
64     {
65       regex_t re;
66       regmatch_t match;
67 
68       if (0 !=
69           regcomp (&re,
70                    sd[i].data,
71                    REG_EXTENDED))
72       {
73         fprintf (stderr,
74                  "Not a valid regex: %s\n",
75                  sd[i].data);
76         abort ();
77       }
78       if ( ('\0' != data[data_len - 1]) ||
79            (0 != regexec (&re,
80                           data,
81                           1,
82                           &match,
83                           0)) )
84       {
85         regfree (&re);
86         continue;
87       }
88       regfree (&re);
89     }
90     else
91     {
92       if ( (EXTRACTOR_METAFORMAT_BINARY != format) &&
93            ( (sd[i].data_len != data_len) ||
94              (0 != memcmp (sd[i].data, data, data_len)) ) )
95         continue;
96       if ( (EXTRACTOR_METAFORMAT_BINARY == format) &&
97            ( (sd[i].data_len > data_len) ||
98              (0 != memcmp (sd[i].data, data, sd[i].data_len)) ) )
99         continue;
100     }
101 
102     if (NULL != sd[i].data_mime_type)
103     {
104       if (NULL == data_mime_type)
105         continue;
106       if (0 != strcmp (sd[i].data_mime_type, data_mime_type))
107         continue;
108     }
109     else
110     {
111       if (NULL != data_mime_type)
112         continue;
113     }
114     sd[i].solved = 1;
115     return 0;
116   }
117   fprintf (stderr,
118            "Got additional meta data of type %d and format %d with value `%.*s' from plugin `%s'\n",
119            type,
120            format,
121            (int) data_len,
122            data,
123            plugin_name);
124   return 0;
125 }
126 
127 
128 /**
129  * Run a test for the given plugin, problem set and options.
130  *
131  * @param plugin_name name of the plugin to load
132  * @param ps array of problems the plugin should solve;
133  *        NULL in filename terminates the array.
134  * @param opt options to use for loading the plugin
135  * @return 0 on success, 1 on failure
136  */
137 static int
run(const char * plugin_name,struct ProblemSet * ps,enum EXTRACTOR_Options opt)138 run (const char *plugin_name,
139      struct ProblemSet *ps,
140      enum EXTRACTOR_Options opt)
141 {
142   struct EXTRACTOR_PluginList *pl;
143   unsigned int i;
144   unsigned int j;
145   int ret;
146 
147   pl = EXTRACTOR_plugin_add_config (NULL,
148                                     plugin_name,
149                                     opt);
150   for (i = 0; NULL != ps[i].filename; i++)
151     EXTRACTOR_extract (pl,
152                        ps[i].filename,
153                        NULL, 0,
154                        &process_replies,
155                        ps[i].solution);
156   EXTRACTOR_plugin_remove_all (pl);
157   ret = 0;
158   for (i = 0; NULL != ps[i].filename; i++)
159     for (j = 0; -1 != ps[i].solution[j].solved; j++)
160       if (0 == ps[i].solution[j].solved)
161       {
162         ret = 1;
163         fprintf (stderr,
164                  "Did not get expected meta data of type %d and format %d with value `%.*s' from plugin `%s'\n",
165                  ps[i].solution[j].type,
166                  ps[i].solution[j].format,
167                  (int) ps[i].solution[j].data_len,
168                  ps[i].solution[j].data,
169                  plugin_name);
170       }
171       else
172         ps[i].solution[j].solved = 0;
173   /* reset for next round */
174   return ret;
175 }
176 
177 
178 #ifndef WINDOWS
179 /**
180  * Install a signal handler to ignore SIGPIPE.
181  */
182 static void
ignore_sigpipe()183 ignore_sigpipe ()
184 {
185   struct sigaction oldsig;
186   struct sigaction sig;
187 
188   memset (&sig, 0, sizeof (struct sigaction));
189   sig.sa_handler = SIG_IGN;
190   sigemptyset (&sig.sa_mask);
191 #ifdef SA_INTERRUPT
192   sig.sa_flags = SA_INTERRUPT;  /* SunOS */
193 #else
194   sig.sa_flags = SA_RESTART;
195 #endif
196   if (0 != sigaction (SIGPIPE, &sig, &oldsig))
197     fprintf (stderr,
198              "Failed to install SIGPIPE handler: %s\n", strerror (errno));
199 }
200 
201 
202 #endif
203 
204 
205 /**
206  * Main function to be called to test a plugin.
207  *
208  * @param plugin_name name of the plugin to load
209  * @param ps array of problems the plugin should solve;
210  *        NULL in filename terminates the array.
211  * @return 0 on success, 1 on failure
212  */
213 int
ET_main(const char * plugin_name,struct ProblemSet * ps)214 ET_main (const char *plugin_name,
215          struct ProblemSet *ps)
216 {
217   int ret;
218 
219   /* change environment to find plugins which may not yet be
220      not installed but should be in the current directory (or .libs)
221      on 'make check' */
222 #ifndef WINDOWS
223   ignore_sigpipe ();
224 #endif
225   if (0 != putenv ("LIBEXTRACTOR_PREFIX=./.libs/"))
226     fprintf (stderr,
227              "Failed to update my environment, plugin loading may fail: %s\n",
228              strerror (errno));
229   ret = run (plugin_name, ps, EXTRACTOR_OPTION_DEFAULT_POLICY);
230   if (0 != ret)
231     return ret;
232   ret = run (plugin_name, ps, EXTRACTOR_OPTION_IN_PROCESS);
233   if (0 != ret)
234     return ret;
235   return 0;
236 }
237 
238 
239 /* end of test_lib.c */
240