Commits

dcutting committed d2adcb8

String regex support.

  • Participants
  • Parent commits d981b65

Comments (0)

Files changed (7)

VeriJSON.xcodeproj/project.pbxproj

 		C8A64F9D169347C800D01705 /* ObjectWithNullArray.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A64F9B169347C800D01705 /* ObjectWithNullArray.json */; };
 		C8A64F9E169347C800D01705 /* ObjectWithOptionalArrayPattern.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A64F9C169347C800D01705 /* ObjectWithOptionalArrayPattern.json */; };
 		C8A64FA0169347F000D01705 /* ObjectWithNonNullArray.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A64F9F169347EF00D01705 /* ObjectWithNonNullArray.json */; };
+		C8A64FA31693494B00D01705 /* ObjectWithDateString.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A64FA11693494A00D01705 /* ObjectWithDateString.json */; };
+		C8A64FA41693494B00D01705 /* ObjectWithDateStringPattern.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A64FA21693494A00D01705 /* ObjectWithDateStringPattern.json */; };
+		C8A64FA61693499700D01705 /* ObjectWithDateStringInvalid.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A64FA51693499700D01705 /* ObjectWithDateStringInvalid.json */; };
 		C8A69A6B169203DB0038211F /* ObjectWithBool.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A69A68169203DB0038211F /* ObjectWithBool.json */; };
 		C8A69A6C169203DB0038211F /* ObjectWithBoolInvalid.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A69A69169203DB0038211F /* ObjectWithBoolInvalid.json */; };
 		C8A69A6D169203DB0038211F /* ObjectWithBoolPattern.json in Resources */ = {isa = PBXBuildFile; fileRef = C8A69A6A169203DB0038211F /* ObjectWithBoolPattern.json */; };
 		C8A64F9B169347C800D01705 /* ObjectWithNullArray.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithNullArray.json; path = Data/ObjectWithNullArray.json; sourceTree = "<group>"; };
 		C8A64F9C169347C800D01705 /* ObjectWithOptionalArrayPattern.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithOptionalArrayPattern.json; path = Data/ObjectWithOptionalArrayPattern.json; sourceTree = "<group>"; };
 		C8A64F9F169347EF00D01705 /* ObjectWithNonNullArray.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithNonNullArray.json; path = Data/ObjectWithNonNullArray.json; sourceTree = "<group>"; };
+		C8A64FA11693494A00D01705 /* ObjectWithDateString.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithDateString.json; path = Data/ObjectWithDateString.json; sourceTree = "<group>"; };
+		C8A64FA21693494A00D01705 /* ObjectWithDateStringPattern.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithDateStringPattern.json; path = Data/ObjectWithDateStringPattern.json; sourceTree = "<group>"; };
+		C8A64FA51693499700D01705 /* ObjectWithDateStringInvalid.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithDateStringInvalid.json; path = Data/ObjectWithDateStringInvalid.json; sourceTree = "<group>"; };
 		C8A69A68169203DB0038211F /* ObjectWithBool.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithBool.json; path = Data/ObjectWithBool.json; sourceTree = "<group>"; };
 		C8A69A69169203DB0038211F /* ObjectWithBoolInvalid.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithBoolInvalid.json; path = Data/ObjectWithBoolInvalid.json; sourceTree = "<group>"; };
 		C8A69A6A169203DB0038211F /* ObjectWithBoolPattern.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = ObjectWithBoolPattern.json; path = Data/ObjectWithBoolPattern.json; sourceTree = "<group>"; };
 				C8A64F9C169347C800D01705 /* ObjectWithOptionalArrayPattern.json */,
 				C8A64F9B169347C800D01705 /* ObjectWithNullArray.json */,
 				C8A64F9F169347EF00D01705 /* ObjectWithNonNullArray.json */,
+				C8A64FA21693494A00D01705 /* ObjectWithDateStringPattern.json */,
+				C8A64FA11693494A00D01705 /* ObjectWithDateString.json */,
+				C8A64FA51693499700D01705 /* ObjectWithDateStringInvalid.json */,
 			);
 			name = Data;
 			sourceTree = "<group>";
 				C8A64F9D169347C800D01705 /* ObjectWithNullArray.json in Resources */,
 				C8A64F9E169347C800D01705 /* ObjectWithOptionalArrayPattern.json in Resources */,
 				C8A64FA0169347F000D01705 /* ObjectWithNonNullArray.json in Resources */,
+				C8A64FA31693494B00D01705 /* ObjectWithDateString.json in Resources */,
+				C8A64FA41693494B00D01705 /* ObjectWithDateStringPattern.json in Resources */,
+				C8A64FA61693499700D01705 /* ObjectWithDateStringInvalid.json in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

VeriJSON/VeriJSON/VeriJSON.m

 
 - (BOOL)verifyBaseValue:(id)value pattern:(id)pattern patternStack:(NSMutableArray *)patternStack {
     [patternStack addObject:pattern];
-    Class class = [self classForType:pattern];
-    BOOL valid = [value isKindOfClass:class];
+    
+    BOOL valid = NO;
+
+    if ([@"string" isEqualToString:pattern] || [pattern hasPrefix:@"string:"]) {
+        valid = [self verifyString:value pattern:pattern];
+    }
+    if ([@"number" isEqualToString:pattern]) {
+        valid = [value isKindOfClass:[NSNumber class]];
+    }
+    if ([@"bool" isEqualToString:pattern]) {
+        valid = [value isKindOfClass:[NSNumber class]];
+    }
+
     if (valid) {
         [patternStack removeLastObject];
     }
     return valid;
 }
 
-- (Class)classForType:(id)type {
-    if ([@"string" isEqualToString:type]) return [NSString class];
-    if ([@"number" isEqualToString:type]) return [NSNumber class];
-    if ([@"bool" isEqualToString:type]) return [NSNumber class];
-    return nil;
+- (BOOL)verifyString:(NSString *)value pattern:(NSString *)pattern {
+    if (![value isKindOfClass:[NSString class]]) return NO;
+    NSArray *components = [pattern componentsSeparatedByString:@":"];
+    if ([components count] > 1) {
+        NSString *regexPattern = components[1];
+        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexPattern options:0 error:NULL];
+        NSUInteger numMatches = [regex numberOfMatchesInString:value options:NSMatchingReportCompletion range:NSMakeRange(0, [value length])];
+        return numMatches > 0;
+    }
+    return YES;
 }
 
 - (NSError *)buildErrorFromPatternStack:(NSArray *)patternStack {

VeriJSONTests/Data/ObjectWithDateString.json

+{
+    "date": "20130101"
+}

VeriJSONTests/Data/ObjectWithDateStringInvalid.json

+{
+    "date": "130101"
+}

VeriJSONTests/Data/ObjectWithDateStringPattern.json

+{
+    "date": "string:\\d{8}"
+}

VeriJSONTests/Helpers/NSBundle+JSONLoader.m

 - (id)jsonFromResource:(NSString *)resource {
     NSString *path = [self pathForResource:resource ofType:nil];
     NSData *jsonData = [NSData dataWithContentsOfFile:path];
-    return [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
+    id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
+    if (!json) {
+        @throw @"Could not load JSON.";
+    }
+    return json;
 }
 
 @end

VeriJSONTests/VeriJSONTests.m

         [[@(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];
+        });
+    });
+    
     it(@"hack to ensure tests finish", ^{
         sleep(1);
     });