blob: 2c9f9dfd8a9a4356f7bfe3f9b5d9445b41d76487 [file] [log] [blame]
Dominik Laskowskidfeded72022-11-15 16:53:53 -05001/*
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
25namespace android::test {
26namespace {
27
28// Keep in sync with example usage in header file.
29
30struct Id : ftl::Constructible<Id, std::int32_t>, ftl::Equatable<Id> {
31 using Constructible::Constructible;
32};
33
34static_assert(!std::is_default_constructible_v<Id>);
35
36struct Color : ftl::DefaultConstructible<Color, std::uint8_t>,
37 ftl::Equatable<Color>,
38 ftl::Orderable<Color> {
39 using DefaultConstructible::DefaultConstructible;
40};
41
42static_assert(Color() == Color(0u));
43static_assert(ftl::to_underlying(Color(-1)) == 255u);
44static_assert(Color(1u) < Color(2u));
45
46struct 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
53static_assert(Sequence() == Sequence(-1));
54
55struct Timeout : ftl::DefaultConstructible<Timeout, std::chrono::seconds, 10>,
56 ftl::Equatable<Timeout>,
57 ftl::Addable<Timeout> {
58 using DefaultConstructible::DefaultConstructible;
59};
60
61using namespace std::chrono_literals;
62static_assert(Timeout() + Timeout(5s) == Timeout(15s));
63
64// Construction.
65constexpr Id kId{1234};
66constexpr Sequence kSequence;
67
68// Underlying value.
69static_assert(ftl::to_underlying(Id(-42)) == -42);
70static_assert(ftl::to_underlying(kSequence) == -1);
71
72// Casting.
73static_assert(static_cast<std::int32_t>(Id(-1)) == -1);
74static_assert(static_cast<std::int8_t>(kSequence) == -1);
75
76static_assert(!std::is_convertible_v<std::int32_t, Id>);
77static_assert(!std::is_convertible_v<Id, std::int32_t>);
78
79// Equality.
80static_assert(kId == Id(1234));
81static_assert(kId != Id(123));
82static_assert(kSequence == Sequence(-1));
83
84// Ordering.
85static_assert(Sequence(1) < Sequence(2));
86static_assert(Sequence(2) > Sequence(1));
87static_assert(Sequence(3) <= Sequence(4));
88static_assert(Sequence(4) >= Sequence(3));
89static_assert(Sequence(5) <= Sequence(5));
90static_assert(Sequence(6) >= Sequence(6));
91
92// Incrementing.
93template <typename Op, typename T, typename... Ts>
94constexpr 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
99static_assert(mutable_op([](auto& lhs) { return ++lhs; }, Sequence()) ==
100 std::make_pair(Sequence(0), Sequence(0)));
101
102static_assert(mutable_op([](auto& lhs) { return lhs++; }, Sequence()) ==
103 std::make_pair(Sequence(0), Sequence(-1)));
104
105// Addition.
106
107// `Addable` implies `Incrementable`.
108static_assert(mutable_op([](auto& lhs) { return ++lhs; }, Timeout()) ==
109 std::make_pair(Timeout(11s), Timeout(11s)));
110
111static_assert(mutable_op([](auto& lhs) { return lhs++; }, Timeout()) ==
112 std::make_pair(Timeout(11s), Timeout(10s)));
113
114static_assert(Timeout(5s) + Timeout(6s) == Timeout(11s));
115
116static_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
121namespace traits {
122
123template <typename, typename = void>
124struct is_incrementable : std::false_type {};
125
126template <typename T>
127struct is_incrementable<T, std::void_t<decltype(++std::declval<T&>())>> : std::true_type {};
128
129template <typename T>
130constexpr bool is_incrementable_v = is_incrementable<T>{};
131
132template <typename, typename, typename, typename = void>
133struct has_binary_op : std::false_type {};
134
135template <typename Op, typename T, typename U>
136struct has_binary_op<Op, T, U, std::void_t<decltype(Op{}(std::declval<T&>(), std::declval<U&>()))>>
137 : std::true_type {};
138
139template <typename T, typename U>
140constexpr 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
143template <typename T, typename U>
144constexpr 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
148template <typename T, typename U>
149constexpr bool is_addable_v = has_binary_op<std::plus<void>, T, U>{};
150
151} // namespace traits
152
153struct Real : ftl::Constructible<Real, float> {
154 using Constructible::Constructible;
155};
156
157static_assert(traits::is_equatable_v<Id, Id>);
158static_assert(!traits::is_equatable_v<Real, Real>);
159static_assert(!traits::is_equatable_v<Id, Color>);
160static_assert(!traits::is_equatable_v<Sequence, Id>);
161static_assert(!traits::is_equatable_v<Id, std::int32_t>);
162static_assert(!traits::is_equatable_v<std::chrono::seconds, Timeout>);
163
164static_assert(traits::is_orderable_v<Color, Color>);
165static_assert(!traits::is_orderable_v<Id, Id>);
166static_assert(!traits::is_orderable_v<Real, Real>);
167static_assert(!traits::is_orderable_v<Color, Sequence>);
168static_assert(!traits::is_orderable_v<Color, std::uint8_t>);
169static_assert(!traits::is_orderable_v<std::chrono::seconds, Timeout>);
170
171static_assert(traits::is_incrementable_v<Sequence>);
172static_assert(traits::is_incrementable_v<Timeout>);
173static_assert(!traits::is_incrementable_v<Id>);
174static_assert(!traits::is_incrementable_v<Color>);
175static_assert(!traits::is_incrementable_v<Real>);
176
177static_assert(traits::is_addable_v<Timeout, Timeout>);
178static_assert(!traits::is_addable_v<Id, Id>);
179static_assert(!traits::is_addable_v<Real, Real>);
180static_assert(!traits::is_addable_v<Sequence, Sequence>);
181static_assert(!traits::is_addable_v<Timeout, Sequence>);
182static_assert(!traits::is_addable_v<Color, Timeout>);
183
184} // namespace
185} // namespace android::test