init iOS module
This commit is contained in:
217
iOS/Example/Pods/Nimble-Snapshots/DynamicSize/DynamicSizeSnapshot.swift
generated
Normal file
217
iOS/Example/Pods/Nimble-Snapshots/DynamicSize/DynamicSizeSnapshot.swift
generated
Normal file
@@ -0,0 +1,217 @@
|
||||
import Foundation
|
||||
import Nimble
|
||||
import QuartzCore
|
||||
import UIKit
|
||||
|
||||
public enum ResizeMode {
|
||||
case frame
|
||||
case constrains
|
||||
case block(resizeBlock: (UIView, CGSize) -> Void)
|
||||
case custom(viewResizer: ViewResizer)
|
||||
|
||||
func viewResizer() -> ViewResizer {
|
||||
switch self {
|
||||
case .frame:
|
||||
return FrameViewResizer()
|
||||
|
||||
case .constrains:
|
||||
return ConstraintViewResizer()
|
||||
|
||||
case .block(resizeBlock: let block):
|
||||
return BlockViewResizer(block: block)
|
||||
|
||||
case .custom(viewResizer: let resizer):
|
||||
return resizer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public protocol ViewResizer {
|
||||
func resize(view: UIView, for size: CGSize)
|
||||
}
|
||||
|
||||
struct FrameViewResizer: ViewResizer {
|
||||
func resize(view: UIView, for size: CGSize) {
|
||||
view.frame = CGRect(origin: .zero, size: size)
|
||||
view.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
struct BlockViewResizer: ViewResizer {
|
||||
|
||||
let resizeBlock: (UIView, CGSize) -> Void
|
||||
|
||||
init(block: @escaping (UIView, CGSize) -> Void) {
|
||||
self.resizeBlock = block
|
||||
}
|
||||
|
||||
func resize(view: UIView, for size: CGSize) {
|
||||
self.resizeBlock(view, size)
|
||||
}
|
||||
}
|
||||
|
||||
class ConstraintViewResizer: ViewResizer {
|
||||
|
||||
typealias SizeConstrainsWrapper = (heightConstrain: NSLayoutConstraint, widthConstrain: NSLayoutConstraint)
|
||||
|
||||
func resize(view: UIView, for size: CGSize) {
|
||||
let sizesConstrains = findConstrains(of: view)
|
||||
|
||||
sizesConstrains.heightConstrain.constant = size.height
|
||||
sizesConstrains.widthConstrain.constant = size.width
|
||||
|
||||
NSLayoutConstraint.activate([sizesConstrains.heightConstrain,
|
||||
sizesConstrains.widthConstrain])
|
||||
|
||||
view.layoutIfNeeded()
|
||||
|
||||
//iOS 9+ BUG: Before the first draw, iOS will not calculate the layout,
|
||||
// it add a _UITemporaryLayoutWidth equals to its bounds and create a conflict.
|
||||
// So to it do all the layout we create a Window and add it as subview
|
||||
if view.bounds.width != size.width || view.bounds.width != size.width {
|
||||
let window = UIWindow(frame: CGRect(origin: .zero, size: size))
|
||||
let viewController = UIViewController()
|
||||
viewController.view = UIView()
|
||||
viewController.view.addSubview(view)
|
||||
window.rootViewController = viewController
|
||||
window.makeKeyAndVisible()
|
||||
view.setNeedsLayout()
|
||||
view.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
func findConstrains(of view: UIView) -> SizeConstrainsWrapper {
|
||||
var height: NSLayoutConstraint!
|
||||
var width: NSLayoutConstraint!
|
||||
|
||||
let heightLayout = NSLayoutAttribute.height
|
||||
let widthLayout = NSLayoutAttribute.width
|
||||
let equalRelation = NSLayoutRelation.equal
|
||||
|
||||
for constrain in view.constraints {
|
||||
if constrain.firstAttribute == heightLayout &&
|
||||
constrain.relation == equalRelation && constrain.secondItem == nil {
|
||||
height = constrain
|
||||
}
|
||||
|
||||
if constrain.firstAttribute == widthLayout &&
|
||||
constrain.relation == equalRelation && constrain.secondItem == nil {
|
||||
width = constrain
|
||||
}
|
||||
}
|
||||
|
||||
if height == nil {
|
||||
height = NSLayoutConstraint(item: view, attribute: heightLayout, relatedBy: equalRelation, toItem: nil,
|
||||
attribute: heightLayout, multiplier: 1, constant: 0)
|
||||
view.addConstraint(height)
|
||||
}
|
||||
|
||||
if width == nil {
|
||||
width = NSLayoutConstraint(item: view, attribute: widthLayout, relatedBy: equalRelation, toItem: nil,
|
||||
attribute: widthLayout, multiplier: 1, constant: 0)
|
||||
view.addConstraint(width)
|
||||
}
|
||||
|
||||
return (height, width)
|
||||
}
|
||||
}
|
||||
|
||||
public struct DynamicSizeSnapshot {
|
||||
let name: String?
|
||||
let record: Bool
|
||||
let sizes: [String: CGSize]
|
||||
let resizeMode: ResizeMode
|
||||
|
||||
init(name: String?, record: Bool, sizes: [String: CGSize], resizeMode: ResizeMode) {
|
||||
self.name = name
|
||||
self.record = record
|
||||
self.sizes = sizes
|
||||
self.resizeMode = resizeMode
|
||||
}
|
||||
}
|
||||
|
||||
public func snapshot(_ name: String? = nil, sizes: [String: CGSize],
|
||||
resizeMode: ResizeMode = .frame) -> DynamicSizeSnapshot {
|
||||
return DynamicSizeSnapshot(name: name, record: false, sizes: sizes, resizeMode: resizeMode)
|
||||
}
|
||||
|
||||
public func haveValidDynamicSizeSnapshot(named name: String? = nil, sizes: [String: CGSize],
|
||||
isDeviceAgnostic: Bool = false, usesDrawRect: Bool = false,
|
||||
tolerance: CGFloat? = nil,
|
||||
resizeMode: ResizeMode = .frame) -> Predicate<Snapshotable> {
|
||||
return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in
|
||||
return performDynamicSizeSnapshotTest(name, sizes: sizes, isDeviceAgnostic: isDeviceAgnostic,
|
||||
usesDrawRect: usesDrawRect, actualExpression: actualExpression,
|
||||
failureMessage: failureMessage, tolerance: tolerance,
|
||||
isRecord: false, resizeMode: resizeMode)
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_parameter_count
|
||||
func performDynamicSizeSnapshotTest(_ name: String?, sizes: [String: CGSize], isDeviceAgnostic: Bool = false,
|
||||
usesDrawRect: Bool = false, actualExpression: Expression<Snapshotable>,
|
||||
failureMessage: FailureMessage, tolerance: CGFloat? = nil, isRecord: Bool,
|
||||
resizeMode: ResizeMode) -> Bool {
|
||||
// swiftlint:disable:next force_try force_unwrapping
|
||||
let instance = try! actualExpression.evaluate()!
|
||||
let testFileLocation = actualExpression.location.file
|
||||
let referenceImageDirectory = getDefaultReferenceDirectory(testFileLocation)
|
||||
let snapshotName = sanitizedTestName(name)
|
||||
let tolerance = tolerance ?? getTolerance()
|
||||
|
||||
let resizer = resizeMode.viewResizer()
|
||||
|
||||
let result = sizes.map { (sizeName, size) -> Bool in
|
||||
// swiftlint:disable:next force_unwrapping
|
||||
let view = instance.snapshotObject!
|
||||
|
||||
resizer.resize(view: view, for: size)
|
||||
|
||||
return FBSnapshotTest.compareSnapshot(instance, isDeviceAgnostic: isDeviceAgnostic, usesDrawRect: usesDrawRect,
|
||||
snapshot: "\(snapshotName) - \(sizeName)", record: isRecord,
|
||||
referenceDirectory: referenceImageDirectory, tolerance: tolerance,
|
||||
filename: actualExpression.location.file)
|
||||
}
|
||||
|
||||
if isRecord {
|
||||
if result.filter({ !$0 }).isEmpty {
|
||||
let name = name ?? snapshotName
|
||||
failureMessage.actualValue = "snapshot \(name) successfully recorded, replace recordSnapshot with a check"
|
||||
} else {
|
||||
failureMessage.actualValue = "expected to record a snapshot in \(String(describing: name))"
|
||||
}
|
||||
|
||||
return false
|
||||
} else {
|
||||
if !result.filter({ !$0 }).isEmpty {
|
||||
clearFailureMessage(failureMessage)
|
||||
failureMessage.actualValue = "expected a matching snapshot in \(snapshotName)"
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public func recordSnapshot(_ name: String? = nil, sizes: [String: CGSize],
|
||||
resizeMode: ResizeMode = .frame) -> DynamicSizeSnapshot {
|
||||
return DynamicSizeSnapshot(name: name, record: true, sizes: sizes, resizeMode: resizeMode)
|
||||
}
|
||||
|
||||
public func recordDynamicSizeSnapshot(named name: String? = nil, sizes: [String: CGSize],
|
||||
isDeviceAgnostic: Bool = false, usesDrawRect: Bool = false,
|
||||
resizeMode: ResizeMode = .frame) -> Predicate<Snapshotable> {
|
||||
return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in
|
||||
return performDynamicSizeSnapshotTest(name, sizes: sizes, isDeviceAgnostic: isDeviceAgnostic,
|
||||
usesDrawRect: usesDrawRect, actualExpression: actualExpression,
|
||||
failureMessage: failureMessage, isRecord: true, resizeMode: resizeMode)
|
||||
}
|
||||
}
|
||||
|
||||
public func == (lhs: Expectation<Snapshotable>, rhs: DynamicSizeSnapshot) {
|
||||
if rhs.record {
|
||||
lhs.to(recordDynamicSizeSnapshot(named: rhs.name, sizes: rhs.sizes, resizeMode: rhs.resizeMode))
|
||||
} else {
|
||||
lhs.to(haveValidDynamicSizeSnapshot(named: rhs.name, sizes: rhs.sizes, resizeMode: rhs.resizeMode))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user