|
1 // Copyright (c) 2004-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 the License "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 // Unit tests for the CMassStorageDrive and CDriveManager classes |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @internalTechnology |
|
21 */ |
|
22 |
|
23 #include <e32std.h> |
|
24 #include <e32std_private.h> |
|
25 #include <e32twin.h> |
|
26 #include <e32test.h> |
|
27 #include <e32property.h> |
|
28 |
|
29 #include "usbmsshared.h" |
|
30 #include "drivemanager.h" |
|
31 |
|
32 |
|
33 enum TestStep |
|
34 { |
|
35 EStepRead0, |
|
36 EStepRead1, |
|
37 EStepWrite0, |
|
38 EStepWrite1, |
|
39 EStepConnected, |
|
40 EStepActive, |
|
41 EStepMediaRemoved, |
|
42 EStepLocked, |
|
43 EStepDisconnecting, |
|
44 EStepDisconnected, |
|
45 EStepConnecting |
|
46 }; |
|
47 |
|
48 LOCAL_D RTest test(_L("MSDRIVE")); |
|
49 LOCAL_D const TDriveNumber gDrive1 = EDriveL; // used drive |
|
50 LOCAL_D const TDriveNumber gDrive2 = EDriveN; // unused drive |
|
51 LOCAL_D CDriveManager* gMgr = NULL; |
|
52 LOCAL_D TestStep gTestStep = EStepRead0; |
|
53 |
|
54 #define NEXT(x) test.Next(_L(#x)); gTestStep = x; |
|
55 |
|
56 |
|
57 /** |
|
58 These CProxyDrive functions are copies of code in sf_ext.cpp, |
|
59 since we don't link to EFILE. |
|
60 */ |
|
61 CProxyDrive::CProxyDrive(CMountCB* aMount) : iMount(aMount) {} |
|
62 |
|
63 EXPORT_C TInt CProxyDrive::ControlIO( |
|
64 const RMessagePtr2& /*aMessage*/, |
|
65 TInt /*aCommand*/,TAny* /*aParam1*/,TAny* /*aParam2*/) |
|
66 { |
|
67 return(KErrNone); |
|
68 } |
|
69 |
|
70 EXPORT_C TInt CProxyDrive::DeleteNotify(TInt64 /*aPos*/, TInt /*aLength*/) |
|
71 { |
|
72 return(KErrNone); |
|
73 } |
|
74 |
|
75 EXPORT_C TInt CProxyDrive::GetInterface(TInt /*aInterfaceId*/, TAny*& /*aInterface*/, TAny* /*aInput*/) |
|
76 { return KErrNotSupported; } |
|
77 |
|
78 // Implemented the GetLastErrorInfo method here as this is usually |
|
79 // exported by EFILE, but these unit tests don't link to it. |
|
80 EXPORT_C TInt CProxyDrive::GetLastErrorInfo(TDes8& /*anErrorInfo*/) |
|
81 { return KErrNotSupported; } |
|
82 |
|
83 CProxyDrive::~CProxyDrive() |
|
84 { |
|
85 } |
|
86 |
|
87 EXPORT_C TInt CProxyDrive::Read(TInt64 aPos, TInt aLength, const TAny* aTrg, TInt /*aThreadHandle*/, TInt /*aOffset*/, TInt /*aFlags*/) |
|
88 { |
|
89 return Read(aPos, aLength, *(TDes8*)aTrg); |
|
90 } |
|
91 |
|
92 EXPORT_C TInt CProxyDrive::Write(TInt64 aPos, TInt /*aLength*/, const TAny* aSrc, TInt /*aThreadHandle*/, TInt /*aOffset*/, TInt /*aFlags*/) |
|
93 { |
|
94 return Write(aPos, *(TDesC8*)aSrc); |
|
95 } |
|
96 |
|
97 /** |
|
98 CMassStorageMountCB gets the CProxyDrive from the filesystem, |
|
99 but here we want to instantiate our own derived class for testing. |
|
100 This allows us to control the error code returned by each function. |
|
101 */ |
|
102 class CTestProxyDrive : public CProxyDrive |
|
103 { |
|
104 public: |
|
105 static TInt iRetval; |
|
106 static TInt iRetval_caps; |
|
107 static TLocalDriveCapsV4 iCaps; |
|
108 |
|
109 CTestProxyDrive(CDriveManager& aDriveManager) : CProxyDrive(NULL) |
|
110 { |
|
111 iCaps.iType = ::EMediaUnknown; |
|
112 |
|
113 iWriteTransferPublisher = CDriveWriteTransferPublisher::NewL(aDriveManager.iDrives); |
|
114 iReadTransferPublisher = CDriveReadTransferPublisher::NewL(aDriveManager.iDrives); |
|
115 } |
|
116 |
|
117 ~CTestProxyDrive() |
|
118 { |
|
119 delete iWriteTransferPublisher; |
|
120 delete iReadTransferPublisher; |
|
121 } |
|
122 virtual TInt Initialise() |
|
123 { |
|
124 return iRetval; |
|
125 } |
|
126 virtual TInt Dismounted() |
|
127 { |
|
128 return iRetval; |
|
129 } |
|
130 virtual TInt Enlarge(TInt ) |
|
131 { |
|
132 return iRetval; |
|
133 } |
|
134 virtual TInt ReduceSize(TInt , TInt ) |
|
135 { |
|
136 return iRetval; |
|
137 } |
|
138 virtual TInt Read(TInt64 ,TInt ,const TAny* ,TInt ,TInt ) |
|
139 { |
|
140 iReadTransferPublisher->StartTimer(); |
|
141 return iRetval; |
|
142 } |
|
143 virtual TInt Read(TInt64 ,TInt len, TDes8& buf) |
|
144 { |
|
145 iReadTransferPublisher->StartTimer(); |
|
146 buf.SetLength(len); |
|
147 return iRetval; |
|
148 } |
|
149 virtual TInt Write(TInt64 ,TInt ,const TAny* ,TInt ,TInt ) |
|
150 { |
|
151 iWriteTransferPublisher->StartTimer(); |
|
152 return iRetval; |
|
153 } |
|
154 virtual TInt Write(TInt64 ,const TDesC8& ) |
|
155 { |
|
156 iWriteTransferPublisher->StartTimer(); |
|
157 return iRetval; |
|
158 } |
|
159 virtual TInt Caps(TDes8& aBuf) |
|
160 { |
|
161 ((TLocalDriveCapsV4Buf&)aBuf) = iCaps; |
|
162 |
|
163 return iRetval_caps; |
|
164 } |
|
165 virtual TInt Format(TFormatInfo& ) |
|
166 { |
|
167 return iRetval; |
|
168 } |
|
169 virtual TInt Format(TInt64 ,TInt ) |
|
170 { |
|
171 return iRetval; |
|
172 } |
|
173 virtual TInt SetMountInfo(const TDesC8* ,TInt ) |
|
174 { |
|
175 return iRetval; |
|
176 } |
|
177 virtual TInt ForceRemount(TUint ) |
|
178 { |
|
179 return iRetval; |
|
180 } |
|
181 virtual TInt Unlock(TMediaPassword &, TBool ) |
|
182 { |
|
183 return iRetval; |
|
184 } |
|
185 virtual TInt Lock(TMediaPassword &, TMediaPassword &, TBool ) |
|
186 { |
|
187 return iRetval; |
|
188 } |
|
189 virtual TInt Clear(TMediaPassword &) |
|
190 { |
|
191 return iRetval; |
|
192 } |
|
193 virtual TInt ErasePassword() |
|
194 { |
|
195 return iRetval; |
|
196 } |
|
197 |
|
198 private: |
|
199 /** |
|
200 Publish and subscribe properties for tracking data transfer volume |
|
201 */ |
|
202 CDriveWriteTransferPublisher* iWriteTransferPublisher; |
|
203 CDriveReadTransferPublisher* iReadTransferPublisher; |
|
204 }; |
|
205 |
|
206 TInt CTestProxyDrive::iRetval = KErrNone; |
|
207 TInt CTestProxyDrive::iRetval_caps = KErrNone; |
|
208 TLocalDriveCapsV4 CTestProxyDrive::iCaps; |
|
209 |
|
210 /** |
|
211 From USBMSAPP: |
|
212 A set of static objects that hold the latest properties published by Mass Storage, |
|
213 and a set of corresponding static functions that process the publish events. |
|
214 The functions are passed by pointer to, and invoked by, CPropertyWatch instances. |
|
215 */ |
|
216 class PropertyHandlers |
|
217 { |
|
218 public: |
|
219 /** The prototype for all public property handler functions */ |
|
220 typedef void(*THandler)(RProperty&); |
|
221 |
|
222 public: |
|
223 static void Read(RProperty& aProperty); |
|
224 static void Written(RProperty& aProperty); |
|
225 static void DriveStatus(RProperty& aProperty); |
|
226 |
|
227 public: |
|
228 static TBuf8<16> iAllDrivesStatus; |
|
229 static TUsbMsBytesTransferred iKBytesRead; |
|
230 static TUsbMsBytesTransferred iKBytesWritten; |
|
231 }; |
|
232 |
|
233 /** |
|
234 From USBMSAPP: |
|
235 An active object that subscribes to a specified Mass Storage property and |
|
236 calls a provided handler each time the property is published. |
|
237 */ |
|
238 class CPropertyWatch : public CActive |
|
239 { |
|
240 public: |
|
241 static CPropertyWatch* NewLC(TUsbMsDriveState_Subkey aSubkey, PropertyHandlers::THandler aHandler); |
|
242 private: |
|
243 CPropertyWatch(PropertyHandlers::THandler aHandler); |
|
244 void ConstructL(TUsbMsDriveState_Subkey aSubkey); |
|
245 ~CPropertyWatch(); |
|
246 void RunL(); |
|
247 void DoCancel(); |
|
248 private: |
|
249 RProperty iProperty; |
|
250 PropertyHandlers::THandler iHandler; |
|
251 }; |
|
252 |
|
253 CPropertyWatch* CPropertyWatch::NewLC(TUsbMsDriveState_Subkey aSubkey, PropertyHandlers::THandler aHandler) |
|
254 { |
|
255 CPropertyWatch* me=new(ELeave) CPropertyWatch(aHandler); |
|
256 CleanupStack::PushL(me); |
|
257 me->ConstructL(aSubkey); |
|
258 return me; |
|
259 } |
|
260 |
|
261 CPropertyWatch::CPropertyWatch(PropertyHandlers::THandler aHandler) |
|
262 : CActive(0), iHandler(aHandler) |
|
263 {} |
|
264 |
|
265 void CPropertyWatch::ConstructL(TUsbMsDriveState_Subkey aSubkey) |
|
266 { |
|
267 User::LeaveIfError(iProperty.Attach(KUsbMsDriveState_Category, aSubkey)); |
|
268 CActiveScheduler::Add(this); |
|
269 // initial subscription and process current property value |
|
270 RunL(); |
|
271 } |
|
272 |
|
273 CPropertyWatch::~CPropertyWatch() |
|
274 { |
|
275 Cancel(); |
|
276 iProperty.Close(); |
|
277 } |
|
278 |
|
279 void CPropertyWatch::DoCancel() |
|
280 { |
|
281 iProperty.Cancel(); |
|
282 } |
|
283 |
|
284 void CPropertyWatch::RunL() |
|
285 { |
|
286 // resubscribe before processing new value to prevent missing updates |
|
287 iProperty.Subscribe(iStatus); |
|
288 |
|
289 iHandler(iProperty); |
|
290 |
|
291 SetActive(); |
|
292 } |
|
293 |
|
294 |
|
295 TBuf8<16> PropertyHandlers::iAllDrivesStatus; |
|
296 TUsbMsBytesTransferred PropertyHandlers::iKBytesRead; |
|
297 TUsbMsBytesTransferred PropertyHandlers::iKBytesWritten; |
|
298 |
|
299 |
|
300 /** |
|
301 Handle a publish event for the Bytes Read property. |
|
302 */ |
|
303 void PropertyHandlers::Read(RProperty& aProperty) |
|
304 { |
|
305 const TUint KNoBytesToRead = 1000; |
|
306 test(aProperty.Get(iKBytesRead)==KErrNone); |
|
307 TInt kbytes = iKBytesRead[0]; |
|
308 |
|
309 TBuf8<KNoBytesToRead> buf; |
|
310 buf.SetLength(KNoBytesToRead); |
|
311 TInt err; |
|
312 |
|
313 switch(gTestStep) |
|
314 { |
|
315 case EStepRead0: |
|
316 // don't do anything until 1st KB reported in 1s interval |
|
317 if(kbytes==0) |
|
318 { |
|
319 break; |
|
320 } |
|
321 test(kbytes==1); |
|
322 |
|
323 test(KErrNone == gMgr->Drive(0,err)->Read(0,KNoBytesToRead,buf)); |
|
324 NEXT(EStepRead1); |
|
325 break; |
|
326 |
|
327 case EStepRead1: |
|
328 test(kbytes==2); |
|
329 |
|
330 // trigger an update: |
|
331 test(KErrNone == gMgr->Drive(0,err)->Write(0,buf)); |
|
332 NEXT(EStepWrite0); |
|
333 break; |
|
334 |
|
335 default: |
|
336 break; |
|
337 } |
|
338 } |
|
339 |
|
340 /** |
|
341 Handle a publish event for the Bytes Written property. |
|
342 */ |
|
343 void PropertyHandlers::Written(RProperty& aProperty) |
|
344 { |
|
345 const TUint KNoBytesToWrite = 1000; |
|
346 test(aProperty.Get(iKBytesWritten)==KErrNone); |
|
347 TInt kbytes = iKBytesWritten[0]; |
|
348 |
|
349 TBuf8<KNoBytesToWrite> buf; |
|
350 buf.SetLength(KNoBytesToWrite); |
|
351 TInt err; |
|
352 |
|
353 switch(gTestStep) |
|
354 { |
|
355 case EStepWrite0: |
|
356 test(kbytes==2); |
|
357 |
|
358 test(KErrNone == gMgr->Drive(0,err)->Write(0,buf)); |
|
359 NEXT(EStepWrite1); |
|
360 break; |
|
361 |
|
362 case EStepWrite1: |
|
363 test(kbytes==3); |
|
364 |
|
365 // trigger transient change to Active state: |
|
366 test(KErrNone == gMgr->Drive(0,err)->Write(0,buf)); |
|
367 NEXT(EStepConnected); |
|
368 break; |
|
369 |
|
370 default: |
|
371 break; |
|
372 } |
|
373 } |
|
374 |
|
375 /** |
|
376 Handle a publish event for the Drive Status property. |
|
377 */ |
|
378 void PropertyHandlers::DriveStatus(RProperty& aProperty) |
|
379 { |
|
380 RDebug::Print(_L(">> PropertyHandlers::DriveStatus")); |
|
381 TInt err = aProperty.Get(iAllDrivesStatus); |
|
382 test(err == KErrNone); |
|
383 |
|
384 // There should be status for 2 drives: |
|
385 // (Note: there is a pair of bytes per drive, |
|
386 // drive number and drive status.) |
|
387 test(2 == iAllDrivesStatus.Length()/2); |
|
388 test(iAllDrivesStatus[0] == gDrive1); |
|
389 test(iAllDrivesStatus[2*1] == gDrive2); |
|
390 TInt status = iAllDrivesStatus[1]; |
|
391 |
|
392 switch(gTestStep) |
|
393 { |
|
394 case EStepConnected: |
|
395 test(status==EUsbMsDriveState_Connected); |
|
396 |
|
397 test(KErrNone==gMgr->Drive(0,err)->SetCritical(ETrue)); |
|
398 NEXT(EStepActive); |
|
399 break; |
|
400 |
|
401 case EStepActive: |
|
402 test(status==EUsbMsDriveState_Active); |
|
403 |
|
404 CTestProxyDrive::iRetval_caps = KErrNotReady; |
|
405 test(CMassStorageDrive::EMediaNotPresent |
|
406 ==gMgr->Drive(0,err)->CheckDriveState()); |
|
407 CTestProxyDrive::iRetval_caps = KErrNone; |
|
408 |
|
409 NEXT(EStepMediaRemoved); |
|
410 break; |
|
411 |
|
412 case EStepMediaRemoved: |
|
413 { |
|
414 test(status==EUsbMsDriveState_MediaNotPresent); |
|
415 |
|
416 gMgr->Drive(0,err)->CheckDriveState(); // clear old state |
|
417 |
|
418 CTestProxyDrive::iRetval = KErrLocked; |
|
419 TBuf8<1> buf; |
|
420 buf.SetLength(1); |
|
421 test(KErrLocked==gMgr->Drive(0,err)->Write(0,buf)); |
|
422 CTestProxyDrive::iRetval = KErrNone; |
|
423 NEXT(EStepLocked); |
|
424 } |
|
425 break; |
|
426 |
|
427 case EStepLocked: |
|
428 test(status==EUsbMsDriveState_Locked); |
|
429 |
|
430 test(KErrNone == gMgr->Disconnect(0)); |
|
431 test(KErrNone == gMgr->Disconnect(0)); // ensure it can be called more than once |
|
432 NEXT(EStepDisconnecting); |
|
433 break; |
|
434 |
|
435 case EStepDisconnecting: |
|
436 test(status==EUsbMsDriveState_Disconnecting); |
|
437 |
|
438 test(KErrNone == gMgr->DeregisterDrive(0)); |
|
439 NEXT(EStepDisconnected); |
|
440 break; |
|
441 |
|
442 case EStepDisconnected: |
|
443 test(status==EUsbMsDriveState_Disconnected); |
|
444 |
|
445 test(KErrNone == gMgr->Connect(0)); |
|
446 test(KErrNone == gMgr->Connect(0)); // ensure it can be called more than once |
|
447 NEXT(EStepConnecting); |
|
448 break; |
|
449 |
|
450 case EStepConnecting: |
|
451 test(status==EUsbMsDriveState_Connecting); |
|
452 CActiveScheduler::Stop(); |
|
453 break; |
|
454 |
|
455 default: |
|
456 break; |
|
457 } |
|
458 |
|
459 RDebug::Print(_L("<< PropertyHandlers::DriveStatus")); |
|
460 } |
|
461 |
|
462 LOCAL_C void doTestL() |
|
463 { |
|
464 test.Start(_L("MSDrive1")); |
|
465 |
|
466 CActiveScheduler* sched = new(ELeave) CActiveScheduler; |
|
467 CleanupStack::PushL(sched); |
|
468 CActiveScheduler::Install(sched); |
|
469 |
|
470 RArray<TInt> driveMap; |
|
471 CleanupClosePushL(driveMap); |
|
472 driveMap.AppendL(gDrive1); |
|
473 driveMap.AppendL(gDrive2); |
|
474 |
|
475 gMgr = CDriveManager::NewL(driveMap); |
|
476 CleanupStack::PushL(gMgr); |
|
477 TInt err = KErrGeneral; |
|
478 CMassStorageDrive* drive1 = gMgr->Drive(0,err); |
|
479 test(err == KErrNone); |
|
480 |
|
481 /////////////////////////////////////////////////////////////////////////// |
|
482 test.Next(_L("Check initial state")); |
|
483 test(CMassStorageDrive::EDisconnected==drive1->MountState()); |
|
484 test(CMassStorageDrive::EErrDisMounted==drive1->DriveState()); |
|
485 test(0==drive1->KBytesRead()); |
|
486 test(0==drive1->KBytesWritten()); |
|
487 test(EFalse==drive1->IsMediaChanged()); |
|
488 |
|
489 /////////////////////////////////////////////////////////////////////////// |
|
490 test.Next(_L("Ensure Read/Write/Caps don't work when disconnected")); |
|
491 |
|
492 const TInt KNoBytes = 1000; |
|
493 TBuf8<KNoBytes> buf; |
|
494 TLocalDriveCapsV4 caps; |
|
495 test(KErrDisconnected==drive1->Read(0,0,buf)); |
|
496 test(KErrDisconnected==drive1->Write(0,buf)); |
|
497 test(KErrDisconnected==drive1->Caps(caps)); |
|
498 |
|
499 /////////////////////////////////////////////////////////////////////////// |
|
500 test.Next(_L("Test EConnecting state")); |
|
501 |
|
502 drive1->SetMountConnecting(); |
|
503 test(CMassStorageDrive::EConnecting==drive1->MountState()); |
|
504 test(KErrDisconnected==drive1->Read(0,0,buf)); |
|
505 test(KErrDisconnected==drive1->Write(0,buf)); |
|
506 test(KErrDisconnected==drive1->Caps(caps)); |
|
507 |
|
508 /////////////////////////////////////////////////////////////////////////// |
|
509 test.Next(_L("Test EDisconnecting state")); |
|
510 |
|
511 drive1->SetMountDisconnecting(); |
|
512 test(CMassStorageDrive::EDisconnecting==drive1->MountState()); |
|
513 test(KErrDisconnected==drive1->Read(0,0,buf)); |
|
514 test(KErrDisconnected==drive1->Write(0,buf)); |
|
515 test(KErrDisconnected==drive1->Caps(caps)); |
|
516 |
|
517 /////////////////////////////////////////////////////////////////////////// |
|
518 test.Next(_L("Test EConnected state")); |
|
519 |
|
520 CTestProxyDrive* proxyDrive = new(ELeave) CTestProxyDrive(*gMgr); |
|
521 CleanupStack::PushL(proxyDrive); |
|
522 |
|
523 TBool mediaChanged = EFalse; |
|
524 test(KErrNone==gMgr->RegisterDrive(*proxyDrive, mediaChanged, 0)); |
|
525 test(CMassStorageDrive::EConnected==drive1->MountState()); |
|
526 |
|
527 /////////////////////////////////////////////////////////////////////////// |
|
528 test.Next(_L("Test SetCritical")); |
|
529 test(CMassStorageDrive::EIdle==drive1->DriveState()); |
|
530 test(KErrNone==drive1->SetCritical(ETrue)); |
|
531 test(CMassStorageDrive::EActive==drive1->DriveState()); |
|
532 test(KErrNone==drive1->SetCritical(EFalse)); |
|
533 test(CMassStorageDrive::EIdle==drive1->DriveState()); |
|
534 |
|
535 /////////////////////////////////////////////////////////////////////////// |
|
536 test.Next(_L("Test that ProxyDrive is called")); |
|
537 |
|
538 CTestProxyDrive::iRetval = KErrNone; |
|
539 |
|
540 // Test that bytesRead is incremented correctly |
|
541 // when the count increments from 999 to 1000: |
|
542 test(KErrNone==drive1->Read(0,999,buf)); |
|
543 test(0==drive1->KBytesRead()); |
|
544 test(KErrNone==drive1->Read(0,1,buf)); |
|
545 test(1==drive1->KBytesRead()); |
|
546 |
|
547 buf.SetLength(KNoBytes); |
|
548 test(KErrNone==drive1->Write(0,buf)); |
|
549 test(KErrNone==drive1->Caps(caps)); |
|
550 // Write was called when EIdle, should restore state to EIdle |
|
551 // after transient EActive state. |
|
552 test(CMassStorageDrive::EIdle==drive1->DriveState()); |
|
553 |
|
554 CTestProxyDrive::iRetval = KErrDied; // arbitrary test value |
|
555 CTestProxyDrive::iRetval_caps = KErrDied; |
|
556 test(KErrDied==drive1->Read(0,0,buf)); |
|
557 test(KErrDied==drive1->Write(0,buf)); |
|
558 test(KErrDied==drive1->Caps(caps)); |
|
559 CTestProxyDrive::iRetval = KErrNone; |
|
560 CTestProxyDrive::iRetval_caps = KErrNone; |
|
561 |
|
562 test.Next(_L("Test IsMediaChanged")); |
|
563 test(EFalse==drive1->IsMediaChanged(ETrue)); |
|
564 test(EFalse==drive1->IsMediaChanged(EFalse)); |
|
565 |
|
566 /////////////////////////////////////////////////////////////////////////// |
|
567 |
|
568 CPropertyWatch::NewLC(EUsbMsDriveState_KBytesRead, PropertyHandlers::Read); |
|
569 CPropertyWatch::NewLC(EUsbMsDriveState_KBytesWritten, PropertyHandlers::Written); |
|
570 CPropertyWatch::NewLC(EUsbMsDriveState_DriveStatus, PropertyHandlers::DriveStatus); |
|
571 |
|
572 /////////////////////////////////////////////////////////////////////////// |
|
573 |
|
574 NEXT(EStepRead0); |
|
575 CActiveScheduler::Start(); |
|
576 |
|
577 /////////////////////////////////////////////////////////////////////////// |
|
578 |
|
579 test.Printf(_L("\nCLEANING UP\n")); |
|
580 |
|
581 CleanupStack::PopAndDestroy(3); //CPropertyWatch x 3 |
|
582 CleanupStack::PopAndDestroy(proxyDrive); |
|
583 CleanupStack::PopAndDestroy(gMgr); |
|
584 CleanupStack::PopAndDestroy(&driveMap); |
|
585 CleanupStack::PopAndDestroy(sched); |
|
586 |
|
587 return; |
|
588 } |
|
589 |
|
590 GLDEF_C TInt E32Main() |
|
591 { |
|
592 __UHEAP_MARK; |
|
593 CTrapCleanup* cleanup=CTrapCleanup::New(); |
|
594 |
|
595 TRAPD(error,doTestL()); |
|
596 if (error) |
|
597 test.Printf(_L("Leave occurred; code=%d\n"), error); |
|
598 |
|
599 test.End(); // output success/fail |
|
600 test.Close(); |
|
601 |
|
602 delete cleanup; |
|
603 __UHEAP_MARKEND; |
|
604 return 0; |
|
605 } |