Authored by Jonas Budelmann

composite constraint tests

... ... @@ -79,6 +79,7 @@
DD52F1E6179CAACA005CD195 /* UIView+MASAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+MASAdditions.m"; sourceTree = "<group>"; };
DD52F1ED179CAAEE005CD195 /* Masonry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Masonry.h; sourceTree = "<group>"; };
DDE2653D179D24E600D48565 /* UIView+MASShorthandAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+MASShorthandAdditions.h"; sourceTree = "<group>"; };
DDF3875D179E8A2900178773 /* SpecHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpecHelpers.h; sourceTree = "<group>"; };
DE643A835A4447F4807FDBFA /* libPods-MasonryTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MasonryTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
... ... @@ -178,6 +179,7 @@
DD52F1D7179CAA78005CD195 /* Specs */ = {
isa = PBXGroup;
children = (
DDF3875D179E8A2900178773 /* SpecHelpers.h */,
DD52F1D8179CAA9C005CD195 /* MASCompositeConstraintSpec.m */,
DD52F1D9179CAA9C005CD195 /* MASViewConstraintSpec.m */,
);
... ...
... ... @@ -40,7 +40,7 @@
switch (self.type) {
case MASCompositeViewConstraintTypeEdges:
viewAttributes = @[
self.view.mas_left, self.view.mas_top,
self.view.mas_top, self.view.mas_left,
self.view.mas_bottom, self.view.mas_right
];
break;
... ... @@ -187,6 +187,12 @@
}];
}
#pragma mark - Semantic properties
- (id<MASConstraint>)with {
return self;
}
#pragma mark - MASConstraint
- (void)commit {
... ...
... ... @@ -32,6 +32,9 @@ typedef float MASLayoutPriority;
@property (nonatomic, copy, readonly) id<MASConstraint> (^greaterThanOrEqualTo)(id attr);
@property (nonatomic, copy, readonly) id<MASConstraint> (^lessThanOrEqualTo)(id attr);
//semantic properties
@property (nonatomic, copy, readonly) id<MASConstraint> with;
- (void)commit;
@end
... ...
... ... @@ -225,6 +225,12 @@
};
}
#pragma mark - Semantic properties
- (id<MASConstraint>)with {
return self;
}
#pragma mark - MASConstraint
- (void)commit {
... ...
... ... @@ -66,7 +66,6 @@
DD52F21E179CAD57005CD195 = {
isa = PBXGroup;
children = (
DD52F26D179CBA05005CD195 /* libMasonry.a */,
DD52F230179CAD57005CD195 /* MasonryExamples */,
DD52F229179CAD57005CD195 /* Frameworks */,
DD52F228179CAD57005CD195 /* Products */,
... ... @@ -84,6 +83,7 @@
DD52F229179CAD57005CD195 /* Frameworks */ = {
isa = PBXGroup;
children = (
DD52F26D179CBA05005CD195 /* libMasonry.a */,
DD52F22A179CAD57005CD195 /* UIKit.framework */,
DD52F22C179CAD57005CD195 /* Foundation.framework */,
DD52F22E179CAD57005CD195 /* CoreGraphics.framework */,
... ...
... ... @@ -34,23 +34,26 @@
UIView *superview = self;
int padding = 10;
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.greaterThanOrEqualTo(superview.mas_top).offset(padding);
make.left.equalTo(superview.mas_left).offset(padding);
make.bottom.equalTo(view3.mas_top).offset(-padding);
make.right.equalTo(view2.mas_left).offset(-padding);
make.width.equalTo(view2.mas_width);
//if you want to use Masonry without the mas_ prefix
//define MAS_SHORTHAND before importing Masonry.h see MasonryExamples-Prefix.pch
[view1 makeConstraints:^(MASConstraintMaker *make) {
make.top.greaterThanOrEqualTo(superview.top).offset(padding);
make.left.equalTo(superview.left).offset(padding);
make.bottom.equalTo(view3.top).offset(-padding);
make.right.equalTo(view2.left).offset(-padding);
make.width.equalTo(view2.width);
//you can chain same attribute
make.height
.equalTo(view2.mas_height)
.equalTo(view3.mas_height);
.equalTo(view2.height)
.equalTo(view3.height);
}];
//with is semantic and option
[view2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).offset(padding);
make.left.equalTo(view1.mas_right).offset(padding);
make.top.equalTo(superview.mas_top).with.offset(padding); //with with
make.left.equalTo(view1.mas_right).offset(padding); //without with
make.bottom.equalTo(view3.mas_top).offset(-padding);
make.right.equalTo(superview.mas_right).offset(-padding);
make.width.equalTo(view1.mas_width);
... ...
... ... @@ -7,53 +7,112 @@
//
#import "MASCompositeConstraint.h"
#import "MASViewConstraint.h"
#import "SpecHelpers.h"
@interface MASCompositeConstraint () <MASConstraintDelegate>
@property (nonatomic, strong) NSMutableArray *completedChildConstraints;
@property (nonatomic, strong) NSMutableArray *currentChildConstraints;
@property (nonatomic, assign) BOOL added;
@end
@interface MASViewConstraint ()
@property (nonatomic, assign) CGFloat layoutConstant;
@end
SpecBegin(MASCompositeConstraint)
__block MASCompositeConstraint *composite;
__block id<MASConstraintDelegate> delegate;
it(@"should create centerY and centerX children", ^{
MASCompositeConstraint *composite = createCompositeWithType(MASCompositeViewConstraintTypeCenter);
expect(composite.currentChildConstraints).to.haveCountOf(2);
MASViewConstraint *viewConstraint = composite.currentChildConstraints[0];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeCenterX);
beforeEach(^{
delegate = mockProtocol(@protocol(MASConstraintDelegate));
viewConstraint = composite.currentChildConstraints[1];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeCenterY);
});
describe(@"commit", ^{
it(@"should create top, left, bottom, right children", ^{
UIView *newView = UIView.new;
MASCompositeConstraint *composite = createCompositeWithType(MASCompositeViewConstraintTypeEdges);
composite.equalTo(newView);
});
expect(composite.completedChildConstraints).to.haveCountOf(4);
//top
MASViewConstraint *viewConstraint = composite.completedChildConstraints[0];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeTop);
//left
viewConstraint = composite.completedChildConstraints[1];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeLeft);
describe(@"centering", ^{
beforeEach(^{
composite = [[MASCompositeConstraint alloc] initWithView:mock(UIView.class) type:MASCompositeViewConstraintTypeCenter];
composite.delegate = delegate;
});
xit(@"should forward to children", ^{});
//bottom
viewConstraint = composite.completedChildConstraints[2];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeBottom);
//right
viewConstraint = composite.completedChildConstraints[3];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeRight);
});
describe(@"sizing", ^{
beforeEach(^{
composite = [[MASCompositeConstraint alloc] initWithView:mock(UIView.class) type:MASCompositeViewConstraintTypeCenter];
composite.delegate = delegate;
});
xit(@"should forward to children", ^{});
it(@"should create width and height children", ^{
MASCompositeConstraint *composite = createCompositeWithType(MASCompositeViewConstraintTypeSize);
expect(composite.currentChildConstraints).to.haveCountOf(2);
MASViewConstraint *viewConstraint = composite.currentChildConstraints[0];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeWidth);
viewConstraint = composite.currentChildConstraints[1];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeHeight);
});
describe(@"alignment", ^{
beforeEach(^{
composite = [[MASCompositeConstraint alloc] initWithView:mock(UIView.class) type:MASCompositeViewConstraintTypeCenter];
composite.delegate = delegate;
});
xit(@"should forward to children", ^{});
it(@"should complete children", ^{
UIView *view = UIView.new;
MASCompositeConstraint *composite = createCompositeWithType(MASCompositeViewConstraintTypeSize);
composite.equalTo(view).sizeOffset(CGSizeMake(90, 30));
[verify(composite.delegate) addConstraint:(id)composite];
expect(composite.completedChildConstraints).to.haveCountOf(2);
expect(composite.currentChildConstraints).to.haveCountOf(2);
MASViewConstraint *viewConstraint = composite.completedChildConstraints[0];
expect(viewConstraint.secondViewAttribute.view).to.beIdenticalTo(view);
expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeWidth);
expect(viewConstraint.layoutConstant).to.equal(90);
viewConstraint = composite.completedChildConstraints[1];
expect(viewConstraint.secondViewAttribute.view).to.beIdenticalTo(view);
expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeHeight);
expect(viewConstraint.layoutConstant).to.equal(30);
composite.greaterThanOrEqualTo(@6);
expect(composite.completedChildConstraints).to.haveCountOf(4);
expect(composite.currentChildConstraints).to.haveCountOf(2);
viewConstraint = composite.completedChildConstraints[2];
expect(viewConstraint.secondViewAttribute.view).to.beNil();
expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(0);
expect(viewConstraint.layoutConstant).to.equal(6);
viewConstraint = composite.completedChildConstraints[2];
expect(viewConstraint.secondViewAttribute.view).to.beNil();
expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(0);
expect(viewConstraint.layoutConstant).to.equal(6);
});
SpecEnd
\ No newline at end of file
... ...
... ... @@ -8,6 +8,7 @@
#import "MASViewConstraint.h"
#import "MASConstraint.h"
#import "SpecHelpers.h"
@interface MASViewConstraint ()
... ... @@ -24,22 +25,15 @@ SpecBegin(MASViewConstraint)
__block UIView *superview;
__block MASViewConstraint *constraint;
__block id<MASConstraintDelegate> delegate;
__block MASViewAttribute *secondViewAttribute;
beforeEach(^{
superview = mock(UIView.class);
UIView *secondView = mock(UIView.class);
[given(secondView.superview) willReturn:superview];
secondViewAttribute = [[MASViewAttribute alloc] initWithView:secondView layoutAttribute:NSLayoutAttributeHeight];
delegate = mockProtocol(@protocol(MASConstraintDelegate));
UIView *firstView = mock(UIView.class);
[given(firstView.superview) willReturn:superview];
MASViewAttribute *firstViewAttribute = [[MASViewAttribute alloc] initWithView:firstView layoutAttribute:NSLayoutAttributeWidth];
constraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:firstViewAttribute];
constraint.delegate = delegate;
superview = UIView.new;
constraint = createConstraintWithLayoutAttribute(NSLayoutAttributeWidth);
[superview addSubview:constraint.firstViewAttribute.view];
secondViewAttribute = createViewAttribute(NSLayoutAttributeHeight);
[superview addSubview:secondViewAttribute.view];
});
describe(@"equality chaining", ^{
... ... @@ -47,7 +41,7 @@ describe(@"equality chaining", ^{
it(@"should return same constraint when encountering equal for first time", ^{
MASViewConstraint *newConstraint = constraint.equalTo(secondViewAttribute);
[verify(delegate) addConstraint:(id)constraint];
[verify(constraint.delegate) addConstraint:(id)constraint];
expect(newConstraint).to.beIdenticalTo(constraint);
expect(constraint.secondViewAttribute).to.beIdenticalTo(secondViewAttribute);
expect(constraint.layoutRelation).to.equal(NSLayoutRelationEqual);
... ... @@ -57,15 +51,15 @@ describe(@"equality chaining", ^{
constraint.greaterThanOrEqualTo(secondViewAttribute);
MASViewConstraint *newConstraint = constraint.equalTo(secondViewAttribute);
[verify(delegate) addConstraint:(id)constraint];
[verify(delegate) addConstraint:(id)newConstraint];
[verify(constraint.delegate) addConstraint:(id)constraint];
[verify(constraint.delegate) addConstraint:(id)newConstraint];
expect(newConstraint).notTo.beIdenticalTo(constraint);
});
it(@"should return same constraint when encountering greaterThanOrEqual for first time", ^{
MASViewConstraint *newConstraint = constraint.greaterThanOrEqualTo(secondViewAttribute);
[verify(delegate) addConstraint:(id)constraint];
[verify(constraint.delegate) addConstraint:(id)constraint];
expect(newConstraint).to.beIdenticalTo(constraint);
expect(constraint.secondViewAttribute).to.beIdenticalTo(secondViewAttribute);
expect(constraint.layoutRelation).to.equal(NSLayoutRelationGreaterThanOrEqual);
... ... @@ -75,15 +69,15 @@ describe(@"equality chaining", ^{
constraint.lessThanOrEqualTo(secondViewAttribute);
MASViewConstraint *newConstraint = constraint.greaterThanOrEqualTo(secondViewAttribute);
[verify(delegate) addConstraint:(id)constraint];
[verify(delegate) addConstraint:(id)newConstraint];
[verify(constraint.delegate) addConstraint:(id)constraint];
[verify(constraint.delegate) addConstraint:(id)newConstraint];
expect(newConstraint).notTo.beIdenticalTo(constraint);
});
it(@"should return same constraint when encountering lessThanOrEqual for first time", ^{
MASViewConstraint *newConstraint = constraint.lessThanOrEqualTo(secondViewAttribute);
[verify(delegate) addConstraint:(id)constraint];
[verify(constraint.delegate) addConstraint:(id)constraint];
expect(newConstraint).to.beIdenticalTo(constraint);
expect(constraint.secondViewAttribute).to.beIdenticalTo(secondViewAttribute);
expect(constraint.layoutRelation).to.equal(NSLayoutRelationLessThanOrEqual);
... ... @@ -93,8 +87,8 @@ describe(@"equality chaining", ^{
constraint.equalTo(secondViewAttribute);
MASViewConstraint *newConstraint = constraint.lessThanOrEqualTo(secondViewAttribute);
[verify(delegate) addConstraint:(id)constraint];
[verify(delegate) addConstraint:(id)newConstraint];
[verify(constraint.delegate) addConstraint:(id)constraint];
[verify(constraint.delegate) addConstraint:(id)newConstraint];
expect(newConstraint).notTo.beIdenticalTo(constraint);
});
... ... @@ -122,6 +116,14 @@ describe(@"equality chaining", ^{
}).to.raise(@"NSInternalInconsistencyException");
});
it(@"should accept view object", ^{
UIView *view = UIView.new;
constraint.equalTo(view);
expect(constraint.secondViewAttribute.view).to.beIdenticalTo(view);
expect(constraint.firstViewAttribute.layoutAttribute).to.equal(constraint.secondViewAttribute.layoutAttribute);
});
xit(@"should create composite when passed array of views", ^{
});
... ... @@ -145,11 +147,55 @@ describe(@"multiplier & constant", ^{
expect(constraint.layoutConstraint.constant).to.equal(10);
});
xit(@"should update sides only", ^{});
it(@"should update sides offset only", ^{
MASViewConstraint *centerY = createConstraintWithLayoutAttribute(NSLayoutAttributeCenterY);
centerY.insets(UIEdgeInsetsMake(10, 10, 10, 10));
expect(centerY.layoutConstant).to.equal(0);
MASViewConstraint *top = createConstraintWithLayoutAttribute(NSLayoutAttributeTop);
top.insets(UIEdgeInsetsMake(15, 10, 10, 10));
expect(top.layoutConstant).to.equal(15);
MASViewConstraint *left = createConstraintWithLayoutAttribute(NSLayoutAttributeLeft);
left.insets(UIEdgeInsetsMake(10, 15, 10, 10));
expect(left.layoutConstant).to.equal(15);
MASViewConstraint *bottom = createConstraintWithLayoutAttribute(NSLayoutAttributeBottom);
bottom.insets(UIEdgeInsetsMake(10, 10, 15, 10));
expect(bottom.layoutConstant).to.equal(-15);
MASViewConstraint *right = createConstraintWithLayoutAttribute(NSLayoutAttributeRight);
right.insets(UIEdgeInsetsMake(10, 10, 10, 15));
expect(right.layoutConstant).to.equal(-15);
});
xit(@"should update center only", ^{});
it(@"should update center offset only", ^{
MASViewConstraint *width = createConstraintWithLayoutAttribute(NSLayoutAttributeWidth);
width.centerOffset(CGPointMake(-20, -10));
expect(width.layoutConstant).to.equal(0);
MASViewConstraint *centerX = createConstraintWithLayoutAttribute(NSLayoutAttributeCenterX);
centerX.centerOffset(CGPointMake(-20, -10));
expect(centerX.layoutConstant).to.equal(-20);
MASViewConstraint *centerY = createConstraintWithLayoutAttribute(NSLayoutAttributeCenterY);
centerY.centerOffset(CGPointMake(-20, -10));
expect(centerY.layoutConstant).to.equal(-10);
});
xit(@"should update size only", ^{});
it(@"should update size offset only", ^{
MASViewConstraint *bottom = createConstraintWithLayoutAttribute(NSLayoutAttributeBottom);
bottom.sizeOffset(CGSizeMake(-40, 55));
expect(bottom.layoutConstant).to.equal(0);
MASViewConstraint *width = createConstraintWithLayoutAttribute(NSLayoutAttributeWidth);
width.sizeOffset(CGSizeMake(-40, 55));
expect(width.layoutConstant).to.equal(-40);
MASViewConstraint *height = createConstraintWithLayoutAttribute(NSLayoutAttributeHeight);
height.sizeOffset(CGSizeMake(-40, 55));
expect(height.layoutConstant).to.equal(55);
});
});
describe(@"commit", ^{
... ... @@ -169,8 +215,8 @@ describe(@"commit", ^{
expect(constraint.layoutConstraint.constant).to.equal(10);
expect(constraint.layoutConstraint.priority).to.equal(345);
expect(constraint.layoutConstraint.multiplier).to.equal(0.5);
[verify(superview) addConstraint:constraint.layoutConstraint];
expect(superview.constraints[0]).to.beIdenticalTo(constraint.layoutConstraint);
});
});
... ...
//
// SpecHelpers.h
// Masonry
//
// Created by Jonas Budelmann on 23/07/13.
// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
//
#import "MASCompositeConstraint.h"
#import "MASViewAttribute.h"
#import "MASViewConstraint.h"
static id (^createViewAttribute)(NSLayoutAttribute layoutAttribute) = ^id(NSLayoutAttribute layoutAttribute) {
UIView *view = UIView.new;
MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:view layoutAttribute:layoutAttribute];
return viewAttribute;
};
static id (^createConstraintWithLayoutAttribute)(NSLayoutAttribute layoutAttribute) = ^id(NSLayoutAttribute layoutAttribute) {
id delegate = mockProtocol(@protocol(MASConstraintDelegate));
MASViewConstraint *constraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:createViewAttribute(layoutAttribute)];
constraint.delegate = delegate;
return constraint;
};
static id(^createCompositeWithType)(MASCompositeViewConstraintType type) = ^id(MASCompositeViewConstraintType type){
id delegate = mockProtocol(@protocol(MASConstraintDelegate));
UIView *view = UIView.new;
MASCompositeConstraint *composite = [[MASCompositeConstraint alloc] initWithView:view type:type];
composite.delegate = delegate;
return composite;
};
\ No newline at end of file
... ...