mirror of
https://github.com/material-components/material-components-ios.git
synced 2026-02-20 08:27:32 +08:00
1657 lines
58 KiB
Objective-C
1657 lines
58 KiB
Objective-C
// Copyright 2016-present the Material Components for iOS authors. All Rights Reserved.
|
|
//
|
|
// 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 <XCTest/XCTest.h>
|
|
|
|
#import "MaterialButtons.h"
|
|
#import "MaterialShadowElevations.h"
|
|
#import "MaterialShadowLayer.h"
|
|
#import "MaterialShapeLibrary.h"
|
|
#import "MaterialShapes.h"
|
|
#import "MaterialTypography.h"
|
|
|
|
static const CGFloat kEpsilonAccuracy = (CGFloat)0.001;
|
|
// A value greater than the largest value created by combining normal values of UIControlState.
|
|
// This is a complete hack, but UIControlState doesn't expose anything useful here.
|
|
// This assumes that UIControlState is actually a set of bitfields and ignores application-specific
|
|
// values.
|
|
static const UIControlState kNumUIControlStates = 2 * UIControlStateSelected - 1;
|
|
static const UIControlState kUIControlStateDisabledHighlighted =
|
|
UIControlStateHighlighted | UIControlStateDisabled;
|
|
|
|
static CGFloat randomNumber(void) { return arc4random_uniform(100) / (CGFloat)10; }
|
|
|
|
static CGFloat randomNumberNotEqualTo(const CGFloat targetNumber) {
|
|
while (1) {
|
|
CGFloat number = randomNumber();
|
|
if (number != targetNumber) {
|
|
return number;
|
|
}
|
|
}
|
|
}
|
|
|
|
static UIColor *randomColor(void) {
|
|
switch (arc4random_uniform(5)) {
|
|
case 0:
|
|
return [UIColor colorWithRed:1 green:1 blue:1 alpha:1];
|
|
break;
|
|
case 1:
|
|
return [UIColor colorWithRed:0 green:0 blue:0 alpha:1];
|
|
break;
|
|
case 2:
|
|
return [UIColor redColor];
|
|
break;
|
|
case 3:
|
|
return [UIColor orangeColor];
|
|
break;
|
|
case 4:
|
|
return [UIColor greenColor];
|
|
break;
|
|
default:
|
|
return [UIColor blueColor];
|
|
break;
|
|
}
|
|
}
|
|
|
|
static NSString *controlStateDescription(UIControlState controlState) {
|
|
if (controlState == UIControlStateNormal) {
|
|
return @"Normal";
|
|
}
|
|
NSMutableString *string = [NSMutableString string];
|
|
if ((UIControlStateHighlighted & controlState) == UIControlStateHighlighted) {
|
|
[string appendString:@"Highlighted "];
|
|
}
|
|
if ((UIControlStateDisabled & controlState) == UIControlStateDisabled) {
|
|
[string appendString:@"Disabled "];
|
|
}
|
|
if ((UIControlStateSelected & controlState) == UIControlStateSelected) {
|
|
[string appendString:@"Selected "];
|
|
}
|
|
return [string copy];
|
|
}
|
|
|
|
@interface FakeShadowLayer : MDCShapedShadowLayer
|
|
@property(nonatomic, assign) NSInteger elevationAssignmentCount;
|
|
@end
|
|
|
|
@implementation FakeShadowLayer
|
|
|
|
- (void)setElevation:(MDCShadowElevation)elevation {
|
|
++self.elevationAssignmentCount;
|
|
[super setElevation:elevation];
|
|
}
|
|
@end
|
|
|
|
@interface TestButton : MDCButton
|
|
@property(nonatomic, strong) FakeShadowLayer *shadowLayer;
|
|
@property(nonatomic, strong) UITraitCollection *traitCollectionOverride;
|
|
@end
|
|
|
|
@implementation TestButton
|
|
+ (Class)layerClass {
|
|
return [FakeShadowLayer class];
|
|
}
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame {
|
|
self = [super initWithFrame:frame];
|
|
if (self) {
|
|
_shadowLayer = (FakeShadowLayer *)self.layer;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (UITraitCollection *)traitCollection {
|
|
return self.traitCollectionOverride ?: [super traitCollection];
|
|
}
|
|
|
|
@end
|
|
|
|
@interface MDCButtonTests : XCTestCase
|
|
@property(nonatomic, strong, nullable) MDCButton *button;
|
|
@end
|
|
|
|
@implementation MDCButtonTests
|
|
|
|
- (void)setUp {
|
|
[super setUp];
|
|
|
|
self.button = [[MDCButton alloc] init];
|
|
}
|
|
|
|
- (void)tearDown {
|
|
self.button = nil;
|
|
|
|
[super tearDown];
|
|
}
|
|
|
|
- (void)testUppercaseTitleYes {
|
|
// Given
|
|
NSString *originalTitle = @"some Text";
|
|
|
|
// When
|
|
self.button.uppercaseTitle = YES;
|
|
[self.button setTitle:originalTitle forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.currentTitle,
|
|
[originalTitle uppercaseStringWithLocale:[NSLocale currentLocale]]);
|
|
}
|
|
|
|
- (void)testUppercaseAttributedTitleYes {
|
|
// Given
|
|
NSAttributedString *originalAttributedTitle =
|
|
[[NSAttributedString alloc] initWithString:@"some Text"];
|
|
|
|
// When
|
|
self.button.uppercaseTitle = YES;
|
|
[self.button setAttributedTitle:originalAttributedTitle forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
NSString *uppercaseString =
|
|
[originalAttributedTitle.string uppercaseStringWithLocale:[NSLocale currentLocale]];
|
|
NSAttributedString *uppercaseAttributedTitle =
|
|
[[NSAttributedString alloc] initWithString:uppercaseString];
|
|
XCTAssertEqualObjects(self.button.currentAttributedTitle, uppercaseAttributedTitle);
|
|
}
|
|
|
|
- (void)testUppercaseTitleNo {
|
|
// Given
|
|
NSString *originalTitle = @"some Text";
|
|
|
|
// When
|
|
self.button.uppercaseTitle = NO;
|
|
[self.button setTitle:originalTitle forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.currentTitle, originalTitle);
|
|
}
|
|
|
|
- (void)testUppercaseAttributedTitleNo {
|
|
// Given
|
|
NSAttributedString *originalAttributedTitle =
|
|
[[NSAttributedString alloc] initWithString:@"some Text"];
|
|
|
|
// When
|
|
self.button.uppercaseTitle = NO;
|
|
[self.button setAttributedTitle:originalAttributedTitle forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.currentAttributedTitle, originalAttributedTitle);
|
|
}
|
|
|
|
- (void)testUppercaseTitleNoChangedToYes {
|
|
// Given
|
|
NSString *originalTitle = @"some Text";
|
|
|
|
// When
|
|
self.button.uppercaseTitle = NO;
|
|
[self.button setTitle:originalTitle forState:UIControlStateNormal];
|
|
[self.button setTitle:originalTitle forState:UIControlStateHighlighted];
|
|
[self.button setTitle:originalTitle forState:UIControlStateDisabled];
|
|
self.button.uppercaseTitle = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.currentTitle,
|
|
[originalTitle uppercaseStringWithLocale:[NSLocale currentLocale]]);
|
|
}
|
|
|
|
- (void)testUppercaseAttributedTitleNoChangedToYes {
|
|
// Given
|
|
NSAttributedString *originalAttributedTitle =
|
|
[[NSAttributedString alloc] initWithString:@"some Text"];
|
|
|
|
// When
|
|
self.button.uppercaseTitle = NO;
|
|
[self.button setAttributedTitle:originalAttributedTitle forState:UIControlStateNormal];
|
|
[self.button setAttributedTitle:originalAttributedTitle forState:UIControlStateHighlighted];
|
|
[self.button setAttributedTitle:originalAttributedTitle forState:UIControlStateDisabled];
|
|
self.button.uppercaseTitle = YES;
|
|
|
|
// Then
|
|
NSString *uppercaseString =
|
|
[originalAttributedTitle.string uppercaseStringWithLocale:[NSLocale currentLocale]];
|
|
NSAttributedString *uppercaseAttributedTitle =
|
|
[[NSAttributedString alloc] initWithString:uppercaseString];
|
|
XCTAssertEqualObjects(self.button.currentAttributedTitle, uppercaseAttributedTitle);
|
|
}
|
|
|
|
- (void)testUppercaseTitleYesChangedToNo {
|
|
// Given
|
|
NSString *originalTitle = @"some Text";
|
|
|
|
// When
|
|
self.button.uppercaseTitle = YES;
|
|
[self.button setTitle:originalTitle forState:UIControlStateNormal];
|
|
[self.button setTitle:originalTitle forState:UIControlStateHighlighted];
|
|
[self.button setTitle:originalTitle forState:UIControlStateDisabled];
|
|
self.button.uppercaseTitle = NO;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.currentTitle, originalTitle);
|
|
}
|
|
|
|
- (void)testUppercaseAttributedTitleYesChangedToNo {
|
|
// Given
|
|
NSAttributedString *originalAttributedTitle =
|
|
[[NSAttributedString alloc] initWithString:@"some Text"];
|
|
|
|
// When
|
|
self.button.uppercaseTitle = YES;
|
|
[self.button setAttributedTitle:originalAttributedTitle forState:UIControlStateNormal];
|
|
[self.button setAttributedTitle:originalAttributedTitle forState:UIControlStateHighlighted];
|
|
[self.button setAttributedTitle:originalAttributedTitle forState:UIControlStateDisabled];
|
|
self.button.uppercaseTitle = NO;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.currentAttributedTitle, originalAttributedTitle);
|
|
}
|
|
|
|
- (void)testSetEnabledAnimated {
|
|
// Given
|
|
NSArray *boolValues = @[ @YES, @NO ];
|
|
for (id enabled in boolValues) {
|
|
for (id animated in boolValues) {
|
|
// When
|
|
[self.button setEnabled:[enabled boolValue] animated:[animated boolValue]];
|
|
|
|
// Then
|
|
XCTAssertEqual(self.button.enabled, [enabled boolValue]);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)testElevationForState {
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
// Given
|
|
CGFloat elevation = randomNumber();
|
|
|
|
// When
|
|
[self.button setElevation:elevation forState:controlState];
|
|
|
|
// Then
|
|
XCTAssertEqual([self.button elevationForState:controlState], elevation);
|
|
}
|
|
}
|
|
|
|
- (void)testSetElevationOnlyUpdatesCurrentState {
|
|
// Given
|
|
TestButton *selectedButton = [[TestButton alloc] init];
|
|
TestButton *highlightedButton = [[TestButton alloc] init];
|
|
|
|
XCTAssertEqualWithAccuracy([selectedButton elevationForState:UIControlStateNormal],
|
|
[selectedButton elevationForState:UIControlStateHighlighted], 0.0001,
|
|
@"This test assumes that .normal and .highlighted start with the same "
|
|
"elevation values.");
|
|
|
|
[selectedButton setSelected:YES];
|
|
[highlightedButton setHighlighted:YES];
|
|
NSInteger selectedButtonElevationCount = selectedButton.shadowLayer.elevationAssignmentCount;
|
|
NSInteger highlightedButtonElevationCount =
|
|
highlightedButton.shadowLayer.elevationAssignmentCount;
|
|
|
|
// When
|
|
[selectedButton setElevation:77 forState:UIControlStateHighlighted];
|
|
[highlightedButton setElevation:75 forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertEqual(selectedButton.shadowLayer.elevationAssignmentCount, selectedButtonElevationCount,
|
|
@"Updating an unrelated elevation should not update the layer elevation.");
|
|
XCTAssertEqual(highlightedButtonElevationCount + 1,
|
|
highlightedButton.shadowLayer.elevationAssignmentCount,
|
|
@"Updating the current elevation should cause one elevation update.");
|
|
}
|
|
|
|
- (void)testElevationNormal {
|
|
// Given
|
|
CGFloat normalElevation = randomNumberNotEqualTo(0);
|
|
|
|
// When
|
|
[self.button setElevation:normalElevation forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertEqual([self.button elevationForState:UIControlStateNormal], normalElevation);
|
|
XCTAssertEqual([self.button elevationForState:UIControlStateHighlighted], normalElevation);
|
|
XCTAssertEqual([self.button elevationForState:UIControlStateDisabled], normalElevation);
|
|
XCTAssertEqual([self.button elevationForState:UIControlStateSelected], normalElevation);
|
|
}
|
|
|
|
- (void)testElevationNormalZeroElevation {
|
|
// When
|
|
[self.button setElevation:0 forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertEqual([self.button elevationForState:UIControlStateNormal], 0);
|
|
}
|
|
|
|
- (void)testDefaultBorderWidth {
|
|
// Then
|
|
for (NSUInteger controlState = 0; controlState <= kNumUIControlStates; ++controlState) {
|
|
XCTAssertEqualWithAccuracy([self.button borderWidthForState:controlState], 0, 0.001);
|
|
}
|
|
}
|
|
|
|
- (void)testBorderWidthForStateWithDifferentValues {
|
|
for (NSUInteger controlState = 0; controlState <= kNumUIControlStates; ++controlState) {
|
|
// Given
|
|
CGFloat width = (CGFloat)controlState;
|
|
|
|
// When
|
|
[self.button setBorderWidth:width forState:controlState];
|
|
|
|
// Then
|
|
if (controlState == (UIControlStateHighlighted | UIControlStateDisabled)) {
|
|
XCTAssertEqualWithAccuracy([self.button borderWidthForState:controlState],
|
|
[self.button borderWidthForState:UIControlStateHighlighted],
|
|
0.001);
|
|
} else if (controlState ==
|
|
(UIControlStateHighlighted | UIControlStateDisabled | UIControlStateSelected)) {
|
|
XCTAssertNotEqualWithAccuracy([self.button borderWidthForState:controlState],
|
|
[self.button borderWidthForState:UIControlStateNormal], 0.001);
|
|
} else {
|
|
XCTAssertEqualWithAccuracy([self.button borderWidthForState:controlState], width, 0.001);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)testBorderWidthFallbackBehavior {
|
|
// Given
|
|
CGFloat fakeBorderWidth = 99;
|
|
|
|
// When
|
|
[self.button setBorderWidth:fakeBorderWidth forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
for (NSUInteger controlState = 0; controlState <= kNumUIControlStates; ++controlState) {
|
|
XCTAssertEqualWithAccuracy([self.button borderWidthForState:controlState], fakeBorderWidth,
|
|
0.001);
|
|
}
|
|
}
|
|
|
|
- (void)testBorderColorForState {
|
|
for (NSUInteger state = 0; state <= kNumUIControlStates; ++state) {
|
|
// Given
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
[self.button setBorderColor:color forState:state];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button borderColorForState:state], color);
|
|
}
|
|
}
|
|
|
|
- (void)testBorderColorForStateFallbackBehavior {
|
|
// When
|
|
[self.button setBorderColor:UIColor.redColor forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
for (NSUInteger state = 0; state <= kNumUIControlStates; ++state) {
|
|
XCTAssertEqualObjects([self.button borderColorForState:state], UIColor.redColor);
|
|
}
|
|
}
|
|
|
|
- (void)testBorderColorForStateBehaviorMatchesTitleColorForStateForward {
|
|
// Given
|
|
MDCButton *testButton = [[MDCButton alloc] init];
|
|
UIButton *uiButton = [[UIButton alloc] init];
|
|
|
|
// When
|
|
UIControlState maxState = UIControlStateNormal | UIControlStateHighlighted |
|
|
UIControlStateDisabled | UIControlStateSelected;
|
|
for (UIControlState state = 0; state <= maxState; ++state) {
|
|
UIColor *color = [UIColor colorWithWhite:0 alpha:(CGFloat)(state / (CGFloat)maxState)];
|
|
[testButton setBorderColor:color forState:state];
|
|
[uiButton setTitleColor:color forState:state];
|
|
}
|
|
|
|
// Then
|
|
for (UIControlState state = 0; state <= maxState; ++state) {
|
|
XCTAssertEqualObjects([testButton borderColorForState:state],
|
|
[uiButton titleColorForState:state], @" for state (%lu)",
|
|
(unsigned long)state);
|
|
}
|
|
}
|
|
|
|
- (void)testBorderColorForStateBehaviorMatchesTitleColorForStateBackward {
|
|
// Given
|
|
MDCButton *testButton = [[MDCButton alloc] init];
|
|
UIButton *uiButton = [[UIButton alloc] init];
|
|
|
|
// When
|
|
UIControlState maxState = UIControlStateNormal | UIControlStateHighlighted |
|
|
UIControlStateDisabled | UIControlStateSelected;
|
|
for (NSInteger state = maxState; state >= 0; --state) {
|
|
UIColor *color = [UIColor colorWithWhite:0 alpha:(CGFloat)(state / (CGFloat)maxState)];
|
|
[testButton setBorderColor:color forState:state];
|
|
[uiButton setTitleColor:color forState:state];
|
|
}
|
|
|
|
// Then
|
|
for (UIControlState state = 0; state <= maxState; ++state) {
|
|
XCTAssertEqualObjects([testButton borderColorForState:state],
|
|
[uiButton titleColorForState:state], @" for state (%lu)",
|
|
(unsigned long)state);
|
|
}
|
|
}
|
|
|
|
- (void)testBackgroundColorForState {
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
// Given
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
[self.button setBackgroundColor:color forState:controlState];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button backgroundColorForState:controlState], color);
|
|
}
|
|
}
|
|
|
|
- (void)testBackgroundColorForStateFallbackBehavior {
|
|
// When
|
|
[self.button setBackgroundColor:UIColor.purpleColor forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
XCTAssertEqualObjects([self.button backgroundColorForState:controlState], UIColor.purpleColor);
|
|
}
|
|
}
|
|
|
|
- (void)testBackgroundColorForStateUpdatesBackgroundColor {
|
|
// Given
|
|
for (NSUInteger controlState = 0; controlState <= kNumUIControlStates; ++controlState) {
|
|
// Disabling the button removes any highlighted state
|
|
UIControlState testState = controlState;
|
|
if ((testState & UIControlStateDisabled) == UIControlStateDisabled) {
|
|
testState &= ~UIControlStateHighlighted;
|
|
}
|
|
BOOL isDisabled = (testState & UIControlStateDisabled) == UIControlStateDisabled;
|
|
BOOL isSelected = (testState & UIControlStateSelected) == UIControlStateSelected;
|
|
BOOL isHighlighted = (testState & UIControlStateHighlighted) == UIControlStateHighlighted;
|
|
|
|
// Also given
|
|
UIColor *color = randomColor();
|
|
[self.button setBackgroundColor:color forState:testState];
|
|
|
|
// When
|
|
self.button.enabled = !isDisabled;
|
|
self.button.selected = isSelected;
|
|
self.button.highlighted = isHighlighted;
|
|
|
|
XCTAssertEqualObjects(self.button.backgroundColor, color, @"for state (%lu).",
|
|
(unsigned long)testState);
|
|
}
|
|
}
|
|
|
|
- (void)testBackgroundColorForStateUpdatesBackgroundColorWithFallback {
|
|
// Given
|
|
[self.button setBackgroundColor:UIColor.magentaColor forState:UIControlStateNormal];
|
|
|
|
for (NSUInteger controlState = 0; controlState <= kNumUIControlStates; ++controlState) {
|
|
BOOL isDisabled = (controlState & UIControlStateDisabled) == UIControlStateDisabled;
|
|
BOOL isSelected = (controlState & UIControlStateSelected) == UIControlStateSelected;
|
|
BOOL isHighlighted = (controlState & UIControlStateHighlighted) == UIControlStateHighlighted;
|
|
|
|
// When
|
|
self.button.enabled = !isDisabled;
|
|
self.button.selected = isSelected;
|
|
self.button.highlighted = isHighlighted;
|
|
|
|
XCTAssertEqualObjects(self.button.backgroundColor,
|
|
[self.button backgroundColorForState:UIControlStateNormal],
|
|
@"for state (%lu).", (unsigned long)controlState);
|
|
}
|
|
}
|
|
|
|
// Behavioral test to verify that MDCButton's `backgroundColor:forState:` matches the behavior of
|
|
// UIButton's `titleColor:forState:`. Specifically, to ensure that the special handling of
|
|
// (UIControlStateDisabled | UIControlStateHighlighted) is identical.
|
|
//
|
|
// This test is valuable because clients who are familiar with the fallback behavior of
|
|
// `titleColor:forState:` may be surprised if the MDCButton APIs don't match. For example, setting
|
|
// the titleColor for (UIControlStateDisabled | UIControlStateHighlighted) will actually update the
|
|
// value assigned for UIControlStateHighlighted, but ONLY if it has already been assigned. Otherwise
|
|
// no update will take place.
|
|
- (void)testBackgroundColorForStateBehaviorMatchesTitleColorForStateWithoutFallbackForward {
|
|
// Given
|
|
UIButton *uiButton = [[UIButton alloc] init];
|
|
|
|
// When
|
|
UIControlState maxState = UIControlStateNormal | UIControlStateHighlighted |
|
|
UIControlStateDisabled | UIControlStateSelected;
|
|
for (UIControlState state = 0; state <= maxState; ++state) {
|
|
UIColor *color = [UIColor colorWithWhite:0 alpha:(CGFloat)(state / (CGFloat)maxState)];
|
|
[self.button setBackgroundColor:color forState:state];
|
|
[uiButton setTitleColor:color forState:state];
|
|
}
|
|
|
|
// Then
|
|
for (UIControlState state = 0; state <= maxState; ++state) {
|
|
XCTAssertEqualObjects([self.button backgroundColorForState:state],
|
|
[uiButton titleColorForState:state], @" for state (%lu)",
|
|
(unsigned long)state);
|
|
}
|
|
}
|
|
|
|
- (void)testBackgroundColorForStateBehaviorMatchesTitleColorForStateWithoutFallbackBackward {
|
|
// Given
|
|
UIButton *uiButton = [[UIButton alloc] init];
|
|
|
|
// When
|
|
UIControlState maxState = UIControlStateNormal | UIControlStateHighlighted |
|
|
UIControlStateDisabled | UIControlStateSelected;
|
|
for (NSInteger state = maxState; state >= 0; --state) {
|
|
UIColor *color = [UIColor colorWithWhite:0 alpha:(CGFloat)(state / (CGFloat)maxState)];
|
|
[self.button setBackgroundColor:color forState:(UIControlState)state];
|
|
[uiButton setTitleColor:color forState:(UIControlState)state];
|
|
}
|
|
|
|
// Then
|
|
for (UIControlState state = 0; state <= maxState; ++state) {
|
|
XCTAssertEqualObjects([self.button backgroundColorForState:state],
|
|
[uiButton titleColorForState:state], @" for state (%lu)",
|
|
(unsigned long)state);
|
|
}
|
|
}
|
|
|
|
#pragma mark - titleFont:forState:
|
|
|
|
- (void)testTitleFontForState {
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
// Given
|
|
UIFont *randomFont = [UIFont systemFontOfSize:arc4random_uniform(100)];
|
|
|
|
// When
|
|
[self.button setTitleFont:randomFont forState:controlState];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button titleFontForState:controlState], randomFont);
|
|
}
|
|
}
|
|
|
|
- (void)testTitleFontForStateFallbackBehavior {
|
|
// Given
|
|
UIFont *fakeFont = [UIFont systemFontOfSize:25];
|
|
// When
|
|
[self.button setTitleFont:fakeFont forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
XCTAssertEqualObjects([self.button titleFontForState:controlState], fakeFont);
|
|
}
|
|
}
|
|
|
|
- (void)testTitleFontForStateFallbackBehaviorWithLegacyDynamicType {
|
|
// When
|
|
self.button.mdc_adjustsFontForContentSizeCategory = YES;
|
|
|
|
// Then
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
XCTAssertTrue(
|
|
[[self.button titleFontForState:controlState]
|
|
mdc_isSimplyEqual:[[MDCTypography buttonFont]
|
|
mdc_fontSizedForMaterialTextStyle:MDCFontTextStyleButton
|
|
scaledForDynamicType:YES]],
|
|
@"(%@) is not equal to (%@)", [self.button titleFontForState:UIControlStateNormal],
|
|
[[MDCTypography buttonFont] mdc_fontSizedForMaterialTextStyle:MDCFontTextStyleButton
|
|
scaledForDynamicType:YES]);
|
|
}
|
|
}
|
|
|
|
- (void)testTitleFontForStateWithLegacyDynamicTypeReturnsRenderedFonts {
|
|
// Given
|
|
UIFont *userFont = [UIFont systemFontOfSize:99];
|
|
[self.button setTitleFont:userFont forState:UIControlStateNormal];
|
|
|
|
// When
|
|
self.button.mdc_adjustsFontForContentSizeCategory = YES;
|
|
|
|
// Then
|
|
XCTAssertFalse([[self.button titleFontForState:UIControlStateNormal] mdc_isSimplyEqual:userFont],
|
|
@"(%@) is equal to (%@)", [self.button titleFontForState:UIControlStateNormal],
|
|
userFont);
|
|
XCTAssertFalse([self.button.titleLabel.font mdc_isSimplyEqual:userFont], @"(%@) is equal to (%@)",
|
|
self.button.titleLabel.font, userFont);
|
|
XCTAssertTrue([[self.button titleFontForState:UIControlStateNormal]
|
|
mdc_isSimplyEqual:self.button.titleLabel.font],
|
|
@"(%@) is not equal to (%@)", [self.button titleFontForState:UIControlStateNormal],
|
|
self.button.titleLabel.font);
|
|
}
|
|
|
|
- (void)testTitleFontForStateWithLegacyDynamicTypeRestoresUserFonts {
|
|
// Given
|
|
UIFont *userFont = [UIFont systemFontOfSize:99];
|
|
[self.button setTitleFont:userFont forState:UIControlStateNormal];
|
|
self.button.mdc_adjustsFontForContentSizeCategory = YES;
|
|
|
|
// When
|
|
self.button.mdc_adjustsFontForContentSizeCategory = NO;
|
|
|
|
// Then
|
|
XCTAssertTrue([[self.button titleFontForState:UIControlStateNormal] mdc_isSimplyEqual:userFont],
|
|
@"(%@) is not equal to (%@)", [self.button titleFontForState:UIControlStateNormal],
|
|
userFont);
|
|
XCTAssertTrue([self.button.titleLabel.font mdc_isSimplyEqual:userFont],
|
|
@"(%@) is not equal to (%@)", self.button.titleLabel.font, userFont);
|
|
XCTAssertTrue([[self.button titleFontForState:UIControlStateNormal]
|
|
mdc_isSimplyEqual:self.button.titleLabel.font],
|
|
@"(%@) is not equal to (%@)", [self.button titleFontForState:UIControlStateNormal],
|
|
self.button.titleLabel.font);
|
|
}
|
|
|
|
/**
|
|
Verifies that disabling the @c titleFont:forState: APIs after setting fonts preserves the
|
|
directly-assigned font on the button's @c titleLabel.
|
|
*/
|
|
- (void)testTitleFontForStateDisabledAfterSettingFontsPreventsFontChange {
|
|
// Given
|
|
UIFont *normalFont = [UIFont systemFontOfSize:10];
|
|
UIFont *selectedFont = [UIFont systemFontOfSize:40];
|
|
UIFont *directlyAssignedFont = [UIFont systemFontOfSize:25];
|
|
[self.button setTitleFont:normalFont forState:UIControlStateNormal];
|
|
[self.button setTitleFont:selectedFont forState:UIControlStateSelected];
|
|
|
|
// When
|
|
self.button.enableTitleFontForState = NO;
|
|
self.button.titleLabel.font = directlyAssignedFont;
|
|
self.button.selected = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.titleLabel.font, directlyAssignedFont);
|
|
}
|
|
|
|
/**
|
|
Verifies that disabling @c titleFont:forState: APIs before setting fonts preserves the
|
|
directly-assigned font on the button's @c titleLabel.
|
|
*/
|
|
- (void)testTitleFontForStateDisabledBeforeSettingFontsPreventsFontChange {
|
|
// Given
|
|
UIFont *normalFont = [UIFont systemFontOfSize:10];
|
|
UIFont *selectedFont = [UIFont systemFontOfSize:40];
|
|
UIFont *directlyAssignedFont = [UIFont systemFontOfSize:25];
|
|
self.button.enableTitleFontForState = NO;
|
|
self.button.titleLabel.font = directlyAssignedFont;
|
|
|
|
// When
|
|
[self.button setTitleFont:normalFont forState:UIControlStateNormal];
|
|
[self.button setTitleFont:selectedFont forState:UIControlStateSelected];
|
|
self.button.selected = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.titleLabel.font, directlyAssignedFont);
|
|
}
|
|
|
|
/**
|
|
Verifies that after enabling @c titleFont:forState: APIs, that @c titleLabel.font will be
|
|
replaced by the next time the state is changed.
|
|
*/
|
|
- (void)testTitleFontForStateReenabledUpdatesFontsOnNextStateChange {
|
|
// Given
|
|
UIFont *normalFont = [UIFont systemFontOfSize:10];
|
|
UIFont *selectedFont = [UIFont systemFontOfSize:40];
|
|
UIFont *directlyAssignedFont = [UIFont systemFontOfSize:25];
|
|
self.button.enableTitleFontForState = NO;
|
|
[self.button setTitleFont:normalFont forState:UIControlStateNormal];
|
|
[self.button setTitleFont:selectedFont forState:UIControlStateSelected];
|
|
self.button.titleLabel.font = directlyAssignedFont;
|
|
self.button.selected = YES;
|
|
|
|
// When
|
|
self.button.enableTitleFontForState = YES;
|
|
self.button.selected = NO;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.titleLabel.font, normalFont);
|
|
}
|
|
|
|
#pragma mark - shadowColor:forState:
|
|
|
|
- (void)testRemovedShadowColorForState {
|
|
// When
|
|
[self.button setShadowColor:nil forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertNil([self.button shadowColorForState:UIControlStateNormal]);
|
|
XCTAssertNil([self.button shadowColorForState:UIControlStateHighlighted]);
|
|
}
|
|
|
|
- (void)testDefaultShadowColorForState {
|
|
// Then
|
|
XCTAssertNotNil([self.button shadowColorForState:UIControlStateSelected]);
|
|
}
|
|
|
|
- (void)testShadowColorForUnspecifiedStateEqualsNormalState {
|
|
// Given
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
[self.button setShadowColor:color forState:UIControlStateNormal];
|
|
|
|
XCTAssertEqual([self.button shadowColorForState:UIControlStateHighlighted], color);
|
|
}
|
|
|
|
- (void)testShadowColorForState {
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
// Given
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
[self.button setShadowColor:color forState:controlState];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button shadowColorForState:controlState], color);
|
|
}
|
|
}
|
|
|
|
- (void)testLayerShadowColorForState {
|
|
for (NSUInteger controlState = 0; controlState <= kNumUIControlStates; ++controlState) {
|
|
// Given
|
|
NSUInteger effectiveControlState = controlState;
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
[self.button setShadowColor:color forState:controlState];
|
|
if ((effectiveControlState & UIControlStateHighlighted) == UIControlStateHighlighted) {
|
|
self.button.highlighted = YES;
|
|
} else {
|
|
self.button.highlighted = NO;
|
|
}
|
|
|
|
if ((effectiveControlState & UIControlStateDisabled) == UIControlStateDisabled) {
|
|
self.button.enabled = NO;
|
|
// Disabling a button turns off "highlighted"
|
|
effectiveControlState = (effectiveControlState & ~UIControlStateHighlighted);
|
|
} else {
|
|
self.button.enabled = YES;
|
|
}
|
|
|
|
if ((effectiveControlState & UIControlStateSelected) == UIControlStateSelected) {
|
|
self.button.selected = YES;
|
|
} else {
|
|
self.button.selected = NO;
|
|
}
|
|
|
|
// Then
|
|
UIColor *layerShadowColor = [UIColor colorWithCGColor:self.button.layer.shadowColor];
|
|
XCTAssertEqualObjects([self.button shadowColorForState:effectiveControlState],
|
|
layerShadowColor);
|
|
}
|
|
}
|
|
|
|
#pragma mark - imageTintColor:forState:
|
|
|
|
- (void)testRemovedImageTintColorForState {
|
|
// When
|
|
[self.button setImageTintColor:nil forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertNil([self.button imageTintColorForState:UIControlStateNormal]);
|
|
XCTAssertNil([self.button imageTintColorForState:UIControlStateHighlighted]);
|
|
}
|
|
|
|
- (void)testDefaultImageTintColorForState {
|
|
// Then
|
|
XCTAssertNil([self.button imageTintColorForState:UIControlStateSelected]);
|
|
}
|
|
|
|
- (void)testImageTintForUnspecifiedStateEqualsNormalState {
|
|
// Given
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
[self.button setImageTintColor:color forState:UIControlStateNormal];
|
|
|
|
XCTAssertEqual([self.button imageTintColorForState:UIControlStateHighlighted], color);
|
|
}
|
|
|
|
- (void)testImageTintColorForState {
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
// Given
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
[self.button setImageTintColor:color forState:controlState];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button imageTintColorForState:controlState], color);
|
|
}
|
|
}
|
|
|
|
- (void)testImageTintColorForStateFallsBackToDefault {
|
|
// Given
|
|
UIColor *normalTint = [UIColor yellowColor];
|
|
UIColor *selectedTint = [UIColor redColor];
|
|
|
|
// When
|
|
[self.button setImageTintColor:normalTint forState:UIControlStateNormal];
|
|
[self.button setImageTintColor:selectedTint forState:UIControlStateSelected];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button imageTintColorForState:UIControlStateNormal], normalTint);
|
|
XCTAssertEqualObjects([self.button imageTintColorForState:UIControlStateSelected], selectedTint);
|
|
XCTAssertEqualObjects([self.button imageTintColorForState:UIControlStateHighlighted], normalTint);
|
|
}
|
|
|
|
- (void)testImageTintColorForStateSetsImageViewTintColor {
|
|
// Given
|
|
UIColor *normalTint = [UIColor yellowColor];
|
|
UIColor *selectedTint = [UIColor redColor];
|
|
|
|
// When
|
|
[self.button setImageTintColor:normalTint forState:UIControlStateNormal];
|
|
[self.button setImageTintColor:selectedTint forState:UIControlStateSelected];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.imageView.tintColor, normalTint);
|
|
|
|
// When
|
|
self.button.selected = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.imageView.tintColor, selectedTint);
|
|
}
|
|
|
|
#pragma mark - backgroundColor:forState:
|
|
|
|
- (void)testCurrentBackgroundColorNormal {
|
|
// Given
|
|
UIColor *normalColor = [UIColor redColor];
|
|
[self.button setBackgroundColor:normalColor forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button backgroundColor], normalColor);
|
|
}
|
|
|
|
- (void)testCurrentBackgroundColorHighlighted {
|
|
// Given
|
|
UIColor *normalColor = [UIColor redColor];
|
|
UIColor *color = [UIColor orangeColor];
|
|
[self.button setBackgroundColor:normalColor forState:UIControlStateNormal];
|
|
[self.button setBackgroundColor:color forState:UIControlStateHighlighted];
|
|
|
|
// When
|
|
self.button.highlighted = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button backgroundColor], color);
|
|
}
|
|
|
|
- (void)testCurrentBackgroundColorDisabled {
|
|
// Given
|
|
UIColor *normalColor = [UIColor redColor];
|
|
UIColor *color = [UIColor orangeColor];
|
|
[self.button setBackgroundColor:normalColor forState:UIControlStateNormal];
|
|
[self.button setBackgroundColor:color forState:UIControlStateDisabled];
|
|
|
|
// When
|
|
self.button.enabled = NO;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button backgroundColor], color);
|
|
}
|
|
|
|
- (void)testCurrentBackgroundColorSelected {
|
|
// Given
|
|
UIColor *normalColor = [UIColor redColor];
|
|
UIColor *color = [UIColor orangeColor];
|
|
[self.button setBackgroundColor:normalColor forState:UIControlStateNormal];
|
|
[self.button setBackgroundColor:color forState:UIControlStateSelected];
|
|
|
|
// When
|
|
self.button.selected = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button backgroundColor], color);
|
|
}
|
|
|
|
#pragma mark - elevation:forState:
|
|
|
|
- (void)testCurrentElevationNormal {
|
|
// Given
|
|
CGFloat normalElevation = 10;
|
|
[self.button setElevation:normalElevation forState:UIControlStateNormal];
|
|
|
|
// Then
|
|
XCTAssertEqualWithAccuracy([self.button elevationForState:self.button.state], normalElevation,
|
|
kEpsilonAccuracy);
|
|
}
|
|
|
|
- (void)testCurrentElevationHighlighted {
|
|
// Given
|
|
CGFloat normalElevation = 10;
|
|
CGFloat elevation = 40;
|
|
[self.button setElevation:normalElevation forState:UIControlStateNormal];
|
|
[self.button setElevation:elevation forState:UIControlStateHighlighted];
|
|
|
|
// When
|
|
self.button.highlighted = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualWithAccuracy([self.button elevationForState:self.button.state], elevation,
|
|
kEpsilonAccuracy);
|
|
}
|
|
|
|
- (void)testCurrentElevationDisabled {
|
|
// Given
|
|
CGFloat normalElevation = 10;
|
|
CGFloat elevation = 40;
|
|
[self.button setElevation:normalElevation forState:UIControlStateNormal];
|
|
[self.button setElevation:elevation forState:UIControlStateDisabled];
|
|
|
|
// When
|
|
self.button.enabled = NO;
|
|
|
|
// Then
|
|
XCTAssertEqualWithAccuracy([self.button elevationForState:self.button.state], elevation,
|
|
kEpsilonAccuracy);
|
|
}
|
|
|
|
- (void)testCurrentElevationSelected {
|
|
// Given
|
|
CGFloat normalElevation = 10;
|
|
CGFloat elevation = 40;
|
|
[self.button setElevation:normalElevation forState:UIControlStateNormal];
|
|
[self.button setElevation:elevation forState:UIControlStateSelected];
|
|
|
|
// When
|
|
self.button.selected = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualWithAccuracy([self.button elevationForState:self.button.state], elevation,
|
|
kEpsilonAccuracy);
|
|
}
|
|
|
|
#pragma mark - Ink Color
|
|
|
|
- (void)testInkColors {
|
|
// Given
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
self.button.inkColor = color;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.inkColor, color);
|
|
}
|
|
|
|
- (void)testRippleColors {
|
|
// Given
|
|
UIColor *color = randomColor();
|
|
|
|
// When
|
|
self.button.rippleColor = color;
|
|
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.rippleColor, color);
|
|
}
|
|
|
|
/*
|
|
TODO: things to unit test
|
|
(should these even be a thing?)
|
|
- hitAreaInset
|
|
- underlyingColor (text color)
|
|
*/
|
|
|
|
- (void)testPointInsideWithoutHitAreaInsets {
|
|
// Given
|
|
self.button.frame = CGRectMake(0, 0, 80, 50);
|
|
|
|
CGPoint touchPointInsideBoundsTopLeft = CGPointMake(0, 0);
|
|
CGPoint touchPointInsideBoundsTopRight = CGPointMake((CGFloat)79.9, 0);
|
|
CGPoint touchPointInsideBoundsBottomRight = CGPointMake((CGFloat)79.9, (CGFloat)49.9);
|
|
CGPoint touchPointInsideBoundsBottomLeft = CGPointMake(0, (CGFloat)49.9);
|
|
|
|
CGPoint touchPointOutsideBoundsTopLeft = CGPointMake(0, (CGFloat)-0.1);
|
|
CGPoint touchPointOutsideBoundsTopRight = CGPointMake(80, 0);
|
|
CGPoint touchPointOutsideBoundsBottomRight = CGPointMake(80, 50);
|
|
CGPoint touchPointOutsideBoundsBottomLeft = CGPointMake(0, 50);
|
|
|
|
// Then
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideBoundsTopLeft withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideBoundsTopRight withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideBoundsBottomRight withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideBoundsBottomLeft withEvent:nil]);
|
|
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideBoundsTopLeft withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideBoundsTopRight withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideBoundsBottomRight withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideBoundsBottomLeft withEvent:nil]);
|
|
}
|
|
|
|
- (void)testPointInsideWithoutHitAreaInsetsTooSmall {
|
|
// Given
|
|
self.button.frame = CGRectMake(0, 0, 10, 10);
|
|
|
|
CGPoint touchPointInsideBoundsTopLeft = CGPointMake(0, 0);
|
|
CGPoint touchPointInsideBoundsTopRight = CGPointMake((CGFloat)9.9, 0);
|
|
CGPoint touchPointInsideBoundsBottomRight = CGPointMake((CGFloat)9.9, (CGFloat)9.9);
|
|
CGPoint touchPointInsideBoundsBottomLeft = CGPointMake(0, (CGFloat)9.9);
|
|
|
|
CGPoint touchPointOutsideBoundsTopLeft = CGPointMake(0, (CGFloat)-0.1);
|
|
CGPoint touchPointOutsideBoundsTopRight = CGPointMake(10, 0);
|
|
CGPoint touchPointOutsideBoundsBottomRight = CGPointMake(10, 10);
|
|
CGPoint touchPointOutsideBoundsBottomLeft = CGPointMake(0, 10);
|
|
|
|
// Then
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideBoundsTopLeft withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideBoundsTopRight withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideBoundsBottomRight withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideBoundsBottomLeft withEvent:nil]);
|
|
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideBoundsTopLeft withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideBoundsTopRight withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideBoundsBottomRight withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideBoundsBottomLeft withEvent:nil]);
|
|
}
|
|
|
|
- (void)testPointInsideWithCustomHitAreaInsets {
|
|
// Given
|
|
self.button.frame = CGRectMake(0, 0, 10, 10);
|
|
|
|
CGPoint touchPointInsideHitAreaTopLeft = CGPointMake(-5, -5);
|
|
CGPoint touchPointInsideHitAreaTopRight = CGPointMake(-5, (CGFloat)14.9);
|
|
CGPoint touchPointInsideHitAreaBottomRight = CGPointMake((CGFloat)14.9, (CGFloat)14.9);
|
|
CGPoint touchPointInsideHitAreaBottomLeft = CGPointMake((CGFloat)14.9, -5);
|
|
|
|
CGPoint touchPointOutsideHitAreaTopLeft = CGPointMake((CGFloat)-5.1, -5);
|
|
CGPoint touchPointOutsideHitAreaTopRight = CGPointMake(-5, 15);
|
|
CGPoint touchPointOutsideHitAreaBottomRight = CGPointMake(15, 15);
|
|
CGPoint touchPointOutsideHitAreaBottomLeft = CGPointMake(15, -5);
|
|
|
|
// When
|
|
self.button.hitAreaInsets = UIEdgeInsetsMake(-5, -5, -5, -5);
|
|
|
|
// Then
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideHitAreaTopLeft withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideHitAreaTopRight withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideHitAreaBottomRight withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideHitAreaBottomLeft withEvent:nil]);
|
|
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideHitAreaTopLeft withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideHitAreaTopRight withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideHitAreaBottomRight withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideHitAreaBottomLeft withEvent:nil]);
|
|
}
|
|
|
|
- (void)testPointInsideWithNonStandardizedBounds {
|
|
// Given
|
|
// This is (-10, -10, 20, 20) in standardized form
|
|
CGRect bounds = CGRectMake(10, 10, -20, -20);
|
|
// Once applied, these insets should increase the hitArea to (-15, -20, 30, 40)
|
|
UIEdgeInsets insets = UIEdgeInsetsMake(-10, -5, -10, -5);
|
|
|
|
CGPoint touchPointInsideHitAreaTopLeft = CGPointMake(-15, -20);
|
|
CGPoint touchPointInsideHitAreaTopRight = CGPointMake((CGFloat)14.9, -20);
|
|
CGPoint touchPointInsideHitAreaBottomRight = CGPointMake((CGFloat)14.9, (CGFloat)19.9);
|
|
CGPoint touchPointInsideHitAreaBottomLeft = CGPointMake(-15, (CGFloat)19.9);
|
|
|
|
CGPoint touchPointOutsideHitAreaTopLeft = CGPointMake((CGFloat)-15.1, -20);
|
|
CGPoint touchPointOutsideHitAreaTopRight = CGPointMake(20, -20);
|
|
CGPoint touchPointOutsideHitAreaBottomRight = CGPointMake(15, 20);
|
|
CGPoint touchPointOutsideHitAreaBottomLeft = CGPointMake(-15, 20);
|
|
|
|
// When
|
|
self.button.bounds = bounds;
|
|
self.button.hitAreaInsets = insets;
|
|
|
|
// Then
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideHitAreaTopLeft withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideHitAreaTopRight withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideHitAreaBottomRight withEvent:nil]);
|
|
XCTAssertTrue([self.button pointInside:touchPointInsideHitAreaBottomLeft withEvent:nil]);
|
|
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideHitAreaTopLeft withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideHitAreaTopRight withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideHitAreaBottomRight withEvent:nil]);
|
|
XCTAssertFalse([self.button pointInside:touchPointOutsideHitAreaBottomLeft withEvent:nil]);
|
|
}
|
|
|
|
#pragma mark - UIButton strangeness
|
|
|
|
- (void)testTitleColorForState {
|
|
for (NSUInteger controlState = 0; controlState < kNumUIControlStates; ++controlState) {
|
|
if (controlState & kUIControlStateDisabledHighlighted) {
|
|
// We skip the Disabled Highlighted state because UIButton titleColorForState ignores it.
|
|
continue;
|
|
}
|
|
// Given
|
|
UIColor *color = [UIColor blueColor];
|
|
|
|
// When
|
|
[self.button setTitleColor:color forState:controlState];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button titleColorForState:controlState], color,
|
|
@"for control state:%@ ", controlStateDescription(controlState));
|
|
}
|
|
}
|
|
- (void)testTitleColorForStateDisabledHighlight {
|
|
// This is strange that setting the color for a state does not return the value of that state.
|
|
// It turns out that it returns the value set to the normal state.
|
|
|
|
// Given
|
|
UIControlState controlState = kUIControlStateDisabledHighlighted;
|
|
UIColor *color = [UIColor blueColor];
|
|
UIColor *normalColor = [UIColor greenColor];
|
|
[self.button setTitleColor:normalColor forState:UIControlStateNormal];
|
|
|
|
// When
|
|
[self.button setTitleColor:color forState:controlState];
|
|
|
|
// Then
|
|
XCTAssertEqualObjects([self.button titleColorForState:controlState], normalColor,
|
|
@"for control state:%@ ", controlStateDescription(controlState));
|
|
XCTAssertNotEqualObjects([self.button titleColorForState:controlState], color,
|
|
@"for control state:%@ ", controlStateDescription(controlState));
|
|
}
|
|
|
|
#pragma mark - UIButton state changes
|
|
|
|
- (void)testEnabled {
|
|
// Given
|
|
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
button.highlighted = (BOOL)arc4random_uniform(2);
|
|
button.selected = (BOOL)arc4random_uniform(2);
|
|
button.enabled = (BOOL)arc4random_uniform(2);
|
|
|
|
// When
|
|
button.enabled = YES;
|
|
|
|
// Then
|
|
XCTAssertTrue(button.enabled);
|
|
XCTAssertFalse(button.state & UIControlStateDisabled);
|
|
}
|
|
|
|
- (void)testDisabled {
|
|
// Given
|
|
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
button.highlighted = (BOOL)arc4random_uniform(2);
|
|
button.selected = (BOOL)arc4random_uniform(2);
|
|
button.enabled = (BOOL)arc4random_uniform(2);
|
|
|
|
// When
|
|
button.enabled = NO;
|
|
|
|
// Then
|
|
XCTAssertFalse(button.enabled);
|
|
XCTAssertTrue(button.state & UIControlStateDisabled);
|
|
}
|
|
|
|
- (void)testHighlighted {
|
|
// Given
|
|
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
button.highlighted = NO;
|
|
button.selected = (BOOL)arc4random_uniform(2);
|
|
|
|
// For some reason we can only set the highlighted state to YES if its enabled is also YES.
|
|
button.enabled = YES;
|
|
|
|
UIControlState oldState = button.state;
|
|
XCTAssertFalse(button.highlighted);
|
|
|
|
// When
|
|
button.highlighted = YES;
|
|
|
|
// Then
|
|
XCTAssertTrue(button.highlighted);
|
|
XCTAssertTrue(button.state & UIControlStateHighlighted);
|
|
XCTAssertEqual(button.state, (oldState | UIControlStateHighlighted));
|
|
}
|
|
|
|
- (void)testUnhighlighted {
|
|
// Given
|
|
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
button.highlighted = YES;
|
|
button.selected = (BOOL)arc4random_uniform(2);
|
|
button.enabled = (BOOL)arc4random_uniform(2);
|
|
UIControlState oldState = button.state;
|
|
XCTAssertTrue(button.highlighted);
|
|
|
|
// When
|
|
button.highlighted = NO;
|
|
|
|
// Then
|
|
XCTAssertFalse(button.highlighted);
|
|
XCTAssertFalse(button.state & UIControlStateHighlighted);
|
|
XCTAssertEqual(button.state, (oldState & ~UIControlStateHighlighted));
|
|
}
|
|
|
|
- (void)testSelected {
|
|
// Given
|
|
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
button.highlighted = (BOOL)arc4random_uniform(2);
|
|
button.selected = NO;
|
|
button.enabled = (BOOL)arc4random_uniform(2);
|
|
UIControlState oldState = button.state;
|
|
|
|
// When
|
|
button.selected = YES;
|
|
|
|
// Then
|
|
XCTAssertTrue(button.selected);
|
|
XCTAssertTrue(button.state & UIControlStateSelected);
|
|
XCTAssertEqual(button.state, (oldState | UIControlStateSelected));
|
|
}
|
|
|
|
- (void)testUnselected {
|
|
// Given
|
|
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
button.highlighted = (BOOL)arc4random_uniform(2);
|
|
button.selected = YES;
|
|
button.enabled = (BOOL)arc4random_uniform(2);
|
|
|
|
// When
|
|
button.selected = NO;
|
|
|
|
// Then
|
|
XCTAssertFalse(button.selected);
|
|
XCTAssertFalse(button.state & UIControlStateSelected);
|
|
}
|
|
|
|
- (void)testDefaultFont {
|
|
// Then
|
|
XCTAssertEqualObjects(self.button.titleLabel.font, [MDCTypography buttonFont]);
|
|
}
|
|
|
|
- (void)testDefaultAdjustsFontProperty {
|
|
// Then
|
|
XCTAssertFalse(self.button.mdc_adjustsFontForContentSizeCategory);
|
|
}
|
|
|
|
- (void)testAdjustsFontProperty {
|
|
UIFont *preferredFont = [UIFont mdc_preferredFontForMaterialTextStyle:MDCFontTextStyleButton];
|
|
|
|
// When
|
|
self.button.mdc_adjustsFontForContentSizeCategory = YES;
|
|
|
|
// Then
|
|
XCTAssertTrue(self.button.mdc_adjustsFontForContentSizeCategory);
|
|
XCTAssertEqualWithAccuracy(self.button.titleLabel.font.pointSize, preferredFont.pointSize,
|
|
kEpsilonAccuracy,
|
|
@"Font size should be equal to MDCFontTextStyleButton's.");
|
|
}
|
|
|
|
/**
|
|
Test legacy dynamic type impacts a @c MDCButton when @c
|
|
mdc_adjustsFontForContentSizeCategory is set to @c YES that the font changes.
|
|
*/
|
|
- (void)testLegacyDynamicTypeEnabled {
|
|
// Given
|
|
UIFont *fakeFont = [UIFont systemFontOfSize:55];
|
|
[self.button setTitleFont:fakeFont forState:UIControlStateNormal];
|
|
UIFont *originalFont = self.button.titleLabel.font;
|
|
self.button.mdc_adjustsFontForContentSizeCategory = YES;
|
|
|
|
// Then
|
|
XCTAssertFalse([self.button.titleLabel.font mdc_isSimplyEqual:originalFont], @"%@ is equal to %@",
|
|
self.button.titleLabel.font, originalFont);
|
|
}
|
|
|
|
#pragma mark - Size-related tests
|
|
|
|
- (void)testSizeThatFitsWithMinimumOnly {
|
|
// Given
|
|
[self.button sizeToFit];
|
|
CGRect expectedFrame = CGRectMake(0, 0, CGRectGetWidth(self.button.frame) + 15,
|
|
CGRectGetHeight(self.button.frame) + 21);
|
|
|
|
// When
|
|
self.button.minimumSize = expectedFrame.size;
|
|
[self.button sizeToFit];
|
|
|
|
// Then
|
|
XCTAssertTrue(CGRectEqualToRect(expectedFrame, self.button.frame), @"\nE: %@\nA: %@",
|
|
NSStringFromCGRect(expectedFrame), NSStringFromCGRect(self.button.frame));
|
|
}
|
|
|
|
- (void)testSizeThatFitsWithMaximumOnly {
|
|
// Given
|
|
[self.button sizeToFit];
|
|
CGRect expectedFrame = CGRectMake(0, 0, CGRectGetWidth(self.button.frame) - 7,
|
|
CGRectGetHeight(self.button.frame) - 3);
|
|
|
|
// When
|
|
self.button.maximumSize = expectedFrame.size;
|
|
[self.button sizeToFit];
|
|
|
|
// Then
|
|
XCTAssertTrue(CGRectEqualToRect(expectedFrame, self.button.frame), @"\nE: %@\nA: %@",
|
|
NSStringFromCGRect(expectedFrame), NSStringFromCGRect(self.button.frame));
|
|
}
|
|
|
|
- (void)testSizeThatFitsWithMinimumAndMaximum {
|
|
// Given
|
|
[self.button sizeToFit];
|
|
CGRect expectedFrame = CGRectMake(0, 0, CGRectGetWidth(self.button.frame) + 21,
|
|
CGRectGetHeight(self.button.frame) - 4);
|
|
|
|
// When
|
|
self.button.maximumSize = CGSizeMake(0, CGRectGetHeight(expectedFrame)); // Only bound max height
|
|
self.button.minimumSize = CGSizeMake(CGRectGetWidth(expectedFrame), 0); // Only bound min width
|
|
[self.button sizeToFit];
|
|
|
|
// Then
|
|
XCTAssertTrue(CGRectEqualToRect(expectedFrame, self.button.frame), @"\nE: %@\nA: %@",
|
|
NSStringFromCGRect(expectedFrame), NSStringFromCGRect(self.button.frame));
|
|
}
|
|
|
|
- (void)testIntrinsicContentSizeWithMinimumSizeIncreasesSize {
|
|
// Given
|
|
CGSize originalSize = self.button.intrinsicContentSize;
|
|
CGSize expectedSize = CGSizeMake(originalSize.width + 10, originalSize.height + 10);
|
|
|
|
// When
|
|
self.button.minimumSize = expectedSize;
|
|
|
|
// Then
|
|
XCTAssertTrue(CGSizeEqualToSize(expectedSize, self.button.intrinsicContentSize));
|
|
}
|
|
|
|
- (void)testIntrinsicContentSizeWithMaximumDecreasesSize {
|
|
// Given
|
|
CGSize originalSize = self.button.intrinsicContentSize;
|
|
CGSize expectedSize = CGSizeMake(originalSize.width - 5, originalSize.height - 5);
|
|
|
|
// When
|
|
self.button.maximumSize = expectedSize;
|
|
|
|
// Then
|
|
XCTAssertTrue(CGSizeEqualToSize(expectedSize, self.button.intrinsicContentSize));
|
|
}
|
|
|
|
- (void)testIntrinsicContentSizeWithMaximumAndMinimumSizeBehavior {
|
|
// Given
|
|
CGSize originalSize = self.button.intrinsicContentSize;
|
|
CGSize expectedSize = CGSizeMake(originalSize.width + 5, originalSize.height - 5);
|
|
|
|
// When
|
|
self.button.maximumSize = CGSizeMake(0, expectedSize.height);
|
|
self.button.minimumSize = CGSizeMake(expectedSize.width, 0);
|
|
|
|
// Then
|
|
XCTAssertTrue(CGSizeEqualToSize(expectedSize, self.button.intrinsicContentSize));
|
|
}
|
|
|
|
#pragma mark - UIAccessibility
|
|
|
|
- (void)testAccessibilityTraitsDefault {
|
|
// Then
|
|
XCTAssertEqual(self.button.accessibilityTraits, UIAccessibilityTraitButton);
|
|
}
|
|
|
|
- (void)testAccessibilityTraitsDefaultIncludesButtonExplicitlyTrue {
|
|
// When
|
|
self.button.accessibilityTraitsIncludesButton = YES;
|
|
|
|
// Then
|
|
XCTAssertEqual(self.button.accessibilityTraits, UIAccessibilityTraitButton);
|
|
}
|
|
|
|
- (void)testAccessibilityTraitsDefaultIncludesButtonExplicitlyFalse {
|
|
// Given
|
|
UIButton *referenceButton = [[UIButton alloc] init];
|
|
[referenceButton setTitle:@"title" forState:UIControlStateNormal];
|
|
|
|
// When
|
|
self.button.accessibilityTraitsIncludesButton = NO;
|
|
|
|
// Then
|
|
// UIButton does not return `.button` in unit tests, but will in a simulator. The best this test
|
|
// can do is confirm the behavior matches UIButton.
|
|
XCTAssertEqual(self.button.accessibilityTraits, referenceButton.accessibilityTraits);
|
|
}
|
|
|
|
- (void)testSetAccessibilityTraitsIncludesButtonByDefault {
|
|
// When
|
|
self.button.accessibilityTraits = UIAccessibilityTraitLink;
|
|
|
|
// Then
|
|
XCTAssertEqual(self.button.accessibilityTraits,
|
|
UIAccessibilityTraitLink | UIAccessibilityTraitButton);
|
|
}
|
|
|
|
- (void)testSetAccessibilityTraitsExcludesButtonExplicitly {
|
|
// When
|
|
self.button.accessibilityTraitsIncludesButton = NO;
|
|
self.button.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;
|
|
|
|
// Then
|
|
XCTAssertEqual(self.button.accessibilityTraits, UIAccessibilityTraitAllowsDirectInteraction);
|
|
}
|
|
|
|
- (void)testSetAccessibilityTraitsIncludesButtonExplicitly {
|
|
// When
|
|
self.button.accessibilityTraitsIncludesButton = YES;
|
|
self.button.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;
|
|
|
|
// Then
|
|
XCTAssertEqual(self.button.accessibilityTraits,
|
|
UIAccessibilityTraitAllowsDirectInteraction | UIAccessibilityTraitButton);
|
|
}
|
|
|
|
#pragma mark - UITraitCollection
|
|
|
|
- (void)testTraitCollectionDidChangeBlockCalledWhenTraitCollectionChanges {
|
|
// Given
|
|
MDCButton *button = [[MDCButton alloc] init];
|
|
XCTestExpectation *expectation =
|
|
[self expectationWithDescription:@"Called traitCollectionDidChange"];
|
|
|
|
__block MDCButton *passedButton;
|
|
button.traitCollectionDidChangeBlock =
|
|
^(MDCButton *_Nonnull buttonInBlock, UITraitCollection *_Nullable previousTraitCollection) {
|
|
passedButton = buttonInBlock;
|
|
[expectation fulfill];
|
|
};
|
|
|
|
// When
|
|
[button traitCollectionDidChange:nil];
|
|
|
|
// Then
|
|
[self waitForExpectations:@[ expectation ] timeout:1];
|
|
XCTAssertEqual(passedButton, button);
|
|
}
|
|
|
|
#pragma mark - MaterialElevation
|
|
|
|
- (void)testDefaultValueForOverrideBaseElevationIsNegative {
|
|
// Given
|
|
MDCButton *button = [[MDCButton alloc] init];
|
|
|
|
// Then
|
|
XCTAssertLessThan(button.mdc_overrideBaseElevation, 0);
|
|
}
|
|
|
|
- (void)testCurrentElevationMatchesElevationForState {
|
|
// Given
|
|
MDCButton *button = [[MDCButton alloc] init];
|
|
|
|
// When
|
|
UIControlState allStatesCombined = UIControlStateNormal | UIControlStateDisabled |
|
|
UIControlStateSelected | UIControlStateHighlighted;
|
|
MDCShadowElevation startingElevation = 100;
|
|
|
|
for (NSUInteger state = 0; state <= allStatesCombined; ++state) {
|
|
[button setElevation:startingElevation + state forState:state];
|
|
}
|
|
|
|
// Then
|
|
for (NSUInteger state = 0; state <= allStatesCombined; ++state) {
|
|
if (state & (UIControlStateDisabled | UIControlStateHighlighted)) {
|
|
continue;
|
|
}
|
|
button.enabled = (state & UIControlStateDisabled) == UIControlStateDisabled ? NO : YES;
|
|
button.selected = (state & UIControlStateSelected) == UIControlStateSelected ? YES : NO;
|
|
button.highlighted =
|
|
(state & UIControlStateHighlighted) == UIControlStateHighlighted ? YES : NO;
|
|
XCTAssertEqualWithAccuracy(button.mdc_currentElevation, [button elevationForState:state],
|
|
0.001);
|
|
}
|
|
}
|
|
|
|
- (void)testElevationDidChangeBlockCalledWhenStateChangeCausesElevationChange {
|
|
// Given
|
|
MDCButton *button = [[MDCButton alloc] init];
|
|
[button setElevation:1 forState:UIControlStateNormal];
|
|
[button setElevation:9 forState:UIControlStateSelected];
|
|
__block CGFloat newElevation = 0;
|
|
button.mdc_elevationDidChangeBlock = ^(id<MDCElevatable> _, CGFloat elevation) {
|
|
newElevation = elevation;
|
|
};
|
|
|
|
// When
|
|
button.selected = YES;
|
|
|
|
// Then
|
|
XCTAssertEqualWithAccuracy(newElevation, [button elevationForState:UIControlStateSelected],
|
|
0.001);
|
|
}
|
|
|
|
- (void)testElevationDidChangeBlockNotCalledWhenStateChangeDoesNotCauseElevationChange {
|
|
// Given
|
|
MDCButton *button = [[MDCButton alloc] init];
|
|
[button setElevation:1 forState:UIControlStateNormal];
|
|
[button setElevation:1 forState:UIControlStateHighlighted];
|
|
__block BOOL blockCalled = NO;
|
|
button.mdc_elevationDidChangeBlock = ^(id<MDCElevatable> _, CGFloat elevation) {
|
|
blockCalled = YES;
|
|
};
|
|
|
|
// When
|
|
button.highlighted = YES;
|
|
|
|
// Then
|
|
XCTAssertFalse(blockCalled);
|
|
}
|
|
|
|
- (void)testElevationDidChangeBlockCalledWhenElevationChangesForCurrentState {
|
|
// Given
|
|
MDCButton *button = [[MDCButton alloc] init];
|
|
button.selected = YES;
|
|
__block CGFloat newElevation = 0;
|
|
button.mdc_elevationDidChangeBlock = ^(id<MDCElevatable> _, CGFloat elevation) {
|
|
newElevation = elevation;
|
|
};
|
|
|
|
// When
|
|
[button setElevation:99 forState:button.state];
|
|
|
|
// Then
|
|
XCTAssertEqualWithAccuracy(newElevation, [button elevationForState:button.state], 0.001);
|
|
}
|
|
|
|
- (void)testDefaultVisibleAreaInsetAndShapeGeneratorValues {
|
|
// Then
|
|
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.button.visibleAreaInsets, UIEdgeInsetsZero));
|
|
XCTAssertNil(self.button.shapeGenerator);
|
|
}
|
|
|
|
- (void)testSettingVisibleAreaInsetCreatesCorrectShape {
|
|
// Given
|
|
CGFloat cornerRadius = 5;
|
|
UIEdgeInsets visibleAreaInsets = UIEdgeInsetsMake(1, 2, 3, 4);
|
|
MDCRectangleShapeGenerator *rectangleShapeGenerator = [[MDCRectangleShapeGenerator alloc] init];
|
|
MDCCornerTreatment *cornerTreatment =
|
|
[[MDCRoundedCornerTreatment alloc] initWithRadius:cornerRadius];
|
|
[rectangleShapeGenerator setCorners:cornerTreatment];
|
|
rectangleShapeGenerator.topLeftCornerOffset =
|
|
CGPointMake(visibleAreaInsets.left, visibleAreaInsets.top);
|
|
rectangleShapeGenerator.topRightCornerOffset =
|
|
CGPointMake(-visibleAreaInsets.right, visibleAreaInsets.top);
|
|
rectangleShapeGenerator.bottomLeftCornerOffset =
|
|
CGPointMake(visibleAreaInsets.left, -visibleAreaInsets.bottom);
|
|
rectangleShapeGenerator.bottomRightCornerOffset =
|
|
CGPointMake(-visibleAreaInsets.right, -visibleAreaInsets.bottom);
|
|
self.button.layer.cornerRadius = cornerRadius;
|
|
[self.button sizeToFit];
|
|
|
|
// When
|
|
self.button.visibleAreaInsets = visibleAreaInsets;
|
|
|
|
// Then
|
|
XCTAssertTrue(CGPathEqualToPath([self.button.shapeGenerator pathForSize:CGSizeMake(100, 100)],
|
|
[rectangleShapeGenerator pathForSize:CGSizeMake(100, 100)]));
|
|
}
|
|
|
|
- (void)testSettingVisibleAreaInsetAndAfterCornerRadiusCreatesCorrectShape {
|
|
// Given
|
|
CGFloat cornerRadius = 12;
|
|
UIEdgeInsets visibleAreaInsets = UIEdgeInsetsMake(1, 2, 3, 4);
|
|
MDCRectangleShapeGenerator *rectangleShapeGenerator = [[MDCRectangleShapeGenerator alloc] init];
|
|
MDCCornerTreatment *cornerTreatment =
|
|
[[MDCRoundedCornerTreatment alloc] initWithRadius:cornerRadius];
|
|
[rectangleShapeGenerator setCorners:cornerTreatment];
|
|
rectangleShapeGenerator.topLeftCornerOffset =
|
|
CGPointMake(visibleAreaInsets.left, visibleAreaInsets.top);
|
|
rectangleShapeGenerator.topRightCornerOffset =
|
|
CGPointMake(-visibleAreaInsets.right, visibleAreaInsets.top);
|
|
rectangleShapeGenerator.bottomLeftCornerOffset =
|
|
CGPointMake(visibleAreaInsets.left, -visibleAreaInsets.bottom);
|
|
rectangleShapeGenerator.bottomRightCornerOffset =
|
|
CGPointMake(-visibleAreaInsets.right, -visibleAreaInsets.bottom);
|
|
self.button.layer.cornerRadius = 5;
|
|
[self.button sizeToFit];
|
|
|
|
// When
|
|
self.button.visibleAreaInsets = visibleAreaInsets;
|
|
self.button.layer.cornerRadius = cornerRadius;
|
|
|
|
// Then
|
|
XCTAssertTrue(CGPathEqualToPath([self.button.shapeGenerator pathForSize:CGSizeMake(100, 100)],
|
|
[rectangleShapeGenerator pathForSize:CGSizeMake(100, 100)]));
|
|
}
|
|
|
|
- (void)testSettingVisibleAreaInsetAndThenResetingItAndCheckingCorrectShapeGeneratorValue {
|
|
// Given
|
|
UIEdgeInsets visibleAreaInsets = UIEdgeInsetsMake(1, 2, 3, 4);
|
|
[self.button sizeToFit];
|
|
self.button.visibleAreaInsets = visibleAreaInsets;
|
|
|
|
// When
|
|
self.button.visibleAreaInsets = UIEdgeInsetsZero;
|
|
|
|
// Then
|
|
XCTAssertNil(self.button.shapeGenerator);
|
|
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.button.visibleAreaInsets, UIEdgeInsetsZero));
|
|
}
|
|
|
|
- (void)testSettingVisibleAreaInsetsProvidesCorrectSizeThatFitsAndIntrinsicContentSize {
|
|
// Given
|
|
CGSize buttonSize = CGSizeMake(32, 33);
|
|
UIEdgeInsets visibleAreaInsets = UIEdgeInsetsMake(1, 2, 3, 4);
|
|
[self.button sizeToFit];
|
|
CGRect beforeButtonFrame = self.button.frame;
|
|
CGSize beforeInsetsSize = [self.button intrinsicContentSize];
|
|
|
|
// When
|
|
self.button.visibleAreaInsets = visibleAreaInsets;
|
|
[self.button sizeToFit];
|
|
CGRect afterButtonFrame = self.button.frame;
|
|
CGSize afterInsetsSize = [self.button intrinsicContentSize];
|
|
|
|
// Then
|
|
XCTAssertTrue(CGSizeEqualToSize(beforeInsetsSize, buttonSize));
|
|
XCTAssertTrue(CGSizeEqualToSize(beforeButtonFrame.size, buttonSize));
|
|
XCTAssertTrue(CGSizeEqualToSize(
|
|
afterInsetsSize,
|
|
CGSizeMake(buttonSize.width + visibleAreaInsets.left + visibleAreaInsets.right,
|
|
buttonSize.height + visibleAreaInsets.top + visibleAreaInsets.bottom)));
|
|
XCTAssertTrue(CGSizeEqualToSize(
|
|
afterButtonFrame.size,
|
|
CGSizeMake(buttonSize.width + visibleAreaInsets.left + visibleAreaInsets.right,
|
|
buttonSize.height + visibleAreaInsets.top + visibleAreaInsets.bottom)));
|
|
}
|
|
|
|
@end
|