1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <ftl/mixins.h>
18 #include <gtest/gtest.h>
19
20 #include <chrono>
21 #include <functional>
22 #include <type_traits>
23 #include <utility>
24
25 namespace android::test {
26 namespace {
27
28 // Keep in sync with example usage in header file.
29
30 struct Id : ftl::Constructible<Id, std::int32_t>, ftl::Equatable<Id> {
31 using Constructible::Constructible;
32 };
33
34 static_assert(!std::is_default_constructible_v<Id>);
35
36 struct Color : ftl::DefaultConstructible<Color, std::uint8_t>,
37 ftl::Equatable<Color>,
38 ftl::Orderable<Color> {
39 using DefaultConstructible::DefaultConstructible;
40 };
41
42 static_assert(Color() == Color(0u));
43 static_assert(ftl::to_underlying(Color(-1)) == 255u);
44 static_assert(Color(1u) < Color(2u));
45
46 struct Sequence : ftl::DefaultConstructible<Sequence, std::int8_t, -1>,
47 ftl::Equatable<Sequence>,
48 ftl::Orderable<Sequence>,
49 ftl::Incrementable<Sequence> {
50 using DefaultConstructible::DefaultConstructible;
51 };
52
53 static_assert(Sequence() == Sequence(-1));
54
55 struct Timeout : ftl::DefaultConstructible<Timeout, std::chrono::seconds, 10>,
56 ftl::Equatable<Timeout>,
57 ftl::Addable<Timeout> {
58 using DefaultConstructible::DefaultConstructible;
59 };
60
61 using namespace std::chrono_literals;
62 static_assert(Timeout() + Timeout(5s) == Timeout(15s));
63
64 // Construction.
65 constexpr Id kId{1234};
66 constexpr Sequence kSequence;
67
68 // Underlying value.
69 static_assert(ftl::to_underlying(Id(-42)) == -42);
70 static_assert(ftl::to_underlying(kSequence) == -1);
71
72 // Casting.
73 static_assert(static_cast<std::int32_t>(Id(-1)) == -1);
74 static_assert(static_cast<std::int8_t>(kSequence) == -1);
75
76 static_assert(!std::is_convertible_v<std::int32_t, Id>);
77 static_assert(!std::is_convertible_v<Id, std::int32_t>);
78
79 // Equality.
80 static_assert(kId == Id(1234));
81 static_assert(kId != Id(123));
82 static_assert(kSequence == Sequence(-1));
83
84 // Ordering.
85 static_assert(Sequence(1) < Sequence(2));
86 static_assert(Sequence(2) > Sequence(1));
87 static_assert(Sequence(3) <= Sequence(4));
88 static_assert(Sequence(4) >= Sequence(3));
89 static_assert(Sequence(5) <= Sequence(5));
90 static_assert(Sequence(6) >= Sequence(6));
91
92 // Incrementing.
93 template <typename Op, typename T, typename... Ts>
mutable_op(Op op,T lhs,Ts...rhs)94 constexpr auto mutable_op(Op op, T lhs, Ts... rhs) {
95 const T result = op(lhs, rhs...);
96 return std::make_pair(lhs, result);
97 }
98
__anon4f5555200202(auto& lhs) 99 static_assert(mutable_op([](auto& lhs) { return ++lhs; }, Sequence()) ==
100 std::make_pair(Sequence(0), Sequence(0)));
101
__anon4f5555200302(auto& lhs) 102 static_assert(mutable_op([](auto& lhs) { return lhs++; }, Sequence()) ==
103 std::make_pair(Sequence(0), Sequence(-1)));
104
105 // Addition.
106
107 // `Addable` implies `Incrementable`.
__anon4f5555200402(auto& lhs) 108 static_assert(mutable_op([](auto& lhs) { return ++lhs; }, Timeout()) ==
109 std::make_pair(Timeout(11s), Timeout(11s)));
110
__anon4f5555200502(auto& lhs) 111 static_assert(mutable_op([](auto& lhs) { return lhs++; }, Timeout()) ==
112 std::make_pair(Timeout(11s), Timeout(10s)));
113
114 static_assert(Timeout(5s) + Timeout(6s) == Timeout(11s));
115
__anon4f5555200602(auto& lhs, const auto& rhs) 116 static_assert(mutable_op([](auto& lhs, const auto& rhs) { return lhs += rhs; }, Timeout(7s),
117 Timeout(8s)) == std::make_pair(Timeout(15s), Timeout(15s)));
118
119 // Type safety.
120
121 namespace traits {
122
123 template <typename, typename = void>
124 struct is_incrementable : std::false_type {};
125
126 template <typename T>
127 struct is_incrementable<T, std::void_t<decltype(++std::declval<T&>())>> : std::true_type {};
128
129 template <typename T>
130 constexpr bool is_incrementable_v = is_incrementable<T>{};
131
132 template <typename, typename, typename, typename = void>
133 struct has_binary_op : std::false_type {};
134
135 template <typename Op, typename T, typename U>
136 struct has_binary_op<Op, T, U, std::void_t<decltype(Op{}(std::declval<T&>(), std::declval<U&>()))>>
137 : std::true_type {};
138
139 template <typename T, typename U>
140 constexpr bool is_equatable_v =
141 has_binary_op<std::equal_to<void>, T, U>{} && has_binary_op<std::not_equal_to<void>, T, U>{};
142
143 template <typename T, typename U>
144 constexpr bool is_orderable_v =
145 has_binary_op<std::less<void>, T, U>{} && has_binary_op<std::less_equal<void>, T, U>{} &&
146 has_binary_op<std::greater<void>, T, U>{} && has_binary_op<std::greater_equal<void>, T, U>{};
147
148 template <typename T, typename U>
149 constexpr bool is_addable_v = has_binary_op<std::plus<void>, T, U>{};
150
151 } // namespace traits
152
153 struct Real : ftl::Constructible<Real, float> {
154 using Constructible::Constructible;
155 };
156
157 static_assert(traits::is_equatable_v<Id, Id>);
158 static_assert(!traits::is_equatable_v<Real, Real>);
159 static_assert(!traits::is_equatable_v<Id, Color>);
160 static_assert(!traits::is_equatable_v<Sequence, Id>);
161 static_assert(!traits::is_equatable_v<Id, std::int32_t>);
162 static_assert(!traits::is_equatable_v<std::chrono::seconds, Timeout>);
163
164 static_assert(traits::is_orderable_v<Color, Color>);
165 static_assert(!traits::is_orderable_v<Id, Id>);
166 static_assert(!traits::is_orderable_v<Real, Real>);
167 static_assert(!traits::is_orderable_v<Color, Sequence>);
168 static_assert(!traits::is_orderable_v<Color, std::uint8_t>);
169 static_assert(!traits::is_orderable_v<std::chrono::seconds, Timeout>);
170
171 static_assert(traits::is_incrementable_v<Sequence>);
172 static_assert(traits::is_incrementable_v<Timeout>);
173 static_assert(!traits::is_incrementable_v<Id>);
174 static_assert(!traits::is_incrementable_v<Color>);
175 static_assert(!traits::is_incrementable_v<Real>);
176
177 static_assert(traits::is_addable_v<Timeout, Timeout>);
178 static_assert(!traits::is_addable_v<Id, Id>);
179 static_assert(!traits::is_addable_v<Real, Real>);
180 static_assert(!traits::is_addable_v<Sequence, Sequence>);
181 static_assert(!traits::is_addable_v<Timeout, Sequence>);
182 static_assert(!traits::is_addable_v<Color, Timeout>);
183
184 } // namespace
185 } // namespace android::test
186