Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Andrewli/add color tolerance #213

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "542E5EAD47EA299C9005C3138923F693160B998F",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {

},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"542E5EAD47EA299C9005C3138923F693160B998F" : 9223372036854775807,
"C29DD0E89C17000393FD71820E9E7C86451DD28A" : 9223372036854775807
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "61F27B42-711F-4F72-989C-E02DC0D613E8",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"542E5EAD47EA299C9005C3138923F693160B998F" : "FBSnapshotTestCase\/",
"C29DD0E89C17000393FD71820E9E7C86451DD28A" : ".."
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "FBSnapshotTestCase",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "FBSnapshotTestCase.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/thorthugnasty\/ios-snapshot-test-case.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "542E5EAD47EA299C9005C3138923F693160B998F"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "ssh:\/\/git.corp.squareup.com\/ios\/appointments.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "C29DD0E89C17000393FD71820E9E7C86451DD28A"
}
]
}
2 changes: 1 addition & 1 deletion FBSnapshotTestCase/Categories/UIImage+Compare.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@

@interface UIImage (Compare)

- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance;
- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance colorTolerance:(CGFloat)colorTolerance;

@end
34 changes: 26 additions & 8 deletions FBSnapshotTestCase/Categories/UIImage+Compare.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

@implementation UIImage (Compare)

- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance
- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance colorTolerance:(CGFloat)colorTolerance
{
NSAssert(CGSizeEqualToSize(self.size, image.size), @"Images must be same size.");

Expand Down Expand Up @@ -97,7 +97,7 @@ - (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance
BOOL imageEqual = YES;

// Do a fast compare if we can
if (tolerance == 0) {
if (tolerance == 0 && colorTolerance == 0) {
imageEqual = (memcmp(referenceImagePixels, imagePixels, referenceImageSizeBytes) == 0);
} else {
// Go through each pixel in turn and see if it is different
Expand All @@ -111,12 +111,30 @@ - (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance
// If this pixel is different, increment the pixel diff count and see
// if we have hit our limit.
if (p1->raw != p2->raw) {
numDiffPixels ++;

CGFloat percent = (CGFloat)numDiffPixels / pixelCount;
if (percent > tolerance) {
imageEqual = NO;
break;
BOOL pixelsEqual = YES;
if (colorTolerance == 0) {
pixelsEqual = NO;
} else {
long dr = (long)p1->pixels.red - (long)p2->pixels.red;
long dg = (long)p1->pixels.green - (long)p2->pixels.green;
long db = (long)p1->pixels.blue - (long)p2->pixels.blue;

double distanceSquared = (float) (dr * dr + dg * dg + db * db);
distanceSquared /= (255.0 * 255.0); // Scale each channel from 0 - 255 to 0 - 1.0

if (distanceSquared > colorTolerance * colorTolerance) {
pixelsEqual = NO;
}
}

if (!pixelsEqual) {
numDiffPixels++;

CGFloat percent = (CGFloat)numDiffPixels / pixelCount;
if (percent > tolerance) {
imageEqual = NO;
break;
}
}
}

Expand Down
35 changes: 35 additions & 0 deletions FBSnapshotTestCase/FBSnapshotTestCase.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,54 @@
tolerance:(CGFloat)tolerance
error:(NSError **)errorPtr;

/**
Performs the comparison or records a snapshot of the layer if recordMode is YES.
@param layer The Layer to snapshot
@param referenceImagesDirectory The directory in which reference images are stored.
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
@param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
@param colorTolerance The euclidean distance allowable between two colors (with each channel 0-1.0) to consider pixels to be "identical". colorTolerance is applied before calculating percentage of pixels that are different.
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
@returns YES if the comparison (or saving of the reference image) succeeded.
*/
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
referenceImagesDirectory:(NSString *)referenceImagesDirectory
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr;

/**
Performs the comparison or records a snapshot of the view if recordMode is YES.
@param view The view to snapshot
@param referenceImagesDirectory The directory in which reference images are stored.
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
@param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
@returns YES if the comparison (or saving of the reference image) succeeded.
*/
- (BOOL)compareSnapshotOfView:(UIView *)view
referenceImagesDirectory:(NSString *)referenceImagesDirectory
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
error:(NSError **)errorPtr;


/**
Performs the comparison or records a snapshot of the view if recordMode is YES.
@param view The view to snapshot
@param referenceImagesDirectory The directory in which reference images are stored.
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
@param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
@param colorTolerance The euclidean distance allowable between two colors (with each channel 0-1.0) to consider pixels to be "identical". colorTolerance is applied before calculating percentage of pixels that are different.
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
@returns YES if the comparison (or saving of the reference image) succeeded.
*/
- (BOOL)compareSnapshotOfView:(UIView *)view
referenceImagesDirectory:(NSString *)referenceImagesDirectory
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr;

/**
Expand Down
41 changes: 39 additions & 2 deletions FBSnapshotTestCase/FBSnapshotTestCase.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ - (NSString *)snapshotVerifyViewOrLayer:(id)viewOrLayer

if (self.recordMode) {
NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%@%@", referenceImageDirectory, suffixes.firstObject];
BOOL referenceImageSaved = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:(identifier) tolerance:tolerance error:&error];
BOOL referenceImageSaved = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:(identifier) tolerance:tolerance colorTolerance: 0.0 error:&error];
if (!referenceImageSaved) {
[errors addObject:error];
}
Expand All @@ -97,7 +97,7 @@ - (NSString *)snapshotVerifyViewOrLayer:(id)viewOrLayer
BOOL referenceImageAvailable = [self referenceImageRecordedInDirectory:referenceImagesDirectory identifier:(identifier) error:&error];

if (referenceImageAvailable) {
BOOL comparisonSuccess = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:identifier tolerance:tolerance error:&error];
BOOL comparisonSuccess = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:identifier tolerance:tolerance colorTolerance: 0.0 error:&error];
[errors removeAllObjects];
if (comparisonSuccess) {
testSuccess = YES;
Expand Down Expand Up @@ -131,19 +131,54 @@ - (BOOL)compareSnapshotOfLayer:(CALayer *)layer
referenceImagesDirectory:referenceImagesDirectory
identifier:identifier
tolerance:tolerance
colorTolerance:0
error:errorPtr];
}



- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
referenceImagesDirectory:(NSString *)referenceImagesDirectory
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr
{
return [self _compareSnapshotOfViewOrLayer:layer
referenceImagesDirectory:referenceImagesDirectory
identifier:identifier
tolerance:tolerance
colorTolerance:colorTolerance
error:errorPtr];
}

- (BOOL)compareSnapshotOfView:(UIView *)view
referenceImagesDirectory:(NSString *)referenceImagesDirectory
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
error:(NSError **)errorPtr
{
return [self _compareSnapshotOfViewOrLayer:view
referenceImagesDirectory:referenceImagesDirectory
identifier:identifier
tolerance:tolerance
colorTolerance:0
error:errorPtr];
}


- (BOOL)compareSnapshotOfView:(UIView *)view
referenceImagesDirectory:(NSString *)referenceImagesDirectory
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr
{
return [self _compareSnapshotOfViewOrLayer:view
referenceImagesDirectory:referenceImagesDirectory
identifier:identifier
tolerance:tolerance
colorTolerance:colorTolerance
error:errorPtr];
}

Expand Down Expand Up @@ -179,13 +214,15 @@ - (BOOL)_compareSnapshotOfViewOrLayer:(id)viewOrLayer
referenceImagesDirectory:(NSString *)referenceImagesDirectory
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr
{
_snapshotController.referenceImagesDirectory = referenceImagesDirectory;
return [_snapshotController compareSnapshotOfViewOrLayer:viewOrLayer
selector:self.invocation.selector
identifier:identifier
tolerance:tolerance
colorTolerance:colorTolerance
error:errorPtr];
}

Expand Down
34 changes: 33 additions & 1 deletion FBSnapshotTestCase/FBSnapshotTestController.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,24 @@ extern NSString *const FBDiffedImageKey;
@param selector The test method being run.
@param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
@param tolerance The percentage of pixels that can differ and still be considered 'identical'
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
@param colorTolerance The euclidean distance allowable between two colors (with each channel 0-1.0) to consider pixels to be "identical". colorTolerance is applied before calculating percentage of pixels that are different.
@param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
@returns YES if the comparison (or saving of the reference image) succeeded.
*/
- (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
selector:(SEL)selector
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr;

/**
Performs the comparison of a view or layer.
@param view The view or layer to snapshot.
@param selector The test method being run.
@param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
@param tolerance The percentage of pixels that can differ and still be considered 'identical'
@param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
@returns YES if the comparison (or saving of the reference image) succeeded.
*/
- (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
Expand Down Expand Up @@ -149,6 +166,21 @@ extern NSString *const FBDiffedImageKey;
tolerance:(CGFloat)tolerance
error:(NSError **)errorPtr;

/**
Performs a pixel-by-pixel comparison of the two images with an allowable margin of error.
@param referenceImage The reference (correct) image.
@param image The image to test against the reference.
@param tolerance The percentage of pixels that can differ and still be considered 'identical'
@param colorTolerance The euclidean distance allowable between two colors (with each channel 0-1.0) to consider pixels to be "identical". colorTolerance is applied before calculating percentage of pixels that are different.
@param errorPtr An error that indicates why the comparison failed if it does.
@returns YES if the comparison succeeded and the images are the same(ish).
*/
- (BOOL)compareReferenceImage:(UIImage *)referenceImage
toImage:(UIImage *)image
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr;

/**
Saves the reference image and the test image to `failedOutputDirectory`.
@param referenceImage The reference (correct) image.
Expand Down
25 changes: 22 additions & 3 deletions FBSnapshotTestCase/FBSnapshotTestController.m
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,21 @@ - (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
error:(NSError **)errorPtr
{
return [self compareSnapshotOfViewOrLayer:viewOrLayer selector:selector identifier:identifier tolerance:tolerance colorTolerance:0.0 error:errorPtr];
}

- (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
selector:(SEL)selector
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr
{
if (self.recordMode) {
return [self _recordSnapshotOfViewOrLayer:viewOrLayer selector:selector identifier:identifier error:errorPtr];
} else {
return [self _performPixelComparisonWithViewOrLayer:viewOrLayer selector:selector identifier:identifier tolerance:tolerance error:errorPtr];
return [self _performPixelComparisonWithViewOrLayer:viewOrLayer selector:selector identifier:identifier tolerance:tolerance colorTolerance:colorTolerance error:errorPtr];
}
}

Expand Down Expand Up @@ -127,10 +137,18 @@ - (UIImage *)referenceImageForSelector:(SEL)selector
- (BOOL)compareReferenceImage:(UIImage *)referenceImage
toImage:(UIImage *)image
tolerance:(CGFloat)tolerance
error:(NSError **)errorPtr {
return [self compareReferenceImage:referenceImage toImage:image tolerance:tolerance colorTolerance:0 error:errorPtr];
}

- (BOOL)compareReferenceImage:(UIImage *)referenceImage
toImage:(UIImage *)image
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr
{
BOOL sameImageDimensions = CGSizeEqualToSize(referenceImage.size, image.size);
if (sameImageDimensions && [referenceImage fb_compareWithImage:image tolerance:tolerance]) {
if (sameImageDimensions && [referenceImage fb_compareWithImage:image tolerance:tolerance colorTolerance:colorTolerance]) {
return YES;
}

Expand Down Expand Up @@ -275,12 +293,13 @@ - (BOOL)_performPixelComparisonWithViewOrLayer:(id)viewOrLayer
selector:(SEL)selector
identifier:(NSString *)identifier
tolerance:(CGFloat)tolerance
colorTolerance:(CGFloat)colorTolerance
error:(NSError **)errorPtr
{
UIImage *referenceImage = [self referenceImageForSelector:selector identifier:identifier error:errorPtr];
if (nil != referenceImage) {
UIImage *snapshot = [self _imageForViewOrLayer:viewOrLayer];
BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot tolerance:tolerance error:errorPtr];
BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot tolerance:tolerance colorTolerance:colorTolerance error:errorPtr];
if (!imagesSame) {
NSError *saveError = nil;
if ([self saveFailedReferenceImage:referenceImage testImage:snapshot selector:selector identifier:identifier error:&saveError] == NO) {
Expand Down
Loading