/* Ċ Ġ* ĠCopyright Ġ 2 0 2 0 ĠIN O VA ĠIT Ġd . o . o . Ċ Ġ* Ċ Ġ* ĠPermission Ġis Ġhereby Ġgranted , Ġfree Ġof Ġcharge , Ġto Ġany Ġperson Ġobtaining Ġa Ġcopy Ġof Ġthis Ġsoftware Ġand Ġassociated Ġdocumentation Ġfiles Ġ( the Ġ" Software "), Ġto Ġdeal Ġin Ġthe ĠSoftware Ġwithout Ġrestriction , Ġincluding Ġwithout Ġlimitation Ġthe Ġrights Ġto Ġuse , Ġcopy , Ġmodify , Ġmerge , Ġpublish , Ġdistribute , Ġsublicense , Ġand / or Ġsell Ġcopies Ġof Ġthe ĠSoftware , Ġand Ġto Ġpermit Ġpersons Ġto Ġwhom Ġthe ĠSoftware Ġis Ġfurnished Ġto Ġdo Ġso , Ġsubject Ġto Ġthe Ġfollowing Ġconditions : Ċ Ġ* Ċ Ġ* ĠThe Ġabove Ġcopyright Ġnotice Ġand Ġthis Ġpermission Ġnotice Ġshall Ġbe Ġincluded Ġin Ġall Ġcopies Ġor Ġsubstantial Ġportions Ġof Ġthe ĠSoftware . Ċ Ġ* Ċ Ġ* ĠTHE ĠSOFTWARE ĠIS ĠPROVIDED Ġ" AS ĠIS ", ĠWITHOUT ĠWARRANTY ĠOF ĠANY ĠKIND , ĠEXPRESS ĠOR ĠIMPLIED , ĠINCLUDING ĠBUT ĠNOT ĠLIMITED ĠTO ĠTHE ĠWARRANTIES ĠOF ĠMERCHANTABILITY , ĠFITNESS ĠFOR ĠA ĠPARTICULAR ĠPURPOSE ĠAND ĠNONINFRINGEMENT . ĠIN ĠNO ĠEVENT ĠSHALL ĠTHE ĠAUTHORS ĠOR ĠCOPYRIGHT ĠHOLDERS ĠBE ĠLIABLE ĠFOR ĠANY ĠCLAIM , ĠDAMAGES ĠOR ĠOTHER ĠLIABILITY , ĠWHETHER ĠIN ĠAN ĠACTION ĠOF ĠCONTRACT , ĠTORT ĠOR ĠOTHERWISE , ĠARISING ĠFROM , ĠOUT ĠOF ĠOR ĠIN ĠCONNECTION ĠWITH ĠTHE ĠSOFTWARE ĠOR ĠTHE ĠUSE ĠOR ĠOTHER ĠDEALINGS ĠIN ĠTHE ĠSOFTWARE . Ċ Ġ* Ċ Ġ*/ Ċ Ċ package Ġsi . in ova . kotlin ova . coroutines Ċ Ċ import Ġandroidx . arch . core . executor . testing . Instant Task Executor Rule Ċ import Ġandroidx . lifecycle . Mutable LiveData Ċ import Ġandroidx . lifecycle . Observer Ċ import Ġcom . n ha ar man . mock it ok otlin 2 . arg That Ċ import Ġcom . n ha ar man . mock it ok otlin 2 . mock Ċ import Ġcom . n ha ar man . mock it ok otlin 2 . verify Ċ import Ġio . reactivex . Flow able Ċ import Ġkotlinx . coroutines . Job Ċ import Ġkotlinx . coroutines . delay Ċ import Ġkotlinx . coroutines . launch Ċ import Ġorg . junit . Assert . assertEquals Ċ import Ġorg . junit . Assert . assertFalse Ċ import Ġorg . junit . Assert . assertNotNull Ċ import Ġorg . junit . Assert . assertNot Same Ċ import Ġorg . junit . Assert . assertTrue Ċ import Ġorg . junit . Before Ċ import Ġorg . junit . Rule Ċ import Ġorg . junit . Test Ċ import Ġorg . junit . rules . Expected Exception Ċ import Ġorg . junit . rules . Rule Chain Ċ import Ġsi . in ova . kotlin ova . data . resources . Resource Ċ import Ġsi . in ova . kotlin ova . data . resources . Resource LiveData Ċ import Ġsi . in ova . kotlin ova . testing . Cor outines Time Machine Ċ import Ġsi . in ova . kotlin ova . testing . Un caught Exception Throw Rule Ċ import Ġsi . in ova . kotlin ova . testing . assertIs Ċ import Ġsi . in ova . kotlin ova . utils . add Resource Source Ċ import Ġsi . in ova . kotlin ova . utils . add Source Ċ Ċ /** Ċ Ġ* Ġ@ author ĠM ate j ĠD ro bn ic Ċ Ġ*/ Ċ class ĠCor outine ViewModel Test Ġ{ ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġtest ViewModel : ĠTest ViewModel ĊĊĠĠĠ Ġ@ get : Rule ĊĠĠĠ Ġval Ġdispatcher Ġ= ĠCor outines Time Machine () ĊĊĠĠĠ Ġval Ġexpect Exception Ġ= ĠExpected Exception . none () ĊĊĠĠĠ Ġ@ get : Rule ĊĠĠĠ Ġval Ġexceptions And Un caught Rule Ġ= ĊĠĠĠĠĠĠĠ ĠRule Chain . outer Rule ( expect Exception ). around ( Un caught Exception Throw Rule ()) ĊĊĠĠĠ Ġ@ get : Rule ĊĠĠĠ Ġval Ġarch Rule Ġ= ĠInstant Task Executor Rule () ĊĊĠĠĠ Ġ@ Before ĊĠĠĠ Ġfun ĠsetUp () Ġ{ ĊĠĠĠĠĠĠĠ Ġtest ViewModel Ġ= ĠTest ViewModel () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġacquire Resource Success () Ġ{ ĊĠĠĠĠĠĠĠ Ġtest ViewModel . first Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ Ġassert Is ( test ViewModel . resource A . value , ĠResource . Loading :: class . java ) ĊĠĠĠĠĠĠĠ Ġdispatcher . advance Time ( 6 0 0 ) ĊĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Success ( 1 0 ), Ġtest ViewModel . resource A . value ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġacquire Resource Error () Ġ{ ĊĠĠĠĠĠĠĠ Ġtest ViewModel . exception Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ Ġassert Is ( test ViewModel . resource A . value , ĠResource . Loading :: class . java ) ĊĠĠĠĠĠĠĠ Ġdispatcher . advance Time ( 6 0 0 ) ĊĠĠĠĠĠĠĠ Ġassert Is ( test ViewModel . resource A . value , ĠResource . Error :: class . java ) ĊĊĠĠĠĠĠĠĠ Ġval Ġexception Ġ= Ġ( test ViewModel . resource A . value Ġas ĠResource . Error < Int >). exception ĊĠĠĠĠĠĠĠ Ġassert Is ( exception , ĠIllegalStateException :: class . java ) ĊĠĠĠĠĠĠĠ ĠassertEquals (" Test Ġexception ", Ġexception . message ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġcancel Concurrent Jobs () Ġ{ ĊĠĠĠĠĠĠĠ Ġtest ViewModel . first Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĠĠĠĠĠĠĠ Ġval Ġfirst Task Job Ġ= Ġtest ViewModel . get Job ( test ViewModel . resource A ) ĊĊĠĠĠĠĠĠĠ Ġtest ViewModel . second Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĠĠĠĠĠĠĠ Ġval Ġsecond Task Job Ġ= Ġtest ViewModel . get Job ( test ViewModel . resource A ) ĊĊĠĠĠĠĠĠĠ Ġassert Not Same ( first Task Job , Ġsecond Task Job ) ĊĠĠĠĠĠĠĠ ĠassertNotNull ( first Task Job ) ĊĠĠĠĠĠĠĠ ĠassertNotNull ( second Task Job ) ĊĊĠĠĠĠĠĠĠ ĠassertTrue ( first Task Job !!. is Cancelled ) ĊĠĠĠĠĠĠĠ ĠassertFalse ( second Task Job !!. is Cancelled ) ĊĊĠĠĠĠĠĠĠ Ġdispatcher . advance Time ( 6 0 0 ) ĊĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Success ( 2 0 ), Ġtest ViewModel . resource A . value ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġcancel Mediator LiveData Subscriptions When C ancell ing Job () Ġ{ ĊĠĠĠĠĠĠĠ Ġtest ViewModel . resource A . observe Fore ver Ġ{} ĊĊĠĠĠĠĠĠĠ Ġval Ġadditional Resource Ġ= ĠMutable LiveData < Resource < Int >>() ĊĠĠĠĠĠĠĠ Ġtest ViewModel . resource A . add Source ( additional Resource ) ĊĠĠĠĠĠĠĠ ĠassertTrue ( additional Resource . has Active Observer s ()) ĊĊĠĠĠĠĠĠĠ Ġtest ViewModel . first Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ ĠassertFalse ( additional Resource . has Active Observer s ()) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġis Resource Taken () Ġ{ ĊĠĠĠĠĠĠĠ ĠassertFalse ( test ViewModel . is Resource Taken Public ( test ViewModel . resource A )) ĊĊĠĠĠĠĠĠĠ Ġtest ViewModel . first Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ ĠassertTrue ( test ViewModel . is Resource Taken Public ( test ViewModel . resource A )) ĊĠĠĠĠĠĠĠ Ġdispatcher . advance Time ( 6 0 0 ) ĊĠĠĠĠĠĠĠ ĠassertFalse ( test ViewModel . is Resource Taken Public ( test ViewModel . resource A )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġcancel Resource () Ġ{ ĊĠĠĠĠĠĠĠ Ġtest ViewModel . first Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ Ġtest ViewModel . cancel Resource Public ( test ViewModel . resource A ) ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ Ġassert Is ( test ViewModel . resource A . value , ĠResource . Cancelled :: class . java ) ĊĠĠĠĠĠĠĠ Ġdispatcher . advance Time ( 6 0 0 ) ĊĠĠĠĠĠĠĠ Ġassert Is ( test ViewModel . resource A . value , ĠResource . Cancelled :: class . java ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġconcurrent La unches () Ġ{ ĊĠĠĠĠĠĠĠ Ġrepeat ( 1 0 0 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtest ViewModel . first Task () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġ` Do Ġnot Ġcancel Ġall Ġjobs Ġon Ġsingle Ġjob Ġfailure `() Ġ{ ĊĠĠĠĠĠĠĠ Ġexpect Exception . expect Message (" Test Ġexception ") ĊĊĠĠĠĠĠĠĠ Ġtest ViewModel . first Task () ĊĠĠĠĠĠĠĠ Ġtest ViewModel . fail Job () ĊĊĠĠĠĠĠĠĠ Ġdispatcher . advance Time ( 1 0 0 ) ĊĊĠĠĠĠĠĠĠ ĠassertTrue ( test ViewModel . is Resource Taken Public ( test ViewModel . resource A )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġ` Receive Ġerrors Ġfrom Ġcommon Ġerror Ġobserver Ġwhen Ġred irection Ġis Ġenabled Ġby Ġdefault `() Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcommon Error ViewModel Ġ= ĠTest Common Error ViewModel () ĊĊĠĠĠĠĠĠĠ Ġval Ġerror Observer : ĠObserver < Throwable > Ġ= Ġmock () ĊĠĠĠĠĠĠĠ Ġcommon Error ViewModel . errors . observe Fore ver ( error Observer ) ĊĊĠĠĠĠĠĠĠ Ġcommon Error ViewModel . exception Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ Ġassert Is ( common Error ViewModel . resource A . value , ĠResource . Cancelled :: class . java ) ĊĠĠĠĠĠĠĠ Ġverify ( error Observer ). on Changed ( arg That Ġ{ Ġthis Ġis ĠIllegalStateException Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġ` Also Ġredirect Ġreceived Ġerrors Ġto Ġcommon Ġerror Ġobserver `() Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcommon Error ViewModel Ġ= ĠTest Common Error ViewModel () ĊĠĠĠĠĠĠĠ Ġcommon Error ViewModel . resource A . observe Fore ver Ġ{} ĊĊĠĠĠĠĠĠĠ Ġval Ġerror Observer : ĠObserver < Throwable > Ġ= Ġmock () ĊĠĠĠĠĠĠĠ Ġcommon Error ViewModel . errors . observe Fore ver ( error Observer ) ĊĊĠĠĠĠĠĠĠ Ġcommon Error ViewModel . exception Pass ing Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ Ġassert Is ( common Error ViewModel . resource A . value , ĠResource . Cancelled :: class . java ) ĊĠĠĠĠĠĠĠ Ġverify ( error Observer ). on Changed ( arg That Ġ{ Ġthis Ġis ĠIllegalStateException Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġ` Receive Ġerrors Ġfrom Ġcommon Ġerror Ġobserver Ġwhen Ġred irection Ġis Ġenabled Ġby Ġspecific Ġjob `() Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġerror Observer : ĠObserver < Throwable > Ġ= Ġmock () ĊĠĠĠĠĠĠĠ Ġtest ViewModel . errors . observe Fore ver ( error Observer ) ĊĊĠĠĠĠĠĠĠ Ġtest ViewModel . exception Task With Common Error () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ Ġassert Is ( test ViewModel . resource A . value , ĠResource . Cancelled :: class . java ) ĊĠĠĠĠĠĠĠ Ġverify ( error Observer ). on Changed ( arg That Ġ{ Ġthis Ġis ĠIllegalStateException Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġ` Crash Ġwhen Ġcommon Ġerror Ġobserver Ġis Ġnot Ġbeing Ġobserved Ġby Ġanyone `() Ġ{ ĊĠĠĠĠĠĠĠ Ġexpect Exception . expect ( LiveData Coroutine ResourceManager . Un deliver able Exception :: class . java ) ĊĊĠĠĠĠĠĠĠ Ġval Ġcommon Error ViewModel Ġ= ĠTest Common Error ViewModel () ĊĊĠĠĠĠĠĠĠ Ġcommon Error ViewModel . exception Task () ĊĠĠĠĠĠĠĠ Ġdispatcher . trigger Actions () ĊĊĠĠĠĠĠĠĠ Ġassert Is ( common Error ViewModel . resource A . value , ĠResource . Cancelled :: class . java ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġclass ĠTest ViewModel Ġ: ĠCor outine ViewModel () Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġresource A Ġ= ĠResource LiveData < Int >() ĊĊĠĠĠĠĠĠĠ Ġfun Ġfirst Task () Ġ= Ġresources . launch Resource Control Task ( resource A ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( 5 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsend Value ( Resource . Success ( 1 0 )) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġsecond Task () Ġ= Ġresources . launch Resource Control Task ( resource A ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( 5 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsend Value ( Resource . Success ( 2 0 )) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġexception Task () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġresources . launch Resource Control Task ( resource A ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( 5 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException (" Test Ġexception ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġexception Task With Common Error () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġresources . launch Resource Control Task ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresource A , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġroute Errors To Common Observable Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException (" Test Ġexception ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġfail Job () Ġ= Ġlaunch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException (" Test Ġexception ") ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġ< T > Ġis Resource Taken Public ( resource : ĠMutable LiveData < Resource < T >> ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġresources . is Resource Taken ( resource ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġ< T > Ġcancel Resource Public ( resource : ĠMutable LiveData < Resource < T >>) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġresources . cancel Resource ( resource ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġ< T > Ġget Job ( resource : ĠMutable LiveData < Resource < T >> ): ĠJob ? Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġresources . getCurrent Job ( resource Ġas ĠMutable LiveData <* >) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġclass ĠTest Common Error ViewModel Ġ: ĠCommon Error Coroutine ViewModel () Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġresource A Ġ= ĠResource LiveData < Int >() ĊĊĠĠĠĠĠĠĠ Ġfun Ġexception Task () Ġ= Ġresources . launch Resource Control Task ( resource A ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException (" Test Ġexception ") ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġexception Pass ing Task () Ġ= Ġresources . launch Resource Control Task ( resource A ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd Resource Source ( Flow able . error ( IllegalStateException (" Test Ġexception "))) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ }