blob: fb11e36ded970d0515b1fda1db0a9e17596a4089 [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 "GTXChecksCollection.h"
#import "GTXTestDynamicTypeCheckOptions.h"
NSString *const kExpectedErrorDescription = @"Check \"Accessibility label punctuation\" failed";
/**
* A view which responds to touches in a region defined by @c touchableRect, independent of @c frame
* or @c accessibilityFrame.
*/
@interface GTXTestDynamicTouchView : UIView
/**
* The region to respond to touches in, in this view's coordinate system.
*/
@property(assign, nonatomic) CGRect touchableRect;
@end
@implementation GTXTestDynamicTouchView
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return CGRectContainsPoint(self.touchableRect, point);
}
@end
@interface GTXChecksCollectionTests : XCTestCase
@end
@implementation GTXChecksCollectionTests
- (void)testAllGTXChecksForVersionExcludingChecksWithNamesNoExclusions {
NSSet<NSString *> *excludedNames = [[NSSet alloc] init];
NSArray<id<GTXChecking>> *checks = [GTXChecksCollection allGTXChecksForVersion:GTXVersionLatest
excludingChecksWithNames:excludedNames];
NSSet<NSString *> *actual = [self gtxtest_namesOfChecks:checks];
NSSet<NSString *> *expected =
[self gtxtest_namesOfChecks:[GTXChecksCollection allGTXChecksForVersion:GTXVersionLatest]];
XCTAssertEqualObjects(actual, expected);
}
- (void)testAllGTXChecksForVersionExcludingChecksWithNamesOneExclusion {
NSSet<NSString *> *excludedNames = [[NSSet alloc]
initWithArray:@[ [[GTXChecksCollection checkForSufficientContrastRatio] name] ]];
NSArray<id<GTXChecking>> *checks = [GTXChecksCollection allGTXChecksForVersion:GTXVersionLatest
excludingChecksWithNames:excludedNames];
NSSet<NSString *> *actual = [self gtxtest_namesOfChecks:checks];
NSSet<NSString *> *expected = [self gtxtest_namesOfChecks:@[
[GTXChecksCollection checkForAXLabelPresent],
[GTXChecksCollection checkForAXLabelNotPunctuated],
[GTXChecksCollection checkForAXLabelNotRedundantWithTraits],
[GTXChecksCollection checkForAXTraitDontConflict],
[GTXChecksCollection checkForMinimumTappableArea],
[GTXChecksCollection checkForSupportsDynamicType]
]];
XCTAssertEqualObjects(actual, expected);
}
- (void)testAllGTXChecksForVersionExcludingChecksWithNamesManyExclusions {
NSSet<NSString *> *excludedNames = [[NSSet alloc] initWithArray:@[
[[GTXChecksCollection checkForSufficientContrastRatio] name],
[[GTXChecksCollection checkForAXLabelNotPunctuated] name],
[[GTXChecksCollection checkForSupportsDynamicType] name]
]];
NSArray<id<GTXChecking>> *checks = [GTXChecksCollection allGTXChecksForVersion:GTXVersionLatest
excludingChecksWithNames:excludedNames];
NSSet<NSString *> *actual = [self gtxtest_namesOfChecks:checks];
NSSet<NSString *> *expected = [self gtxtest_namesOfChecks:@[
[GTXChecksCollection checkForAXLabelPresent],
[GTXChecksCollection checkForAXLabelNotRedundantWithTraits],
[GTXChecksCollection checkForAXTraitDontConflict],
[GTXChecksCollection checkForMinimumTappableArea]
]];
XCTAssertEqualObjects(actual, expected);
}
- (void)testAllGTXChecksForVersionExcludingChecksWithNamesAllExclusions {
NSSet<NSString *> *excludedNames =
[self gtxtest_namesOfChecks:[GTXChecksCollection allGTXChecksForVersion:GTXVersionLatest]];
NSArray<id<GTXChecking>> *checks = [GTXChecksCollection allGTXChecksForVersion:GTXVersionLatest
excludingChecksWithNames:excludedNames];
NSSet<NSString *> *actual = [self gtxtest_namesOfChecks:checks];
NSSet<NSString *> *expected = [self gtxtest_namesOfChecks:@[]];
XCTAssertEqualObjects(actual, expected);
}
- (void)testAllGTXChecksForVersionExcludingChecksWithNamesExclusionNotInChecks {
NSSet<NSString *> *excludedNames = [[NSSet alloc] initWithArray:@[ @"nonexistent name" ]];
XCTAssertThrows([GTXChecksCollection allGTXChecksForVersion:GTXVersionLatest
excludingChecksWithNames:excludedNames]);
}
- (void)testGtxCheckForAXLabelNotPunctuated {
// Valid label.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@"foo"]
errorDescription:nil];
// Empty label.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@""]
errorDescription:nil];
// nil label.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:nil]
errorDescription:nil];
// Label ending in period.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@"foo."]
errorDescription:kExpectedErrorDescription];
// Label ending in period with trailing space.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@"foo. "]
errorDescription:kExpectedErrorDescription];
// Single character label ending in period.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@"f."]
errorDescription:kExpectedErrorDescription];
// Single character label with just period.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@"."]
errorDescription:kExpectedErrorDescription];
// UILabel with text ending in period must pass.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
label.text = @"foo.";
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:label
errorDescription:kExpectedErrorDescription];
}
- (void)testGtxCheckForAXLabelNotPunctuatedWorksWithAttributedStrings {
id accessibilityLabel = [[NSAttributedString alloc] initWithString:@"foo"];
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:nil];
accessibilityLabel = [[NSAttributedString alloc] initWithString:@"foo."];
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:kExpectedErrorDescription];
}
- (void)testGtxCheckForAXLabelNotPunctuatedWorksWithMutableStrings {
id accessibilityLabel = [NSMutableString stringWithString:@"foo"];
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:nil];
accessibilityLabel = [NSMutableString stringWithString:@"foo."];
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:kExpectedErrorDescription];
}
- (void)testGtxCheckForAXLabelPresent {
NSString *const expectedErrorDescription = @"Check \"Accessibility label\" failed";
// Valid label.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@"foo"]
errorDescription:nil];
// Label with just space.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@" "]
errorDescription:expectedErrorDescription];
// Empty string label.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@""]
errorDescription:expectedErrorDescription];
// Element with no label.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithLabel:nil]
errorDescription:expectedErrorDescription];
}
- (void)testGtxCheckForAXLabelPresentWorksForTextElementsWithNotText {
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[[UILabel alloc] initWithFrame:CGRectZero]
errorDescription:nil];
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[[UITextField alloc] initWithFrame:CGRectZero]
errorDescription:nil];
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[[UITextView alloc] initWithFrame:CGRectZero]
errorDescription:nil];
UIAccessibilityElement *textElement = [self gtxtest_uiAccessibilityElementWithLabel:@""];
textElement.accessibilityTraits = UIAccessibilityTraitStaticText;
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:textElement
errorDescription:nil];
}
- (void)testGtxCheckForAXLabelPresentWorksForAccessibilityElementsContainedInUITextField {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectZero];
textField.text = @"foo";
for (id element in textField.accessibilityElements) {
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:element
errorDescription:nil];
}
}
- (void)testGtxCheckForAXLabelPresentWorksWithAttributedStrings {
id accessibilityLabel = [[NSAttributedString alloc] initWithString:@"foo"];
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:nil];
}
- (void)testGtxCheckForAXLabelPresentWorksWithMutableStrings {
id accessibilityLabel = [NSMutableString stringWithString:@"foo"];
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:nil];
}
- (void)testGtxCheckForAXLabelNotRedundantWithTraits {
// Label is not redundant with traits.
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self
gtxtest_uiAccessibilityElementWithLabel:@"foo"
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Label is redundant with traits (uppercase).
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:NO
withElement:[self
gtxtest_uiAccessibilityElementWithLabel:@"FOO BUTTON"
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Label is redundant with traits (lowercase).
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:NO
withElement:[self
gtxtest_uiAccessibilityElementWithLabel:@"foo button"
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Label is not redundant with traits (not suffix).
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self
gtxtest_uiAccessibilityElementWithLabel:@"button foo"
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Empty label (not redundant).
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self
gtxtest_uiAccessibilityElementWithLabel:@""
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Whitespace label (not redundant).
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self
gtxtest_uiAccessibilityElementWithLabel:@" "
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// No traits or violating label (not redundant).
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@"foo"]
errorDescription:nil];
// No traits (not redundant).
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithLabel:@"foo button"]
errorDescription:nil];
// Wrong traits (not redundant).
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:
[self gtxtest_uiAccessibilityElementWithLabel:@"foo button"
traits:UIAccessibilityTraitStaticText]
errorDescription:nil];
}
- (void)testGtxCheckForAXTraitsConflict {
NSString *const expectedErrorDescription = @"Check \"Accessibility traits\" failed";
// Check for a valid trait (in valid range, no conflict).
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXTraitDontConflict]
succeeds:YES
withElement:
[self gtxtest_uiAccessibilityElementWithTraits:UIAccessibilityTraitButton]
errorDescription:nil];
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXTraitDontConflict]
succeeds:YES
withElement:[self gtxtest_uiAccessibilityElementWithTraits:
(UIAccessibilityTraitLink | UIAccessibilityTraitAdjustable)]
errorDescription:nil];
// Check for conflict rule no.1 (conflict among button, link, search field, keyboard key).
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXTraitDontConflict]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithTraits:
(UIAccessibilityTraitKeyboardKey |
UIAccessibilityTraitSearchField)]
errorDescription:expectedErrorDescription];
// Check for conflict rule no.2 (conflict between button and adjustable (slider)).
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForAXTraitDontConflict]
succeeds:NO
withElement:[self gtxtest_uiAccessibilityElementWithTraits:
(UIAccessibilityTraitAdjustable |
UIAccessibilityTraitButton)]
errorDescription:expectedErrorDescription];
}
- (void)testGtxCheckForMinimumTappableArea {
NSString *accessibilityFrameErrorDescription = @"Element accessibilityFrame:";
NSString *frameErrorDescription = @"Element frame:";
CGFloat validSize = 64.0;
CGFloat invalidSize = 16.0;
CGRect validFrame = CGRectMake(0.0, 0.0, validSize, validSize);
CGRect invalidFrame = CGRectMake(0.0, 0.0, invalidSize, invalidSize);
CGRect validTouchableRect = CGRectMake(-validSize / 2.0, -validSize / 2.0, validSize, validSize);
CGRect invalidTouchableRect =
CGRectMake(-invalidSize / 2.0, -invalidSize / 2.0, invalidSize, invalidSize);
// accessibilityFrame
//
// width and height valid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:YES
withElement:[self gtxtest_tappableUIAccessibilityElementWithFrame:validFrame]
errorDescription:accessibilityFrameErrorDescription];
// width and height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableUIAccessibilityElementWithFrame:invalidFrame]
errorDescription:accessibilityFrameErrorDescription];
// width valid, height invalid.
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableUIAccessibilityElementWithFrame:CGRectMake(
0, 0,
validSize,
invalidSize)]
errorDescription:accessibilityFrameErrorDescription];
// width invalid, height valid.
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableUIAccessibilityElementWithFrame:CGRectMake(
0, 0,
invalidSize,
validSize)]
errorDescription:accessibilityFrameErrorDescription];
// frame
//
// width and height valid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:YES
withElement:[self gtxtest_tappableViewWithFrame:validFrame]
errorDescription:frameErrorDescription];
// width and height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:invalidFrame]
errorDescription:frameErrorDescription];
// width valid, height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:CGRectMake(0, 0, validSize,
invalidSize)]
errorDescription:frameErrorDescription];
// width invalid, height valid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:CGRectMake(0, 0, invalidSize,
validSize)]
errorDescription:frameErrorDescription];
// accessibilityFrame (frame always valid)
//
// width and height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:validFrame
accessibilityFrame:invalidFrame]
errorDescription:accessibilityFrameErrorDescription];
// width valid, height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:validFrame
accessibilityFrame:CGRectMake(0, 0, validSize,
invalidSize)]
errorDescription:accessibilityFrameErrorDescription];
// width invalid, height valid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:validFrame
accessibilityFrame:CGRectMake(0, 0, invalidSize,
validSize)]
errorDescription:accessibilityFrameErrorDescription];
// frame (accessibilityFrame always valid)
//
// width and height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:invalidFrame
accessibilityFrame:validFrame]
errorDescription:frameErrorDescription];
// width valid, height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:CGRectMake(0, 0, validSize,
invalidSize)
accessibilityFrame:validFrame]
errorDescription:frameErrorDescription];
// width invalid, height valid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:CGRectMake(0, 0, invalidSize,
validSize)
accessibilityFrame:validFrame]
errorDescription:frameErrorDescription];
// frame and accessibilityFrame both invalid
//
// width and height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:invalidFrame
accessibilityFrame:invalidFrame]
errorDescription:nil];
// width valid, height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:CGRectMake(0, 0, validSize,
invalidSize)
accessibilityFrame:CGRectMake(0, 0, validSize,
invalidSize)]
errorDescription:nil];
// width invalid, height valid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:CGRectMake(0, 0, invalidSize,
validSize)
accessibilityFrame:CGRectMake(0, 0, invalidSize,
validSize)]
errorDescription:nil];
// frame width valid, height invalid. accessibilityFrame width invalid, height valid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:CGRectMake(0, 0, validSize,
invalidSize)
accessibilityFrame:CGRectMake(0, 0, invalidSize,
validSize)]
errorDescription:nil];
// frame width invalid, height valid. accessibilityFrame width valid, height invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tappableViewWithFrame:CGRectMake(0, 0, invalidSize,
validSize)
accessibilityFrame:CGRectMake(0, 0, validSize,
invalidSize)]
errorDescription:nil];
// frame and accessibility frame invalid, pointInside:withEvent: valid.
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:YES
withElement:[self gtxtest_tabbableViewRespondingToTouchesInRect:validTouchableRect]
errorDescription:nil];
// frame, accessibility frame, and pointInside:withEvent: all invalid.
[self
gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self
gtxtest_tabbableViewRespondingToTouchesInRect:invalidTouchableRect]
errorDescription:nil];
// frame, accessibility frame, and pointInside:withEvent: all valid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:YES
withElement:[self gtxtest_tabbableViewRespondingToTouchesInRect:validFrame
frame:validFrame
accessibilityFrame:validFrame]
errorDescription:nil];
// frame, accessibility frame valid, but pointInside:withEvent: invalid.
[self gtxtest_assertGtxCheck:[GTXChecksCollection checkForMinimumTappableArea]
succeeds:NO
withElement:[self gtxtest_tabbableViewRespondingToTouchesInRect:invalidFrame
frame:validFrame
accessibilityFrame:validFrame]
errorDescription:nil];
}
- (void)testGtxCheckForSupportsDynamicType {
id<GTXChecking> dynamicTypeCheck = [GTXChecksCollection checkForSupportsDynamicType];
UIFont *fontFromPreferredFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
UIFont *fontFromFontWithName = [UIFont fontWithName:@"Arial" size:12.0];
NSArray<GTXTestDynamicTypeCheckOptions *> *options = @[
[[GTXTestDynamicTypeCheckOptions alloc] initWithFont:nil
adjustsFontForContentSizeCategory:NO
succeeds:NO],
[[GTXTestDynamicTypeCheckOptions alloc] initWithFont:nil
adjustsFontForContentSizeCategory:YES
succeeds:NO],
[[GTXTestDynamicTypeCheckOptions alloc] initWithFont:fontFromPreferredFont
adjustsFontForContentSizeCategory:NO
succeeds:NO],
[[GTXTestDynamicTypeCheckOptions alloc] initWithFont:fontFromPreferredFont
adjustsFontForContentSizeCategory:YES
succeeds:YES],
[[GTXTestDynamicTypeCheckOptions alloc] initWithFont:fontFromFontWithName
adjustsFontForContentSizeCategory:NO
succeeds:NO],
[[GTXTestDynamicTypeCheckOptions alloc] initWithFont:fontFromFontWithName
adjustsFontForContentSizeCategory:YES
succeeds:NO],
];
if (@available(iOS 11.0, *)) {
UIFont *fontFromMetrics = [[UIFontMetrics metricsForTextStyle:UIFontTextStyleBody]
scaledFontForFont:fontFromFontWithName];
options = [options arrayByAddingObjectsFromArray:@[
[[GTXTestDynamicTypeCheckOptions alloc] initWithFont:fontFromMetrics
adjustsFontForContentSizeCategory:NO
succeeds:NO],
[[GTXTestDynamicTypeCheckOptions alloc] initWithFont:fontFromMetrics
adjustsFontForContentSizeCategory:YES
succeeds:YES],
]];
}
for (GTXTestDynamicTypeCheckOptions *option in options) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 44)];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 44, 100, 44)];
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 88, 100, 44)];
label.adjustsFontForContentSizeCategory = option.adjustsFontForContentSizeCategory;
textField.adjustsFontForContentSizeCategory = option.adjustsFontForContentSizeCategory;
textView.adjustsFontForContentSizeCategory = option.adjustsFontForContentSizeCategory;
if (option.font != nil) {
label.font = option.font;
textField.font = option.font;
textView.font = option.font;
}
for (id element in @[ label, textField, textView ]) {
[self gtxtest_assertGtxCheck:dynamicTypeCheck
succeeds:option.succeeds
withElement:element
errorDescription:nil];
}
}
// Elements that don't implement font or adjustsFontForContentSizeCategory should be ignored, even
// if they have the static traits text.
UIAccessibilityElement *textElementWithoutProperties =
[self gtxtest_uiAccessibilityElementWithTraits:UIAccessibilityTraitStaticText];
[self gtxtest_assertGtxCheck:dynamicTypeCheck
succeeds:YES
withElement:textElementWithoutProperties
errorDescription:nil];
}
#pragma mark - Private
- (NSSet<NSString *> *)gtxtest_namesOfChecks:(NSArray<id<GTXChecking>> *)checks {
NSMutableSet<NSString *> *names = [[NSMutableSet alloc] init];
for (id<GTXChecking> check in checks) {
[names addObject:[check name]];
}
return names;
}
/**
* @return An accessibility element whose accessibility label is set to the specified @c label.
*/
- (UIAccessibilityElement *)gtxtest_uiAccessibilityElementWithLabel:(id)label {
NSAssert(!label || [label isKindOfClass:[NSString class]] ||
[label isKindOfClass:[NSAttributedString class]],
@"Provided label must be a NSString or NSAttributedString object.");
NSObject *container = [[NSObject alloc] init];
UIAccessibilityElement *element =
[[UIAccessibilityElement alloc] initWithAccessibilityContainer:container];
element.accessibilityLabel = label;
return element;
}
/**
* @return An accessibility element whose accessibility trait is set to the specified traits.
*/
- (UIAccessibilityElement *)gtxtest_uiAccessibilityElementWithTraits:(UIAccessibilityTraits)traits {
NSObject *container = [[NSObject alloc] init];
UIAccessibilityElement *element =
[[UIAccessibilityElement alloc] initWithAccessibilityContainer:container];
element.accessibilityTraits = traits;
return element;
}
/**
* @return An accessibility element whose accessibility label is set to the specified @c label
* and accessibility trait is set to the specified @c traits.
*/
- (UIAccessibilityElement *)gtxtest_uiAccessibilityElementWithLabel:(id)label
traits:(UIAccessibilityTraits)traits {
UIAccessibilityElement *element = [self gtxtest_uiAccessibilityElementWithLabel:label];
element.accessibilityTraits = traits;
return element;
}
/**
* @return An accessible and tappable view whose frame and accessibility frame are set to @c frame.
*/
- (UIView *)gtxtest_tappableViewWithFrame:(CGRect)frame {
UIView *view = [[UIView alloc] initWithFrame:frame];
view.isAccessibilityElement = YES;
view.accessibilityFrame = frame;
// The view must have UIAccessibilityTraitButton or else it cannot be tapped.
view.accessibilityTraits = UIAccessibilityTraitButton;
return view;
}
/**
* @return An accessible and tappable view whose frame is set to @c frame and accessibility frame
* is set to @c accessibilityFrame.
*/
- (UIView *)gtxtest_tappableViewWithFrame:(CGRect)frame
accessibilityFrame:(CGRect)accessibilityFrame {
UIView *view = [self gtxtest_tappableViewWithFrame:frame];
view.accessibilityFrame = accessibilityFrame;
return view;
}
/**
* @return An accessible and tappable view responding to touches in @c rect. @c frame and
* @c accessibilityFrame have size 0.
*/
- (UIView *)gtxtest_tabbableViewRespondingToTouchesInRect:(CGRect)rect {
CGRect centerRect = CGRectMake(CGRectGetMidX(rect), CGRectGetMidY(rect), 0, 0);
return [self gtxtest_tabbableViewRespondingToTouchesInRect:rect
frame:centerRect
accessibilityFrame:centerRect];
}
/**
* @return An accessible and tabbable view whose touchable region, frame, and accessibility frame
* are set to the given values.
*/
- (UIView *)gtxtest_tabbableViewRespondingToTouchesInRect:(CGRect)rect
frame:(CGRect)frame
accessibilityFrame:(CGRect)accessibilityFrame {
GTXTestDynamicTouchView *view = [[GTXTestDynamicTouchView alloc] initWithFrame:frame];
view.accessibilityFrame = accessibilityFrame;
view.isAccessibilityElement = YES;
view.accessibilityTraits = UIAccessibilityTraitButton;
view.touchableRect = rect;
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
[window addSubview:view];
return view;
}
/**
* @return A tappable accessibility element whose accessibility frame is set to @c frame.
*/
- (UIAccessibilityElement *)gtxtest_tappableUIAccessibilityElementWithFrame:(CGRect)frame {
// The element must have UIAccessibilityTraitButton or else it cannot be tapped.
UIAccessibilityElement *element =
[self gtxtest_uiAccessibilityElementWithTraits:UIAccessibilityTraitButton];
element.accessibilityFrame = frame;
return element;
}
/**
* Asserts that the given GTXCheck succeeds or fails with the specified element.
*
* @param check The check to be tested.
* @param expectedSuccess A BOOL indicating if the check must succeed or not.
* @param element The element on which to apply the check.
* @param descriptionOrNil An optional expected error description if the check is expected to fail
* and the error description must also be verified.
*/
- (void)gtxtest_assertGtxCheck:(id<GTXChecking>)gtxCheck
succeeds:(BOOL)expectedSuccess
withElement:(id)element
errorDescription:(nullable NSString *)descriptionOrNil {
NSError *error = nil;
BOOL success = [gtxCheck check:element error:&error];
XCTAssertEqual(success, expectedSuccess);
if (expectedSuccess) {
XCTAssertNil(error);
} else {
XCTAssertNotNil(error);
if (descriptionOrNil != nil) {
XCTAssertTrue([[error description] containsString:descriptionOrNil],
@"[Expected] was not present in [Actual]!\n Expected: %@\n Actual: %@",
descriptionOrNil, [error description]);
}
}
}
@end