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