testutil.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  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. template <typename... Args>
  247. nanopb::Message<google_firestore_v1_Value> VectorType(Args&&... values) {
  248. return Map("__type__", "__vector__", "value",
  249. details::MakeArray(std::move(values)...));
  250. }
  251. model::DocumentKey Key(absl::string_view path);
  252. model::FieldPath Field(absl::string_view field);
  253. model::DatabaseId DbId(std::string project = "project/(default)");
  254. nanopb::Message<google_firestore_v1_Value> Ref(std::string project,
  255. absl::string_view path);
  256. model::ResourcePath Resource(absl::string_view field);
  257. /**
  258. * Creates a snapshot version from the given version timestamp.
  259. *
  260. * @param version a timestamp in microseconds since the epoch.
  261. */
  262. model::SnapshotVersion Version(int64_t version);
  263. model::SnapshotVersion Version(int64_t seconds, int32_t nanoseconds);
  264. model::MutableDocument Doc(absl::string_view key, int64_t version = 0);
  265. model::MutableDocument Doc(absl::string_view key,
  266. int64_t version,
  267. nanopb::Message<google_firestore_v1_Value> data);
  268. /** A convenience method for creating deleted docs for tests. */
  269. model::MutableDocument DeletedDoc(absl::string_view key, int64_t version = 0);
  270. /** A convenience method for creating deleted docs for tests. */
  271. model::MutableDocument DeletedDoc(model::DocumentKey key, int64_t version = 0);
  272. /** A convenience method for creating unknown docs for tests. */
  273. model::MutableDocument UnknownDoc(absl::string_view key, int64_t version);
  274. /** A convenience method for creating invalid (missing) docs for tests. */
  275. model::MutableDocument InvalidDoc(absl::string_view key);
  276. /**
  277. * Creates a DocumentComparator that will compare Documents by the given
  278. * field_path string then by key.
  279. */
  280. model::DocumentComparator DocComparator(absl::string_view field_path);
  281. /**
  282. * Creates a DocumentSet based on the given comparator, initially containing the
  283. * given documents.
  284. */
  285. model::DocumentSet DocSet(model::DocumentComparator comp,
  286. std::vector<model::Document> docs);
  287. core::FieldFilter Filter(absl::string_view key,
  288. absl::string_view op,
  289. nanopb::Message<google_firestore_v1_Value> value);
  290. core::FieldFilter Filter(absl::string_view key,
  291. absl::string_view op,
  292. nanopb::Message<google_firestore_v1_ArrayValue> value);
  293. core::FieldFilter Filter(absl::string_view key,
  294. absl::string_view op,
  295. std::nullptr_t);
  296. core::FieldFilter Filter(absl::string_view key,
  297. absl::string_view op,
  298. const char* value);
  299. template <typename T>
  300. EnableForExactlyBool<T, core::FieldFilter> Filter(absl::string_view key,
  301. absl::string_view op,
  302. T value) {
  303. return Filter(key, op, Value(value));
  304. }
  305. core::FieldFilter Filter(absl::string_view key,
  306. absl::string_view op,
  307. int value);
  308. core::FieldFilter Filter(absl::string_view key,
  309. absl::string_view op,
  310. double value);
  311. core::CompositeFilter AndFilters(std::vector<core::Filter> filters);
  312. core::CompositeFilter OrFilters(std::vector<core::Filter> filters);
  313. core::Direction Direction(absl::string_view direction);
  314. core::OrderBy OrderBy(absl::string_view key,
  315. absl::string_view direction = "asc");
  316. core::OrderBy OrderBy(model::FieldPath field_path, core::Direction direction);
  317. core::Query Query(absl::string_view path);
  318. core::Query CollectionGroupQuery(absl::string_view collection_id);
  319. remote::RemoteEvent AddedRemoteEvent(
  320. const std::vector<model::MutableDocument>& docs,
  321. const std::vector<model::TargetId>& added_to_targets);
  322. remote::RemoteEvent AddedRemoteEvent(
  323. const model::MutableDocument& doc,
  324. const std::vector<model::TargetId>& added_to_targets);
  325. remote::RemoteEvent UpdateRemoteEvent(
  326. const model::MutableDocument& doc,
  327. const std::vector<model::TargetId>& updated_in_targets,
  328. const std::vector<model::TargetId>& removed_from_targets);
  329. remote::RemoteEvent UpdateRemoteEventWithLimboTargets(
  330. const model::MutableDocument& doc,
  331. const std::vector<model::TargetId>& updated_in_targets,
  332. const std::vector<model::TargetId>& removed_from_targets,
  333. const std::vector<model::TargetId>& limbo_targets);
  334. model::SetMutation SetMutation(
  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. std::vector<std::pair<std::string, model::TransformOperation>> transforms =
  343. {});
  344. model::PatchMutation PatchMutation(
  345. absl::string_view path,
  346. nanopb::Message<google_firestore_v1_Value> values,
  347. const std::vector<model::FieldPath>& update_mask,
  348. std::vector<std::pair<std::string, model::TransformOperation>> transforms =
  349. {});
  350. model::PatchMutation MergeMutation(
  351. absl::string_view path,
  352. nanopb::Message<google_firestore_v1_Value> values,
  353. const std::vector<model::FieldPath>& update_mask,
  354. std::vector<std::pair<std::string, model::TransformOperation>> transforms =
  355. {});
  356. model::PatchMutation PatchMutationHelper(
  357. absl::string_view path,
  358. nanopb::Message<google_firestore_v1_Value> values,
  359. std::vector<std::pair<std::string, model::TransformOperation>> transforms,
  360. model::Precondition precondition,
  361. const absl::optional<std::vector<model::FieldPath>>& update_mask);
  362. /**
  363. * Creates a pair of field name, TransformOperation that represents a
  364. * server-generated timestamp, suitable for passing to TransformMutation,
  365. * above.
  366. */
  367. std::pair<std::string, model::TransformOperation> ServerTimestamp(
  368. std::string field);
  369. /**
  370. * Creates a pair of field name, TransformOperation that represents a numeric
  371. * increment on the given field, suitable for passing to TransformMutation,
  372. * above.
  373. */
  374. std::pair<std::string, model::TransformOperation> Increment(
  375. std::string field, nanopb::Message<google_firestore_v1_Value> operand);
  376. /**
  377. * Creates a pair of field name, TransformOperation that represents an array
  378. * union on the given field, suitable for passing to TransformMutation,
  379. * above.
  380. */
  381. std::pair<std::string, model::TransformOperation> ArrayUnion(
  382. std::string field,
  383. const std::vector<nanopb::Message<google_firestore_v1_Value>>& operands);
  384. model::DeleteMutation DeleteMutation(absl::string_view path);
  385. model::VerifyMutation VerifyMutation(absl::string_view path, int64_t version);
  386. model::MutationResult MutationResult(int64_t version);
  387. nanopb::ByteString ResumeToken(int64_t snapshot_version);
  388. template <typename T, typename... Ts>
  389. std::vector<T> Vector(T&& arg1, Ts&&... args) {
  390. return {std::forward<T>(arg1), std::forward<Ts>(args)...};
  391. }
  392. // Degenerate case to end recursion of `MoveIntoVector`.
  393. template <typename T>
  394. void MoveIntoVector(std::vector<std::unique_ptr<T>>*) {
  395. }
  396. template <typename T, typename Head, typename... Tail>
  397. void MoveIntoVector(std::vector<std::unique_ptr<T>>* result,
  398. Head head,
  399. Tail... tail) {
  400. result->push_back(std::move(head));
  401. MoveIntoVector(result, std::move(tail)...);
  402. }
  403. // Works around the fact that move-only types (in this case, `unique_ptr`) don't
  404. // work with `initializer_list`. Desired (doesn't work):
  405. //
  406. // std::unique_ptr<int> x, y;
  407. // std::vector<std::unique_ptr>> foo{std::move(x), std::move(y)};
  408. //
  409. // Actual:
  410. //
  411. // std::unique_ptr<int> x, y;
  412. // std::vector<std::unique_ptr<int>> foo = Changes(std::move(x),
  413. // std::move(y));
  414. template <typename T, typename... Elems>
  415. std::vector<std::unique_ptr<T>> VectorOfUniquePtrs(Elems... elems) {
  416. std::vector<std::unique_ptr<T>> result;
  417. MoveIntoVector<T>(&result, std::move(elems)...);
  418. return result;
  419. }
  420. model::FieldIndex MakeFieldIndex(const std::string& collection_group);
  421. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  422. int32_t index_id,
  423. model::IndexState state);
  424. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  425. const std::string& field,
  426. model::Segment::Kind kind);
  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. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  433. const std::string& field_1,
  434. model::Segment::Kind kind_1,
  435. const std::string& field_2,
  436. model::Segment::Kind kind_2,
  437. const std::string& field_3,
  438. model::Segment::Kind kind_3);
  439. model::FieldIndex MakeFieldIndex(const std::string& collection_group,
  440. int32_t index_id,
  441. model::IndexState state,
  442. const std::string& field_1,
  443. model::Segment::Kind kind_1);
  444. } // namespace testutil
  445. } // namespace firestore
  446. } // namespace firebase
  447. #endif // FIRESTORE_CORE_TEST_UNIT_TESTUTIL_TESTUTIL_H_