Skip to content

Commit

Permalink
Merge pull request #179 from Enmk/test_refactoring
Browse files Browse the repository at this point in the history
Test refactoring
  • Loading branch information
Enmk authored May 16, 2022
2 parents e4cc9a1 + fa9a93a commit 68094f3
Show file tree
Hide file tree
Showing 14 changed files with 946 additions and 475 deletions.
2 changes: 1 addition & 1 deletion clickhouse/columns/date.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ ColumnRef ColumnDateTime::Slice(size_t begin, size_t len) const {
}

ColumnRef ColumnDateTime::CloneEmpty() const {
return std::make_shared<ColumnDate>();
return std::make_shared<ColumnDateTime>();
}

void ColumnDateTime::Swap(Column& other) {
Expand Down
9 changes: 7 additions & 2 deletions ut/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@ SET ( clickhouse-cpp-ut-src

performance_tests.cpp
tcp_server.cpp
utils.cpp
readonly_client_test.cpp
connection_failed_client_test.cpp
array_of_low_cardinality_tests.cpp)
array_of_low_cardinality_tests.cpp
CreateColumnByType_ut.cpp
Column_ut.cpp

utils.cpp
value_generators.cpp
)

IF (WITH_OPENSSL)
LIST (APPEND clickhouse-cpp-ut-src ssl_ut.cpp)
Expand Down
213 changes: 213 additions & 0 deletions ut/Column_ut.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#include <clickhouse/columns/array.h>
#include <clickhouse/columns/tuple.h>
#include <clickhouse/columns/date.h>
#include <clickhouse/columns/enum.h>
#include <clickhouse/columns/lowcardinality.h>
#include <clickhouse/columns/nullable.h>
#include <clickhouse/columns/numeric.h>
#include <clickhouse/columns/string.h>
#include <clickhouse/columns/uuid.h>
#include <clickhouse/columns/ip4.h>
#include <clickhouse/columns/ip6.h>
#include <clickhouse/base/input.h>
#include <clickhouse/base/output.h>
#include <clickhouse/base/socket.h> // for ipv4-ipv6 platform-specific stuff

#include <gtest/gtest.h>

#include "utils.h"
#include "value_generators.h"

namespace {
using namespace clickhouse;
}


// Generic tests for a Column subclass against basic API:
// 1. Constructor: Create, ensure that it is empty
// 2. Append: Create, add some data one by one via Append, make sure that values inserted match extracted with At() and operator[]
// 3. Slice: Create, add some data via Append, do Slice()
// 4. CloneEmpty Create, invoke CloneEmplty, ensure that clone is Empty
// 5. Clear: Create, add some data, invoke Clear(), make sure column is empty
// 6. Swap: create two instances, populate one with data, swap with second, make sure has data was transferred
// 7. Load/Save: create, append some data, save to buffer, load from same buffer into new column, make sure columns match.

