blob: 93b26b0f9cec46e994cc7c17b06ca7302ca4545a [file] [log] [blame]
//
// Copyright 2021 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.
//
#include "contrast_check.h"
#import <XCTest/XCTest.h>
#include <abseil/absl/types/optional.h>
#import "GTXLocalizedStringsManagerUtils.h"
#include "GTXProtoUtils.h"
#import "NSString+GTXAdditions.h"
#include "element_trait.h"
#include "gtx_types.h"
#import "GTXUITestUtils.h"
#import "GTXObjCPPTestUtils.h"
/**
* The size of one of the dimensions of test images used in contrast check tests.
*/
static const int kGTXTestImageSize = 3;
/**
* The accessibility frame of UI elements such that they correspond to the correct region of the
* screenshot.
*/
static const CGRect kGTXAccessibilityFrame = CGRectMake(0, 0, kGTXTestImageSize, kGTXTestImageSize);
/**
* The frame of the virtual device screenshots are captured from.
*/
static const gtx::Rect kGTXTestDeviceBounds = {0, 0, kGTXTestImageSize, kGTXTestImageSize};
@interface GTXContrastCheckTests : XCTestCase {
/**
* The check under test.
*/
std::unique_ptr<gtx::ContrastCheck> _check;
}
@end
@implementation GTXContrastCheckTests
- (void)setUp {
[super setUp];
_check = std::make_unique<gtx::ContrastCheck>();
}
- (void)testCategoryReturnsCorrectValue {
XCTAssertEqual(_check->Category(), gtx::CheckCategory::kLowContrast);
}
- (void)testHighContrastImagePassesCheck {
std::vector<gtx::Pixel> pixels = [self gtxtest_pixelsWithForegroundColor:[UIColor blackColor]
backgroundColor:[UIColor whiteColor]];
gtx::Image image;
image.pixels = pixels.data();
image.width = kGTXTestImageSize;
image.height = kGTXTestImageSize;
gtx::Parameters parameters;
parameters.set_screenshot(image);
parameters.set_device_bounds(kGTXTestDeviceBounds);
UIElementProto element;
element.set_ax_traits(static_cast<uint64_t>(gtx::ElementTrait::kStaticText));
*element.mutable_ax_frame() = [GTXProtoUtils protoFromCGRect:kGTXAccessibilityFrame];
absl::optional<CheckResultProto> result = _check->CheckElement(element, parameters);
XCTAssertEqual(result, absl::nullopt);
}
- (void)testLowContrastImagePassesCheck {
UIColor *almostBlack = [UIColor colorWithWhite:0.1 alpha:1.0];
std::vector<gtx::Pixel> pixels = [self gtxtest_pixelsWithForegroundColor:[UIColor blackColor]
backgroundColor:almostBlack];
gtx::Image image;
image.pixels = pixels.data();
image.width = kGTXTestImageSize;
image.height = kGTXTestImageSize;
gtx::Parameters parameters;
parameters.set_screenshot(image);
parameters.set_device_bounds(kGTXTestDeviceBounds);
UIElementProto element;
element.set_ax_traits(static_cast<uint64_t>(gtx::ElementTrait::kStaticText));
*element.mutable_ax_frame() = [GTXProtoUtils protoFromCGRect:kGTXAccessibilityFrame];
absl::optional<CheckResultProto> result = _check->CheckElement(element, parameters);
XCTAssertNotEqual(result, absl::nullopt);
XCTAssertEqual(result->result_id(), gtx::ContrastCheck::RESULT_ID_INSUFFICIENT_CONTRAST_RATIO);
std::vector<std::string> expectedKeys = {
gtx::ContrastCheck::KEY_EXPECTED_CONTRAST_RATIO,
gtx::ContrastCheck::KEY_ACTUAL_CONTRAST_RATIO,
gtx::ContrastCheck::KEY_FOREGROUND_COLOR,
gtx::ContrastCheck::KEY_BACKGROUND_COLOR,
};
XCTAssert([GTXObjCPPTestUtils metadata:result->metadata() contains:expectedKeys]);
}
- (void)testGetRichMessageFormatsMessageWithMetadata {
gtx::MetadataMap metadata;
metadata.SetFloat(gtx::ContrastCheck::KEY_EXPECTED_CONTRAST_RATIO, 7.0);
metadata.SetFloat(gtx::ContrastCheck::KEY_ACTUAL_CONTRAST_RATIO, 2.0);
metadata.SetString(gtx::ContrastCheck::KEY_FOREGROUND_COLOR, "(0.0, 0.0, 0.0, 0.0)");
metadata.SetString(gtx::ContrastCheck::KEY_BACKGROUND_COLOR, "(0.1, 0.1, 0.1, 1.0)");
int result_id = gtx::ContrastCheck::RESULT_ID_INSUFFICIENT_CONTRAST_RATIO;
std::unique_ptr<gtx::LocalizedStringsManager> stringsManager =
[GTXLocalizedStringsManagerUtils defaultLocalizedStringsManager];
std::string message =
_check->GetRichMessage(gtx::kLocaleEnglish, result_id, metadata, *stringsManager);
// Assert that the message was constructed successfully without crashing.
std::string expected =
"The element's text contrast ratio is 2. This ratio is based on a text "
"color of <tt>(0.0, 0.0, 0.0, 0.0)</tt> and background color of <tt>(0.1, 0.1, 0.1, "
"1.0)</tt>. Consider increasing this element's text contrast ratio to 7 or greater.";
XCTAssertEqual(message, expected);
}
- (void)testGetPlainMessageFormatsMessageWithMetadata {
gtx::MetadataMap metadata;
metadata.SetFloat(gtx::ContrastCheck::KEY_EXPECTED_CONTRAST_RATIO, 7.0);
metadata.SetFloat(gtx::ContrastCheck::KEY_ACTUAL_CONTRAST_RATIO, 2.0);
metadata.SetString(gtx::ContrastCheck::KEY_FOREGROUND_COLOR, "(0.0, 0.0, 0.0, 0.0)");
metadata.SetString(gtx::ContrastCheck::KEY_BACKGROUND_COLOR, "(0.1, 0.1, 0.1, 1.0)");
int result_id = gtx::ContrastCheck::RESULT_ID_INSUFFICIENT_CONTRAST_RATIO;
std::unique_ptr<gtx::LocalizedStringsManager> stringsManager =
[GTXLocalizedStringsManagerUtils defaultLocalizedStringsManager];
std::string message =
_check->GetPlainMessage(gtx::kLocaleEnglish, result_id, metadata, *stringsManager);
// Assert that the message was constructed successfully without tags.
std::string expected =
"The element's text contrast ratio is 2. This ratio is based on a text "
"color of (0.0, 0.0, 0.0, 0.0) and background color of (0.1, 0.1, 0.1, "
"1.0). Consider increasing this element's text contrast ratio to 7 or greater.";
XCTAssertEqual(message, expected);
}
#pragma mark - Private Methods
/**
* Constructs a 2d array of pixels containing only foreground and background colors. More pixels are
* @c backgroundColor than @c foregroundColor so it is unambiguous which is which.
* @param foregroundColor The foreground color. Less pixels of this color exist.
* @param backgroundColor The background color. More pixels of this color exist.
* @return An array of pixels containing @c foregroundColor and @c backgroundColor.
*/
- (std::vector<gtx::Pixel>)gtxtest_pixelsWithForegroundColor:(UIColor *)foregroundColor
backgroundColor:(UIColor *)backgroundColor {
CGSize pixelSize = CGSizeMake(kGTXTestImageSize, kGTXTestImageSize);
std::vector<gtx::Pixel> pixels(kGTXTestImageSize * kGTXTestImageSize);
// A gtx::Color is just 4 bytes, one for each color component. It is safe to cast it to an array
// of uint8_t.
[GTXUITestUtils fillRect:CGRectMake(0, 0, kGTXTestImageSize, 1)
withColor:foregroundColor
inBuffer:(uint8_t *)(pixels.data())ofSize:pixelSize];
[GTXUITestUtils fillRect:CGRectMake(0, 1, kGTXTestImageSize, kGTXTestImageSize - 1)
withColor:backgroundColor
inBuffer:(uint8_t *)(pixels.data())ofSize:pixelSize];
return pixels;
}
@end