From cfc182f2e5639e706e0bc465af5da25fbd62a602 Mon Sep 17 00:00:00 2001 From: Bogdan Poplauschi Date: Sat, 24 Sep 2016 00:14:13 +0300 Subject: [PATCH] Added SDImageCacheConfig to all targets, test images, code coverage setting, tests for SDImageCache, SDWebImageDownloader, SDWebImageDownloaderOperation, SDWebImageDecoder --- SDWebImage.xcodeproj/project.pbxproj | 34 +- .../project.pbxproj | 16 + .../xcshareddata/xcschemes/Tests.xcscheme | 3 +- Tests/Tests/MonochromeTestImage.jpg | Bin 0 -> 7096 bytes Tests/Tests/SDImageCacheTests.m | 185 ++++----- Tests/Tests/SDWebImageDecoderTests.m | 61 +++ Tests/Tests/SDWebImageDownloaderTests.m | 356 +++++++++++++++--- Tests/Tests/SDWebImageManagerTests.m | 2 - Tests/Tests/TestImage.gif | Bin 0 -> 3109 bytes Tests/Tests/TestImage.png | Bin 0 -> 6822 bytes 10 files changed, 517 insertions(+), 140 deletions(-) create mode 100644 Tests/Tests/MonochromeTestImage.jpg create mode 100644 Tests/Tests/SDWebImageDecoderTests.m create mode 100644 Tests/Tests/TestImage.gif create mode 100644 Tests/Tests/TestImage.png diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index 8711534d..cccebbdb 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -435,6 +435,18 @@ 43A62A641D0E0A8F0089D7DD /* vp8li.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577D681998E6B2007367ED /* vp8li.h */; }; 43A62A651D0E0A8F0089D7DD /* webp.c in Sources */ = {isa = PBXBuildFile; fileRef = DA577D691998E6B2007367ED /* webp.c */; }; 43A62A661D0E0A8F0089D7DD /* webpi.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577D6A1998E6B2007367ED /* webpi.h */; }; + 43A918641D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; }; + 43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; }; + 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; }; + 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; }; + 43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; }; + 43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; }; + 43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; + 43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; + 43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; + 43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; + 43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; + 43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; }; 43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43CE75771CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43CE75781CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -882,6 +894,8 @@ 4397D2F21D0DDD8C00BB2784 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4397D2F41D0DE2DF00BB2784 /* NSImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+WebCache.h"; sourceTree = ""; }; 4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+WebCache.m"; sourceTree = ""; }; + 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCacheConfig.h; sourceTree = ""; }; + 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCacheConfig.m; sourceTree = ""; }; 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLAnimatedImage.h; sourceTree = ""; }; 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLAnimatedImage.m; sourceTree = ""; }; 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLAnimatedImageView.h; sourceTree = ""; }; @@ -1218,6 +1232,8 @@ children = ( 53922D85148C56230056699D /* SDImageCache.h */, 53922D86148C56230056699D /* SDImageCache.m */, + 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */, + 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */, ); name = Cache; sourceTree = ""; @@ -1417,6 +1433,7 @@ 431739361CDFC8B20008FEB9 /* bit_reader_inl.h in Headers */, 4317393A1CDFC8B20008FEB9 /* color_cache.h in Headers */, 431738E11CDFC8A40008FEB9 /* webpi.h in Headers */, + 43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 431739571CDFC8B70008FEB9 /* encode.h in Headers */, 431739351CDFC8B20008FEB9 /* bit_reader.h in Headers */, 43DA7D5D1D1086600028BE58 /* mips_macro.h in Headers */, @@ -1488,6 +1505,7 @@ 43DA7CFE1D10865E0028BE58 /* yuv.h in Headers */, 4314D1711D0E0E3B004B36C9 /* huffman.h in Headers */, 4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */, + 43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4314D1731D0E0E3B004B36C9 /* vp8li.h in Headers */, 4314D1741D0E0E3B004B36C9 /* types.h in Headers */, 4314D1761D0E0E3B004B36C9 /* decode.h in Headers */, @@ -1575,6 +1593,7 @@ 431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */, 431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */, 431BB6FC1D06D2C1006A3455 /* SDWebImageDecoder.h in Headers */, + 43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1606,6 +1625,7 @@ 4397D2D11D0DDD8C00BB2784 /* decode.h in Headers */, 4397D2D21D0DDD8C00BB2784 /* webpi.h in Headers */, 43DA7DCB1D1086610028BE58 /* mips_macro.h in Headers */, + 43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4397D2D31D0DDD8C00BB2784 /* thread.h in Headers */, 4397D2D41D0DDD8C00BB2784 /* quant_levels.h in Headers */, 4397D2D51D0DDD8C00BB2784 /* bit_reader_inl.h in Headers */, @@ -1650,6 +1670,7 @@ 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */, 431739511CDFC8B70008FEB9 /* format_constants.h in Headers */, 431739231CDFC8B20008FEB9 /* filters.h in Headers */, + 43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, 4A2CAE211AB4BB7000B6BC39 /* SDWebImageManager.h in Headers */, 4A2CAE1F1AB4BB6C00B6BC39 /* SDImageCache.h in Headers */, 43DA7D261D10865F0028BE58 /* mips_macro.h in Headers */, @@ -1755,6 +1776,7 @@ 53EDFB8A17623F7C00698166 /* UIImage+MultiFormat.h in Headers */, 4317387B1CDFC2580008FEB9 /* decode_vp8.h in Headers */, 431738B61CDFC2630008FEB9 /* random.h in Headers */, + 43A918641D8308FE00B3925F /* SDImageCacheConfig.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2017,6 +2039,7 @@ 43DA7D361D1086600028BE58 /* alpha_processing_sse41.c in Sources */, 43DA7D641D1086600028BE58 /* upsampling_mips_dsp_r2.c in Sources */, 431739461CDFC8B20008FEB9 /* random.c in Sources */, + 43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 43DA7D3D1D1086600028BE58 /* cost_sse2.c in Sources */, 431738DB1CDFC8A40008FEB9 /* tree.c in Sources */, 00733A581BC4880000A5A117 /* SDWebImageManager.m in Sources */, @@ -2119,6 +2142,7 @@ 43DA7CFD1D10865E0028BE58 /* yuv.c in Sources */, 4314D1401D0E0E3B004B36C9 /* UIImageView+WebCache.m in Sources */, 43DA7CDC1D10865E0028BE58 /* enc_mips32.c in Sources */, + 43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */, 43DA7CCE1D10865E0028BE58 /* cost_mips32.c in Sources */, 4314D1421D0E0E3B004B36C9 /* webp.c in Sources */, @@ -2215,6 +2239,7 @@ 43DA7DA21D1086600028BE58 /* yuv.c in Sources */, 431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */, 43DA7D811D1086600028BE58 /* enc_mips32.c in Sources */, + 43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 43A62A5F1D0E0A8F0089D7DD /* quant.c in Sources */, 43DA7D731D1086600028BE58 /* cost_mips32.c in Sources */, 431BB6BD1D06D2C1006A3455 /* UIImage+GIF.m in Sources */, @@ -2335,6 +2360,7 @@ 4397D2AA1D0DDD8C00BB2784 /* io.c in Sources */, 43DA7DCF1D1086610028BE58 /* rescaler_neon.c in Sources */, 43DA7DC31D1086610028BE58 /* lossless_enc_sse2.c in Sources */, + 43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 4397D2AB1D0DDD8C00BB2784 /* UIView+WebCacheOperation.m in Sources */, 43DA7DA91D1086610028BE58 /* cost_mips_dsp_r2.c in Sources */, 43DA7DB01D1086610028BE58 /* dec_mips32.c in Sources */, @@ -2407,6 +2433,7 @@ 43DA7CFF1D10865F0028BE58 /* alpha_processing_sse41.c in Sources */, 43DA7D2D1D10865F0028BE58 /* upsampling_mips_dsp_r2.c in Sources */, 4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */, + 43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 43DA7D061D10865F0028BE58 /* cost_sse2.c in Sources */, 4317391F1CDFC8B20008FEB9 /* color_cache.c in Sources */, 4A2CAE301AB4BB7500B6BC39 /* UIImage+MultiFormat.m in Sources */, @@ -2507,6 +2534,7 @@ 43DA7C911D1086570028BE58 /* alpha_processing_sse41.c in Sources */, 43DA7CBF1D1086570028BE58 /* upsampling_mips_dsp_r2.c in Sources */, 5376130D155AD0D5005750A4 /* SDWebImagePrefetcher.m in Sources */, + 43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 43DA7C981D1086570028BE58 /* cost_sse2.c in Sources */, 431738A81CDFC2630008FEB9 /* color_cache.c in Sources */, 5376130E155AD0D5005750A4 /* UIButton+WebCache.m in Sources */, @@ -2847,7 +2875,6 @@ GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - "SD_WEBP=1", "DEBUG=1", "$(inherited)", ); @@ -2901,10 +2928,7 @@ ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "SD_WEBP=1", - "$(inherited)", - ); + GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; GCC_TREAT_WARNINGS_AS_ERRORS = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; diff --git a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj index 2f8b8053..953240cd 100644 --- a/Tests/SDWebImage Tests.xcodeproj/project.pbxproj +++ b/Tests/SDWebImage Tests.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ /* Begin PBXBuildFile section */ 0D87E1F83BD319CEC7622E9F /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0462A7F023A057322E59B3C5 /* libPods-Tests.a */; }; 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; }; + 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; }; + 433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB61D7EF8200086B6E9 /* TestImage.gif */; }; + 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; }; + 433BBBBB1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */; }; 5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */; }; DA248D57195472AA00390AB0 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA248D56195472AA00390AB0 /* XCTest.framework */; }; DA248D59195472AA00390AB0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA248D58195472AA00390AB0 /* Foundation.framework */; }; @@ -22,6 +26,10 @@ /* Begin PBXFileReference section */ 0462A7F023A057322E59B3C5 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderTests.m; sourceTree = ""; }; + 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDecoderTests.m; sourceTree = ""; }; + 433BBBB61D7EF8200086B6E9 /* TestImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = TestImage.gif; sourceTree = ""; }; + 433BBBB81D7EF8260086B6E9 /* TestImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestImage.png; sourceTree = ""; }; + 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = MonochromeTestImage.jpg; sourceTree = ""; }; 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = TestImage.jpg; sourceTree = ""; }; 700B00151041D7EE118B1ABD /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = ""; }; A0085854E7D88C98F2F6C9FC /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = ""; }; @@ -93,12 +101,16 @@ DA248D5C195472AA00390AB0 /* Tests */ = { isa = PBXGroup; children = ( + 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */, + 433BBBB61D7EF8200086B6E9 /* TestImage.gif */, 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */, + 433BBBB81D7EF8260086B6E9 /* TestImage.png */, DA248D5D195472AA00390AB0 /* Supporting Files */, DA248D68195475D800390AB0 /* SDImageCacheTests.m */, DA248D6A195476AC00390AB0 /* SDWebImageManagerTests.m */, DA91BEBB19795BC9006F2536 /* UIImageMultiFormatTests.m */, 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */, + 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */, ); path = Tests; sourceTree = ""; @@ -167,7 +179,10 @@ buildActionMask = 2147483647; files = ( 5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */, + 433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */, DA248D61195472AA00390AB0 /* InfoPlist.strings in Resources */, + 433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */, + 433BBBBB1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -229,6 +244,7 @@ 1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */, DA248D69195475D800390AB0 /* SDImageCacheTests.m in Sources */, DA248D6B195476AC00390AB0 /* SDWebImageManagerTests.m in Sources */, + 433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */, DA91BEBC19795BC9006F2536 /* UIImageMultiFormatTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 822b3fb4..29613b7e 100644 --- a/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Tests/SDWebImage Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -10,7 +10,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> diff --git a/Tests/Tests/MonochromeTestImage.jpg b/Tests/Tests/MonochromeTestImage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..169bae042b96bd7727e11b7aa5e1d49121ec66d4 GIT binary patch literal 7096 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 MeT~IShR5aq1Ig#&M*si- literal 0 HcmV?d00001 diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index f4f066b6..da82904b 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -22,172 +22,179 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; @implementation SDImageCacheTests -- (void)setUp -{ +- (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. self.sharedImageCache = [SDImageCache sharedImageCache]; [self clearAllCaches]; } -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testSharedImageCache { +- (void)test01SharedImageCache { expect(self.sharedImageCache).toNot.beNil(); } -- (void)testSingleton{ +- (void)test02Singleton{ expect(self.sharedImageCache).to.equal([SDImageCache sharedImageCache]); } -- (void)testClearDiskCache{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; - [self.sharedImageCache clearDiskOnCompletion:^{ - expect([self.sharedImageCache diskImageExistsWithKey:kImageTestKey]).to.equal(NO); - expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]); - }]; +- (void)test03ImageCacheCanBeInstantiated { + SDImageCache *imageCache = [[SDImageCache alloc] init]; + expect(imageCache).toNot.equal([SDImageCache sharedImageCache]); } -- (void)testClearMemoryCache{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; +- (void)test04ClearDiskCache{ + XCTestExpectation *expectation = [self expectationWithDescription:@"Clear disk cache"]; + + [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; + [self.sharedImageCache clearDiskOnCompletion:^{ + [self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + if (!isInCache) { + [expectation fulfill]; + } else { + XCTFail(@"Image should not be in cache"); + } + }]; + expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]); + }]; + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} + +- (void)test05ClearMemoryCache{ + XCTestExpectation *expectation = [self expectationWithDescription:@"Clear memory cache"]; + + [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; [self.sharedImageCache clearMemory]; expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; - // Seems not able to access the files correctly (maybe only from test?) - //expect([self.sharedImageCache diskImageExistsWithKey:kImageTestKey]).to.equal(YES); [self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { - expect(isInCache).to.equal(YES); + if (isInCache) { + [expectation fulfill]; + } else { + XCTFail(@"Image should be in cache"); + } }]; + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; } // Testing storeImage:forKey: -- (void)testInsertionOfImage { +- (void)test06InsertionOfImage { + XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey"]; + UIImage *image = [self imageForTesting]; - [self.sharedImageCache storeImage:image forKey:kImageTestKey]; + [self.sharedImageCache storeImage:image forKey:kImageTestKey completion:nil]; expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal(image); - expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.equal(image); + [self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + if (isInCache) { + [expectation fulfill]; + } else { + XCTFail(@"Image should be in cache"); + } + }]; + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; } // Testing storeImage:forKey:toDisk:YES -- (void)testInsertionOfImageForcingDiskStorage{ +- (void)test07InsertionOfImageForcingDiskStorage{ + XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=YES"]; + UIImage *image = [self imageForTesting]; - [self.sharedImageCache storeImage:image forKey:kImageTestKey toDisk:YES]; + [self.sharedImageCache storeImage:image forKey:kImageTestKey toDisk:YES completion:nil]; expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal(image); - // Seems not able to access the files correctly (maybe only from test?) - //expect([self.sharedImageCache diskImageExistsWithKey:kImageTestKey]).to.equal(YES); [self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { - expect(isInCache).to.equal(YES); + if (isInCache) { + [expectation fulfill]; + } else { + XCTFail(@"Image should be in cache"); + } }]; + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; } // Testing storeImage:forKey:toDisk:NO -- (void)testInsertionOfImageOnlyInMemory { +- (void)test08InsertionOfImageOnlyInMemory { + XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=NO"]; UIImage *image = [self imageForTesting]; - [self.sharedImageCache storeImage:image forKey:@"TestImage" toDisk:NO]; - [self.sharedImageCache diskImageExistsWithKey:@"TestImage" completion:^(BOOL isInCache) { - expect(isInCache).to.equal(YES); + [self.sharedImageCache storeImage:image forKey:kImageTestKey toDisk:NO completion:nil]; + + expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]); + [self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { + if (!isInCache) { + [expectation fulfill]; + } else { + XCTFail(@"Image should not be in cache"); + } }]; [self.sharedImageCache clearMemory]; - [self.sharedImageCache diskImageExistsWithKey:@"TestImage" completion:^(BOOL isInCache) { - expect(isInCache).to.equal(NO); - }]; + expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil(); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; } -- (void)testRetrievalImageThroughNSOperation{ - //- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock; +- (void)test09RetrieveImageThroughNSOperation{ + //- (NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock; UIImage *imageForTesting = [self imageForTesting]; - [self.sharedImageCache storeImage:imageForTesting forKey:kImageTestKey]; - NSOperation *operation = [self.sharedImageCache queryDiskCacheForKey:kImageTestKey done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) { + [self.sharedImageCache storeImage:imageForTesting forKey:kImageTestKey completion:nil]; + NSOperation *operation = [self.sharedImageCache queryCacheOperationForKey:kImageTestKey done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) { expect(image).to.equal(imageForTesting); }]; expect(operation).toNot.beNil; } -- (void)testRemoveImageForKey{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; - [self.sharedImageCache removeImageForKey:kImageTestKey]; - expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; - expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.beNil; -} - -- (void)testRemoveImageForKeyWithCompletion{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; +- (void)test10RemoveImageForKeyWithCompletion{ + [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; [self.sharedImageCache removeImageForKey:kImageTestKey withCompletion:^{ expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.beNil; expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; }]; } -- (void)testRemoveImageForKeyNotFromDisk{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; - [self.sharedImageCache removeImageForKey:kImageTestKey fromDisk:NO]; - expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).toNot.beNil; - expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; -} - -- (void)testRemoveImageForKeyFromDisk{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; - [self.sharedImageCache removeImageForKey:kImageTestKey fromDisk:NO]; - expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.beNil; - expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; -} - -- (void)testRemoveImageforKeyNotFromDiskWithCompletion{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; +- (void)test11RemoveImageforKeyNotFromDiskWithCompletion{ + [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; [self.sharedImageCache removeImageForKey:kImageTestKey fromDisk:NO withCompletion:^{ expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).toNot.beNil; expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; }]; } -- (void)testRemoveImageforKeyFromDiskWithCompletion{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; +- (void)test12RemoveImageforKeyFromDiskWithCompletion{ + [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; [self.sharedImageCache removeImageForKey:kImageTestKey fromDisk:YES withCompletion:^{ expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.beNil; expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil; }]; } -// TODO -- Testing insertion with recalculate -- (void)testInsertionOfImageOnlyInDisk { -} - -- (void)testInitialCacheSize{ +- (void)test20InitialCacheSize{ expect([self.sharedImageCache getSize]).to.equal(0); } -- (void)testInitialDiskCount{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; +- (void)test21InitialDiskCount{ + [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; expect([self.sharedImageCache getDiskCount]).to.equal(1); } -- (void)testDiskCountAfterInsertion{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; +- (void)test22DiskCountAfterInsertion{ + [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; expect([self.sharedImageCache getDiskCount]).to.equal(1); } -- (void)testDefaultCachePathForAnyKey{ +- (void)test31DefaultCachePathForAnyKey{ NSString *path = [self.sharedImageCache defaultCachePathForKey:kImageTestKey]; expect(path).toNot.beNil; } -- (void)testCachePathForNonExistingKey{ +- (void)test32CachePathForNonExistingKey{ NSString *path = [self.sharedImageCache cachePathForKey:kImageTestKey inPath:[self.sharedImageCache defaultCachePathForKey:kImageTestKey]]; expect(path).to.beNil; } -- (void)testCachePathForExistingKey{ - [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey]; +- (void)test33CachePathForExistingKey{ + [self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil]; NSString *path = [self.sharedImageCache cachePathForKey:kImageTestKey inPath:[self.sharedImageCache defaultCachePathForKey:kImageTestKey]]; expect(path).notTo.beNil; } // TODO -- Testing image data insertion -- (void)testInsertionOfImageData { +- (void)test40InsertionOfImageData { NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]]; [self.sharedImageCache storeImageDataToDisk:imageData forKey:kImageTestKey]; @@ -202,18 +209,28 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; [self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) { expect(isInCache).to.equal(YES); }]; + + [self.sharedImageCache calculateSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize) { + expect(fileCount).to.beLessThan(100); + }]; } #pragma mark Helper methods - (void)clearAllCaches{ - [self.sharedImageCache clearDisk]; + [self.sharedImageCache deleteOldFilesWithCompletionBlock:nil]; + + // TODO: this is not ok, clearDiskOnCompletion will clear async, this means that when we execute the tests, the cache might not be cleared + [self.sharedImageCache clearDiskOnCompletion:nil]; [self.sharedImageCache clearMemory]; } - (UIImage *)imageForTesting{ - - return [UIImage imageWithContentsOfFile:[self testImagePath]]; + static UIImage *reusableImage = nil; + if (!reusableImage) { + reusableImage = [UIImage imageWithContentsOfFile:[self testImagePath]]; + } + return reusableImage; } - (NSString *)testImagePath { diff --git a/Tests/Tests/SDWebImageDecoderTests.m b/Tests/Tests/SDWebImageDecoderTests.m new file mode 100644 index 00000000..56bcaf91 --- /dev/null +++ b/Tests/Tests/SDWebImageDecoderTests.m @@ -0,0 +1,61 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Matt Galloway + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#define EXP_SHORTHAND // required by Expecta + + +#import +#import + +#import "SDWebImageDecoder.h" + +@interface SDWebImageDecoderTests : XCTestCase + +@end + +@implementation SDWebImageDecoderTests + +- (void)test01ThatDecodedImageWithNilImageReturnsNil { + expect([UIImage decodedImageWithImage:nil]).to.beNil(); +} + +- (void)test02ThatDecodedImageWithImageWorksWithARegularJPGImage { + NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"]; + UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *decodedImage = [UIImage decodedImageWithImage:image]; + expect(decodedImage).toNot.beNil(); + expect(decodedImage).toNot.equal(image); +} + +- (void)test03ThatDecodedImageWithImageDoesNotDecodeAnimatedImages { + NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"]; + UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *animatedImage = [UIImage animatedImageWithImages:@[image] duration:0]; + UIImage *decodedImage = [UIImage decodedImageWithImage:animatedImage]; + expect(decodedImage).toNot.beNil(); + expect(decodedImage).to.equal(animatedImage); +} + +- (void)test04ThatDecodedImageWithImageDoesNotDecodeImagesWithAlpha { + NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"png"]; + UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *decodedImage = [UIImage decodedImageWithImage:image]; + expect(decodedImage).toNot.beNil(); + expect(decodedImage).to.equal(image); +} + +- (void)test05ThatDecodedImageWithImageWorksEvenWithMonochromeImage { + NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"MonochromeTestImage" ofType:@"jpg"]; + UIImage *image = [UIImage imageWithContentsOfFile:testImagePath]; + UIImage *decodedImage = [UIImage decodedImageWithImage:image]; + expect(decodedImage).toNot.beNil(); + expect(decodedImage).toNot.equal(image); +} + +@end diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index f7b7641a..d42bee18 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -14,6 +14,46 @@ #import #import "SDWebImageDownloader.h" +#import "SDWebImageDownloaderOperation.h" + +/** + * Category for SDWebImageDownloader so we can access the operationClass + */ +@interface SDWebImageDownloader () +@property (assign, nonatomic, nullable) Class operationClass; +@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; + +- (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock + completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock + forURL:(nullable NSURL *)url + createCallback:(SDWebImageDownloaderOperation *(^)())createCallback; +@end + +/** + * A class that fits the NSOperation+SDWebImageDownloaderOperationInterface requirement so we can test + */ +@interface CustomDownloaderOperation : NSOperation + +@property (nonatomic, assign) BOOL shouldDecompressImages; +@property (nonatomic, strong, nullable) NSURLCredential *credential; + +@end + +@implementation CustomDownloaderOperation + +- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)req inSession:(nullable NSURLSession *)ses options:(SDWebImageDownloaderOptions)opt { + if ((self = [super init])) { } + return self; +} + +- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { + return nil; +} + +@end + + @interface SDWebImageDownloaderTests : XCTestCase @@ -21,68 +61,288 @@ @implementation SDWebImageDownloaderTests -- (void)setUp -{ - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. +- (void)test01ThatSharedDownloaderIsNotEqualToInitDownloader { + SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init]; + expect(downloader).toNot.equal([SDWebImageDownloader sharedDownloader]); } -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; +- (void)test02ThatByDefaultDownloaderSetsTheAcceptHTTPHeader { + expect([[SDWebImageDownloader sharedDownloader] valueForHTTPHeaderField:@"Accept"]).to.match(@"image/\\*"); } -- (void)testThatDownloadingSameURLTwiceAndCancellingFirstWorks { - XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"]; - - NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage000.jpg"]; - - id token1 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL - options:0 - progress:nil - completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { - XCTFail(@"Shouldn't have completed here."); - }]; - expect(token1).toNot.beNil(); - - id token2 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL - options:0 - progress:nil - completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { - [expectation fulfill]; - }]; - expect(token2).toNot.beNil(); - - [[SDWebImageDownloader sharedDownloader] cancel:token1]; - - [self waitForExpectationsWithTimeout:5. handler:nil]; +- (void)test03ThatSetAndGetValueForHTTPHeaderFieldWork { + NSString *headerValue = @"Tests"; + NSString *headerName = @"AppName"; + // set it + [[SDWebImageDownloader sharedDownloader] setValue:headerValue forHTTPHeaderField:headerName]; + expect([[SDWebImageDownloader sharedDownloader] valueForHTTPHeaderField:headerName]).to.equal(headerValue); + // clear it + [[SDWebImageDownloader sharedDownloader] setValue:nil forHTTPHeaderField:headerName]; + expect([[SDWebImageDownloader sharedDownloader] valueForHTTPHeaderField:headerName]).to.beNil(); } -- (void)testThatCancelingDownloadThenRequestingAgainWorks { - XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"]; +- (void)test04ThatASimpleDownloadWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Simple download"]; + NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage004.jpg"]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else { + XCTFail(@"Something went wrong"); + } + }]; + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} +- (void)test05ThatSetAndGetMaxConcurrentDownloadsWorks { + NSInteger initialValue = [SDWebImageDownloader sharedDownloader].maxConcurrentDownloads; + + [[SDWebImageDownloader sharedDownloader] setMaxConcurrentDownloads:3]; + expect([SDWebImageDownloader sharedDownloader].maxConcurrentDownloads).to.equal(3); + + [[SDWebImageDownloader sharedDownloader] setMaxConcurrentDownloads:initialValue]; +} + +- (void)test06ThatUsingACustomDownloaderOperationWorks { + // we try to set a usual NSOperation as operation class. Should not work + [[SDWebImageDownloader sharedDownloader] setOperationClass:[NSOperation class]]; + expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([SDWebImageDownloaderOperation class]); + + // setting an NSOperation subclass that conforms to SDWebImageDownloaderOperationInterface - should work + [[SDWebImageDownloader sharedDownloader] setOperationClass:[CustomDownloaderOperation class]]; + expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([CustomDownloaderOperation class]); + + // back to the original value + [[SDWebImageDownloader sharedDownloader] setOperationClass:nil]; + expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([SDWebImageDownloaderOperation class]); +} + +- (void)test07ThatAddProgressCallbackCompletedBlockWithNilURLCallsTheCompletionBlockWithNils { + XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called with nils"]; + [[SDWebImageDownloader sharedDownloader] addProgressCallback:nil completedBlock:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (!image && !data && !error) { + [expectation fulfill]; + } else { + XCTFail(@"All params should be nil"); + } + } forURL:nil createCallback:nil]; + [self waitForExpectationsWithTimeout:0.5 handler:nil]; +} + +- (void)test08ThatAHTTPAuthDownloadWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"HTTP Auth download"]; + [SDWebImageDownloader sharedDownloader].username = @"httpwatch"; + [SDWebImageDownloader sharedDownloader].password = @"httpwatch01"; + NSURL *imageURL = [NSURL URLWithString:@"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633"]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else { + XCTFail(@"Something went wrong"); + } + }]; + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; + [SDWebImageDownloader sharedDownloader].username = nil; + [SDWebImageDownloader sharedDownloader].password = nil; +} + +- (void)test09ThatProgressiveJPEGWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive JPEG download"]; + NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage009.jpg"]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveDownload progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else if (finished) { + XCTFail(@"Something went wrong"); + } else { + // progressive updates + } + }]; + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} + +- (void)test10That404CaseCallsCompletionWithError { NSURL *imageURL = [NSURL URLWithString:@"http://static2.dmcdn.net/static/video/656/177/44771656:jpeg_preview_small.jpg?20120509154705"]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"404"]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (!image && !data && error && finished) { + [expectation fulfill]; + } else { + XCTFail(@"Something went wrong"); + } + }]; + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} - id token1 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL - options:0 - progress:nil - completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { - XCTFail(@"Shouldn't have completed here."); - }]; +- (void)test11ThatCancelWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Cancel"]; + + NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage011.jpg"]; + SDWebImageDownloadToken *token = [[SDWebImageDownloader sharedDownloader] + downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + XCTFail(@"Should not get here"); + }]; + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); + + [[SDWebImageDownloader sharedDownloader] cancel:token]; + + // doesn't cancel immediately - since it uses dispatch async + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(0); + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} + +- (void)test12ThatWeCanUseAnotherSessionForEachDownloadOperation { + XCTestExpectation *expectation = [self expectationWithDescription:@"Owned session"]; + NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage012.jpg"]; + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:imageURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15]; + request.HTTPShouldUsePipelining = YES; + request.allHTTPHeaderFields = @{@"Accept": @"image/*;q=0.8"}; + + SDWebImageDownloaderOperation *operation = [[SDWebImageDownloaderOperation alloc] initWithRequest:request + inSession:nil + options:0]; + [operation addHandlersForProgress:^(NSInteger receivedSize, NSInteger expectedSize) { + + } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else { + XCTFail(@"Something went wrong"); + } + }]; + + [operation start]; + + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} + +- (void)test13ThatDownloadCanContinueWhenTheAppEntersBackground { + XCTestExpectation *expectation = [self expectationWithDescription:@"Simple download"]; + NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage013.jpg"]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderContinueInBackground progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else { + XCTFail(@"Something went wrong"); + } + }]; + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} + +- (void)test14ThatPNGWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"WEBP"]; + NSURL *imageURL = [NSURL URLWithString:@"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png"]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else { + XCTFail(@"Something went wrong"); + } + }]; + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} + +- (void)test15ThatWEBPWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"WEBP"]; + NSURL *imageURL = [NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]; + [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else { + XCTFail(@"Something went wrong"); + } + }]; + expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} + +/** + * Per #883 - Fix multiple requests for same image and then canceling one + * Old SDWebImage (3.x) could not handle correctly multiple requests for the same image + cancel + * In 4.0, via #883 added `SDWebImageDownloadToken` so we can cancel exactly the request we want + * This test validates the scenario of making 2 requests for the same image and cancelling the 1st one + */ +- (void)test20ThatDownloadingSameURLTwiceAndCancellingFirstWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"]; + + NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage020.jpg"]; + + SDWebImageDownloadToken *token1 = [[SDWebImageDownloader sharedDownloader] + downloadImageWithURL:imageURL + options:0 + progress:nil + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { + XCTFail(@"Shouldn't have completed here."); + }]; expect(token1).toNot.beNil(); + + SDWebImageDownloadToken *token2 = [[SDWebImageDownloader sharedDownloader] + downloadImageWithURL:imageURL + options:0 + progress:nil + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else { + XCTFail(@"Something went wrong"); + } + }]; + expect(token2).toNot.beNil(); [[SDWebImageDownloader sharedDownloader] cancel:token1]; - id token2 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL - options:0 - progress:nil - completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { - [expectation fulfill]; - }]; - expect(token2).toNot.beNil(); + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; +} - [self waitForExpectationsWithTimeout:5. handler:nil]; +/** + * Per #883 - Fix multiple requests for same image and then canceling one + * Old SDWebImage (3.x) could not handle correctly multiple requests for the same image + cancel + * In 4.0, via #883 added `SDWebImageDownloadToken` so we can cancel exactly the request we want + * This test validates the scenario of requesting an image, cancel and then requesting it again + */ +- (void)test21ThatCancelingDownloadThenRequestingAgainWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"]; + + NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage021.jpg"]; + + SDWebImageDownloadToken *token1 = [[SDWebImageDownloader sharedDownloader] + downloadImageWithURL:imageURL + options:0 + progress:nil + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { + XCTFail(@"Shouldn't have completed here."); + }]; + expect(token1).toNot.beNil(); + + [[SDWebImageDownloader sharedDownloader] cancel:token1]; + + SDWebImageDownloadToken *token2 = [[SDWebImageDownloader sharedDownloader] + downloadImageWithURL:imageURL + options:0 + progress:nil + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { + if (image && data && !error && finished) { + [expectation fulfill]; + } else { + NSLog(@"image = %@, data = %@, error = %@", image, data, error); + XCTFail(@"Something went wrong"); + } + }]; + expect(token2).toNot.beNil(); + + [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; } @end diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index f2059e48..f12455a2 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -14,8 +14,6 @@ #import "SDWebImageManager.h" -static int64_t kAsyncTestTimeout = 5; - @interface SDWebImageManagerTests : XCTestCase diff --git a/Tests/Tests/TestImage.gif b/Tests/Tests/TestImage.gif new file mode 100644 index 0000000000000000000000000000000000000000..a47fd4b99311bc8a3f18c7fc8de85161e94428c5 GIT binary patch literal 3109 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 TNmFQAY7{c1sb;NktaIT%%KXL_ literal 0 HcmV?d00001 diff --git a/Tests/Tests/TestImage.png b/Tests/Tests/TestImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9d9dd87742e52fa78e9750b88d8758636c78677e GIT binary patch literal 6822 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 literal 0 HcmV?d00001