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