Source

VeriJSON / VeriJSONTests / VeriJSONTests.m

dcutting c99eef9 
dcutting caf46ee 
dcutting 5e35de1 
dcutting c44dc2d 






dcutting caf46ee 
dcutting 94e7095 


dcutting caf46ee 
dcutting 94e7095 


dcutting c44dc2d 
dcutting d3f2985 
dcutting c99eef9 
dcutting c44dc2d 


dcutting caf46ee 
dcutting c44dc2d 
dcutting d3f2985 
dcutting c99eef9 
dcutting c44dc2d 

dcutting caf46ee 

dcutting d3f2985 
dcutting c99eef9 
dcutting caf46ee 

dcutting 1983421 
dcutting 9e123e4 
dcutting caf46ee 
dcutting d3f2985 
dcutting c99eef9 
dcutting caf46ee 

dcutting 1983421 


dcutting d3f2985 
dcutting c99eef9 
dcutting 1983421 

dcutting df43144 


dcutting d3f2985 
dcutting c99eef9 
dcutting df43144 




dcutting d3f2985 
dcutting c99eef9 
dcutting df43144 


dcutting d3f2985 


dcutting c99eef9 
dcutting d3f2985 


dcutting df43144 
dcutting d3f2985 

dcutting c99eef9 
dcutting df43144 

dcutting 3ac85e9 



dcutting c99eef9 
dcutting 3ac85e9 

dcutting 4463c81 



dcutting c99eef9 
dcutting 4463c81 





dcutting c99eef9 
dcutting 4463c81 

dcutting 0dfc04d 



dcutting c99eef9 
dcutting 0dfc04d 

dcutting f1ebc8f 



dcutting c99eef9 
dcutting f1ebc8f 





dcutting c99eef9 
dcutting f1ebc8f 





dcutting c99eef9 
dcutting f1ebc8f 

dcutting 1a71ced 



dcutting c99eef9 
dcutting 1a71ced 

dcutting 0dfc04d 



dcutting c99eef9 
dcutting 0dfc04d 

dcutting 5cc1d6d 









dcutting c99eef9 
dcutting 5cc1d6d 




dcutting c99eef9 
dcutting 5cc1d6d 




dcutting c99eef9 
dcutting 5cc1d6d 




dcutting c99eef9 
dcutting 5cc1d6d 


dcutting 5e35de1 
dcutting a10e65a 
dcutting 5e35de1 
dcutting a10e65a 
dcutting 5e35de1 






dcutting a10e65a 










dcutting 753967c 










dcutting 5e35de1 

dcutting b323e3e 






dcutting 75cdfae 






dcutting 994324a 





dcutting c3f8d7d 
dcutting 517a81c 






dcutting c3f8d7d 






dcutting 563414c 






dcutting d981b65 













dcutting d2adcb8 



















dcutting 14b7a35 
dcutting e057db3 





dcutting bd72a3e 




dcutting e057db3 
dcutting d73dcee 





dcutting e057db3 




dcutting 36afd7f 





dcutting 33e1048 





dcutting bd72a3e 
dcutting 14b7a35 







dcutting bb7cad0 
dcutting 14b7a35 



dcutting bb7cad0 











dcutting 14b7a35 
dcutting bd72a3e 
dcutting c44dc2d 




#import "Kiwi.h"
#import "NSBundle+JSONLoader.h"
#import "NSString+JSON.h"
#import "VeriJSON.h"

SPEC_BEGIN(VeriJSONTests)

