]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/trigger/test/testTriggerDomain.C
Adding unit testing code for the AliHLTTriggerDomain class and fixing found bug....
[u/mrichter/AliRoot.git] / HLT / trigger / test / testTriggerDomain.C
1 /**************************************************************************
2  * This file is property of and copyright by the ALICE HLT Project        *
3  * ALICE Experiment at CERN, All rights reserved.                         *
4  *                                                                        *
5  * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
6  *                  for The ALICE HLT Project.                            *
7  *                                                                        *
8  * Permission to use, copy, modify and distribute this software and its   *
9  * documentation strictly for non-commercial purposes is hereby granted   *
10  * without fee, provided that the above copyright notice appears in all   *
11  * copies and that both the copyright notice and this permission notice   *
12  * appear in the supporting documentation. The authors make no claims     *
13  * about the suitability of this software for any purpose. It is          *
14  * provided "as is" without express or implied warranty.                  *
15  **************************************************************************/
16
17 /**
18  * This macro is used to test the behaviour of the AliHLTTriggerDomain class.
19  * We specifically check that the AliHLTTriggerDomain operators behave correctly
20  * as set operations.
21  */
22
23 #if defined(__CINT__) && (! defined(__MAKECINT__))
24 #error This macro must be compiled. Try running as testTriggerDomain.C++
25 #endif
26
27 #include "Riostream.h"
28 #include "TSystem.h"
29 #include "TClassTable.h"
30 #include "TRandom3.h"
31 #include "TObjArray.h"
32 #include "AliHLTTriggerDomain.h"
33 #include "AliHLTDomainEntry.h"
34
35 const int N = 6;
36 const char* datatype[N] = {"*******", "AAAAAAAA", "BBBBBBBB", "CCCCCCCC", "DDDDDDDD", "EEEEEEEE"};
37 const char* origin[N] = {"***", "xxxx", "yyyy", "zzzz", "wwww", "uuuu"};
38 int spec[N] = {0, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555};
39
40 /**
41  * Randomly builds a trigger domain from the various data types, origins and specifications.
42  * \param domain <i>[out]</i> The new constructed domain is filled into this output variable.
43  * \param opcount <i>[in]</i> The number of Add / Remove operations to apply to the domain.
44  */
45 void BuildTriggerDomain(AliHLTTriggerDomain& domain, int opcount = 100)
46 {
47         domain.Clear();
48         for (int i = 0; i < opcount; i++)
49         {
50                 // Make sure not to use the last data type, origin or specification in
51                 // the respective lists because we want to use them later to test the
52                 // matching against wild card values.
53                 int itype = gRandom->Integer(N-1);
54                 int iorigin = gRandom->Integer(N-1);
55                 int ispec = gRandom->Integer(N-1);
56                 if (gRandom->Integer(2) == 0)
57                 {
58                         if (spec[ispec] == 0)
59                                 domain.Add(datatype[itype], origin[iorigin]);
60                         else
61                                 domain.Add(datatype[itype], origin[iorigin], spec[ispec]);
62                 }
63                 else
64                 {
65                         if (spec[ispec] == 0)
66                                 domain.Remove(datatype[itype], origin[iorigin]);
67                         else
68                                 domain.Remove(datatype[itype], origin[iorigin], spec[ispec]);
69                 }
70         }
71 }
72
73 /**
74  * Returns the string representation of the data type.
75  */
76 const char* TypeToString(const AliHLTComponentDataType& type)
77 {
78         static char str[kAliHLTComponentDataTypefIDsize+1];
79         for (int i = 0; i < kAliHLTComponentDataTypefIDsize; i++)
80         {
81                 str[i] = type.fID[i];
82         }
83         return str;
84 }
85
86 /**
87  * Returns the string representation of the data origin.
88  */
89 const char* OriginToString(const AliHLTComponentDataType& type)
90 {
91         static char str[kAliHLTComponentDataTypefOriginSize+1];
92         for (int i = 0; i < kAliHLTComponentDataTypefOriginSize; i++)
93         {
94                 str[i] = type.fOrigin[i];
95         }
96         return str;
97 }
98
99 /**
100  * Checks to see if the domain is correctly constructed compared to the list of entries
101  * that were applied to the domain.
102  * \param entryList <i>[out]</i> The list of entries that were used to construct the domain.
103  * \param domain <i>[in]</i> The trigger domain to check.
104  */
105 bool DomainOK(const TObjArray& entryList, const AliHLTTriggerDomain& domain)
106 {
107         for (int i = 1; i < N; i++)
108         for (int j = 1; j < N; j++)
109         for (int k = 1; k < N; k++)
110         {
111                 AliHLTDomainEntry entry(datatype[i], origin[j], spec[k]);
112                 AliHLTComponentBlockData block;
113                 block.fDataType = entry;
114                 block.fSpecification = spec[k];
115                 
116                 bool result = false;
117                 bool result2 = false;
118                 for (int n = 0; n < entryList.GetEntriesFast(); n++)
119                 {
120                         const AliHLTDomainEntry* rule = static_cast<const AliHLTDomainEntry*>( entryList[n] );
121                         if (*rule == entry) result = rule->Inclusive();
122                         if (*rule == &block) result2 = rule->Inclusive();
123                 }
124                 
125                 bool containsResult = domain.Contains(entry);
126                 bool includeResult = domain.IncludeInReadout(&block);
127                 if (containsResult != result or includeResult != result2)
128                 {
129                         cout << "FAILED DomainOK test!" << endl;
130                         cout << "==============================================================================" << endl;
131                         cout << "Dump of how AliHLTTriggerDomain was built:" << endl;
132                         cout << "  AliHLTTriggerDomain domain;" << endl;
133                         for (int n = 0; n < entryList.GetEntriesFast(); n++)
134                         {
135                                 const AliHLTDomainEntry* rule = static_cast<const AliHLTDomainEntry*>( entryList[n] );
136                                 const char* opstr = (rule->Exclusive() ? "Remove" : "Add");
137                                 if (rule->IsValidSpecification())
138                                 {
139                                         cout << "  domain." << opstr << "(\"" << TypeToString(rule->DataType())
140                                                 << "\", \"" << OriginToString(rule->DataType())
141                                                 << "\", 0x" << hex << rule->Specification() << dec
142                                                 << ");" << endl;
143                                 }
144                                 else
145                                 {
146                                         cout << "  domain." << opstr << "(\"" << TypeToString(rule->DataType())
147                                                 << "\", \"" << OriginToString(rule->DataType())
148                                                 << "\");" << endl;
149                                 }
150                         }
151                         cout << "==============================================================================" << endl;
152                         cout << "Dump of the trigger domain contents:" << endl;
153                         domain.Print();
154                         cout << "==============================================================================" << endl;
155                 }
156                 if (containsResult != result)
157                 {
158                         cout << "Failed for entry = ";
159                         entry.Print();
160                         cout << "Result of domain.Contains(entry) == " << containsResult << endl;
161                         cout << " Expected domain.Contains(entry) == " << result << endl;
162                         return false;
163                 }
164                 if (includeResult != result2)
165                 {
166                         cout << "Failed for block: type = " << TypeToString(block.fDataType)
167                                 << ", origin = " << OriginToString(block.fDataType)
168                                 << ", specification = " << hex << block.fSpecification << dec;
169                         cout << "Result of domain.IncludeInReadout(&block) == " << includeResult << endl;
170                         cout << " Expected domain.IncludeInReadout(&block) == " << result2 << endl;
171                         return false;
172                 }
173         }
174         
175         return true;
176 }
177
178 /**
179  * Randomly builds a trigger domain and tests the Add / Remove operations of the
180  * AliHLTTriggerDomain class.
181  * \param opcount <i>[in]</i> The number of Add / Remove operations to use to
182  *     build the domain.
183  */
184 bool AddRemoveOK(int opcount = 100)
185 {
186         TObjArray entryList;
187         entryList.SetOwner(kTRUE);
188         AliHLTTriggerDomain domain;
189         
190         for (int i = 0; i < opcount; i++)
191         {
192                 // Make sure not to use the last data type, origin or specification in
193                 // the respective lists because we want to use them later to test the
194                 // matching against wild card values.
195                 int itype = gRandom->Integer(N-1);
196                 int iorigin = gRandom->Integer(N-1);
197                 int ispec = gRandom->Integer(N-1);
198                 if (gRandom->Integer(2) == 0)
199                 {
200                         if (spec[ispec] == 0)
201                         {
202                                 entryList.Add(new AliHLTDomainEntry(kFALSE, datatype[itype], origin[iorigin]));
203                                 domain.Add(datatype[itype], origin[iorigin]);
204                         }
205                         else
206                         {
207                                 entryList.Add(new AliHLTDomainEntry(kFALSE, datatype[itype], origin[iorigin], spec[ispec]));
208                                 domain.Add(datatype[itype], origin[iorigin], spec[ispec]);
209                         }
210                 }
211                 else
212                 {
213                         if (spec[ispec] == 0)
214                         {
215                                 entryList.Add(new AliHLTDomainEntry(kTRUE, datatype[itype], origin[iorigin]));
216                                 domain.Remove(datatype[itype], origin[iorigin]);
217                         }
218                         else
219                         {
220                                 entryList.Add(new AliHLTDomainEntry(kTRUE, datatype[itype], origin[iorigin], spec[ispec]));
221                                 domain.Remove(datatype[itype], origin[iorigin], spec[ispec]);
222                         }
223                 }
224         }
225         
226         if (not DomainOK(entryList, domain)) return false;
227         
228         return true;
229 }
230
231
232 #define DefOperation(name, expr, logicExpr) \
233         class name \
234         { \
235         public: \
236                 static const char* Name() \
237                 { \
238                         return #name; \
239                 } \
240                 static const char* Expression() \
241                 { \
242                         return #expr; \
243                 } \
244                 static AliHLTTriggerDomain Apply(const AliHLTTriggerDomain& a, const AliHLTTriggerDomain& b) \
245                 { \
246                         return expr; \
247                 } \
248                 static bool ExpectedResult(bool a, const bool b) \
249                 { \
250                         return logicExpr; \
251                 } \
252         };
253
254
255 DefOperation( OpComplement, ~a,    !a       );
256 DefOperation( OpUnion,      a | b, a | b    );
257 DefOperation( OpIntersect,  a & b, a & b    );
258 DefOperation( OpXor,        a ^ b, a ^ b    );
259 DefOperation( OpPlus,       a + b, a | b    );
260 DefOperation( OpMinus,      a - b, a & (!b) );
261
262 /**
263  * Randomly builds two trigger domains and tests a overloaded operator of the
264  * AliHLTTriggerDomain class.
265  * \param opcount <i>[in]</i> The number of Add / Remove operations to use to
266  *     build the domains.
267  */
268 template <class Op>
269 bool OperatorOK(int opcount = 100)
270 {
271         AliHLTTriggerDomain d1;
272         BuildTriggerDomain(d1, opcount);
273         AliHLTTriggerDomain d2;
274         BuildTriggerDomain(d2, opcount);
275         AliHLTTriggerDomain d3 = Op::Apply(d1, d2);
276         
277         for (int i = 1; i < N; i++)
278         for (int j = 1; j < N; j++)
279         for (int k = 1; k < N; k++)
280         {
281                 AliHLTDomainEntry entry(datatype[i], origin[j], spec[k]);
282                 bool d1Result = d1.Contains(entry);
283                 bool d2Result = d2.Contains(entry);
284                 bool d3Result = d3.Contains(entry);
285                 bool d3ExpectedResult = Op::ExpectedResult(d1Result, d2Result);
286                 if (d3Result != d3ExpectedResult)
287                 {
288                         cout << "FAILED OperatorOK<" << Op::Name() << "> test!" << endl;
289                         cout << "==============================================================================" << endl;
290                         cout << "Dump of the trigger domain a contents:" << endl;
291                         d1.Print();
292                         cout << "==============================================================================" << endl;
293                         cout << "Dump of the trigger domain b contents:" << endl;
294                         d2.Print();
295                         cout << "==============================================================================" << endl;
296                         cout << "Dump of the trigger domain c = " << Op::Expression() << " contents:" << endl;
297                         d3.Print();
298                         cout << "==============================================================================" << endl;
299                         cout << "Failed for entry = ";
300                         entry.Print();
301                         cout << "Result of c.Contains(entry) == " << d3Result << endl;
302                         cout << " Expected c.Contains(entry) == " << d3ExpectedResult << endl;
303                         return false;
304                 }
305         }
306         
307         return true;
308 }
309
310
311 #define DefEqualExprCheck(name, expr1, expr2) \
312         class name \
313         { \
314         public: \
315                 static const char* Name() \
316                 { \
317                         return #name; \
318                 } \
319                 static const char* Expr1() \
320                 { \
321                         return #expr1; \
322                 } \
323                 static const char* Expr2() \
324                 { \
325                         return #expr2; \
326                 } \
327                 static AliHLTTriggerDomain Apply1(const AliHLTTriggerDomain& a, const AliHLTTriggerDomain& b) \
328                 { \
329                         return expr1; \
330                 } \
331                 static AliHLTTriggerDomain Apply2(const AliHLTTriggerDomain& a, const AliHLTTriggerDomain& b) \
332                 { \
333                         return expr2; \
334                 } \
335         };
336
337
338 DefEqualExprCheck( XorExprCheck1,  a ^ b, (a | b) - (a & b)             );
339 DefEqualExprCheck( XorExprCheck2,  a ^ b, (a - (a & b)) | (b - (a & b)) );
340 DefEqualExprCheck( MinusExprCheck1, a - b, a & (a ^ b)                  );
341 DefEqualExprCheck( MinusExprCheck2, a - b, a & ~(a & b)                 );
342
343 /**
344  * Randomly builds two trigger domains and tests two expressions applied to the
345  * domains that should be equivalent.
346  * \param opcount <i>[in]</i> The number of Add / Remove operations to use to
347  *     build the domains.
348  */
349 template <class Expr>
350 bool EquivalentExpressionsOK(int opcount = 100)
351 {
352         AliHLTTriggerDomain d1;
353         BuildTriggerDomain(d1, opcount);
354         AliHLTTriggerDomain d2;
355         BuildTriggerDomain(d2, opcount);
356         AliHLTTriggerDomain d3 = Expr::Apply1(d1, d2);
357         AliHLTTriggerDomain d4 = Expr::Apply2(d1, d2);
358         
359         for (int i = 1; i < N; i++)
360         for (int j = 1; j < N; j++)
361         for (int k = 1; k < N; k++)
362         {
363                 AliHLTDomainEntry entry(datatype[i], origin[j], spec[k]);
364                 bool d3Result = d3.Contains(entry);
365                 bool d4Result = d4.Contains(entry);
366                 if (d3Result != d4Result)
367                 {
368                         cout << "FAILED EquivalentExpressionsOK<" << Expr::Name() << "> test!" << endl;
369                         cout << "==============================================================================" << endl;
370                         cout << "Dump of the trigger domain a contents:" << endl;
371                         d1.Print();
372                         cout << "==============================================================================" << endl;
373                         cout << "Dump of the trigger domain b contents:" << endl;
374                         d2.Print();
375                         cout << "==============================================================================" << endl;
376                         cout << "Dump of the trigger domain c = " << Expr::Expr1() << " contents:" << endl;
377                         d3.Print();
378                         cout << "==============================================================================" << endl;
379                         cout << "Dump of the trigger domain d = " << Expr::Expr2() << " contents:" << endl;
380                         d3.Print();
381                         cout << "==============================================================================" << endl;
382                         cout << "Failed for entry = ";
383                         entry.Print();
384                         cout << "Result of c.Contains(entry) == " << d3Result << endl;
385                         cout << "Result of d.Contains(entry) == " << d4Result << endl;
386                         cout << "But the results should be the same." << endl;
387                         return false;
388                 }
389         }
390         
391         return true;
392 }
393
394
395 #define DefTest(name, routine, description) \
396         class name \
397         { \
398         public: \
399                 static bool Run(int opcount) \
400                 { \
401                         return routine(opcount); \
402                 } \
403                 static const char* Description() \
404                 { \
405                         return description; \
406                 } \
407         }
408
409 // Declarations of the different tests.
410 DefTest(AddRemoveTest,           AddRemoveOK,              "AliHLTTriggerDomain::Add and AliHLTTriggerDomain::Remove");
411 DefTest(ComplementOperationTest, OperatorOK<OpComplement>, "operator ~a");
412 DefTest(UnionOperationTest,      OperatorOK<OpUnion>,      "operator a | b");
413 DefTest(IntersectOperationTest,  OperatorOK<OpIntersect>,  "operator a & b");
414 DefTest(XorOperationTest,        OperatorOK<OpXor>,        "operator a ^ b");
415 DefTest(PlusOperationTest,       OperatorOK<OpPlus>,       "operator a + b");
416 DefTest(MinusOperationTest,      OperatorOK<OpMinus>,      "operator a - b");
417 DefTest(XorExpressionTest1,   EquivalentExpressionsOK<XorExprCheck1>,   "expression a ^ b == (a | b) - (a & b)");
418 DefTest(XorExpressionTest2,   EquivalentExpressionsOK<XorExprCheck2>,   "expression a ^ b == (a - (a & b)) | (b - (a & b))");
419 DefTest(MinusExpressionTest1, EquivalentExpressionsOK<MinusExprCheck1>, "expression a - b == a & (a ^ b)");
420 DefTest(MinusExpressionTest2, EquivalentExpressionsOK<MinusExprCheck2>, "expression a - b == a & ~(a & b)");
421
422 /**
423  * Routine to run an individual test.
424  * \param print  Should information be printed showing the progress of testing.
425  * \param numOfTests  The number of test iterations to run.
426  */
427 template <class Test>
428 bool Run(bool print = true, int numOfTests = 100)
429 {
430         if (print) cout << "Testing " << Test::Description() << " ..." << endl;
431         for (int i = 0; i < numOfTests; i++)
432         {
433                 if (not Test::Run(10)) return false;
434                 if (not Test::Run(100)) return false;
435                 if (not Test::Run(1000)) return false;
436                 if (print and ((i+1) % (numOfTests / 10) == 0))
437                 {
438                         cout << "  Completed " << ((i+1) * 100 / numOfTests) << "%" << endl;
439                 }
440         }
441         return true;
442 }
443
444 /**
445  * This is the top level testing method which calls individual tests.
446  * \param print  Should information be printed showing the progress of testing.
447  * \param numOfTests  The number of test iterations to run.
448  * \param seed  The random number seed to use.
449  */
450 bool testTriggerDomain(bool print = true, int numOfTests = 100, int seed = 0)
451 {
452         if (gClassTable->GetID("AliHLTDomainEntry") < 0)
453         {
454                 gSystem->Load("libAliHLTTrigger.so");
455         }
456         
457         gRandom->SetSeed(seed);
458         
459         if (not Run<AddRemoveTest>(print, numOfTests)) return false;
460         if (not Run<ComplementOperationTest>(print, numOfTests)) return false;
461         if (not Run<UnionOperationTest>(print, numOfTests)) return false;
462         if (not Run<IntersectOperationTest>(print, numOfTests)) return false;
463         if (not Run<XorOperationTest>(print, numOfTests)) return false;
464         if (not Run<PlusOperationTest>(print, numOfTests)) return false;
465         if (not Run<MinusOperationTest>(print, numOfTests)) return false;
466         if (not Run<XorExpressionTest1>(print, numOfTests)) return false;
467         if (not Run<XorExpressionTest2>(print, numOfTests)) return false;
468         if (not Run<MinusExpressionTest1>(print, numOfTests)) return false;
469         if (not Run<MinusExpressionTest2>(print, numOfTests)) return false;
470         
471         return true;
472 }
473
474 #ifndef __MAKECINT__
475
476 int main(int /*argc*/, const char** /*argv*/)
477 {
478         bool resultOk = testTriggerDomain();
479         if (not resultOk) return 1;
480         return 0;
481 }
482
483 #endif // __MAKECINT__
484