testutil.h 17 KB

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