Add tests about SDAnimatedImage SDAnimatedImageView and SDAnimatedImage+WebCache
This commit is contained in:
parent
4563e714d7
commit
7e83d78ca3
|
@ -54,10 +54,10 @@
|
|||
// These methods are for SDAnimatedImage class only but not for SDWebImageAnimatedCoder.
|
||||
@optional
|
||||
/**
|
||||
Preload all frame image to memory. Then directly return the frame for index without decoding.
|
||||
Preload all frame image to memory. Then later request can directly return the frame for index without decoding.
|
||||
This method may be called on background thread.
|
||||
|
||||
@note If the image is shared by lots of imageViews, preload all frames will reduce the CPU cost because the decoder may not need to keep re-entrant for randomly index access.
|
||||
@note If the image is shared by lots of imageViews, preload all frames will reduce the CPU cost because the decoder may not need to keep re-entrant for randomly index access. But this will cause more memory usage.
|
||||
*/
|
||||
- (void)preloadAllFrames;
|
||||
|
||||
|
@ -102,11 +102,11 @@
|
|||
#endif
|
||||
|
||||
/**
|
||||
Preload all frame image to memory. Then directly return the frame for index without decoding.
|
||||
Preload all frame image to memory. Then later request can directly return the frame for index without decoding.
|
||||
The preloaded animated image frames will be removed when receiving memory warning.
|
||||
|
||||
@note If the image is shared by lots of imageViews, preload all frames will reduce the CPU cost because the decoder may not need to keep re-entrant for randomly index access.
|
||||
@note Once preload the frames into memory, there is no huge differenec on performance between UIImage's `animatedImageWithImages:duration:` for UIKit. But UIImage's animation have some issue such like blanking or frame resetting. It's recommend to use only if need.
|
||||
@note If the image is shared by lots of imageViews, preload all frames will reduce the CPU cost because the decoder may not need to keep re-entrant for randomly index access. But this will cause more memory usage.
|
||||
@note Once preload the frames into memory, there is no huge difference on performance between this and UIImage's `animatedImageWithImages:duration:`. But UIImage's animation have some issue such like blanking or frame restarting working with `UIImageView`. It's recommend to use only if need.
|
||||
*/
|
||||
- (void)preloadAllFrames;
|
||||
|
||||
|
|
|
@ -387,9 +387,8 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
if (shouldDecode) {
|
||||
image = [SDWebImageCoderHelper decodedImageWithImage:image];
|
||||
}
|
||||
if (!finished) {
|
||||
image.sd_isIncremental = YES;
|
||||
}
|
||||
// mark the image as progressive (completionBlock one are not mark as progressive)
|
||||
image.sd_isIncremental = YES;
|
||||
|
||||
// We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding.
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; };
|
||||
32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */; };
|
||||
32B99EAE203B366C0017FD66 /* SDWebCacheCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */; };
|
||||
32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; };
|
||||
32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */; };
|
||||
37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 37D122871EC48B5E00D98CEB /* SDMockFileManager.m */; };
|
||||
433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; };
|
||||
|
@ -66,6 +67,7 @@
|
|||
32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = "<group>"; };
|
||||
32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
32B99E96203B2DF90017FD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageTest.m; sourceTree = "<group>"; };
|
||||
32E6F0301F3A1B4700A945E6 /* SDWebImageTestDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDecoder.h; sourceTree = "<group>"; };
|
||||
32E6F0311F3A1B4700A945E6 /* SDWebImageTestDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDecoder.m; sourceTree = "<group>"; };
|
||||
37D122861EC48B5E00D98CEB /* SDMockFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDMockFileManager.h; sourceTree = "<group>"; };
|
||||
|
@ -195,6 +197,7 @@
|
|||
3254C31F20641077008D1022 /* SDWebImageTransformerTests.m */,
|
||||
4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */,
|
||||
32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */,
|
||||
32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */,
|
||||
37D122861EC48B5E00D98CEB /* SDMockFileManager.h */,
|
||||
37D122871EC48B5E00D98CEB /* SDMockFileManager.m */,
|
||||
2D7AF05E1F329763000083C2 /* SDTestCase.h */,
|
||||
|
@ -469,6 +472,7 @@
|
|||
files = (
|
||||
32E6F0321F3A1B4700A945E6 /* SDWebImageTestDecoder.m in Sources */,
|
||||
3254C32020641077008D1022 /* SDWebImageTransformerTests.m in Sources */,
|
||||
32A571562037DB2D002EDAAE /* SDAnimatedImageTest.m in Sources */,
|
||||
1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */,
|
||||
37D122881EC48B5E00D98CEB /* SDMockFileManager.m in Sources */,
|
||||
4369C2741D9804B1007E863A /* SDWebCacheCategoriesTests.m in Sources */,
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
* (c) Matt Galloway
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDTestCase.h"
|
||||
#import <SDWebImage/SDAnimatedImage.h>
|
||||
#import <SDWebImage/SDAnimatedImageView.h>
|
||||
#import <SDWebImage/SDWebImageGIFCoder.h>
|
||||
#import <SDWebImage/UIImage+WebCache.h>
|
||||
#import <SDWebImage/SDAnimatedImageView+WebCache.h>
|
||||
#import <KVOController/KVOController.h>
|
||||
|
||||
static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop count
|
||||
|
||||
@interface SDAnimatedImageTest : SDTestCase
|
||||
|
||||
@property (nonatomic, strong) UIWindow *window;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDAnimatedImageTest
|
||||
|
||||
- (void)tearDown {
|
||||
[[SDImageCache sharedImageCache] removeImageForKey:kTestGIFURL fromDisk:YES withCompletion:nil];
|
||||
[[SDImageCache sharedImageCache] removeImageForKey:kTestWebPURL fromDisk:YES withCompletion:nil];
|
||||
}
|
||||
|
||||
- (void)test01AnimatedImageInitWithData {
|
||||
NSData *invalidData = [@"invalid data" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithData:invalidData];
|
||||
expect(image).beNil();
|
||||
|
||||
NSData *validData = [self testGIFData];
|
||||
image = [[SDAnimatedImage alloc] initWithData:validData scale:2];
|
||||
expect(image).notTo.beNil(); // image
|
||||
expect(image.scale).equal(2); // scale
|
||||
expect(image.animatedImageData).equal(validData); // data
|
||||
expect(image.animatedImageFormat).equal(SDImageFormatGIF); // format
|
||||
expect(image.animatedImageLoopCount).equal(0); // loop count
|
||||
expect(image.animatedImageFrameCount).equal(kTestGIFFrameCount); // frame count
|
||||
expect([image animatedImageFrameAtIndex:1]).notTo.beNil(); // 1 frame
|
||||
}
|
||||
|
||||
- (void)test02AnimatedImageInitWithContentsOfFile {
|
||||
SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithContentsOfFile:[self testGIFPath]];
|
||||
expect(image).notTo.beNil();
|
||||
expect(image.scale).equal(1); // scale
|
||||
// enough, other can be test with InitWithData
|
||||
}
|
||||
|
||||
- (void)test03AnimatedImageInitWithAnimatedCoder {
|
||||
NSData *validData = [self testGIFData];
|
||||
SDWebImageGIFCoder *coder = [[SDWebImageGIFCoder alloc] initWithAnimatedImageData:validData];
|
||||
SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1];
|
||||
expect(image).notTo.beNil();
|
||||
// enough, other can be test with InitWithData
|
||||
}
|
||||
|
||||
- (void)test04AnimatedImagePreloadFrames {
|
||||
NSData *validData = [self testGIFData];
|
||||
SDAnimatedImage *image = [SDAnimatedImage imageWithData:validData];
|
||||
|
||||
// Preload all frames
|
||||
[image preloadAllFrames];
|
||||
|
||||
NSArray *preloadAnimatedImageFrames = [image valueForKey:@"preloadAnimatedImageFrames"];
|
||||
expect(preloadAnimatedImageFrames.count).equal(kTestGIFFrameCount);
|
||||
|
||||
// Test one frame
|
||||
UIImage *frame = [image animatedImageFrameAtIndex:0];
|
||||
expect(frame).notTo.beNil();
|
||||
}
|
||||
|
||||
- (void)test05AnimatedImageViewSetImage {
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
UIImage *image = [UIImage imageWithData:[self testJPEGData]];
|
||||
imageView.image = image;
|
||||
expect(imageView.image).notTo.beNil();
|
||||
expect(imageView.currentFrame).beNil(); // current frame
|
||||
}
|
||||
|
||||
- (void)test06AnimatedImageViewSetAnimatedImage {
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testAnimatedWebPData]];
|
||||
imageView.image = image;
|
||||
expect(imageView.image).notTo.beNil();
|
||||
expect(imageView.currentFrame).notTo.beNil(); // current frame
|
||||
}
|
||||
|
||||
- (void)test07AnimatedImageViewRendering {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView rendering"];
|
||||
SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init];
|
||||
[self.window addSubview:imageView];
|
||||
|
||||
NSMutableDictionary *frames = [NSMutableDictionary dictionaryWithCapacity:kTestGIFFrameCount];
|
||||
|
||||
[self.KVOController observe:imageView keyPaths:@[NSStringFromSelector(@selector(currentFrameIndex)), NSStringFromSelector(@selector(currentLoopCount))] options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
|
||||
NSUInteger frameIndex = imageView.currentFrameIndex;
|
||||
NSUInteger loopCount = imageView.currentLoopCount;
|
||||
[frames setObject:@(YES) forKey:@(frameIndex)];
|
||||
|
||||
BOOL framesRendered = NO;
|
||||
if (frames.count >= kTestGIFFrameCount) {
|
||||
// All frames rendered
|
||||
framesRendered = YES;
|
||||
}
|
||||
BOOL loopFinished = NO;
|
||||
if (loopCount >= 1) {
|
||||
// One loop finished
|
||||
loopFinished = YES;
|
||||
}
|
||||
if (framesRendered && loopFinished) {
|
||||
[imageView stopAnimating];
|
||||
[expectation fulfill];
|
||||
}
|
||||
}];
|
||||
|
||||
SDAnimatedImage *image = [SDAnimatedImage imageWithData:[self testGIFData]];
|
||||
imageView.image = image;
|
||||
|
||||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
- (void)test08AnimatedImageViewSetProgressiveAnimatedImage {
|
||||
NSData *gifData = [self testGIFData];
|
||||
SDWebImageGIFCoder *progressiveCoder = [[SDWebImageGIFCoder alloc] initIncremental];
|
||||
// simulate progressive decode, pass partial data
|
||||
NSData *partialData = [gifData subdataWithRange:NSMakeRange(0, gifData.length - 1)];
|
||||
[progressiveCoder updateIncrementalData:partialData finished:NO];
|
||||
|
||||
SDAnimatedImage *partialImage = [[SDAnimatedImage alloc] initWithAnimatedCoder:progressiveCoder scale:1];
|
||||
partialImage.sd_isIncremental = YES;
|
||||
|
||||
SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init];
|
||||
imageView.image = partialImage;
|
||||
|
||||
BOOL isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue];
|
||||
expect(isProgressive).equal(YES);
|
||||
|
||||
// pass full data
|
||||
[progressiveCoder updateIncrementalData:gifData finished:YES];
|
||||
|
||||
SDAnimatedImage *fullImage = [[SDAnimatedImage alloc] initWithAnimatedCoder:progressiveCoder scale:1];
|
||||
|
||||
imageView.image = fullImage;
|
||||
|
||||
isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue];
|
||||
expect(isProgressive).equal(NO);
|
||||
}
|
||||
|
||||
- (void)test09AnimatedImageViewCategory {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"];
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
NSURL *testURL = [NSURL URLWithString:kTestWebPURL];
|
||||
[imageView sd_setImageWithURL:testURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(error).to.beNil();
|
||||
expect(image).notTo.beNil();
|
||||
expect([image isKindOfClass:[SDAnimatedImage class]]).beTruthy();
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
- (void)test10AnimatedImageViewCategoryProgressive {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"];
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
NSURL *testURL = [NSURL URLWithString:kTestGIFURL];
|
||||
[imageView sd_setImageWithURL:testURL placeholderImage:nil options:SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIImage *image = imageView.image;
|
||||
// Progressive image may be nil when download data is not enough
|
||||
if (image) {
|
||||
expect(image.sd_isIncremental).beTruthy();
|
||||
BOOL isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue];
|
||||
expect(isProgressive).equal(YES);
|
||||
}
|
||||
});
|
||||
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(error).to.beNil();
|
||||
expect(image).notTo.beNil();
|
||||
expect([image isKindOfClass:[SDAnimatedImage class]]).beTruthy();
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
#pragma mark - Helper
|
||||
- (UIWindow *)window {
|
||||
if (!_window) {
|
||||
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
}
|
||||
return _window;
|
||||
}
|
||||
|
||||
- (NSString *)testGIFPath {
|
||||
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *testPath = [testBundle pathForResource:@"TestImage" ofType:@"gif"];
|
||||
return testPath;
|
||||
}
|
||||
|
||||
- (NSData *)testGIFData {
|
||||
NSData *testData = [NSData dataWithContentsOfFile:[self testGIFPath]];
|
||||
return testData;
|
||||
}
|
||||
|
||||
- (NSString *)testAnimatedWebPPath {
|
||||
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *testPath = [testBundle pathForResource:@"TestImageAnimated" ofType:@"webp"];
|
||||
return testPath;
|
||||
}
|
||||
|
||||
- (NSData *)testAnimatedWebPData {
|
||||
return [NSData dataWithContentsOfFile:[self testAnimatedWebPPath]];
|
||||
}
|
||||
|
||||
- (NSString *)testJPEGPath {
|
||||
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *testPath = [testBundle pathForResource:@"TestImage" ofType:@"jpg"];
|
||||
return testPath;
|
||||
}
|
||||
|
||||
- (NSData *)testJPEGData {
|
||||
NSData *testData = [NSData dataWithContentsOfFile:[self testJPEGPath]];
|
||||
return testData;
|
||||
}
|
||||
|
||||
@end
|
|
@ -17,6 +17,8 @@ FOUNDATION_EXPORT const int64_t kAsyncTestTimeout;
|
|||
FOUNDATION_EXPORT const int64_t kMinDelayNanosecond;
|
||||
FOUNDATION_EXPORT NSString * _Nonnull const kTestJpegURL;
|
||||
FOUNDATION_EXPORT NSString * _Nonnull const kTestPNGURL;
|
||||
FOUNDATION_EXPORT NSString * _Nonnull const kTestGIFURL;
|
||||
FOUNDATION_EXPORT NSString * _Nonnull const kTestWebPURL;
|
||||
|
||||
@interface SDTestCase : XCTestCase
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ const int64_t kAsyncTestTimeout = 5;
|
|||
const int64_t kMinDelayNanosecond = NSEC_PER_MSEC * 100; // 0.1s
|
||||
NSString *const kTestJpegURL = @"http://via.placeholder.com/50x50.jpg";
|
||||
NSString *const kTestPNGURL = @"http://via.placeholder.com/50x50.png";
|
||||
NSString *const kTestGIFURL = @"https://media.giphy.com/media/UEsrLdv7ugRTq/giphy.gif";
|
||||
NSString *const kTestWebPURL = @"http://littlesvr.ca/apng/images/SteamEngine.webp";
|
||||
|
||||
@implementation SDTestCase
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
return image;
|
||||
}
|
||||
|
||||
- (instancetype)initIncrementally
|
||||
- (instancetype)initIncremental
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
|
@ -33,13 +33,17 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished {
|
||||
- (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished {
|
||||
return;
|
||||
}
|
||||
|
||||
- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options {
|
||||
NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"];
|
||||
UIImage *image = [[UIImage alloc] initWithContentsOfFile:testImagePath];
|
||||
return image;
|
||||
}
|
||||
|
||||
- (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data {
|
||||
- (BOOL)canIncrementalDecodeFromData:(NSData *)data {
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue