FSTMutationTests.mm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "Firestore/Source/Model/FSTMutation.h"
  17. #import <FirebaseFirestore/FIRFieldValue.h>
  18. #import <FirebaseFirestore/FIRTimestamp.h>
  19. #import <XCTest/XCTest.h>
  20. #include <vector>
  21. #import "Firestore/Source/API/FIRFieldValue+Internal.h"
  22. #import "Firestore/Source/Model/FSTDocument.h"
  23. #import "Firestore/Source/Model/FSTFieldValue.h"
  24. #import "Firestore/Example/Tests/Util/FSTHelpers.h"
  25. #include "Firestore/core/src/firebase/firestore/model/document_key.h"
  26. #include "Firestore/core/src/firebase/firestore/model/field_mask.h"
  27. #include "Firestore/core/src/firebase/firestore/model/field_transform.h"
  28. #include "Firestore/core/src/firebase/firestore/model/precondition.h"
  29. #include "Firestore/core/src/firebase/firestore/model/transform_operations.h"
  30. #include "Firestore/core/test/firebase/firestore/testutil/testutil.h"
  31. namespace testutil = firebase::firestore::testutil;
  32. using firebase::firestore::model::ArrayTransform;
  33. using firebase::firestore::model::DocumentKey;
  34. using firebase::firestore::model::FieldMask;
  35. using firebase::firestore::model::FieldPath;
  36. using firebase::firestore::model::FieldTransform;
  37. using firebase::firestore::model::Precondition;
  38. using firebase::firestore::model::TransformOperation;
  39. @interface FSTMutationTests : XCTestCase
  40. @end
  41. @implementation FSTMutationTests {
  42. FIRTimestamp *_timestamp;
  43. }
  44. - (void)setUp {
  45. _timestamp = [FIRTimestamp timestamp];
  46. }
  47. - (void)testAppliesSetsToDocuments {
  48. NSDictionary *docData = @{@"foo" : @"foo-value", @"baz" : @"baz-value"};
  49. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  50. FSTMutation *set = FSTTestSetMutation(@"collection/key", @{@"bar" : @"bar-value"});
  51. FSTMaybeDocument *setDoc =
  52. [set applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  53. NSDictionary *expectedData = @{@"bar" : @"bar-value"};
  54. XCTAssertEqualObjects(
  55. setDoc, FSTTestDoc("collection/key", 0, expectedData, FSTDocumentStateLocalMutations));
  56. }
  57. - (void)testAppliesPatchesToDocuments {
  58. NSDictionary *docData = @{@"foo" : @{@"bar" : @"bar-value"}, @"baz" : @"baz-value"};
  59. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  60. FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo.bar" : @"new-bar-value"}, {});
  61. FSTMaybeDocument *patchedDoc =
  62. [patch applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  63. NSDictionary *expectedData = @{@"foo" : @{@"bar" : @"new-bar-value"}, @"baz" : @"baz-value"};
  64. XCTAssertEqualObjects(
  65. patchedDoc, FSTTestDoc("collection/key", 0, expectedData, FSTDocumentStateLocalMutations));
  66. }
  67. - (void)testDeletesValuesFromTheFieldMask {
  68. NSDictionary *docData = @{@"foo" : @{@"bar" : @"bar-value", @"baz" : @"baz-value"}};
  69. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  70. DocumentKey key = testutil::Key("collection/key");
  71. FSTMutation *patch = [[FSTPatchMutation alloc] initWithKey:key
  72. fieldMask:{testutil::Field("foo.bar")}
  73. value:[FSTObjectValue objectValue]
  74. precondition:Precondition::None()];
  75. FSTMaybeDocument *patchedDoc =
  76. [patch applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  77. NSDictionary *expectedData = @{@"foo" : @{@"baz" : @"baz-value"}};
  78. XCTAssertEqualObjects(
  79. patchedDoc, FSTTestDoc("collection/key", 0, expectedData, FSTDocumentStateLocalMutations));
  80. }
  81. - (void)testPatchesPrimitiveValue {
  82. NSDictionary *docData = @{@"foo" : @"foo-value", @"baz" : @"baz-value"};
  83. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  84. FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo.bar" : @"new-bar-value"}, {});
  85. FSTMaybeDocument *patchedDoc =
  86. [patch applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  87. NSDictionary *expectedData = @{@"foo" : @{@"bar" : @"new-bar-value"}, @"baz" : @"baz-value"};
  88. XCTAssertEqualObjects(
  89. patchedDoc, FSTTestDoc("collection/key", 0, expectedData, FSTDocumentStateLocalMutations));
  90. }
  91. - (void)testPatchingDeletedDocumentsDoesNothing {
  92. FSTMaybeDocument *baseDoc = FSTTestDeletedDoc("collection/key", 0, NO);
  93. FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo" : @"bar"}, {});
  94. FSTMaybeDocument *patchedDoc =
  95. [patch applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  96. XCTAssertEqualObjects(patchedDoc, baseDoc);
  97. }
  98. - (void)testAppliesLocalServerTimestampTransformToDocuments {
  99. NSDictionary *docData = @{@"foo" : @{@"bar" : @"bar-value"}, @"baz" : @"baz-value"};
  100. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  101. FSTMutation *transform = FSTTestTransformMutation(
  102. @"collection/key", @{@"foo.bar" : [FIRFieldValue fieldValueForServerTimestamp]});
  103. FSTMaybeDocument *transformedDoc =
  104. [transform applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  105. // Server timestamps aren't parsed, so we manually insert it.
  106. FSTObjectValue *expectedData = FSTTestObjectValue(
  107. @{@"foo" : @{@"bar" : @"<server-timestamp>"},
  108. @"baz" : @"baz-value"});
  109. expectedData =
  110. [expectedData objectBySettingValue:[FSTServerTimestampValue
  111. serverTimestampValueWithLocalWriteTime:_timestamp
  112. previousValue:nil]
  113. forPath:testutil::Field("foo.bar")];
  114. FSTDocument *expectedDoc = [FSTDocument documentWithData:expectedData
  115. key:FSTTestDocKey(@"collection/key")
  116. version:testutil::Version(0)
  117. state:FSTDocumentStateLocalMutations];
  118. XCTAssertEqualObjects(transformedDoc, expectedDoc);
  119. }
  120. // NOTE: This is more a test of FSTUserDataConverter code than FSTMutation code but we don't have
  121. // unit tests for it currently. We could consider removing this test once we have integration tests.
  122. - (void)testCreateArrayUnionTransform {
  123. FSTTransformMutation *transform = FSTTestTransformMutation(@"collection/key", @{
  124. @"foo" : [FIRFieldValue fieldValueForArrayUnion:@[ @"tag" ]],
  125. @"bar.baz" :
  126. [FIRFieldValue fieldValueForArrayUnion:@[ @YES,
  127. @{@"nested" : @{@"a" : @[ @1, @2 ]}} ]]
  128. });
  129. XCTAssertEqual(transform.fieldTransforms.size(), 2);
  130. const FieldTransform &first = transform.fieldTransforms[0];
  131. XCTAssertEqual(first.path(), FieldPath({"foo"}));
  132. {
  133. std::vector<FSTFieldValue *> expectedElements{FSTTestFieldValue(@"tag")};
  134. ArrayTransform expected(TransformOperation::Type::ArrayUnion, expectedElements);
  135. XCTAssertEqual(static_cast<const ArrayTransform &>(first.transformation()), expected);
  136. }
  137. const FieldTransform &second = transform.fieldTransforms[1];
  138. XCTAssertEqual(second.path(), FieldPath({"bar", "baz"}));
  139. {
  140. std::vector<FSTFieldValue *> expectedElements {
  141. FSTTestFieldValue(@YES), FSTTestFieldValue(@{@"nested" : @{@"a" : @[ @1, @2 ]}})
  142. };
  143. ArrayTransform expected(TransformOperation::Type::ArrayUnion, expectedElements);
  144. XCTAssertEqual(static_cast<const ArrayTransform &>(second.transformation()), expected);
  145. }
  146. }
  147. // NOTE: This is more a test of FSTUserDataConverter code than FSTMutation code but we don't have
  148. // unit tests for it currently. We could consider removing this test once we have integration tests.
  149. - (void)testCreateArrayRemoveTransform {
  150. FSTTransformMutation *transform = FSTTestTransformMutation(@"collection/key", @{
  151. @"foo" : [FIRFieldValue fieldValueForArrayRemove:@[ @"tag" ]],
  152. });
  153. XCTAssertEqual(transform.fieldTransforms.size(), 1);
  154. const FieldTransform &first = transform.fieldTransforms[0];
  155. XCTAssertEqual(first.path(), FieldPath({"foo"}));
  156. {
  157. std::vector<FSTFieldValue *> expectedElements{FSTTestFieldValue(@"tag")};
  158. const ArrayTransform expected(TransformOperation::Type::ArrayRemove, expectedElements);
  159. XCTAssertEqual(static_cast<const ArrayTransform &>(first.transformation()), expected);
  160. }
  161. }
  162. - (void)testAppliesLocalArrayUnionTransformToMissingField {
  163. auto baseDoc = @{};
  164. auto transform = @{@"missing" : [FIRFieldValue fieldValueForArrayUnion:@[ @1, @2 ]]};
  165. auto expected = @{@"missing" : @[ @1, @2 ]};
  166. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  167. }
  168. - (void)testAppliesLocalArrayUnionTransformToNonArrayField {
  169. auto baseDoc = @{@"non-array" : @42};
  170. auto transform = @{@"non-array" : [FIRFieldValue fieldValueForArrayUnion:@[ @1, @2 ]]};
  171. auto expected = @{@"non-array" : @[ @1, @2 ]};
  172. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  173. }
  174. - (void)testAppliesLocalArrayUnionTransformWithNonExistingElements {
  175. auto baseDoc = @{@"array" : @[ @1, @3 ]};
  176. auto transform = @{@"array" : [FIRFieldValue fieldValueForArrayUnion:@[ @2, @4 ]]};
  177. auto expected = @{@"array" : @[ @1, @3, @2, @4 ]};
  178. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  179. }
  180. - (void)testAppliesLocalArrayUnionTransformWithExistingElements {
  181. auto baseDoc = @{@"array" : @[ @1, @3 ]};
  182. auto transform = @{@"array" : [FIRFieldValue fieldValueForArrayUnion:@[ @1, @3 ]]};
  183. auto expected = @{@"array" : @[ @1, @3 ]};
  184. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  185. }
  186. - (void)testAppliesLocalArrayUnionTransformWithDuplicateExistingElements {
  187. // Duplicate entries in your existing array should be preserved.
  188. auto baseDoc = @{@"array" : @[ @1, @2, @2, @3 ]};
  189. auto transform = @{@"array" : [FIRFieldValue fieldValueForArrayUnion:@[ @2 ]]};
  190. auto expected = @{@"array" : @[ @1, @2, @2, @3 ]};
  191. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  192. }
  193. - (void)testAppliesLocalArrayUnionTransformWithDuplicateUnionElements {
  194. // Duplicate entries in your union array should only be added once.
  195. auto baseDoc = @{@"array" : @[ @1, @3 ]};
  196. auto transform = @{@"array" : [FIRFieldValue fieldValueForArrayUnion:@[ @2, @2 ]]};
  197. auto expected = @{@"array" : @[ @1, @3, @2 ]};
  198. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  199. }
  200. - (void)testAppliesLocalArrayUnionTransformWithNonPrimitiveElements {
  201. // Union nested object values (one existing, one not).
  202. auto baseDoc = @{@"array" : @[ @1, @{@"a" : @"b"} ]};
  203. auto transform =
  204. @{@"array" : [FIRFieldValue fieldValueForArrayUnion:@[ @{@"a" : @"b"}, @{@"c" : @"d"} ]]};
  205. auto expected = @{@"array" : @[ @1, @{@"a" : @"b"}, @{@"c" : @"d"} ]};
  206. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  207. }
  208. - (void)testAppliesLocalArrayUnionTransformWithPartiallyOverlappingElements {
  209. // Union objects that partially overlap an existing object.
  210. auto baseDoc = @{@"array" : @[ @1, @{@"a" : @"b", @"c" : @"d"} ]};
  211. auto transform =
  212. @{@"array" : [FIRFieldValue fieldValueForArrayUnion:@[ @{@"a" : @"b"}, @{@"c" : @"d"} ]]};
  213. auto expected =
  214. @{@"array" : @[ @1, @{@"a" : @"b", @"c" : @"d"}, @{@"a" : @"b"}, @{@"c" : @"d"} ]};
  215. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  216. }
  217. - (void)testAppliesLocalArrayRemoveTransformToMissingField {
  218. auto baseDoc = @{};
  219. auto transform = @{@"missing" : [FIRFieldValue fieldValueForArrayRemove:@[ @1, @2 ]]};
  220. auto expected = @{@"missing" : @[]};
  221. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  222. }
  223. - (void)testAppliesLocalArrayRemoveTransformToNonArrayField {
  224. auto baseDoc = @{@"non-array" : @42};
  225. auto transform = @{@"non-array" : [FIRFieldValue fieldValueForArrayRemove:@[ @1, @2 ]]};
  226. auto expected = @{@"non-array" : @[]};
  227. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  228. }
  229. - (void)testAppliesLocalArrayRemoveTransformWithNonExistingElements {
  230. auto baseDoc = @{@"array" : @[ @1, @3 ]};
  231. auto transform = @{@"array" : [FIRFieldValue fieldValueForArrayRemove:@[ @2, @4 ]]};
  232. auto expected = @{@"array" : @[ @1, @3 ]};
  233. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  234. }
  235. - (void)testAppliesLocalArrayRemoveTransformWithExistingElements {
  236. auto baseDoc = @{@"array" : @[ @1, @2, @3, @4 ]};
  237. auto transform = @{@"array" : [FIRFieldValue fieldValueForArrayRemove:@[ @1, @3 ]]};
  238. auto expected = @{@"array" : @[ @2, @4 ]};
  239. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  240. }
  241. - (void)testAppliesLocalArrayRemoveTransformWithNonPrimitiveElements {
  242. // Remove nested object values (one existing, one not).
  243. auto baseDoc = @{@"array" : @[ @1, @{@"a" : @"b"} ]};
  244. auto transform =
  245. @{@"array" : [FIRFieldValue fieldValueForArrayRemove:@[ @{@"a" : @"b"}, @{@"c" : @"d"} ]]};
  246. auto expected = @{@"array" : @[ @1 ]};
  247. [self transformBaseDoc:baseDoc with:transform expecting:expected];
  248. }
  249. // Helper to test a particular transform scenario.
  250. - (void)transformBaseDoc:(NSDictionary<NSString *, id> *)baseData
  251. with:(NSDictionary<NSString *, id> *)transformData
  252. expecting:(NSDictionary<NSString *, id> *)expectedData {
  253. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, baseData, FSTDocumentStateSynced);
  254. FSTMutation *transform = FSTTestTransformMutation(@"collection/key", transformData);
  255. FSTMaybeDocument *transformedDoc =
  256. [transform applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  257. FSTDocument *expectedDoc = [FSTDocument documentWithData:FSTTestObjectValue(expectedData)
  258. key:FSTTestDocKey(@"collection/key")
  259. version:testutil::Version(0)
  260. state:FSTDocumentStateLocalMutations];
  261. XCTAssertEqualObjects(transformedDoc, expectedDoc);
  262. }
  263. - (void)testAppliesServerAckedServerTimestampTransformToDocuments {
  264. NSDictionary *docData = @{@"foo" : @{@"bar" : @"bar-value"}, @"baz" : @"baz-value"};
  265. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  266. FSTMutation *transform = FSTTestTransformMutation(
  267. @"collection/key", @{@"foo.bar" : [FIRFieldValue fieldValueForServerTimestamp]});
  268. FSTMutationResult *mutationResult = [[FSTMutationResult alloc]
  269. initWithVersion:testutil::Version(1)
  270. transformResults:@[ [FSTTimestampValue timestampValue:_timestamp] ]];
  271. FSTMaybeDocument *transformedDoc =
  272. [transform applyToRemoteDocument:baseDoc mutationResult:mutationResult];
  273. NSDictionary *expectedData = @{@"foo" : @{@"bar" : _timestamp.dateValue}, @"baz" : @"baz-value"};
  274. XCTAssertEqualObjects(transformedDoc, FSTTestDoc("collection/key", 1, expectedData,
  275. FSTDocumentStateCommittedMutations));
  276. }
  277. - (void)testAppliesServerAckedArrayTransformsToDocuments {
  278. NSDictionary *docData = @{@"array_1" : @[ @1, @2 ], @"array_2" : @[ @"a", @"b" ]};
  279. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  280. FSTMutation *transform = FSTTestTransformMutation(@"collection/key", @{
  281. @"array_1" : [FIRFieldValue fieldValueForArrayUnion:@[ @2, @3 ]],
  282. @"array_2" : [FIRFieldValue fieldValueForArrayRemove:@[ @"a", @"c" ]]
  283. });
  284. // Server just sends null transform results for array operations.
  285. FSTMutationResult *mutationResult = [[FSTMutationResult alloc]
  286. initWithVersion:testutil::Version(1)
  287. transformResults:@[ [FSTNullValue nullValue], [FSTNullValue nullValue] ]];
  288. FSTMaybeDocument *transformedDoc =
  289. [transform applyToRemoteDocument:baseDoc mutationResult:mutationResult];
  290. NSDictionary *expectedData = @{@"array_1" : @[ @1, @2, @3 ], @"array_2" : @[ @"b" ]};
  291. XCTAssertEqualObjects(transformedDoc, FSTTestDoc("collection/key", 1, expectedData,
  292. FSTDocumentStateCommittedMutations));
  293. }
  294. - (void)testDeleteDeletes {
  295. NSDictionary *docData = @{@"foo" : @"bar"};
  296. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  297. FSTMutation *mutation = FSTTestDeleteMutation(@"collection/key");
  298. FSTMaybeDocument *result =
  299. [mutation applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  300. XCTAssertEqualObjects(result, FSTTestDeletedDoc("collection/key", 0, NO));
  301. }
  302. - (void)testSetWithMutationResult {
  303. NSDictionary *docData = @{@"foo" : @"bar"};
  304. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  305. FSTMutation *set = FSTTestSetMutation(@"collection/key", @{@"foo" : @"new-bar"});
  306. FSTMutationResult *mutationResult =
  307. [[FSTMutationResult alloc] initWithVersion:testutil::Version(4) transformResults:nil];
  308. FSTMaybeDocument *setDoc = [set applyToRemoteDocument:baseDoc mutationResult:mutationResult];
  309. NSDictionary *expectedData = @{@"foo" : @"new-bar"};
  310. XCTAssertEqualObjects(
  311. setDoc, FSTTestDoc("collection/key", 4, expectedData, FSTDocumentStateCommittedMutations));
  312. }
  313. - (void)testPatchWithMutationResult {
  314. NSDictionary *docData = @{@"foo" : @"bar"};
  315. FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, FSTDocumentStateSynced);
  316. FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo" : @"new-bar"}, {});
  317. FSTMutationResult *mutationResult =
  318. [[FSTMutationResult alloc] initWithVersion:testutil::Version(4) transformResults:nil];
  319. FSTMaybeDocument *patchedDoc =
  320. [patch applyToRemoteDocument:baseDoc mutationResult:mutationResult];
  321. NSDictionary *expectedData = @{@"foo" : @"new-bar"};
  322. XCTAssertEqualObjects(patchedDoc, FSTTestDoc("collection/key", 4, expectedData,
  323. FSTDocumentStateCommittedMutations));
  324. }
  325. #define ASSERT_VERSION_TRANSITION(mutation, base, result, expected) \
  326. do { \
  327. FSTMaybeDocument *actual = [mutation applyToRemoteDocument:base mutationResult:result]; \
  328. XCTAssertEqualObjects(actual, expected); \
  329. } while (0);
  330. /**
  331. * Tests the transition table documented in FSTMutation.h.
  332. */
  333. - (void)testTransitions {
  334. FSTDocument *docV3 = FSTTestDoc("collection/key", 3, @{}, FSTDocumentStateSynced);
  335. FSTDeletedDocument *deletedV3 = FSTTestDeletedDoc("collection/key", 3, NO);
  336. FSTMutation *setMutation = FSTTestSetMutation(@"collection/key", @{});
  337. FSTMutation *patchMutation = FSTTestPatchMutation("collection/key", @{}, {});
  338. FSTMutation *transformMutation = FSTTestTransformMutation(@"collection/key", @{});
  339. FSTMutation *deleteMutation = FSTTestDeleteMutation(@"collection/key");
  340. FSTDeletedDocument *docV7Deleted = FSTTestDeletedDoc("collection/key", 7, YES);
  341. FSTDocument *docV7Committed =
  342. FSTTestDoc("collection/key", 7, @{}, FSTDocumentStateCommittedMutations);
  343. FSTUnknownDocument *docV7Unknown = FSTTestUnknownDoc("collection/key", 7);
  344. FSTMutationResult *mutationResult =
  345. [[FSTMutationResult alloc] initWithVersion:testutil::Version(7) transformResults:nil];
  346. FSTMutationResult *transformResult =
  347. [[FSTMutationResult alloc] initWithVersion:testutil::Version(7) transformResults:@[]];
  348. ASSERT_VERSION_TRANSITION(setMutation, docV3, mutationResult, docV7Committed);
  349. ASSERT_VERSION_TRANSITION(setMutation, deletedV3, mutationResult, docV7Committed);
  350. ASSERT_VERSION_TRANSITION(setMutation, nil, mutationResult, docV7Committed);
  351. ASSERT_VERSION_TRANSITION(patchMutation, docV3, mutationResult, docV7Committed);
  352. ASSERT_VERSION_TRANSITION(patchMutation, deletedV3, mutationResult, docV7Unknown);
  353. ASSERT_VERSION_TRANSITION(patchMutation, nil, mutationResult, docV7Unknown);
  354. ASSERT_VERSION_TRANSITION(transformMutation, docV3, transformResult, docV7Committed);
  355. ASSERT_VERSION_TRANSITION(transformMutation, deletedV3, transformResult, docV7Unknown);
  356. ASSERT_VERSION_TRANSITION(transformMutation, nil, transformResult, docV7Unknown);
  357. ASSERT_VERSION_TRANSITION(deleteMutation, docV3, mutationResult, docV7Deleted);
  358. ASSERT_VERSION_TRANSITION(deleteMutation, deletedV3, mutationResult, docV7Deleted);
  359. ASSERT_VERSION_TRANSITION(deleteMutation, nil, mutationResult, docV7Deleted);
  360. }
  361. #undef ASSERT_TRANSITION
  362. @end