diff --git a/.gitignore b/.gitignore index 3566e86..a729292 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ project.xcworkspace xcuserdata Examples/ -.DS_Store \ No newline at end of file +.DS_Store +Gemfile +Gemfile.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b722d..80241ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Beta ======= +# Next Release + +* Re-worked some internal API to allow for future updates +* Added `snp_prepareConstraints -> [Constraint]` which allows pre-building of constraints +* Added a fatal error to `and` when it is used after relation has been set + # 0.0.6 - February 11th, 2015 * Renamed `maker` to `make` in all block APIs \ No newline at end of file diff --git a/Snap.xcodeproj/project.pbxproj b/Snap.xcodeproj/project.pbxproj index d6151c3..70f4e6f 100644 --- a/Snap.xcodeproj/project.pbxproj +++ b/Snap.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + EEAED5481A8F56A500777EF9 /* Snap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEBCC9D819CC627D0083B827 /* Snap.framework */; }; + EEAED5491A8F56BF00777EF9 /* SnapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE91728C19CB304E007888CF /* SnapTests.swift */; }; EEBCC9F019CC64F80083B827 /* EdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9EF19CC64F70083B827 /* EdgeInsets.swift */; }; EEBCC9F219CC65050083B827 /* View+Snap.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9F119CC65040083B827 /* View+Snap.swift */; }; EEBCC9F419CC65110083B827 /* ConstraintAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9F319CC65110083B827 /* ConstraintAttributes.swift */; }; @@ -46,6 +48,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EEAED5481A8F56A500777EF9 /* Snap.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -233,6 +236,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EEAED5491A8F56BF00777EF9 /* SnapTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Snap/Constraint.swift b/Snap/Constraint.swift index c9fa8ae..59676ff 100644 --- a/Snap/Constraint.swift +++ b/Snap/Constraint.swift @@ -31,19 +31,24 @@ import AppKit * Constraint is a single item that defines all the properties for a single ConstraintMaker chain */ public class Constraint { - public var left: Constraint { return addConstraint(ConstraintAttributes.Left) } - public var top: Constraint { return addConstraint(ConstraintAttributes.Top) } - public var right: Constraint { return addConstraint(ConstraintAttributes.Right) } - public var bottom: Constraint { return addConstraint(ConstraintAttributes.Bottom) } - public var leading: Constraint { return addConstraint(ConstraintAttributes.Leading) } - public var trailing: Constraint { return addConstraint(ConstraintAttributes.Trailing) } - public var width: Constraint { return addConstraint(ConstraintAttributes.Width) } - public var height: Constraint { return addConstraint(ConstraintAttributes.Height) } - public var centerX: Constraint { return addConstraint(ConstraintAttributes.CenterX) } - public var centerY: Constraint { return addConstraint(ConstraintAttributes.CenterY) } - public var baseline: Constraint { return addConstraint(ConstraintAttributes.Baseline) } + public var left: Constraint { return self.addConstraint(ConstraintAttributes.Left) } + public var top: Constraint { return self.addConstraint(ConstraintAttributes.Top) } + public var right: Constraint { return self.addConstraint(ConstraintAttributes.Right) } + public var bottom: Constraint { return self.addConstraint(ConstraintAttributes.Bottom) } + public var leading: Constraint { return self.addConstraint(ConstraintAttributes.Leading) } + public var trailing: Constraint { return self.addConstraint(ConstraintAttributes.Trailing) } + public var width: Constraint { return self.addConstraint(ConstraintAttributes.Width) } + public var height: Constraint { return self.addConstraint(ConstraintAttributes.Height) } + public var centerX: Constraint { return self.addConstraint(ConstraintAttributes.CenterX) } + public var centerY: Constraint { return self.addConstraint(ConstraintAttributes.CenterY) } + public var baseline: Constraint { return self.addConstraint(ConstraintAttributes.Baseline) } - public var and: Constraint { return self } + public var and: Constraint { + if self.relation != nil { + fatalError("And is semantic only and can only be used before a relation is set.") + } + return self + } public var with: Constraint { return self } // MARK: initializer @@ -56,115 +61,115 @@ public class Constraint { // MARK: equalTo public func equalTo(other: ConstraintItem) -> Constraint { - return constrainTo(other, relation: .Equal) + return self.constrainTo(other, relation: .Equal) } public func equalTo(other: View) -> Constraint { - return constrainTo(other, relation: .Equal) + return self.constrainTo(other, relation: .Equal) } #if os(iOS) public func equalTo(other: UILayoutSupport) -> Constraint { - return constrainTo(other, relation: .Equal) + return self.constrainTo(other, relation: .Equal) } #endif public func equalTo(other: Float) -> Constraint { - return constrainTo(other, relation: .Equal) + return self.constrainTo(other, relation: .Equal) } public func equalTo(other: Double) -> Constraint { - return constrainTo(Float(other), relation: .Equal) + return self.constrainTo(Float(other), relation: .Equal) } public func equalTo(other: CGFloat) -> Constraint { - return constrainTo(Float(other), relation: .Equal) + return self.constrainTo(Float(other), relation: .Equal) } public func equalTo(other: Int) -> Constraint { - return constrainTo(Float(other), relation: .Equal) + return self.constrainTo(Float(other), relation: .Equal) } public func equalTo(other: UInt) -> Constraint { - return constrainTo(Float(other), relation: .Equal) + return self.constrainTo(Float(other), relation: .Equal) } public func equalTo(other: CGSize) -> Constraint { - return constrainTo(other, relation: .Equal) + return self.constrainTo(other, relation: .Equal) } public func equalTo(other: CGPoint) -> Constraint { - return constrainTo(other, relation: .Equal) + return self.constrainTo(other, relation: .Equal) } public func equalTo(other: EdgeInsets) -> Constraint { - return constrainTo(other, relation: .Equal) + return self.constrainTo(other, relation: .Equal) } // MARK: lessThanOrEqualTo public func lessThanOrEqualTo(other: ConstraintItem) -> Constraint { - return constrainTo(other, relation: .LessThanOrEqualTo) + return self.constrainTo(other, relation: .LessThanOrEqualTo) } public func lessThanOrEqualTo(other: View) -> Constraint { - return constrainTo(other, relation: .LessThanOrEqualTo) + return self.constrainTo(other, relation: .LessThanOrEqualTo) } #if os(iOS) public func lessThanOrEqualTo(other: UILayoutSupport) -> Constraint { - return constrainTo(other, relation: .LessThanOrEqualTo) + return self.constrainTo(other, relation: .LessThanOrEqualTo) } #endif public func lessThanOrEqualTo(other: Float) -> Constraint { - return constrainTo(other, relation: .LessThanOrEqualTo) + return self.constrainTo(other, relation: .LessThanOrEqualTo) } public func lessThanOrEqualTo(other: Double) -> Constraint { - return constrainTo(Float(other), relation: .LessThanOrEqualTo) + return self.constrainTo(Float(other), relation: .LessThanOrEqualTo) } public func lessThanOrEqualTo(other: CGFloat) -> Constraint { - return constrainTo(Float(other), relation: .LessThanOrEqualTo) + return self.constrainTo(Float(other), relation: .LessThanOrEqualTo) } public func lessThanOrEqualTo(other: Int) -> Constraint { - return constrainTo(Float(other), relation: .LessThanOrEqualTo) + return self.constrainTo(Float(other), relation: .LessThanOrEqualTo) } public func lessThanOrEqualTo(other: UInt) -> Constraint { - return constrainTo(Float(other), relation: .LessThanOrEqualTo) + return self.constrainTo(Float(other), relation: .LessThanOrEqualTo) } public func lessThanOrEqualTo(other: CGSize) -> Constraint { - return constrainTo(other, relation: .LessThanOrEqualTo) + return self.constrainTo(other, relation: .LessThanOrEqualTo) } public func lessThanOrEqualTo(other: CGPoint) -> Constraint { - return constrainTo(other, relation: .LessThanOrEqualTo) + return self.constrainTo(other, relation: .LessThanOrEqualTo) } public func lessThanOrEqualTo(other: EdgeInsets) -> Constraint { - return constrainTo(other, relation: .LessThanOrEqualTo) + return self.constrainTo(other, relation: .LessThanOrEqualTo) } // MARK: greaterThanOrEqualTo public func greaterThanOrEqualTo(other: ConstraintItem) -> Constraint { - return constrainTo(other, relation: .GreaterThanOrEqualTo) + return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } public func greaterThanOrEqualTo(other: View) -> Constraint { - return constrainTo(other, relation: .GreaterThanOrEqualTo) + return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } #if os(iOS) public func greaterThanOrEqualTo(other: UILayoutSupport) -> Constraint { - return constrainTo(other, relation: .GreaterThanOrEqualTo) + return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } #endif public func greaterThanOrEqualTo(other: Float) -> Constraint { - return constrainTo(other, relation: .GreaterThanOrEqualTo) + return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } public func greaterThanOrEqualTo(other: Double) -> Constraint { - return constrainTo(Float(other), relation: .GreaterThanOrEqualTo) + return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo) } public func greaterThanOrEqualTo(other: CGFloat) -> Constraint { - return constrainTo(Float(other), relation: .GreaterThanOrEqualTo) + return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo) } public func greaterThanOrEqualTo(other: Int) -> Constraint { - return constrainTo(Float(other), relation: .GreaterThanOrEqualTo) + return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo) } public func greaterThanOrEqualTo(other: UInt) -> Constraint { - return constrainTo(Float(other), relation: .GreaterThanOrEqualTo) + return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo) } public func greaterThanOrEqualTo(other: CGSize) -> Constraint { - return constrainTo(other, relation: .GreaterThanOrEqualTo) + return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } public func greaterThanOrEqualTo(other: CGPoint) -> Constraint { - return constrainTo(other, relation: .GreaterThanOrEqualTo) + return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } public func greaterThanOrEqualTo(other: EdgeInsets) -> Constraint { - return constrainTo(other, relation: .GreaterThanOrEqualTo) + return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } // MARK: multiplier @@ -282,11 +287,6 @@ public class Constraint { // MARK: internal internal func installOnView(updateExisting: Bool = false) -> Array { - if self.installedOnView != nil { - NSException(name: "Cannot Install Constraint", reason: "Already installed", userInfo: nil).raise() - return [] - } - var installOnView: View? = nil if self.toItem.view != nil { installOnView = Constraint.closestCommonSuperviewFromView(self.fromItem.view, toView: self.toItem.view) @@ -301,14 +301,22 @@ public class Constraint { installOnView = self.fromItem.view } - if installedOnView == nil { + if installOnView == nil { NSException(name: "Cannot Install Constraint", reason: "Missing superview", userInfo: nil).raise() return [] } } } - var layoutConstraints: Array = [] + if self.installedOnView != nil { + if self.installedOnView != installOnView { + NSException(name: "Cannot Install Constraint", reason: "Already installed on different view.", userInfo: nil).raise() + return [] + } + return self.installedLayoutConstraints?.allObjects as Array + } + + var newLayoutConstraints = Array() let layoutFromAttributes = self.fromItem.attributes.layoutAttributes let layoutToAttributes = self.toItem.attributes.layoutAttributes @@ -348,7 +356,7 @@ public class Constraint { // set constraint layoutConstraint.constraint = self - layoutConstraints.append(layoutConstraint) + newLayoutConstraints.append(layoutConstraint) } // special logic for updating @@ -356,11 +364,11 @@ public class Constraint { // get existing constraints for this view let existingLayoutConstraints = reverse(layoutFrom!.snp_installedLayoutConstraints) - // array that will contain only new layout constraints - var newLayoutConstraints = Array() - + // array that will contain only new layout constraints to keep + var newLayoutConstraintsToKeep = Array() + // begin looping - for layoutConstraint in layoutConstraints { + for layoutConstraint in newLayoutConstraints { // layout constraint that should be updated var updateLayoutConstraint: LayoutConstraint? = nil @@ -376,34 +384,45 @@ public class Constraint { if updateLayoutConstraint != nil { updateLayoutConstraint!.constant = layoutConstraint.constant } - // otherwise add this layout constraint to new list + // otherwise add this layout constraint to new keep list else { - newLayoutConstraints.append(layoutConstraint) + newLayoutConstraintsToKeep.append(layoutConstraint) } } - + // set constraints to only new ones - layoutConstraints = newLayoutConstraints + newLayoutConstraints = newLayoutConstraintsToKeep } // add constraints - installOnView!.addConstraints(layoutConstraints) + installOnView!.addConstraints(newLayoutConstraints) + // store which view this constraint was installed on self.installedOnView = installOnView + + // store which layout constraints are installed for this constraint self.installedLayoutConstraints = NSHashTable.weakObjectsHashTable() - for layoutConstraint in layoutConstraints { + for layoutConstraint in newLayoutConstraints { self.installedLayoutConstraints!.addObject(layoutConstraint) } - return layoutConstraints + // store the layout constraints against the installed on view + var layoutConstraints = Array(layoutFrom!.snp_installedLayoutConstraints) + layoutConstraints += newLayoutConstraints + layoutFrom!.snp_installedLayoutConstraints = layoutConstraints + + // return the new constraints + return newLayoutConstraints } internal func uninstallFromView() { if let view = self.installedOnView { // remove all installed layout constraints var layoutConstraintsToRemove = Array() - if let installedLayoutConstraints = self.installedLayoutConstraints?.allObjects as? Array { - layoutConstraintsToRemove += installedLayoutConstraints + if let allObjects = self.installedLayoutConstraints?.allObjects { + if let installedLayoutConstraints = allObjects as? Array { + layoutConstraintsToRemove += installedLayoutConstraints + } } if layoutConstraintsToRemove.count > 0 { @@ -490,19 +509,27 @@ public class Constraint { } private class func closestCommonSuperviewFromView(fromView: View?, toView: View?) -> View? { - var closestCommonSuperview: View? - var secondViewSuperview: View? = toView - while closestCommonSuperview == nil && secondViewSuperview != nil { - var firstViewSuperview = fromView - while closestCommonSuperview == nil && firstViewSuperview != nil { - if secondViewSuperview == firstViewSuperview { - closestCommonSuperview = secondViewSuperview + var views = NSMutableSet() + var fromView = fromView + var toView = toView + do { + if let view = toView { + if views.containsObject(view) { + return view } - firstViewSuperview = firstViewSuperview?.superview + views.addObject(view) + toView = view.superview } - secondViewSuperview = secondViewSuperview?.superview - } - return closestCommonSuperview + if let view = fromView { + if views.containsObject(view) { + return view + } + views.addObject(view) + fromView = view.superview + } + } while (fromView != nil || toView != nil) + + return nil } } diff --git a/Snap/ConstraintMaker.swift b/Snap/ConstraintMaker.swift index 2449ed9..49e03d2 100644 --- a/Snap/ConstraintMaker.swift +++ b/Snap/ConstraintMaker.swift @@ -31,21 +31,21 @@ import AppKit * ConstraintMaker is the maker in snap that gets all constraints kickstarted */ public class ConstraintMaker { - public var left: Constraint { return addConstraint(ConstraintAttributes.Left) } - public var top: Constraint { return addConstraint(ConstraintAttributes.Top) } - public var right: Constraint { return addConstraint(ConstraintAttributes.Right) } - public var bottom: Constraint { return addConstraint(ConstraintAttributes.Bottom) } - public var leading: Constraint { return addConstraint(ConstraintAttributes.Leading) } - public var trailing: Constraint { return addConstraint(ConstraintAttributes.Trailing) } - public var width: Constraint { return addConstraint(ConstraintAttributes.Width) } - public var height: Constraint { return addConstraint(ConstraintAttributes.Height) } - public var centerX: Constraint { return addConstraint(ConstraintAttributes.CenterX) } - public var centerY: Constraint { return addConstraint(ConstraintAttributes.CenterY) } - public var baseline: Constraint { return addConstraint(ConstraintAttributes.Baseline) } + public var left: Constraint { return self.addConstraint(ConstraintAttributes.Left) } + public var top: Constraint { return self.addConstraint(ConstraintAttributes.Top) } + public var right: Constraint { return self.addConstraint(ConstraintAttributes.Right) } + public var bottom: Constraint { return self.addConstraint(ConstraintAttributes.Bottom) } + public var leading: Constraint { return self.addConstraint(ConstraintAttributes.Leading) } + public var trailing: Constraint { return self.addConstraint(ConstraintAttributes.Trailing) } + public var width: Constraint { return self.addConstraint(ConstraintAttributes.Width) } + public var height: Constraint { return self.addConstraint(ConstraintAttributes.Height) } + public var centerX: Constraint { return self.addConstraint(ConstraintAttributes.CenterX) } + public var centerY: Constraint { return self.addConstraint(ConstraintAttributes.CenterY) } + public var baseline: Constraint { return self.addConstraint(ConstraintAttributes.Baseline) } - public var edges: Constraint { return addConstraint(ConstraintAttributes.Edges) } - public var size: Constraint { return addConstraint(ConstraintAttributes.Size) } - public var center: Constraint { return addConstraint(ConstraintAttributes.Center) } + public var edges: Constraint { return self.addConstraint(ConstraintAttributes.Edges) } + public var size: Constraint { return self.addConstraint(ConstraintAttributes.Size) } + public var center: Constraint { return self.addConstraint(ConstraintAttributes.Center) } init(view: View) { self.view = view @@ -61,24 +61,26 @@ public class ConstraintMaker { return constraint } - internal class func makeConstraints(view: View, block: (make: ConstraintMaker) -> ()) { - #if os(iOS) - view.setTranslatesAutoresizingMaskIntoConstraints(false) - #else - view.translatesAutoresizingMaskIntoConstraints = false - #endif + internal class func prepareConstraints(view: View, block: (make: ConstraintMaker) -> Void) -> Array { let maker = ConstraintMaker(view: view) block(make: maker) - - var layoutConstraints = view.snp_installedLayoutConstraints - for constraint in maker.constraints { - layoutConstraints += constraint.install() - } - - view.snp_installedLayoutConstraints = layoutConstraints + return maker.constraints } - internal class func remakeConstraints(view: View, block: (make: ConstraintMaker) -> ()) { + internal class func makeConstraints(view: View, block: (make: ConstraintMaker) -> Void) { + #if os(iOS) + view.setTranslatesAutoresizingMaskIntoConstraints(false) + #else + view.translatesAutoresizingMaskIntoConstraints = false + #endif + let maker = ConstraintMaker(view: view) + block(make: maker) + for constraint in maker.constraints { + constraint.installOnView(updateExisting: false) + } + } + + internal class func remakeConstraints(view: View, block: (make: ConstraintMaker) -> Void) { #if os(iOS) view.setTranslatesAutoresizingMaskIntoConstraints(false) #else @@ -87,20 +89,17 @@ public class ConstraintMaker { let maker = ConstraintMaker(view: view) block(make: maker) - var layoutConstraints: Array = view.snp_installedLayoutConstraints + var layoutConstraints = Array(view.snp_installedLayoutConstraints) for existingLayoutConstraint in layoutConstraints { - existingLayoutConstraint.constraint?.uninstall() + existingLayoutConstraint.constraint?.uninstallFromView() } - layoutConstraints = [] for constraint in maker.constraints { - layoutConstraints += constraint.install() + constraint.installOnView(updateExisting: false) } - - view.snp_installedLayoutConstraints = layoutConstraints } - internal class func updateConstraints(view: View, block: (make: ConstraintMaker) -> ()) { + internal class func updateConstraints(view: View, block: (make: ConstraintMaker) -> Void) { #if os(iOS) view.setTranslatesAutoresizingMaskIntoConstraints(false) #else @@ -109,19 +108,15 @@ public class ConstraintMaker { let maker = ConstraintMaker(view: view) block(make: maker) - var layoutConstraints = view.snp_installedLayoutConstraints for constraint in maker.constraints { - layoutConstraints += constraint.installOnView(updateExisting: true) + constraint.installOnView(updateExisting: true) } - - view.snp_installedLayoutConstraints = layoutConstraints } internal class func removeConstraints(view: View) { - for existingLayoutConstraint in view.snp_installedLayoutConstraints { - existingLayoutConstraint.constraint?.uninstall() + let existingLayoutConstraints = Array(view.snp_installedLayoutConstraints) + for existingLayoutConstraint in existingLayoutConstraints { + existingLayoutConstraint.constraint?.uninstallFromView() } - - view.snp_installedLayoutConstraints = [] } } \ No newline at end of file diff --git a/Snap/View+Snap.swift b/Snap/View+Snap.swift index ebb0c19..09d1bab 100644 --- a/Snap/View+Snap.swift +++ b/Snap/View+Snap.swift @@ -68,15 +68,19 @@ public extension View { public var snp_centerWithinMargins: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.CenterWithinMargins) } #endif - public func snp_makeConstraints(block: (make: ConstraintMaker) -> ()) { + public func snp_prepareConstraints(block: (make: ConstraintMaker) -> Void) -> Array { + return ConstraintMaker.prepareConstraints(self, block: block) + } + + public func snp_makeConstraints(block: (make: ConstraintMaker) -> Void) { ConstraintMaker.makeConstraints(self, block: block) } - public func snp_updateConstraints(block: (make: ConstraintMaker) -> ()) { + public func snp_updateConstraints(block: (make: ConstraintMaker) -> Void) { ConstraintMaker.updateConstraints(self, block: block) } - public func snp_remakeConstraints(block: (make: ConstraintMaker) -> ()) { + public func snp_remakeConstraints(block: (make: ConstraintMaker) -> Void) { ConstraintMaker.remakeConstraints(self, block: block) } @@ -88,11 +92,10 @@ public extension View { internal var snp_installedLayoutConstraints: Array { get { - var constraints = objc_getAssociatedObject(self, &installedLayoutConstraintsKey) as? Array - if constraints != nil { - return constraints! + if let constraints = objc_getAssociatedObject(self, &installedLayoutConstraintsKey) as? Array { + return constraints } - return [] + return Array() } set { objc_setAssociatedObject(self, &installedLayoutConstraintsKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) diff --git a/SnapTests/SnapTests.swift b/SnapTests/SnapTests.swift index 82665ad..50b41ca 100644 --- a/SnapTests/SnapTests.swift +++ b/SnapTests/SnapTests.swift @@ -8,9 +8,12 @@ import UIKit import XCTest +import Snap class SnapTests: XCTestCase { + let container = UIView() + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. @@ -21,16 +24,146 @@ class SnapTests: XCTestCase { super.tearDown() } - func testExample() { - // This is an example of a functional test case. - XCTAssert(true, "Pass") + func testMakeConstraints() { + let v1 = UIView() + let v2 = UIView() + self.container.addSubview(v1) + self.container.addSubview(v2) + + v1.snp_makeConstraints { (make) -> Void in + make.top.equalTo(v2.snp_top).offset(50) + make.left.equalTo(v2.snp_top).offset(50) + return + } + + XCTAssertEqual(self.container.constraints().count, 2, "Should have 2 constraints installed") + + v2.snp_makeConstraints { (make) -> Void in + make.edges.equalTo(v1) + return + } + + XCTAssertEqual(self.container.constraints().count, 6, "Should have 6 constraints installed") + } - func testPerformanceExample() { - // This is an example of a performance test case. - self.measureBlock() { - // Put the code you want to measure the time of here. + func testUpdateConstraints() { + let v1 = UIView() + let v2 = UIView() + self.container.addSubview(v1) + self.container.addSubview(v2) + + v1.snp_makeConstraints { (make) -> Void in + make.top.equalTo(v2.snp_top).offset(50) + make.left.equalTo(v2.snp_top).offset(50) + return } + + XCTAssertEqual(self.container.constraints().count, 2, "Should have 2 constraints installed") + + v1.snp_updateConstraints { (make) -> Void in + make.top.equalTo(v2.snp_top).offset(15) + return + } + + XCTAssertEqual(self.container.constraints().count, 2, "Should still have 2 constraints installed") + + } + + func testRemakeConstraints() { + let v1 = UIView() + let v2 = UIView() + self.container.addSubview(v1) + self.container.addSubview(v2) + + v1.snp_makeConstraints { (make) -> Void in + make.top.equalTo(v2.snp_top).offset(50) + make.left.equalTo(v2.snp_top).offset(50) + return + } + + XCTAssertEqual(self.container.constraints().count, 2, "Should have 2 constraints installed") + + v1.snp_remakeConstraints { (make) -> Void in + make.edges.equalTo(v2) + return + } + + XCTAssertEqual(self.container.constraints().count, 4, "Should have 4 constraints installed") + + } + + func testRemoveConstraints() { + let v1 = UIView() + let v2 = UIView() + self.container.addSubview(v1) + self.container.addSubview(v2) + + v1.snp_makeConstraints { (make) -> Void in + make.top.equalTo(v2.snp_top).offset(50) + make.left.equalTo(v2.snp_top).offset(50) + return + } + + XCTAssertEqual(self.container.constraints().count, 2, "Should have 2 constraints installed") + + v1.snp_removeConstraints() + + XCTAssertEqual(self.container.constraints().count, 0, "Should have 0 constraints installed") + + } + + func testPrepareConstraints() { + let v1 = UIView() + let v2 = UIView() + self.container.addSubview(v1) + self.container.addSubview(v2) + + let constraints = v1.snp_prepareConstraints { (make) -> Void in + make.edges.equalTo(v2) + return + } + + XCTAssertEqual(self.container.constraints().count, 0, "Should have 0 constraints installed") + + for constraint in constraints { + constraint.install() + } + + XCTAssertEqual(self.container.constraints().count, 4, "Should have 4 constraints installed") + + for constraint in constraints { + constraint.uninstall() + } + + XCTAssertEqual(self.container.constraints().count, 0, "Should have 0 constraints installed") + + } + + func testReinstallConstraints() { + let v1 = UIView() + let v2 = UIView() + self.container.addSubview(v1) + self.container.addSubview(v2) + + let constraints = v1.snp_prepareConstraints { (make) -> Void in + make.edges.equalTo(v2) + return + } + + XCTAssertEqual(self.container.constraints().count, 0, "Should have 0 constraints installed") + + for constraint in constraints { + constraint.install() + } + + XCTAssertEqual(self.container.constraints().count, 4, "Should have 4 constraints installed") + + for constraint in constraints { + constraint.install() + } + + XCTAssertEqual(self.container.constraints().count, 4, "Should have 0 constraints installed") } }