1 // Copyright 2021 gRPC 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 // http://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 #include "src/core/lib/gprpp/table.h"
16
17 #include <string>
18 #include <tuple>
19 #include <variant>
20
21 #include "absl/types/optional.h"
22 #include "gtest/gtest.h"
23
24 namespace grpc_core {
25 namespace testing {
26
TEST(Table,InstantiateEmpty)27 TEST(Table, InstantiateEmpty) { Table<>(); }
28
TEST(Table,NoOp)29 TEST(Table, NoOp) {
30 Table<int, double, std::string> t;
31 EXPECT_EQ(t.get<int>(), nullptr);
32 EXPECT_EQ(t.get<double>(), nullptr);
33 EXPECT_EQ(t.get<std::string>(), nullptr);
34 EXPECT_EQ(t.get<0>(), nullptr);
35 EXPECT_EQ(t.get<1>(), nullptr);
36 EXPECT_EQ(t.get<2>(), nullptr);
37 }
38
TEST(Table,SetTheThings)39 TEST(Table, SetTheThings) {
40 Table<int, double, std::string> t;
41 t.set<int>(3);
42 t.set<double>(2.9);
43 t.set<std::string>("Hello world!");
44 EXPECT_EQ(*t.get<int>(), 3);
45 EXPECT_EQ(*t.get<double>(), 2.9);
46 EXPECT_EQ(*t.get<std::string>(), "Hello world!");
47 EXPECT_EQ(*t.get<0>(), 3);
48 EXPECT_EQ(*t.get<1>(), 2.9);
49 EXPECT_EQ(*t.get<2>(), "Hello world!");
50 }
51
TEST(Table,GetDefault)52 TEST(Table, GetDefault) {
53 Table<int, double, std::string> t;
54 EXPECT_EQ(*t.get_or_create<std::string>(), "");
55 EXPECT_EQ(*t.get_or_create<double>(), 0.0);
56 EXPECT_EQ(*t.get_or_create<int>(), 0);
57 }
58
TEST(Table,GetDefaultIndexed)59 TEST(Table, GetDefaultIndexed) {
60 Table<int, double, std::string> t;
61 EXPECT_EQ(*t.get_or_create<2>(), "");
62 EXPECT_EQ(*t.get_or_create<1>(), 0.0);
63 EXPECT_EQ(*t.get_or_create<0>(), 0);
64 }
65
TEST(Table,Copy)66 TEST(Table, Copy) {
67 Table<int, std::string> t;
68 t.set<std::string>("abcdefghijklmnopqrstuvwxyz");
69 EXPECT_EQ(*t.get<std::string>(), "abcdefghijklmnopqrstuvwxyz");
70 EXPECT_EQ(t.get<int>(), nullptr);
71 Table<int, std::string> u(t);
72 EXPECT_EQ(*u.get<std::string>(), "abcdefghijklmnopqrstuvwxyz");
73 EXPECT_EQ(*t.get<std::string>(), "abcdefghijklmnopqrstuvwxyz");
74 EXPECT_EQ(t.get<int>(), nullptr);
75 EXPECT_EQ(u.get<int>(), nullptr);
76 u.set<std::string>("hello");
77 EXPECT_EQ(*u.get<1>(), "hello");
78 EXPECT_EQ(*t.get<1>(), "abcdefghijklmnopqrstuvwxyz");
79 t = u;
80 EXPECT_EQ(*u.get<std::string>(), "hello");
81 EXPECT_EQ(*t.get<std::string>(), "hello");
82 }
83
TEST(Table,Move)84 TEST(Table, Move) {
85 Table<int, std::string> t;
86 t.set<std::string>("abcdefghijklmnopqrstuvwxyz");
87 EXPECT_EQ(*t.get<std::string>(), "abcdefghijklmnopqrstuvwxyz");
88 EXPECT_EQ(t.get<int>(), nullptr);
89 Table<int, std::string> u(std::move(t));
90 EXPECT_NE(t.get<std::string>(), nullptr); // NOLINT(bugprone-use-after-move)
91 EXPECT_EQ(*u.get<std::string>(), "abcdefghijklmnopqrstuvwxyz");
92 EXPECT_EQ(t.get<int>(), nullptr);
93 EXPECT_EQ(u.get<int>(), nullptr);
94 u.set<std::string>("hello");
95 EXPECT_EQ(*u.get<1>(), "hello");
96 t = std::move(u);
97 EXPECT_NE(u.get<std::string>(), nullptr); // NOLINT(bugprone-use-after-move)
98 EXPECT_EQ(*t.get<std::string>(), "hello");
99 }
100
TEST(Table,SameTypes)101 TEST(Table, SameTypes) {
102 Table<std::string, std::string, std::string> t;
103 // The following lines should not compile:
104 // t.get<std::string>();
105 // t.has<4>();
106 // t.get<4>();
107 // t.clear<4>();
108 EXPECT_EQ(t.get<0>(), nullptr);
109 EXPECT_EQ(t.get<1>(), nullptr);
110 EXPECT_EQ(t.get<2>(), nullptr);
111 t.set<1>("Hello!");
112 EXPECT_EQ(t.get<0>(), nullptr);
113 EXPECT_EQ(*t.get<1>(), "Hello!");
114 EXPECT_EQ(t.get<2>(), nullptr);
115 }
116
TEST(Table,ForEach)117 TEST(Table, ForEach) {
118 Table<int, int, int> t;
119 t.set<0>(1);
120 t.set<1>(2);
121 t.set<2>(3);
122 int i = 1;
123 t.ForEach([&i](int x) {
124 EXPECT_EQ(x, i);
125 i++;
126 });
127 }
128
129 #if !defined(_MSC_VER)
130 // Test suite proving this is memory efficient compared to
131 // tuple<optional<Ts>...>
132 // TODO(ctiller): determine why this test doesn't compile under MSVC.
133 // For now whether it passes or not in that one environment is probably
134 // immaterial.
135
136 template <typename T>
137 struct TableSizeTest : public ::testing::Test {};
138
139 using SizeTests = ::testing::Types<
140 std::tuple<char>, std::tuple<char, char>, std::tuple<char, char, char>,
141 std::tuple<int>, std::tuple<std::string>,
142 std::tuple<int, int, int, int, int, int, int, int, int, int>>;
143
144 TYPED_TEST_SUITE(TableSizeTest, SizeTests);
145
146 template <typename... Ts>
sizeof_tuple_of_optionals(std::tuple<Ts...> *)147 int sizeof_tuple_of_optionals(std::tuple<Ts...>*) {
148 return sizeof(std::tuple<absl::optional<Ts>...>);
149 }
150
151 template <typename... Ts>
sizeof_table(std::tuple<Ts...> *)152 int sizeof_table(std::tuple<Ts...>*) {
153 return sizeof(Table<Ts...>);
154 }
155
TYPED_TEST(TableSizeTest,SmallerThanTupleOfOptionals)156 TYPED_TEST(TableSizeTest, SmallerThanTupleOfOptionals) {
157 EXPECT_GE(sizeof_tuple_of_optionals(static_cast<TypeParam*>(nullptr)),
158 sizeof_table(static_cast<TypeParam*>(nullptr)));
159 }
160 #endif
161
162 } // namespace testing
163 } // namespace grpc_core
164
main(int argc,char ** argv)165 int main(int argc, char** argv) {
166 ::testing::InitGoogleTest(&argc, argv);
167 return RUN_ALL_TESTS();
168 }
169