blob: fedb2d640722528d5f6d2d6f8748089b2e5f41bc [file] [log] [blame]
//
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "GTXImageAndColorUtils.h"
@interface GTXImageAndColorUtils (ExposedForTesting)
+ (UIColor *)gtx_shiftedColorWithColor:(UIColor *)color;
+ (CGFloat)gtx_contrastRatioWithTextElementImage:(UIImage *)original
textElementColorShiftedImage:(UIImage *)colorShifted;
@end
@interface GTXImageAndColorUtilsTests : XCTestCase
@end
@implementation GTXImageAndColorUtilsTests
- (void)testLuminanceAlgorithmWorks {
const CGFloat kAccuracy = 0.01f;
// Values computed using http://springmeier.org/www/contrastcalculator/index.php
XCTAssertEqualWithAccuracy([GTXImageAndColorUtils luminanceWithColor:[UIColor redColor]],
0.21f, kAccuracy);
XCTAssertEqualWithAccuracy([GTXImageAndColorUtils luminanceWithColor:[UIColor blueColor]],
0.07f, kAccuracy);
XCTAssertEqualWithAccuracy([GTXImageAndColorUtils luminanceWithColor:[UIColor greenColor]],
0.72f, kAccuracy);
XCTAssertEqualWithAccuracy([GTXImageAndColorUtils luminanceWithColor:[UIColor whiteColor]],
1.0f, kAccuracy);
XCTAssertEqualWithAccuracy([GTXImageAndColorUtils luminanceWithColor:[UIColor blackColor]],
0, kAccuracy);
XCTAssertEqualWithAccuracy(
[GTXImageAndColorUtils luminanceWithColor:[UIColor colorWithWhite:0.5f alpha:1.0f]],
0.22f, kAccuracy);
// We are using colorWithRed:green:blue:alpha: instead of UIColor::orangeColor to ensure known
// and testable values for red, green and blue.
UIColor *orange = [UIColor colorWithRed:1.0f green:0.5f blue:0.0f alpha:1.0f];
XCTAssertEqualWithAccuracy([GTXImageAndColorUtils luminanceWithColor:orange], 0.37f, kAccuracy);
// We are using colorWithRed:green:blue:alpha: instead of UIColor::purpleColor to ensure known
// and testable values for red, green and blue.
UIColor *purple = [UIColor colorWithRed:0.5f green:0.25f blue:0.5f alpha:1.0f];
XCTAssertEqualWithAccuracy([GTXImageAndColorUtils luminanceWithColor:purple], 0.1f, kAccuracy);
}
- (void)testShiftedColorsAreDifferent {
[self gtxtest_assertColor:[UIColor blackColor]
isDifferentFromColor:[GTXImageAndColorUtils gtx_shiftedColorWithColor:[UIColor blackColor]]];
[self gtxtest_assertColor:[UIColor whiteColor]
isDifferentFromColor:[GTXImageAndColorUtils gtx_shiftedColorWithColor:[UIColor whiteColor]]];
UIColor *grey = [UIColor colorWithWhite:0.5f alpha:1.0f];
[self gtxtest_assertColor:grey
isDifferentFromColor:[GTXImageAndColorUtils gtx_shiftedColorWithColor:grey]];
}
- (void)testContrastRatioIsComputedAccuratelyForLargeImages {
// Create a large grey image with light grey rect inside it.
CGSize imageSize = CGSizeMake(1000, 1000);
CGRect rect = CGRectMake(200, 200, 500, 500);
UIColor *testDarkGrey = [UIColor colorWithWhite:0.4 alpha:1.0];
UIColor *testLightGrey = [UIColor colorWithWhite:0.5 alpha:1.0];
[self gtx_assertContrastRatioIsSufficientlyAccurateInImageOfSize:imageSize
color:testLightGrey
withRect:rect
ofColor:testDarkGrey];
}
- (void)testContrastRatioIsComputedAccuratelyForSmallImages {
// Create a small red image with purple rect inside it.
CGSize imageSize = CGSizeMake(40, 40);
CGRect rect = CGRectMake(0, 0, 10, 10);
[self gtx_assertContrastRatioIsSufficientlyAccurateInImageOfSize:imageSize
color:[UIColor redColor]
withRect:rect
ofColor:[UIColor purpleColor]];
}
#pragma mark - Private
/**
* Asserts that the contrast ratio of colors in an image is same that computed from colors
* directly.
*
* @param size Image size.
* @param backgroundColor Background color on the image.
* @param rect Rectangle to be filled with @c rectColor.
* @param rectColor Fill color for @c rect.
*/
- (void)gtx_assertContrastRatioIsSufficientlyAccurateInImageOfSize:(CGSize)size
color:(UIColor *)backgroundColor
withRect:(CGRect)rect
ofColor:(UIColor *)rectColor {
// Create an image with the given colors.
UIImage *imageWithRect = [self gtxtest_imageOfColor:backgroundColor
inSize:size
withRectOfColor:rectColor
atRect:rect];
// Create the same image with rectColor replaced by its shifted color.
UIColor *shiftedColor = [GTXImageAndColorUtils gtx_shiftedColorWithColor:rectColor];
UIImage *imageWithShiftedColorRect = [self gtxtest_imageOfColor:backgroundColor
inSize:size
withRectOfColor:shiftedColor
atRect:rect];
// Assert that contrast ratio of the image is almost the same as contrast ratio of individual
// colors.
CGFloat luminanceOfFirstColor = [GTXImageAndColorUtils luminanceWithColor:backgroundColor];
CGFloat luminanceOfSecondColor = [GTXImageAndColorUtils luminanceWithColor:rectColor];
CGFloat contrastRatioOfColors =
[GTXImageAndColorUtils contrastRatioWithLuminaceOfFirstColor:luminanceOfFirstColor
andLuminanceOfSecondColor:luminanceOfSecondColor];
CGFloat contrastRatioInImage =
[GTXImageAndColorUtils gtx_contrastRatioWithTextElementImage:imageWithRect
textElementColorShiftedImage:imageWithShiftedColorRect];
XCTAssertEqualWithAccuracy(contrastRatioInImage, contrastRatioOfColors, kContrastRatioAccuracy);
}
/**
* Create an image with the given color and draws a rect filled with the given fill color.
*
* @param backgroundColor Background color on the image.
* @param imageSize Image size.
* @param rectColor Fill color for @c rect.
* @param rect Rectangle to be filled with @c rectColor.
*
* @return An UIImage with the given color.
*/
- (UIImage *)gtxtest_imageOfColor:(UIColor *)backgroundColor
inSize:(CGSize)imageSize
withRectOfColor:(UIColor *)rectColor
atRect:(CGRect)rect {
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
CGContextFillRect(context, CGRectMake(0, 0, imageSize.width, imageSize.height));
CGContextSetFillColorWithColor(context, rectColor.CGColor);
CGContextFillRect(context, rect);
return UIGraphicsGetImageFromCurrentImageContext();
}
- (void)gtxtest_assertColor:(UIColor *)first isDifferentFromColor:(UIColor *)second {
CGFloat firstRed, firstGreen, firstBlue;
CGFloat secondRed, secondGreen, secondBlue;
[first getRed:&firstRed green:&firstGreen blue:&firstBlue alpha:NULL];
[second getRed:&secondRed green:&secondGreen blue:&secondBlue alpha:NULL];
const CGFloat accuracy = 0.001f;
XCTAssertNotEqualWithAccuracy(firstRed, secondRed, accuracy);
XCTAssertNotEqualWithAccuracy(firstBlue, secondBlue, accuracy);
XCTAssertNotEqualWithAccuracy(firstGreen, secondGreen, accuracy);
}
@end