testutil.h 18 KB

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