Skip to content

Commit f51e8d3

Browse files
committed
add some unit tests
1 parent dd166d3 commit f51e8d3

File tree

5 files changed

+276
-5
lines changed

5 files changed

+276
-5
lines changed

src/iceberg/type.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ std::string MapType::ToString() const {
216216
std::string repr = "map<";
217217

218218
std::format_to(std::back_inserter(repr), "{}: {}", key(), value());
219-
repr += "}";
219+
repr += ">";
220220
return repr;
221221
}
222222
std::span<const SchemaField> MapType::fields() const { return fields_; }

src/iceberg/type.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,4 @@ class ICEBERG_EXPORT StructType : public NestedType {
408408

409409
/// @}
410410

411-
// TODO: need to specialize std::format (ideally via a trait?)
412-
413411
} // namespace iceberg

src/iceberg/type_fwd.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,29 @@ enum class TimeUnit {
5757
kMicrosecond,
5858
};
5959

60+
class BinaryType;
6061
class BooleanType;
61-
class SchemaField;
62+
class DateType;
63+
class DecimalType;
64+
class FixedType;
65+
class Float32Type;
66+
class Float64Type;
67+
class Int32Type;
68+
class Int64Type;
69+
class ListType;
70+
class MapType;
6271
class NestedType;
6372
class PrimitiveType;
6473
class Schema;
74+
class SchemaField;
75+
class StringType;
76+
class StructType;
6577
class StructType;
78+
class TimeType;
79+
class TimestampBase;
80+
class TimestampType;
81+
class TimestampTzType;
6682
class Type;
83+
class UuidType;
6784

6885
} // namespace iceberg

test/core/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# under the License.
1717

1818
add_executable(core_unittest)
19-
target_sources(core_unittest PRIVATE core_unittest.cc)
19+
target_sources(core_unittest PRIVATE core_unittest.cc type_test.cc)
2020
target_link_libraries(core_unittest PRIVATE iceberg_static GTest::gtest_main)
2121
target_include_directories(core_unittest PRIVATE "${ICEBERG_INCLUDES}")
2222
add_test(NAME core_unittest COMMAND core_unittest)

