susumu.yata
null+****@clear*****
Thu Aug 21 10:37:55 JST 2014
susumu.yata 2014-08-21 10:37:55 +0900 (Thu, 21 Aug 2014) New Revision: 6913fe6589793ee8f8cd01517085915e1cfe2628 https://github.com/groonga/grnxx/commit/6913fe6589793ee8f8cd01517085915e1cfe2628 Message: Update tests for Sorter. Modified files: test/test_sorter.cpp Modified: test/test_sorter.cpp (+369 -89) =================================================================== --- test/test_sorter.cpp 2014-08-21 10:20:01 +0900 (38d10ec) +++ test/test_sorter.cpp 2014-08-21 10:37:55 +0900 (f0ee048) @@ -28,176 +28,456 @@ #include "grnxx/table.hpp" #include "grnxx/sorter.hpp" -void test_sorter() { +struct { + grnxx::unique_ptr<grnxx::DB> db; + grnxx::Table *table; + grnxx::Array<grnxx::Bool> bool_values; + grnxx::Array<grnxx::Int> int_values; + grnxx::Array<grnxx::Float> float_values; + grnxx::Array<grnxx::Text> text_values; + grnxx::Array<std::string> text_bodies; +} test; + +void init_test() { grnxx::Error error; // Create a database with the default options. - auto db = grnxx::open_db(&error, ""); - assert(db); + test.db = grnxx::open_db(&error, ""); + assert(test.db); // Create a table with the default options. - auto table = db->create_table(&error, "Table"); - assert(table); + test.table = test.db->create_table(&error, "Table"); + assert(test.table); - // Create a Bool column named "BoolColumn". - auto bool_column = table->create_column(&error, "BoolColumn", - grnxx::BOOL_DATA); + // Create columns for Bool, Int, Float, and Text values. + grnxx::DataType data_type = grnxx::BOOL_DATA; + auto bool_column = test.table->create_column(&error, "Bool", data_type); assert(bool_column); - // Create a Int column named "IntColumn". - auto int_column = table->create_column(&error, "IntColumn", - grnxx::INT_DATA); + data_type = grnxx::INT_DATA; + auto int_column = test.table->create_column(&error, "Int", data_type); assert(int_column); - // Generate 1,024 random integers in a range [0, 64). - constexpr size_t NUM_VALUES = 1024; - std::vector<grnxx::Bool> bool_values(NUM_VALUES); - std::vector<grnxx::Int> int_values(NUM_VALUES); + data_type = grnxx::FLOAT_DATA; + auto float_column = test.table->create_column(&error, "Float", data_type); + assert(float_column); + + data_type = grnxx::TEXT_DATA; + auto text_column = test.table->create_column(&error, "Text", data_type); + assert(text_column); + + // Generate random values. + // Bool: true or false. + // Int: [0, 100). + // Float: [0.0, 1.0]. + // Text: length = [1, 4], byte = ['0', '9']. + constexpr grnxx::Int NUM_ROWS = 1 << 16; + constexpr grnxx::Int MIN_LENGTH = 1; + constexpr grnxx::Int MAX_LENGTH = 4; std::mt19937_64 mersenne_twister; - for (size_t i = 0; i < bool_values.size(); ++i) { + assert(test.bool_values.resize(&error, NUM_ROWS + 1)); + assert(test.int_values.resize(&error, NUM_ROWS + 1)); + assert(test.float_values.resize(&error, NUM_ROWS + 1)); + assert(test.text_values.resize(&error, NUM_ROWS + 1)); + assert(test.text_bodies.resize(&error, NUM_ROWS + 1)); + for (grnxx::Int i = 1; i <= NUM_ROWS; ++i) { + test.bool_values.set(i, (mersenne_twister() & 1) != 0); + test.int_values.set(i, mersenne_twister() % 100); + constexpr auto MAX_VALUE = mersenne_twister.max(); + test.float_values.set(i, 1.0 * mersenne_twister() / MAX_VALUE); + grnxx::Int length = + (mersenne_twister() % (MAX_LENGTH - MIN_LENGTH)) + MIN_LENGTH; + test.text_bodies[i].resize(length); + for (grnxx::Int j = 0; j < length; ++j) { + test.text_bodies[i][j] = '0' + (mersenne_twister() % 10); + } + test.text_values.set(i, grnxx::Text(test.text_bodies[i].data(), length)); + } + + // Store generated values into columns. + for (grnxx::Int i = 1; i <= NUM_ROWS; ++i) { grnxx::Int row_id; - assert(table->insert_row(&error, grnxx::NULL_ROW_ID, - grnxx::Datum(), &row_id)); - bool_values[i] = (mersenne_twister() & 1) != 0; - int_values[i] = mersenne_twister() % 64; - assert(bool_column->set(&error, row_id, grnxx::Bool(bool_values[i]))); - assert(int_column->set(&error, row_id, int_values[i])); + assert(test.table->insert_row(&error, grnxx::NULL_ROW_ID, + grnxx::Datum(), &row_id)); + assert(bool_column->set(&error, row_id, test.bool_values[i])); + assert(int_column->set(&error, row_id, test.int_values[i])); + assert(float_column->set(&error, row_id, test.float_values[i])); + assert(text_column->set(&error, row_id, test.text_values[i])); } +} - grnxx::Array<grnxx::Record> records; - auto cursor = table->create_cursor(&error); +void test_bool() { + grnxx::Error error; + + // Create a cursor which reads all the records. + auto cursor = test.table->create_cursor(&error); assert(cursor); - assert(cursor->read_all(&error, &records) == - static_cast<grnxx::Int>(int_values.size())); - assert(records.size() == static_cast<grnxx::Int>(int_values.size())); + grnxx::Array<grnxx::Record> records; + assert(cursor->read_all(&error, &records) == test.table->num_rows()); - // Sort records in order of BoolColumn value and row ID. - grnxx::Array<grnxx::SortOrder> orders; - assert(orders.resize(&error, 2)); + // Create an object for building expressions. auto expression_builder = - grnxx::ExpressionBuilder::create(&error, table); - assert(expression_builder->push_column(&error, "BoolColumn")); + grnxx::ExpressionBuilder::create(&error, test.table); + assert(expression_builder); + + // Create a regular sorter. + grnxx::Array<grnxx::SortOrder> orders; + assert(orders.resize(&error, 1)); + assert(expression_builder->push_column(&error, "Bool")); auto expression = expression_builder->release(&error); assert(expression); orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; + auto sorter = grnxx::Sorter::create(&error, std::move(orders)); - assert(expression_builder->push_column(&error, "_id")); + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Bool lhs_value = test.bool_values[lhs_row_id]; + grnxx::Bool rhs_value = test.bool_values[rhs_row_id]; + assert(!lhs_value || rhs_value); + } + + // Create a reverse sorter. + assert(orders.resize(&error, 1)); + assert(expression_builder->push_column(&error, "Bool")); expression = expression_builder->release(&error); assert(expression); - orders[1].expression = std::move(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REVERSE_ORDER; + sorter = grnxx::Sorter::create(&error, std::move(orders)); - auto sorter = grnxx::Sorter::create(&error, std::move(orders)); - assert(sorter); - assert(sorter->table() == table); + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Bool lhs_value = test.bool_values[lhs_row_id]; + grnxx::Bool rhs_value = test.bool_values[rhs_row_id]; + assert(lhs_value || !rhs_value); + } - assert(sorter->sort(&error, &records)); - assert(records.size() == static_cast<grnxx::Int>(int_values.size())); + // Create a multiple order sorter. + assert(orders.resize(&error, 2)); + assert(expression_builder->push_column(&error, "Bool")); + expression = expression_builder->release(&error); + assert(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; + assert(expression_builder->push_column(&error, "_id")); + expression = expression_builder->release(&error); + assert(expression); + orders[1].expression = std::move(expression); + orders[1].type = grnxx::REGULAR_ORDER; + sorter = grnxx::Sorter::create(&error, std::move(orders)); + sorter->sort(&error, &records); for (grnxx::Int i = 1; i < records.size(); ++i) { - grnxx::Int lhs_id = records.get_row_id(i - 1) - 1; - grnxx::Int rhs_id = records.get_row_id(i) - 1; - grnxx::Bool lhs_value = bool_values[lhs_id]; - grnxx::Bool rhs_value = bool_values[rhs_id]; + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Bool lhs_value = test.bool_values[lhs_row_id]; + grnxx::Bool rhs_value = test.bool_values[rhs_row_id]; assert(!lhs_value || rhs_value); if (lhs_value == rhs_value) { - assert(lhs_id < rhs_id); + assert(lhs_row_id < rhs_row_id); } } +} - // Sort records in reverse order of BoolColumn value and row ID. - assert(orders.resize(&error, 2)); - expression_builder = grnxx::ExpressionBuilder::create(&error, table); - assert(expression_builder->push_column(&error, "BoolColumn")); +void test_int() { + grnxx::Error error; + + // Create a cursor which reads all the records. + auto cursor = test.table->create_cursor(&error); + assert(cursor); + grnxx::Array<grnxx::Record> records; + assert(cursor->read_all(&error, &records) == test.table->num_rows()); + + // Create an object for building expressions. + auto expression_builder = + grnxx::ExpressionBuilder::create(&error, test.table); + assert(expression_builder); + + // Create a regular sorter. + grnxx::Array<grnxx::SortOrder> orders; + assert(orders.resize(&error, 1)); + assert(expression_builder->push_column(&error, "Int")); + auto expression = expression_builder->release(&error); + assert(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; + auto sorter = grnxx::Sorter::create(&error, std::move(orders)); + + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Int lhs_value = test.int_values[lhs_row_id]; + grnxx::Int rhs_value = test.int_values[rhs_row_id]; + assert(lhs_value <= rhs_value); + } + + // Create a reverse sorter. + assert(orders.resize(&error, 1)); + assert(expression_builder->push_column(&error, "Int")); expression = expression_builder->release(&error); assert(expression); orders[0].expression = std::move(expression); orders[0].type = grnxx::REVERSE_ORDER; + sorter = grnxx::Sorter::create(&error, std::move(orders)); + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Int lhs_value = test.int_values[lhs_row_id]; + grnxx::Int rhs_value = test.int_values[rhs_row_id]; + assert(lhs_value >= rhs_value); + } + + // Create a multiple order sorter. + assert(orders.resize(&error, 2)); + assert(expression_builder->push_column(&error, "Int")); + expression = expression_builder->release(&error); + assert(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; assert(expression_builder->push_column(&error, "_id")); expression = expression_builder->release(&error); assert(expression); orders[1].expression = std::move(expression); - orders[1].type = grnxx::REVERSE_ORDER; - + orders[1].type = grnxx::REGULAR_ORDER; sorter = grnxx::Sorter::create(&error, std::move(orders)); - assert(sorter); - - assert(sorter->sort(&error, &records)); - assert(records.size() == static_cast<grnxx::Int>(int_values.size())); + sorter->sort(&error, &records); for (grnxx::Int i = 1; i < records.size(); ++i) { - grnxx::Int lhs_id = records.get_row_id(i - 1) - 1; - grnxx::Int rhs_id = records.get_row_id(i) - 1; - grnxx::Bool lhs_value = bool_values[lhs_id]; - grnxx::Bool rhs_value = bool_values[rhs_id]; - assert(lhs_value || !rhs_value); + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Int lhs_value = test.int_values[lhs_row_id]; + grnxx::Int rhs_value = test.int_values[rhs_row_id]; + assert(lhs_value <= rhs_value); if (lhs_value == rhs_value) { - assert(lhs_id > rhs_id); + assert(lhs_row_id < rhs_row_id); } } +} - // Sort records in order of IntColumn value and row ID. - assert(orders.resize(&error, 2)); - expression_builder = grnxx::ExpressionBuilder::create(&error, table); - assert(expression_builder->push_column(&error, "IntColumn")); +void test_float() { + grnxx::Error error; + + // Create a cursor which reads all the records. + auto cursor = test.table->create_cursor(&error); + assert(cursor); + grnxx::Array<grnxx::Record> records; + assert(cursor->read_all(&error, &records) == test.table->num_rows()); + + // Create an object for building expressions. + auto expression_builder = + grnxx::ExpressionBuilder::create(&error, test.table); + assert(expression_builder); + + // Create a regular sorter. + grnxx::Array<grnxx::SortOrder> orders; + assert(orders.resize(&error, 1)); + assert(expression_builder->push_column(&error, "Float")); + auto expression = expression_builder->release(&error); + assert(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; + auto sorter = grnxx::Sorter::create(&error, std::move(orders)); + + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Float lhs_value = test.float_values[lhs_row_id]; + grnxx::Float rhs_value = test.float_values[rhs_row_id]; + assert(lhs_value <= rhs_value); + } + + // Create a reverse sorter. + assert(orders.resize(&error, 1)); + assert(expression_builder->push_column(&error, "Float")); expression = expression_builder->release(&error); + assert(expression); orders[0].expression = std::move(expression); + orders[0].type = grnxx::REVERSE_ORDER; + sorter = grnxx::Sorter::create(&error, std::move(orders)); + + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Float lhs_value = test.float_values[lhs_row_id]; + grnxx::Float rhs_value = test.float_values[rhs_row_id]; + assert(lhs_value >= rhs_value); + } + // Create a multiple order sorter. + assert(orders.resize(&error, 2)); + assert(expression_builder->push_column(&error, "Float")); + expression = expression_builder->release(&error); + assert(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; assert(expression_builder->push_column(&error, "_id")); expression = expression_builder->release(&error); assert(expression); orders[1].expression = std::move(expression); - + orders[1].type = grnxx::REGULAR_ORDER; sorter = grnxx::Sorter::create(&error, std::move(orders)); - assert(sorter); - - assert(sorter->sort(&error, &records)); - assert(records.size() == static_cast<grnxx::Int>(int_values.size())); + sorter->sort(&error, &records); for (grnxx::Int i = 1; i < records.size(); ++i) { - grnxx::Int lhs_id = records.get_row_id(i - 1) - 1; - grnxx::Int rhs_id = records.get_row_id(i) - 1; - grnxx::Int lhs_value = int_values[lhs_id]; - grnxx::Int rhs_value = int_values[rhs_id]; + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Float lhs_value = test.float_values[lhs_row_id]; + grnxx::Float rhs_value = test.float_values[rhs_row_id]; assert(lhs_value <= rhs_value); if (lhs_value == rhs_value) { - assert(lhs_id < rhs_id); + assert(lhs_row_id < rhs_row_id); } } +} - // Sort records in reverse order of IntColumn value and row ID. - assert(orders.resize(&error, 2)); - assert(expression_builder->push_column(&error, "IntColumn")); +void test_text() { + grnxx::Error error; + + // Create a cursor which reads all the records. + auto cursor = test.table->create_cursor(&error); + assert(cursor); + grnxx::Array<grnxx::Record> records; + assert(cursor->read_all(&error, &records) == test.table->num_rows()); + + // Create an object for building expressions. + auto expression_builder = + grnxx::ExpressionBuilder::create(&error, test.table); + assert(expression_builder); + + // Create a regular sorter. + grnxx::Array<grnxx::SortOrder> orders; + assert(orders.resize(&error, 1)); + assert(expression_builder->push_column(&error, "Text")); + auto expression = expression_builder->release(&error); + assert(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; + auto sorter = grnxx::Sorter::create(&error, std::move(orders)); + + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Text lhs_value = test.text_values[lhs_row_id]; + grnxx::Text rhs_value = test.text_values[rhs_row_id]; + assert(lhs_value <= rhs_value); + } + + // Create a reverse sorter. + assert(orders.resize(&error, 1)); + assert(expression_builder->push_column(&error, "Text")); expression = expression_builder->release(&error); assert(expression); orders[0].expression = std::move(expression); orders[0].type = grnxx::REVERSE_ORDER; + sorter = grnxx::Sorter::create(&error, std::move(orders)); + + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Text lhs_value = test.text_values[lhs_row_id]; + grnxx::Text rhs_value = test.text_values[rhs_row_id]; + assert(lhs_value >= rhs_value); + } + // Create a multiple order sorter. + assert(orders.resize(&error, 2)); + assert(expression_builder->push_column(&error, "Text")); + expression = expression_builder->release(&error); + assert(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; assert(expression_builder->push_column(&error, "_id")); expression = expression_builder->release(&error); assert(expression); orders[1].expression = std::move(expression); - orders[1].type = grnxx::REVERSE_ORDER; - + orders[1].type = grnxx::REGULAR_ORDER; sorter = grnxx::Sorter::create(&error, std::move(orders)); - assert(sorter); - assert(sorter->sort(&error, &records)); - assert(records.size() == static_cast<grnxx::Int>(int_values.size())); + sorter->sort(&error, &records); + for (grnxx::Int i = 1; i < records.size(); ++i) { + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Text lhs_value = test.text_values[lhs_row_id]; + grnxx::Text rhs_value = test.text_values[rhs_row_id]; + assert(lhs_value <= rhs_value); + if (lhs_value == rhs_value) { + assert(lhs_row_id < rhs_row_id); + } + } +} + +void test_composite() { + grnxx::Error error; + // Create a cursor which reads all the records. + auto cursor = test.table->create_cursor(&error); + assert(cursor); + grnxx::Array<grnxx::Record> records; + assert(cursor->read_all(&error, &records) == test.table->num_rows()); + + // Create an object for building expressions. + auto expression_builder = + grnxx::ExpressionBuilder::create(&error, test.table); + assert(expression_builder); + + // Create a composite sorter. + grnxx::Array<grnxx::SortOrder> orders; + assert(orders.resize(&error, 3)); + assert(expression_builder->push_column(&error, "Bool")); + auto expression = expression_builder->release(&error); + assert(expression); + orders[0].expression = std::move(expression); + orders[0].type = grnxx::REGULAR_ORDER; + assert(expression_builder->push_column(&error, "Int")); + expression = expression_builder->release(&error); + assert(expression); + orders[1].expression = std::move(expression); + orders[1].type = grnxx::REVERSE_ORDER; + assert(expression_builder->push_column(&error, "Text")); + expression = expression_builder->release(&error); + assert(expression); + orders[2].expression = std::move(expression); + orders[2].type = grnxx::REGULAR_ORDER; + auto sorter = grnxx::Sorter::create(&error, std::move(orders)); + + sorter->sort(&error, &records); for (grnxx::Int i = 1; i < records.size(); ++i) { - grnxx::Int lhs_id = records.get_row_id(i - 1) - 1; - grnxx::Int rhs_id = records.get_row_id(i) - 1; - grnxx::Int lhs_value = int_values[lhs_id]; - grnxx::Int rhs_value = int_values[rhs_id]; - assert(lhs_value >= rhs_value); + grnxx::Int lhs_row_id = records.get_row_id(i - 1); + grnxx::Int rhs_row_id = records.get_row_id(i); + grnxx::Bool lhs_value = test.bool_values[lhs_row_id]; + grnxx::Bool rhs_value = test.bool_values[rhs_row_id]; + assert(!lhs_value || rhs_value); if (lhs_value == rhs_value) { - assert(lhs_id > rhs_id); + grnxx::Int lhs_value = test.int_values[lhs_row_id]; + grnxx::Int rhs_value = test.int_values[rhs_row_id]; + assert(lhs_value >= rhs_value); + if (lhs_value == rhs_value) { + grnxx::Text lhs_value = test.text_values[lhs_row_id]; + grnxx::Text rhs_value = test.text_values[rhs_row_id]; + assert(lhs_value <= rhs_value); + } } } } int main() { - test_sorter(); + init_test(); + test_bool(); + test_int(); + test_float(); + test_text(); + test_composite(); return 0; } -------------- next part -------------- HTML����������������������������...ダウンロード