template <typename T>
class GenericColumnTest : public testing::Test {
public:
using ColumnType = std::decay_t<T>;

static auto MakeColumn() {
if constexpr (std::is_same_v<ColumnType, ColumnFixedString>) {
return std::make_shared<ColumnFixedString>(12);
} else if constexpr (std::is_same_v<ColumnType, ColumnDateTime64>) {
return std::make_shared<ColumnDateTime64>(3);
} else if constexpr (std::is_same_v<ColumnType, ColumnDecimal>) {
return std::make_shared<ColumnDecimal>(10, 5);
} else {
return std::make_shared<ColumnType>();
}
}

static auto GenerateValues(size_t values_size) {
if constexpr (std::is_same_v<ColumnType, ColumnString>) {
return GenerateVector(values_size, FooBarGenerator);
} else if constexpr (std::is_same_v<ColumnType, ColumnFixedString>) {
return GenerateVector(values_size, FromVectorGenerator{MakeFixedStrings(12)});
} else if constexpr (std::is_same_v<ColumnType, ColumnDate>) {
return GenerateVector(values_size, FromVectorGenerator{MakeDates()});
} else if constexpr (std::is_same_v<ColumnType, ColumnDateTime>) {
return GenerateVector(values_size, FromVectorGenerator{MakeDateTimes()});
} else if constexpr (std::is_same_v<ColumnType, ColumnDateTime64>) {
return MakeDateTime64s(3u, values_size);
} else if constexpr (std::is_same_v<ColumnType, ColumnIPv4>) {
return GenerateVector(values_size, FromVectorGenerator{MakeIPv4s()});
} else if constexpr (std::is_same_v<ColumnType, ColumnIPv6>) {
return GenerateVector(values_size, FromVectorGenerator{MakeIPv6s()});
} else if constexpr (std::is_same_v<ColumnType, ColumnInt128>) {
return GenerateVector(values_size, FromVectorGenerator{MakeInt128s()});
} else if constexpr (std::is_same_v<ColumnType, ColumnDecimal>) {
return GenerateVector(values_size, FromVectorGenerator{MakeDecimals(3, 10)});
} else if constexpr (std::is_same_v<ColumnType, ColumnUUID>) {
return GenerateVector(values_size, FromVectorGenerator{MakeUUIDs()});
} else if constexpr (std::is_integral_v<typename ColumnType::ValueType>) {
// ColumnUIntX and ColumnIntX
return GenerateVector<typename ColumnType::ValueType>(values_size, RandomGenerator<int>());
} else if constexpr (std::is_floating_point_v<typename ColumnType::ValueType>) {
// OR ColumnFloatX
return GenerateVector<typename ColumnType::ValueType>(values_size, RandomGenerator<typename ColumnType::ValueType>());
}
}

template <typename Values>
static void AppendValues(std::shared_ptr<ColumnType> column, const Values& values) {
for (const auto & v : values) {
column->Append(v);
}
}

static auto MakeColumnWithValues(size_t values_size) {
auto column = MakeColumn();
auto values = GenerateValues(values_size);
AppendValues(column, values);

return std::tuple{column, values};
}
};

using ValueColumns = ::testing::Types<
ColumnUInt8, ColumnUInt16, ColumnUInt32, ColumnUInt64
, ColumnInt8, ColumnInt16, ColumnInt32, ColumnInt64
, ColumnFloat32, ColumnFloat64
, ColumnString, ColumnFixedString
, ColumnDate, ColumnDateTime, ColumnDateTime64
, ColumnIPv4, ColumnIPv6
, ColumnInt128
, ColumnDecimal
, ColumnUUID
>;
TYPED_TEST_SUITE(GenericColumnTest, ValueColumns);

TYPED_TEST(GenericColumnTest, Construct) {
auto column = this->MakeColumn();
ASSERT_EQ(0u, column->Size());
}

TYPED_TEST(GenericColumnTest, EmptyColumn) {
auto column = this->MakeColumn();
ASSERT_EQ(0u, column->Size());

// verify that Column methods work as expected on empty column:
// some throw exceptions, some return poper values (like CloneEmpty)

// Shouldn't be able to get items on empty column.
ASSERT_ANY_THROW(column->At(0));

{
auto slice = column->Slice(0, 0);
ASSERT_NO_THROW(slice->template AsStrict<typename TestFixture::ColumnType>());
ASSERT_EQ(0u, slice->Size());
}

{
auto clone = column->CloneEmpty();
ASSERT_NO_THROW(clone->template AsStrict<typename TestFixture::ColumnType>());
ASSERT_EQ(0u, clone->Size());
}

ASSERT_NO_THROW(column->Clear());
ASSERT_NO_THROW(column->Swap(*this->MakeColumn()));
}

TYPED_TEST(GenericColumnTest, Append) {
auto column = this->MakeColumn();
const auto values = this->GenerateValues(100);

for (const auto & v : values) {
EXPECT_NO_THROW(column->Append(v));
}

EXPECT_TRUE(CompareRecursive(values, *column));
}

