testutil.h 15 KB

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