blob: ee2ecff8227d8a8bd68e6c9408c3844073527091 [file]
/*
Copyright 2017-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 "MDCMath.h"
@interface MDCMathTests : XCTestCase
@end
@implementation MDCMathTests
#pragma mark - MDCRect
/**
Basic test for alignment.
*/
- (void)testMDCRectAlignScale {
// Given
CGRect misalignedRect = CGRectMake(0.45, 0.78, 1.01, 5.98);
CGRect alignedScale1Rect = CGRectMake(0, 0, 2, 7);
CGRect alignedScale2Rect = CGRectMake(0, 0.5, 1.5, 6.5);
CGRect alignedScale3Rect = CGRectMake(1.0 / 3.0, 2.0 / 3.0, 4.0 / 3.0, 19.0 / 3.0);
// Then
CGRect outputScale1Rect = MDCRectAlignToScale(misalignedRect, 1);
XCTAssertTrue(CGRectEqualToRect(alignedScale1Rect, outputScale1Rect));
XCTAssertTrue(CGRectContainsRect(outputScale1Rect, misalignedRect));
CGRect outputScale2Rect = MDCRectAlignToScale(misalignedRect, 2);
XCTAssertTrue(CGRectEqualToRect(alignedScale2Rect, outputScale2Rect));
XCTAssertTrue(CGRectContainsRect(outputScale2Rect, misalignedRect));
CGRect outputScale3Rect = MDCRectAlignToScale(misalignedRect, 3);
XCTAssertTrue(CGRectEqualToRect(alignedScale3Rect, outputScale3Rect));
XCTAssertTrue(CGRectContainsRect(outputScale3Rect, misalignedRect));
}
/**
Basic test of rectangle alignment when the origin has negative values.
*/
- (void)testMDCRectAlignScaleNegativeRectangle {
// Given
CGRect misalignedRect = CGRectMake(-5.01, -0.399, 8.35, 2.65);
CGRect alignedScale1Rect = CGRectMake(-6, -1, 10, 4);
CGRect alignedScale2Rect = CGRectMake(-5.5, -0.5, 9, 3);
CGRect alignedScale3Rect = CGRectMake(-16.0 / 3.0, -2.0 / 3.0, 9, 3);
// Then
CGRect outputScale1Rect = MDCRectAlignToScale(misalignedRect, 1);
XCTAssertTrue(CGRectEqualToRect(alignedScale1Rect, outputScale1Rect));
XCTAssertTrue(CGRectContainsRect(outputScale1Rect, misalignedRect));
CGRect outputScale2Rect = MDCRectAlignToScale(misalignedRect, 2);
XCTAssertTrue(CGRectEqualToRect(alignedScale2Rect, outputScale2Rect));
XCTAssertTrue(CGRectContainsRect(outputScale2Rect, misalignedRect));
CGRect outputScale3Rect = MDCRectAlignToScale(misalignedRect, 3);
XCTAssertTrue(CGRectEqualToRect(alignedScale3Rect, outputScale3Rect));
XCTAssertTrue(CGRectContainsRect(outputScale3Rect, misalignedRect));
}
/**
Test of a non-standardized rectangle (height/width are negative)
*/
- (void)testMDCRectAlignScaleNonStandardRectangle {
// Given
CGRect misalignedRect = CGRectMake(17.9, -4.44, -10.10, -15.85);
// Standardized: (7.80, -20.29), (10.10, 15.85)
CGRect alignedScale1Rect = CGRectMake(7, -21, 11, 17);
CGRect alignedScale2Rect = CGRectMake(7.5, -20.5, 10.5, 16.5);
CGRect alignedScale3Rect = CGRectMake(23.0 / 3.0, -61.0 / 3.0, 31.0 / 3.0, 16);
// Then
CGRect outputScale1Rect = MDCRectAlignToScale(misalignedRect, 1);
XCTAssertTrue(CGRectEqualToRect(alignedScale1Rect, outputScale1Rect));
XCTAssertTrue(CGRectContainsRect(outputScale1Rect, misalignedRect));
CGRect outputScale2Rect = MDCRectAlignToScale(misalignedRect, 2);
XCTAssertTrue(CGRectEqualToRect(alignedScale2Rect, outputScale2Rect));
XCTAssertTrue(CGRectContainsRect(outputScale2Rect, misalignedRect));
CGRect outputScale3Rect = MDCRectAlignToScale(misalignedRect, 3);
XCTAssertTrue(CGRectEqualToRect(alignedScale3Rect, outputScale3Rect));
XCTAssertTrue(CGRectContainsRect(outputScale3Rect, misalignedRect));
}
/**
Test that an already-aligned rectangle will not be changed.
*/
- (void)testMDCRectAlignScaleAlreadyAligned {
// Given
CGRect alignedScale1Rect = CGRectMake(10, 15, 5, 10);
CGRect alignedScale2Rect = CGRectMake(10.5, 15.5, 5.5, 10.5);
CGRect alignedScale3Rect = CGRectMake(31.0 / 3.0, 47.0 / 3.0, 16.0 / 3.0, 32.0 / 3.0);
// Then
CGRect outputScale1Rect = MDCRectAlignToScale(alignedScale1Rect, 1);
XCTAssertTrue(CGRectEqualToRect(alignedScale1Rect, outputScale1Rect));
XCTAssertTrue(CGRectContainsRect(outputScale1Rect, alignedScale1Rect));
CGRect outputScale2Rect = MDCRectAlignToScale(alignedScale2Rect, 2);
XCTAssertTrue(CGRectEqualToRect(alignedScale2Rect, outputScale2Rect));
XCTAssertTrue(CGRectContainsRect(outputScale2Rect, alignedScale2Rect));
CGRect outputScale3Rect = MDCRectAlignToScale(alignedScale3Rect, 3);
XCTAssertTrue(CGRectEqualToRect(alignedScale3Rect, outputScale3Rect));
XCTAssertTrue(CGRectContainsRect(outputScale3Rect, alignedScale3Rect));
}
/**
Test that a null rectangle returns CGRectNull.
*/
- (void)testMDCRectAlignScaleNullRectangle {
// Then
XCTAssertTrue(CGRectIsNull(MDCRectAlignToScale(CGRectNull, 1)));
XCTAssertTrue(CGRectIsNull(MDCRectAlignToScale(CGRectNull, 2)));
XCTAssertTrue(CGRectIsNull(MDCRectAlignToScale(CGRectNull, 3)));
}
/**
Test that a scale value of zero returns the same as a scale of 1.
*/
- (void)testMDCRectAlignScaleZeroScale {
// Given
CGRect rectangle = CGRectMake(1.1, 2.2, 3.3, 4.4);
// Then
XCTAssertTrue(CGRectEqualToRect(MDCRectAlignToScale(rectangle, 0),
MDCRectAlignToScale(rectangle, 1)));
}
#pragma mark - MDCPoint
- (void)testMDCPointRoundWithScale {
// Given
CGPoint misalignedPoint = CGPointMake(0.7, -1.3);
CGPoint alignedScale1Point = CGPointMake(1.0, -1.0);
CGPoint alignedScale2Point = CGPointMake(0.5, -1.5);
CGPoint alignedScale3Point = CGPointMake((CGFloat)(2.0 / 3.0), (CGFloat)(-4.0 / 3.0));
// Then
XCTAssertTrue(CGPointEqualToPoint(alignedScale1Point,
MDCPointRoundWithScale(misalignedPoint, 1)));
XCTAssertTrue(CGPointEqualToPoint(alignedScale2Point,
MDCPointRoundWithScale(misalignedPoint, 2)));
XCTAssertTrue(CGPointEqualToPoint(alignedScale3Point,
MDCPointRoundWithScale(misalignedPoint, 3)));
}
- (void)testMDCPointRoundScaleZeroScale {
// Then
XCTAssertTrue(CGPointEqualToPoint(CGPointZero, MDCPointRoundWithScale(CGPointMake(5.5, 13), 0)));
}
#pragma mark - MDCCenter
- (void)testMDCRoundCenterWithBoundsAndScale {
// Given
CGPoint misalignedCenter = CGPointMake(0.7, -1.3);
CGRect bounds = CGRectMake(0, 0, 20, 21);
CGPoint alignedScale1Center = CGPointMake(1, -1.5);
CGPoint alignedScale2Center = CGPointMake(0.5, -1.5);
CGPoint alignedScale3Center = CGPointMake((CGFloat)(2.0 / 3.0), (CGFloat)(-7.0 / 6.0));
// Then
CGPoint outputScale1Center = MDCRoundCenterWithBoundsAndScale(misalignedCenter, bounds, 1);
XCTAssertTrue(MDCCGFloatEqual(alignedScale1Center.x, outputScale1Center.x));
XCTAssertTrue(MDCCGFloatEqual(alignedScale1Center.y, outputScale1Center.y));
CGPoint outputScale2Center = MDCRoundCenterWithBoundsAndScale(misalignedCenter, bounds, 2);
XCTAssertTrue(MDCCGFloatEqual(alignedScale2Center.x, outputScale2Center.x));
XCTAssertTrue(MDCCGFloatEqual(alignedScale2Center.y, outputScale2Center.y));
CGPoint outputScale3Center = MDCRoundCenterWithBoundsAndScale(misalignedCenter, bounds, 3);
XCTAssertTrue(MDCCGFloatEqual(alignedScale3Center.x, outputScale3Center.x));
XCTAssertTrue(MDCCGFloatEqual(alignedScale3Center.y, outputScale3Center.y));
}
- (void)testMDCRoundCenterWithBoundsAndScaleRoundingErrors {
// Given
#if CGFLOAT_IS_DOUBLE
const CGFloat acceptableRoundingError = 5E-15;
#else
const CGFloat acceptableRoundingError = 5E-7f;
#endif
CGPoint misalignedCenter = CGPointMake(0.3, 9.99);
CGRect bounds = CGRectMake(0, 0, 20.1, 21.9);
CGPoint alignedScale1Center = CGPointMake((CGFloat)0.05, (CGFloat)9.95);
CGPoint alignedScale2Center = CGPointMake((CGFloat)0.05, (CGFloat)9.95);
CGPoint alignedScale3Center = CGPointMake((CGFloat)(0.05 + 1.0 / 3.0), (CGFloat)(9.95));
// Then
CGPoint outputScale1Center = MDCRoundCenterWithBoundsAndScale(misalignedCenter, bounds, 1);
XCTAssertLessThan(MDCFabs(alignedScale1Center.x - outputScale1Center.x), acceptableRoundingError);
XCTAssertLessThan(MDCFabs(alignedScale1Center.y - outputScale1Center.y), acceptableRoundingError);
CGPoint outputScale2Center = MDCRoundCenterWithBoundsAndScale(misalignedCenter, bounds, 2);
XCTAssertLessThan(MDCFabs(alignedScale2Center.x - outputScale2Center.x), acceptableRoundingError);
XCTAssertLessThan(MDCFabs(alignedScale2Center.y - outputScale2Center.y), acceptableRoundingError);
CGPoint outputScale3Center = MDCRoundCenterWithBoundsAndScale(misalignedCenter, bounds, 3);
XCTAssertLessThan(MDCFabs(alignedScale3Center.x - outputScale3Center.x), acceptableRoundingError);
XCTAssertLessThan(MDCFabs(alignedScale3Center.y - outputScale3Center.y), acceptableRoundingError);
}
- (void)testMDCRoundCenterWithBoundsAndScaleZero {
// Then
XCTAssertTrue(CGPointEqualToPoint(CGPointZero,
MDCRoundCenterWithBoundsAndScale(CGPointMake(-5, 10),
CGRectMake(0, 0, 20, 20),
0)));
}
- (void)testMDCRoundCenterWithBoundsAndScaleNullBounds {
// Then
XCTAssertTrue(CGPointEqualToPoint(CGPointZero,
MDCRoundCenterWithBoundsAndScale(CGPointMake(1, 2),
CGRectNull,
1)));
}
@end