Authored by Jonas Budelmann

add attribute chaining unit tests

... ... @@ -87,16 +87,6 @@
};
}
#pragma mark - Semantic properties
- (MASConstraint *)with {
return self;
}
- (MASConstraint *)and {
return self;
}
#pragma mark - attribute chaining
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
... ... @@ -104,50 +94,6 @@
return self;
}
- (MASConstraint *)left {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}
- (MASConstraint *)top {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
}
- (MASConstraint *)right {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeRight];
}
- (MASConstraint *)bottom {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBottom];
}
- (MASConstraint *)leading {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeading];
}
- (MASConstraint *)trailing {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTrailing];
}
- (MASConstraint *)width {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeWidth];
}
- (MASConstraint *)height {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];
}
- (MASConstraint *)centerX {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterX];
}
- (MASConstraint *)centerY {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterY];
}
- (MASConstraint *)baseline {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBaseline];
}
#pragma mark - Animator proxy
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
... ...
... ... @@ -45,6 +45,11 @@
*/
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation;
/**
* Override to set a custom chaining behaviour
*/
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
@end
... ... @@ -56,4 +61,6 @@
*/
- (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint;
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
@end
\ No newline at end of file
... ...
... ... @@ -223,6 +223,4 @@
*/
- (MASConstraint * (^)(id offset))mas_offset;
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
@end
... ...
... ... @@ -8,7 +8,7 @@
#import "MASConstraint.h"
#import "MASConstraint+Private.h"
#define methodNotImplemented() \
#define MASMethodNotImplemented() \
@throw [NSException exceptionWithName:NSInternalInconsistencyException \
reason:[NSString stringWithFormat:@"You must override %@ in a subclass.", NSStringFromSelector(_cmd)] \
userInfo:nil]
... ... @@ -154,58 +154,88 @@
return self;
}
#pragma mark - Abstract
- (MASConstraint *)and {
return self;
}
- (MASConstraint * (^)(CGFloat multiplier))multipliedBy { methodNotImplemented(); }
#pragma mark - Chaining
- (MASConstraint * (^)(CGFloat divider))dividedBy { methodNotImplemented(); }
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
MASMethodNotImplemented();
}
- (MASConstraint * (^)(MASLayoutPriority priority))priority { methodNotImplemented(); }
- (MASConstraint *)left {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}
- (MASConstraint *)top {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
}
- (MASConstraint *)right {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeRight];
}
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation { methodNotImplemented(); }
- (MASConstraint *)bottom {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBottom];
}
- (MASConstraint *)and { methodNotImplemented(); }
- (MASConstraint *)leading {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeading];
}
- (MASConstraint *)left { methodNotImplemented(); }
- (MASConstraint *)trailing {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTrailing];
}
- (MASConstraint *)top { methodNotImplemented(); }
- (MASConstraint *)width {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeWidth];
}
- (MASConstraint *)right { methodNotImplemented(); }
- (MASConstraint *)height {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];
}
- (MASConstraint *)bottom { methodNotImplemented(); }
- (MASConstraint *)centerX {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterX];
}
- (MASConstraint *)leading { methodNotImplemented(); }
- (MASConstraint *)centerY {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterY];
}
- (MASConstraint *)trailing { methodNotImplemented(); }
- (MASConstraint *)baseline {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBaseline];
}
- (MASConstraint *)width { methodNotImplemented(); }
#pragma mark - Abstract
- (MASConstraint *)height { methodNotImplemented(); }
- (MASConstraint * (^)(CGFloat multiplier))multipliedBy { MASMethodNotImplemented(); }
- (MASConstraint *)centerX { methodNotImplemented(); }
- (MASConstraint * (^)(CGFloat divider))dividedBy { MASMethodNotImplemented(); }
- (MASConstraint *)centerY { methodNotImplemented(); }
- (MASConstraint * (^)(MASLayoutPriority priority))priority { MASMethodNotImplemented(); }
- (MASConstraint *)baseline { methodNotImplemented(); }
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation { MASMethodNotImplemented(); }
- (MASConstraint * (^)(id key))key { methodNotImplemented(); }
- (MASConstraint * (^)(id key))key { MASMethodNotImplemented(); }
- (void)setInsets:(MASEdgeInsets)insets { methodNotImplemented(); }
- (void)setInsets:(MASEdgeInsets)insets { MASMethodNotImplemented(); }
- (void)setSizeOffset:(CGSize)sizeOffset { methodNotImplemented(); }
- (void)setSizeOffset:(CGSize)sizeOffset { MASMethodNotImplemented(); }
- (void)setCenterOffset:(CGPoint)centerOffset { methodNotImplemented(); }
- (void)setCenterOffset:(CGPoint)centerOffset { MASMethodNotImplemented(); }
- (void)setOffset:(CGFloat)offset { methodNotImplemented(); }
- (void)setOffset:(CGFloat)offset { MASMethodNotImplemented(); }
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
- (MASConstraint *)animator { methodNotImplemented(); }
- (MASConstraint *)animator { MASMethodNotImplemented(); }
#endif
- (void)install { methodNotImplemented(); }
- (void)install { MASMethodNotImplemented(); }
- (void)uninstall { methodNotImplemented(); }
- (void)uninstall { MASMethodNotImplemented(); }
@end
... ...
... ... @@ -190,51 +190,6 @@ static char kInstalledConstraintsKey;
#pragma mark - attribute chaining
- (MASConstraint *)left {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}
- (MASConstraint *)top {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
}
- (MASConstraint *)right {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeRight];
}
- (MASConstraint *)bottom {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBottom];
}
- (MASConstraint *)leading {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeading];
}
- (MASConstraint *)trailing {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTrailing];
}
- (MASConstraint *)width {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeWidth];
}
- (MASConstraint *)height {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];
}
- (MASConstraint *)centerX {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterX];
}
- (MASConstraint *)centerY {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeCenterY];
}
- (MASConstraint *)baseline {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBaseline];
}
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
NSAssert(!self.hasLayoutRelation, @"Attributes should be chained before defining the constraint relation");
... ...
... ... @@ -5,9 +5,9 @@
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#define EXP_SHORTHAND
#import "XCTest+Spec.h"
#define EXP_SHORTHAND
#import "Expecta.h"
#import "MASUtilities.h"
... ...
... ... @@ -152,4 +152,25 @@ SpecBegin(MASCompositeConstraint) {
expect(superview.constraints).to.haveCountOf(0);
}
- (void)testAttributeChainingShouldCallDelegate {
NSArray *children = @[
[[MASViewConstraint alloc] initWithFirstViewAttribute:view.mas_left],
[[MASViewConstraint alloc] initWithFirstViewAttribute:view.mas_right]
];
composite = [[MASCompositeConstraint alloc] initWithChildren:children];
composite.delegate = delegate;
expect(composite.childConstraints.count).to.equal(2);
MASConstraint *result = (id)composite.and.bottom;
expect(result).to.beIdenticalTo(composite);
expect(delegate.chainedConstraints).to.equal(@[composite]);
expect(composite.childConstraints.count).to.equal(3);
MASViewConstraint *newChild = composite.childConstraints[2];
expect(newChild.firstViewAttribute.layoutAttribute).to.equal(@(NSLayoutAttributeBottom));
expect(newChild.delegate).to.beIdenticalTo(composite);
}
SpecEnd
\ No newline at end of file
... ...
... ... @@ -11,5 +11,6 @@
@interface MASConstraintDelegateMock : NSObject <MASConstraintDelegate>
@property (nonatomic, strong) NSMutableArray *constraints;
@property (nonatomic, strong) NSMutableArray *chainedConstraints;
@end
... ...
... ... @@ -7,6 +7,7 @@
//
#import "MASConstraintDelegateMock.h"
#import "MASViewConstraint.h"
@implementation MASConstraintDelegateMock
... ... @@ -15,6 +16,7 @@
if (!self) return nil;
self.constraints = NSMutableArray.new;
self.chainedConstraints = NSMutableArray.new;
return self;
}
... ... @@ -23,4 +25,11 @@
[self.constraints replaceObjectAtIndex:[self.constraints indexOfObject:constraint] withObject:replacementConstraint];
}
- (id)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
[self.chainedConstraints addObject:constraint];
MASViewConstraint *viewConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:[[MASViewAttribute alloc] initWithView:nil layoutAttribute:layoutAttribute]];
return viewConstraint;
}
@end
... ...
... ... @@ -209,4 +209,46 @@ SpecBegin(MASConstraintMaker) {
expect(maker.centerY).notTo.beIdenticalTo(maker.centerY);
}
- (void)testAttributeChainingWithComposite {
composite = (MASCompositeConstraint *)maker.size;
expect(maker.constraints.count).to.equal(1);
expect(composite.childConstraints.count).to.equal(2);
composite = (id)composite.left;
expect(maker.constraints.count).to.equal(1);
expect(composite.childConstraints.count).to.equal(3);
MASViewConstraint *viewConstraint = composite.childConstraints[2];
expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeLeft);
expect(viewConstraint.delegate).to.beIdenticalTo(composite);
}
- (void)testAttributeChainingWithViewConstraint {
MASViewConstraint *viewConstraint = (MASViewConstraint *)maker.width;
expect(maker.constraints.count).to.equal(1);
expect(viewConstraint).to.beIdenticalTo(maker.constraints[0]);
expect(viewConstraint.delegate).to.beIdenticalTo(maker);
composite = (id)viewConstraint.height;
expect(composite).to.beKindOf(MASCompositeConstraint.class);
expect(maker.constraints.count).to.equal(1);
expect(composite).to.beIdenticalTo(maker.constraints[0]);
expect(composite.delegate).to.beIdenticalTo(maker);
expect(viewConstraint.delegate).to.beIdenticalTo(composite);
MASViewConstraint *childConstraint = composite.childConstraints[0];
expect(childConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
expect(childConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeWidth);
expect(childConstraint.delegate).to.beIdenticalTo(composite);
expect(childConstraint).to.beIdenticalTo(viewConstraint);
childConstraint = composite.childConstraints[1];
expect(childConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
expect(childConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeHeight);
expect(childConstraint.delegate).to.beIdenticalTo(composite);
}
SpecEnd
\ No newline at end of file
... ...
... ... @@ -509,4 +509,19 @@ SpecBegin(MASViewConstraint) {
expect(superview.constraints).to.haveCountOf(0);
}
- (void)testAttributeChainingShouldNotHaveRelation {
MASViewAttribute *secondViewAttribute = otherView.mas_top;
constraint.lessThanOrEqualTo(secondViewAttribute);
expect(^{
id result = constraint.bottom;
}).to.raise(@"NSInternalInconsistencyException");
}
- (void)testAttributeChainingShouldCallDelegate {
MASViewConstraint *result = (id)constraint.and.bottom;
expect(result.firstViewAttribute.layoutAttribute).to.equal(@(NSLayoutAttributeBottom));
expect(delegate.chainedConstraints).to.equal(@[constraint]);
}
SpecEnd
\ No newline at end of file
... ...