From 422db236aea093da5dc8a87773bb48bb2497689c Mon Sep 17 00:00:00 2001 From: Frank <472730949@qq.com> Date: Thu, 23 Dec 2021 15:23:35 +0800 Subject: [PATCH] Add more tests for - `String to Data` case - `AttributedString to String` case Remove unnecessary ivar of cache class. Boost large properties with small amount dictionary. #197 --- MJExtension.xcodeproj/project.pbxproj | 12 +++ MJExtension/MJEClass.h | 5 +- MJExtension/MJEClass.m | 14 ++- MJExtension/MJProperty.h | 2 + MJExtension/MJProperty.m | 2 + MJExtension/NSObject+MJKeyValue.m | 91 ++++++++++++------- MJExtensionTests/CoreDataTests.swift | 6 +- MJExtensionTests/MultiThreadTests.swift | 6 +- MJExtensionTests/SwiftModel/MJArticle.swift | 14 +++ .../SwiftModel/MJCredential.swift | 13 +++ MJExtensionTests/SwiftModelTests.swift | 32 ++++--- MJExtensionTests/ValueTransformingTest.swift | 35 +++++++ 12 files changed, 172 insertions(+), 60 deletions(-) create mode 100644 MJExtensionTests/SwiftModel/MJArticle.swift create mode 100644 MJExtensionTests/SwiftModel/MJCredential.swift create mode 100644 MJExtensionTests/ValueTransformingTest.swift diff --git a/MJExtension.xcodeproj/project.pbxproj b/MJExtension.xcodeproj/project.pbxproj index 0f0696c..f420cae 100644 --- a/MJExtension.xcodeproj/project.pbxproj +++ b/MJExtension.xcodeproj/project.pbxproj @@ -21,6 +21,9 @@ 0130EE80233C56D8008D2386 /* MJFrenchUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 0130EE7F233C56D8008D2386 /* MJFrenchUser.m */; }; 0179886C24EFA460007F7FBC /* MJTester.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0179886B24EFA460007F7FBC /* MJTester.swift */; }; 0179887024EFA58B007F7FBC /* SwiftModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0179886F24EFA58B007F7FBC /* SwiftModelTests.swift */; }; + 01BC91E2277418DF004E5265 /* ValueTransformingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01BC91E1277418DF004E5265 /* ValueTransformingTest.swift */; }; + 01BC91E427741956004E5265 /* MJCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01BC91E327741956004E5265 /* MJCredential.swift */; }; + 01BC91E627741D8C004E5265 /* MJArticle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01BC91E527741D8C004E5265 /* MJArticle.swift */; }; 01D3949B26FACE7D00457B88 /* MJCoreDataTestModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 0107507626E88DD400AAEA10 /* MJCoreDataTestModel.xcdatamodeld */; }; 01F28187248F64ED008775BA /* MJCat.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F28186248F64ED008775BA /* MJCat.m */; }; 01F5515E2757144500518218 /* MJEClass.h in Headers */ = {isa = PBXBuildFile; fileRef = 01F5515C2757144500518218 /* MJEClass.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -91,6 +94,9 @@ 0179886A24EFA460007F7FBC /* MJExtensionTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MJExtensionTests-Bridging-Header.h"; sourceTree = ""; }; 0179886B24EFA460007F7FBC /* MJTester.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MJTester.swift; sourceTree = ""; }; 0179886F24EFA58B007F7FBC /* SwiftModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftModelTests.swift; sourceTree = ""; }; + 01BC91E1277418DF004E5265 /* ValueTransformingTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueTransformingTest.swift; sourceTree = ""; }; + 01BC91E327741956004E5265 /* MJCredential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MJCredential.swift; sourceTree = ""; }; + 01BC91E527741D8C004E5265 /* MJArticle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MJArticle.swift; sourceTree = ""; }; 01F28185248F64ED008775BA /* MJCat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MJCat.h; sourceTree = ""; }; 01F28186248F64ED008775BA /* MJCat.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MJCat.m; sourceTree = ""; }; 01F5515C2757144500518218 /* MJEClass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MJEClass.h; sourceTree = ""; }; @@ -202,6 +208,8 @@ isa = PBXGroup; children = ( 0179886B24EFA460007F7FBC /* MJTester.swift */, + 01BC91E327741956004E5265 /* MJCredential.swift */, + 01BC91E527741D8C004E5265 /* MJArticle.swift */, ); path = SwiftModel; sourceTree = ""; @@ -261,6 +269,7 @@ 0107507526E88DA600AAEA10 /* CoreDataModel */, 2D2DBA5F2317DBDF005A689E /* Model */, 2D2DBA572317DBB9005A689E /* MJExtensionTests.m */, + 01BC91E1277418DF004E5265 /* ValueTransformingTest.swift */, 010DF01D2761D90A0007EEF0 /* SpecialPropertyTypeTests.swift */, 0179886F24EFA58B007F7FBC /* SwiftModelTests.swift */, 01052EAC25F872D00049EC6F /* MultiThreadTests.swift */, @@ -522,6 +531,7 @@ buildActionMask = 2147483647; files = ( 2D2DBA812317DBE0005A689E /* MJStatusResult.m in Sources */, + 01BC91E627741D8C004E5265 /* MJArticle.swift in Sources */, 2D2DBA7C2317DBE0005A689E /* MJStudent.m in Sources */, 2D2DBA822317DBE0005A689E /* MJStatus.m in Sources */, 2D2DBA832317DBE0005A689E /* MJAd.m in Sources */, @@ -534,6 +544,7 @@ 01F551642758C74F00518218 /* NSObject+MJExtensionExample.m in Sources */, 2D2DBA852317DBE0005A689E /* MJPerson.m in Sources */, 0107507C26E88EAC00AAEA10 /* MJCoreDataTester+CoreDataProperties.swift in Sources */, + 01BC91E2277418DF004E5265 /* ValueTransformingTest.swift in Sources */, 2D2DBA7B2317DBE0005A689E /* MJBox.m in Sources */, 2D2DBA582317DBB9005A689E /* MJExtensionTests.m in Sources */, 010DF01E2761D90A0007EEF0 /* SpecialPropertyTypeTests.swift in Sources */, @@ -544,6 +555,7 @@ 0107507826E88DD400AAEA10 /* MJCoreDataTestModel.xcdatamodeld in Sources */, 2D2DBA7A2317DBE0005A689E /* MJDog.m in Sources */, 01052EAD25F872D00049EC6F /* MultiThreadTests.swift in Sources */, + 01BC91E427741956004E5265 /* MJCredential.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MJExtension/MJEClass.h b/MJExtension/MJEClass.h index 25c872b..d64f454 100644 --- a/MJExtension/MJEClass.h +++ b/MJExtension/MJEClass.h @@ -18,14 +18,17 @@ NS_ASSUME_NONNULL_BEGIN NSArray * _Nullable _allProperties2JSON; NSDictionary *_mapper; + NSArray *_multiKeysProperties; BOOL _hasOld2NewModifier; - BOOL _hasLocaleModifier; BOOL _hasDictionary2ObjectModifier; BOOL _hasObject2DictionaryModifier; BOOL _hasClassModifier; BOOL _needsUpdate; + /// = _allProperties.count + NSInteger _propertiesCount; + NSLocale * _Nullable _locale; } - (void)setNeedsUpdate; diff --git a/MJExtension/MJEClass.m b/MJExtension/MJEClass.m index b05bee6..8f4f1f3 100644 --- a/MJExtension/MJEClass.m +++ b/MJExtension/MJEClass.m @@ -111,7 +111,9 @@ - (instancetype)initWithClass:(Class)cls { hasKeyReplacementModifier:hasKeyReplacementModifier inClass:cls]; - _hasLocaleModifier = [cls respondsToSelector:@selector(mj_locale)]; + if ([cls respondsToSelector:@selector(mj_locale)]) { + _locale = [(Class)cls mj_locale]; + } _hasOld2NewModifier = [cls instancesRespondToSelector:@selector(mj_newValueFromOldValue:property:)]; // TODO: 4.0.0 new feature // _hasClassModifier = [ @@ -156,6 +158,7 @@ - (void)mj_handlePropertiesWithAllowedList:(NSSet *)allowedList NSMutableArray *allProperties = [NSMutableArray array]; NSMutableArray *codingProperties = [NSMutableArray array]; NSMutableDictionary *mapper = [NSMutableDictionary new]; + NSMutableArray *multiKeysProperties = [NSMutableArray array]; // TODO: 4.0.0 new feature // NSMutableArray *allProperties2JSON = [NSMutableArray array]; [cls mj_enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) { @@ -201,8 +204,10 @@ - (void)mj_handlePropertiesWithAllowedList:(NSSet *)allowedList // handle keypath / keypath array / keypath array(with subkey) [property handleOriginKey:key]; - // The property matched with a singular key is only condition that should be considered. - if (!property->_isMultiMapping) { + // The property matched with a singular key is the only condition for dictionary enumeration. + if (property->_isMultiMapping) { + [multiKeysProperties addObject:property]; + } else { property->_nextSame = mapper[property->_mappedKey] ?: nil; mapper[property->_mappedKey] = property; } @@ -224,6 +229,9 @@ - (void)mj_handlePropertiesWithAllowedList:(NSSet *)allowedList _allProperties = allProperties.copy; _allCodingProperties = codingProperties.copy; _mapper = mapper.copy; + _multiKeysProperties = multiKeysProperties.copy; + + _propertiesCount = _allProperties.count; } - (void)setNeedsUpdate { diff --git a/MJExtension/MJProperty.h b/MJExtension/MJProperty.h index 417b898..2fb82ae 100644 --- a/MJExtension/MJProperty.h +++ b/MJExtension/MJProperty.h @@ -55,6 +55,7 @@ typedef NS_ENUM(NSUInteger, MJEBasicType) { MJEBasicTypeMutableDictionary, MJEBasicTypeMutableData, MJEBasicTypeDecimalNumber, + MJEBasicTypeMutableAttributedString, MJEBasicTypeString, MJEBasicTypeSet, @@ -62,6 +63,7 @@ typedef NS_ENUM(NSUInteger, MJEBasicType) { MJEBasicTypeDictionary, MJEBasicTypeData, MJEBasicTypeNumber, + MJEBasicTypeAttributedString, MJEBasicTypeValue, MJEBasicTypeDate, diff --git a/MJExtension/MJProperty.m b/MJExtension/MJProperty.m index 6083e13..4a6004c 100644 --- a/MJExtension/MJProperty.m +++ b/MJExtension/MJProperty.m @@ -288,6 +288,7 @@ always_inline MJEBasicType MJEGetBasicObjectType(Class cls) { if ([cls isSubclassOfClass:NSMutableDictionary.class]) return MJEBasicTypeMutableDictionary; if ([cls isSubclassOfClass:NSMutableData.class]) return MJEBasicTypeMutableData; if ([cls isSubclassOfClass:NSDecimalNumber.class]) return MJEBasicTypeDecimalNumber; + if ([cls isSubclassOfClass:NSMutableAttributedString.class]) return MJEBasicTypeMutableAttributedString; if ([cls isSubclassOfClass:NSString.class]) return MJEBasicTypeString; if ([cls isSubclassOfClass:NSSet.class]) return MJEBasicTypeSet; @@ -295,6 +296,7 @@ always_inline MJEBasicType MJEGetBasicObjectType(Class cls) { if ([cls isSubclassOfClass:NSDictionary.class]) return MJEBasicTypeDictionary; if ([cls isSubclassOfClass:NSData.class]) return MJEBasicTypeData; if ([cls isSubclassOfClass:NSNumber.class]) return MJEBasicTypeNumber; + if ([cls isSubclassOfClass:NSAttributedString.class]) return MJEBasicTypeAttributedString; if ([cls isSubclassOfClass:NSValue.class]) return MJEBasicTypeValue; if ([cls isSubclassOfClass:NSDate.class]) return MJEBasicTypeDate; diff --git a/MJExtension/NSObject+MJKeyValue.m b/MJExtension/NSObject+MJKeyValue.m index 6ebd6d2..9ae1b7c 100755 --- a/MJExtension/NSObject+MJKeyValue.m +++ b/MJExtension/NSObject+MJKeyValue.m @@ -79,38 +79,63 @@ + (void)load #pragma mark - --公共方法-- #pragma mark - 字典 -> 模型 -- (instancetype)mj_setKeyValues:(id)keyValues -{ +- (instancetype)mj_setKeyValues:(id)keyValues { return [self mj_setKeyValues:keyValues context:nil]; } /** 核心代码: */ -- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context -{ +- (instancetype)mj_setKeyValues:(id)keyValues + context:(NSManagedObjectContext *)context { // 获得JSON对象 - keyValues = [keyValues mj_JSONObject]; + id object = [keyValues mj_JSONObject]; - MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], self, [self class], @"keyValues参数不是一个字典"); + MJExtensionAssertError([object isKindOfClass:[NSDictionary class]], self, [self class], @"keyValues参数不是一个字典"); MJEClass *mjeClass = [MJEClass cachedClass:self.class]; - NSArray *allProperties = mjeClass->_allProperties; + NSDictionary *dict = object; - NSLocale *numberLocale = nil; - if (mjeClass->_hasLocaleModifier) { - numberLocale = self.class.mj_locale; + if (mjeClass->_propertiesCount > dict.count) { + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) { + MJProperty *property = mjeClass->_mapper[key]; + while (property) { + [self mj_setValue:value forProperty:property + context:context locale:mjeClass->_locale + classCache:mjeClass]; + property = property->_nextSame; + } + }]; + if (mjeClass->_multiKeysProperties.count) { + [self mj_enumerateProperties:mjeClass->_multiKeysProperties + withDictionary:dict classCache:mjeClass context:context]; + } + } else { + [self mj_enumerateProperties:mjeClass->_allProperties + withDictionary:dict classCache:mjeClass + context:context]; } - - [allProperties enumerateObjectsUsingBlock:^(MJProperty * _Nonnull property, NSUInteger idx, BOOL * _Nonnull stop) { + + // 转换完毕 + if (mjeClass->_hasDictionary2ObjectModifier) { + [self mj_didConvertToObjectWithKeyValues:keyValues]; + } + return self; +} + +- (void)mj_enumerateProperties:(NSArray *)properties + withDictionary:(NSDictionary *)dictionary + classCache:(MJEClass *)classCache + context:(NSManagedObjectContext *)context { + [properties enumerateObjectsUsingBlock:^(MJProperty * _Nonnull property, NSUInteger idx, BOOL * _Nonnull stop) { @try { // 1.取出属性值 id value; if (!property->_isMultiMapping) { - value = keyValues[property->_mappedKey]; + value = dictionary[property->_mappedKey]; } else { for (NSArray *propertyKeys in property->_mappedMultiKeys) { - value = keyValues; + value = dictionary; for (MJPropertyKey *propertyKey in propertyKeys) { value = [propertyKey valueInObject:value]; } @@ -118,17 +143,9 @@ - (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *) } } - if (mjeClass->_hasOld2NewModifier - && property->_hasValueModifier) { - id newValue = [self mj_newValueFromOldValue:value property:property]; - if (newValue != value) { // 有过滤后的新值 - [property setValue:newValue forObject:self]; - return; - } - } - [self mj_setValue:value forProperty:property - inContext:context locale:numberLocale]; + context:context locale:classCache->_locale + classCache:classCache]; } @catch (NSException *exception) { MJExtensionBuildError([self class], exception.reason); @@ -138,17 +155,21 @@ - (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *) #endif } }]; - - // 转换完毕 - if (mjeClass->_hasDictionary2ObjectModifier) { - [self mj_didConvertToObjectWithKeyValues:keyValues]; - } - return self; } - (void)mj_setValue:(id)value forProperty:(MJProperty *)property - inContext:(NSManagedObjectContext *)context - locale:(NSLocale *)locale { + context:(NSManagedObjectContext *)context + locale:(NSLocale *)locale + classCache:(MJEClass *)classCache { + if (classCache->_hasOld2NewModifier + && property->_hasValueModifier) { + id newValue = [self mj_newValueFromOldValue:value property:property]; + if (newValue != value) { // 有过滤后的新值 + [property setValue:newValue forObject:self]; + return; + } + } + // 如果没有值,就直接返回 if (!value || value == NSNull.null) return; // 2.复杂处理 @@ -198,6 +219,8 @@ - (void)mj_setValue:(id)value forProperty:(MJProperty *)property long double num = [value mj_longDoubleValueWithLocale:locale]; mj_selfSend(property.setter, long double, num); return; + } else if (property->_basicObjectType == MJEBasicTypeData || property->_basicObjectType == MJEBasicTypeMutableData) { + value = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding].mutableCopy; } else if (property.isNumber) { NSString *oldValue = value; @@ -377,8 +400,10 @@ - (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys ignoredKeys:(NSArr } else if ([value isKindOfClass:[NSArray class]]) { // 3.处理数组里面有模型的情况 value = [NSObject mj_keyValuesArrayWithObjectArray:value]; - } else if (propertyClass == [NSURL class]) { + } else if (property->_basicObjectType == MJEBasicTypeURL) { value = [value absoluteString]; + } else if (property->_basicObjectType == MJEBasicTypeAttributedString || property->_basicObjectType == MJEBasicTypeMutableAttributedString) { + value = [(NSAttributedString *)value string]; } // 4.赋值 diff --git a/MJExtensionTests/CoreDataTests.swift b/MJExtensionTests/CoreDataTests.swift index 97f8326..8d2075d 100644 --- a/MJExtensionTests/CoreDataTests.swift +++ b/MJExtensionTests/CoreDataTests.swift @@ -57,8 +57,7 @@ class CoreDataTests: XCTestCase { func json2CoreDataObject() { context.performAndWait { guard let tester = MJCoreDataTester.mj_object(withKeyValues: Values.testJSONObject, context: context) else { - XCTAssert(false, "conversion to core data object failed") - return + fatalError("conversion to core data object failed") } XCTAssert(tester.isJuan == Values.isJuan) @@ -77,8 +76,7 @@ class CoreDataTests: XCTestCase { coreDataObject.identifier = Values.identifier guard let dict = coreDataObject.mj_keyValues() else { - XCTAssert(false, "conversion to keyValues failed") - return + fatalError("conversion to core data object failed") } XCTAssert(dict["isJuan"] as? Bool == Values.isJuan) diff --git a/MJExtensionTests/MultiThreadTests.swift b/MJExtensionTests/MultiThreadTests.swift index a9c3c98..85e3eb4 100644 --- a/MJExtensionTests/MultiThreadTests.swift +++ b/MJExtensionTests/MultiThreadTests.swift @@ -41,8 +41,7 @@ class MultiThreadTests: XCTestCase { sleep(1) let testerDict = self.testerJSON(id) guard let _ = MJTester.mj_object(withKeyValues: testerDict) else { - XCTAssert(false, "conversion failed") - return + fatalError("conversion failed") } print("tester: \(id)") // XCTAssert(tester.isSpecialAgent) @@ -59,8 +58,7 @@ class MultiThreadTests: XCTestCase { sleep(1) let catDict = self.catJSON(id) guard let _ = MJCat.mj_object(withKeyValues: catDict) else { - XCTAssert(false, "convertion failed") - return + fatalError("conversion failed") } print("cat: \(id)") // cat.nicknames?.forEach({ (nickname) in diff --git a/MJExtensionTests/SwiftModel/MJArticle.swift b/MJExtensionTests/SwiftModel/MJArticle.swift new file mode 100644 index 0000000..ee2a4d7 --- /dev/null +++ b/MJExtensionTests/SwiftModel/MJArticle.swift @@ -0,0 +1,14 @@ +// +// MJArticle.swift +// MJExtensionTests +// +// Created by Frank on 2021/12/23. +// Copyright © 2021 MJ Lee. All rights reserved. +// + +import Foundation + +@objcMembers +class MJArticle: NSObject { + var attributedTitle: NSAttributedString? +} diff --git a/MJExtensionTests/SwiftModel/MJCredential.swift b/MJExtensionTests/SwiftModel/MJCredential.swift new file mode 100644 index 0000000..93be3b7 --- /dev/null +++ b/MJExtensionTests/SwiftModel/MJCredential.swift @@ -0,0 +1,13 @@ +// +// MJCredential.swift +// MJExtensionTests +// +// Created by Frank on 2021/12/23. +// Copyright © 2021 MJ Lee. All rights reserved. +// + +import Foundation +@objcMembers +class MJCredential: NSObject { + var data: Data? +} diff --git a/MJExtensionTests/SwiftModelTests.swift b/MJExtensionTests/SwiftModelTests.swift index 1641507..ef4ddc2 100644 --- a/MJExtensionTests/SwiftModelTests.swift +++ b/MJExtensionTests/SwiftModelTests.swift @@ -20,21 +20,23 @@ class SwiftModelTests: XCTestCase { "child": "im" ] - for _ in 0...5 { - guard let tester1 = MJSuperTester.mj_object(withKeyValues: testerDict) else { - XCTAssert(false, "conversion failed") - return - } - guard let tester = MJTester.mj_object(withKeyValues: testerDict) else { - XCTAssert(false, "conversion failed") - return - } - - XCTAssert(tester.isSpecialAgent) - XCTAssert(tester.identifier == testerDict["identifier"] as? String) - XCTAssert(tester.age == testerDict["age"] as! Int) - XCTAssert(tester.name == testerDict["name"] as? String) + guard let tester1 = MJSuperTester.mj_object(withKeyValues: testerDict) else { + fatalError("conversion failed") } + XCTAssert(tester1.isSpecialAgent) + XCTAssert(tester1.identifier == testerDict["identifier"] as? String) + XCTAssert(tester1.age == testerDict["age"] as! Int) + XCTAssert(tester1.name == testerDict["name"] as? String) + + guard let tester = MJTester.mj_object(withKeyValues: testerDict) else { + fatalError("conversion failed") + } + + XCTAssert(tester.isSpecialAgent) + XCTAssert(tester.identifier == testerDict["identifier"] as? String) + XCTAssert(tester.age == testerDict["age"] as! Int) + XCTAssert(tester.name == testerDict["name"] as? String) + XCTAssertEqual(tester.child, testerDict["child"] as? String) } // MARK: 🌈 Use Objective-C model code @@ -47,7 +49,7 @@ class SwiftModelTests: XCTestCase { ] guard let user = MJUser.mj_object(withKeyValues: userDict) else { - XCTAssert(false, "conversion failed") + fatalError("conversion failed") return } XCTAssert(user.rich) diff --git a/MJExtensionTests/ValueTransformingTest.swift b/MJExtensionTests/ValueTransformingTest.swift new file mode 100644 index 0000000..8f64fc9 --- /dev/null +++ b/MJExtensionTests/ValueTransformingTest.swift @@ -0,0 +1,35 @@ +// +// ValueTransformingTest.swift +// MJExtensionTests +// +// Created by Frank on 2021/12/23. +// Copyright © 2021 MJ Lee. All rights reserved. +// + +import XCTest + +class ValueTransformingTest: XCTestCase { + func testString2Data() throws { + let dict: [String: Any] = [ + "data": "7355608" + ] + + guard let credential = MJCredential.mj_object(withKeyValues: dict) else { fatalError("credential conversion failed") } + guard let testString = dict["data"] as? String, + let testData = testString.data(using: .utf8) else { fatalError("8 bad data😭") } + + XCTAssertEqual(credential.data, testData) + } + + @available(iOS 15, *) + func testAttributedString2String() throws { + let article = MJArticle() + article.attributedTitle = try? NSAttributedString(markdown: "**m0nesy may help Niko get major trophy.**") + + guard let JSON = article.mj_JSONString() else { + fatalError("Object to JSON conversion failed") + } + + XCTAssertEqual(JSON, "{\"attributedTitle\":\"m0nesy may help Niko get major trophy.\"}") + } +}