|
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <e32std.h> |
|
17 #include <e32base.h> |
|
18 #include "tdexcformatter.h" |
|
19 #include "dexcformatter.h" |
|
20 |
|
21 CDexcFormatterTest * CDexcFormatterTest::NewL(RTest &itest) |
|
22 { |
|
23 CDexcFormatterTest *self = CDexcFormatterTest::NewLC(itest); |
|
24 CleanupStack::Pop(); |
|
25 return self; |
|
26 } |
|
27 |
|
28 CDexcFormatterTest * CDexcFormatterTest::NewLC(RTest &itest) |
|
29 { |
|
30 CDexcFormatterTest *self = new(ELeave) CDexcFormatterTest(itest); |
|
31 CleanupStack::PushL(self); |
|
32 self->ConstructL(); |
|
33 return self; |
|
34 } |
|
35 |
|
36 void CDexcFormatterTest::ConstructL() |
|
37 { |
|
38 server = new(ELeave) CTestCrashDataSource; |
|
39 formatter = CDexcFormatter::NewL(); |
|
40 writer = CTestDataSave::NewL(); |
|
41 formatter->ConfigureDataSourceL(server); |
|
42 formatter->ConfigureDataSaveL(writer); |
|
43 } |
|
44 |
|
45 CDexcFormatterTest::CDexcFormatterTest(RTest &aTest) : itest(aTest) { } |
|
46 |
|
47 CDexcFormatterTest::~CDexcFormatterTest() |
|
48 { |
|
49 delete server; |
|
50 delete writer; |
|
51 delete formatter; |
|
52 } |
|
53 |
|
54 void CDexcFormatterTest::CleanupEComArray(TAny* aArray) |
|
55 { |
|
56 (static_cast<RImplInfoPtrArray*> (aArray))->ResetAndDestroy(); |
|
57 REComSession::FinalClose(); |
|
58 } |
|
59 |
|
60 void CDexcFormatterTest::TestSuiteL(TSuite aSuite) const |
|
61 { |
|
62 RDebug::Print(_L("-> TestSuite(%d)\n"), aSuite); |
|
63 TInt err; |
|
64 TBuf<23> name(KTestName); |
|
65 name.AppendNum(aSuite); |
|
66 itest.Next(name); |
|
67 |
|
68 switch(aSuite) |
|
69 { |
|
70 case EConfigData: |
|
71 { |
|
72 RDebug::Print(_L("EConfigData starting...\n")); |
|
73 TRAP(err, formatter->ConfigureDataSourceL(server)); |
|
74 itest(err == KErrNone); |
|
75 itest(server == formatter->iDataSource); |
|
76 |
|
77 TRAP(err, formatter->ConfigureDataSaveL(writer)); |
|
78 itest(err == KErrNone); |
|
79 itest(writer == formatter->iDataSave); |
|
80 |
|
81 TRAP(err, formatter->ConfigureDataSourceL(NULL)); |
|
82 itest(err == KErrNoMemory); |
|
83 |
|
84 TRAP(err, formatter->ConfigureDataSaveL(NULL)); |
|
85 itest(err == KErrNoMemory); |
|
86 RDebug::Print(_L("EConfigData passed!\n")); |
|
87 break; |
|
88 } |
|
89 |
|
90 case EFindImplementation: |
|
91 { |
|
92 |
|
93 RDebug::Print(_L("EFindImplementation starting...\n")); |
|
94 RImplInfoPtrArray infoArray; |
|
95 TCleanupItem cleanup(CDexcFormatterTest::CleanupEComArray, (TAny*)&infoArray); |
|
96 CleanupStack::PushL(cleanup); |
|
97 |
|
98 TRAPD(err, CDexcFormatter::ListAllImplementationsL(infoArray)); |
|
99 itest(err == KErrNone); |
|
100 |
|
101 CCoreDumpFormatter* findImpFormatter = 0; |
|
102 RBuf description; |
|
103 description.CreateL(MaxPluginDescription); |
|
104 CleanupClosePushL(description); |
|
105 |
|
106 err = KErrNotFound; |
|
107 for (TInt i = 0; i < infoArray.Count(); i++) |
|
108 { |
|
109 TUid uid = infoArray[i]->ImplementationUid(); |
|
110 findImpFormatter = CCoreDumpFormatter::NewL(uid); |
|
111 findImpFormatter->GetDescription(description); |
|
112 delete findImpFormatter; |
|
113 RDebug::Print(_L("found plugin[%d]: (%S)\n"), i, &description); |
|
114 if(description == KPluginDescription()) |
|
115 { |
|
116 itest(uid == KDexcFormatterUid); |
|
117 err = KErrNone; |
|
118 break; |
|
119 } |
|
120 description.Zero(); |
|
121 } |
|
122 CleanupStack::PopAndDestroy(); |
|
123 itest(err == KErrNone); |
|
124 CleanupStack::PopAndDestroy(); // infoArray, results in a call to CleanupEComArray |
|
125 break; |
|
126 |
|
127 } |
|
128 |
|
129 case EConfigParams: |
|
130 { |
|
131 RDebug::Print(_L("EConfigParams starting\n")); |
|
132 |
|
133 _LIT( KTrueFalseOpt, "True,False" ); |
|
134 _LIT( KFalseOpt, "False" ); |
|
135 _LIT( KTrueOpt, "True" ); |
|
136 |
|
137 TInt err; |
|
138 COptionConfig * param = NULL; |
|
139 TInt paramsCount = formatter->GetNumberConfigParametersL(); //it should be non leaving call |
|
140 itest(paramsCount == formatter->iConfigList.Count()); |
|
141 |
|
142 TRAP(err, param = formatter->GetConfigParameterL(0)); |
|
143 itest(param->Index() == CDexcFormatter::EDumpStack); |
|
144 itest(param->Uid() == KDEXCFormatterUid ); |
|
145 itest(param->Source() == COptionConfig::EFormatterPlugin); |
|
146 itest(param->Type() == COptionConfig::ETBool); |
|
147 itest(param->Options() == KTrueFalseOpt); |
|
148 itest(param->ValueAsBool() == 1); |
|
149 param = NULL; |
|
150 |
|
151 TRAP(err, param = formatter->GetConfigParameterL(1)); |
|
152 itest(param->Index() == CDexcFormatter::EAsciiStack); |
|
153 itest(param->Uid() == KDEXCFormatterUid ); |
|
154 itest(param->Source() == COptionConfig::EFormatterPlugin); |
|
155 itest(param->Type() == COptionConfig::ETBool); |
|
156 itest(param->Options() == KTrueFalseOpt); |
|
157 itest(param->ValueAsBool() == 0); |
|
158 param = NULL; |
|
159 |
|
160 RDebug::Printf("->TRAP(err, param = formatter->GetConfigParameterL(paramsCount))\n"); |
|
161 TRAP(err, param = formatter->GetConfigParameterL(paramsCount)); |
|
162 itest(err == KErrBadHandle); |
|
163 param = NULL; |
|
164 |
|
165 RDebug::Printf("formatter->SetConfigParameterL( 0, (TInt)EFalse, KFalseOpt );\n"); |
|
166 TRAP(err, formatter->SetConfigParameterL( 0, (TInt)EFalse, KFalseOpt )); |
|
167 itest(err == KErrNone); |
|
168 itest(formatter->iConfigList[0]->ValueAsBool() == EFalse); |
|
169 TRAP(err, param = formatter->GetConfigParameterL(0)); |
|
170 itest(formatter->iConfigList[0]->ValueAsBool() == EFalse); |
|
171 itest(param->ValueAsDesc() == KFalseOpt); |
|
172 |
|
173 RDebug::Printf("formatter->SetConfigParameterL( 0, (TInt)ETrue, KTrueOpt );\n"); |
|
174 TRAP(err, formatter->SetConfigParameterL( 0, (TInt)ETrue, KNullDesC )); |
|
175 itest(err == KErrNone); |
|
176 TRAP(err, param = formatter->GetConfigParameterL(0)); |
|
177 itest(formatter->iConfigList[0]->ValueAsBool()); |
|
178 itest(param->ValueAsDesc() == KTrueOpt); |
|
179 |
|
180 RDebug::Print(_L("EConfigParams finished\n")); |
|
181 |
|
182 break; |
|
183 } |
|
184 |
|
185 case EDumpLog: |
|
186 { |
|
187 RDebug::Print(_L("EDumpLog starting.... \n")); |
|
188 // 0123456789012345678901234567890123456789012345678901234567890123456789012345 |
|
189 _LIT8(KLine, "----------------------------------------------------------------------------"); |
|
190 // 0 12345678901234567890 1 23456789012345 6 78901234567890 1 2345678901234? |
|
191 _LIT8(KLogDump, "%S\r\nEKA2 USER CRASH LOG\r\nThread Name: %S\r\nThread ID: %u\r\nUser Stack %08X-%08X\r\n"); |
|
192 TBuf8<65+76+KMaxName+11+16> reference; //line, thread name, id and 2x 8-digits |
|
193 |
|
194 //add newLC |
|
195 CThreadInfo *thread = CThreadInfo::NewL(KCrashTid, |
|
196 KCrashThreadName, |
|
197 KCrashPid, |
|
198 KCrashThreadPriority, |
|
199 KCrashSvcStackPtr, |
|
200 KCrashSvcStackAddr, |
|
201 KCrashSvcStackSize, |
|
202 KCrashUsrStackAddr, |
|
203 KCrashUsrStackSize); |
|
204 |
|
205 RDebug::Print(_L(" -> writer->OpenL(_L(\"\"), handle)\n")); |
|
206 writer->OpenL(_L("")); //clear writer buffer |
|
207 formatter->DumpLogL(*thread); |
|
208 delete thread; |
|
209 itest(writer->iData != KLogDump()); |
|
210 reference.Format(KLogDump, &KLine, &KCrashThreadName8, KCrashTid, KCrashUsrStackAddr, KCrashUsrStackAddr + KCrashUsrStackSize); |
|
211 itest(writer->iData == reference); |
|
212 RDebug::Print(_L("EDumpLog finished\n")); |
|
213 break; |
|
214 } |
|
215 |
|
216 case EDumpPanicInfo: |
|
217 { |
|
218 RDebug::Print(_L("EDumpPanicInfo starting.... \n")); |
|
219 // 0123456 7 8 9 0 |
|
220 _LIT8(KPanicDump, "Panic: %S-%d\r\n"); |
|
221 RBuf8 reference; |
|
222 reference.CreateL(KPanicDump().Length() + 11 + KMaxExitCategoryName); |
|
223 CleanupClosePushL(reference); |
|
224 |
|
225 TCrashInfo crash; |
|
226 crash.iReason = KCrashReason; |
|
227 crash.iCategory = KCrashCategory; |
|
228 |
|
229 writer->OpenL(_L("")); //clear writer buffer |
|
230 formatter->DumpPanicInfoL(crash); |
|
231 itest(writer->iData != KPanicDump()); |
|
232 |
|
233 reference.Format(KPanicDump, &KCrashCategory8, KCrashReason); |
|
234 |
|
235 itest(writer->iData == reference); |
|
236 |
|
237 CleanupStack::PopAndDestroy(); //reference |
|
238 RDebug::Print(_L("EDumpPanicInfo finished\n")); |
|
239 break; |
|
240 } |
|
241 |
|
242 case EDumpExcInfo: |
|
243 { |
|
244 RDebug::Print(_L("EDumpExcInfo starting.... \n")); |
|
245 |
|
246 _LIT8(KExcDump, "\r\nUNHANDLED EXCEPTION:\r\ncode=%d PC=%08x FAR=%08x FSR=%08x\r\nR13svc=%08x R14svc=%08x SPSRsvc=%08x\r\n"); |
|
247 // 012345 6 7890123456789012345678901234567890123 4 5 |
|
248 RBuf8 reference; |
|
249 reference.CreateL(KExcDump().Length() + 11 + 6*4); |
|
250 CleanupClosePushL(reference); |
|
251 |
|
252 TCrashInfo crash; |
|
253 crash.iType = TCrashInfo::ECrashException; |
|
254 crash.iContext.iExcCode = KCrashExcCode; |
|
255 |
|
256 crash.iContext.iFaultAddress = KCrashFaultAddress; |
|
257 crash.iContext.iFaultStatus = KCrashFaultStatus; |
|
258 |
|
259 crash.iContext.iR15 = KRegValue32 + KCrashTid; |
|
260 crash.iContext.iR13Svc = crash.iContext.iR15 + 1; |
|
261 crash.iContext.iR14Svc = crash.iContext.iR15 + 2; |
|
262 crash.iContext.iSpsrSvc = crash.iContext.iR15 + 3; |
|
263 |
|
264 writer->Open(_L("")); //clear writer buffer |
|
265 formatter->DumpExcInfoL(crash); |
|
266 |
|
267 RDebug::Print( _L("-> itest(writer->iData != KExcDump())\n") ); |
|
268 itest(writer->iData != KExcDump()); |
|
269 |
|
270 TInt32 code = KCrashExcCode; |
|
271 TInt32 pc = KRegValue32 + KCrashTid; //index of r15 |
|
272 TInt32 far = KCrashFaultAddress; |
|
273 TInt32 fsr = KCrashFaultStatus; |
|
274 TInt32 r13svc = KRegValue32 + KCrashTid + 1; //index of r13svc |
|
275 TInt32 r14svc = KRegValue32 + KCrashTid + 2; //index of r14svc |
|
276 TInt32 spsr = KRegValue32 + KCrashTid + 3; //index of spsr |
|
277 |
|
278 reference.Format(KExcDump, code, pc, far, fsr, r13svc, r14svc, spsr); |
|
279 |
|
280 /* |
|
281 RBuf8 referencePrint; |
|
282 referencePrint.CreateL(256); |
|
283 referencePrint.Copy( reference ); |
|
284 char *tonp = (char*) referencePrint.PtrZ(); |
|
285 LOG_MSG2(" KExcDump=%s\n", tonp); |
|
286 referencePrint.Close(); |
|
287 writer->Print(); |
|
288 */ |
|
289 RDebug::Print( _L("-> itest(writer->iData == reference)\n") ); |
|
290 itest(writer->iData == reference); |
|
291 |
|
292 CleanupStack::PopAndDestroy(); //reference |
|
293 RDebug::Print(_L("EDumpExcInfo finished\n")); |
|
294 |
|
295 break; |
|
296 } |
|
297 |
|
298 case EDumpRegisters: |
|
299 { |
|
300 RDebug::Print(_L("EDumpRegisters starting.... \n")); |
|
301 |
|
302 _LIT8(KCpsrDump, "\r\nUSER REGISTERS:\r\nCPSR=%08x\r\n"); |
|
303 _LIT8(KRegsDump, "r%02d=%08x %08x %08x %08x\r\n"); |
|
304 RBuf8 reference; |
|
305 reference.CreateL(KCpsrDump().Length() + 4 + KCoreRegsCount * (KRegsDump().Length() + 4*4)); |
|
306 CleanupClosePushL(reference); |
|
307 |
|
308 writer->Open(_L("")); //clear writer buffer |
|
309 TRAP(err, formatter->DumpRegistersL(KCrashTid)); |
|
310 itest(err == KErrNone); |
|
311 itest(writer->iData != KRegsDump()); |
|
312 |
|
313 TInt32 cpsr = KRegValue32 + KCrashTid + 16; //index of cpsr |
|
314 |
|
315 reference.Format(KCpsrDump, cpsr); |
|
316 TBuf8<41> line; |
|
317 #define REG_VAL(i) ( KRegValue32 + KCrashTid + i ) |
|
318 for(TInt i = 0; i < KCoreRegsCount; i+=4) |
|
319 { |
|
320 TInt reg0 = REG_VAL(i); |
|
321 TInt reg1 = REG_VAL(i+1); |
|
322 TInt reg2 = REG_VAL(i+2); |
|
323 TInt reg3 = REG_VAL(i+3); |
|
324 line.Format(KRegsDump, i, reg0, reg1, reg2, reg3); |
|
325 reference.Append(line); |
|
326 } |
|
327 #undef REG_VAL |
|
328 itest(writer->iData == reference); |
|
329 CleanupStack::PopAndDestroy(); //reference |
|
330 RDebug::Print(_L("EDumpRegisters finished\n")); |
|
331 |
|
332 break; |
|
333 } |
|
334 |
|
335 case EDumpCodeSegs: |
|
336 { |
|
337 RDebug::Print(_L("EDumpCodeSegs starting.... \n")); |
|
338 |
|
339 _LIT8(KSegsLine, "%08X-%08X %S\r\n"); |
|
340 RBuf8 line; |
|
341 CleanupClosePushL(line); |
|
342 line.CreateL(KSegsLine().Length() + 2*4 + KMaxFileName); |
|
343 // 0123456789012345679012 |
|
344 _LIT8(KSegsDump, "\r\nCODE SEGMENTS:\r\n"); |
|
345 RBuf8 reference; |
|
346 CleanupClosePushL(reference); |
|
347 reference.CreateL(KSegsDump().Length() + KCodeSegsCount * (line.MaxLength()) + 76); |
|
348 |
|
349 writer->Open(_L("")); //clear writer buffer |
|
350 formatter->DumpCodeSegsL(KCrashPid); |
|
351 //writer->Print(); |
|
352 |
|
353 itest(writer->iData != KSegsDump()); |
|
354 RDebug::Print( _L(" writer->iData.Length() = %d\n"), writer->iData.Length() ); |
|
355 |
|
356 reference = KSegsDump(); |
|
357 TUint base; |
|
358 TUint size; |
|
359 |
|
360 // See CTestCrashDataSource::GetCodeSegmentsL() |
|
361 |
|
362 base = KCrashCodeRunAddr + KCrashPid; |
|
363 size= KCrashCodeSize + KCrashPid; |
|
364 line.Format(KSegsLine, base, base + size, &KCrashProcessName8); |
|
365 reference.Append(line); |
|
366 |
|
367 base = KCrashCodeRunAddr + KCrashPid + 1; |
|
368 size= KCrashCodeSize + KCrashPid + 1; |
|
369 line.Format(KSegsLine, base, base + size, &KLibName1_8); |
|
370 reference.Append(line); |
|
371 |
|
372 base = KCrashCodeRunAddr + KCrashPid + 2; |
|
373 size= KCrashCodeSize + KCrashPid + 2; |
|
374 line.Format(KSegsLine, base, base + size, &KLibName2_8); |
|
375 reference.Append(line); |
|
376 |
|
377 reference.Append(_L8("\r\n")); |
|
378 |
|
379 /* |
|
380 RBuf8 referencePrint; |
|
381 referencePrint.CreateL(256); |
|
382 referencePrint.Copy( reference ); |
|
383 char *tonp = (char*) referencePrint.PtrZ(); |
|
384 LOG_MSG2(" KCodeSeg=%s\n", tonp); |
|
385 referencePrint.Close(); |
|
386 writer->Print(); |
|
387 */ |
|
388 |
|
389 itest(writer->iData == reference); |
|
390 CleanupStack::PopAndDestroy(2); |
|
391 RDebug::Print(_L("EDumpCodeSegs finished\n")); |
|
392 break; |
|
393 } |
|
394 |
|
395 case EDumpStack: |
|
396 { |
|
397 RDebug::Print(_L("EDumpStack starting.... \n")); |
|
398 _LIT( KFalseOpt, "False" ); |
|
399 |
|
400 CThreadInfo *thread = CThreadInfo::NewL(KCrashTid, |
|
401 KCrashThreadName, |
|
402 KCrashPid, |
|
403 KCrashThreadPriority, |
|
404 KCrashSvcStackPtr, |
|
405 KCrashSvcStackAddr, |
|
406 KCrashSvcStackSize, |
|
407 KCrashUsrStackAddr, |
|
408 KCrashUsrStackSize); |
|
409 |
|
410 CleanupStack::PushL(thread); |
|
411 |
|
412 RBuf8 stack; |
|
413 stack.CreateL(KCrashUsrStackSize*5); |
|
414 CleanupClosePushL(stack); |
|
415 |
|
416 writer->Open(_L("")); //clear writer buffer |
|
417 formatter->SetConfigParameterL( 1, (TInt32)EFalse, KFalseOpt ); //binary dump |
|
418 formatter->DumpStackL(KCrashTid, *thread); |
|
419 |
|
420 for( TInt i = 0; i < KCrashUsrStackSize; i++ ) |
|
421 { |
|
422 stack.Append((TUint8*)&i, 1); |
|
423 } |
|
424 |
|
425 RDebug::Printf("itest(writer->iData == stack);"); |
|
426 itest(writer->iData == stack); |
|
427 itest(writer->iData != _L8("")); |
|
428 stack.Zero(); |
|
429 |
|
430 for(TInt i = 0; i < KCrashUsrStackSize; i+=16) |
|
431 { |
|
432 stack.AppendNumFixedWidth(KCrashUsrStackAddr + i, EHex, 8); |
|
433 stack.Append(_L8(": ")); |
|
434 for(TInt j = 0; j < 16; ++j) |
|
435 { |
|
436 stack.AppendNumFixedWidth(i+j, EHex, 2); |
|
437 stack.Append(' '); |
|
438 } |
|
439 for(TInt j = 0; j < 16; ++j) |
|
440 { |
|
441 TInt c = i+j; |
|
442 if(c < 0x20 || c >= 0x7f) //something writable |
|
443 c = 0x2e; //. |
|
444 stack.Append(TChar(c)); |
|
445 } |
|
446 stack.AppendFormat(_L8("\r\n")); |
|
447 } |
|
448 |
|
449 writer->OpenL(_L("")); //clear writer buffer |
|
450 RDebug::Printf("formatter->SetConfigParameterL( 1, (TInt)ETrue, KNullDesC );"); |
|
451 formatter->SetConfigParameterL( 1, (TInt)ETrue, KNullDesC ); //ascii dump |
|
452 |
|
453 RDebug::Printf("formatter->DumpStackL(KCrashTid, *thread);"); |
|
454 formatter->DumpStackL(KCrashTid, *thread); |
|
455 |
|
456 RDebug::Printf("itest(writer->iData == stack);"); |
|
457 itest(writer->iData == stack); |
|
458 itest(writer->iData != _L8("")); |
|
459 CleanupStack::PopAndDestroy(); |
|
460 CleanupStack::PopAndDestroy(thread); |
|
461 RDebug::Print(_L("EDumpStack finished\n")); |
|
462 break; |
|
463 } |
|
464 |
|
465 default: |
|
466 break; |
|
467 } |
|
468 RDebug::Print(_L("<- TestSuite(%d)\n"), aSuite); |
|
469 } |
|
470 |
|
471 void RunTestsL() |
|
472 { |
|
473 RDebug::Print(_L("-> RunTestsL()\n")); |
|
474 |
|
475 CDexcFormatterTest::TSuite suite[] = { |
|
476 CDexcFormatterTest::ENone, |
|
477 CDexcFormatterTest::EConfigData, |
|
478 CDexcFormatterTest::EFindImplementation, |
|
479 CDexcFormatterTest::EConfigParams, |
|
480 CDexcFormatterTest::EGetDescription, |
|
481 CDexcFormatterTest::EDumpLog, |
|
482 CDexcFormatterTest::EDumpPanicInfo, |
|
483 CDexcFormatterTest::EDumpExcInfo, |
|
484 CDexcFormatterTest::EDumpRegisters, |
|
485 CDexcFormatterTest::EDumpCodeSegs, |
|
486 CDexcFormatterTest::EDumpStack, |
|
487 CDexcFormatterTest::ECrash |
|
488 }; |
|
489 |
|
490 RTest rtest(KTestTitle); |
|
491 rtest.Title(); |
|
492 rtest.Start(_L("")); |
|
493 CDexcFormatterTest::TSuite *test = suite; |
|
494 |
|
495 while(*test != CDexcFormatterTest::ECrash) |
|
496 { |
|
497 CDexcFormatterTest *itester = CDexcFormatterTest::NewLC(rtest); |
|
498 itester->TestSuiteL(*test++); |
|
499 CleanupStack::PopAndDestroy(); |
|
500 } |
|
501 |
|
502 rtest.End(); |
|
503 rtest.Close(); |
|
504 RDebug::Print(_L("<- RunTestsL()\n")); |
|
505 } |
|
506 |
|
507 TInt E32Main() |
|
508 { |
|
509 RDebug::Print(_L("-> E32Main()\n")); |
|
510 __UHEAP_MARK; |
|
511 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
512 __ASSERT_ALWAYS(cleanup, User::Panic(_L("D_EXC_TEST-NO_CLEANUP"), KErrNoMemory)); |
|
513 |
|
514 TRAPD(err, RunTestsL()); |
|
515 __ASSERT_ALWAYS(!err, User::Panic(_L("D_EXC_TEST-RunTestsL trapped with error: "), err)); |
|
516 |
|
517 delete cleanup; |
|
518 __UHEAP_MARKEND; |
|
519 RDebug::Print(_L("<- E32Main()\n")); |
|
520 return err; |
|
521 } |
|
522 |