test/core/type_test.cc

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/type.h"
21+
22+
#include <format>
23+
#include <memory>
24+
#include <string>
25+
26+
#include <gtest/gtest.h>
27+
28+
#include "gtest/gtest.h"
29+
#include "iceberg/util/formatter.h"
30+
31+
struct TypeTestCase {
32+
/// Test case name, must be safe for Googletest (alphanumeric + underscore)
33+
std::string name;
34+
std::shared_ptr<iceberg::Type> type;
35+
iceberg::TypeId type_id;
36+
bool primitive;
37+
std::string repr;
38+
};
39+
40+
std::string TypeTestCaseToString(const ::testing::TestParamInfo<TypeTestCase>& info) {
41+
return info.param.name;
42+
}
43+
44+
class TypeTest : public ::testing::TestWithParam<TypeTestCase> {};
45+
46+
TEST_P(TypeTest, TypeId) {
47+
const auto& test_case = GetParam();
48+
ASSERT_EQ(test_case.type_id, test_case.type->type_id());
49+
}
50+
51+
TEST_P(TypeTest, IsPrimitive) {
52+
const auto& test_case = GetParam();
53+
if (test_case.primitive) {
54+
ASSERT_TRUE(test_case.type->is_primitive());
55+
ASSERT_FALSE(test_case.type->is_nested());
56+
57+
const auto* primitive =
58+
dynamic_cast<const iceberg::PrimitiveType*>(test_case.type.get());
59+
ASSERT_NE(nullptr, primitive);
60+
}
61+
}
62+
63+
TEST_P(TypeTest, IsNested) {
64+
const auto& test_case = GetParam();
65+
if (!test_case.primitive) {
66+
ASSERT_FALSE(test_case.type->is_primitive());
67+
ASSERT_TRUE(test_case.type->is_nested());
68+
69+
const auto* nested = dynamic_cast<const iceberg::NestedType*>(test_case.type.get());
70+
ASSERT_NE(nullptr, nested);
71+
}
72+
}
73+
74+
TEST_P(TypeTest, ReflexiveEquality) {
75+
const auto& test_case = GetParam();
76+
ASSERT_EQ(*test_case.type, *test_case.type);
77+
}
78+
79+
TEST_P(TypeTest, ToString) {
80+
const auto& test_case = GetParam();
81+
ASSERT_EQ(test_case.repr, test_case.type->ToString());
82+
}
83+
84+
TEST_P(TypeTest, StdFormat) {
85+
const auto& test_case = GetParam();
86+
ASSERT_EQ(test_case.repr, std::format("{}", *test_case.type));
87+
}
88+
89+
const static TypeTestCase kPrimitiveTypes[] = {
90+
{
91+
.name = "boolean",
92+
.type = std::make_shared<iceberg::BooleanType>(),
93+
.type_id = iceberg::TypeId::kBoolean,
94+
.primitive = true,
95+
.repr = "boolean",
96+
},
97+
{
98+
.name = "int32",
99+
.type = std::make_shared<iceberg::Int32Type>(),
100+
.type_id = iceberg::TypeId::kInt32,
101+
.primitive = true,
102+
.repr = "int32",
103+
},
104+
{
105+
.name = "int64",
106+
.type = std::make_shared<iceberg::Int64Type>(),
107+
.type_id = iceberg::TypeId::kInt64,
108+
.primitive = true,
109+
.repr = "int64",
110+
},
111+
{
112+
.name = "float32",
113+
.type = std::make_shared<iceberg::Float32Type>(),
114+
.type_id = iceberg::TypeId::kFloat32,
115+
.primitive = true,
116+
.repr = "float32",
117+
},
118+
{
119+
.name = "float64",
120+
.type = std::make_shared<iceberg::Float64Type>(),
121+
.type_id = iceberg::TypeId::kFloat64,
122+
.primitive = true,
123+
.repr = "float64",
124+
},
125+
{
126+
.name = "decimal9_2",
127+
.type = std::make_shared<iceberg::DecimalType>(9, 2),
128+
.type_id = iceberg::TypeId::kDecimal,
129+
.primitive = true,
130+
.repr = "decimal(9, 2)",
131+
},
132+
{
133+
.name = "decimal38_10",
134+
.type = std::make_shared<iceberg::DecimalType>(38, 10),
135+
.type_id = iceberg::TypeId::kDecimal,
136+
.primitive = true,
137+
.repr = "decimal(38, 10)",
138+
},
139+
{
140+
.name = "date",
141+
.type = std::make_shared<iceberg::DateType>(),
142+
.type_id = iceberg::TypeId::kDate,
143+
.primitive = true,
144+
.repr = "date",
145+
},
146+
{
147+
.name = "time",
148+
.type = std::make_shared<iceberg::TimeType>(),
149+
.type_id = iceberg::TypeId::kTime,
150+
.primitive = true,
151+
.repr = "time",
152+
},
153+
{
154+
.name = "timestamp",
155+
.type = std::make_shared<iceberg::TimestampType>(),
156+
.type_id = iceberg::TypeId::kTimestamp,
157+
.primitive = true,
158+
.repr = "timestamp",
159+
},
160+
{
161+
.name = "timestamptz",
162+
.type = std::make_shared<iceberg::TimestampTzType>(),
163+
.type_id = iceberg::TypeId::kTimestampTz,
164+
.primitive = true,
165+
.repr = "timestamptz",
166+
},
167+
{
168+
.name = "binary",
169+
.type = std::make_shared<iceberg::BinaryType>(),
170+
.type_id = iceberg::TypeId::kBinary,
171+
.primitive = true,
172+
.repr = "binary",
173+
},
174+
{
175+
.name = "string",
176+
.type = std::make_shared<iceberg::StringType>(),
177+
.type_id = iceberg::TypeId::kString,
178+
.primitive = true,
179+
.repr = "string",
180+
},
181+
{
182+
.name = "fixed10",
183+
.type = std::make_shared<iceberg::FixedType>(10),
184+
.type_id = iceberg::TypeId::kFixed,
185+
.primitive = true,
186+
.repr = "fixed(10)",
187+
},
188+
{
189+
.name = "fixed255",
190+
.type = std::make_shared<iceberg::FixedType>(255),
191+
.type_id = iceberg::TypeId::kFixed,
192+
.primitive = true,
193+
.repr = "fixed(255)",
194+
},
195+
{
196+
.name = "uuid",
197+
.type = std::make_shared<iceberg::UuidType>(),
198+
.type_id = iceberg::TypeId::kUuid,
199+
.primitive = true,
200+
.repr = "uuid",
201+
},
202+
};
203+
204+
const static TypeTestCase kNestedTypes[] = {
205+
{
206+
.name = "list_int",
207+
.type = std::make_shared<iceberg::ListType>(
208+
1, std::make_shared<iceberg::Int32Type>(), true),
209+
.type_id = iceberg::TypeId::kList,
210+
.primitive = false,
211+
.repr = "list<element (1): int32>",
212+
},
213+
{
214+
.name = "list_list_int",
215+
.type = std::make_shared<iceberg::ListType>(
216+
1,
217+
std::make_shared<iceberg::ListType>(2, std::make_shared<iceberg::Int32Type>(),
218+
true),
219+
false),
220+
.type_id = iceberg::TypeId::kList,
221+
.primitive = false,
222+
.repr = "list<element (1): list<element (2): int32> (required)>",
223+
},
224+
{
225+
.name = "map_int_string",
226+
.type = std::make_shared<iceberg::MapType>(
227+
iceberg::SchemaField::MakeRequired(1, "key",
228+
std::make_shared<iceberg::Int64Type>()),
229+
iceberg::SchemaField::MakeRequired(2, "value",
230+
std::make_shared<iceberg::StringType>())),
231+
.type_id = iceberg::TypeId::kMap,
232+
.primitive = false,
233+
.repr = "map<key (1): int64 (required): value (2): string (required)>",
234+
},
235+
{
236+
.name = "struct",
237+
.type = std::make_shared<iceberg::StructType>(std::vector<iceberg::SchemaField>{
238+
iceberg::SchemaField::MakeRequired(1, "foo",
239+
std::make_shared<iceberg::Int64Type>()),
240+
iceberg::SchemaField::MakeOptional(2, "bar",
241+
std::make_shared<iceberg::StringType>()),
242+
}),
243+
.type_id = iceberg::TypeId::kStruct,
244+
.primitive = false,
245+
.repr = R"(struct<
246+
foo (1): int64 (required)
247+
bar (2): string
248+
>)",
249+
},
250+
};
251+
252+
INSTANTIATE_TEST_SUITE_P(Primitive, TypeTest, ::testing::ValuesIn(kPrimitiveTypes),
253+
TypeTestCaseToString);
254+
255+
INSTANTIATE_TEST_SUITE_P(Nested, TypeTest, ::testing::ValuesIn(kNestedTypes),
256+
TypeTestCaseToString);

0 commit comments

Comments
 (0)