blob: 65e9b721bfecb062162cc781ab796dd3539c7319 [file] [log] [blame] [edit]
// Copyright 2019-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
@testable import MaterialComponents.MaterialM3CTextField
class M3CTextViewTests: XCTestCase {
let testColorValues: [UIControl.State: UIColor] = [
.normal: .black, .error: .red, .selected: .blue,
]
var sutTextView: M3CTextView!
var sutTextContainer: UITextView!
override func setUp() {
super.setUp()
sutTextView = M3CTextView()
sutTextContainer = sutTextView.textContainer
}
override func tearDown() {
sutTextView = nil
super.tearDown()
}
/// Tests that the expected colors are applied for the .normal to .error case.
/// This includes verifying:
/// - Expected colors for background, border, labels, input text, and tint.
/// - !isFirstResponder unchanged.
func testApplyColorsFromNormalToErrorState() {
applyInitialColorTestingConfiguration(for: .normal)
let normalColor = expectedColor(for: .normal)
sutTextContainer.resignFirstResponder()
assertSUTExpectations(for: normalColor)
XCTAssertFalse(sutTextContainer.isFirstResponder)
sutTextView.isInErrorState = true
let errorColor = expectedColor(for: .error)
assertSUTExpectations(for: errorColor)
XCTAssertFalse(sutTextContainer.isFirstResponder)
}
/// Tests that the expected colors are applied for the .normal to .selected case.
/// This includes verifying:
/// - Expected colors for background, border, labels, input text, and tint.
/// - !isFirstResponder toggled to isFirstResponder.
func testApplyColorsFromNormalToSelectedState() {
applyInitialColorTestingConfiguration(for: .normal)
let normalColor = expectedColor(for: .normal)
sutTextContainer.resignFirstResponder()
assertSUTExpectations(for: normalColor)
XCTAssertFalse(sutTextContainer.isFirstResponder)
sutTextView.isInErrorState = false
sutTextContainer.becomeFirstResponder()
let selectedColor = expectedColor(for: .selected)
assertSUTExpectations(for: selectedColor)
XCTAssertTrue(sutTextContainer.isFirstResponder)
}
/// Tests that the expected colors are applied for the .error to .normal case.
/// This includes verifying:
/// - Expected colors for background, border, labels, input text, and tint.
/// - !isFirstResponder unchanged.
func testApplyColorsFromErrorToNormalState() {
applyInitialColorTestingConfiguration(for: .error)
sutTextView.isInErrorState = true
let errorColor = expectedColor(for: .error)
sutTextContainer.resignFirstResponder()
assertSUTExpectations(for: errorColor)
XCTAssertFalse(sutTextContainer.isFirstResponder)
sutTextView.isInErrorState = false
let normalColor = expectedColor(for: .normal)
assertSUTExpectations(for: normalColor)
XCTAssertFalse(sutTextContainer.isFirstResponder)
}
/// Tests that the expected colors are applied for the .error to .selected case.
/// This includes verifying:
/// - Expected colors for background, border, labels, input text, and tint.
/// - !isFirstResponder toggled to isFirstResponder.
func testApplyColorsFromErrorToSelectedState() {
applyInitialColorTestingConfiguration(for: .error)
sutTextView.isInErrorState = true
let errorColor = expectedColor(for: .error)
sutTextContainer.resignFirstResponder()
assertSUTExpectations(for: errorColor)
XCTAssertFalse(sutTextContainer.isFirstResponder)
sutTextView.isInErrorState = false
sutTextContainer.becomeFirstResponder()
let selectedColor = expectedColor(for: .selected)
assertSUTExpectations(for: selectedColor)
XCTAssertTrue(sutTextContainer.isFirstResponder)
}
/// Tests that the expected colors are applied for the .selected to .normal case.
/// This includes verifying:
/// - Expected colors for background, border, labels, input text, and tint.
/// - isFirstResponder toggled to !isFirstResponder.
func testApplyColorsFromSelectedToNormalState() {
applyInitialColorTestingConfiguration(for: .selected)
let selectedColor = expectedColor(for: .selected)
let sutTextContainer = sutTextView.textContainer
sutTextContainer.becomeFirstResponder()
assertSUTExpectations(for: selectedColor)
XCTAssertTrue(sutTextContainer.isFirstResponder)
sutTextContainer.resignFirstResponder()
let normalColor = expectedColor(for: .normal)
assertSUTExpectations(for: normalColor)
XCTAssertFalse(sutTextContainer.isFirstResponder)
}
/// Tests that the expected colors are applied for the .selected to .error case.
/// This includes verifying:
/// - Expected colors for background, border, labels, input text, and tint.
/// - isFirstResponder unchanged.
func testApplyColorsFromSelectedToErrorState() {
applyInitialColorTestingConfiguration(for: .selected)
let selectedColor = expectedColor(for: .selected)
sutTextContainer.becomeFirstResponder()
assertSUTExpectations(for: selectedColor)
XCTAssertTrue(sutTextContainer.isFirstResponder)
sutTextView.isInErrorState = true
let errorColor = expectedColor(for: .error)
assertSUTExpectations(for: errorColor)
XCTAssertTrue(sutTextContainer.isFirstResponder)
}
/// Tests that a new background color for a specific state is applied to the underlying
/// UITextView when calling `setBackgroundColor`.
func testSetBackgroundColorAppliesNewColor() {
applyInitialColorTestingConfiguration(for: .normal)
let defaultColor = expectedColor(for: .normal)
let customColor = UIColor.green
XCTAssertEqual(sutTextContainer.backgroundColor, defaultColor)
sutTextView.setBackgroundColor(customColor, for: UIControl.State.normal)
XCTAssertEqual(sutTextContainer.backgroundColor, customColor)
}
/// Tests that a new border color for a specific state is applied to the underlying
/// UITextView when calling `setBorderColor`.
func testSetBorderColorAppliesNewColor() {
applyInitialColorTestingConfiguration(for: .normal)
let defaultColor = expectedColor(for: .normal)
let customColor = UIColor.green
XCTAssertEqual(sutTextContainer.layer.borderColor, defaultColor.cgColor)
sutTextView.setBorderColor(customColor, for: UIControl.State.normal)
XCTAssertEqual(sutTextContainer.layer.borderColor, customColor.cgColor)
}
/// Tests that a new input color for a specific state is applied to the underlying
/// UITextView when calling `setInputColor`.
func testSetInputColorAppliesNewColor() {
applyInitialColorTestingConfiguration(for: .normal)
let defaultColor = expectedColor(for: .normal)
let customColor = UIColor.green
XCTAssertEqual(sutTextContainer.textColor, defaultColor)
sutTextView.setInputColor(customColor, for: UIControl.State.normal)
XCTAssertEqual(sutTextContainer.textColor, customColor)
}
/// Tests that a new supporting label color for a specific state is applied to the underlying
/// UILabel when calling `setSupportingLabelColor`.
func testSetSupportingLabelColorAppliesNewColor() {
applyInitialColorTestingConfiguration(for: .normal)
let defaultColor = expectedColor(for: .normal)
let customColor = UIColor.green
XCTAssertEqual(sutTextView.supportingLabel.textColor, defaultColor)
sutTextView.setSupportingLabelColor(customColor, for: UIControl.State.normal)
XCTAssertEqual(sutTextView.supportingLabel.textColor, customColor)
}
/// Tests that a new tint color for a specific state is applied to the underlying
/// UITextView when calling `setTintColor`.
func testSetTintColorAppliesNewColor() {
applyInitialColorTestingConfiguration(for: .normal)
let defaultColor = expectedColor(for: .normal)
let customColor = UIColor.green
XCTAssertEqual(sutTextContainer.tintColor, defaultColor)
sutTextView.setTintColor(customColor, for: UIControl.State.normal)
XCTAssertEqual(sutTextContainer.tintColor, customColor)
}
/// Tests that a new title label color for a specific state is applied to the underlying
/// UILabel when calling `setTitleLabelColor`.
func testSetTitleLabelColorAppliesNewColor() {
applyInitialColorTestingConfiguration(for: .normal)
let defaultColor = expectedColor(for: .normal)
let customColor = UIColor.green
XCTAssertEqual(sutTextView.titleLabel.textColor, defaultColor)
sutTextView.setTitleLabelColor(customColor, for: UIControl.State.normal)
XCTAssertEqual(sutTextView.titleLabel.textColor, customColor)
}
/// Tests that a new trailing label color for a specific state is applied to the underlying
/// UILabel when calling `setTrailingLabelColor`.
func testSetTrailingLabelColorAppliesNewColor() {
applyInitialColorTestingConfiguration(for: .normal)
let defaultColor = expectedColor(for: .normal)
let customColor = UIColor.green
XCTAssertEqual(sutTextView.trailingLabel.textColor, defaultColor)
sutTextView.setTrailingLabelColor(customColor, for: UIControl.State.normal)
XCTAssertEqual(sutTextView.trailingLabel.textColor, customColor)
}
}
// MARK: - Test Assertion Helpers
extension M3CTextViewTests {
private func assertSUTExpectations(
for color: UIColor, file: StaticString = #file, line: UInt = #line
) {
XCTAssertEqual(sutTextContainer.backgroundColor, color, file: file, line: line)
XCTAssertEqual(sutTextContainer.layer.borderColor, color.cgColor, file: file, line: line)
XCTAssertEqual(sutTextContainer.textColor, color, file: file, line: line)
XCTAssertEqual(sutTextContainer.tintColor, color, file: file, line: line)
XCTAssertEqual(sutTextView.supportingLabel.textColor, color, file: file, line: line)
XCTAssertEqual(sutTextView.titleLabel.textColor, color, file: file, line: line)
XCTAssertEqual(sutTextView.trailingLabel.textColor, color, file: file, line: line)
}
}
// MARK: - Test Configuration Helpers
extension M3CTextViewTests {
private func applyInitialColorTestingConfiguration(for controlState: UIControl.State) {
// `becomeFirstResponder` and `resignFirstResponder` require a window.
let window = UIWindow()
window.addSubview(sutTextView)
sutTextView.text = "test"
configureColorDictionaries()
configureTextContentColors(for: controlState)
}
private func configureColorDictionaries() {
sutTextView.backgroundColors = testColorValues
sutTextView.borderColors = testColorValues
sutTextView.inputColors = testColorValues
sutTextView.supportingLabelColors = testColorValues
sutTextView.titleLabelColors = testColorValues
sutTextView.trailingLabelColors = testColorValues
sutTextView.tintColors = testColorValues
}
private func configureTextContentColors(for controlState: UIControl.State) {
let color = expectedColor(for: controlState)
sutTextContainer.backgroundColor = color
sutTextContainer.layer.borderColor = color.cgColor
sutTextContainer.textColor = color
sutTextContainer.tintColor = color
sutTextView.supportingLabel.textColor = color
sutTextView.titleLabel.textColor = color
sutTextView.trailingLabel.textColor = color
}
private func expectedColor(for controlState: UIControl.State) -> UIColor {
switch controlState {
case .normal:
.black
case .error:
.red
case .selected:
.blue
default:
.black
}
}
}