diff --git a/Sources/Mew/Protocols/CellProtocol.swift b/Sources/Mew/Protocols/CellProtocol.swift index f38baa1..64ed7b8 100644 --- a/Sources/Mew/Protocols/CellProtocol.swift +++ b/Sources/Mew/Protocols/CellProtocol.swift @@ -51,7 +51,9 @@ extension TableViewCellProtocol where Self: UIView { NSLayoutConstraint.activate( [ viewController.view.topAnchor.constraint(equalTo: contentView.topAnchor), - viewController.view.leftAnchor.constraint(equalTo: contentView.leftAnchor) + viewController.view.leftAnchor.constraint(equalTo: contentView.leftAnchor), + viewController.view.rightAnchor.constraint(lessThanOrEqualTo: contentView.rightAnchor), + viewController.view.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor) ] + [ viewController.view.rightAnchor.constraint(equalTo: contentView.rightAnchor), viewController.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) @@ -66,6 +68,7 @@ public enum SizeConstraint: Equatable { case maximumSize(CGSize) case maximumWidth(CGFloat) case maximumHeight(CGFloat) + /// Note: Support UICollectionViewFlowLayout sizing. Not yet UICollectionViewDelegateFlowLayout. case automaticDimension(UICollectionViewLayout) typealias Calculated = (width: CGFloat?, height: CGFloat?) @@ -80,13 +83,14 @@ public enum SizeConstraint: Equatable { return (nil, height) case .automaticDimension(let layout): let frame = layout.collectionView?.frame ?? .zero - let size = layout.collectionViewContentSize + let direction = (layout as? UICollectionViewFlowLayout)?.scrollDirection + let inset = (layout as? UICollectionViewFlowLayout)?.sectionInset ?? UIEdgeInsets.zero var result: Calculated = (nil, nil) - if frame.height >= size.height { - result.height = frame.height + if direction != UICollectionViewScrollDirection.vertical { + result.height = frame.height - inset.top - inset.bottom } - if frame.width >= size.width { - result.width = frame.width + if direction != UICollectionViewScrollDirection.horizontal { + result.width = frame.width - inset.left - inset.right } return result } diff --git a/Tests/MewTests/CollectionViewCellTests.swift b/Tests/MewTests/CollectionViewCellTests.swift index 46e287c..659571c 100644 --- a/Tests/MewTests/CollectionViewCellTests.swift +++ b/Tests/MewTests/CollectionViewCellTests.swift @@ -9,80 +9,6 @@ import XCTest @testable import Mew -final private class ViewController: UIViewController, Injectable, Instantiatable, Interactable { - typealias Input = Int - var parameter: Int - var handler: ((Int) -> ())? - - let environment: Void - - init(with value: Int, environment: Void) { - self.parameter = value - self.environment = environment - super.init(nibName: nil, bundle: nil) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func input(_ value: Int) { - self.parameter = value - } - - func output(_ handler: ((Int) -> Void)?) { - self.handler = handler - } - - func fire() { - handler?(parameter) - } -} - -final private class CollectionViewController: UICollectionViewController, Instantiatable, UICollectionViewDelegateFlowLayout { - let environment: Void - var elements: [Int] - - init(with input: [Int], environment: Void) { - self.environment = environment - self.elements = input - super.init(collectionViewLayout: UICollectionViewFlowLayout()) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - CollectionViewCell.register(to: collectionView!) - CollectionReusableView.register(to: collectionView!, for: .header) - collectionViewLayout.invalidateLayout() - collectionView?.reloadData() - collectionView?.layoutIfNeeded() - } - - override func numberOfSections(in collectionView: UICollectionView) -> Int { - return 1 - } - - override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return elements.count - } - - override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - return CollectionViewCell.dequeued(from: collectionView, for: indexPath, input: elements[indexPath.row], parentViewController: self) - } - - override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - return CollectionReusableView.dequeued(from: collectionView, of: kind, for: indexPath, input: elements.count, parentViewController: self) - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - return CGSize(width: collectionView.frame.width, height: 44.0) - } -} - class CollectionViewCellTests: XCTestCase { func testDequeueCollectionViewCellWithViewController() { let collectionViewController = CollectionViewController(with: [1, 2, 3], environment: ()) @@ -148,9 +74,81 @@ class CollectionViewCellTests: XCTestCase { self.wait(for: [exp], timeout: 5.0) } + func testAutosizingCell() { + let data = [ + [ + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))) + ], + [ + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))) + ], + [ + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))) + ] + ] + VERTICAL: do { + let collectionViewController = AutolayoutCollectionViewController(with: [], environment: ()) + _ = collectionViewController.view // load view + (collectionViewController.collectionViewLayout as! UICollectionViewFlowLayout).scrollDirection = .vertical + + UIApplication.shared.keyWindow?.rootViewController = collectionViewController + for expects in data { + collectionViewController.input(expects) + collectionViewController.collectionView!.layoutIfNeeded() + let cells = collectionViewController.collectionView!.indexPathsForVisibleItems.sorted().compactMap { collectionViewController.collectionView!.cellForItem(at: $0) } + zip(expects, cells).forEach { expect, cell in + let expectedSize = CGSize(width: min(collectionViewController.collectionView!.frame.width - 40.0, 200 + expect.additionalWidth), height: 200 + expect.additionalHeight) + XCTAssertEqual(cell.frame.size, expectedSize) + XCTAssertEqual(cell.contentView.frame.size, expectedSize) + let childViewController = collectionViewController.childViewControllers.first(where: { $0.view.superview == cell.contentView }) as! AutolayoutViewController + XCTAssertEqual(childViewController.view.frame.size, expectedSize) + XCTAssertFalse(cell.hasAmbiguousLayout) + } + } + } + HORIZONTAL: do { + let collectionViewController = AutolayoutCollectionViewController(with: [], environment: ()) + _ = collectionViewController.view // load view + (collectionViewController.collectionViewLayout as! UICollectionViewFlowLayout).scrollDirection = .horizontal + + UIApplication.shared.keyWindow?.rootViewController = collectionViewController + for expects in data { + collectionViewController.input(expects) + collectionViewController.collectionView!.layoutIfNeeded() + let cells = collectionViewController.collectionView!.indexPathsForVisibleItems.sorted().compactMap { collectionViewController.collectionView!.cellForItem(at: $0) } + zip(expects, cells).forEach { expect, cell in + let expectedSize = CGSize(width: 200 + expect.additionalWidth, height: min(collectionViewController.collectionView!.frame.height - 40.0, 200 + expect.additionalHeight)) + XCTAssertEqual(cell.frame.size, expectedSize) + XCTAssertEqual(cell.contentView.frame.size, expectedSize) + let childViewController = collectionViewController.childViewControllers.first(where: { $0.view.superview == cell.contentView }) as! AutolayoutViewController + XCTAssertEqual(childViewController.view.frame.size, expectedSize) + XCTAssertFalse(cell.hasAmbiguousLayout) + } + } + } + } + static var allTests = [ ("testDequeueCollectionViewCellWithViewController", testDequeueCollectionViewCellWithViewController), ("testDequeueCollectionViewHeaderFooterWithViewController", testDequeueCollectionViewHeaderFooterWithViewController), - ("testViewControllerLifeCycle", testViewControllerLifeCycle) + ("testViewControllerLifeCycle", testViewControllerLifeCycle), + ("testAutosizingCell", testAutosizingCell) ] } diff --git a/Tests/MewTests/Supports.swift b/Tests/MewTests/Supports.swift index c1cfb0c..bbe24ed 100644 --- a/Tests/MewTests/Supports.swift +++ b/Tests/MewTests/Supports.swift @@ -7,6 +7,7 @@ // import UIKit +import Mew extension UIView { private static func contains(_ view: UIView, where condition: (UIView) -> Bool) -> Bool { @@ -42,3 +43,280 @@ extension UIView { } } } + +final class ViewController: UIViewController, Injectable, Instantiatable, Interactable { + typealias Input = Int + var parameter: Int + var handler: ((Int) -> ())? + + let environment: Void + + init(with value: Int, environment: Void) { + self.parameter = value + self.environment = environment + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func input(_ value: Int) { + self.parameter = value + } + + func output(_ handler: ((Int) -> Void)?) { + self.handler = handler + } + + func fire() { + handler?(parameter) + } +} + +final class TableViewController: UITableViewController, Instantiatable { + let environment: Void + var elements: [Int] + + init(with input: [Int], environment: Void) { + self.environment = environment + self.elements = input + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + TableViewCell.register(to: tableView) + TableViewHeaderFooterView.register(to: tableView) + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return elements.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + return TableViewCell.dequeued(from: tableView, for: indexPath, input: elements[indexPath.row], parentViewController: self) + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + return TableViewHeaderFooterView.dequeued(from: tableView, input: elements.count, parentViewController: self) + } +} + +final class CollectionViewController: UICollectionViewController, Instantiatable, UICollectionViewDelegateFlowLayout { + let environment: Void + var elements: [Int] + + init(with input: [Int], environment: Void) { + self.environment = environment + self.elements = input + super.init(collectionViewLayout: UICollectionViewFlowLayout()) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + CollectionViewCell.register(to: collectionView!) + CollectionReusableView.register(to: collectionView!, for: .header) + collectionViewLayout.invalidateLayout() + collectionView?.reloadData() + collectionView?.layoutIfNeeded() + } + + override func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return elements.count + } + + override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + return CollectionViewCell.dequeued(from: collectionView, for: indexPath, input: elements[indexPath.row], parentViewController: self) + } + + override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + return CollectionReusableView.dequeued(from: collectionView, of: kind, for: indexPath, input: elements.count, parentViewController: self) + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + return CGSize(width: collectionView.frame.width, height: 44.0) + } +} + +final class AutolayoutViewController: UIViewController, Injectable, Instantiatable { + struct Input { + var additionalWidth: CGFloat + var additionalHeight: CGFloat + } + var parameter: Input { + didSet { + updateLayout() + } + } + + let environment: Void + + init(with input: Input, environment: Void) { + self.parameter = input + self.environment = environment + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var squareRequiredView: UIView! + var additionalWidthView: UIView! + var additionalHeightView: UIView! + var additionalWidthConstraints = [NSLayoutConstraint]() + var additionalHeightConstraints = [NSLayoutConstraint]() + + /** + ``` + ┌┬─┐ + ├┴─┤ + └──┘ + ``` + */ + override func viewDidLoad() { + super.viewDidLoad() + squareRequiredView = UIView() + squareRequiredView.translatesAutoresizingMaskIntoConstraints = false + additionalWidthView = UIView() + additionalWidthView.translatesAutoresizingMaskIntoConstraints = false + additionalHeightView = UIView() + additionalHeightView.translatesAutoresizingMaskIntoConstraints = false + additionalWidthConstraints = [ + { let x = additionalWidthView.widthAnchor.constraint(equalToConstant: 0); x.priority = .defaultHigh + 1; return x }(), + additionalWidthView.widthAnchor.constraint(lessThanOrEqualToConstant: 0) + ] + additionalHeightConstraints = [ + { let x = additionalHeightView.heightAnchor.constraint(equalToConstant: 0); x.priority = .defaultHigh + 1; return x }(), + additionalHeightView.heightAnchor.constraint(lessThanOrEqualToConstant: 0) + ] + view.addSubview(squareRequiredView) + view.addSubview(additionalWidthView) + view.addSubview(additionalHeightView) + NSLayoutConstraint.activate( + [ + squareRequiredView.heightAnchor.constraint(equalToConstant: 200.0), + squareRequiredView.widthAnchor.constraint(equalToConstant: 200.0), + squareRequiredView.topAnchor.constraint(equalTo: view.topAnchor), + squareRequiredView.leftAnchor.constraint(equalTo: view.leftAnchor), + squareRequiredView.rightAnchor.constraint(equalTo: additionalWidthView.leftAnchor), + additionalWidthView.topAnchor.constraint(equalTo: view.topAnchor), + additionalWidthView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + additionalWidthView.rightAnchor.constraint(equalTo: view.rightAnchor), + squareRequiredView.bottomAnchor.constraint(equalTo: additionalHeightView.topAnchor), + additionalHeightView.leftAnchor.constraint(equalTo: view.leftAnchor), + additionalHeightView.rightAnchor.constraint(equalTo: view.rightAnchor), + additionalHeightView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + + ] + additionalWidthConstraints + additionalHeightConstraints + ) + updateLayout() + } + + func input(_ value: Input) { + self.parameter = value + } + + func updateLayout() { + additionalWidthConstraints.forEach { $0.constant = parameter.additionalWidth } + additionalHeightConstraints.forEach { $0.constant = parameter.additionalHeight } + } +} + +final class AutolayoutTableViewController: UITableViewController, Instantiatable, Injectable { + let environment: Void + var elements: [AutolayoutViewController.Input] + + init(with input: [AutolayoutViewController.Input], environment: Void) { + self.environment = environment + self.elements = input + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + TableViewCell.register(to: tableView) + } + + func input(_ input: [AutolayoutViewController.Input]) { + self.elements = input + tableView.reloadData() + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return elements.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + return TableViewCell.dequeued(from: tableView, for: indexPath, input: elements[indexPath.row], parentViewController: self) + } +} + +final class AutolayoutCollectionViewController: UICollectionViewController, Instantiatable, Injectable { + let environment: Void + let flowLayout: UICollectionViewFlowLayout + var elements: [AutolayoutViewController.Input] + + init(with input: [AutolayoutViewController.Input], environment: Void) { + self.environment = environment + self.elements = input + self.flowLayout = UICollectionViewFlowLayout() + super.init(collectionViewLayout: flowLayout) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + CollectionViewCell.register(to: collectionView!) + if #available(iOS 10.0, *) { + flowLayout.itemSize = UICollectionViewFlowLayoutAutomaticSize + } + flowLayout.estimatedItemSize = CGSize(width: 200.0, height: 200.0) + flowLayout.sectionInset = UIEdgeInsets(top: 20.0, left: 20.0, bottom: 20.0, right: 20.0) + } + + func input(_ input: [AutolayoutViewController.Input]) { + self.elements = input + collectionView!.reloadData() + } + + override func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return elements.count + } + + override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + return CollectionViewCell.dequeued(from: collectionView, for: indexPath, input: elements[indexPath.row], parentViewController: self) + } +} diff --git a/Tests/MewTests/TableViewCellTests.swift b/Tests/MewTests/TableViewCellTests.swift index 0033b3d..60bc12b 100644 --- a/Tests/MewTests/TableViewCellTests.swift +++ b/Tests/MewTests/TableViewCellTests.swift @@ -9,73 +9,6 @@ import XCTest @testable import Mew -final private class ViewController: UIViewController, Injectable, Instantiatable, Interactable { - typealias Input = Int - var parameter: Int - var handler: ((Int) -> ())? - - let environment: Void - - init(with value: Int, environment: Void) { - self.parameter = value - self.environment = environment - super.init(nibName: nil, bundle: nil) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func input(_ value: Int) { - self.parameter = value - } - - func output(_ handler: ((Int) -> Void)?) { - self.handler = handler - } - - func fire() { - handler?(parameter) - } -} - -final private class TableViewController: UITableViewController, Instantiatable { - let environment: Void - var elements: [Int] - - init(with input: [Int], environment: Void) { - self.environment = environment - self.elements = input - super.init(nibName: nil, bundle: nil) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - TableViewCell.register(to: tableView) - TableViewHeaderFooterView.register(to: tableView) - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return elements.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return TableViewCell.dequeued(from: tableView, for: indexPath, input: elements[indexPath.row], parentViewController: self) - } - - override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - return TableViewHeaderFooterView.dequeued(from: tableView, input: elements.count, parentViewController: self) - } -} - class TableViewCellTests: XCTestCase { func testDequeueTableViewCellWithViewController() { let tableViewController = TableViewController(with: [1, 2, 3], environment: ()) @@ -147,9 +80,55 @@ class TableViewCellTests: XCTestCase { self.wait(for: [exp], timeout: 5.0) } + func testAutosizingCell() { + let tableViewController = AutolayoutTableViewController(with: [], environment: ()) + _ = tableViewController.view // load view + let data = [ + [ + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<100)), additionalHeight: CGFloat(Int.random(in: 0..<100))) + ], + [ + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 200..<1000)), additionalHeight: CGFloat(Int.random(in: 200..<1000))) + ], + [ + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))), + AutolayoutViewController.Input(additionalWidth: CGFloat(Int.random(in: 0..<1000)), additionalHeight: CGFloat(Int.random(in: 0..<1000))) + ] + ] + UIApplication.shared.keyWindow?.rootViewController = tableViewController + for expects in data { + tableViewController.input(expects) + let cells = tableViewController.tableView.visibleCells + zip(expects, cells).forEach { expect, cell in + XCTAssertEqual(cell.frame.size, CGSize(width: tableViewController.tableView.frame.width, height: 200 + expect.additionalHeight + 0.5)) + XCTAssertEqual(cell.contentView.frame.size, CGSize(width: tableViewController.tableView.frame.width, height: 200 + expect.additionalHeight)) + let childViewController = tableViewController.childViewControllers.first(where: { $0.view.superview == cell.contentView }) as! AutolayoutViewController + XCTAssertEqual(childViewController.view.frame.size, CGSize(width: min(tableViewController.tableView.frame.width, 200 + expect.additionalWidth), height: 200 + expect.additionalHeight)) + XCTAssertFalse(cell.hasAmbiguousLayout) + } + } + } + static var allTests = [ ("testDequeueTableViewCellWithViewController", testDequeueTableViewCellWithViewController), ("testDequeueTableViewHeaderFooterWithViewController", testDequeueTableViewHeaderFooterWithViewController), - ("testViewControllerLifeCycle", testViewControllerLifeCycle) + ("testViewControllerLifeCycle", testViewControllerLifeCycle), + ("testAutosizingCell", testAutosizingCell) ] }