Add UIVariationEnvironment and unit tests

This commit is contained in:
Wojciech Nagrodzki 2021-06-03 19:32:05 +02:00
parent 008ae67343
commit 677cf799f1
Signed by: wnagrodzki
GPG key ID: E9D0EB0302264569
2 changed files with 173 additions and 0 deletions

View file

@ -0,0 +1,72 @@
import UIKit
public protocol UIVariationEnvironment { }
extension UIVariationEnvironment where Self: UITraitEnvironment {
public var variations: NSMutableArray {
get {
let key = Unmanaged.passUnretained(association).toOpaque()
if let array = objc_getAssociatedObject(self, key) as! NSMutableArray? { return array }
let array = NSMutableArray()
objc_setAssociatedObject(self, key, array, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return array
}
}
public func addVariation<Object, Value>(_ variation: UIVariation<Object, Value>) {
variation.traitEnvironment = self
variations.add(variation)
variation.applyIfMatchesTraitEnvironment()
}
public func removeVariation<Object, Value>(_ variation: UIVariation<Object, Value>) {
variations.remove(variation)
variation.traitEnvironment = nil
}
public func addVariation<Object: AnyObject, Value>(for object: Object,
property: ReferenceWritableKeyPath<Object, Value>,
sizeClassDimension: SizeClassDimension,
whenCompact: Value) {
switch sizeClassDimension {
case .horizontal:
addVariation(UIVariation<Object, Value>(object: object,
keyPath: property,
value: object[keyPath: property],
horizontalSizeClass: .regular,
verticalSizeClass: nil))
addVariation(UIVariation<Object, Value>(object: object,
keyPath: property,
value: whenCompact,
horizontalSizeClass: .compact,
verticalSizeClass: nil))
case .vertical:
addVariation(UIVariation<Object, Value>(object: object,
keyPath: property,
value: object[keyPath: property],
horizontalSizeClass: nil,
verticalSizeClass: .regular))
addVariation(UIVariation<Object, Value>(object: object,
keyPath: property,
value: whenCompact,
horizontalSizeClass: nil,
verticalSizeClass: .compact))
}
}
/// Call this method when trait collection changes to keep variations reacting to them.
///
/// override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
/// super.traitCollectionDidChange(previousTraitCollection)
/// activateVariationsMatchingTraitEnvironment()
/// }
///
public func activateVariationsMatchingTraitEnvironment() {
for variation in variations as! [UIVariationApplying] {
variation.applyIfMatchesTraitEnvironment()
}
}
}
private let association = NSObject()

View file

@ -0,0 +1,101 @@
import XCTest
@testable import UserInterfaceVariations
final class UIVariationEnvironmentTests: XCTestCase {
let label = UILabel()
let valueWhenCompact = "value when compact"
let valueWhenRegular = "value when regular"
override func setUp() {
label.text = nil
}
func test_When_variation_matches_traitEnvironment_Then_it_is_applied() {
let variationEnvironment = UIVariationEnvironmentFake(traitCollection: UITraitCollection(horizontalSizeClass: .compact))
let variation = UIVariation(object: label,
keyPath: \.text,
value: valueWhenCompact,
horizontalSizeClass: .compact,
verticalSizeClass: nil)
variationEnvironment.addVariation(variation)
XCTAssertEqual(label.text, variation.value)
}
func test_adding_variation_convenience_method_for_sizeClassDimension_horizontal() {
label.text = valueWhenRegular
let variationEnvironment = UIVariationEnvironmentFake(traitCollection: UITraitCollection(horizontalSizeClass: .regular))
variationEnvironment.addVariation(for: label,
property: \.text,
sizeClassDimension: .horizontal,
whenCompact: valueWhenCompact)
let variation0 = variationEnvironment.variations[0] as! UIVariation<UILabel, String?>
XCTAssertTrue(variation0.object === label)
XCTAssertTrue(variation0.property == \.text)
XCTAssertTrue(variation0.value == valueWhenRegular)
XCTAssertTrue(variation0.horizontalSizeClass == .regular)
XCTAssertTrue(variation0.verticalSizeClass == nil)
let variation1 = variationEnvironment.variations[1] as! UIVariation<UILabel, String?>
XCTAssertTrue(variation1.object === label)
XCTAssertTrue(variation1.property == \.text)
XCTAssertTrue(variation1.value == valueWhenCompact)
XCTAssertTrue(variation1.horizontalSizeClass == .compact)
XCTAssertTrue(variation1.verticalSizeClass == nil)
}
func test_adding_variation_convenience_method_for_sizeClassDimension_vartical() {
label.text = valueWhenRegular
let variationEnvironment = UIVariationEnvironmentFake(traitCollection: UITraitCollection(horizontalSizeClass: .regular))
variationEnvironment.addVariation(for: label,
property: \.text,
sizeClassDimension: .vertical,
whenCompact: valueWhenCompact)
let variation0 = variationEnvironment.variations[0] as! UIVariation<UILabel, String?>
XCTAssertTrue(variation0.object === label)
XCTAssertTrue(variation0.property == \.text)
XCTAssertTrue(variation0.value == valueWhenRegular)
XCTAssertTrue(variation0.horizontalSizeClass == nil)
XCTAssertTrue(variation0.verticalSizeClass == .regular)
let variation1 = variationEnvironment.variations[1] as! UIVariation<UILabel, String?>
XCTAssertTrue(variation1.object === label)
XCTAssertTrue(variation1.property == \.text)
XCTAssertTrue(variation1.value == valueWhenCompact)
XCTAssertTrue(variation1.horizontalSizeClass == nil)
XCTAssertTrue(variation1.verticalSizeClass == .compact)
}
func test_When_verticalSizeClass_in_traitCollection_changes_Then_variation_is_applied() {
let variationEnvironment = UIVariationEnvironmentFake(traitCollection: UITraitCollection(verticalSizeClass: .regular))
label.text = valueWhenRegular
variationEnvironment.addVariation(for: label,
property: \.text,
sizeClassDimension: .vertical,
whenCompact: valueWhenCompact)
variationEnvironment.traitCollection = UITraitCollection(verticalSizeClass: .compact)
XCTAssertEqual(label.text, valueWhenCompact)
}
}
class UIVariationEnvironmentFake: NSObject, UITraitEnvironment {
var traitCollection = UITraitCollection() {
didSet { traitCollectionDidChange(oldValue) }
}
init(traitCollection: UITraitCollection) {
self.traitCollection = traitCollection
super.init()
}
func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
activateVariationsMatchingTraitEnvironment()
}
}
extension UIVariationEnvironmentFake: UIVariationEnvironment { }