blob: a3c0bda7f6c1e5dfaabef834dce056a63b70ba8f [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* License); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "format/input_format.h"
#include <gtest/gtest.h>
#include <sstream>
#include "common/db_common.h"
#include "utils/db_utils.h"
TEST(InputFormatTest, ParseColumnsSpecValid) {
std::vector<tsfile_cli::ColumnDef> cols;
std::string err;
EXPECT_TRUE(tsfile_cli::parse_columns_spec("id1:STRING:tag,s1:INT64:field",
cols, err));
ASSERT_EQ(cols.size(), 2u);
EXPECT_EQ(cols[0].name, "id1");
EXPECT_EQ(cols[0].type, common::STRING);
EXPECT_EQ(cols[0].category, common::ColumnCategory::TAG);
EXPECT_EQ(cols[1].type, common::INT64);
EXPECT_EQ(cols[1].category, common::ColumnCategory::FIELD);
}
TEST(InputFormatTest, ParseColumnsSpecCaseInsensitiveType) {
std::vector<tsfile_cli::ColumnDef> cols;
std::string err;
EXPECT_TRUE(tsfile_cli::parse_columns_spec("s1:int64:field", cols, err));
EXPECT_EQ(cols[0].type, common::INT64);
}
TEST(InputFormatTest, ParseColumnsSpecCaseInsensitiveCategory) {
std::vector<tsfile_cli::ColumnDef> cols;
std::string err;
EXPECT_TRUE(tsfile_cli::parse_columns_spec("id1:STRING:TAG,s1:INT64:Field",
cols, err))
<< err;
ASSERT_EQ(cols.size(), 2u);
EXPECT_EQ(cols[0].category, common::ColumnCategory::TAG);
EXPECT_EQ(cols[1].category, common::ColumnCategory::FIELD);
}
TEST(InputFormatTest, ParseColumnsSpecExtendedTypes) {
std::vector<tsfile_cli::ColumnDef> cols;
std::string err;
EXPECT_TRUE(tsfile_cli::parse_columns_spec(
"ts:TIMESTAMP:field,d:DATE:field,b:BLOB:field", cols, err))
<< err;
ASSERT_EQ(cols.size(), 3u);
EXPECT_EQ(cols[0].type, common::TIMESTAMP);
EXPECT_EQ(cols[1].type, common::DATE);
EXPECT_EQ(cols[2].type, common::BLOB);
}
TEST(InputFormatTest, ParseColumnsSpecErrors) {
std::vector<tsfile_cli::ColumnDef> cols;
std::string err;
EXPECT_FALSE(tsfile_cli::parse_columns_spec("s1:NOPE:field", cols, err));
EXPECT_FALSE(tsfile_cli::parse_columns_spec("s1:INT64:bogus", cols, err));
EXPECT_FALSE(tsfile_cli::parse_columns_spec("s1:INT64", cols, err));
EXPECT_FALSE(tsfile_cli::parse_columns_spec("", cols, err));
EXPECT_FALSE(tsfile_cli::parse_columns_spec(":INT64:field", cols, err));
}
TEST(InputFormatTest, ParseColumnsSpecRejectsDuplicateNames) {
std::vector<tsfile_cli::ColumnDef> cols;
std::string err;
EXPECT_FALSE(tsfile_cli::parse_columns_spec("s1:INT64:field,s1:INT32:field",
cols, err));
EXPECT_NE(err.find("duplicate column"), std::string::npos) << err;
}
TEST(InputFormatTest, SplitLineTsv) {
std::vector<std::string> f =
tsfile_cli::split_line("0\t10\t20", '\t', false);
ASSERT_EQ(f.size(), 3u);
EXPECT_EQ(f[0], "0");
EXPECT_EQ(f[2], "20");
}
TEST(InputFormatTest, SplitLineCsvQuotes) {
std::vector<std::string> f =
tsfile_cli::split_line("1,\"a,b\",\"she \"\"hi\"\"\"", ',', true);
ASSERT_EQ(f.size(), 3u);
EXPECT_EQ(f[1], "a,b");
EXPECT_EQ(f[2], "she \"hi\"");
}
TEST(InputFormatTest, SplitLineEmptyFields) {
std::vector<std::string> f = tsfile_cli::split_line("0,,5", ',', true);
ASSERT_EQ(f.size(), 3u);
EXPECT_EQ(f[1], "");
}
TEST(InputFormatTest, ParseBoolCell) {
bool b = false;
EXPECT_TRUE(tsfile_cli::parse_bool_cell("true", b));
EXPECT_TRUE(b);
EXPECT_TRUE(tsfile_cli::parse_bool_cell("0", b));
EXPECT_FALSE(b);
EXPECT_FALSE(tsfile_cli::parse_bool_cell("maybe", b));
}
TEST(InputFormatTest, ReadRecordSingleLinePlain) {
std::istringstream in("a,b,c\nd,e,f\n");
std::string rec;
long long n = 0;
ASSERT_TRUE(tsfile_cli::read_record(in, true, rec, n));
EXPECT_EQ(rec, "a,b,c");
EXPECT_EQ(n, 1);
ASSERT_TRUE(tsfile_cli::read_record(in, true, rec, n));
EXPECT_EQ(rec, "d,e,f");
EXPECT_EQ(n, 1);
EXPECT_FALSE(tsfile_cli::read_record(in, true, rec, n));
}
TEST(InputFormatTest, ReadRecordJoinsQuotedNewline) {
std::istringstream in("1,\"line one\nline two\",x\n2,plain,y\n");
std::string rec;
long long n = 0;
ASSERT_TRUE(tsfile_cli::read_record(in, true, rec, n));
EXPECT_EQ(rec, "1,\"line one\nline two\",x");
EXPECT_EQ(n, 2); // two physical lines made one record
// The embedded newline survives field splitting inside the quotes.
std::vector<std::string> f = tsfile_cli::split_line(rec, ',', true);
ASSERT_EQ(f.size(), 3u);
EXPECT_EQ(f[1], "line one\nline two");
ASSERT_TRUE(tsfile_cli::read_record(in, true, rec, n));
EXPECT_EQ(rec, "2,plain,y");
EXPECT_EQ(n, 1);
}
TEST(InputFormatTest, ReadRecordStripsCarriageReturn) {
std::istringstream in("a,b\r\nc,d\r\n");
std::string rec;
long long n = 0;
ASSERT_TRUE(tsfile_cli::read_record(in, true, rec, n));
EXPECT_EQ(rec, "a,b");
}
TEST(InputFormatTest, ReadRecordTsvIgnoresQuotes) {
// With csv_quotes false a quote is just data; no line joining happens.
std::istringstream in("1\t\"open\n2\tclosed\n");
std::string rec;
long long n = 0;
ASSERT_TRUE(tsfile_cli::read_record(in, false, rec, n));
EXPECT_EQ(rec, "1\t\"open");
EXPECT_EQ(n, 1);
}
TEST(InputFormatTest, ReadRecordUnterminatedQuoteAtEof) {
std::istringstream in("1,\"never closed\n");
std::string rec;
long long n = 0;
ASSERT_TRUE(tsfile_cli::read_record(in, true, rec, n));
EXPECT_EQ(rec, "1,\"never closed");
EXPECT_EQ(n, 1);
EXPECT_FALSE(tsfile_cli::read_record(in, true, rec, n));
}