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