describe(@"VeriJSON Tests", ^{
    registerMatchers(@"SKKiwi");
    
    __block NSBundle *bundle;
    __block VeriJSON *veriJSON;
    
    beforeEach(^{
        bundle = [NSBundle bundleForClass:[self class]];
        veriJSON = [VeriJSON new];
    });
    
    it(@"nil JSON and nil pattern", ^{
        BOOL valid = [veriJSON verifyJSON:nil pattern:nil];
        [[@(valid) should] beYes];
    });
    
    it(@"non-nil JSON and nil pattern", ^{
        NSData *jsonData = [@"{}" dataUsingEncoding:NSUTF8StringEncoding];
        id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
        BOOL valid = [veriJSON verifyJSON:json pattern:nil];
        [[@(valid) should] beYes];
    });
    
    it(@"nil JSON and non-nil pattern", ^{
        id pattern = [bundle jsonFromResource:@"SimpleObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:nil pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"simple invalid object", ^{
        id json = [bundle jsonFromResource:@"SimpleObjectInvalid.json"];
        id pattern = [bundle jsonFromResource:@"SimpleObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"simple valid object", ^{
        id json = [bundle jsonFromResource:@"SimpleObject.json"];
        id pattern = [bundle jsonFromResource:@"SimpleObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"required attribute missing", ^{
        id json = [bundle jsonFromResource:@"SimpleObject.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithStringPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"string type", ^{
        id json = [bundle jsonFromResource:@"ObjectWithString.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithStringPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"invalid string type", ^{
        id json = [bundle jsonFromResource:@"ObjectWithStringInvalid.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithStringPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"number type", ^{
        id json = [bundle jsonFromResource:@"ObjectWithNumber.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithNumberPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"invalid number type", ^{
        id json = [bundle jsonFromResource:@"ObjectWithNumberInvalid.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithNumberPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"bool type", ^{
        id json = [bundle jsonFromResource:@"ObjectWithBool.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithBoolPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"invalid bool type", ^{
        id json = [bundle jsonFromResource:@"ObjectWithBoolInvalid.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithBoolPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"bool/numbers interchangeable - this is because there is no BOOL object in Objective-C", ^{
        id json = [bundle jsonFromResource:@"ObjectWithBoolAsNumber.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithBoolPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"object containing an object", ^{
        id json = [bundle jsonFromResource:@"ObjectWithObject.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"object containing an invalid object", ^{
        id json = [bundle jsonFromResource:@"ObjectWithObjectInvalid.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"object expecting to contain an object but getting something else", ^{
        id json = [bundle jsonFromResource:@"ObjectWithNonObject.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"multi-attribute object with an embedded object", ^{
        id json = [bundle jsonFromResource:@"RealisticObject.json"];
        id pattern = [bundle jsonFromResource:@"RealisticObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"simple array", ^{
        id json = [bundle jsonFromResource:@"SimpleArray.json"];
        id pattern = [bundle jsonFromResource:@"SimpleArrayPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    context(@"array of strings", ^{
        __block id pattern;
        
        beforeEach(^{
            pattern = [bundle jsonFromResource:@"ArrayOfStringsPattern.json"];
        });
        
        it(@"0 strings", ^{
            id json = [bundle jsonFromResource:@"ArrayOf0Strings.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beYes];
        });
        
        it(@"1 string", ^{
            id json = [bundle jsonFromResource:@"ArrayOf1String.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beYes];
        });
        
        it(@"2 strings", ^{
            id json = [bundle jsonFromResource:@"ArrayOf2Strings.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beYes];
        });
        
        it(@"other objects", ^{
            id json = [bundle jsonFromResource:@"ArrayOfStringsAndNumbers.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beNo];
        });
    });
    
    context(@"bad pattern", ^{
        it(@"object pattern with bad type", ^{
            id json = [@"{ \"count\": 42 }" toJSON];
            id pattern = [@"{ \"count\": \"foobartype\" }" toJSON];
            NSError *error;
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern error:&error];
            [[@(valid) should] beNo];
            [[error.domain should] equal:VeriJSONErrorDomain];
            [[@(error.code) should] equal:@(VeriJSONErrorCodeInvalidPattern)];
            [[[error localizedDescription] should] equal:@"Invalid pattern .count.foobartype"];
        });

        it(@"array pattern with bad type", ^{
            id json = [@"[42]" toJSON];
            id pattern = [bundle jsonFromResource:@"ArrayPatternWithBadType.json"];
            NSError *error;
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern error:&error];
            [[@(valid) should] beNo];
            [[error.domain should] equal:VeriJSONErrorDomain];
            [[@(error.code) should] equal:@(VeriJSONErrorCodeInvalidPattern)];
            [[[error localizedDescription] should] equal:@"Invalid pattern .foobartype"];
        });

        it(@"realistic pattern with bad type", ^{
            id json = [bundle jsonFromResource:@"RealisticObject.json"];
            id pattern = [bundle jsonFromResource:@"RealisticObjectPatternInvalid.json"];
            NSError *error;
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern error:&error];
            [[@(valid) should] beNo];
            [[error.domain should] equal:VeriJSONErrorDomain];
            [[@(error.code) should] equal:@(VeriJSONErrorCodeInvalidPattern)];
            [[[error localizedDescription] should] equal:@"Invalid pattern .properties.tags.foo"];
        });
    });
    
    it(@"additional attributes in the JSON are ignored", ^{
        id json = [bundle jsonFromResource:@"ExtraAttributes.json"];
        id pattern = [bundle jsonFromResource:@"RealisticObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"by default, all attributes in the pattern are required in the JSON", ^{
        id json = [bundle jsonFromResource:@"MissingAttributes.json"];
        id pattern = [bundle jsonFromResource:@"RealisticObjectPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"optional attributes", ^{
        id json = [bundle jsonFromResource:@"RealisticObjectOptional.json"];
        id pattern = [bundle jsonFromResource:@"RealisticObjectPatternOptional.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"optional attributes must still be the right type", ^{
        id json = [bundle jsonFromResource:@"RealisticObjectOptionalWrongType.json"];
        id pattern = [bundle jsonFromResource:@"RealisticObjectPatternOptional.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"null values not accepted for mandatory attributes", ^{
        id json = [bundle jsonFromResource:@"ObjectWithNullString.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithStringPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beNo];
    });
    
    it(@"null values are accepted for optional attributes", ^{
        id json = [bundle jsonFromResource:@"ObjectWithNullString.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithOptionalStringPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"null values for array attributes", ^{
        id json = [bundle jsonFromResource:@"ObjectWithNullArray.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithOptionalArrayPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    it(@"non-null values for optional array attributes", ^{
        id json = [bundle jsonFromResource:@"ObjectWithNonNullArray.json"];
        id pattern = [bundle jsonFromResource:@"ObjectWithOptionalArrayPattern.json"];
        BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
        [[@(valid) should] beYes];
    });
    
    context(@"regex strings", ^{
        __block id pattern;
        
        beforeEach(^{
            pattern = [bundle jsonFromResource:@"ObjectWithDateStringPattern.json"];
        });

        it(@"valid", ^{
            id json = [bundle jsonFromResource:@"ObjectWithDateString.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beYes];
        });
        
        it(@"invalid", ^{
            id json = [bundle jsonFromResource:@"ObjectWithDateStringInvalid.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beNo];
        });
    });
    
    context(@"URL types", ^{
        __block id pattern;
        
        beforeEach(^{
            pattern = [bundle jsonFromResource:@"ObjectWithURLPattern.json"];
        });

        it(@"absolute URL", ^{
            id json = [bundle jsonFromResource:@"ObjectWithURL.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beYes];
        });
        
        it(@"relative URL", ^{
            id json = [bundle jsonFromResource:@"ObjectWithURLRelative.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beYes];
        });
        
        it(@"invalid URL", ^{
            id json = [bundle jsonFromResource:@"ObjectWithURLInvalid.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beNo];
        });
        
        it(@"empty URL", ^{
            id json = [bundle jsonFromResource:@"ObjectWithURLInvalidEmpty.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beNo];
        });
        
        it(@"whitespace URL", ^{
            id json = [bundle jsonFromResource:@"ObjectWithURLInvalidWhitespace.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beNo];
        });
    });

    context(@"HTTP URL types", ^{
        __block id pattern;
        
        beforeEach(^{
            pattern = [bundle jsonFromResource:@"ObjectWithHTTPURLPattern.json"];
        });
        
        it(@"HTTP URL", ^{
            id json = [bundle jsonFromResource:@"ObjectWithHTTPURL.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beYes];
        });
        
        it(@"HTTPS URL", ^{
            id json = [bundle jsonFromResource:@"ObjectWithHTTPSURL.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beYes];
        });

        it(@"non-HTTP URL", ^{
            id json = [bundle jsonFromResource:@"ObjectWithURL.json"];
            BOOL valid = [veriJSON verifyJSON:json pattern:pattern];
            [[@(valid) should] beNo];
        });
    });
    
    it(@"hack to ensure tests finish", ^{
        sleep(1);
    });
});

SPEC_END