ObjectCreationTests.mm 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2017 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import "RLMTestCase.h"
  19. #pragma mark - Test Objects
  20. @interface DogExtraObject : RLMObject
  21. @property NSString *dogName;
  22. @property int age;
  23. @property NSString *breed;
  24. @end
  25. @implementation DogExtraObject
  26. @end
  27. @interface BizzaroDog : RLMObject
  28. @property int dogName;
  29. @property NSString *age;
  30. @end
  31. @implementation BizzaroDog
  32. @end
  33. @interface PrimaryKeyWithDefault : RLMObject
  34. @property NSString *stringCol;
  35. @property int intCol;
  36. @end
  37. @implementation PrimaryKeyWithDefault
  38. + (NSString *)primaryKey {
  39. return @"stringCol";
  40. }
  41. + (NSDictionary *)defaultPropertyValues {
  42. return @{@"intCol": @10};
  43. }
  44. @end
  45. @interface AllLinks : RLMObject
  46. @property StringObject *string;
  47. @property PrimaryStringObject *primaryString;
  48. @property RLM_GENERIC_ARRAY(IntObject) *intArray;
  49. @property RLM_GENERIC_ARRAY(PrimaryIntObject) *primaryIntArray;
  50. @end
  51. @implementation AllLinks
  52. @end
  53. @interface AllLinksWithPrimary : RLMObject
  54. @property NSString *pk;
  55. @property StringObject *string;
  56. @property PrimaryStringObject *primaryString;
  57. @property RLM_GENERIC_ARRAY(IntObject) *intArray;
  58. @property RLM_GENERIC_ARRAY(PrimaryIntObject) *primaryIntArray;
  59. @end
  60. @implementation AllLinksWithPrimary
  61. + (NSString *)primaryKey {
  62. return @"pk";
  63. }
  64. @end
  65. @interface PrimaryKeyAndRequiredString : RLMObject
  66. @property int pk;
  67. @property NSString *value;
  68. @end
  69. @implementation PrimaryKeyAndRequiredString
  70. + (NSString *)primaryKey {
  71. return @"pk";
  72. }
  73. + (NSArray *)requiredProperties {
  74. return @[@"value"];
  75. }
  76. @end
  77. #pragma mark - Tests
  78. @interface ObjectCreationTests : RLMTestCase
  79. @end
  80. @implementation ObjectCreationTests
  81. #pragma mark - Init With Value
  82. - (void)testInitWithInvalidThings {
  83. RLMAssertThrowsWithReasonMatching([[DogObject alloc] initWithValue:self.nonLiteralNil],
  84. @"Must provide a non-nil value");
  85. RLMAssertThrowsWithReasonMatching([[DogObject alloc] initWithValue:NSNull.null],
  86. @"Must provide a non-nil value");
  87. RLMAssertThrowsWithReasonMatching([[DogObject alloc] initWithValue:@"name"],
  88. @"Invalid value 'name' to initialize object of type 'DogObject'");
  89. }
  90. - (void)testInitWithArray {
  91. auto co = [[CompanyObject alloc] initWithValue:@[]];
  92. XCTAssertNil(co.name);
  93. XCTAssertEqual(co.employees.count, 0U);
  94. co = [[CompanyObject alloc] initWithValue:@[@"empty company"]];
  95. XCTAssertEqualObjects(co.name, @"empty company");
  96. XCTAssertEqual(co.employees.count, 0U);
  97. co = [[CompanyObject alloc] initWithValue:@[@"empty company", NSNull.null]];
  98. XCTAssertEqualObjects(co.name, @"empty company");
  99. XCTAssertEqual(co.employees.count, 0U);
  100. co = [[CompanyObject alloc] initWithValue:@[@"empty company", @[]]];
  101. XCTAssertEqualObjects(co.name, @"empty company");
  102. XCTAssertEqual(co.employees.count, 0U);
  103. co = [[CompanyObject alloc] initWithValue:@[@"one employee",
  104. @[@[@"name", @2, @YES]]]];
  105. XCTAssertEqualObjects(co.name, @"one employee");
  106. XCTAssertEqual(co.employees.count, 1U);
  107. EmployeeObject *eo = co.employees.firstObject;
  108. XCTAssertEqualObjects(eo.name, @"name");
  109. XCTAssertEqual(eo.age, 2);
  110. XCTAssertEqual(eo.hired, YES);
  111. co = [[CompanyObject alloc] initWithValue:@[@"one employee", @[eo]]];
  112. XCTAssertEqualObjects(co.name, @"one employee");
  113. XCTAssertEqual(co.employees.count, 1U);
  114. eo = co.employees.firstObject;
  115. XCTAssertEqualObjects(eo.name, @"name");
  116. XCTAssertEqual(eo.age, 2);
  117. XCTAssertEqual(eo.hired, YES);
  118. }
  119. - (void)testWithNonArrayEnumerableForRLMArrayProperty {
  120. auto employees = @[@[@"name", @2, @YES], @[@"name 2", @3, @NO]];
  121. auto co = [[CompanyObject alloc] initWithValue:@[@"one employee", employees.reverseObjectEnumerator]];
  122. XCTAssertEqual(2U, co.employees.count);
  123. XCTAssertEqualObjects(@"name 2", co.employees[0].name);
  124. XCTAssertEqualObjects(@"name", co.employees[1].name);
  125. }
  126. - (void)testInitWithArrayUsesDefaultValuesForMissingFields {
  127. auto obj = [[NumberDefaultsObject alloc] initWithValue:@[]];
  128. XCTAssertEqualObjects(obj.intObj, @1);
  129. XCTAssertEqualObjects(obj.floatObj, @2.2f);
  130. XCTAssertEqualObjects(obj.doubleObj, @3.3);
  131. XCTAssertEqualObjects(obj.boolObj, @NO);
  132. obj = [[NumberDefaultsObject alloc] initWithValue:@[@10, @22.2f]];
  133. XCTAssertEqualObjects(obj.intObj, @10);
  134. XCTAssertEqualObjects(obj.floatObj, @22.2f);
  135. XCTAssertEqualObjects(obj.doubleObj, @3.3);
  136. XCTAssertEqualObjects(obj.boolObj, @NO);
  137. }
  138. - (void)testInitWithInvalidArray {
  139. RLMAssertThrowsWithReason(([[DogObject alloc] initWithValue:@[@"name", @"age"]]),
  140. @"Invalid value 'age' of type '__NSCFConstantString' for 'int' property 'DogObject.age'.");
  141. RLMAssertThrowsWithReason(([[DogObject alloc] initWithValue:@[@"name", NSNull.null]]),
  142. @"Invalid value '(null)' of type '(null)' for 'int' property 'DogObject.age'.");
  143. RLMAssertThrowsWithReason(([[DogObject alloc] initWithValue:@[@"name", @5, @"too many values"]]),
  144. @"Invalid array input: more values (3) than properties (2).");
  145. }
  146. - (void)testInitWithDictionary {
  147. auto co = [[CompanyObject alloc] initWithValue:@{}];
  148. XCTAssertNil(co.name);
  149. XCTAssertEqual(co.employees.count, 0U);
  150. co = [[CompanyObject alloc] initWithValue:@{@"name": NSNull.null}];
  151. XCTAssertNil(co.name);
  152. XCTAssertEqual(co.employees.count, 0U);
  153. co = [[CompanyObject alloc] initWithValue:@{@"name": @"empty company"}];
  154. XCTAssertEqualObjects(co.name, @"empty company");
  155. XCTAssertEqual(co.employees.count, 0U);
  156. co = [[CompanyObject alloc] initWithValue:@{@"name": @"empty company",
  157. @"employees": NSNull.null}];
  158. XCTAssertEqualObjects(co.name, @"empty company");
  159. XCTAssertEqual(co.employees.count, 0U);
  160. co = [[CompanyObject alloc] initWithValue:@{@"name": @"empty company",
  161. @"employees": @[]}];
  162. XCTAssertEqualObjects(co.name, @"empty company");
  163. XCTAssertEqual(co.employees.count, 0U);
  164. co = [[CompanyObject alloc] initWithValue:@{@"name": @"one employee",
  165. @"employees": @[@[@"name", @2, @YES]]}];
  166. XCTAssertEqualObjects(co.name, @"one employee");
  167. XCTAssertEqual(co.employees.count, 1U);
  168. EmployeeObject *eo = co.employees.firstObject;
  169. XCTAssertEqualObjects(eo.name, @"name");
  170. XCTAssertEqual(eo.age, 2);
  171. XCTAssertEqual(eo.hired, YES);
  172. co = [[CompanyObject alloc] initWithValue:@{@"name": @"one employee",
  173. @"employees": @[@{@"name": @"name",
  174. @"age": @2,
  175. @"hired": @YES}]}];
  176. XCTAssertEqualObjects(co.name, @"one employee");
  177. XCTAssertEqual(co.employees.count, 1U);
  178. eo = co.employees.firstObject;
  179. XCTAssertEqualObjects(eo.name, @"name");
  180. XCTAssertEqual(eo.age, 2);
  181. XCTAssertEqual(eo.hired, YES);
  182. co = [[CompanyObject alloc] initWithValue:@{@"name": @"no employees",
  183. @"extra fields": @"are okay"}];
  184. XCTAssertEqualObjects(co.name, @"no employees");
  185. XCTAssertEqual(co.employees.count, 0U);
  186. }
  187. - (void)testInitWithInvalidDictionary {
  188. RLMAssertThrowsWithReason(([[DogObject alloc] initWithValue:@{@"name": @"a", @"age": NSNull.null}]),
  189. @"Invalid value '(null)' of type '(null)' for 'int' property 'DogObject.age'");
  190. RLMAssertThrowsWithReasonMatching(([[DogObject alloc] initWithValue:@{@"name": @"a", @"age": NSDate.date}]),
  191. @"Invalid value '20.*' of type '.*Date' for 'int' property 'DogObject.age'");
  192. }
  193. - (void)testInitWithDictionaryUsesDefaultValuesForMissingFields {
  194. auto obj = [[NumberDefaultsObject alloc] initWithValue:@{}];
  195. XCTAssertEqualObjects(obj.intObj, @1);
  196. XCTAssertEqualObjects(obj.floatObj, @2.2f);
  197. XCTAssertEqualObjects(obj.doubleObj, @3.3);
  198. XCTAssertEqualObjects(obj.boolObj, @NO);
  199. obj = [[NumberDefaultsObject alloc] initWithValue:@{@"intObj": @10}];
  200. XCTAssertEqualObjects(obj.intObj, @10);
  201. XCTAssertEqualObjects(obj.floatObj, @2.2f);
  202. XCTAssertEqualObjects(obj.doubleObj, @3.3);
  203. XCTAssertEqualObjects(obj.boolObj, @NO);
  204. }
  205. - (void)testInitWithObject {
  206. auto eo = [[EmployeeObject alloc] init];
  207. eo.name = @"employee name";
  208. eo.age = 1;
  209. eo.hired = NO;
  210. auto co = [[CompanyObject alloc] init];
  211. co.name = @"name";
  212. [co.employees addObject:eo];
  213. auto co2 = [[CompanyObject alloc] initWithValue:co];
  214. XCTAssertEqualObjects(co.name, co2.name);
  215. XCTAssertEqual(co.employees[0], co2.employees[0]); // not EqualObjects as it's a shallow copy
  216. auto dogExt = [[DogExtraObject alloc] initWithValue:@[@"Fido", @12, @"Poodle"]];
  217. auto dog = [[DogObject alloc] initWithValue:dogExt];
  218. XCTAssertEqualObjects(dog.dogName, @"Fido");
  219. XCTAssertEqual(dog.age, 12);
  220. auto owner = [[OwnerObject alloc] initWithValue:@[@"Alex", dogExt]];
  221. XCTAssertEqualObjects(owner.dog.dogName, @"Fido");
  222. auto array1 = [[AllPrimitiveArrays alloc] init];
  223. [array1.intObj addObject:@2];
  224. auto array2 = [[AllPrimitiveArrays alloc] initWithValue:array1];
  225. XCTAssertEqual(array2.intObj.count, 1U);
  226. XCTAssertEqualObjects(array2.intObj.firstObject, @2);
  227. }
  228. - (void)testInitWithInvalidObject {
  229. // No overlap in properties
  230. auto so = [[StringObject alloc] initWithValue:@[@"str"]];
  231. RLMAssertThrowsWithReason([[IntObject alloc] initWithValue:so], @"missing key 'intCol'");
  232. // Dog has some but not all of DogExtra's properties
  233. auto dog = [[DogObject alloc] initWithValue:@[@"Fido", @10]];
  234. RLMAssertThrowsWithReason([[DogExtraObject alloc] initWithValue:dog], @"missing key 'breed'");
  235. // Same property names, but different types
  236. RLMAssertThrowsWithReason([[BizzaroDog alloc] initWithValue:dog],
  237. @"Invalid value 'Fido' of type '__NSCFConstantString' for 'int' property 'BizzaroDog.dogName'");
  238. }
  239. - (void)testInitPrimitiveArraysWithInvalidValues {
  240. RLMAssertThrowsWithReason([[AllPrimitiveArrays alloc] initWithValue:@{@"intObj": @[NSNull.null]}],
  241. @"Invalid value '<null>' of type 'NSNull' for 'int' array property 'AllPrimitiveArrays.intObj'.");
  242. RLMAssertThrowsWithReason([[AllPrimitiveArrays alloc] initWithValue:@{@"intObj": @[@1.1]}],
  243. @"Invalid value '1.1' of type '__NSCFNumber' for 'int' array property 'AllPrimitiveArrays.intObj'.");
  244. RLMAssertThrowsWithReason([[AllPrimitiveArrays alloc] initWithValue:@{@"intObj": @[@"0"]}],
  245. @"Invalid value '0' of type '__NSCFConstantString' for 'int' array property 'AllPrimitiveArrays.intObj'.");
  246. RLMAssertThrowsWithReason([[AllPrimitiveArrays alloc] initWithValue:@{@"intObj": @1}],
  247. @"Invalid value (1) for 'int' array property 'AllPrimitiveArrays.intObj': value is not enumerable.");
  248. }
  249. - (void)testInitWithCustomAccessors {
  250. // Create with array
  251. auto ca = [[CustomAccessorsObject alloc] initWithValue:@[@"a", @1]];
  252. XCTAssertEqualObjects(ca.name, @"a");
  253. XCTAssertEqual(ca.age, 1);
  254. // Create with dictionary
  255. ca = [[CustomAccessorsObject alloc] initWithValue:@{@"name": @"b", @"age": @2}];
  256. XCTAssertEqualObjects(ca.name, @"b");
  257. XCTAssertEqual(ca.age, 2);
  258. // Create with KVC-compatible object
  259. ca = [[CustomAccessorsObject alloc] initWithValue:ca];
  260. XCTAssertEqualObjects(ca.name, @"b");
  261. XCTAssertEqual(ca.age, 2);
  262. }
  263. - (void)testInitWithRenamedColumns {
  264. // Create with array
  265. auto obj = [[RenamedProperties1 alloc] initWithValue:@[@1, @"a"]];
  266. XCTAssertEqual(obj.propA, 1);
  267. XCTAssertEqualObjects(obj.propB, @"a");
  268. // Create with dictionary
  269. obj = [[RenamedProperties1 alloc] initWithValue:@{@"propB": @"b", @"propA": @2}];
  270. XCTAssertEqual(obj.propA, 2);
  271. XCTAssertEqualObjects(obj.propB, @"b");
  272. // Create with KVC-compatible object
  273. obj = [[RenamedProperties1 alloc] initWithValue:obj];
  274. XCTAssertEqual(obj.propA, 2);
  275. XCTAssertEqualObjects(obj.propB, @"b");
  276. }
  277. - (void)testInitAllPropertyTypes {
  278. auto now = [NSDate date];
  279. auto bytes = [NSData dataWithBytes:"a" length:1];
  280. auto so = [[StringObject alloc] init];
  281. so.stringCol = @"string";
  282. auto ao = [[AllTypesObject alloc] initWithValue:@[@YES, @1, @1.1f, @1.11,
  283. @"string", bytes,
  284. now, @YES, @11, so]];
  285. XCTAssertEqual(ao.boolCol, YES);
  286. XCTAssertEqual(ao.intCol, 1);
  287. XCTAssertEqual(ao.floatCol, 1.1f);
  288. XCTAssertEqual(ao.doubleCol, 1.11);
  289. XCTAssertEqualObjects(ao.stringCol, @"string");
  290. XCTAssertEqualObjects(ao.binaryCol, bytes);
  291. XCTAssertEqual(ao.dateCol, now);
  292. XCTAssertEqual(ao.cBoolCol, true);
  293. XCTAssertEqual(ao.longCol, 11);
  294. XCTAssertEqual(ao.objectCol, so);
  295. auto opt = [[AllOptionalTypes alloc] initWithValue:@[NSNull.null, NSNull.null,
  296. NSNull.null, NSNull.null,
  297. NSNull.null, NSNull.null,
  298. NSNull.null]];
  299. XCTAssertNil(opt.intObj);
  300. XCTAssertNil(opt.boolObj);
  301. XCTAssertNil(opt.floatObj);
  302. XCTAssertNil(opt.doubleObj);
  303. XCTAssertNil(opt.date);
  304. XCTAssertNil(opt.data);
  305. XCTAssertNil(opt.string);
  306. opt = [[AllOptionalTypes alloc] initWithValue:@[@1, @2.2f, @3.3, @YES,
  307. @"str", bytes, now]];
  308. XCTAssertEqualObjects(opt.intObj, @1);
  309. XCTAssertEqualObjects(opt.boolObj, @YES);
  310. XCTAssertEqualObjects(opt.floatObj, @2.2f);
  311. XCTAssertEqualObjects(opt.doubleObj, @3.3);
  312. XCTAssertEqualObjects(opt.date, now);
  313. XCTAssertEqualObjects(opt.data, bytes);
  314. XCTAssertEqualObjects(opt.string, @"str");
  315. auto arrays = [[AllPrimitiveArrays alloc] initWithValue:@{@"intObj": @[@1, @2, @3],
  316. @"boolObj": @[@YES, @NO],
  317. @"floatObj": @[@1.1f, @2.2f],
  318. @"doubleObj": @[@3.3, @4.4],
  319. @"stringObj": @[@"a", @"b"],
  320. @"dateObj": @[now],
  321. @"dataObj": @[bytes]}];
  322. XCTAssertEqual(3U, arrays.intObj.count);
  323. XCTAssertEqual(2U, arrays.boolObj.count);
  324. XCTAssertEqual(2U, arrays.floatObj.count);
  325. XCTAssertEqual(2U, arrays.doubleObj.count);
  326. XCTAssertEqual(2U, arrays.stringObj.count);
  327. XCTAssertEqual(1U, arrays.dateObj.count);
  328. XCTAssertEqual(1U, arrays.dataObj.count);
  329. XCTAssertEqualObjects([arrays.intObj valueForKey:@"self"], (@[@1, @2, @3]));
  330. XCTAssertEqualObjects([arrays.boolObj valueForKey:@"self"], (@[@YES, @NO]));
  331. XCTAssertEqualObjects([arrays.floatObj valueForKey:@"self"], (@[@1.1f, @2.2f]));
  332. XCTAssertEqualObjects([arrays.doubleObj valueForKey:@"self"], (@[@3.3, @4.4]));
  333. XCTAssertEqualObjects([arrays.stringObj valueForKey:@"self"], (@[@"a", @"b"]));
  334. XCTAssertEqualObjects([arrays.dateObj valueForKey:@"self"], (@[now]));
  335. XCTAssertEqualObjects([arrays.dataObj valueForKey:@"self"], (@[bytes]));
  336. }
  337. - (void)testInitValidatesNumberTypes {
  338. XCTAssertNoThrow(([[NumberObject alloc] initWithValue:@{}]));
  339. RLMAssertThrowsWithReason(([[NumberObject alloc] initWithValue:@{@"intObj": @1.1}]),
  340. @"Invalid value '1.1' of type '__NSCFNumber' for 'int?' property 'NumberObject.intObj'.");
  341. RLMAssertThrowsWithReason(([[NumberObject alloc] initWithValue:@{@"intObj": @1.1f}]),
  342. @"Invalid value '1.1' of type '__NSCFNumber' for 'int?' property 'NumberObject.intObj'.");
  343. XCTAssertNoThrow(([[NumberObject alloc] initWithValue:@{@"boolObj": @YES}]));
  344. XCTAssertNoThrow(([[NumberObject alloc] initWithValue:@{@"boolObj": @1}]));
  345. XCTAssertNoThrow(([[NumberObject alloc] initWithValue:@{@"boolObj": @0}]));
  346. // This error is kinda bad....
  347. RLMAssertThrowsWithReason(([[NumberObject alloc] initWithValue:@{@"boolObj": @1.0}]),
  348. @"Invalid value '1' of type '__NSCFNumber' for 'bool?' property 'NumberObject.boolObj'.");
  349. RLMAssertThrowsWithReason(([[NumberObject alloc] initWithValue:@{@"boolObj": @1.0f}]),
  350. @"Invalid value '1' of type '__NSCFNumber' for 'bool?' property 'NumberObject.boolObj'.");
  351. RLMAssertThrowsWithReason(([[NumberObject alloc] initWithValue:@{@"boolObj": @2}]),
  352. @"Invalid value '2' of type '__NSCFNumber' for 'bool?' property 'NumberObject.boolObj'.");
  353. XCTAssertNoThrow(([[NumberObject alloc] initWithValue:@{@"floatObj": @1.1}]));
  354. RLMAssertThrowsWithReasonMatching(([[NumberObject alloc] initWithValue:@{@"floatObj": @DBL_MAX}]),
  355. @"Invalid value '.*' of type '__NSCFNumber' for 'float\\?' property 'NumberObject.floatObj'");
  356. XCTAssertNoThrow(([[NumberObject alloc] initWithValue:@{@"doubleObj": @DBL_MAX}]));
  357. }
  358. #pragma mark - Create
  359. - (void)testCreateWithArray {
  360. auto realm = RLMRealm.defaultRealm;
  361. [realm beginWriteTransaction];
  362. auto co = [CompanyObject createInRealm:realm withValue:@[@"empty company", NSNull.null]];
  363. XCTAssertEqualObjects(co.name, @"empty company");
  364. XCTAssertEqual(co.employees.count, 0U);
  365. co = [CompanyObject createInRealm:realm withValue:@[@"empty company", @[]]];
  366. XCTAssertEqualObjects(co.name, @"empty company");
  367. XCTAssertEqual(co.employees.count, 0U);
  368. co = [CompanyObject createInRealm:realm withValue:@[@"one employee",
  369. @[@[@"name", @2, @YES]]]];
  370. XCTAssertEqualObjects(co.name, @"one employee");
  371. XCTAssertEqual(co.employees.count, 1U);
  372. EmployeeObject *eo = co.employees.firstObject;
  373. XCTAssertEqualObjects(eo.name, @"name");
  374. XCTAssertEqual(eo.age, 2);
  375. XCTAssertEqual(eo.hired, YES);
  376. [realm cancelWriteTransaction];
  377. }
  378. - (void)testCreateWithInvalidArray {
  379. auto realm = RLMRealm.defaultRealm;
  380. [realm beginWriteTransaction];
  381. RLMAssertThrowsWithReason(([DogObject createInRealm:realm withValue:@[@"name", @"age"]]),
  382. @"Invalid value 'age' of type '__NSCFConstantString' for 'int' property 'DogObject.age'");
  383. RLMAssertThrowsWithReason(([DogObject createInRealm:realm withValue:@[@"name", NSNull.null]]),
  384. @"Invalid value '<null>' of type 'NSNull' for 'int' property 'DogObject.age'");
  385. RLMAssertThrowsWithReason(([DogObject createInRealm:realm withValue:@[@"name", @5, @"too many values"]]),
  386. @"Invalid array input: more values (3) than properties (2).");
  387. RLMAssertThrowsWithReason(([PrimaryStringObject createInRealm:realm withValue:@[]]),
  388. @"Missing value for property 'PrimaryStringObject.stringCol'");
  389. [realm cancelWriteTransaction];
  390. }
  391. - (void)testCreateWithDictionary {
  392. auto realm = RLMRealm.defaultRealm;
  393. [realm beginWriteTransaction];
  394. auto co = [CompanyObject createInRealm:realm withValue:@{}];
  395. XCTAssertNil(co.name);
  396. XCTAssertEqual(co.employees.count, 0U);
  397. co = [CompanyObject createInRealm:realm withValue:@{@"name": NSNull.null}];
  398. XCTAssertNil(co.name);
  399. XCTAssertEqual(co.employees.count, 0U);
  400. co = [CompanyObject createInRealm:realm withValue:@{@"name": @"empty company"}];
  401. XCTAssertEqualObjects(co.name, @"empty company");
  402. XCTAssertEqual(co.employees.count, 0U);
  403. co = [CompanyObject createInRealm:realm withValue:@{@"name": @"empty company",
  404. @"employees": NSNull.null}];
  405. XCTAssertEqualObjects(co.name, @"empty company");
  406. XCTAssertEqual(co.employees.count, 0U);
  407. co = [CompanyObject createInRealm:realm withValue:@{@"name": @"empty company",
  408. @"employees": @[]}];
  409. XCTAssertEqualObjects(co.name, @"empty company");
  410. XCTAssertEqual(co.employees.count, 0U);
  411. co = [CompanyObject createInRealm:realm withValue:@{@"name": @"one employee",
  412. @"employees": @[@[@"name", @2, @YES]]}];
  413. XCTAssertEqualObjects(co.name, @"one employee");
  414. XCTAssertEqual(co.employees.count, 1U);
  415. EmployeeObject *eo = co.employees.firstObject;
  416. XCTAssertEqualObjects(eo.name, @"name");
  417. XCTAssertEqual(eo.age, 2);
  418. XCTAssertEqual(eo.hired, YES);
  419. co = [CompanyObject createInRealm:realm withValue:@{@"name": @"one employee",
  420. @"employees": @[@{@"name": @"name",
  421. @"age": @2,
  422. @"hired": @YES}]}];
  423. XCTAssertEqualObjects(co.name, @"one employee");
  424. XCTAssertEqual(co.employees.count, 1U);
  425. eo = co.employees.firstObject;
  426. XCTAssertEqualObjects(eo.name, @"name");
  427. XCTAssertEqual(eo.age, 2);
  428. XCTAssertEqual(eo.hired, YES);
  429. co = [CompanyObject createInRealm:realm withValue:@{@"name": @"no employees",
  430. @"extra fields": @"are okay"}];
  431. XCTAssertEqualObjects(co.name, @"no employees");
  432. XCTAssertEqual(co.employees.count, 0U);
  433. [realm cancelWriteTransaction];
  434. }
  435. - (void)testCreateWithInvalidDictionary {
  436. auto realm = RLMRealm.defaultRealm;
  437. [realm beginWriteTransaction];
  438. RLMAssertThrowsWithReason(([DogObject createInRealm:realm withValue:@{@"name": @"a", @"age": NSNull.null}]),
  439. @"Invalid value '<null>' of type 'NSNull' for 'int' property 'DogObject.age'");
  440. RLMAssertThrowsWithReasonMatching(([DogObject createInRealm:realm withValue:@{@"name": @"a", @"age": NSDate.date}]),
  441. @"Invalid value '20.*' for 'int' property 'DogObject.age'");
  442. [realm cancelWriteTransaction];
  443. }
  444. - (void)testCreateWithObject {
  445. auto realm = RLMRealm.defaultRealm;
  446. [realm beginWriteTransaction];
  447. auto eo = [[EmployeeObject alloc] init];
  448. eo.name = @"employee name";
  449. eo.age = 1;
  450. eo.hired = NO;
  451. auto co = [[CompanyObject alloc] init];
  452. co.name = @"name";
  453. [co.employees addObject:eo];
  454. auto co2 = [CompanyObject createInRealm:realm withValue:co];
  455. XCTAssertEqualObjects(co.name, co2.name);
  456. // Deep copy, so it's a different object
  457. XCTAssertFalse([co.employees[0] isEqualToObject:co2.employees[0]]);
  458. XCTAssertEqualObjects(co.employees[0].name, co2.employees[0].name);
  459. auto dogExt = [DogExtraObject createInRealm:realm withValue:@[@"Fido", @12, @"Poodle"]];
  460. auto dog = [DogObject createInRealm:realm withValue:dogExt];
  461. XCTAssertEqualObjects(dog.dogName, @"Fido");
  462. XCTAssertEqual(dog.age, 12);
  463. auto owner = [OwnerObject createInRealm:realm withValue:@[@"Alex", dogExt]];
  464. XCTAssertEqualObjects(owner.dog.dogName, @"Fido");
  465. [realm cancelWriteTransaction];
  466. }
  467. - (void)testCreateWithInvalidObject {
  468. auto realm = RLMRealm.defaultRealm;
  469. [realm beginWriteTransaction];
  470. RLMAssertThrowsWithReasonMatching([DogObject createInRealm:realm withValue:self.nonLiteralNil],
  471. @"Must provide a non-nil value");
  472. RLMAssertThrowsWithReasonMatching([DogObject createInRealm:realm withValue:NSNull.null],
  473. @"Must provide a non-nil value");
  474. RLMAssertThrowsWithReasonMatching([DogObject createInRealm:realm withValue:@""],
  475. @"Invalid value '' to initialize object of type 'DogObject'");
  476. // No overlap in properties
  477. auto so = [StringObject createInRealm:realm withValue:@[@"str"]];
  478. RLMAssertThrowsWithReasonMatching([IntObject createInRealm:realm withValue:so], @"missing key 'intCol'");
  479. // Dog has some but not all of DogExtra's properties
  480. auto dog = [DogObject createInRealm:realm withValue:@[@"Fido", @10]];
  481. RLMAssertThrowsWithReasonMatching([DogExtraObject createInRealm:realm withValue:dog],
  482. @"missing key 'breed'");
  483. // Same property names, but different types
  484. RLMAssertThrowsWithReasonMatching([BizzaroDog createInRealm:realm withValue:dog],
  485. @"Invalid value 'Fido' of type '.*' for 'int' property 'BizzaroDog.dogName'");
  486. [realm cancelWriteTransaction];
  487. }
  488. - (void)testCreateAllPropertyTypes {
  489. auto realm = RLMRealm.defaultRealm;
  490. [realm beginWriteTransaction];
  491. auto now = [NSDate date];
  492. auto bytes = [NSData dataWithBytes:"a" length:1];
  493. auto so = [[StringObject alloc] init];
  494. so.stringCol = @"string";
  495. auto ao = [AllTypesObject createInRealm:realm withValue:@[@YES, @1, @1.1f, @1.11,
  496. @"string", bytes,
  497. now, @YES, @11, so]];
  498. XCTAssertEqual(ao.boolCol, YES);
  499. XCTAssertEqual(ao.intCol, 1);
  500. XCTAssertEqual(ao.floatCol, 1.1f);
  501. XCTAssertEqual(ao.doubleCol, 1.11);
  502. XCTAssertEqualObjects(ao.stringCol, @"string");
  503. XCTAssertEqualObjects(ao.binaryCol, bytes);
  504. XCTAssertEqualObjects(ao.dateCol, now);
  505. XCTAssertEqual(ao.cBoolCol, true);
  506. XCTAssertEqual(ao.longCol, 11);
  507. XCTAssertNotEqual(ao.objectCol, so);
  508. XCTAssertEqualObjects(ao.objectCol.stringCol, @"string");
  509. auto opt = [AllOptionalTypes createInRealm:realm withValue:@[NSNull.null, NSNull.null,
  510. NSNull.null, NSNull.null,
  511. NSNull.null, NSNull.null,
  512. NSNull.null]];
  513. XCTAssertNil(opt.intObj);
  514. XCTAssertNil(opt.boolObj);
  515. XCTAssertNil(opt.floatObj);
  516. XCTAssertNil(opt.doubleObj);
  517. XCTAssertNil(opt.date);
  518. XCTAssertNil(opt.data);
  519. XCTAssertNil(opt.string);
  520. opt = [AllOptionalTypes createInRealm:realm withValue:@[@1, @2.2f, @3.3, @YES,
  521. @"str", bytes, now]];
  522. XCTAssertEqualObjects(opt.intObj, @1);
  523. XCTAssertEqualObjects(opt.boolObj, @YES);
  524. XCTAssertEqualObjects(opt.floatObj, @2.2f);
  525. XCTAssertEqualObjects(opt.doubleObj, @3.3);
  526. XCTAssertEqualObjects(opt.date, now);
  527. XCTAssertEqualObjects(opt.data, bytes);
  528. XCTAssertEqualObjects(opt.string, @"str");
  529. [realm cancelWriteTransaction];
  530. }
  531. - (void)testCreateRequiredPrimitiveArrays {
  532. auto realm = RLMRealm.defaultRealm;
  533. [realm beginWriteTransaction];
  534. auto now = [NSDate date];
  535. auto bytes = [NSData dataWithBytes:"a" length:1];
  536. auto req = [AllPrimitiveArrays createInRealm:realm
  537. withValue:@{@"intObj": @[@1, @2, @3],
  538. @"boolObj": @[@YES, @NO],
  539. @"floatObj": @[@1.1f, @2.2f],
  540. @"doubleObj": @[@3.3, @4.4],
  541. @"stringObj": @[@"a", @"b"],
  542. @"dateObj": @[now],
  543. @"dataObj": @[bytes]}];
  544. XCTAssertEqual(3U, req.intObj.count);
  545. XCTAssertEqual(2U, req.boolObj.count);
  546. XCTAssertEqual(2U, req.floatObj.count);
  547. XCTAssertEqual(2U, req.doubleObj.count);
  548. XCTAssertEqual(2U, req.stringObj.count);
  549. XCTAssertEqual(1U, req.dateObj.count);
  550. XCTAssertEqual(1U, req.dataObj.count);
  551. XCTAssertEqualObjects([req.intObj valueForKey:@"self"], (@[@1, @2, @3]));
  552. XCTAssertEqualObjects([req.boolObj valueForKey:@"self"], (@[@YES, @NO]));
  553. XCTAssertEqualObjects([req.floatObj valueForKey:@"self"], (@[@1.1f, @2.2f]));
  554. XCTAssertEqualObjects([req.doubleObj valueForKey:@"self"], (@[@3.3, @4.4]));
  555. XCTAssertEqualObjects([req.stringObj valueForKey:@"self"], (@[@"a", @"b"]));
  556. XCTAssertEqualObjects([req.dateObj valueForKey:@"self"], (@[now]));
  557. XCTAssertEqualObjects([req.dataObj valueForKey:@"self"], (@[bytes]));
  558. [realm cancelWriteTransaction];
  559. }
  560. #if 0
  561. - (void)testCreateRequiredPrimitiveArraysWithNonNSArrayEnumerable {
  562. auto realm = RLMRealm.defaultRealm;
  563. [realm beginWriteTransaction];
  564. auto now = [NSDate date];
  565. auto bytes = [NSData dataWithBytes:"a" length:1];
  566. auto req = [AllPrimitiveArrays createInRealm:realm
  567. withValue:@{@"intObj": @[@1, @2, @3].reverseObjectEnumerator,
  568. @"boolObj": @[@YES, @NO].reverseObjectEnumerator,
  569. @"floatObj": @[@1.1f, @2.2f].reverseObjectEnumerator,
  570. @"doubleObj": @[@3.3, @4.4].reverseObjectEnumerator,
  571. @"stringObj": @[@"a", @"b"].reverseObjectEnumerator,
  572. @"dateObj": @[now].reverseObjectEnumerator,
  573. @"dataObj": @[bytes].reverseObjectEnumerator}];
  574. XCTAssertEqual(3U, req.intObj.count);
  575. XCTAssertEqual(2U, req.boolObj.count);
  576. XCTAssertEqual(2U, req.floatObj.count);
  577. XCTAssertEqual(2U, req.doubleObj.count);
  578. XCTAssertEqual(2U, req.stringObj.count);
  579. XCTAssertEqual(1U, req.dateObj.count);
  580. XCTAssertEqual(1U, req.dataObj.count);
  581. XCTAssertEqualObjects([req.intObj valueForKey:@"self"], (@[@3, @2, @1]));
  582. XCTAssertEqualObjects([req.boolObj valueForKey:@"self"], (@[@NO, @YES]));
  583. XCTAssertEqualObjects([req.floatObj valueForKey:@"self"], (@[@2.2f, @1.1f]));
  584. XCTAssertEqualObjects([req.doubleObj valueForKey:@"self"], (@[@4.4, @3.3]));
  585. XCTAssertEqualObjects([req.stringObj valueForKey:@"self"], (@[@"b", @"a"]));
  586. XCTAssertEqualObjects([req.dateObj valueForKey:@"self"], (@[now]));
  587. XCTAssertEqualObjects([req.dataObj valueForKey:@"self"], (@[bytes]));
  588. [realm cancelWriteTransaction];
  589. }
  590. #endif
  591. - (void)testCreatePrimitiveArraysWithNSNull {
  592. auto realm = RLMRealm.defaultRealm;
  593. [realm beginWriteTransaction];
  594. auto req = [AllPrimitiveArrays createInRealm:realm
  595. withValue:@{@"intObj": NSNull.null,
  596. @"boolObj": NSNull.null,
  597. @"floatObj": NSNull.null,
  598. @"doubleObj": NSNull.null,
  599. @"stringObj": NSNull.null,
  600. @"dateObj": NSNull.null,
  601. @"dataObj": NSNull.null}];
  602. XCTAssertEqual(0U, req.intObj.count);
  603. XCTAssertEqual(0U, req.boolObj.count);
  604. XCTAssertEqual(0U, req.floatObj.count);
  605. XCTAssertEqual(0U, req.doubleObj.count);
  606. XCTAssertEqual(0U, req.stringObj.count);
  607. XCTAssertEqual(0U, req.dateObj.count);
  608. XCTAssertEqual(0U, req.dataObj.count);
  609. }
  610. - (void)testCreatePrimitiveArraysWithMissingKeys {
  611. auto realm = RLMRealm.defaultRealm;
  612. [realm beginWriteTransaction];
  613. auto req = [AllPrimitiveArrays createInRealm:realm
  614. withValue:@{@"intObj": @[@1, @2, @2],
  615. @"dataObj": NSNull.null}];
  616. XCTAssertEqual(3U, req.intObj.count);
  617. XCTAssertEqual(0U, req.boolObj.count);
  618. XCTAssertEqual(0U, req.floatObj.count);
  619. XCTAssertEqual(0U, req.doubleObj.count);
  620. XCTAssertEqual(0U, req.stringObj.count);
  621. XCTAssertEqual(0U, req.dateObj.count);
  622. XCTAssertEqual(0U, req.dataObj.count);
  623. }
  624. - (void)testCreateRequiredPrimitiveArraysWithInvalidValues {
  625. auto realm = RLMRealm.defaultRealm;
  626. [realm beginWriteTransaction];
  627. RLMAssertThrowsWithReason([AllPrimitiveArrays createInRealm:realm
  628. withValue:@{@"intObj": @[NSNull.null]}],
  629. @"Invalid value '<null>' of type 'NSNull' for 'int' array property 'AllPrimitiveArrays.intObj'.");
  630. RLMAssertThrowsWithReason([AllPrimitiveArrays createInRealm:realm
  631. withValue:@{@"intObj": @[@1.1]}],
  632. @"Invalid value '1.1' of type '__NSCFNumber' for 'int' array property 'AllPrimitiveArrays.intObj'.");
  633. RLMAssertThrowsWithReason([AllPrimitiveArrays createInRealm:realm
  634. withValue:@{@"intObj": @[@"0"]}],
  635. @"Invalid value '0' of type '__NSCFConstantString' for 'int' array property 'AllPrimitiveArrays.intObj'.");
  636. RLMAssertThrowsWithReason([AllPrimitiveArrays createInRealm:realm
  637. withValue:@{@"intObj": @1}],
  638. @"Invalid value (1) for 'int' array property 'AllPrimitiveArrays.intObj': value is not enumerable.");
  639. [realm cancelWriteTransaction];
  640. }
  641. - (void)testCreateOptionalPrimitiveArrays {
  642. auto realm = RLMRealm.defaultRealm;
  643. [realm beginWriteTransaction];
  644. auto now = [NSDate date];
  645. auto bytes = [NSData dataWithBytes:"a" length:1];
  646. auto req = [AllOptionalPrimitiveArrays createInRealm:realm
  647. withValue:@{@"intObj": @[@1, @2, @3, NSNull.null],
  648. @"boolObj": @[@YES, @NO, NSNull.null],
  649. @"floatObj": @[@1.1f, @2.2f, NSNull.null],
  650. @"doubleObj": @[@3.3, @4.4, NSNull.null],
  651. @"stringObj": @[@"a", @"b", NSNull.null],
  652. @"dateObj": @[now, NSNull.null],
  653. @"dataObj": @[bytes, NSNull.null]}];
  654. XCTAssertEqual(4U, req.intObj.count);
  655. XCTAssertEqual(3U, req.boolObj.count);
  656. XCTAssertEqual(3U, req.floatObj.count);
  657. XCTAssertEqual(3U, req.doubleObj.count);
  658. XCTAssertEqual(3U, req.stringObj.count);
  659. XCTAssertEqual(2U, req.dateObj.count);
  660. XCTAssertEqual(2U, req.dataObj.count);
  661. XCTAssertEqualObjects([req.intObj valueForKey:@"self"], (@[@1, @2, @3, NSNull.null]));
  662. XCTAssertEqualObjects([req.boolObj valueForKey:@"self"], (@[@YES, @NO, NSNull.null]));
  663. XCTAssertEqualObjects([req.floatObj valueForKey:@"self"], (@[@1.1f, @2.2f, NSNull.null]));
  664. XCTAssertEqualObjects([req.doubleObj valueForKey:@"self"], (@[@3.3, @4.4, NSNull.null]));
  665. XCTAssertEqualObjects([req.stringObj valueForKey:@"self"], (@[@"a", @"b", NSNull.null]));
  666. XCTAssertEqualObjects([req.dateObj valueForKey:@"self"], (@[now, NSNull.null]));
  667. XCTAssertEqualObjects([req.dataObj valueForKey:@"self"], (@[bytes, NSNull.null]));
  668. [realm cancelWriteTransaction];
  669. }
  670. - (void)testCreateOptionalPrimitiveArraysWithInvalidValues {
  671. auto realm = RLMRealm.defaultRealm;
  672. [realm beginWriteTransaction];
  673. RLMAssertThrowsWithReason([AllOptionalPrimitiveArrays createInRealm:realm
  674. withValue:@{@"intObj": @[@1.1]}],
  675. @"Invalid value '1.1' of type '__NSCFNumber' for 'int?' array property 'AllOptionalPrimitiveArrays.intObj'.");
  676. RLMAssertThrowsWithReason([AllOptionalPrimitiveArrays createInRealm:realm
  677. withValue:@{@"intObj": @[@"0"]}],
  678. @"Invalid value '0' of type '__NSCFConstantString' for 'int?' array property 'AllOptionalPrimitiveArrays.intObj'.");
  679. RLMAssertThrowsWithReason([AllOptionalPrimitiveArrays createInRealm:realm
  680. withValue:@{@"intObj": @1}],
  681. @"Invalid value (1) for 'int?' array property 'AllOptionalPrimitiveArrays.intObj': value is not enumerable.");
  682. }
  683. - (void)testCreateUsesDefaultValuesForMissingDictionaryKeys {
  684. auto realm = [RLMRealm defaultRealm];
  685. [realm beginWriteTransaction];
  686. auto obj = [NumberDefaultsObject createInRealm:realm withValue:@{}];
  687. XCTAssertEqualObjects(obj.intObj, @1);
  688. XCTAssertEqualObjects(obj.floatObj, @2.2f);
  689. XCTAssertEqualObjects(obj.doubleObj, @3.3);
  690. XCTAssertEqualObjects(obj.boolObj, @NO);
  691. obj = [NumberDefaultsObject createInRealm:realm withValue:@{@"intObj": @10}];
  692. XCTAssertEqualObjects(obj.intObj, @10);
  693. XCTAssertEqualObjects(obj.floatObj, @2.2f);
  694. XCTAssertEqualObjects(obj.doubleObj, @3.3);
  695. XCTAssertEqualObjects(obj.boolObj, @NO);
  696. [realm cancelWriteTransaction];
  697. }
  698. - (void)testCreateOnManagedObjectInSameRealmShallowCopies {
  699. auto realm = [RLMRealm defaultRealm];
  700. [realm beginWriteTransaction];
  701. auto so = [StringObject createInRealm:realm withValue:@[@"str"]];
  702. auto pso = [PrimaryStringObject createInRealm:realm withValue:@[@"pk", @1]];
  703. auto io = [IntObject createInRealm:realm withValue:@[@2]];
  704. auto pio = [PrimaryIntObject createInRealm:realm withValue:@[@3]];
  705. auto links = [AllLinks createInRealm:realm withValue:@[so, pso, @[io, io], @[pio, pio]]];
  706. auto copy = [AllLinks createInRealm:realm withValue:links];
  707. XCTAssertEqual(2U, [AllLinks allObjectsInRealm:realm].count);
  708. XCTAssertEqual(1U, [StringObject allObjectsInRealm:realm].count);
  709. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  710. XCTAssertEqual(1U, [IntObject allObjectsInRealm:realm].count);
  711. XCTAssertEqual(1U, [PrimaryIntObject allObjectsInRealm:realm].count);
  712. XCTAssertTrue([links.string isEqualToObject:so]);
  713. XCTAssertTrue([copy.string isEqualToObject:so]);
  714. XCTAssertTrue([links.primaryString isEqualToObject:pso]);
  715. XCTAssertTrue([copy.primaryString isEqualToObject:pso]);
  716. [realm cancelWriteTransaction];
  717. }
  718. - (void)testCreateOnManagedObjectInDifferentRealmDeepCopies {
  719. auto realm = [RLMRealm defaultRealm];
  720. [realm beginWriteTransaction];
  721. auto realm2 = [self realmWithTestPath];
  722. [realm2 beginWriteTransaction];
  723. auto so = [StringObject createInRealm:realm withValue:@[@"str"]];
  724. auto pso = [PrimaryStringObject createInRealm:realm withValue:@[@"pk", @1]];
  725. auto io = [IntObject createInRealm:realm withValue:@[@2]];
  726. auto pio = [PrimaryIntObject createInRealm:realm withValue:@[@3]];
  727. auto links = [AllLinks createInRealm:realm withValue:@[so, pso, @[io, io], @[pio]]];
  728. [AllLinks createInRealm:realm2 withValue:links];
  729. XCTAssertEqual(1U, [AllLinks allObjectsInRealm:realm2].count);
  730. XCTAssertEqual(1U, [StringObject allObjectsInRealm:realm2].count);
  731. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm2].count);
  732. XCTAssertEqual(2U, [IntObject allObjectsInRealm:realm2].count);
  733. XCTAssertEqual(1U, [PrimaryIntObject allObjectsInRealm:realm2].count);
  734. [realm cancelWriteTransaction];
  735. [realm2 cancelWriteTransaction];
  736. }
  737. - (void)testCreateOnManagedObjectInDifferentRealmDoesntReallyWorkUsefullyWithLinkedPKs {
  738. auto realm = [RLMRealm defaultRealm];
  739. [realm beginWriteTransaction];
  740. auto realm2 = [self realmWithTestPath];
  741. [realm2 beginWriteTransaction];
  742. auto pio = [PrimaryIntObject createInRealm:realm withValue:@[@3]];
  743. auto links = [AllLinks createInRealm:realm withValue:@[NSNull.null, NSNull.null, NSNull.null, @[pio, pio]]];
  744. RLMAssertThrowsWithReason([AllLinks createInRealm:realm2 withValue:links],
  745. @"existing primary key value '3'");
  746. [realm cancelWriteTransaction];
  747. [realm2 cancelWriteTransaction];
  748. }
  749. - (void)testCreateWithInvalidatedObject {
  750. auto realm = [RLMRealm defaultRealm];
  751. [realm beginWriteTransaction];
  752. auto obj1 = [IntObject createInRealm:realm withValue:@[@0]];
  753. auto obj2 = [IntObject createInRealm:realm withValue:@[@1]];
  754. id obj1alias = [IntObject allObjectsInRealm:realm].firstObject;
  755. [realm deleteObject:obj1];
  756. RLMAssertThrowsWithReasonMatching([IntObject createInRealm:realm withValue:obj1],
  757. @"Object has been deleted or invalidated.");
  758. RLMAssertThrowsWithReasonMatching([IntObject createInRealm:realm withValue:obj1alias],
  759. @"Object has been deleted or invalidated.");
  760. [realm commitWriteTransaction];
  761. [realm invalidate];
  762. [realm beginWriteTransaction];
  763. RLMAssertThrowsWithReasonMatching([IntObject createInRealm:realm withValue:obj2],
  764. @"Object has been deleted or invalidated.");
  765. [realm cancelWriteTransaction];
  766. }
  767. - (void)testCreateOutsideWriteTransaction {
  768. auto realm = [RLMRealm defaultRealm];
  769. RLMAssertThrowsWithReasonMatching([IntObject createInRealm:realm withValue:@[@0]],
  770. @"call beginWriteTransaction");
  771. }
  772. - (void)testCreateInNilRealm {
  773. RLMAssertThrowsWithReasonMatching(([IntObject createInRealm:self.nonLiteralNil withValue:@[@0]]),
  774. @"Realm must not be nil");
  775. }
  776. - (void)testCreatingObjectWithoutAnyPropertiesThrows {
  777. auto realm = [RLMRealm defaultRealm];
  778. [realm beginWriteTransaction];
  779. RLMAssertThrows([AbstractObject createInRealm:realm withValue:@[]]);
  780. [realm cancelWriteTransaction];
  781. }
  782. - (void)testCreateWithNonEnumerableValueForArrayProperty {
  783. auto realm = [RLMRealm defaultRealm];
  784. [realm beginWriteTransaction];
  785. RLMAssertThrowsWithReason(([CompanyObject createInRealm:realm withValue:@[@"one employee", @1]]),
  786. @"Invalid value (1) for 'EmployeeObject' array property 'CompanyObject.employees': value is not enumerable.");
  787. [realm cancelWriteTransaction];
  788. }
  789. - (void)testCreateWithNonArrayEnumerableValueForArrayProperty {
  790. auto realm = [RLMRealm defaultRealm];
  791. [realm beginWriteTransaction];
  792. auto employees = @[@[@"name", @2, @YES], @[@"name 2", @3, @NO]];
  793. auto co = [CompanyObject createInRealm:realm withValue:@[@"one employee", employees.reverseObjectEnumerator]];
  794. XCTAssertEqual(2U, co.employees.count);
  795. XCTAssertEqualObjects(@"name 2", co.employees[0].name);
  796. XCTAssertEqualObjects(@"name", co.employees[1].name);
  797. [realm cancelWriteTransaction];
  798. }
  799. - (void)testCreateWithCustomAccessors {
  800. auto realm = [RLMRealm defaultRealm];
  801. [realm beginWriteTransaction];
  802. // Create with array
  803. auto ca = [CustomAccessorsObject createInRealm:realm withValue:@[@"a", @1]];
  804. XCTAssertEqualObjects(ca.name, @"a");
  805. XCTAssertEqual(ca.age, 1);
  806. // Create with dictionary
  807. ca = [CustomAccessorsObject createInRealm:realm withValue:@{@"name": @"b", @"age": @2}];
  808. XCTAssertEqualObjects(ca.name, @"b");
  809. XCTAssertEqual(ca.age, 2);
  810. // Create with KVC-compatible object
  811. auto ca2 = [CustomAccessorsObject createInRealm:realm withValue:ca];
  812. XCTAssertEqualObjects(ca2.name, @"b");
  813. XCTAssertEqual(ca2.age, 2);
  814. [realm cancelWriteTransaction];
  815. }
  816. - (void)testCreateWithRenamedColumns {
  817. auto realm = [RLMRealm defaultRealm];
  818. [realm beginWriteTransaction];
  819. // Create with array
  820. auto obj = [RenamedProperties1 createInRealm:realm withValue:@[@1, @"a"]];
  821. XCTAssertEqual(obj.propA, 1);
  822. XCTAssertEqualObjects(obj.propB, @"a");
  823. // Create with dictionary
  824. obj = [RenamedProperties1 createInRealm:realm withValue:@{@"propB": @"b", @"propA": @2}];
  825. XCTAssertEqual(obj.propA, 2);
  826. XCTAssertEqualObjects(obj.propB, @"b");
  827. // Create with KVC-compatible object
  828. obj = [RenamedProperties1 createInRealm:realm withValue:obj];
  829. XCTAssertEqual(obj.propA, 2);
  830. XCTAssertEqualObjects(obj.propB, @"b");
  831. // Verify that they're all readable via the other class
  832. RLMResults<RenamedProperties2 *> *results = [RenamedProperties2 allObjectsInRealm:realm];
  833. XCTAssertEqual(results[0].propC, 1);
  834. XCTAssertEqualObjects(results[0].propD, @"a");
  835. XCTAssertEqual(results[1].propC, 2);
  836. XCTAssertEqualObjects(results[1].propD, @"b");
  837. XCTAssertEqual(results[2].propC, 2);
  838. XCTAssertEqualObjects(results[2].propD, @"b");
  839. [realm cancelWriteTransaction];
  840. }
  841. #pragma mark - Create Or Update
  842. - (void)testCreateOrUpdateWithoutPKThrows {
  843. auto realm = [RLMRealm defaultRealm];
  844. [realm beginWriteTransaction];
  845. RLMAssertThrowsWithReason([DogObject createOrUpdateInRealm:realm withValue:@[]],
  846. @"'DogObject' does not have a primary key");
  847. [realm cancelWriteTransaction];
  848. }
  849. - (void)testCreateOrUpdateUpdatesExistingItemWithSamePK {
  850. auto realm = [RLMRealm defaultRealm];
  851. [realm beginWriteTransaction];
  852. auto so = [PrimaryStringObject createOrUpdateInRealm:realm withValue:@[@"pk", @2]];
  853. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  854. XCTAssertEqual(so.intCol, 2);
  855. auto so2 = [PrimaryStringObject createOrUpdateInRealm:realm withValue:@[@"pk", @3]];
  856. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  857. XCTAssertEqual(so.intCol, 3);
  858. XCTAssertEqualObjects(so, so2);
  859. [realm cancelWriteTransaction];
  860. }
  861. - (void)testCreateOrUpdateWithNullPrimaryKey {
  862. RLMRealm *realm = [RLMRealm defaultRealm];
  863. [realm beginWriteTransaction];
  864. [PrimaryNullableStringObject createOrUpdateInRealm:realm withValue:@{@"intCol": @5}];
  865. [PrimaryNullableStringObject createOrUpdateInRealm:realm withValue:@{@"intCol": @7}];
  866. XCTAssertEqual([PrimaryNullableStringObject objectInRealm:realm forPrimaryKey:NSNull.null].intCol, 7);
  867. [PrimaryNullableStringObject createOrUpdateInRealm:realm withValue:@{@"stringCol": NSNull.null, @"intCol": @11}];
  868. XCTAssertEqual([PrimaryNullableStringObject objectInRealm:realm forPrimaryKey:nil].intCol, 11);
  869. [PrimaryNullableIntObject createOrUpdateInRealm:realm withValue:@{@"value": @5}];
  870. [PrimaryNullableIntObject createOrUpdateInRealm:realm withValue:@{@"value": @7}];
  871. XCTAssertEqual([PrimaryNullableIntObject objectInRealm:realm forPrimaryKey:NSNull.null].value, 7);
  872. [PrimaryNullableIntObject createOrUpdateInRealm:realm withValue:@{@"optIntCol": NSNull.null, @"value": @11}];
  873. XCTAssertEqual([PrimaryNullableIntObject objectInRealm:realm forPrimaryKey:nil].value, 11);
  874. [realm cancelWriteTransaction];
  875. }
  876. - (void)testCreateOrUpdateDoesNotModifyKeysNotPresent {
  877. auto realm = [RLMRealm defaultRealm];
  878. [realm beginWriteTransaction];
  879. auto so = [PrimaryStringObject createOrUpdateInRealm:realm withValue:@[@"pk", @2]];
  880. auto so2 = [PrimaryStringObject createOrUpdateInRealm:realm withValue:@{@"stringCol": @"pk"}];
  881. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  882. XCTAssertEqual(so.intCol, 2);
  883. XCTAssertEqual(so2.intCol, 2);
  884. [realm cancelWriteTransaction];
  885. }
  886. - (void)testCreateOrUpdateDoesNotReplaceExistingValuesWithDefaults {
  887. auto realm = [RLMRealm defaultRealm];
  888. [realm beginWriteTransaction];
  889. auto so = [PrimaryKeyWithDefault createInRealm:realm withValue:@[@"pk", @2]];
  890. [PrimaryKeyWithDefault createOrUpdateInRealm:realm withValue:@{@"stringCol": @"pk"}];
  891. XCTAssertEqual(so.intCol, 2);
  892. [realm cancelWriteTransaction];
  893. }
  894. - (void)testCreateOrUpdateReplacesExistingArrayPropertiesAndDoesNotMergeThem {
  895. auto realm = [RLMRealm defaultRealm];
  896. [realm beginWriteTransaction];
  897. auto obj = [AllLinksWithPrimary createInRealm:realm withValue:@[@"pk", @[@"str"],
  898. @[@"str pk", @5],
  899. @[@[@1], @[@2], @[@3]]]];
  900. [AllLinksWithPrimary createOrUpdateInRealm:realm withValue:@[@"pk", @[@"str"],
  901. @[@"str pk", @6],
  902. @[@[@4]]]];
  903. XCTAssertEqual(1U, obj.intArray.count);
  904. XCTAssertEqual(4, obj.intArray[0].intCol);
  905. XCTAssertEqual(6, obj.primaryString.intCol);
  906. [realm cancelWriteTransaction];
  907. }
  908. - (void)testCreateOrUpdateReusesExistingLinkedObjectsWithPrimaryKeys {
  909. auto realm = [RLMRealm defaultRealm];
  910. [realm beginWriteTransaction];
  911. [AllLinksWithPrimary createInRealm:realm withValue:@[@"pk", NSNull.null,
  912. @[@"str pk", @5]]];
  913. [AllLinksWithPrimary createOrUpdateInRealm:realm withValue:@[@"pk", NSNull.null,
  914. @{@"stringCol": @"str pk"}]];
  915. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  916. [realm cancelWriteTransaction];
  917. }
  918. - (void)testCreateOrUpdateCreatesNewLinkedObjectsWithoutPrimaryKeys {
  919. auto realm = [RLMRealm defaultRealm];
  920. [realm beginWriteTransaction];
  921. [AllLinksWithPrimary createInRealm:realm withValue:@[@"pk", @[@"str"]]];
  922. [AllLinksWithPrimary createOrUpdateInRealm:realm withValue:@[@"pk", @[@"str"]]];
  923. XCTAssertEqual(2U, [StringObject allObjectsInRealm:realm].count);
  924. [realm cancelWriteTransaction];
  925. }
  926. - (void)testCreateOrUpdateWithMissingValuesAndNoExistingObject {
  927. auto realm = [RLMRealm defaultRealm];
  928. [realm beginWriteTransaction];
  929. RLMAssertThrowsWithReason([PrimaryStringObject createOrUpdateInRealm:realm withValue:@{@"stringCol": @"pk"}],
  930. @"Missing value for property 'PrimaryStringObject.intCol'");
  931. RLMAssertThrowsWithReason(([PrimaryStringObject createOrUpdateInRealm:realm
  932. withValue:@{@"stringCol": @"pk",
  933. @"intCol": NSNull.null}]),
  934. @"Invalid value '<null>' of type 'NSNull' for 'int' property 'PrimaryStringObject.intCol'");
  935. [realm cancelWriteTransaction];
  936. }
  937. - (void)testCreateOrUpdateOnManagedObjectInSameRealmReturnsExistingObjectInstance {
  938. auto realm = [RLMRealm defaultRealm];
  939. [realm beginWriteTransaction];
  940. auto so = [PrimaryStringObject createOrUpdateInRealm:realm withValue:@[@"pk", @2]];
  941. auto so2 = [PrimaryStringObject createOrUpdateInRealm:realm withValue:so];
  942. XCTAssertEqual(so, so2);
  943. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  944. [realm cancelWriteTransaction];
  945. }
  946. - (void)testCreateOrUpdateOnManagedObjectInDifferentRealmDeepCopies {
  947. auto realm = [RLMRealm defaultRealm];
  948. [realm beginWriteTransaction];
  949. auto realm2 = [self realmWithTestPath];
  950. [realm2 beginWriteTransaction];
  951. auto so = [StringObject createInRealm:realm withValue:@[@"str"]];
  952. auto pso = [PrimaryStringObject createInRealm:realm withValue:@[@"pk", @1]];
  953. auto io = [IntObject createInRealm:realm withValue:@[@2]];
  954. auto pio = [PrimaryIntObject createInRealm:realm withValue:@[@3]];
  955. auto links = [AllLinksWithPrimary createInRealm:realm withValue:@[@"pk", so, pso, @[io, io], @[pio, pio]]];
  956. auto copy = [AllLinksWithPrimary createOrUpdateInRealm:realm2 withValue:links];
  957. XCTAssertEqual(1U, [AllLinksWithPrimary allObjectsInRealm:realm2].count);
  958. XCTAssertEqual(1U, [StringObject allObjectsInRealm:realm2].count);
  959. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm2].count);
  960. XCTAssertEqual(2U, [IntObject allObjectsInRealm:realm2].count);
  961. XCTAssertEqual(1U, [PrimaryIntObject allObjectsInRealm:realm2].count);
  962. XCTAssertEqualObjects(so.stringCol, copy.string.stringCol);
  963. XCTAssertEqualObjects(pso.stringCol, copy.primaryString.stringCol);
  964. XCTAssertEqual(pso.intCol, copy.primaryString.intCol);
  965. XCTAssertEqual(2U, copy.intArray.count);
  966. XCTAssertEqual(2U, copy.primaryIntArray.count);
  967. [realm cancelWriteTransaction];
  968. [realm2 cancelWriteTransaction];
  969. }
  970. - (void)testCreateOrUpdateWithNilValues {
  971. auto now = [NSDate date];
  972. auto bytes = [NSData dataWithBytes:"a" length:1];
  973. auto nonnull = [[AllOptionalTypesPK alloc] initWithValue:@[@0, @1, @2.2f, @3.3, @YES, @"a", bytes, now]];
  974. auto null = [[AllOptionalTypesPK alloc] initWithValue:@[@0]];
  975. auto realm = [RLMRealm defaultRealm];
  976. [realm beginWriteTransaction];
  977. auto obj = [AllOptionalTypesPK createInRealm:realm withValue:nonnull];
  978. [AllOptionalTypesPK createOrUpdateInRealm:realm withValue:null];
  979. XCTAssertNil(obj.intObj);
  980. XCTAssertNil(obj.floatObj);
  981. XCTAssertNil(obj.doubleObj);
  982. XCTAssertNil(obj.boolObj);
  983. XCTAssertNil(obj.string);
  984. XCTAssertNil(obj.data);
  985. XCTAssertNil(obj.date);
  986. [AllOptionalTypesPK createOrUpdateInRealm:realm withValue:nonnull];
  987. [AllOptionalTypesPK createOrUpdateInRealm:realm withValue:@[@0]];
  988. // No values specified, so old values should remain
  989. XCTAssertNotNil(obj.intObj);
  990. XCTAssertNotNil(obj.floatObj);
  991. XCTAssertNotNil(obj.doubleObj);
  992. XCTAssertNotNil(obj.boolObj);
  993. XCTAssertNotNil(obj.string);
  994. XCTAssertNotNil(obj.data);
  995. XCTAssertNotNil(obj.date);
  996. [AllOptionalTypesPK createOrUpdateInRealm:realm withValue:@{@"pk": @0}];
  997. XCTAssertNotNil(obj.intObj);
  998. XCTAssertNotNil(obj.floatObj);
  999. XCTAssertNotNil(obj.doubleObj);
  1000. XCTAssertNotNil(obj.boolObj);
  1001. XCTAssertNotNil(obj.string);
  1002. XCTAssertNotNil(obj.data);
  1003. XCTAssertNotNil(obj.date);
  1004. [AllOptionalTypesPK createOrUpdateInRealm:realm withValue:@{@"pk": @0,
  1005. @"intObj": NSNull.null,
  1006. @"floatObj": NSNull.null,
  1007. @"doubleObj": NSNull.null,
  1008. @"boolObj": NSNull.null,
  1009. @"string": NSNull.null,
  1010. @"data": NSNull.null,
  1011. @"date": NSNull.null,
  1012. }];
  1013. XCTAssertNil(obj.intObj);
  1014. XCTAssertNil(obj.floatObj);
  1015. XCTAssertNil(obj.doubleObj);
  1016. XCTAssertNil(obj.boolObj);
  1017. XCTAssertNil(obj.string);
  1018. XCTAssertNil(obj.data);
  1019. XCTAssertNil(obj.date);
  1020. [realm cancelWriteTransaction];
  1021. }
  1022. - (void)testCreateOrUpdateWithRenamedPrimaryKey {
  1023. auto realm = [RLMRealm defaultRealm];
  1024. [realm beginWriteTransaction];
  1025. auto obj = [RenamedPrimaryKey createInRealm:realm withValue:@[@1, @2]];
  1026. [RenamedPrimaryKey createOrUpdateInRealm:realm withValue:@[@1, @3]];
  1027. XCTAssertEqual(obj.pk, 1);
  1028. XCTAssertEqual(obj.value, 3);
  1029. [RenamedPrimaryKey createOrUpdateInRealm:realm withValue:@{@"pk": @1, @"value": @4}];
  1030. XCTAssertEqual(obj.value, 4);
  1031. [realm cancelWriteTransaction];
  1032. }
  1033. #pragma mark - Add
  1034. - (void)testAddInvalidated {
  1035. auto realm = [RLMRealm defaultRealm];
  1036. [realm beginWriteTransaction];
  1037. auto dog = [DogObject createInRealm:realm withValue:@[@"name", @1]];
  1038. [realm deleteObject:dog];
  1039. RLMAssertThrowsWithReason([realm addObject:dog],
  1040. @"Adding a deleted or invalidated");
  1041. [realm cancelWriteTransaction];
  1042. }
  1043. - (void)testAddDuplicatePrimaryKey {
  1044. auto realm = [RLMRealm defaultRealm];
  1045. [realm beginWriteTransaction];
  1046. [realm addObject:[[PrimaryStringObject alloc] initWithValue:@[@"pk", @1]]];
  1047. RLMAssertThrowsWithReason(([realm addObject:[[PrimaryStringObject alloc] initWithValue:@[@"pk", @1]]]),
  1048. @"existing primary key value 'pk'");
  1049. [realm cancelWriteTransaction];
  1050. }
  1051. - (void)testAddNested {
  1052. auto realm = [RLMRealm defaultRealm];
  1053. [realm beginWriteTransaction];
  1054. auto co = [[CompanyObject alloc] initWithValue:@[@"one employee",
  1055. @[@[@"name", @2, @YES]]]];
  1056. [realm addObject:co];
  1057. XCTAssertEqual(co.realm, realm);
  1058. XCTAssertEqualObjects(co.name, @"one employee");
  1059. auto eo = co.employees[0];
  1060. XCTAssertEqual(eo.realm, realm);
  1061. XCTAssertEqualObjects(eo.name, @"name");
  1062. eo = [[EmployeeObject alloc] initWithValue:@[@"name 2", @3, @NO]];
  1063. co = [[CompanyObject alloc] initWithValue:@[@"one employee", @[eo]]];
  1064. [realm addObject:co];
  1065. XCTAssertEqual(co.realm, realm);
  1066. XCTAssertEqual(eo.realm, realm);
  1067. [realm cancelWriteTransaction];
  1068. }
  1069. - (void)testAddingObjectWithoutAnyPropertiesThrows {
  1070. auto realm = [RLMRealm defaultRealm];
  1071. [realm beginWriteTransaction];
  1072. RLMAssertThrows([realm addObject:[[AbstractObject alloc] initWithValue:@[]]]);
  1073. [realm cancelWriteTransaction];
  1074. }
  1075. - (void)testAddWithCustomAccessors {
  1076. auto realm = [RLMRealm defaultRealm];
  1077. [realm beginWriteTransaction];
  1078. auto ca = [[CustomAccessorsObject alloc] initWithValue:@[@"a", @1]];
  1079. [realm addObject:ca];
  1080. XCTAssertEqualObjects(ca.name, @"a");
  1081. XCTAssertEqual(ca.age, 1);
  1082. [realm cancelWriteTransaction];
  1083. }
  1084. - (void)testAddWithRenamedColumns {
  1085. auto realm = [RLMRealm defaultRealm];
  1086. [realm beginWriteTransaction];
  1087. auto obj = [[RenamedProperties1 alloc] initWithValue:@[@1, @"a"]];
  1088. [realm addObject:obj];
  1089. XCTAssertEqual(obj.propA, 1);
  1090. XCTAssertEqualObjects(obj.propB, @"a");
  1091. RLMResults<RenamedProperties2 *> *results = [RenamedProperties2 allObjectsInRealm:realm];
  1092. XCTAssertEqual(results[0].propC, 1);
  1093. XCTAssertEqualObjects(results[0].propD, @"a");
  1094. [realm cancelWriteTransaction];
  1095. }
  1096. - (void)testAddToCurrentRealmIsNoOp {
  1097. DogObject *dog = [[DogObject alloc] init];
  1098. auto realm = [RLMRealm defaultRealm];
  1099. [realm beginWriteTransaction];
  1100. [realm addObject:dog];
  1101. XCTAssertEqual(dog.realm, realm);
  1102. XCTAssertEqual(1U, [DogObject allObjectsInRealm:realm].count);
  1103. XCTAssertNoThrow([realm addObject:dog]);
  1104. XCTAssertEqual(dog.realm, realm);
  1105. XCTAssertEqual(1U, [DogObject allObjectsInRealm:realm].count);
  1106. [realm cancelWriteTransaction];
  1107. }
  1108. - (void)testAddToDifferentRealmThrows {
  1109. auto eo = [[EmployeeObject alloc] init];
  1110. auto realm = [RLMRealm defaultRealm];
  1111. [realm beginWriteTransaction];
  1112. [realm addObject:eo];
  1113. auto realm2 = [self realmWithTestPath];
  1114. [realm2 beginWriteTransaction];
  1115. RLMAssertThrowsWithReason([realm2 addObject:eo],
  1116. @"Object is already managed by another Realm. Use create instead to copy it into this Realm.");
  1117. XCTAssertEqual(eo.realm, realm);
  1118. auto co = [CompanyObject new];
  1119. [co.employees addObject:eo];
  1120. RLMAssertThrowsWithReason([realm2 addObject:co],
  1121. @"Object is already managed by another Realm. Use create instead to copy it into this Realm.");
  1122. XCTAssertEqual(co.realm, realm2);
  1123. [realm cancelWriteTransaction];
  1124. [realm2 cancelWriteTransaction];
  1125. }
  1126. - (void)testAddToCurrentRealmChecksForWrite {
  1127. DogObject *dog = [[DogObject alloc] init];
  1128. auto realm = [RLMRealm defaultRealm];
  1129. [realm beginWriteTransaction];
  1130. [realm addObject:dog];
  1131. [realm commitWriteTransaction];
  1132. RLMAssertThrowsWithReason([realm addObject:dog],
  1133. @"call beginWriteTransaction");
  1134. }
  1135. - (void)testAddObjectWithObserver {
  1136. DogObject *dog = [[DogObject alloc] init];
  1137. [dog addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptions)0 context:0];
  1138. auto realm = [RLMRealm defaultRealm];
  1139. [realm beginWriteTransaction];
  1140. RLMAssertThrowsWithReason([realm addObject:dog],
  1141. @"Cannot add an object with observers to a Realm");
  1142. [realm cancelWriteTransaction];
  1143. [dog removeObserver:self forKeyPath:@"name"];
  1144. }
  1145. - (void)testAddObjectWithNilValueForRequiredProperty {
  1146. auto realm = [RLMRealm defaultRealm];
  1147. [realm beginWriteTransaction];
  1148. RLMAssertThrowsWithReason([realm addObject:[[RequiredPropertiesObject alloc] init]],
  1149. @"Invalid value '<null>' of type 'NSNull' for 'string' property 'RequiredPropertiesObject.stringCol'.");
  1150. [realm cancelWriteTransaction];
  1151. }
  1152. #pragma mark - Add Or Update
  1153. - (void)testAddOrUpdateWithoutPKThrows {
  1154. auto realm = [RLMRealm defaultRealm];
  1155. [realm beginWriteTransaction];
  1156. RLMAssertThrowsWithReason([realm addOrUpdateObject:[DogObject new]],
  1157. @"'DogObject' does not have a primary key");
  1158. }
  1159. - (void)testAddOrUpdateUpdatesExistingItemWithSamePK {
  1160. auto realm = [RLMRealm defaultRealm];
  1161. [realm beginWriteTransaction];
  1162. auto so1 = [[PrimaryStringObject alloc] initWithValue:@[@"pk", @2]];
  1163. auto so2 = [[PrimaryStringObject alloc] initWithValue:@[@"pk", @3]];
  1164. [realm addOrUpdateObject:so1];
  1165. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  1166. XCTAssertEqual(so1.intCol, 2);
  1167. [realm addOrUpdateObject:so2];
  1168. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  1169. XCTAssertEqual(so1.intCol, 3);
  1170. XCTAssertEqualObjects(so1, so2);
  1171. [realm cancelWriteTransaction];
  1172. }
  1173. - (void)testAddOrUpdateWithNullPrimaryKey {
  1174. RLMRealm *realm = [RLMRealm defaultRealm];
  1175. [realm beginWriteTransaction];
  1176. auto so1 = [[PrimaryNullableStringObject alloc] initWithValue:@{@"intCol": @5}];
  1177. auto so2 = [[PrimaryNullableStringObject alloc] initWithValue:@{@"intCol": @7}];
  1178. XCTAssertNil([PrimaryNullableStringObject objectInRealm:realm forPrimaryKey:NSNull.null]);
  1179. XCTAssertNil([PrimaryNullableStringObject objectInRealm:realm forPrimaryKey:nil]);
  1180. [realm addOrUpdateObject:so1];
  1181. XCTAssertEqual([PrimaryNullableStringObject objectInRealm:realm forPrimaryKey:NSNull.null].intCol, 5);
  1182. XCTAssertEqual([PrimaryNullableStringObject objectInRealm:realm forPrimaryKey:nil].intCol, 5);
  1183. [realm addOrUpdateObject:so2];
  1184. XCTAssertEqual([PrimaryNullableStringObject objectInRealm:realm forPrimaryKey:NSNull.null].intCol, 7);
  1185. XCTAssertEqual([PrimaryNullableStringObject objectInRealm:realm forPrimaryKey:nil].intCol, 7);
  1186. auto io1 = [[PrimaryNullableIntObject alloc] initWithValue:@{@"value": @5}];
  1187. auto io2 = [[PrimaryNullableIntObject alloc] initWithValue:@{@"value": @7}];
  1188. XCTAssertNil([PrimaryNullableIntObject objectInRealm:realm forPrimaryKey:NSNull.null]);
  1189. XCTAssertNil([PrimaryNullableIntObject objectInRealm:realm forPrimaryKey:nil]);
  1190. [realm addOrUpdateObject:io1];
  1191. XCTAssertEqual([PrimaryNullableIntObject objectInRealm:realm forPrimaryKey:NSNull.null].value, 5);
  1192. XCTAssertEqual([PrimaryNullableIntObject objectInRealm:realm forPrimaryKey:nil].value, 5);
  1193. [realm addOrUpdateObject:io2];
  1194. XCTAssertEqual([PrimaryNullableIntObject objectInRealm:realm forPrimaryKey:NSNull.null].value, 7);
  1195. XCTAssertEqual([PrimaryNullableIntObject objectInRealm:realm forPrimaryKey:nil].value, 7);
  1196. [realm cancelWriteTransaction];
  1197. }
  1198. - (void)testAddOrUpdateDoesNotHaveAnyConceptOfKeysNotPresentThatShouldBeLeftAlone {
  1199. auto realm = [RLMRealm defaultRealm];
  1200. [realm beginWriteTransaction];
  1201. auto obj1 = [[PrimaryKeyWithDefault alloc] initWithValue:@[@"pk", @2]];
  1202. auto obj2 = [[PrimaryKeyWithDefault alloc] initWithValue:@[@"pk"]];
  1203. [realm addOrUpdateObject:obj1];
  1204. [realm addOrUpdateObject:obj2];
  1205. XCTAssertEqual(obj1.intCol, 10);
  1206. [realm cancelWriteTransaction];
  1207. }
  1208. - (void)testAddObjectWithNilValueForRequiredPropertyDoesNotUseExistingValue {
  1209. auto realm = [RLMRealm defaultRealm];
  1210. [realm beginWriteTransaction];
  1211. [PrimaryKeyAndRequiredString createInRealm:realm withValue:@[@0, @"value"]];
  1212. RLMAssertThrowsWithReason([realm addOrUpdateObject:[[PrimaryKeyAndRequiredString alloc] init]],
  1213. @"Invalid value '<null>' of type 'NSNull' for 'string' property 'PrimaryKeyAndRequiredString.value'");
  1214. [realm cancelWriteTransaction];
  1215. }
  1216. - (void)testAddOrUpdateWithDuplicateConflictingValuesForPrimaryKeyInArrayProperty {
  1217. auto realm = [RLMRealm defaultRealm];
  1218. [realm beginWriteTransaction];
  1219. auto company = [[PrimaryCompanyObject alloc] init];
  1220. [company.employees addObject:[[PrimaryEmployeeObject alloc] initWithValue:@[@"a", @1, @NO]]];
  1221. [company.employees addObject:[[PrimaryEmployeeObject alloc] initWithValue:@[@"a", @2, @NO]]];
  1222. [realm addOrUpdateObject:company];
  1223. XCTAssertEqual(1U, [PrimaryEmployeeObject allObjectsInRealm:realm].count);
  1224. XCTAssertEqual(2, company.employees[0].age);
  1225. XCTAssertEqual(2, company.employees[1].age);
  1226. XCTAssertEqualObjects(company.employees[0], company.employees[1]);
  1227. }
  1228. - (void)testAddOrUpdateReplacesExistingArrayPropertiesAndDoesNotMergeThem {
  1229. auto realm = [RLMRealm defaultRealm];
  1230. [realm beginWriteTransaction];
  1231. auto obj1 = [[AllLinksWithPrimary alloc] initWithValue:@[@"pk", @[@"str"],
  1232. @[@"str pk", @5],
  1233. @[@[@1], @[@2], @[@3]]]];
  1234. auto obj2 = [[AllLinksWithPrimary alloc] initWithValue:@[@"pk", @[@"str"],
  1235. @[@"str pk", @6],
  1236. @[@[@4]]]];
  1237. [realm addOrUpdateObject:obj1];
  1238. [realm addOrUpdateObject:obj2];
  1239. XCTAssertEqual(1U, obj1.intArray.count);
  1240. XCTAssertEqual(4, obj1.intArray[0].intCol);
  1241. XCTAssertEqual(6, obj1.primaryString.intCol);
  1242. [realm cancelWriteTransaction];
  1243. }
  1244. - (void)testAddOrUpdateReusesExistingLinkedObjectsWithPrimaryKeys {
  1245. auto realm = [RLMRealm defaultRealm];
  1246. [realm beginWriteTransaction];
  1247. auto obj1 = [[AllLinksWithPrimary alloc] initWithValue:@[@"pk", NSNull.null,
  1248. @[@"str pk", @5]]];
  1249. auto obj2 = [[AllLinksWithPrimary alloc] initWithValue:@[@"pk", NSNull.null,
  1250. @{@"stringCol": @"str pk"}]];
  1251. [realm addOrUpdateObject:obj1];
  1252. [realm addOrUpdateObject:obj2];
  1253. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  1254. [realm cancelWriteTransaction];
  1255. }
  1256. - (void)testAddOrUpdateAddsNewLinkedObjectsWithoutPrimaryKeys {
  1257. auto realm = [RLMRealm defaultRealm];
  1258. [realm beginWriteTransaction];
  1259. auto obj1 = [[AllLinksWithPrimary alloc] initWithValue:@[@"pk", @[@"str"]]];
  1260. auto obj2 = [[AllLinksWithPrimary alloc] initWithValue:@[@"pk", @[@"str"]]];
  1261. [realm addOrUpdateObject:obj1];
  1262. [realm addOrUpdateObject:obj2];
  1263. XCTAssertEqual(2U, [StringObject allObjectsInRealm:realm].count);
  1264. XCTAssertFalse([obj1.string isEqualToObject:[StringObject allObjectsInRealm:realm][0]]);
  1265. XCTAssertTrue([obj1.string isEqualToObject:[StringObject allObjectsInRealm:realm][1]]);
  1266. [realm cancelWriteTransaction];
  1267. }
  1268. - (void)testAddOrUpdateOnManagedObjectInSameRealmIsNoOp {
  1269. auto realm = [RLMRealm defaultRealm];
  1270. [realm beginWriteTransaction];
  1271. auto so = [PrimaryStringObject createOrUpdateInRealm:realm withValue:@[@"pk", @2]];
  1272. XCTAssertNoThrow([realm addOrUpdateObject:so]);
  1273. XCTAssertEqual(1U, [PrimaryStringObject allObjectsInRealm:realm].count);
  1274. [realm cancelWriteTransaction];
  1275. }
  1276. - (void)testAddOrUpdateOnManagedObjectInDifferentRealmThrows {
  1277. auto eo = [[PrimaryEmployeeObject alloc] init];
  1278. auto realm = [RLMRealm defaultRealm];
  1279. [realm beginWriteTransaction];
  1280. [realm addObject:eo];
  1281. auto realm2 = [self realmWithTestPath];
  1282. [realm2 beginWriteTransaction];
  1283. RLMAssertThrowsWithReason([realm2 addOrUpdateObject:eo],
  1284. @"Object is already managed by another Realm. Use create instead to copy it into this Realm.");
  1285. XCTAssertEqual(eo.realm, realm);
  1286. auto co = [PrimaryCompanyObject new];
  1287. [co.employees addObject:eo];
  1288. RLMAssertThrowsWithReason([realm2 addOrUpdateObject:co],
  1289. @"Object is already managed by another Realm. Use create instead to copy it into this Realm.");
  1290. XCTAssertEqual(co.realm, realm2);
  1291. [realm cancelWriteTransaction];
  1292. [realm2 cancelWriteTransaction];
  1293. }
  1294. - (void)testAddOrUpdateWithNilValues {
  1295. auto now = [NSDate date];
  1296. auto bytes = [NSData dataWithBytes:"a" length:1];
  1297. auto nonnull = [[AllOptionalTypesPK alloc] initWithValue:@[@0, @1, @2.2f, @3.3, @YES, @"a", bytes, now]];
  1298. auto null = [[AllOptionalTypesPK alloc] initWithValue:@[@0]];
  1299. auto realm = [RLMRealm defaultRealm];
  1300. [realm beginWriteTransaction];
  1301. auto obj = [AllOptionalTypesPK createInRealm:realm withValue:nonnull];
  1302. auto nullobj = [[AllOptionalTypesPK alloc] initWithValue:null];
  1303. [realm addOrUpdateObject:nullobj];
  1304. XCTAssertNil(obj.intObj);
  1305. XCTAssertNil(obj.floatObj);
  1306. XCTAssertNil(obj.doubleObj);
  1307. XCTAssertNil(obj.boolObj);
  1308. XCTAssertNil(obj.string);
  1309. XCTAssertNil(obj.data);
  1310. XCTAssertNil(obj.date);
  1311. [realm cancelWriteTransaction];
  1312. }
  1313. @end