Framework/ROADSerialization/ROADSerializationTest/Classes/RFAnnotatedCoderTest.m (175 lines of code) (raw):
//
// RFAnnotatedCoderTest.m
// ROADSerialization
//
// Copyright (c) 2014 EPAM Systems, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
// Neither the name of the EPAM Systems, Inc. nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// See the NOTICE file and the LICENSE file distributed with this work
// for additional information regarding copyright ownership and licensing
#import <XCTest/XCTest.h>
#import "RFSerializationTestObject.h"
#import "RFAttributedDecoder.h"
#import "RFAttributedCoder.h"
#import "RFDateTestClass.h"
#import "RFSerializableStringChecker.h"
#import "RFJSONPropertyPreprocessingClass.h"
@interface RFAnnotatedCoderTest : XCTestCase
@end
@implementation RFAnnotatedCoderTest {
RFSerializationTestObject *object;
}
- (void)setUp {
object = [RFSerializationTestObject sampleObject];
[super setUp];
}
- (void)tearDown {
object.child = nil;
object = nil;
[super tearDown];
}
- (void)testSerialization {
NSString *result = [RFAttributedCoder encodeRootObject:object];
NSError *error;
NSString *test = [NSString stringWithContentsOfFile:[[NSBundle bundleForClass:self.class] pathForResource:@"SerializationTest" ofType:@"json"] encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error, @"Assertion: SerializationTest.json file was not loaded to check result");
NSString *errorMessage = [RFSerializableStringChecker serializeAndCheckEqualityOfString:test withString:result];
XCTAssertNil(errorMessage, @"%@", errorMessage);
}
- (void)testDeserialization {
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
NSString *pathToDeserialisationTestFile = [testBundle pathForResource:@"DeserialisationTest" ofType:@"json"];
NSError *error = nil;
NSString *deserialisationTestString = [NSString stringWithContentsOfFile:pathToDeserialisationTestFile encoding:NSUTF8StringEncoding error:&error];
XCTAssertTrue(!error, @"Deserialisation content is not available, error: %@", error);
XCTAssertTrue([deserialisationTestString length] > 0, @"Deserialisation content is missing");
RFSerializationTestObject *restored = [RFAttributedDecoder decodeJSONString:deserialisationTestString];
[self checkRestoredObject:restored];
}
- (void)checkRestoredObject:(RFSerializationTestObject *)restored {
XCTAssertTrue([restored isKindOfClass:[RFSerializationTestObject class]], @"Assertion: the restored object is of the correct class: %@", NSStringFromClass([restored class]));
XCTAssertTrue([restored.string1 isEqualToString:@"value1"] && [restored.child.string1 isEqualToString:@"value5"], @"Assertion: strings are restored to the correct value.");
XCTAssertTrue([restored.strings[1] isEqualToString:@"value4"], @"Assertion: stringarray is restored correctly.");
XCTAssertTrue([restored.subDictionary[@"object3"] isKindOfClass:[RFSerializationTestObject class]], @"Assertion: dictionary value is of the correct class");
XCTAssertTrue([[restored.subDictionary[@"object3"] string1] isEqualToString:@"value31"], @"Assertion: object embedded in dictionary is restored correctly.");
XCTAssertTrue([restored.string2 length] == 0 && [restored.child.string2 length] == 0, @"Assertion: derived properties are ignored.");
XCTAssertTrue([[restored.child.subObjects[0] string1] isEqualToString:@"value31"], @"Assertion: embedded objects in array are restored properly.");
XCTAssertTrue([restored.subDictionary[@"object3"] integer] == 5, @"Assertion: primitive types in embedded objects are restored correctly.");
XCTAssertTrue([[restored.child.subObjects[1] number] integerValue] == 3, @"Assertion: NSNumber values are restored correctly.");
XCTAssertTrue(restored.booleanToTranslateTrue, @"The translation was unsuccessfull.");
XCTAssertTrue(restored.booleanToTranslateTrueFromNumber, @"The translation was unsuccessfull.");
XCTAssertTrue(!restored.booleanToTranslateFalse, @"The translation from number was unsuccessfull.");
XCTAssertTrue(!restored.booleanToTranslateFalseFromNumber, @"The translation from number was unsuccessfull.");
}
- (void)testDateSerialization {
RFDateTestClass *testObject = [RFDateTestClass testObject];
NSString *testObjectStandardString = [RFDateTestClass testObjectStringRepresentation];
NSDictionary *testObjectStandard = [NSJSONSerialization JSONObjectWithData:[testObjectStandardString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
XCTAssertNotNil(testObjectStandard, @"Standard string has invalid format.");
NSString * testString = [RFAttributedCoder encodeRootObject:testObject];
NSDictionary *test = [NSJSONSerialization JSONObjectWithData:[testString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
XCTAssertNotNil(test, @"Serialized string has invalid format.");
XCTAssertTrue([test[@"unixTimestamp"] isEqualToString:testObjectStandard[@"unixTimestamp"]], @"Unix timestamp serialized incorrectly.");
XCTAssertTrue([test[@"unixTimestampWithMultiplier"] isEqualToString:testObjectStandard[@"unixTimestampWithMultiplier"]], @"Unix timestamp with multiplier serialized incorrectly.");
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = [[RFDateTestClass RF_attributeForProperty:@"dateWithFormat" withAttributeType:[RFSerializableDate class]] format];
XCTAssertTrue([[dateFormatter dateFromString:test[@"dateWithFormat"]] isEqualToDate:[dateFormatter dateFromString:testObjectStandard[@"dateWithFormat"]]], @"dateWithFormat serialized incorrectly");
dateFormatter.dateFormat = [[RFDateTestClass RF_attributeForProperty:@"dateWithEncodeDecodeFormat" withAttributeType:[RFSerializableDate class]] encodingFormat];
XCTAssertTrue([[dateFormatter dateFromString:test[@"dateWithEncodeDecodeFormat"]] isEqualToDate:[dateFormatter dateFromString:testObjectStandard[@"dateWithEncodeDecodeFormat"]]], @"dateWithEncodeDecodeFormat serialized incorrectly.");
dateFormatter.dateFormat = [[RFDateTestClass RF_attributeForProperty:@"dateWithEncodeFormatPriority" withAttributeType:[RFSerializableDate class]] encodingFormat];
XCTAssertTrue([[dateFormatter dateFromString:test[@"dateWithEncodeFormatPriority"]] isEqualToDate:[dateFormatter dateFromString:testObjectStandard[@"dateWithEncodeFormatPriority"]]], @"dateWithEncodeFormatPriority serialized incorrectly.");
dateFormatter.dateFormat = [[RFDateTestClass RF_attributeForProperty:@"dateWithDecodeFormatPriority" withAttributeType:[RFSerializableDate class]] format];
XCTAssertTrue([[dateFormatter dateFromString:test[@"dateWithDecodeFormatPriority"]] isEqualToDate:[dateFormatter dateFromString:testObjectStandard[@"dateWithDecodeFormatPriority"]]], @"dateWithDecodeFormatPriority serialized incorrectly.");
}
- (void)testDateDeserialization {
RFDateTestClass *testObject = [RFDateTestClass testObject];
NSString *testDeserizationString = [RFDateTestClass testDeserialisationString];
id testDeserizationObject = [RFAttributedDecoder decodeJSONString:testDeserizationString];
XCTAssertTrue([testDeserizationObject isEqual:testObject], @"Deserialization of dates works incorrectly.");
}
- (void)testJsonWrongDeserializationRoot {
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
NSString *pathToDeserialisationTestFile = [testBundle pathForResource:@"DeserialisationTest" ofType:@"json"];
NSData *deserialisationTestData = [NSData dataWithContentsOfFile:pathToDeserialisationTestFile];
id decodedObject = [RFAttributedDecoder decodeJSONData:deserialisationTestData withSerializationRoot:@"child.subObjects.object" rootClassNamed:@"RFSerializationTestObject"];
XCTAssertNil(decodedObject, @"Wrong deserialization root returned some value.");
}
- (void)testJsonDeserializationRoot {
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
NSString *pathToDeserialisationTestFile = [testBundle pathForResource:@"DeserialisationTest" ofType:@"json"];
NSData *deserialisationTestData = [NSData dataWithContentsOfFile:pathToDeserialisationTestFile];
id decodedObject = [RFAttributedDecoder decodeJSONData:deserialisationTestData withSerializationRoot:@"child.subObjects.number" rootClassNamed:nil];
XCTAssertNotNil(decodedObject, @"Wrong deserialization root returned some value.");
}
- (void)testJsonEmptyDeserializationRoot {
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
NSString *pathToDeserialisationTestFile = [testBundle pathForResource:@"DeserialisationTestEmpty" ofType:@"json"];
NSData *deserialisationTestData = [NSData dataWithContentsOfFile:pathToDeserialisationTestFile];
id decodedObject = [RFAttributedDecoder decodeJSONData:deserialisationTestData withSerializationRoot:@"emptyResult" rootClassNamed:nil];
XCTAssertNotNil(decodedObject, @"Wrong deserialization root returned some value");
}
- (void)testMappingPredeserializedObject {
id predeserializedObject = @[ @{@"string1" : @"value1"} ];
NSArray *testArray = [RFAttributedDecoder decodePredeserializedObject:predeserializedObject withRootClassName:@"RFSerializationTestObject"];
XCTAssertNotNil(testArray, @"Mapping predeserialized object failed");
XCTAssertTrue([testArray count] == 1, @"Mapping predeserialized object performed incorrectly. Number of object in array must be one");
RFSerializationTestObject *testObject = [testArray lastObject];
XCTAssertNotNil(testObject, @"Mapping predeserialized object failed");
XCTAssertTrue([testObject.string1 isEqualToString:@"value1"], @"Mapping predeserialized object performed incorrectly");
}
- (void)testCreationSerializableDictionaryFromObject {
RFSerializationTestObject *testObject = [[RFSerializationTestObject alloc] init];
testObject.string1 = @"value1";
NSDictionary *testDictionary = [RFAttributedCoder encodeRootObjectToSerializableObject:@{ @"testObject" : testObject }];
XCTAssertNotNil(testDictionary, @"Creating serializable dictionary failed");
XCTAssertTrue([testDictionary[@"testObject"][@"string1"] isEqualToString:@"value1"], @"Creating serializable dictionary performed incorrectly");
}
- (void)testCreationSerializableArrayFromObject {
RFSerializationTestObject *testObject = [[RFSerializationTestObject alloc] init];
testObject.string1 = @"value1";
NSArray *testArray = [RFAttributedCoder encodeRootObjectToSerializableObject:@[ testObject ]];
XCTAssertNotNil(testArray, @"Creating serializable array failed");
XCTAssertTrue([testArray count] == 1, @"Array must contain only one object. Serialization performed incorrectly");
NSDictionary *testDictionary = [testArray lastObject];
XCTAssertNotNil(testDictionary, @"Creating serializable array performed incorrectly");
XCTAssertTrue([testDictionary[@"string1"] isEqualToString:@"value1"], @"Creating serializable dictionary in array performed incorrectly");
}
static const float kFloatPrecision = 0.0000001f;
- (void)testPropertyCustomDecodingPreprocessor {
NSString *testString = @"{\"number\" : 325.567}";
RFJSONPropertyPreprocessingClass *testObject = [RFAttributedDecoder decodeJSONString:testString withRootClassNamed:NSStringFromClass([RFJSONPropertyPreprocessingClass class])];
XCTAssertTrue([testObject.number floatValue] - 325.0f < kFloatPrecision, @"Property was not preprocessed with assigned block");
}
- (void)testRootClassConvinientInitializer {
NSString *testString = @"{\"number\" : 325.567}";
RFJSONPropertyPreprocessingClass *testObject = [RFAttributedDecoder decodeJSONString:testString withRootClass:[RFJSONPropertyPreprocessingClass class]];
XCTAssertTrue([testObject.number floatValue] - 325.0f < kFloatPrecision, @"Property was not preprocessed with assigned block");
}
- (void)testPropertyCustomEncodingPreprocessor {
RFJSONPropertyPreprocessingClass *testObject = [[RFJSONPropertyPreprocessingClass alloc] init];
testObject.number = @325.567;
NSString *testString = [RFAttributedCoder encodeRootObject:testObject];
NSError *error;
NSDictionary *testDictionary = [NSJSONSerialization JSONObjectWithData:[testString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
XCTAssertTrue([testDictionary[@"number"] floatValue] - 325.0f < kFloatPrecision, @"Property was not preprocessed with assigned block");
}
- (void)testSerializationOfBigUnixTimestamps {
NSTimeInterval timeInterval = 15000000000;
RFSerializationTestObject *testObject = [[RFSerializationTestObject alloc] init];
testObject.unixTimestamp = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear fromDate:testObject.unixTimestamp];
XCTAssertEqual(components.year, 2445, @"Wrong year after encoding");
NSString *string = [RFAttributedCoder encodeRootObject:testObject];
RFSerializationTestObject *deserializedTestObject = (RFSerializationTestObject *)[RFAttributedDecoder decodeJSONString:string withRootClassNamed:NSStringFromClass([RFSerializationTestObject class])];
XCTAssertTrue(fabs([deserializedTestObject.unixTimestamp timeIntervalSince1970] - timeInterval) < 1000, @"Big time interval was corrupted");
}
- (void)testNilInDecoder {
id nil1 = [RFAttributedDecoder decodeJSONData:nil withRootClassNamed:@""];
id nil2 = [RFAttributedDecoder decodeJSONString:nil withRootClassNamed:@""];
XCTAssertNil(nil1, @"RFAttrbutedCoder returned value for nil data");
XCTAssertNil(nil2, @"RFAttrbutedCoder returned value for nil data");
}
- (void)testNilInDecoderWithRootClass {
id nil1 = [RFAttributedDecoder decodeJSONData:nil withRootClass:nil];
id nil2 = [RFAttributedDecoder decodeJSONString:nil withRootClass:nil];
XCTAssertNil(nil1, @"RFAttrbutedCoder returned value for nil data");
XCTAssertNil(nil2, @"RFAttrbutedCoder returned value for nil data");
}
- (void)testErrorInDecodedString {
NSError *error;
id result = [RFAttributedDecoder decodeJSONString:@"*" withRootClass:[NSObject class] error:&error];
XCTAssertNotNil(error, @"RFAttrbutedCoder did not return error of serializtion");
XCTAssertNil(result, @"RFAttrbutedCoder returned value for errored data");
}
@end