624 lines
33 KiB
Objective-C
624 lines
33 KiB
Objective-C
/*
|
|
* 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 <KVOController/KVOController.h>
|
|
|
|
@interface SDWebCacheCategoriesTests : SDTestCase
|
|
|
|
@property (nonatomic, strong) UIWindow *window;
|
|
|
|
@end
|
|
|
|
@implementation SDWebCacheCategoriesTests
|
|
|
|
- (void)testUIImageViewSetImageWithURL {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setImageWithURL"];
|
|
|
|
UIImageView *imageView = [[UIImageView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[imageView sd_setImageWithURL:originalImageURL
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect(imageView.image).to.equal(image);
|
|
[expectation fulfill];
|
|
}];
|
|
expect(imageView.sd_imageURL).equal(originalImageURL);
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIImageViewSetImageWithURLDiskSync {
|
|
NSData *imageData = [NSData dataWithContentsOfFile:[self testJPEGPath]];
|
|
|
|
// Ensure the image is cached in disk but not memory
|
|
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache storeImageDataToDisk:imageData forKey:kTestJPEGURL];
|
|
|
|
UIImageView *imageView = [[UIImageView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
|
|
[imageView sd_setImageWithURL:originalImageURL
|
|
placeholderImage:nil
|
|
options:SDWebImageQueryDiskDataSync
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect(imageView.image).to.equal(image);
|
|
}];
|
|
expect(imageView.sd_imageURL).equal(originalImageURL);
|
|
expect(imageView.image).toNot.beNil();
|
|
}
|
|
|
|
#if SD_UIKIT
|
|
- (void)testUIImageViewSetHighlightedImageWithURL {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setHighlightedImageWithURL"];
|
|
|
|
UIImageView *imageView = [[UIImageView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[imageView sd_setHighlightedImageWithURL:originalImageURL
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect(imageView.highlightedImage).to.equal(image);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
#endif
|
|
|
|
- (void)testMKAnnotationViewSetImageWithURL {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"MKAnnotationView setImageWithURL"];
|
|
|
|
MKAnnotationView *annotationView = [[MKAnnotationView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[annotationView sd_setImageWithURL:originalImageURL
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect(annotationView.image).to.equal(image);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
#if SD_UIKIT
|
|
- (void)testUIButtonSetImageWithURLNormalState {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setImageWithURL normalState"];
|
|
|
|
UIButton *button = [[UIButton alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[button sd_setImageWithURL:originalImageURL
|
|
forState:UIControlStateNormal
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect([button imageForState:UIControlStateNormal]).to.equal(image);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIButtonSetImageWithURLHighlightedState {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setImageWithURL highlightedState"];
|
|
|
|
UIButton *button = [[UIButton alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[button sd_setImageWithURL:originalImageURL
|
|
forState:UIControlStateHighlighted
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect([button imageForState:UIControlStateHighlighted]).to.equal(image);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIButtonSetBackgroundImageWithURLNormalState {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setBackgroundImageWithURL normalState"];
|
|
|
|
UIButton *button = [[UIButton alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[button sd_setBackgroundImageWithURL:originalImageURL
|
|
forState:UIControlStateNormal
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect([button backgroundImageForState:UIControlStateNormal]).to.equal(image);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIButtonBackgroundImageCancelCurrentImageLoad {
|
|
UIButton *button = [[UIButton alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[button sd_setBackgroundImageWithURL:originalImageURL forState:UIControlStateNormal];
|
|
[button sd_cancelBackgroundImageLoadForState:UIControlStateNormal];
|
|
NSString *backgroundImageOperationKey = [self testBackgroundImageOperationKeyForState:UIControlStateNormal];
|
|
expect([button sd_imageLoadOperationForKey:backgroundImageOperationKey]).beNil();
|
|
}
|
|
|
|
#endif
|
|
|
|
#if SD_MAC
|
|
- (void)testNSButtonSetImageWithURL {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"NSButton setImageWithURL"];
|
|
|
|
NSButton *button = [[NSButton alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[button sd_setImageWithURL:originalImageURL
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect(button.image).to.equal(image);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testNSButtonSetAlternateImageWithURL {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"NSButton setAlternateImageWithURL"];
|
|
|
|
NSButton *button = [[NSButton alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[button sd_setAlternateImageWithURL:originalImageURL
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect(button.alternateImage).to.equal(image);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
#endif
|
|
|
|
- (void)testUIViewInternalSetImageWithURL {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIView internalSetImageWithURL"];
|
|
|
|
UIView *view = [[UIView alloc] init];
|
|
#if SD_MAC
|
|
view.wantsLayer = YES;
|
|
#endif
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
UIImage *placeholder = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
|
|
[view sd_internalSetImageWithURL:originalImageURL
|
|
placeholderImage:placeholder
|
|
options:0
|
|
context:nil
|
|
setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
if (!imageData && cacheType == SDImageCacheTypeNone) {
|
|
// placeholder
|
|
expect(image).to.equal(placeholder);
|
|
} else {
|
|
// cache or download
|
|
expect(image).toNot.beNil();
|
|
}
|
|
view.layer.contents = (__bridge id _Nullable)(image.CGImage);
|
|
}
|
|
progress:nil
|
|
completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
expect(image).toNot.beNil();
|
|
expect(error).to.beNil();
|
|
expect(originalImageURL).to.equal(imageURL);
|
|
expect((__bridge CGImageRef)view.layer.contents == image.CGImage).to.beTruthy();
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIViewCancelWithDelayPlaceholderShouldCallbackOnceBeforeSecond {
|
|
XCTestExpectation *expectation1 = [self expectationWithDescription:@"UIView internalSetImageWithURL call 1"];
|
|
XCTestExpectation *expectation2 = [self expectationWithDescription:@"UIView internalSetImageWithURL call 2"];
|
|
|
|
UIView *imageView = [[UIView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
|
|
|
|
__block NSUInteger calledSetImageTimes = 0;
|
|
__block NSUInteger calledSetImageTimes2 = 0;
|
|
NSString *operationKey = NSUUID.UUID.UUIDString;
|
|
UIImage *placeholder1 = UIImage.new;
|
|
id<SDWebImageOperation> op1 = [imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:placeholder1 options:SDWebImageDelayPlaceholder context:@{ SDWebImageContextSetImageOperationKey:operationKey} setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
// Should called before second query (We changed the cache callback in sync when cancelled)
|
|
expect(calledSetImageTimes2).equal(0);
|
|
calledSetImageTimes++;
|
|
} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
if (calledSetImageTimes == 1) {
|
|
[expectation1 fulfill];
|
|
}
|
|
}];
|
|
[op1 cancel];
|
|
|
|
UIImage *placeholder2 = UIImage.new;
|
|
[imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:placeholder2 options:0 context:@{ SDWebImageContextSetImageOperationKey:operationKey} setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
if (calledSetImageTimes2 == 0) {
|
|
expect(image).equal(placeholder2);
|
|
} else {
|
|
expect(image).notTo.beNil();
|
|
}
|
|
calledSetImageTimes2++;
|
|
} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
if (calledSetImageTimes2 == 2) {
|
|
[expectation2 fulfill];
|
|
}
|
|
}];
|
|
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIViewCancelWithoutDelayPlaceholderShouldCallbackOnceBeforeSecond {
|
|
XCTestExpectation *expectation1 = [self expectationWithDescription:@"UIView internalSetImageWithURL call 1"];
|
|
XCTestExpectation *expectation2 = [self expectationWithDescription:@"UIView internalSetImageWithURL call 2"];
|
|
|
|
UIView *imageView = [[UIView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
|
|
|
|
__block NSUInteger calledSetImageTimes = 0;
|
|
__block NSUInteger calledSetImageTimes2 = 0;
|
|
NSString *operationKey = NSUUID.UUID.UUIDString;
|
|
UIImage *placeholder1 = UIImage.new;
|
|
id<SDWebImageOperation> op1 = [imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:placeholder1 options:0 context:@{ SDWebImageContextSetImageOperationKey:operationKey} setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
// Should called before second query (We changed the cache callback in sync when cancelled)
|
|
expect(calledSetImageTimes2).equal(0);
|
|
calledSetImageTimes++;
|
|
} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
if (calledSetImageTimes == 1) {
|
|
[expectation1 fulfill];
|
|
}
|
|
}];
|
|
[op1 cancel];
|
|
|
|
UIImage *placeholder2 = UIImage.new;
|
|
[imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:placeholder2 options:0 context:@{ SDWebImageContextSetImageOperationKey:operationKey} setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
if (calledSetImageTimes2 == 0) {
|
|
expect(image).equal(placeholder2);
|
|
} else {
|
|
expect(image).notTo.beNil();
|
|
}
|
|
calledSetImageTimes2++;
|
|
} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
if (calledSetImageTimes2 == 2) {
|
|
[expectation2 fulfill];
|
|
}
|
|
}];
|
|
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIViewCancelCurrentImageLoad {
|
|
UIView *imageView = [[UIView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
|
|
[imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:nil];
|
|
[imageView sd_cancelCurrentImageLoad];
|
|
NSString *operationKey = NSStringFromClass(UIView.class);
|
|
expect(imageView.sd_latestOperationKey).beNil();
|
|
expect([imageView sd_imageLoadOperationForKey:operationKey]).beNil();
|
|
}
|
|
|
|
- (void)testUIViewCancelCurrentImageLoadWithTransition {
|
|
UIView *imageView = [[UIView alloc] init];
|
|
NSURL *firstImageUrl = [NSURL URLWithString:kTestJPEGURL];
|
|
NSURL *secondImageUrl = [NSURL URLWithString:kTestPNGURL];
|
|
|
|
// First, reset our caches
|
|
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestPNGURL];
|
|
|
|
// Next, lets put our second image into memory, so that the next time
|
|
// we load it, it will come from memory, and thus shouldUseTransition will be NO
|
|
XCTestExpectation *firstLoadExpectation = [self expectationWithDescription:@"First image loaded"];
|
|
|
|
[imageView sd_internalSetImageWithURL:secondImageUrl placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
[firstLoadExpectation fulfill];
|
|
}];
|
|
|
|
[self waitForExpectations:@[firstLoadExpectation]
|
|
timeout:5.0];
|
|
|
|
// Now, lets load a new image using a transition
|
|
XCTestExpectation *secondLoadExpectation = [self expectationWithDescription:@"Second image loaded"];
|
|
XCTestExpectation *transitionPreparesExpectation = [self expectationWithDescription:@"Transition prepares"];
|
|
|
|
// Build a custom transition with a completion block that
|
|
// we do not expect to be called, because we cancel in the
|
|
// middle of a transition
|
|
XCTestExpectation *transitionCompletionExpecation = [self expectationWithDescription:@"Transition completed"];
|
|
transitionCompletionExpecation.inverted = YES;
|
|
|
|
SDWebImageTransition *customTransition = [SDWebImageTransition new];
|
|
customTransition.duration = 1.0;
|
|
customTransition.prepares = ^(__kindof UIView * _Nonnull view, UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
[transitionPreparesExpectation fulfill];
|
|
};
|
|
customTransition.completion = ^(BOOL finished) {
|
|
[transitionCompletionExpecation fulfill];
|
|
};
|
|
|
|
// Now, load our first image URL (maybe as part of a UICollectionView)
|
|
// We use a custom context to ensure a unique ImageOperationKey for every load
|
|
// that is requested
|
|
NSMutableDictionary *context = [NSMutableDictionary new];
|
|
context[SDWebImageContextSetImageOperationKey] = firstImageUrl.absoluteString;
|
|
|
|
imageView.sd_imageTransition = customTransition;
|
|
[imageView sd_internalSetImageWithURL:firstImageUrl placeholderImage:nil options:0 context:context setImageBlock:nil progress:nil completed:nil];
|
|
[self waitForExpectations:@[transitionPreparesExpectation] timeout:5.0];
|
|
|
|
// At this point, our transition has started, and so we cancel the load operation,
|
|
// perhaps as a result of a call to `prepareForReuse` in a UICollectionViewCell
|
|
[imageView sd_cancelCurrentImageLoad];
|
|
|
|
// Now, we update our context's imageOperationKey and URL, perhaps
|
|
// because of a re-use of a UICollectionViewCell. In this case,
|
|
// we are assigning an image URL that is already present in the
|
|
// memory cache
|
|
context[SDWebImageContextSetImageOperationKey] = secondImageUrl.absoluteString;
|
|
[imageView sd_internalSetImageWithURL:secondImageUrl placeholderImage:nil options:0 context:context setImageBlock:nil progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
|
|
[secondLoadExpectation fulfill];
|
|
}];
|
|
|
|
// The original load operation's transitionCompletionExpecation should never
|
|
// be called (it has been inverted, above)
|
|
[self waitForExpectations:@[secondLoadExpectation, transitionCompletionExpecation]
|
|
timeout:2.0];
|
|
}
|
|
|
|
- (void)testUIViewCancelCallbackWithError {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIView internalSetImageWithURL cancel callback error"];
|
|
|
|
UIView *imageView = [[UIView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
|
|
[imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
expect(error).notTo.beNil();
|
|
expect(error.code).equal(SDWebImageErrorCancelled);
|
|
[expectation fulfill];
|
|
}];
|
|
[imageView sd_cancelCurrentImageLoad];
|
|
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIViewImageProgressKVOWork {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIView imageProgressKVO failed"];
|
|
UIView *view = [[UIView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
|
|
[self.KVOController observe:view.sd_imageProgress keyPath:NSStringFromSelector(@selector(fractionCompleted)) options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
|
|
NSProgress *progress = object;
|
|
NSNumber *completedValue = change[NSKeyValueChangeNewKey];
|
|
expect(progress.fractionCompleted).equal(completedValue.doubleValue);
|
|
// mark that KVO is called
|
|
[progress setUserInfoObject:@(YES) forKey:NSStringFromSelector(@selector(testUIViewImageProgressKVOWork))];
|
|
}];
|
|
|
|
// Clear the disk cache to force download from network
|
|
[[SDImageCache sharedImageCache] removeImageForKey:kTestJPEGURL withCompletion:^{
|
|
[view sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
expect(view.sd_imageProgress.fractionCompleted).equal(1.0);
|
|
expect([view.sd_imageProgress.userInfo[NSStringFromSelector(_cmd)] boolValue]).equal(YES);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIViewTransitionFromNetworkWork {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIView transition from network does not work"];
|
|
|
|
// Attach a window, or CALayer will not submit drawing
|
|
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
|
|
// Cover each convenience method
|
|
imageView.sd_imageTransition = SDWebImageTransition.fadeTransition;
|
|
imageView.sd_imageTransition = SDWebImageTransition.flipFromTopTransition;
|
|
imageView.sd_imageTransition = SDWebImageTransition.flipFromLeftTransition;
|
|
imageView.sd_imageTransition = SDWebImageTransition.flipFromBottomTransition;
|
|
imageView.sd_imageTransition = SDWebImageTransition.flipFromRightTransition;
|
|
imageView.sd_imageTransition = SDWebImageTransition.curlUpTransition;
|
|
imageView.sd_imageTransition = SDWebImageTransition.curlDownTransition;
|
|
imageView.sd_imageTransition.duration = 1;
|
|
|
|
#if SD_UIKIT
|
|
[self.window addSubview:imageView];
|
|
#else
|
|
imageView.wantsLayer = YES;
|
|
[self.window.contentView addSubview:imageView];
|
|
#endif
|
|
|
|
UIImage *placeholder = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
|
|
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
__weak typeof(imageView) wimageView = imageView;
|
|
[imageView sd_setImageWithURL:originalImageURL
|
|
placeholderImage:placeholder
|
|
options:SDWebImageForceTransition
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
__strong typeof(wimageView) simageView = imageView;
|
|
// Delay to let CALayer commit the transition in next runloop
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kMinDelayNanosecond), dispatch_get_main_queue(), ^{
|
|
// Check current view contains layer animation
|
|
NSArray *animationKeys = simageView.layer.animationKeys;
|
|
expect(animationKeys.count).beGreaterThan(0);
|
|
[expectation fulfill];
|
|
});
|
|
}];
|
|
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIViewTransitionFromDiskWork {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIView transition from disk does not work"];
|
|
|
|
// Attach a window, or CALayer will not submit drawing
|
|
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
|
|
imageView.sd_imageTransition = SDWebImageTransition.fadeTransition;
|
|
imageView.sd_imageTransition.duration = 1;
|
|
|
|
#if SD_UIKIT
|
|
[self.window addSubview:imageView];
|
|
#else
|
|
imageView.wantsLayer = YES;
|
|
[self.window.contentView addSubview:imageView];
|
|
#endif
|
|
|
|
NSData *imageData = [NSData dataWithContentsOfFile:[self testJPEGPath]];
|
|
UIImage *placeholder = [[UIImage alloc] initWithData:imageData];
|
|
|
|
// Ensure the image is cached in disk but not memory
|
|
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache storeImageDataToDisk:imageData forKey:kTestJPEGURL];
|
|
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
__weak typeof(imageView) wimageView = imageView;
|
|
[imageView sd_setImageWithURL:originalImageURL
|
|
placeholderImage:placeholder
|
|
options:SDWebImageFromCacheOnly // Ensure we queired from disk cache
|
|
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL];
|
|
[SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL];
|
|
__strong typeof(wimageView) simageView = imageView;
|
|
// Delay to let CALayer commit the transition in next runloop
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kMinDelayNanosecond), dispatch_get_main_queue(), ^{
|
|
// Check current view contains layer animation
|
|
NSArray *animationKeys = simageView.layer.animationKeys;
|
|
expect(animationKeys.count).beGreaterThan(0);
|
|
[expectation fulfill];
|
|
});
|
|
}];
|
|
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIViewIndicatorWork {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIView indicator does not work"];
|
|
|
|
UIImageView *imageView = [[UIImageView alloc] init];
|
|
imageView.sd_imageIndicator = SDWebImageActivityIndicator.grayIndicator;
|
|
// Cover each convience method, finally use progress indicator for test
|
|
imageView.sd_imageIndicator = SDWebImageActivityIndicator.grayLargeIndicator;
|
|
imageView.sd_imageIndicator = SDWebImageActivityIndicator.whiteIndicator;
|
|
imageView.sd_imageIndicator = SDWebImageActivityIndicator.whiteLargeIndicator;
|
|
#if SD_IOS
|
|
imageView.sd_imageIndicator = SDWebImageProgressIndicator.barIndicator;
|
|
#endif
|
|
imageView.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator;
|
|
// Test setter trigger removeFromSuperView
|
|
expect(imageView.subviews.count).equal(1);
|
|
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
__weak typeof(imageView) wimageView = imageView;
|
|
[imageView sd_setImageWithURL:originalImageURL
|
|
placeholderImage:nil options:SDWebImageFromLoaderOnly progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
__strong typeof(wimageView) simageView = imageView;
|
|
UIView *indicatorView = simageView.subviews.firstObject;
|
|
expect(indicatorView).equal(simageView.sd_imageIndicator.indicatorView);
|
|
|
|
if (receivedSize <= 0 || expectedSize <= 0) {
|
|
return;
|
|
}
|
|
|
|
// Base on current implementation, since we dispatch the progressBlock to main queue, the indicator's progress state should be synchonized
|
|
double progress = 0;
|
|
double imageProgress = (double)receivedSize / (double)expectedSize;
|
|
#if SD_UIKIT
|
|
progress = ((UIProgressView *)simageView.sd_imageIndicator.indicatorView).progress;
|
|
#else
|
|
progress = ((NSProgressIndicator *)simageView.sd_imageIndicator.indicatorView).doubleValue / 100;
|
|
#endif
|
|
expect(progress).equal(imageProgress);
|
|
});
|
|
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
|
__strong typeof(wimageView) simageView = imageView;
|
|
double progress = 0;
|
|
#if SD_UIKIT
|
|
progress = ((UIProgressView *)simageView.sd_imageIndicator.indicatorView).progress;
|
|
#else
|
|
progress = ((NSProgressIndicator *)simageView.sd_imageIndicator.indicatorView).doubleValue / 100;
|
|
#endif
|
|
// Finish progress is 1
|
|
expect(progress).equal(1);
|
|
[expectation fulfill];
|
|
}];
|
|
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
- (void)testUIViewOperationKeyContextWorks {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"UIView operation key context should pass through"];
|
|
|
|
UIView *view = [[UIView alloc] init];
|
|
NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL];
|
|
SDWebImageManager *customManager = [[SDWebImageManager alloc] initWithCache:SDImageCachesManager.sharedManager loader:SDImageLoadersManager.sharedManager];
|
|
customManager.optionsProcessor = [SDWebImageOptionsProcessor optionsProcessorWithBlock:^SDWebImageOptionsResult * _Nullable(NSURL * _Nullable url, SDWebImageOptions options, SDWebImageContext * _Nullable context) {
|
|
// expect manager does not exist, avoid retain cycle
|
|
expect(context[SDWebImageContextCustomManager]).beNil();
|
|
// expect operation key to be the image view class
|
|
expect(context[SDWebImageContextSetImageOperationKey]).equal(NSStringFromClass(view.class));
|
|
return [[SDWebImageOptionsResult alloc] initWithOptions:options context:context];
|
|
}];
|
|
[view sd_internalSetImageWithURL:originalImageURL
|
|
placeholderImage:nil
|
|
options:0
|
|
context:@{SDWebImageContextCustomManager: customManager}
|
|
setImageBlock:nil
|
|
progress:nil
|
|
completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
|
[expectation fulfill];
|
|
}];
|
|
|
|
[self waitForExpectationsWithCommonTimeout];
|
|
}
|
|
|
|
#pragma mark - Helper
|
|
- (UIWindow *)window {
|
|
if (!_window) {
|
|
UIScreen *mainScreen = [UIScreen mainScreen];
|
|
#if SD_UIKIT
|
|
_window = [[UIWindow alloc] initWithFrame:mainScreen.bounds];
|
|
#else
|
|
_window = [[NSWindow alloc] initWithContentRect:mainScreen.frame styleMask:0 backing:NSBackingStoreBuffered defer:NO screen:mainScreen];
|
|
#endif
|
|
}
|
|
return _window;
|
|
}
|
|
|
|
- (NSString *)testJPEGPath {
|
|
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
|
return [testBundle pathForResource:@"TestImage" ofType:@"jpg"];
|
|
}
|
|
|
|
#if SD_UIKIT
|
|
- (NSString *)testBackgroundImageOperationKeyForState:(UIControlState)state {
|
|
return [NSString stringWithFormat:@"UIButtonBackgroundImageOperation%lu", (unsigned long)state];
|
|
}
|
|
#endif
|
|
|
|
@end
|