/* Ċ Ġ* ĠCopyright Ġ( C ) Ġ 2 0 2 2 ĠBlock , ĠInc . Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ package Ġapp . cash . zi pline . loader Ċ Ċ import Ġcom . squareup . sql de light . sqlite . driver . Jdbc Sqlite Driver Ċ import Ġcom . squareup . sql de light . sqlite . driver . Jdbc Sqlite Driver . Companion . IN _ MEMORY Ċ import Ġjava . time . Clock Ċ import Ġkotlin . test . assertEquals Ċ import Ġkotlin . test . assertFalse Ċ import Ġkotlin . test . assertNotNull Ċ import Ġkotlin . test . assertNull Ċ import Ġkotlin . test . assertTrue Ċ import Ġkotlinx . coroutines . Experimental Cor outines Api Ċ import Ġkotlinx . coroutines . run Blocking Ċ import Ġkotlinx . coroutines . test . Test Coroutine Dispatcher Ċ import Ġok io . ByteString . Companion . encode Utf 8 Ċ import Ġok io . FileSystem Ċ import Ġok io . Path . Companion . to Path Ċ import Ġok io . fake filesystem . Fake FileSystem Ċ import Ġorg . junit . After Ċ import Ġorg . junit . Before Ċ import Ġorg . junit . Test Ċ Ċ @ Opt In ( Experimental Cor outines Api :: class ) Ċ class ĠZ i pline Cache Test Ġ{ ĊĠ Ġprivate Ġval Ġdispatcher Ġ= ĠTest Coroutine Dispatcher () ĊĠ Ġprivate Ġval Ġdriver Ġ= ĠJdbc Sqlite Driver ( IN _ MEMORY ) ĊĠ Ġprivate Ġlateinit Ġvar Ġdatabase : ĠDatabase ĊĠ Ġprivate Ġlateinit Ġvar Ġfile System : ĠFileSystem ĊĠ Ġprivate Ġval Ġdirectory Ġ= Ġ"/ zi pline / cache ". to Path () ĊĠ Ġprivate Ġval Ġcache Size Ġ= Ġ 6 4 ĊĠ Ġprivate Ġvar Ġnow Millis Ġ= Ġ 1 _ 0 0 0 L ĊĊĠ Ġ@ Before ĊĠ Ġfun ĠsetUp () Ġ{ ĊĠĠĠ Ġfile System Ġ= ĠFake FileSystem () ĊĠĠĠ Ġdatabase Ġ= Ġcreate Database ( driver ) ĊĠ Ġ} ĊĊĠ Ġ@ After ĊĠ Ġfun ĠtearDown () Ġ{ ĊĠĠĠ Ġdriver . close () ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` read Ġopens Ġfile Ġthat Ġhas Ġbeen Ġdownloaded Ġor Ġnull Ġif Ġnot Ġready ` (): ĠUnit Ġ= Ġrun Blocking ( dispatcher ) Ġ{ ĊĠĠĠ Ġwith Cache Ġ{ Ġz i pline Cache Ġ-> ĊĠĠĠĠĠ Ġval Ġfile Sha Ġ= Ġ" abc 1 2 3 ". encode Utf 8 (). sha 2 5 6 () ĊĠĠĠĠĠ Ġval Ġfile Sha Contents Ġ= Ġ" abc 1 2 3 ". encode Utf 8 (). sha 2 5 6 () ĊĊĠĠĠĠĠ Ġ// ĠFile Ġnot ĠREAD Y ĊĠĠĠĠĠ ĠassertNull ( zi pline Cache . read ( file Sha )) ĊĠĠĠĠĠ ĠassertFalse ( file System . exists ( directory Ġ/ Ġfile Sha . hex ())) ĊĊĠĠĠĠĠ Ġ// ĠFile Ġdownloaded ĊĠĠĠĠĠ Ġz i pline Cache . write ( file Sha , Ġfile Sha Contents ) ĊĠĠĠĠĠ ĠassertTrue ( file System . exists ( directory Ġ/ Ġ" entry - 1 . bin ")) ĊĊĠĠĠĠĠ Ġ// ĠFile Ġcan Ġbe Ġread ĊĠĠĠĠĠ ĠassertEquals ( file Sha Contents , Ġz i pline Cache . read ( file Sha )) ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` read Ġtriggers Ġdownload Ġfor Ġfile Ġthat Ġis Ġnot Ġon Ġfilesystem Ġyet ` (): ĠUnit Ġ= Ġrun Blocking ( dispatcher ) Ġ{ ĊĠĠĠ Ġwith Cache Ġ{ Ġz i pline Cache Ġ-> ĊĠĠĠĠĠ Ġval Ġfile Sha Ġ= Ġ" abc 1 2 3 ". encode Utf 8 (). sha 2 5 6 () ĊĠĠĠĠĠ Ġval Ġfile Sha Contents Ġ= Ġ" abc 1 2 3 ". encode Utf 8 (). sha 2 5 6 () ĊĊĠĠĠĠĠ Ġ// ĠFile Ġnot ĠREAD Y ĊĠĠĠĠĠ ĠassertNull ( zi pline Cache . read ( file Sha )) ĊĠĠĠĠĠ ĠassertFalse ( file System . exists ( directory Ġ/ Ġfile Sha . hex ())) ĊĊĠĠĠĠĠ Ġval Ġresult Ġ= Ġz i pline Cache . get Or Put ( file Sha ) Ġ{ ĊĠĠĠĠĠĠĠ Ġfile Sha Contents ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ ĠassertEquals ( file Sha Contents , Ġresult ) ĊĠĠĠĠĠ ĠassertEquals ( file Sha Contents , Ġz i pline Cache . read ( file Sha )) ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` cache Ġpr unes Ġwhen Ġcapacity Ġexceeded ` (): ĠUnit Ġ= Ġrun Blocking ( dispatcher ) Ġ{ ĊĠĠĠ Ġwith Cache Ġ{ Ġz i pline Cache Ġ-> ĊĠĠĠĠĠ Ġval Ġa 3 2 Ġ= Ġ" a ". repeat ( cache Size Ġ/ Ġ 2 ). encode Utf 8 () ĊĠĠĠĠĠ Ġval Ġb 3 2 Ġ= Ġ" b ". repeat ( cache Size Ġ/ Ġ 2 ). encode Utf 8 () ĊĠĠĠĠĠ Ġval Ġc 3 2 Ġ= Ġ" c ". repeat ( cache Size Ġ/ Ġ 2 ). encode Utf 8 () ĊĠĠĠĠĠ Ġval Ġa 3 2 Hash Ġ= Ġa 3 2 . sha 2 5 6 () ĊĠĠĠĠĠ Ġval Ġb 3 2 Hash Ġ= Ġb 3 2 . sha 2 5 6 () ĊĠĠĠĠĠ Ġval Ġc 3 2 Hash Ġ= Ġc 3 2 . sha 2 5 6 () ĊĊĠĠĠĠĠ ĠassertEquals ( a 3 2 , Ġz i pline Cache . get Or Put ( a 3 2 Hash ) Ġ{ Ġa 3 2 Ġ}) ĊĠĠĠĠĠ ĠassertNotNull ( zi pline Cache . read ( a 3 2 Hash )) ĊĠĠĠĠĠ ĠassertNull ( zi pline Cache . read ( b 3 2 Hash )) ĊĠĠĠĠĠ ĠassertNull ( zi pline Cache . read ( c 3 2 Hash )) ĊĊĠĠĠĠĠ ĠassertEquals ( b 3 2 , Ġz i pline Cache . get Or Put ( b 3 2 Hash ) Ġ{ Ġb 3 2 Ġ}) ĊĠĠĠĠĠ ĠassertNotNull ( zi pline Cache . read ( a 3 2 Hash )) ĊĠĠĠĠĠ ĠassertNotNull ( zi pline Cache . read ( b 3 2 Hash )) ĊĠĠĠĠĠ ĠassertNull ( zi pline Cache . read ( c 3 2 Hash )) ĊĊĠĠĠĠĠ ĠassertEquals ( c 3 2 , Ġz i pline Cache . get Or Put ( c 3 2 Hash ) Ġ{ Ġc 3 2 Ġ}) ĊĠĠĠĠĠ ĠassertNull ( zi pline Cache . read ( a 3 2 Hash )) ĊĠĠĠĠĠ ĠassertNotNull ( zi pline Cache . read ( b 3 2 Hash )) ĊĠĠĠĠĠ ĠassertNotNull ( zi pline Cache . read ( c 3 2 Hash )) ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` cache Ġpr unes Ġby Ġleast Ġrecently Ġaccessed ` (): ĠUnit Ġ= Ġrun Blocking ( dispatcher ) Ġ{ ĊĠĠĠ Ġwith Cache Ġ{ Ġz i pline Cache Ġ-> ĊĠĠĠĠĠ Ġval Ġa 3 2 Ġ= Ġ" a ". repeat ( cache Size Ġ/ Ġ 2 ). encode Utf 8 () ĊĠĠĠĠĠ Ġval Ġb 3 2 Ġ= Ġ" b ". repeat ( cache Size Ġ/ Ġ 2 ). encode Utf 8 () ĊĠĠĠĠĠ Ġval Ġc 3 2 Ġ= Ġ" c ". repeat ( cache Size Ġ/ Ġ 2 ). encode Utf 8 () ĊĠĠĠĠĠ Ġval Ġa 3 2 Hash Ġ= Ġa 3 2 . sha 2 5 6 () ĊĠĠĠĠĠ Ġval Ġb 3 2 Hash Ġ= Ġb 3 2 . sha 2 5 6 () ĊĠĠĠĠĠ Ġval Ġc 3 2 Hash Ġ= Ġc 3 2 . sha 2 5 6 () ĊĊĠĠĠĠĠ ĠassertEquals ( a 3 2 , Ġz i pline Cache . get Or Put ( a 3 2 Hash ) Ġ{ Ġa 3 2 Ġ}) ĊĠĠĠĠĠ Ġtick () ĊĠĠĠĠĠ ĠassertEquals ( b 3 2 , Ġz i pline Cache . get Or Put ( b 3 2 Hash ) Ġ{ Ġb 3 2 Ġ}) ĊĠĠĠĠĠ Ġtick () ĊĠĠĠĠĠ ĠassertEquals ( a 3 2 , Ġz i pline Cache . get Or Put ( a 3 2 Hash ) Ġ{ Ġerror (" expected Ġto Ġbe Ġcached ") Ġ}) ĊĠĠĠĠĠ Ġtick () ĊĠĠĠĠĠ ĠassertEquals ( c 3 2 , Ġz i pline Cache . get Or Put ( c 3 2 Hash ) Ġ{ Ġc 3 2 Ġ}) ĊĠĠĠĠĠ Ġtick () ĊĠĠĠĠĠ ĠassertNotNull ( zi pline Cache . read ( a 3 2 Hash )) ĊĠĠĠĠĠ ĠassertNull ( zi pline Cache . read ( b 3 2 Hash )) Ġ// ĠLe ast Ġrecently Ġaccessed . ĊĠĠĠĠĠ ĠassertNotNull ( zi pline Cache . read ( c 3 2 Hash )) ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` cache Ġelement Ġexceeds Ġcache Ġmax Ġsize ` (): ĠUnit Ġ= Ġrun Blocking ( dispatcher ) Ġ{ ĊĠĠĠ Ġwith Cache Ġ{ Ġz i pline Cache Ġ-> ĊĠĠĠĠĠ Ġval Ġa 6 5 Ġ= Ġ" a ". repeat ( cache Size Ġ+ Ġ 1 ). encode Utf 8 () ĊĠĠĠĠĠ Ġval Ġa 6 5 Hash Ġ= Ġa 6 5 . sha 2 5 6 () ĊĊĠĠĠĠĠ ĠassertEquals ( a 6 5 , Ġz i pline Cache . get Or Put ( a 6 5 Hash ) Ġ{ Ġa 6 5 Ġ}) ĊĠĠĠĠĠ ĠassertNull ( zi pline Cache . read ( a 6 5 Hash )) Ġ// ĠIm mediate ly Ġev ict ed ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġ@ Test ĊĠ Ġfun Ġ` cache Ġon Ġopen Ġpr unes Ġany Ġfiles Ġin Ġexcess Ġof Ġlimit ` (): ĠUnit Ġ= Ġrun Blocking ( dispatcher ) Ġ{ ĊĠĠĠ Ġval Ġa 3 2 Ġ= Ġ" a ". repeat ( cache Size Ġ/ Ġ 2 ). encode Utf 8 () ĊĠĠĠ Ġval Ġa 3 2 Hash Ġ= Ġa 3 2 . sha 2 5 6 () ĊĊĠĠĠ Ġwith Cache Ġ{ ĊĠĠĠĠĠ Ġit . write ( a 3 2 Hash , Ġa 3 2 ) ĊĠĠĠĠĠ ĠassertNotNull ( it . read ( a 3 2 Hash )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġwith Cache Ġ{ ĊĠĠĠĠĠ ĠassertNotNull ( it . read ( a 3 2 Hash )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġwith Cache ( cache Size Ġ/ Ġ 3 ) Ġ{ ĊĠĠĠĠĠ ĠassertNull ( it . read ( a 3 2 Hash )) ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġprivate Ġfun Ġtick () Ġ{ ĊĠĠĠ Ġnow Millis Ġ+= Ġ 1 _ 0 0 0 L ĊĠ Ġ} ĊĊĠ Ġprivate Ġsuspend Ġfun Ġ< T > Ġwith Cache ( ĊĠĠĠ Ġcache Size : ĠInt Ġ= Ġthis . cache Size , ĊĠĠĠ Ġblock : Ġsuspend Ġ( Zi pline Cache ) Ġ-> ĠT , ĊĠ Ġ): ĠT Ġ{ ĊĠĠĠ Ġval Ġcache Ġ= Ġopen Zi pline Cache ForTesting ( database , Ġfile System , Ġdirectory , Ġcache Size . to Long (), Ġ{ Ġnow Millis Ġ}) ĊĠĠĠ Ġreturn Ġblock ( cache ) ĊĠ Ġ} Ċ } Ċ