testutil.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. * Copyright 2018 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. #ifndef FIRESTORE_CORE_TEST_UNIT_TESTUTIL_TESTUTIL_H_
  17. #define FIRESTORE_CORE_TEST_UNIT_TESTUTIL_TESTUTIL_H_
  18. #include <algorithm>
  19. #include <memory>
  20. #include <string>
  21. #include <unordered_map>
  22. #include <utility>
  23. #include <vector>
  24. #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
  25. #include "Firestore/core/src/core/core_fwd.h"
  26. #include "Firestore/core/src/core/direction.h"
  27. #include "Firestore/core/src/model/document_key.h"
  28. #include "Firestore/core/src/model/document_set.h"
  29. #include "Firestore/core/src/model/field_index.h"
  30. #include "Firestore/core/src/model/model_fwd.h"
  31. #include "Firestore/core/src/model/mutation.h"
  32. #include "Firestore/core/src/model/precondition.h"
  33. #include "Firestore/core/src/model/value_util.h"
  34. #include "Firestore/core/src/nanopb/byte_string.h"
  35. #include "Firestore/core/src/nanopb/message.h"
  36. #include "Firestore/core/src/nanopb/nanopb_util.h"
  37. #include "absl/strings/string_view.h"
  38. namespace firebase {
  39. class Timestamp;
  40. namespace firestore {
  41. class GeoPoint;
  42. namespace remote {
  43. class RemoteEvent;
  44. } // namespace remote
  45. namespace model {
  46. class MutableDocument;
  47. } // namespace model
  48. namespace nanopb {
  49. class ByteString;
  50. } // namespace nanopb
  51. namespace core {
  52. class FieldFilter;
  53. class CompositeFilter;
  54. } // namespace core
  55. namespace testutil {
  56. namespace details {
  57. nanopb::Message<google_firestore_v1_Value> BlobValue(
  58. std::initializer_list<uint8_t>);
  59. } // namespace details
  60. // A bit pattern for our canonical NaN value.
  61. ABSL_CONST_INIT extern const uint64_t kCanonicalNanBits;
  62. // Convenience methods for creating instances for tests.
  63. nanopb::ByteString Bytes(std::initializer_list<uint8_t>);
  64. nanopb::Message<google_firestore_v1_Value> Value(std::nullptr_t);
  65. /**
  66. * A type definition that evaluates to type V only if T is exactly type `bool`.
  67. */
  68. template <typename T, typename V>
  69. using EnableForExactlyBool =
  70. typename std::enable_if<std::is_same<bool, T>::value, V>::type;
  71. /**
  72. * A type definition that evaluates to type V only if T is an integral type but
  73. * not `bool`.
  74. */
  75. template <typename T, typename V>
  76. using EnableForInts = typename std::enable_if<std::is_integral<T>::value &&
  77. !std::is_same<bool, T>::value,
  78. V>::type;
  79. /**
  80. * Creates a boolean FieldValue.
  81. *
  82. * @tparam T A type that must be exactly bool. Any T that is not bool causes
  83. * this declaration to be disabled.
  84. * @param bool_value A boolean value that disallows implicit conversions.
  85. */
  86. template <typename T>
  87. EnableForExactlyBool<T, nanopb::Message<google_firestore_v1_Value>> Value(
  88. T bool_value) {
  89. nanopb::Message<google_firestore_v1_Value> result;
  90. result->which_value_type = google_firestore_v1_Value_boolean_value_tag;
  91. result->boolean_value = bool_value;
  92. return result;
  93. }
  94. /**
  95. * Creates an integer FieldValue.
  96. *
  97. * This is defined as a template to capture all integer literals. Just defining
  98. * this as taking int64_t would make integer literals ambiguous because int64_t
  99. * and double are equally good choices according to the standard.
  100. *
  101. * @tparam T Any integral type (but not bool). Types larger than int64_t will
  102. * likely generate a warning.
  103. * @param value An integer value.
  104. */
  105. template <typename T>
  106. EnableForInts<T, nanopb::Message<google_firestore_v1_Value>> Value(T value) {
  107. nanopb::Message<google_firestore_v1_Value> result;
  108. result->which_value_type = google_firestore_v1_Value_integer_value_tag;
  109. result->integer_value = value;
  110. return result;
  111. }
  112. nanopb::Message<google_firestore_v1_Value> Value(double value);
  113. nanopb::Message<google_firestore_v1_Value> Value(Timestamp value);
  114. nanopb::Message<google_firestore_v1_Value> Value(const char* value);
  115. nanopb::Message<google_firestore_v1_Value> Value(const std::string& value);
  116. nanopb::Message<google_firestore_v1_Value> Value(
  117. const nanopb::ByteString& value);
  118. nanopb::Message<google_firestore_v1_Value> Value(const GeoPoint& value);
  119. template <typename... Ints>
  120. nanopb::Message<google_firestore_v1_Value> BlobValue(Ints... octets) {
  121. return details::BlobValue({static_cast<uint8_t>(octets)...});
  122. }
  123. nanopb::Message<google_firestore_v1_Value> Value(
  124. nanopb::Message<google_firestore_v1_Value> value);
  125. nanopb::Message<google_firestore_v1_Value> Value(
  126. nanopb::Message<google_firestore_v1_ArrayValue> value);
  127. nanopb::Message<google_firestore_v1_Value> Value(
  128. nanopb::Message<google_firestore_v1_MapValue> value);
  129. nanopb::Message<google_firestore_v1_Value> Value(
  130. const model::ObjectValue& value);
  131. using OverlayTypeMap = std::unordered_map<model::DocumentKey,
  132. model::Mutation::Type,
  133. model::DocumentKeyHash>;
  134. namespace details {
  135. /**
  136. * Recursive base case for AddPairs, below. Returns the map.
  137. */
  138. inline nanopb::Message<google_firestore_v1_Value> AddPairs(
  139. nanopb::Message<google_firestore_v1_Value> prior) {
  140. return prior;
  141. }
  142. /**
  143. * Inserts the given key-value pair into the map, and then recursively calls
  144. * AddPairs to add any remaining arguments.
  145. *
  146. * @param prior A map into which the values should be inserted.
  147. * @param key The key naming the field to insert.
  148. * @param value A value to wrap with a call to Value(), above.
  149. * @param rest Any remaining arguments
  150. *
  151. * @return The resulting map.
  152. */
  153. template <typename ValueType, typename... Args>
  154. nanopb::Message<google_firestore_v1_Value> AddPairs(
  155. nanopb::Message<google_firestore_v1_Value> prior,
  156. const std::string& key,
  157. ValueType value,
  158. Args... rest) {
  159. nanopb::Message<google_firestore_v1_Value> result = std::move(prior);
  160. result->which_value_type = google_firestore_v1_Value_map_value_tag;
  161. size_t new_count = result->map_value.fields_count + 1;
  162. result->map_value.fields_count = nanopb::CheckedSize(new_count);
  163. result->map_value.fields =
  164. nanopb::ResizeArray<google_firestore_v1_MapValue_FieldsEntry>(
  165. result->map_value.fields, new_count);
  166. result->map_value.fields[new_count - 1].key = nanopb::MakeBytesArray(key);
  167. result->map_value.fields[new_count - 1].value =
  168. *Value(std::move(value)).release();
  169. return AddPairs(std::move(result), std::forward<Args>(rest)...);
  170. }
  171. /**
  172. * Creates an immutable sorted map from the given key/value pairs.
  173. *
  174. * @param key_value_pairs Alternating strings naming keys and values that can
  175. * be passed to Value().
  176. */
  177. template <typename... Args>
  178. nanopb::Message<google_firestore_v1_Value> MakeMap(Args... key_value_pairs) {
  179. nanopb::Message<google_firestore_v1_Value> map_value;
  180. map_value->which_value_type = google_firestore_v1_Value_map_value_tag;
  181. map_value->map_value = {};
  182. return AddPairs(std::move(map_value), std::forward<Args>(key_value_pairs)...);
  183. }
  184. /**
  185. * Recursive base case for AddElements, below.
  186. */
  187. inline void AddElements(nanopb::Message<google_firestore_v1_ArrayValue>&,
  188. pb_size_t) {
  189. }
  190. /**
  191. * Inserts the given element into the array, and then recursively calls
  192. * AddElement to add any remaining arguments.
  193. *
  194. * @param array_value An array into which the values should be inserted.
  195. * @param pos The index of the next element.
  196. * @param value The element to insert.
  197. * @param rest Any remaining arguments
  198. */
  199. template <typename ValueType, typename... Args>
  200. void AddElements(nanopb::Message<google_firestore_v1_ArrayValue>& array_value,
  201. pb_size_t pos,
  202. ValueType value,
  203. Args&&... rest) {
  204. array_value->values[pos] = *Value(std::move(value)).release();
  205. AddElements(array_value, ++pos, std::forward<Args>(rest)...);
  206. }
  207. /**
  208. * Inserts the elements into the given array.
  209. */
  210. template <typename... Args>
  211. nanopb::Message<google_firestore_v1_ArrayValue> MakeArray(Args&&... values) {
  212. nanopb::Message<google_firestore_v1_ArrayValue> array_value;
  213. array_value->values_count = nanopb::CheckedSize(sizeof...(Args));
  214. array_value->values =
  215. nanopb::MakeArray<google_firestore_v1_Value>(array_value->values_count);
  216. AddElements(array_value, 0, std::forward<Args>(values)...);
  217. return array_value;
  218. }
  219. } // namespace details
  220. template <typename... Args>
  221. nanopb::Message<google_firestore_v1_ArrayValue> Array(Args&&... values) {
  222. return details::MakeArray(std::move(values)...);
  223. }
  224. /** Wraps an immutable sorted map into an ObjectValue. */
  225. model::ObjectValue WrapObject(nanopb::Message<google_firestore_v1_Value> value);
  226. /**
  227. * Creates an ObjectValue from the given key/value pairs.
  228. *
  229. * @param key_value_pairs Alternating strings naming keys and values that can
  230. * be passed to Value().
  231. */
  232. template <typename... Args>
  233. model::ObjectValue WrapObject(Args... key_value_pairs) {
  234. return WrapObject(details::MakeMap(std::move(key_value_pairs)...));
  235. }
  236. /**
  237. * Creates an ObjectValue from the given key/value pairs with Type::Object.
  238. *
  239. * @param key_value_pairs Alternating strings naming keys and values that can
  240. * be passed to Value().
  241. */
  242. template <typename... Args>
  243. nanopb::Message<google_firestore_v1_Value> Map(Args... key_value_pairs) {
  244. return details::MakeMap(std::move(key_value_pairs)...);
  245. }
  246. model::DocumentKey Key(absl::string_view path);
  247. model::FieldPath Field(absl::string_view field);
  248. model::DatabaseId DbId(std::string project = "project/(default)");
  249. nanopb::Message<google_firestore_v1_Value> Ref(std::string project,
  250. absl::string_view path);
  251. model::ResourcePath Resource(absl::string_view field);
  252. /**
  253. * Creates a snapshot version from the given version timestamp.
  254. *
  255. * @param version a timestamp in microseconds since the epoch.
  256. */
  257. model::SnapshotVersion Version(int64_t version);
  258. model::SnapshotVersion Version(int64_t seconds, int32_t nanoseconds);
  259. model::MutableDocument Doc(absl::string_view key, int64_t version = 0);
  260. model::MutableDocument Doc(absl::string_view key,
  261. int64_t version,
  262. nanopb::Message<google_firestore_v1_Value> data);
  263. /** A convenience method for creating deleted docs for tests. */
  264. model::MutableDocument DeletedDoc(absl::string_view key, int64_t version = 0);
  265. /** A convenience method for creating deleted docs for tests. */
  266. model::MutableDocument DeletedDoc(model::DocumentKey key, int64_t version = 0);
  267. /** A convenience method for creating unknown docs for tests. */
  268. model::MutableDocument UnknownDoc(absl::string_view key, int64_t version);
  269. /** A convenience method for creating invalid (missing) docs for tests. */
  270. model::MutableDocument InvalidDoc(absl::string_view key);
  271. /**
  272. * Creates a DocumentComparator that will compare Documents by the given
  273. * field_path string then by key.
  274. */
  275. model::DocumentComparator DocComparator(absl::string_view field_path);
  276. /**
  277. * Creates a DocumentSet based on the given comparator, initially containing the
  278. * given documents.
  279. */
  280. model::DocumentSet DocSet(model::DocumentComparator comp,
  281. std::vector<model::Document> docs);
  282. core::FieldFilter Filter(absl::string_view key,
  283. absl::string_view op,
  284. nanopb::Message<google_firestore_v1_Value> value);
  285. core::FieldFilter Filter(absl::string_view key,
  286. absl::string_view op,
  287. nanopb::Message<google_firestore_v1_ArrayValue> value);
  288. core::FieldFilter Filter(absl::string_view key,
  289. absl::string_view op,
  290. std::nullptr_t);
  291. core::FieldFilter Filter(absl::string_view key,
  292. absl::string_view op,
  293. const char* value);
  294. template <typename T>
  295. EnableForExactlyBool<T, core::FieldFilter> Filter(absl::string_view key,
  296. absl::string_view op,
  297. T value) {
  298. return Filter(key, op, Value(value));
  299. }
  300. core::FieldFilter Filter(absl::string_view key,
  301. absl::string_view op,
  302. int value);
  303. core::FieldFilter Filter(absl::string_view key,
  304. absl::string_view op,
  305. double value);
  306. core::CompositeFilter AndFilters(std::vector<core::Filter> filters);
  307. core::CompositeFilter OrFilters(std::vector<core::Filter> filters);
  308. core::Direction Direction(absl::string_view direction);
  309. core::OrderBy OrderBy(absl::string_view key,
  310. absl::string_view direction = "asc");
  311. core::OrderBy OrderBy(model::FieldPath field_path, core::Direction direction);
  312. core::Query Query(absl::string_view path);
  313. core::Query CollectionGroupQuery(absl::string_view collection_id);
  314. remote::RemoteEvent AddedRemoteEvent(
  315. const std::vector<model::MutableDocument>& docs,
  316. const std::vector<model::TargetId>& added_to_targets);
  317. remote::RemoteEvent AddedRemoteEvent(
  318. const model::MutableDocument& doc,
  319. const std::vector<model::TargetId>& added_to_targets);
  320. remote::RemoteEvent UpdateRemoteEvent(
  321. const model::MutableDocument& doc,
  322. const std::vector<model::TargetId>& updated_in_targets,
  323. const std::vector<model::TargetId>& removed_from_targets);
  324. remote::RemoteEvent UpdateRemoteEventWithLimboTargets(
  325. const model::MutableDocument& doc,
  326. const std::vector<model::TargetId>& updated_in_targets,
  327. const std::vector<model::TargetId>& removed_from_targets,
  328. const std::vector<model::TargetId>& limbo_targets);
  329. model::SetMutation SetMutation(
  330. absl::string_view path,
  331. nanopb::Message<google_firestore_v1_Value> values,
  332. std::vector<std::pair<std::string, model::TransformOperation>> transforms =
  333. {});
  334. model::PatchMutation PatchMutation(
  335. absl::string_view path,
  336. nanopb::Message<google_firestore_v1_Value> values,
  337. std::vector<std::pair<std::string, model::TransformOperation>> transforms =
  338. {});
  339. model::PatchMutation PatchMutation(
  340. absl::string_view path,
  341. nanopb::Message<google_firestore_v1_Value> values,
  342. const std::vector<model::FieldPath>& update_mask,
  343. std::vector<std::pair<std::string, model::TransformOperation>> transforms =
  344. {});
  345. model::PatchMutation MergeMutation(
  346. absl::string_view path,
  347. nanopb::Message<google_firestore_v1_Value> values,
  348. const std::vector<model::FieldPath>& update_mask,
  349. std::vector<std::pair<std::string, model::TransformOperation>> transforms =
  350. {});
  351. model::PatchMutation PatchMutationHelper(
  352. absl::string_view path,
  353. nanopb::Message<google_firestore_v1_Value> values,
  354. std::vector<std::pair<std::string, model::TransformOperation>> transforms,
  355. model::Precondition precondition,
  356. const absl::optional<std::vector<model::FieldPath>>& update_mask);
  357. /**
  358. * Creates a pair of field name, TransformOperation that represents a
  359. * server-generated timestamp, suitable for passing to TransformMutation,
  360. * above.
  361. */
  362. std::pair<std::string, model::TransformOperation> ServerTimestamp(
  363. std::string field);
  364. /**
  365. * Creates a pair of field name, TransformOperation that represents a numeric
  366. * increment on the given field, suitable for passing to TransformMutation,
  367. * above.
  368. */
  369. std::pair<std::string, model::TransformOperation> Increment(
  370. std::string field, nanopb::Message<google_firestore_v1_Value> operand);
  371. /**
  372. * Creates a pair of field name, TransformOperation that represents an array
  373. * union on the given field, suitable for passing to TransformMutation,
  374. * above.
  375. */
  376. std::pair<std::string, model::TransformOperation> ArrayUnion(
  377. std::string field,
  378. const std::vector<nanopb::Message<google_firestore_v1_Value>>& operands);
  379. model::DeleteMutation DeleteMutation(absl::string_view path);
  380. model::VerifyMutation VerifyMutation(absl::string_view path, int64_t version);
  381. model::MutationResult MutationResult(int64_t version);
  382. nanopb::ByteString ResumeToken(int64_t snapshot_version);
  383. template <typename T, typename... Ts>
  384. std::vector<T> Vector(T&& arg1, Ts&&... args) {
  385. return {std::forward<T>(arg1), std::forward<Ts>(args)...};
  386. }
  387. // Degenerate case to end recursion of `MoveIntoVector`.
  388. template <typename T>
  389. void MoveIntoVector(std::vector<std::unique_ptr<T>>*) {
  390. }
  391. template <typename T, typename Head, typename... Tail>
  392. void MoveIntoVector(std::vector<std::unique_ptr<T>>* result,
  393. Head head,
  394. Tail... tail) {
  395. result->push_back(std::move(head));
  396. MoveIntoVector(result, std::move(tail)...);
  397. }
  398. // Works around the fact that move-only types (in this case, `unique_ptr`) don't
  399. // work with `initializer_list`. Desired (doesn't work):
  400. //
  401. // std::unique_ptr<int> x, y;
  402. // std::vector<std::unique_ptr>> foo{std::move(x), std::move(y)};
  403. //
  404. // Actual:
  405. //
  406. // std::unique_ptr<int> x, y;
  407. // std::vector<std::unique_ptr<int>> foo = Changes(std::move(x),
  408. // std::move(y));
  409. template <typename T, typename... Elems>
  410. std::vector<std::unique_ptr<T>> VectorOfUniquePtrs(Elems... elems) {
  411. std::vector<std::unique_ptr<T>> result;
  412. MoveIntoVector<T>(&result, std::move(elems)...);
  413. return result;
  414. }
  415. model::FieldIndex MakeFieldIndex(const std::string& collection_group);
  416. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  417. int32_t index_id,
  418. model::IndexState state);
  419. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  420. const std::string& field,
  421. model::Segment::Kind kind);
  422. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  423. const std::string& field_1,
  424. model::Segment::Kind kind_1,
  425. const std::string& field_2,
  426. model::Segment::Kind kind_2);
  427. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  428. const std::string& field_1,
  429. model::Segment::Kind kind_1,
  430. const std::string& field_2,
  431. model::Segment::Kind kind_2,
  432. const std::string& field_3,
  433. model::Segment::Kind kind_3);
  434. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  435. int32_t index_id,
  436. model::IndexState state,
  437. const std::string& field_1,
  438. model::Segment::Kind kind_1);
  439. } // namespace testutil
  440. } // namespace firestore
  441. } // namespace firebase
  442. #endif // FIRESTORE_CORE_TEST_UNIT_TESTUTIL_TESTUTIL_H_