FSTMutationTests.mm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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/FIRTimestamp.h>
  18. #import <XCTest/XCTest.h>
  19. #import "Firestore/Source/Model/FSTDocument.h"
  20. #import "Firestore/Source/Model/FSTDocumentKey.h"
  21. #import "Firestore/Source/Model/FSTFieldValue.h"
  22. #import "Firestore/Source/Model/FSTPath.h"
  23. #import "Firestore/Example/Tests/Util/FSTHelpers.h"
  24. @interface FSTMutationTests : XCTestCase
  25. @end
  26. @implementation FSTMutationTests {
  27. FIRTimestamp *_timestamp;
  28. }
  29. - (void)setUp {
  30. _timestamp = [FIRTimestamp timestamp];
  31. }
  32. - (void)testAppliesSetsToDocuments {
  33. NSDictionary *docData = @{@"foo" : @"foo-value", @"baz" : @"baz-value"};
  34. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  35. FSTMutation *set = FSTTestSetMutation(@"collection/key", @{@"bar" : @"bar-value"});
  36. FSTMaybeDocument *setDoc = [set applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  37. NSDictionary *expectedData = @{@"bar" : @"bar-value"};
  38. XCTAssertEqualObjects(setDoc, FSTTestDoc(@"collection/key", 0, expectedData, YES));
  39. }
  40. - (void)testAppliesPatchesToDocuments {
  41. NSDictionary *docData = @{ @"foo" : @{@"bar" : @"bar-value"}, @"baz" : @"baz-value" };
  42. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  43. FSTMutation *patch =
  44. FSTTestPatchMutation(@"collection/key", @{@"foo.bar" : @"new-bar-value"}, nil);
  45. FSTMaybeDocument *patchedDoc =
  46. [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  47. NSDictionary *expectedData = @{ @"foo" : @{@"bar" : @"new-bar-value"}, @"baz" : @"baz-value" };
  48. XCTAssertEqualObjects(patchedDoc, FSTTestDoc(@"collection/key", 0, expectedData, YES));
  49. }
  50. - (void)testDeletesValuesFromTheFieldMask {
  51. NSDictionary *docData = @{ @"foo" : @{@"bar" : @"bar-value", @"baz" : @"baz-value"} };
  52. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  53. FSTDocumentKey *key = FSTTestDocKey(@"collection/key");
  54. FSTFieldMask *mask = [[FSTFieldMask alloc] initWithFields:@[ FSTTestFieldPath(@"foo.bar") ]];
  55. FSTMutation *patch = [[FSTPatchMutation alloc] initWithKey:key
  56. fieldMask:mask
  57. value:[FSTObjectValue objectValue]
  58. precondition:[FSTPrecondition none]];
  59. FSTMaybeDocument *patchedDoc =
  60. [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  61. NSDictionary *expectedData = @{ @"foo" : @{@"baz" : @"baz-value"} };
  62. XCTAssertEqualObjects(patchedDoc, FSTTestDoc(@"collection/key", 0, expectedData, YES));
  63. }
  64. - (void)testPatchesPrimitiveValue {
  65. NSDictionary *docData = @{@"foo" : @"foo-value", @"baz" : @"baz-value"};
  66. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  67. FSTMutation *patch =
  68. FSTTestPatchMutation(@"collection/key", @{@"foo.bar" : @"new-bar-value"}, nil);
  69. FSTMaybeDocument *patchedDoc =
  70. [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  71. NSDictionary *expectedData = @{ @"foo" : @{@"bar" : @"new-bar-value"}, @"baz" : @"baz-value" };
  72. XCTAssertEqualObjects(patchedDoc, FSTTestDoc(@"collection/key", 0, expectedData, YES));
  73. }
  74. - (void)testPatchingDeletedDocumentsDoesNothing {
  75. FSTMaybeDocument *baseDoc = FSTTestDeletedDoc(@"collection/key", 0);
  76. FSTMutation *patch = FSTTestPatchMutation(@"collection/key", @{@"foo" : @"bar"}, nil);
  77. FSTMaybeDocument *patchedDoc =
  78. [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  79. XCTAssertEqualObjects(patchedDoc, baseDoc);
  80. }
  81. - (void)testAppliesLocalTransformsToDocuments {
  82. NSDictionary *docData = @{ @"foo" : @{@"bar" : @"bar-value"}, @"baz" : @"baz-value" };
  83. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  84. FSTMutation *transform = FSTTestTransformMutation(@"collection/key", @[ @"foo.bar" ]);
  85. FSTMaybeDocument *transformedDoc =
  86. [transform applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  87. // Server timestamps aren't parsed, so we manually insert it.
  88. FSTObjectValue *expectedData = FSTTestObjectValue(
  89. @{ @"foo" : @{@"bar" : @"<server-timestamp>"},
  90. @"baz" : @"baz-value" });
  91. expectedData =
  92. [expectedData objectBySettingValue:[FSTServerTimestampValue
  93. serverTimestampValueWithLocalWriteTime:_timestamp
  94. previousValue:nil]
  95. forPath:FSTTestFieldPath(@"foo.bar")];
  96. FSTDocument *expectedDoc = [FSTDocument documentWithData:expectedData
  97. key:FSTTestDocKey(@"collection/key")
  98. version:FSTTestVersion(0)
  99. hasLocalMutations:YES];
  100. XCTAssertEqualObjects(transformedDoc, expectedDoc);
  101. }
  102. - (void)testAppliesServerAckedTransformsToDocuments {
  103. NSDictionary *docData = @{ @"foo" : @{@"bar" : @"bar-value"}, @"baz" : @"baz-value" };
  104. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  105. FSTMutation *transform = FSTTestTransformMutation(@"collection/key", @[ @"foo.bar" ]);
  106. FSTMutationResult *mutationResult = [[FSTMutationResult alloc]
  107. initWithVersion:FSTTestVersion(1)
  108. transformResults:@[ [FSTTimestampValue timestampValue:_timestamp] ]];
  109. FSTMaybeDocument *transformedDoc = [transform applyTo:baseDoc
  110. baseDocument:baseDoc
  111. localWriteTime:_timestamp
  112. mutationResult:mutationResult];
  113. NSDictionary *expectedData =
  114. @{ @"foo" : @{@"bar" : _timestamp.approximateDateValue},
  115. @"baz" : @"baz-value" };
  116. XCTAssertEqualObjects(transformedDoc, FSTTestDoc(@"collection/key", 0, expectedData, NO));
  117. }
  118. - (void)testDeleteDeletes {
  119. NSDictionary *docData = @{@"foo" : @"bar"};
  120. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  121. FSTMutation *mutation = FSTTestDeleteMutation(@"collection/key");
  122. FSTMaybeDocument *result =
  123. [mutation applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp];
  124. XCTAssertEqualObjects(result, FSTTestDeletedDoc(@"collection/key", 0));
  125. }
  126. - (void)testSetWithMutationResult {
  127. NSDictionary *docData = @{@"foo" : @"bar"};
  128. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  129. FSTMutation *set = FSTTestSetMutation(@"collection/key", @{@"foo" : @"new-bar"});
  130. FSTMutationResult *mutationResult =
  131. [[FSTMutationResult alloc] initWithVersion:FSTTestVersion(4) transformResults:nil];
  132. FSTMaybeDocument *setDoc = [set applyTo:baseDoc
  133. baseDocument:baseDoc
  134. localWriteTime:_timestamp
  135. mutationResult:mutationResult];
  136. NSDictionary *expectedData = @{@"foo" : @"new-bar"};
  137. XCTAssertEqualObjects(setDoc, FSTTestDoc(@"collection/key", 0, expectedData, NO));
  138. }
  139. - (void)testPatchWithMutationResult {
  140. NSDictionary *docData = @{@"foo" : @"bar"};
  141. FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO);
  142. FSTMutation *patch = FSTTestPatchMutation(@"collection/key", @{@"foo" : @"new-bar"}, nil);
  143. FSTMutationResult *mutationResult =
  144. [[FSTMutationResult alloc] initWithVersion:FSTTestVersion(4) transformResults:nil];
  145. FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc
  146. baseDocument:baseDoc
  147. localWriteTime:_timestamp
  148. mutationResult:mutationResult];
  149. NSDictionary *expectedData = @{@"foo" : @"new-bar"};
  150. XCTAssertEqualObjects(patchedDoc, FSTTestDoc(@"collection/key", 0, expectedData, NO));
  151. }
  152. #define ASSERT_VERSION_TRANSITION(mutation, base, expected) \
  153. do { \
  154. FSTMutationResult *mutationResult = \
  155. [[FSTMutationResult alloc] initWithVersion:FSTTestVersion(0) transformResults:nil]; \
  156. FSTMaybeDocument *actual = [mutation applyTo:base \
  157. baseDocument:base \
  158. localWriteTime:_timestamp \
  159. mutationResult:mutationResult]; \
  160. XCTAssertEqualObjects(actual, expected); \
  161. } while (0);
  162. /**
  163. * Tests the transition table documented in FSTMutation.h.
  164. */
  165. - (void)testTransitions {
  166. FSTDocument *docV0 = FSTTestDoc(@"collection/key", 0, @{}, NO);
  167. FSTDeletedDocument *deletedV0 = FSTTestDeletedDoc(@"collection/key", 0);
  168. FSTDocument *docV3 = FSTTestDoc(@"collection/key", 3, @{}, NO);
  169. FSTDeletedDocument *deletedV3 = FSTTestDeletedDoc(@"collection/key", 3);
  170. FSTMutation *setMutation = FSTTestSetMutation(@"collection/key", @{});
  171. FSTMutation *patchMutation = FSTTestPatchMutation(@"collection/key", @{}, nil);
  172. FSTMutation *deleteMutation = FSTTestDeleteMutation(@"collection/key");
  173. ASSERT_VERSION_TRANSITION(setMutation, docV3, docV3);
  174. ASSERT_VERSION_TRANSITION(setMutation, deletedV3, docV0);
  175. ASSERT_VERSION_TRANSITION(setMutation, nil, docV0);
  176. ASSERT_VERSION_TRANSITION(patchMutation, docV3, docV3);
  177. ASSERT_VERSION_TRANSITION(patchMutation, deletedV3, deletedV3);
  178. ASSERT_VERSION_TRANSITION(patchMutation, nil, nil);
  179. ASSERT_VERSION_TRANSITION(deleteMutation, docV3, deletedV0);
  180. ASSERT_VERSION_TRANSITION(deleteMutation, deletedV3, deletedV0);
  181. ASSERT_VERSION_TRANSITION(deleteMutation, nil, deletedV0);
  182. }
  183. #undef ASSERT_TRANSITION
  184. @end