blob: b209668535bbfd8a032e718c699cdd1e3d3bdf29 [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"
NSString * const kExpectedErrorDescription = @"Check \"Accessibility Label Not Punctuated\" failed";
@interface GTXChecksCollectionTests : XCTestCase
@end
@implementation GTXChecksCollectionTests
- (void)testGtxCheckForAXLabelNotPunctuated {
// Valid label.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@"foo"]
errorDescription:nil];
// Empty label.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@""]
errorDescription:nil];
// nil label.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:nil]
errorDescription:nil];
// Label ending in period.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:@"foo."]
errorDescription:kExpectedErrorDescription];
// Label ending in period with trailing space.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:@"foo. "]
errorDescription:kExpectedErrorDescription];
// Single character label ending in period.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:@"f."]
errorDescription:kExpectedErrorDescription];
// Single character label with just period.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self 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 assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:label
errorDescription:kExpectedErrorDescription];
}
- (void)testGtxCheckForAXLabelNotPunctuatedWorksWithAttributedStrings {
id accessibilityLabel = [[NSAttributedString alloc] initWithString:@"foo"];
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:nil];
accessibilityLabel = [[NSAttributedString alloc] initWithString:@"foo."];
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:kExpectedErrorDescription];
}
- (void)testGtxCheckForAXLabelNotPunctuatedWorksWithMutableStrings {
id accessibilityLabel = [NSMutableString stringWithString:@"foo"];
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:nil];
accessibilityLabel = [NSMutableString stringWithString:@"foo."];
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:kExpectedErrorDescription];
}
- (void)testGtxCheckForAXLabelPresent {
NSString * const expectedErrorDescription = @"Check \"Accessibility Label Present\" failed";
// Valid label.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@"foo"]
errorDescription:nil];
// Label with just space.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:@" "]
errorDescription:expectedErrorDescription];
// Empty string label.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:@""]
errorDescription:expectedErrorDescription];
// Element with no label.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:nil]
errorDescription:expectedErrorDescription];
}
- (void)testGtxCheckForAXLabelPresentWorksForTextElementsWithNotText {
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[[UILabel alloc] initWithFrame:CGRectZero]
errorDescription:nil];
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[[UITextField alloc] initWithFrame:CGRectZero]
errorDescription:nil];
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[[UITextView alloc] initWithFrame:CGRectZero]
errorDescription:nil];
UIAccessibilityElement *textElement = [self uiAccessibilityElementWithLabel:@""];
textElement.accessibilityTraits = UIAccessibilityTraitStaticText;
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:textElement
errorDescription:nil];
}
- (void)testGtxCheckForAXLabelPresentWorksWithAttributedStrings {
id accessibilityLabel = [[NSAttributedString alloc] initWithString:@"foo"];
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:nil];
}
- (void)testGtxCheckForAXLabelPresentWorksWithMutableStrings {
id accessibilityLabel = [NSMutableString stringWithString:@"foo"];
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelPresent]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:accessibilityLabel]
errorDescription:nil];
}
- (void)testGtxCheckForAXLabelNotRedundantWithTraits {
// Label is not redundant with traits.
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@"foo"
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Label is redundant with traits (uppercase).
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:@"FOO BUTTON"
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Label is redundant with traits (lowercase).
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:NO
withElement:[self uiAccessibilityElementWithLabel:@"foo button"
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Label is not redundant with traits (not suffix).
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@"button foo"
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Empty label (not redundant).
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@""
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// Whitespace label (not redundant).
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@" "
traits:UIAccessibilityTraitButton]
errorDescription:nil];
// No traits or violating label (not redundant).
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@"foo"]
errorDescription:nil];
// No traits (not redundant).
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@"foo button"]
errorDescription:nil];
// Wrong traits (not redundant).
[self assertGtxCheck:[GTXChecksCollection checkForAXLabelNotRedundantWithTraits]
succeeds:YES
withElement:[self uiAccessibilityElementWithLabel:@"foo button"
traits:UIAccessibilityTraitStaticText]
errorDescription:nil];
}
- (void)testGtxCheckForAXTraitsConflict {
NSString * const expectedErrorDescription =
@"Check \"Accessibility Traits Don't Conflict\" failed";
// Check for a valid trait (in valid range, no conflict).
[self assertGtxCheck:[GTXChecksCollection checkForAXTraitDontConflict]
succeeds:YES
withElement:[self uiAccessibilityElementWithTraits:UIAccessibilityTraitButton]
errorDescription:nil];
[self assertGtxCheck:[GTXChecksCollection checkForAXTraitDontConflict]
succeeds:YES
withElement:[self uiAccessibilityElementWithTraits:
(UIAccessibilityTraitLink | UIAccessibilityTraitAdjustable)]
errorDescription:nil];
// Check for conflict rule no.1 (conflict among button, link, search field, keyboard key).
[self assertGtxCheck:[GTXChecksCollection checkForAXTraitDontConflict]
succeeds:NO
withElement:[self uiAccessibilityElementWithTraits:
(UIAccessibilityTraitKeyboardKey | UIAccessibilityTraitSearchField)]
errorDescription:expectedErrorDescription];
// Check for conflict rule no.2 (conflict between button and adjustable (slider)).
[self assertGtxCheck:[GTXChecksCollection checkForAXTraitDontConflict]
succeeds:NO
withElement:[self uiAccessibilityElementWithTraits:
(UIAccessibilityTraitAdjustable | UIAccessibilityTraitButton)]
errorDescription:expectedErrorDescription];
}
#pragma mark - Private
/**
* @return An accessibility element whose accessibility label is set to the specified @c label.
*/
- (UIAccessibilityElement *)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 *)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 *)uiAccessibilityElementWithLabel:(id)label
traits:(UIAccessibilityTraits)traits {
UIAccessibilityElement *element = [self uiAccessibilityElementWithLabel:label];
element.accessibilityTraits = traits;
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)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