TYPED_TEST(GenericColumnTest, Slice) {
auto [column, values] = this->MakeColumnWithValues(100);

auto untyped_slice = column->Slice(0, column->Size());
auto slice = untyped_slice->template AsStrict<typename TestFixture::ColumnType>();
EXPECT_EQ(column->GetType(), slice->GetType());

EXPECT_TRUE(CompareRecursive(values, *slice));

// TODO: slices of different sizes
}

TYPED_TEST(GenericColumnTest, CloneEmpty) {
auto [column, values] = this->MakeColumnWithValues(100);
EXPECT_EQ(values.size(), column->Size());

auto clone_untyped = column->CloneEmpty();
// Check that type matches
auto clone = clone_untyped->template AsStrict<typename TestFixture::ColumnType>();
EXPECT_EQ(0u, clone->Size());

EXPECT_EQ(column->GetType(), clone->GetType());
}

TYPED_TEST(GenericColumnTest, Clear) {
auto [column, values] = this->MakeColumnWithValues(100);
EXPECT_EQ(values.size(), column->Size());

column->Clear();
EXPECT_EQ(0u, column->Size());
}

TYPED_TEST(GenericColumnTest, Swap) {
auto [column_A, values] = this->MakeColumnWithValues(100);
auto column_B = this->MakeColumn();

column_A->Swap(*column_B);

EXPECT_EQ(0u, column_A->Size());
EXPECT_TRUE(CompareRecursive(values, *column_B));
}

TYPED_TEST(GenericColumnTest, LoadAndSave) {
auto [column_A, values] = this->MakeColumnWithValues(100);

char buffer[4096] = {'\0'};
{
ArrayOutput output(buffer, sizeof(buffer));
// Save
EXPECT_NO_THROW(column_A->Save(&output));
}

auto column_B = this->MakeColumn();
{
ArrayInput input(buffer, sizeof(buffer));
// Load
EXPECT_TRUE(column_B->Load(&input, values.size()));
}

EXPECT_TRUE(CompareRecursive(*column_A, *column_B));
}
84 changes: 84 additions & 0 deletions ut/CreateColumnByType_ut.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include <clickhouse/columns/factory.h>
#include <clickhouse/columns/date.h>
#include <clickhouse/columns/numeric.h>
#include <clickhouse/columns/string.h>

#include <gtest/gtest.h>

namespace {
using namespace clickhouse;
}

TEST(CreateColumnByType, CreateSimpleAggregateFunction) {
auto col = CreateColumnByType("SimpleAggregateFunction(funt, Int32)");

ASSERT_EQ("Int32", col->Type()->GetName());
ASSERT_EQ(Type::Int32, col->Type()->GetCode());
ASSERT_NE(nullptr, col->As<ColumnInt32>());
}

TEST(CreateColumnByType, UnmatchedBrackets) {
// When type string has unmatched brackets, CreateColumnByType must return nullptr.
ASSERT_EQ(nullptr, CreateColumnByType("FixedString(10"));
ASSERT_EQ(nullptr, CreateColumnByType("Nullable(FixedString(10000"));
ASSERT_EQ(nullptr, CreateColumnByType("Nullable(FixedString(10000)"));
ASSERT_EQ(nullptr, CreateColumnByType("LowCardinality(Nullable(FixedString(10000"));
ASSERT_EQ(nullptr, CreateColumnByType("LowCardinality(Nullable(FixedString(10000)"));
ASSERT_EQ(nullptr, CreateColumnByType("LowCardinality(Nullable(FixedString(10000))"));
ASSERT_EQ(nullptr, CreateColumnByType("Array(LowCardinality(Nullable(FixedString(10000"));
ASSERT_EQ(nullptr, CreateColumnByType("Array(LowCardinality(Nullable(FixedString(10000)"));
ASSERT_EQ(nullptr, CreateColumnByType("Array(LowCardinality(Nullable(FixedString(10000))"));
ASSERT_EQ(nullptr, CreateColumnByType("Array(LowCardinality(Nullable(FixedString(10000)))"));
}

