1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // -----------------------------------------------------------------------------
16 // conformance_testing.h
17 // -----------------------------------------------------------------------------
18 //
19 
20 #ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
21 #define ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
22 
23 ////////////////////////////////////////////////////////////////////////////////
24 //                                                                            //
25 // Many templates in this file take a `T` and a `Prof` type as explicit       //
26 // template arguments. These are a type to be checked and a                   //
27 // "Regularity Profile" that describes what operations that type `T` is       //
28 // expected to support. See "regularity_profiles.h" for more details          //
29 // regarding Regularity Profiles.                                             //
30 //                                                                            //
31 ////////////////////////////////////////////////////////////////////////////////
32 
33 #include <cstddef>
34 #include <set>
35 #include <tuple>
36 #include <type_traits>
37 #include <utility>
38 
39 #include "gtest/gtest.h"
40 #include "absl/meta/type_traits.h"
41 #include "absl/strings/ascii.h"
42 #include "absl/strings/str_cat.h"
43 #include "absl/strings/string_view.h"
44 #include "absl/types/internal/conformance_aliases.h"
45 #include "absl/types/internal/conformance_archetype.h"
46 #include "absl/types/internal/conformance_profile.h"
47 #include "absl/types/internal/conformance_testing_helpers.h"
48 #include "absl/types/internal/parentheses.h"
49 #include "absl/types/internal/transform_args.h"
50 #include "absl/utility/utility.h"
51 
52 namespace absl {
53 ABSL_NAMESPACE_BEGIN
54 namespace types_internal {
55 
56 // Returns true if the compiler incorrectly greedily instantiates constexpr
57 // templates in any unevaluated context.
constexpr_instantiation_when_unevaluated()58 constexpr bool constexpr_instantiation_when_unevaluated() {
59 #if defined(__apple_build_version__)  // TODO(calabrese) Make more specific
60   return true;
61 #elif defined(__clang__)
62   return __clang_major__ < 4;
63 #elif defined(__GNUC__)
64   // TODO(calabrese) Figure out why gcc 7 fails (seems like a different bug)
65   return __GNUC__ < 5 || (__GNUC__ == 5 && __GNUC_MINOR__ < 2) || __GNUC__ >= 7;
66 #else
67   return false;
68 #endif
69 }
70 
71 // Returns true if the standard library being used incorrectly produces an error
72 // when instantiating the definition of a poisoned std::hash specialization.
poisoned_hash_fails_instantiation()73 constexpr bool poisoned_hash_fails_instantiation() {
74 #if defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
75   return _MSC_VER < 1914;
76 #else
77   return false;
78 #endif
79 }
80 
81 template <class Fun>
82 struct GeneratorType {
operatorGeneratorType83   decltype(std::declval<const Fun&>()()) operator()() const
84       noexcept(noexcept(std::declval<const Fun&>()())) {
85     return fun();
86   }
87 
88   Fun fun;
89   const char* description;
90 };
91 
92 // A "make" function for the GeneratorType template that deduces the function
93 // object type.
94 template <class Fun,
95           absl::enable_if_t<IsNullaryCallable<Fun>::value>** = nullptr>
Generator(Fun fun,const char * description)96 GeneratorType<Fun> Generator(Fun fun, const char* description) {
97   return GeneratorType<Fun>{absl::move(fun), description};
98 }
99 
100 // A type that contains a set of nullary function objects that each return an
101 // instance of the same type and value (though possibly different
102 // representations, such as +0 and -0 or two vectors with the same elements but
103 // with different capacities).
104 template <class... Funs>
105 struct EquivalenceClassType {
106   std::tuple<GeneratorType<Funs>...> generators;
107 };
108 
109 // A "make" function for the EquivalenceClassType template that deduces the
110 // function object types and is constrained such that a user can only pass in
111 // function objects that all have the same return type.
112 template <class... Funs, absl::enable_if_t<AreGeneratorsWithTheSameReturnType<
113                              Funs...>::value>** = nullptr>
EquivalenceClass(GeneratorType<Funs>...funs)114 EquivalenceClassType<Funs...> EquivalenceClass(GeneratorType<Funs>... funs) {
115   return {std::make_tuple(absl::move(funs)...)};
116 }
117 
118 // A type that contains an ordered series of EquivalenceClassTypes, from
119 // smallest value to largest value.
120 template <class... EqClasses>
121 struct OrderedEquivalenceClasses {
122   std::tuple<EqClasses...> eq_classes;
123 };
124 
125 // An object containing the parts of a given (name, initialization expression),
126 // and is capable of generating a string that describes the given.
127 struct GivenDeclaration {
outputDeclarationGivenDeclaration128   std::string outputDeclaration(std::size_t width) const {
129     const std::size_t indent_size = 2;
130     std::string result = absl::StrCat("  ", name);
131 
132     if (!expression.empty()) {
133       // Indent
134       result.resize(indent_size + width, ' ');
135       absl::StrAppend(&result, " = ", expression, ";\n");
136     } else {
137       absl::StrAppend(&result, ";\n");
138     }
139 
140     return result;
141   }
142 
143   std::string name;
144   std::string expression;
145 };
146 
147 // Produce a string that contains all of the givens of an error report.
148 template <class... Decls>
PrepareGivenContext(const Decls &...decls)149 std::string PrepareGivenContext(const Decls&... decls) {
150   const std::size_t width = (std::max)({decls.name.size()...});
151   return absl::StrCat("Given:\n", decls.outputDeclaration(width)..., "\n");
152 }
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 // Function objects that perform a check for each comparison operator         //
156 ////////////////////////////////////////////////////////////////////////////////
157 
158 #define ABSL_INTERNAL_EXPECT_OP(name, op)                                   \
159   struct Expect##name {                                                     \
160     template <class T>                                                      \
161     void operator()(absl::string_view test_name, absl::string_view context, \
162                     const T& lhs, const T& rhs, absl::string_view lhs_name, \
163                     absl::string_view rhs_name) const {                     \
164       if (!static_cast<bool>(lhs op rhs)) {                                 \
165         errors->addTestFailure(                                             \
166             test_name, absl::StrCat(context,                                \
167                                     "**Unexpected comparison result**\n"    \
168                                     "\n"                                    \
169                                     "Expression:\n"                         \
170                                     "  ",                                   \
171                                     lhs_name, " " #op " ", rhs_name,        \
172                                     "\n"                                    \
173                                     "\n"                                    \
174                                     "Expected: true\n"                      \
175                                     "  Actual: false"));                    \
176       } else {                                                              \
177         errors->addTestSuccess(test_name);                                  \
178       }                                                                     \
179     }                                                                       \
180                                                                             \
181     ConformanceErrors* errors;                                              \
182   };                                                                        \
183                                                                             \
184   struct ExpectNot##name {                                                  \
185     template <class T>                                                      \
186     void operator()(absl::string_view test_name, absl::string_view context, \
187                     const T& lhs, const T& rhs, absl::string_view lhs_name, \
188                     absl::string_view rhs_name) const {                     \
189       if (lhs op rhs) {                                                     \
190         errors->addTestFailure(                                             \
191             test_name, absl::StrCat(context,                                \
192                                     "**Unexpected comparison result**\n"    \
193                                     "\n"                                    \
194                                     "Expression:\n"                         \
195                                     "  ",                                   \
196                                     lhs_name, " " #op " ", rhs_name,        \
197                                     "\n"                                    \
198                                     "\n"                                    \
199                                     "Expected: false\n"                     \
200                                     "  Actual: true"));                     \
201       } else {                                                              \
202         errors->addTestSuccess(test_name);                                  \
203       }                                                                     \
204     }                                                                       \
205                                                                             \
206     ConformanceErrors* errors;                                              \
207   }
208 
209 ABSL_INTERNAL_EXPECT_OP(Eq, ==);
210 ABSL_INTERNAL_EXPECT_OP(Ne, !=);
211 ABSL_INTERNAL_EXPECT_OP(Lt, <);
212 ABSL_INTERNAL_EXPECT_OP(Le, <=);
213 ABSL_INTERNAL_EXPECT_OP(Ge, >=);
214 ABSL_INTERNAL_EXPECT_OP(Gt, >);
215 
216 #undef ABSL_INTERNAL_EXPECT_OP
217 
218 // A function object that verifies that two objects hash to the same value by
219 // way of the std::hash specialization.
220 struct ExpectSameHash {
221   template <class T>
operatorExpectSameHash222   void operator()(absl::string_view test_name, absl::string_view context,
223                   const T& lhs, const T& rhs, absl::string_view lhs_name,
224                   absl::string_view rhs_name) const {
225     if (std::hash<T>()(lhs) != std::hash<T>()(rhs)) {
226       errors->addTestFailure(
227           test_name, absl::StrCat(context,
228                                   "**Unexpected hash result**\n"
229                                   "\n"
230                                   "Expression:\n"
231                                   "  std::hash<T>()(",
232                                   lhs_name, ") == std::hash<T>()(", rhs_name,
233                                   ")\n"
234                                   "\n"
235                                   "Expected: true\n"
236                                   "  Actual: false"));
237     } else {
238       errors->addTestSuccess(test_name);
239     }
240   }
241 
242   ConformanceErrors* errors;
243 };
244 
245 // A function template that takes two objects and verifies that each comparison
246 // operator behaves in a way that is consistent with equality. It has "OneWay"
247 // in the name because the first argument will always be the left-hand operand
248 // of the corresponding comparison operator and the second argument will
249 // always be the right-hand operand. It will never switch that order.
250 // At a higher level in the test suite, the one-way form is called once for each
251 // of the two possible orders whenever lhs and rhs are not the same initializer.
252 template <class T, class Prof>
ExpectOneWayEquality(ConformanceErrors * errors,absl::string_view test_name,absl::string_view context,const T & lhs,const T & rhs,absl::string_view lhs_name,absl::string_view rhs_name)253 void ExpectOneWayEquality(ConformanceErrors* errors,
254                           absl::string_view test_name,
255                           absl::string_view context, const T& lhs, const T& rhs,
256                           absl::string_view lhs_name,
257                           absl::string_view rhs_name) {
258   If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
259       ExpectEq{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
260 
261   If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
262       ExpectNotNe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
263 
264   If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
265       ExpectNotLt{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
266 
267   If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
268       ExpectLe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
269 
270   If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
271       ExpectGe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
272 
273   If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
274       ExpectNotGt{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
275 
276   If<PropertiesOfT<Prof>::is_hashable>::Invoke(
277       ExpectSameHash{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
278 }
279 
280 // A function template that takes two objects and verifies that each comparison
281 // operator behaves in a way that is consistent with equality. This function
282 // differs from ExpectOneWayEquality in that this will do checks with argument
283 // order reversed in addition to in-order.
284 template <class T, class Prof>
ExpectEquality(ConformanceErrors * errors,absl::string_view test_name,absl::string_view context,const T & lhs,const T & rhs,absl::string_view lhs_name,absl::string_view rhs_name)285 void ExpectEquality(ConformanceErrors* errors, absl::string_view test_name,
286                     absl::string_view context, const T& lhs, const T& rhs,
287                     absl::string_view lhs_name, absl::string_view rhs_name) {
288   (ExpectOneWayEquality<T, Prof>)(errors, test_name, context, lhs, rhs,
289                                   lhs_name, rhs_name);
290   (ExpectOneWayEquality<T, Prof>)(errors, test_name, context, rhs, lhs,
291                                   rhs_name, lhs_name);
292 }
293 
294 // Given a generator, makes sure that a generated value and a moved-from
295 // generated value are equal.
296 template <class T, class Prof>
297 struct ExpectMoveConstructOneGenerator {
298   template <class Fun>
operatorExpectMoveConstructOneGenerator299   void operator()(const Fun& generator) const {
300     const T object = generator();
301     const T moved_object = absl::move(generator());  // Force no elision.
302 
303     (ExpectEquality<T, Prof>)(errors, "Move construction",
304                               PrepareGivenContext(
305                                   GivenDeclaration{"const _T object",
306                                                    generator.description},
307                                   GivenDeclaration{"const _T moved_object",
308                                                    std::string("std::move(") +
309                                                        generator.description +
310                                                        ")"}),
311                               object, moved_object, "object", "moved_object");
312   }
313 
314   ConformanceErrors* errors;
315 };
316 
317 // Given a generator, makes sure that a generated value and a copied-from
318 // generated value are equal.
319 template <class T, class Prof>
320 struct ExpectCopyConstructOneGenerator {
321   template <class Fun>
operatorExpectCopyConstructOneGenerator322   void operator()(const Fun& generator) const {
323     const T object = generator();
324     const T copied_object = static_cast<const T&>(generator());
325 
326     (ExpectEquality<T, Prof>)(errors, "Copy construction",
327                               PrepareGivenContext(
328                                   GivenDeclaration{"const _T object",
329                                                    generator.description},
330                                   GivenDeclaration{
331                                       "const _T copied_object",
332                                       std::string("static_cast<const _T&>(") +
333                                           generator.description + ")"}),
334                               object, copied_object, "object", "copied_object");
335   }
336 
337   ConformanceErrors* errors;
338 };
339 
340 // Default-construct and do nothing before destruction.
341 //
342 // This is useful in exercising the codepath of default construction followed by
343 // destruction, but does not explicitly test anything. An example of where this
344 // might fail is a default destructor that default-initializes a scalar and a
345 // destructor reads the value of that member. Sanitizers can catch this as long
346 // as our test attempts to execute such a case.
347 template <class T>
348 struct ExpectDefaultConstructWithDestruct {
operatorExpectDefaultConstructWithDestruct349   void operator()() const {
350     // Scoped so that destructor gets called before reporting success.
351     {
352       T object;
353       static_cast<void>(object);
354     }
355 
356     errors->addTestSuccess("Default construction");
357   }
358 
359   ConformanceErrors* errors;
360 };
361 
362 // Check move-assign into a default-constructed object.
363 template <class T, class Prof>
364 struct ExpectDefaultConstructWithMoveAssign {
365   template <class Fun>
operatorExpectDefaultConstructWithMoveAssign366   void operator()(const Fun& generator) const {
367     const T source_of_truth = generator();
368     T object;
369     object = generator();
370 
371     (ExpectEquality<T, Prof>)(errors, "Move assignment",
372                               PrepareGivenContext(
373                                   GivenDeclaration{"const _T object",
374                                                    generator.description},
375                                   GivenDeclaration{"_T object", ""},
376                                   GivenDeclaration{"object",
377                                                    generator.description}),
378                               object, source_of_truth, "std::as_const(object)",
379                               "source_of_truth");
380   }
381 
382   ConformanceErrors* errors;
383 };
384 
385 // Check copy-assign into a default-constructed object.
386 template <class T, class Prof>
387 struct ExpectDefaultConstructWithCopyAssign {
388   template <class Fun>
operatorExpectDefaultConstructWithCopyAssign389   void operator()(const Fun& generator) const {
390     const T source_of_truth = generator();
391     T object;
392     object = static_cast<const T&>(generator());
393 
394     (ExpectEquality<T, Prof>)(errors, "Copy assignment",
395                               PrepareGivenContext(
396                                   GivenDeclaration{"const _T source_of_truth",
397                                                    generator.description},
398                                   GivenDeclaration{"_T object", ""},
399                                   GivenDeclaration{
400                                       "object",
401                                       std::string("static_cast<const _T&>(") +
402                                           generator.description + ")"}),
403                               object, source_of_truth, "std::as_const(object)",
404                               "source_of_truth");
405   }
406 
407   ConformanceErrors* errors;
408 };
409 
410 // Perform a self move-assign.
411 template <class T, class Prof>
412 struct ExpectSelfMoveAssign {
413   template <class Fun>
operatorExpectSelfMoveAssign414   void operator()(const Fun& generator) const {
415     T object = generator();
416     object = absl::move(object);
417 
418     // NOTE: Self move-assign results in a valid-but-unspecified state.
419 
420     (ExpectEquality<T, Prof>)(errors, "Move assignment",
421                               PrepareGivenContext(
422                                   GivenDeclaration{"_T object",
423                                                    generator.description},
424                                   GivenDeclaration{"object",
425                                                    "std::move(object)"}),
426                               object, object, "object", "object");
427   }
428 
429   ConformanceErrors* errors;
430 };
431 
432 // Perform a self copy-assign.
433 template <class T, class Prof>
434 struct ExpectSelfCopyAssign {
435   template <class Fun>
operatorExpectSelfCopyAssign436   void operator()(const Fun& generator) const {
437     const T source_of_truth = generator();
438     T object = generator();
439     const T& const_object = object;
440     object = const_object;
441 
442     (ExpectEquality<T, Prof>)(errors, "Copy assignment",
443                               PrepareGivenContext(
444                                   GivenDeclaration{"const _T source_of_truth",
445                                                    generator.description},
446                                   GivenDeclaration{"_T object",
447                                                    generator.description},
448                                   GivenDeclaration{"object",
449                                                    "std::as_const(object)"}),
450                               const_object, source_of_truth,
451                               "std::as_const(object)", "source_of_truth");
452   }
453 
454   ConformanceErrors* errors;
455 };
456 
457 // Perform a self-swap.
458 template <class T, class Prof>
459 struct ExpectSelfSwap {
460   template <class Fun>
operatorExpectSelfSwap461   void operator()(const Fun& generator) const {
462     const T source_of_truth = generator();
463     T object = generator();
464 
465     type_traits_internal::Swap(object, object);
466 
467     std::string preliminary_info = absl::StrCat(
468         PrepareGivenContext(
469             GivenDeclaration{"const _T source_of_truth", generator.description},
470             GivenDeclaration{"_T object", generator.description}),
471         "After performing a self-swap:\n"
472         "  using std::swap;\n"
473         "  swap(object, object);\n"
474         "\n");
475 
476     (ExpectEquality<T, Prof>)(errors, "Swap", std::move(preliminary_info),
477                               object, source_of_truth, "std::as_const(object)",
478                               "source_of_truth");
479   }
480 
481   ConformanceErrors* errors;
482 };
483 
484 // Perform each of the single-generator checks when necessary operations are
485 // supported.
486 template <class T, class Prof>
487 struct ExpectSelfComparison {
488   template <class Fun>
operatorExpectSelfComparison489   void operator()(const Fun& generator) const {
490     const T object = generator();
491     (ExpectOneWayEquality<T, Prof>)(errors, "Comparison",
492                                     PrepareGivenContext(GivenDeclaration{
493                                         "const _T object",
494                                         generator.description}),
495                                     object, object, "object", "object");
496   }
497 
498   ConformanceErrors* errors;
499 };
500 
501 // Perform each of the single-generator checks when necessary operations are
502 // supported.
503 template <class T, class Prof>
504 struct ExpectConsistency {
505   template <class Fun>
operatorExpectConsistency506   void operator()(const Fun& generator) const {
507     If<PropertiesOfT<Prof>::is_move_constructible>::Invoke(
508         ExpectMoveConstructOneGenerator<T, Prof>{errors}, generator);
509 
510     If<PropertiesOfT<Prof>::is_copy_constructible>::Invoke(
511         ExpectCopyConstructOneGenerator<T, Prof>{errors}, generator);
512 
513     If<PropertiesOfT<Prof>::is_default_constructible &&
514        PropertiesOfT<Prof>::is_move_assignable>::
515         Invoke(ExpectDefaultConstructWithMoveAssign<T, Prof>{errors},
516                generator);
517 
518     If<PropertiesOfT<Prof>::is_default_constructible &&
519        PropertiesOfT<Prof>::is_copy_assignable>::
520         Invoke(ExpectDefaultConstructWithCopyAssign<T, Prof>{errors},
521                generator);
522 
523     If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
524         ExpectSelfMoveAssign<T, Prof>{errors}, generator);
525 
526     If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
527         ExpectSelfCopyAssign<T, Prof>{errors}, generator);
528 
529     If<PropertiesOfT<Prof>::is_swappable>::Invoke(
530         ExpectSelfSwap<T, Prof>{errors}, generator);
531   }
532 
533   ConformanceErrors* errors;
534 };
535 
536 // Check move-assign with two different values.
537 template <class T, class Prof>
538 struct ExpectMoveAssign {
539   template <class Fun0, class Fun1>
operatorExpectMoveAssign540   void operator()(const Fun0& generator0, const Fun1& generator1) const {
541     const T source_of_truth1 = generator1();
542     T object = generator0();
543     object = generator1();
544 
545     (ExpectEquality<T, Prof>)(errors, "Move assignment",
546                               PrepareGivenContext(
547                                   GivenDeclaration{"const _T source_of_truth1",
548                                                    generator1.description},
549                                   GivenDeclaration{"_T object",
550                                                    generator0.description},
551                                   GivenDeclaration{"object",
552                                                    generator1.description}),
553                               object, source_of_truth1, "std::as_const(object)",
554                               "source_of_truth1");
555   }
556 
557   ConformanceErrors* errors;
558 };
559 
560 // Check copy-assign with two different values.
561 template <class T, class Prof>
562 struct ExpectCopyAssign {
563   template <class Fun0, class Fun1>
operatorExpectCopyAssign564   void operator()(const Fun0& generator0, const Fun1& generator1) const {
565     const T source_of_truth1 = generator1();
566     T object = generator0();
567     object = static_cast<const T&>(generator1());
568 
569     (ExpectEquality<T, Prof>)(errors, "Copy assignment",
570                               PrepareGivenContext(
571                                   GivenDeclaration{"const _T source_of_truth1",
572                                                    generator1.description},
573                                   GivenDeclaration{"_T object",
574                                                    generator0.description},
575                                   GivenDeclaration{
576                                       "object",
577                                       std::string("static_cast<const _T&>(") +
578                                           generator1.description + ")"}),
579                               object, source_of_truth1, "std::as_const(object)",
580                               "source_of_truth1");
581   }
582 
583   ConformanceErrors* errors;
584 };
585 
586 // Check swap with two different values.
587 template <class T, class Prof>
588 struct ExpectSwap {
589   template <class Fun0, class Fun1>
operatorExpectSwap590   void operator()(const Fun0& generator0, const Fun1& generator1) const {
591     const T source_of_truth0 = generator0();
592     const T source_of_truth1 = generator1();
593     T object0 = generator0();
594     T object1 = generator1();
595 
596     type_traits_internal::Swap(object0, object1);
597 
598     const std::string context =
599         PrepareGivenContext(
600             GivenDeclaration{"const _T source_of_truth0",
601                              generator0.description},
602             GivenDeclaration{"const _T source_of_truth1",
603                              generator1.description},
604             GivenDeclaration{"_T object0", generator0.description},
605             GivenDeclaration{"_T object1", generator1.description}) +
606         "After performing a swap:\n"
607         "  using std::swap;\n"
608         "  swap(object0, object1);\n"
609         "\n";
610 
611     (ExpectEquality<T, Prof>)(errors, "Swap", context, object0,
612                               source_of_truth1, "std::as_const(object0)",
613                               "source_of_truth1");
614     (ExpectEquality<T, Prof>)(errors, "Swap", context, object1,
615                               source_of_truth0, "std::as_const(object1)",
616                               "source_of_truth0");
617   }
618 
619   ConformanceErrors* errors;
620 };
621 
622 // Validate that `generator0` and `generator1` produce values that are equal.
623 template <class T, class Prof>
624 struct ExpectEquivalenceClassComparison {
625   template <class Fun0, class Fun1>
operatorExpectEquivalenceClassComparison626   void operator()(const Fun0& generator0, const Fun1& generator1) const {
627     const T object0 = generator0();
628     const T object1 = generator1();
629 
630     (ExpectEquality<T, Prof>)(errors, "Comparison",
631                               PrepareGivenContext(
632                                   GivenDeclaration{"const _T object0",
633                                                    generator0.description},
634                                   GivenDeclaration{"const _T object1",
635                                                    generator1.description}),
636                               object0, object1, "object0", "object1");
637   }
638 
639   ConformanceErrors* errors;
640 };
641 
642 // Validate that all objects in the same equivalence-class have the same value.
643 template <class T, class Prof>
644 struct ExpectEquivalenceClassConsistency {
645   template <class Fun0, class Fun1>
operatorExpectEquivalenceClassConsistency646   void operator()(const Fun0& generator0, const Fun1& generator1) const {
647     If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
648         ExpectMoveAssign<T, Prof>{errors}, generator0, generator1);
649 
650     If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
651         ExpectCopyAssign<T, Prof>{errors}, generator0, generator1);
652 
653     If<PropertiesOfT<Prof>::is_swappable>::Invoke(ExpectSwap<T, Prof>{errors},
654                                                   generator0, generator1);
655   }
656 
657   ConformanceErrors* errors;
658 };
659 
660 // Given a "lesser" object and a "greater" object, perform every combination of
661 // comparison operators supported for the type, expecting consistent results.
662 template <class T, class Prof>
ExpectOrdered(ConformanceErrors * errors,absl::string_view context,const T & small,const T & big,absl::string_view small_name,absl::string_view big_name)663 void ExpectOrdered(ConformanceErrors* errors, absl::string_view context,
664                    const T& small, const T& big, absl::string_view small_name,
665                    absl::string_view big_name) {
666   const absl::string_view test_name = "Comparison";
667 
668   If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
669       ExpectNotEq{errors}, test_name, context, small, big, small_name,
670       big_name);
671   If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
672       ExpectNotEq{errors}, test_name, context, big, small, big_name,
673       small_name);
674 
675   If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
676       ExpectNe{errors}, test_name, context, small, big, small_name, big_name);
677   If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
678       ExpectNe{errors}, test_name, context, big, small, big_name, small_name);
679 
680   If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
681       ExpectLt{errors}, test_name, context, small, big, small_name, big_name);
682   If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
683       ExpectNotLt{errors}, test_name, context, big, small, big_name,
684       small_name);
685 
686   If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
687       ExpectLe{errors}, test_name, context, small, big, small_name, big_name);
688   If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
689       ExpectNotLe{errors}, test_name, context, big, small, big_name,
690       small_name);
691 
692   If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
693       ExpectNotGe{errors}, test_name, context, small, big, small_name,
694       big_name);
695   If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
696       ExpectGe{errors}, test_name, context, big, small, big_name, small_name);
697 
698   If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
699       ExpectNotGt{errors}, test_name, context, small, big, small_name,
700       big_name);
701   If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
702       ExpectGt{errors}, test_name, context, big, small, big_name, small_name);
703 }
704 
705 // For every two elements of an equivalence class, makes sure that those two
706 // elements compare equal, including checks with the same argument passed as
707 // both operands.
708 template <class T, class Prof>
709 struct ExpectEquivalenceClassComparisons {
710   template <class... Funs>
operatorExpectEquivalenceClassComparisons711   void operator()(EquivalenceClassType<Funs...> eq_class) const {
712     (ForEachTupleElement)(ExpectSelfComparison<T, Prof>{errors},
713                           eq_class.generators);
714 
715     (ForEveryTwo)(ExpectEquivalenceClassComparison<T, Prof>{errors},
716                   eq_class.generators);
717   }
718 
719   ConformanceErrors* errors;
720 };
721 
722 // For every element of an equivalence class, makes sure that the element is
723 // self-consistent (in other words, if any of move/copy/swap are defined,
724 // perform those operations and make such that results and operands still
725 // compare equal to known values whenever it is required for that operation.
726 template <class T, class Prof>
727 struct ExpectEquivalenceClass {
728   template <class... Funs>
operatorExpectEquivalenceClass729   void operator()(EquivalenceClassType<Funs...> eq_class) const {
730     (ForEachTupleElement)(ExpectConsistency<T, Prof>{errors},
731                           eq_class.generators);
732 
733     (ForEveryTwo)(ExpectEquivalenceClassConsistency<T, Prof>{errors},
734                   eq_class.generators);
735   }
736 
737   ConformanceErrors* errors;
738 };
739 
740 // Validate that the passed-in argument is a generator of a greater value than
741 // the one produced by the "small_gen" datamember with respect to all of the
742 // comparison operators that Prof requires, with both argument orders to test.
743 template <class T, class Prof, class SmallGenerator>
744 struct ExpectBiggerGeneratorThanComparisons {
745   template <class BigGenerator>
operatorExpectBiggerGeneratorThanComparisons746   void operator()(BigGenerator big_gen) const {
747     const T small = small_gen();
748     const T big = big_gen();
749 
750     (ExpectOrdered<T, Prof>)(errors,
751                              PrepareGivenContext(
752                                  GivenDeclaration{"const _T small",
753                                                   small_gen.description},
754                                  GivenDeclaration{"const _T big",
755                                                   big_gen.description}),
756                              small, big, "small", "big");
757   }
758 
759   SmallGenerator small_gen;
760   ConformanceErrors* errors;
761 };
762 
763 // Perform all of the move, copy, and swap checks on the value generated by
764 // `small_gen` and the value generated by `big_gen`.
765 template <class T, class Prof, class SmallGenerator>
766 struct ExpectBiggerGeneratorThan {
767   template <class BigGenerator>
operatorExpectBiggerGeneratorThan768   void operator()(BigGenerator big_gen) const {
769     If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
770         ExpectMoveAssign<T, Prof>{errors}, small_gen, big_gen);
771     If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
772         ExpectMoveAssign<T, Prof>{errors}, big_gen, small_gen);
773 
774     If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
775         ExpectCopyAssign<T, Prof>{errors}, small_gen, big_gen);
776     If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
777         ExpectCopyAssign<T, Prof>{errors}, big_gen, small_gen);
778 
779     If<PropertiesOfT<Prof>::is_swappable>::Invoke(ExpectSwap<T, Prof>{errors},
780                                                   small_gen, big_gen);
781   }
782 
783   SmallGenerator small_gen;
784   ConformanceErrors* errors;
785 };
786 
787 // Validate that the result of a generator is greater than the results of all
788 // generators in an equivalence class with respect to comparisons.
789 template <class T, class Prof, class SmallGenerator>
790 struct ExpectBiggerGeneratorThanEqClassesComparisons {
791   template <class BigEqClass>
operatorExpectBiggerGeneratorThanEqClassesComparisons792   void operator()(BigEqClass big_eq_class) const {
793     (ForEachTupleElement)(
794         ExpectBiggerGeneratorThanComparisons<T, Prof, SmallGenerator>{small_gen,
795                                                                       errors},
796         big_eq_class.generators);
797   }
798 
799   SmallGenerator small_gen;
800   ConformanceErrors* errors;
801 };
802 
803 // Validate that the non-comparison binary operations required by Prof are
804 // correct for the result of each generator of big_eq_class and a generator of
805 // the logically smaller value returned by small_gen.
806 template <class T, class Prof, class SmallGenerator>
807 struct ExpectBiggerGeneratorThanEqClasses {
808   template <class BigEqClass>
operatorExpectBiggerGeneratorThanEqClasses809   void operator()(BigEqClass big_eq_class) const {
810     (ForEachTupleElement)(
811         ExpectBiggerGeneratorThan<T, Prof, SmallGenerator>{small_gen, errors},
812         big_eq_class.generators);
813   }
814 
815   SmallGenerator small_gen;
816   ConformanceErrors* errors;
817 };
818 
819 // Validate that each equivalence class that is passed is logically less than
820 // the equivalence classes that comes later on in the argument list.
821 template <class T, class Prof>
822 struct ExpectOrderedEquivalenceClassesComparisons {
823   template <class... BigEqClasses>
824   struct Impl {
825     // Validate that the value produced by `small_gen` is less than all of the
826     // values generated by those of the logically larger equivalence classes.
827     template <class SmallGenerator>
operatorExpectOrderedEquivalenceClassesComparisons::Impl828     void operator()(SmallGenerator small_gen) const {
829       (ForEachTupleElement)(ExpectBiggerGeneratorThanEqClassesComparisons<
830                                 T, Prof, SmallGenerator>{small_gen, errors},
831                             big_eq_classes);
832     }
833 
834     std::tuple<BigEqClasses...> big_eq_classes;
835     ConformanceErrors* errors;
836   };
837 
838   // When given no equivalence classes, no validation is necessary.
operatorExpectOrderedEquivalenceClassesComparisons839   void operator()() const {}
840 
841   template <class SmallEqClass, class... BigEqClasses>
operatorExpectOrderedEquivalenceClassesComparisons842   void operator()(SmallEqClass small_eq_class,
843                   BigEqClasses... big_eq_classes) const {
844     // For each generator in the first equivalence class, make sure that it is
845     // less than each of those in the logically greater equivalence classes.
846     (ForEachTupleElement)(
847         Impl<BigEqClasses...>{std::make_tuple(absl::move(big_eq_classes)...),
848                               errors},
849         small_eq_class.generators);
850 
851     // Recurse so that all equivalence class combinations are checked.
852     (*this)(absl::move(big_eq_classes)...);
853   }
854 
855   ConformanceErrors* errors;
856 };
857 
858 // Validate that the non-comparison binary operations required by Prof are
859 // correct for the result of each generator of big_eq_classes and a generator of
860 // the logically smaller value returned by small_gen.
861 template <class T, class Prof>
862 struct ExpectOrderedEquivalenceClasses {
863   template <class... BigEqClasses>
864   struct Impl {
865     template <class SmallGenerator>
operatorExpectOrderedEquivalenceClasses::Impl866     void operator()(SmallGenerator small_gen) const {
867       (ForEachTupleElement)(
868           ExpectBiggerGeneratorThanEqClasses<T, Prof, SmallGenerator>{small_gen,
869                                                                       errors},
870           big_eq_classes);
871     }
872 
873     std::tuple<BigEqClasses...> big_eq_classes;
874     ConformanceErrors* errors;
875   };
876 
877   // Check that small_eq_class is logically consistent and also is logically
878   // less than all values in big_eq_classes.
879   template <class SmallEqClass, class... BigEqClasses>
operatorExpectOrderedEquivalenceClasses880   void operator()(SmallEqClass small_eq_class,
881                   BigEqClasses... big_eq_classes) const {
882     (ForEachTupleElement)(
883         Impl<BigEqClasses...>{std::make_tuple(absl::move(big_eq_classes)...),
884                               errors},
885         small_eq_class.generators);
886 
887     (*this)(absl::move(big_eq_classes)...);
888   }
889 
890   // Terminating case of operator().
operatorExpectOrderedEquivalenceClasses891   void operator()() const {}
892 
893   ConformanceErrors* errors;
894 };
895 
896 // Validate that a type meets the syntactic requirements of std::hash if the
897 // range of profiles requires it.
898 template <class T, class MinProf, class MaxProf>
899 struct ExpectHashable {
operatorExpectHashable900   void operator()() const {
901     ExpectModelOfHashable<T, MinProf, MaxProf>(errors);
902   }
903 
904   ConformanceErrors* errors;
905 };
906 
907 // Validate that the type `T` meets all of the requirements associated with
908 // `MinProf` and without going beyond the syntactic properties of `MaxProf`.
909 template <class T, class MinProf, class MaxProf>
910 struct ExpectModels {
operatorExpectModels911   void operator()(ConformanceErrors* errors) const {
912     ExpectModelOfDefaultConstructible<T, MinProf, MaxProf>(errors);
913     ExpectModelOfMoveConstructible<T, MinProf, MaxProf>(errors);
914     ExpectModelOfCopyConstructible<T, MinProf, MaxProf>(errors);
915     ExpectModelOfMoveAssignable<T, MinProf, MaxProf>(errors);
916     ExpectModelOfCopyAssignable<T, MinProf, MaxProf>(errors);
917     ExpectModelOfDestructible<T, MinProf, MaxProf>(errors);
918     ExpectModelOfEqualityComparable<T, MinProf, MaxProf>(errors);
919     ExpectModelOfInequalityComparable<T, MinProf, MaxProf>(errors);
920     ExpectModelOfLessThanComparable<T, MinProf, MaxProf>(errors);
921     ExpectModelOfLessEqualComparable<T, MinProf, MaxProf>(errors);
922     ExpectModelOfGreaterEqualComparable<T, MinProf, MaxProf>(errors);
923     ExpectModelOfGreaterThanComparable<T, MinProf, MaxProf>(errors);
924     ExpectModelOfSwappable<T, MinProf, MaxProf>(errors);
925 
926     // Only check hashability on compilers that have a compliant default-hash.
927     If<!poisoned_hash_fails_instantiation()>::Invoke(
928         ExpectHashable<T, MinProf, MaxProf>{errors});
929   }
930 };
931 
932 // A metafunction that yields a Profile matching the set of properties that are
933 // safe to be checked (lack-of-hashability is only checked on standard library
934 // implementations that are standards compliant in that they provide a std::hash
935 // primary template that is SFINAE-friendly)
936 template <class LogicalProf, class T>
937 struct MinimalCheckableProfile {
938   using type =
939       MinimalProfiles<PropertiesOfT<LogicalProf>,
940                       PropertiesOfT<SyntacticConformanceProfileOf<
941                           T, !PropertiesOfT<LogicalProf>::is_hashable &&
942                                      poisoned_hash_fails_instantiation()
943                                  ? CheckHashability::no
944                                  : CheckHashability::yes>>>;
945 };
946 
947 // An identity metafunction
948 template <class T>
949 struct Always {
950   using type = T;
951 };
952 
953 // Validate the T meets all of the necessary requirements of LogicalProf, with
954 // syntactic requirements defined by the profile range [MinProf, MaxProf].
955 template <class T, class LogicalProf, class MinProf, class MaxProf,
956           class... EqClasses>
ExpectRegularityImpl(OrderedEquivalenceClasses<EqClasses...> vals)957 ConformanceErrors ExpectRegularityImpl(
958     OrderedEquivalenceClasses<EqClasses...> vals) {
959   ConformanceErrors errors((NameOf<T>()));
960 
961   If<!constexpr_instantiation_when_unevaluated()>::Invoke(
962       ExpectModels<T, MinProf, MaxProf>(), &errors);
963 
964   using minimal_profile = typename absl::conditional_t<
965       constexpr_instantiation_when_unevaluated(), Always<LogicalProf>,
966       MinimalCheckableProfile<LogicalProf, T>>::type;
967 
968   If<PropertiesOfT<minimal_profile>::is_default_constructible>::Invoke(
969       ExpectDefaultConstructWithDestruct<T>{&errors});
970 
971   //////////////////////////////////////////////////////////////////////////////
972   // Perform all comparison checks first, since later checks depend on their
973   // correctness.
974   //
975   // Check all of the comparisons for all values in the same equivalence
976   // class (equal with respect to comparison operators and hash the same).
977   (ForEachTupleElement)(
978       ExpectEquivalenceClassComparisons<T, minimal_profile>{&errors},
979       vals.eq_classes);
980 
981   // Check all of the comparisons for each combination of values that are in
982   // different equivalence classes (not equal with respect to comparison
983   // operators).
984   absl::apply(
985       ExpectOrderedEquivalenceClassesComparisons<T, minimal_profile>{&errors},
986       vals.eq_classes);
987   //
988   //////////////////////////////////////////////////////////////////////////////
989 
990   // Perform remaining checks, relying on comparisons.
991   // TODO(calabrese) short circuit if any comparisons above failed.
992   (ForEachTupleElement)(ExpectEquivalenceClass<T, minimal_profile>{&errors},
993                         vals.eq_classes);
994 
995   absl::apply(ExpectOrderedEquivalenceClasses<T, minimal_profile>{&errors},
996               vals.eq_classes);
997 
998   return errors;
999 }
1000 
1001 // A type that represents a range of profiles that are acceptable to be matched.
1002 //
1003 // `MinProf` is the minimum set of syntactic requirements that must be met.
1004 //
1005 // `MaxProf` is the maximum set of syntactic requirements that must be met.
1006 // This maximum is particularly useful for certain "strictness" checking. Some
1007 // examples for when this is useful:
1008 //
1009 // * Making sure that a type is move-only (rather than simply movable)
1010 //
1011 // * Making sure that a member function is *not* noexcept in cases where it
1012 //   cannot be noexcept, such as if a dependent datamember has certain
1013 //   operations that are not noexcept.
1014 //
1015 // * Making sure that a type tightly matches a spec, such as the standard.
1016 //
1017 // `LogicalProf` is the Profile for which run-time testing is to take place.
1018 //
1019 // Note: The reason for `LogicalProf` is because it is often the case, when
1020 // dealing with templates, that a declaration of a given operation is specified,
1021 // but whose body would fail to instantiate. Examples include the
1022 // copy-constructor of a standard container when the element-type is move-only,
1023 // or the comparison operators of a standard container when the element-type
1024 // does not have the necessary comparison operations defined. The `LogicalProf`
1025 // parameter allows us to capture the intent of what should be tested at
1026 // run-time, even in the cases where syntactically it might otherwise appear as
1027 // though the type undergoing testing supports more than it actually does.
1028 template <class LogicalProf, class MinProf = LogicalProf,
1029           class MaxProf = MinProf>
1030 struct ProfileRange {
1031   using logical_profile = LogicalProf;
1032   using min_profile = MinProf;
1033   using max_profile = MaxProf;
1034 };
1035 
1036 // Similar to ProfileRange except that it creates a profile range that is
1037 // coupled with a Domain and is used when testing that a type matches exactly
1038 // the "minimum" requirements of LogicalProf.
1039 template <class StrictnessDomain, class LogicalProf,
1040           class MinProf = LogicalProf, class MaxProf = MinProf>
1041 struct StrictProfileRange {
1042   // We do not yet support extension.
1043   static_assert(
1044       std::is_same<StrictnessDomain, RegularityDomain>::value,
1045       "Currently, the only valid StrictnessDomain is RegularityDomain.");
1046   using strictness_domain = StrictnessDomain;
1047   using logical_profile = LogicalProf;
1048   using min_profile = MinProf;
1049   using max_profile = MaxProf;
1050 };
1051 
1052 ////////////////////////////////////////////////////////////////////////////////
1053 //
1054 // A metafunction that creates a StrictProfileRange from a Domain and either a
1055 // Profile or ProfileRange.
1056 template <class StrictnessDomain, class ProfOrRange>
1057 struct MakeStrictProfileRange;
1058 
1059 template <class StrictnessDomain, class LogicalProf>
1060 struct MakeStrictProfileRange {
1061   using type = StrictProfileRange<StrictnessDomain, LogicalProf>;
1062 };
1063 
1064 template <class StrictnessDomain, class LogicalProf, class MinProf,
1065           class MaxProf>
1066 struct MakeStrictProfileRange<StrictnessDomain,
1067                               ProfileRange<LogicalProf, MinProf, MaxProf>> {
1068   using type =
1069       StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>;
1070 };
1071 
1072 template <class StrictnessDomain, class ProfOrRange>
1073 using MakeStrictProfileRangeT =
1074     typename MakeStrictProfileRange<StrictnessDomain, ProfOrRange>::type;
1075 //
1076 ////////////////////////////////////////////////////////////////////////////////
1077 
1078 // A profile in the RegularityDomain with the strongest possible requirements.
1079 using MostStrictProfile =
1080     CombineProfiles<TriviallyCompleteProfile, NothrowComparableProfile>;
1081 
1082 // Forms a ProfileRange that treats the Profile as the bare minimum requirements
1083 // of a type.
1084 template <class LogicalProf, class MinProf = LogicalProf>
1085 using LooseProfileRange = StrictProfileRange<RegularityDomain, LogicalProf,
1086                                              MinProf, MostStrictProfile>;
1087 
1088 template <class Prof>
1089 using MakeLooseProfileRangeT = Prof;
1090 
1091 ////////////////////////////////////////////////////////////////////////////////
1092 //
1093 // The following classes implement the metafunction ProfileRangeOfT<T> that
1094 // takes either a Profile or ProfileRange and yields the ProfileRange to be
1095 // used during testing.
1096 //
1097 template <class T, class /*Enabler*/ = void>
1098 struct ProfileRangeOfImpl;
1099 
1100 template <class T>
1101 struct ProfileRangeOfImpl<T, absl::void_t<PropertiesOfT<T>>> {
1102   using type = LooseProfileRange<T>;
1103 };
1104 
1105 template <class T>
1106 struct ProfileRangeOf : ProfileRangeOfImpl<T> {};
1107 
1108 template <class StrictnessDomain, class LogicalProf, class MinProf,
1109           class MaxProf>
1110 struct ProfileRangeOf<
1111     StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>> {
1112   using type =
1113       StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>;
1114 };
1115 
1116 template <class T>
1117 using ProfileRangeOfT = typename ProfileRangeOf<T>::type;
1118 //
1119 ////////////////////////////////////////////////////////////////////////////////
1120 
1121 // Extract the logical profile of a range (what will be runtime tested).
1122 template <class T>
1123 using LogicalProfileOfT = typename ProfileRangeOfT<T>::logical_profile;
1124 
1125 // Extract the minimal syntactic profile of a range (error if not at least).
1126 template <class T>
1127 using MinProfileOfT = typename ProfileRangeOfT<T>::min_profile;
1128 
1129 // Extract the maximum syntactic profile of a range (error if more than).
1130 template <class T>
1131 using MaxProfileOfT = typename ProfileRangeOfT<T>::max_profile;
1132 
1133 ////////////////////////////////////////////////////////////////////////////////
1134 //
1135 template <class T>
1136 struct IsProfileOrProfileRange : IsProfile<T>::type {};
1137 
1138 template <class StrictnessDomain, class LogicalProf, class MinProf,
1139           class MaxProf>
1140 struct IsProfileOrProfileRange<
1141     StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>>
1142     : std::true_type {};
1143 //
1144 ////////////////////////////////////////////////////////////////////////////////
1145 
1146 // TODO(calabrese): Consider naming the functions in this class the same as
1147 // the macros (defined later on) so that auto-complete leads to the correct name
1148 // and so that a user cannot accidentally call a function rather than the macro
1149 // form.
1150 template <bool ExpectSuccess, class T, class... EqClasses>
1151 struct ExpectConformanceOf {
1152   // Add a value to be tested. Subsequent calls to this function on the same
1153   // object must specify logically "larger" values with respect to the
1154   // comparison operators of the type, if any.
1155   //
1156   // NOTE: This function should not be called directly. A stateless lambda is
1157   // implicitly formed and passed when using the INITIALIZER macro at the bottom
1158   // of this file.
1159   template <class Fun,
1160             absl::enable_if_t<std::is_same<
1161                 ResultOfGeneratorT<GeneratorType<Fun>>, T>::value>** = nullptr>
1162   ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
1163                                            EquivalenceClassType<Fun>>
1164   initializer(GeneratorType<Fun> fun) && {
1165     return {
1166         {std::tuple_cat(absl::move(ordered_vals.eq_classes),
1167                         std::make_tuple((EquivalenceClass)(absl::move(fun))))},
1168         std::move(expected_failed_tests)};
1169   }
1170 
1171   template <class... TestNames,
1172             absl::enable_if_t<!ExpectSuccess && sizeof...(EqClasses) == 0 &&
1173                               absl::conjunction<std::is_convertible<
1174                                   TestNames, absl::string_view>...>::value>** =
1175                 nullptr>
1176   ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...>
1177   due_to(TestNames&&... test_names) && {
1178     (InsertEach)(&expected_failed_tests,
1179                  absl::AsciiStrToLower(absl::string_view(test_names))...);
1180 
1181     return {absl::move(ordered_vals), std::move(expected_failed_tests)};
1182   }
1183 
1184   template <class... TestNames, int = 0,  // MSVC disambiguator
1185             absl::enable_if_t<ExpectSuccess && sizeof...(EqClasses) == 0 &&
1186                               absl::conjunction<std::is_convertible<
1187                                   TestNames, absl::string_view>...>::value>** =
1188                 nullptr>
1189   ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...>
1190   due_to(TestNames&&... test_names) && {
1191     // TODO(calabrese) Instead have DUE_TO only exist via a CRTP base.
1192     // This would produce better errors messages than the static_assert.
1193     static_assert(!ExpectSuccess,
1194                   "DUE_TO cannot be called when conformance is expected -- did "
1195                   "you mean to use ASSERT_NONCONFORMANCE_OF?");
1196   }
1197 
1198   // Add a value to be tested. Subsequent calls to this function on the same
1199   // object must specify logically "larger" values with respect to the
1200   // comparison operators of the type, if any.
1201   //
1202   // NOTE: This function should not be called directly. A stateful lambda is
1203   // implicitly formed and passed when using the INITIALIZER macro at the bottom
1204   // of this file.
1205   template <class Fun,
1206             absl::enable_if_t<std::is_same<
1207                 ResultOfGeneratorT<GeneratorType<Fun>>, T>::value>** = nullptr>
1208   ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
1209                                            EquivalenceClassType<Fun>>
1210   dont_class_directly_stateful_initializer(GeneratorType<Fun> fun) && {
1211     return {
1212         {std::tuple_cat(absl::move(ordered_vals.eq_classes),
1213                         std::make_tuple((EquivalenceClass)(absl::move(fun))))},
1214         std::move(expected_failed_tests)};
1215   }
1216 
1217   // Add a set of value to be tested, where each value is equal with respect to
1218   // the comparison operators and std::hash specialization, if defined.
1219   template <
1220       class... Funs,
1221       absl::void_t<absl::enable_if_t<std::is_same<
1222           ResultOfGeneratorT<GeneratorType<Funs>>, T>::value>...>** = nullptr>
1223   ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
1224                                            EquivalenceClassType<Funs...>>
1225   equivalence_class(GeneratorType<Funs>... funs) && {
1226     return {{std::tuple_cat(
1227                 absl::move(ordered_vals.eq_classes),
1228                 std::make_tuple((EquivalenceClass)(absl::move(funs)...)))},
1229             std::move(expected_failed_tests)};
1230   }
1231 
1232   // Execute the tests for the captured set of values, strictly matching a range
1233   // of expected profiles in a given domain.
1234   template <
1235       class ProfRange,
1236       absl::enable_if_t<IsProfileOrProfileRange<ProfRange>::value>** = nullptr>
1237   ABSL_MUST_USE_RESULT ::testing::AssertionResult with_strict_profile(
1238       ProfRange /*profile*/) {
1239     ConformanceErrors test_result =
1240         (ExpectRegularityImpl<
1241             T, LogicalProfileOfT<ProfRange>, MinProfileOfT<ProfRange>,
1242             MaxProfileOfT<ProfRange>>)(absl::move(ordered_vals));
1243 
1244     return ExpectSuccess ? test_result.assertionResult()
1245                          : test_result.expectFailedTests(expected_failed_tests);
1246   }
1247 
1248   // Execute the tests for the captured set of values, loosely matching a range
1249   // of expected profiles (loose in that an interface is allowed to be more
1250   // refined that a profile suggests, such as a type having a noexcept copy
1251   // constructor when all that is required is that the copy constructor exists).
1252   template <class Prof, absl::enable_if_t<IsProfile<Prof>::value>** = nullptr>
1253   ABSL_MUST_USE_RESULT ::testing::AssertionResult with_loose_profile(
1254       Prof /*profile*/) {
1255     ConformanceErrors test_result =
1256         (ExpectRegularityImpl<
1257             T, Prof, Prof,
1258             CombineProfiles<TriviallyCompleteProfile,
1259                             NothrowComparableProfile>>)(absl::
1260                                                             move(ordered_vals));
1261 
1262     return ExpectSuccess ? test_result.assertionResult()
1263                          : test_result.expectFailedTests(expected_failed_tests);
1264   }
1265 
1266   OrderedEquivalenceClasses<EqClasses...> ordered_vals;
1267   std::set<std::string> expected_failed_tests;
1268 };
1269 
1270 template <class T>
1271 using ExpectConformanceOfType = ExpectConformanceOf</*ExpectSuccess=*/true, T>;
1272 
1273 template <class T>
1274 using ExpectNonconformanceOfType =
1275     ExpectConformanceOf</*ExpectSuccess=*/false, T>;
1276 
1277 struct EquivalenceClassMaker {
1278   // TODO(calabrese) Constrain to callable
1279   template <class Fun>
1280   static GeneratorType<Fun> initializer(GeneratorType<Fun> fun) {
1281     return fun;
1282   }
1283 };
1284 
1285 // A top-level macro that begins the builder pattern.
1286 //
1287 // The argument here takes the datatype to be tested.
1288 #define ABSL_INTERNAL_ASSERT_CONFORMANCE_OF(...)                            \
1289   GTEST_AMBIGUOUS_ELSE_BLOCKER_                                             \
1290   if ABSL_INTERNAL_LPAREN                                                   \
1291   const ::testing::AssertionResult gtest_ar =                               \
1292       ABSL_INTERNAL_LPAREN ::absl::types_internal::ExpectConformanceOfType< \
1293           __VA_ARGS__>()
1294 
1295 // Akin to ASSERT_CONFORMANCE_OF except that it expects failure and tries to
1296 // match text.
1297 #define ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(...)                            \
1298   GTEST_AMBIGUOUS_ELSE_BLOCKER_                                                \
1299   if ABSL_INTERNAL_LPAREN                                                      \
1300   const ::testing::AssertionResult gtest_ar =                                  \
1301       ABSL_INTERNAL_LPAREN ::absl::types_internal::ExpectNonconformanceOfType< \
1302           __VA_ARGS__>()
1303 
1304 ////////////////////////////////////////////////////////////////////////////////
1305 // NOTE: The following macros look like they are recursive, but are not (macros
1306 // cannot recurse). These actually refer to member functions of the same name.
1307 // This is done intentionally so that a user cannot accidentally invoke a
1308 // member function of the conformance-testing suite without going through the
1309 // macro.
1310 ////////////////////////////////////////////////////////////////////////////////
1311 
1312 // Specify expected test failures as comma-separated strings.
1313 #define DUE_TO(...) due_to(__VA_ARGS__)
1314 
1315 // Specify a value to be tested.
1316 //
1317 // Note: Internally, this takes an expression and turns it into the return value
1318 // of lambda that captures no data. The expression is stringized during
1319 // preprocessing so that it can be used in error reports.
1320 #define INITIALIZER(...)                         \
1321   initializer(::absl::types_internal::Generator( \
1322       [] { return __VA_ARGS__; }, ABSL_INTERNAL_STRINGIZE(__VA_ARGS__)))
1323 
1324 // Specify a value to be tested.
1325 //
1326 // Note: Internally, this takes an expression and turns it into the return value
1327 // of lambda that captures data by reference. The expression is stringized
1328 // during preprocessing so that it can be used in error reports.
1329 #define STATEFUL_INITIALIZER(...)                         \
1330   stateful_initializer(::absl::types_internal::Generator( \
1331       [&] { return __VA_ARGS__; }, ABSL_INTERNAL_STRINGIZE(__VA_ARGS__)))
1332 
1333 // Used in the builder-pattern.
1334 //
1335 // Takes a series of INITIALIZER and/or STATEFUL_INITIALIZER invocations and
1336 // forwards them along to be tested, grouping them such that the testing suite
1337 // knows that they are supposed to represent the same logical value (the values
1338 // compare the same, hash the same, etc.).
1339 #define EQUIVALENCE_CLASS(...)                    \
1340   equivalence_class(ABSL_INTERNAL_TRANSFORM_ARGS( \
1341       ABSL_INTERNAL_PREPEND_EQ_MAKER, __VA_ARGS__))
1342 
1343 // An invocation of this or WITH_STRICT_PROFILE must end the builder-pattern.
1344 // It takes a Profile as its argument.
1345 //
1346 // This executes the tests and allows types that are "more referined" than the
1347 // profile specifies, but not less. For instance, if the Profile specifies
1348 // noexcept copy-constructiblity, the test will fail if the copy-constructor is
1349 // not noexcept, however, it will succeed if the copy constructor is trivial.
1350 //
1351 // This is useful for testing that a type meets some minimum set of
1352 // requirements.
1353 #define WITH_LOOSE_PROFILE(...)                                      \
1354   with_loose_profile(                                                \
1355       ::absl::types_internal::MakeLooseProfileRangeT<__VA_ARGS__>()) \
1356       ABSL_INTERNAL_RPAREN ABSL_INTERNAL_RPAREN;                     \
1357   else GTEST_FATAL_FAILURE_(gtest_ar.failure_message())  // NOLINT
1358 
1359 // An invocation of this or WITH_STRICT_PROFILE must end the builder-pattern.
1360 // It takes a Domain and a Profile as its arguments.
1361 //
1362 // This executes the tests and disallows types that differ at all from the
1363 // properties of the Profile. For instance, if the Profile specifies noexcept
1364 // copy-constructiblity, the test will fail if the copy constructor is trivial.
1365 //
1366 // This is useful for testing that a type does not do anything more than a
1367 // specification requires, such as to minimize things like Hyrum's Law, or more
1368 // commonly, to prevent a type from being "accidentally" copy-constructible in
1369 // a way that may produce incorrect results, simply because the user forget to
1370 // delete that operation.
1371 #define WITH_STRICT_PROFILE(...)                                      \
1372   with_strict_profile(                                                \
1373       ::absl::types_internal::MakeStrictProfileRangeT<__VA_ARGS__>()) \
1374       ABSL_INTERNAL_RPAREN ABSL_INTERNAL_RPAREN;                      \
1375   else GTEST_FATAL_FAILURE_(gtest_ar.failure_message())  // NOLINT
1376 
1377 // Internal macro that is used in the internals of the EDSL when forming
1378 // equivalence classes.
1379 #define ABSL_INTERNAL_PREPEND_EQ_MAKER(arg) \
1380   ::absl::types_internal::EquivalenceClassMaker().arg
1381 
1382 }  // namespace types_internal
1383 ABSL_NAMESPACE_END
1384 }  // namespace absl
1385 
1386 #endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
1387