TEST(CreateColumnByType, LowCardinalityAsWrappedColumn) {
CreateColumnByTypeSettings create_column_settings;
create_column_settings.low_cardinality_as_wrapped_column = true;

ASSERT_EQ(Type::String, CreateColumnByType("LowCardinality(String)", create_column_settings)->GetType().GetCode());
ASSERT_EQ(Type::String, CreateColumnByType("LowCardinality(String)", create_column_settings)->As<ColumnString>()->GetType().GetCode());

ASSERT_EQ(Type::FixedString, CreateColumnByType("LowCardinality(FixedString(10000))", create_column_settings)->GetType().GetCode());
ASSERT_EQ(Type::FixedString, CreateColumnByType("LowCardinality(FixedString(10000))", create_column_settings)->As<ColumnFixedString>()->GetType().GetCode());
}

TEST(CreateColumnByType, DateTime) {
ASSERT_NE(nullptr, CreateColumnByType("DateTime"));
ASSERT_NE(nullptr, CreateColumnByType("DateTime('Europe/Moscow')"));

ASSERT_EQ(CreateColumnByType("DateTime('UTC')")->As<ColumnDateTime>()->Timezone(), "UTC");
ASSERT_EQ(CreateColumnByType("DateTime64(3, 'UTC')")->As<ColumnDateTime64>()->Timezone(), "UTC");
}

class CreateColumnByTypeWithName : public ::testing::TestWithParam<const char* /*Column Type String*/>
{};

TEST_P(CreateColumnByTypeWithName, CreateColumnByType)
{
const auto col = CreateColumnByType(GetParam());
ASSERT_NE(nullptr, col);
EXPECT_EQ(col->GetType().GetName(), GetParam());
}

INSTANTIATE_TEST_SUITE_P(Basic, CreateColumnByTypeWithName, ::testing::Values(
"Int8", "Int16", "Int32", "Int64",
"UInt8", "UInt16", "UInt32", "UInt64",
"String", "Date", "DateTime",
"UUID", "Int128"
));

INSTANTIATE_TEST_SUITE_P(Parametrized, CreateColumnByTypeWithName, ::testing::Values(
"FixedString(0)", "FixedString(10000)",
"DateTime('UTC')", "DateTime64(3, 'UTC')",
"Decimal(9,3)", "Decimal(18,3)",
"Enum8('ONE' = 1, 'TWO' = 2)",
"Enum16('ONE' = 1, 'TWO' = 2, 'THREE' = 3, 'FOUR' = 4)"
));


INSTANTIATE_TEST_SUITE_P(Nested, CreateColumnByTypeWithName, ::testing::Values(
"Nullable(FixedString(10000))",
"Nullable(LowCardinality(FixedString(10000)))",
"Array(Nullable(LowCardinality(FixedString(10000))))",
"Array(Enum8('ONE' = 1, 'TWO' = 2))"
));
13 changes: 1 addition & 12 deletions ut/client_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,6 @@

using namespace clickhouse;

namespace clickhouse {
std::ostream & operator<<(std::ostream & ostr, const ServerInfo & server_info) {
return ostr << server_info.name << "/" << server_info.display_name
<< " ver "
<< server_info.version_major << "."
<< server_info.version_minor << "."
<< server_info.version_patch
<< " (" << server_info.revision << ")";
}
}

namespace {

uint64_t versionNumber(
Expand Down Expand Up @@ -1013,7 +1002,7 @@ ColumnRef RoundtripColumnValues(Client& client, ColumnRef expected) {
result->Append(b[0]);
});

EXPECT_EQ(expected->Type(), result->Type());
EXPECT_EQ(expected->GetType(), result->GetType());
EXPECT_EQ(expected->Size(), result->Size());
return result;
}
Expand Down
Loading

0 comments on commit 68094f3

Please sign in to comment.