1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
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 #ifdef RELATIONAL_STORE
16 #include <gtest/gtest.h>
17
18 #include "db_errno.h"
19 #include "distributeddb/result_set.h"
20 #include "distributeddb_tools_unit_test.h"
21 #include "log_print.h"
22 #include "relational_result_set_impl.h"
23 #include "relational_row_data.h"
24 #include "relational_row_data_impl.h"
25 #include "relational_row_data_set.h"
26 #include "relational_store_sqlite_ext.h"
27 #include "types_export.h"
28
29 using namespace testing::ext;
30 using namespace DistributedDB;
31 using namespace DistributedDBUnitTest;
32 using namespace std;
33
34 namespace {
35 string g_testDir;
36 string g_storePath;
37 string g_tableName { "data" };
38
39 const vector<uint8_t> BLOB_VALUE { 'a', 'b', 'l', 'o', 'b', '\0', 'e', 'n', 'd' };
40 const double DOUBLE_VALUE = 1.123456; // 1.123456 for test
41 const int64_t INT64_VALUE = 123456; // 123456 for test
42 const std::string STR_VALUE = "I'm a string.";
43
44 DataValue g_blobValue;
45 DataValue g_doubleValue;
46 DataValue g_int64Value;
47 DataValue g_nullValue;
48 DataValue g_strValue;
49
InitGlobalValue()50 void InitGlobalValue()
51 {
52 Blob *blob = new (std::nothrow) Blob();
53 blob->WriteBlob(BLOB_VALUE.data(), BLOB_VALUE.size());
54 g_blobValue.Set(blob);
55
56 g_doubleValue = DOUBLE_VALUE;
57 g_int64Value = INT64_VALUE;
58 g_strValue = STR_VALUE;
59 }
60
CreateDBAndTable()61 void CreateDBAndTable()
62 {
63 sqlite3 *db = nullptr;
64 int errCode = sqlite3_open(g_storePath.c_str(), &db);
65 if (errCode != SQLITE_OK) {
66 LOGE("open db failed:%d", errCode);
67 sqlite3_close(db);
68 return;
69 }
70
71 const string sql =
72 "PRAGMA journal_mode=WAL;"
73 "CREATE TABLE " + g_tableName + "(key INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, value INTEGER);";
74 char *zErrMsg = nullptr;
75 errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &zErrMsg);
76 if (errCode != SQLITE_OK) {
77 LOGE("sql error:%s", zErrMsg);
78 sqlite3_free(zErrMsg);
79 }
80 sqlite3_close(db);
81 }
82 }
83
84 class DistributedDBRelationalResultSetTest : public testing::Test {
85 public:
86 static void SetUpTestCase();
87 static void TearDownTestCase();
88 void SetUp();
89 void TearDown();
90 };
91
SetUpTestCase(void)92 void DistributedDBRelationalResultSetTest::SetUpTestCase(void)
93 {
94 DistributedDBToolsUnitTest::TestDirInit(g_testDir);
95 InitGlobalValue();
96 g_storePath = g_testDir + "/relationalResultSetTest.db";
97 LOGI("The test db is:%s", g_testDir.c_str());
98 }
99
TearDownTestCase(void)100 void DistributedDBRelationalResultSetTest::TearDownTestCase(void) {}
101
SetUp(void)102 void DistributedDBRelationalResultSetTest::SetUp(void)
103 {
104 DistributedDBToolsUnitTest::PrintTestCaseInfo();
105 CreateDBAndTable();
106 }
107
TearDown(void)108 void DistributedDBRelationalResultSetTest::TearDown(void)
109 {
110 if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) {
111 LOGE("rm test db files error.");
112 }
113 }
114
115 /**
116 * @tc.name: SerializeAndDeserialize
117 * @tc.desc: Serialize and deserialize.
118 * @tc.type: FUNC
119 * @tc.require: AR000GK58G
120 * @tc.author: lidongwei
121 */
122 HWTEST_F(DistributedDBRelationalResultSetTest, SerializeAndDeserialize, TestSize.Level1)
123 {
124 RowData data1 {g_strValue, g_int64Value, g_doubleValue, g_blobValue, g_nullValue};
125 RowData data2 {g_nullValue, g_blobValue, g_doubleValue, g_int64Value, g_strValue}; // data1.reverse()
126
127 auto rowDataImpl1 = new (std::nothrow) RelationalRowDataImpl(std::move(data1));
128 auto rowDataImpl2 = new (std::nothrow) RelationalRowDataImpl(std::move(data2));
129
130 /**
131 * @tc.steps: step1. Create a row data set which contains two row data;
132 * @tc.expected: OK.
133 */
134 RelationalRowDataSet rowDataSet1;
135 rowDataSet1.SetColNames({"column 1", "column 2", "column 3", "column 4", "column 5"});
136 rowDataSet1.Insert(rowDataImpl1);
137 rowDataSet1.Insert(rowDataImpl2);
138
139 /**
140 * @tc.steps: step2. Serialize the row data set;
141 * @tc.expected: Serialize OK.
142 */
143 auto bufferLength = rowDataSet1.CalcLength();
144 vector<uint8_t> buffer1(bufferLength);
145 Parcel parcel1(buffer1.data(), buffer1.size());
146 ASSERT_EQ(rowDataSet1.Serialize(parcel1), E_OK);
147 ASSERT_FALSE(parcel1.IsError());
148
149 /**
150 * @tc.steps: step3. Deserialize the row data set;
151 * @tc.expected: Deserialize OK.
152 */
153 vector<uint8_t> buffer2 = buffer1;
154 Parcel parcel2(buffer2.data(), buffer2.size());
155 RelationalRowDataSet rowDataSet2;
156 ASSERT_EQ(rowDataSet2.DeSerialize(parcel2), E_OK);
157 ASSERT_FALSE(parcel2.IsError());
158
159 /**
160 * @tc.steps: step4. Compare the deserialized row data set with the original;
161 * @tc.expected: Compare OK. They are the same.
162 */
163 std::vector<std::string> colNames {"column 1", "column 2", "column 3", "column 4", "column 5"};
164 EXPECT_EQ(rowDataSet2.GetColNames(), colNames);
165
166 // test the second row. if the second row ok, the first row is likely ok
167 StorageType type = StorageType::STORAGE_TYPE_NONE;
168 EXPECT_EQ(rowDataSet2.Get(1)->GetType(0, type), E_OK);
169 EXPECT_EQ(type, StorageType::STORAGE_TYPE_NULL);
170
171 vector<uint8_t> desBlob;
172 EXPECT_EQ(rowDataSet2.Get(1)->Get(1, desBlob), E_OK);
173 EXPECT_EQ(desBlob, BLOB_VALUE);
174
175 double desDoub;
176 EXPECT_EQ(rowDataSet2.Get(1)->Get(2, desDoub), E_OK);
177 EXPECT_EQ(desDoub, DOUBLE_VALUE);
178
179 int64_t desInt64;
180 EXPECT_EQ(rowDataSet2.Get(1)->Get(3, desInt64), E_OK);
181 EXPECT_EQ(desInt64, INT64_VALUE);
182
183 std::string desStr;
184 EXPECT_EQ(rowDataSet2.Get(1)->Get(4, desStr), E_OK);
185 EXPECT_EQ(desStr, STR_VALUE);
186 }
187
188 /**
189 * @tc.name: Put
190 * @tc.desc: Test put into result set
191 * @tc.type: FUNC
192 * @tc.require: AR000GK58G
193 * @tc.author: lidongwei
194 */
195 HWTEST_F(DistributedDBRelationalResultSetTest, Put, TestSize.Level1)
196 {
197 RowData data1 {g_strValue, g_int64Value, g_doubleValue, g_blobValue, g_nullValue};
198 RowData data2 {g_nullValue, g_blobValue, g_doubleValue, g_int64Value, g_strValue}; // data1.reverse()
199 RowData data3 {g_strValue, g_int64Value, g_doubleValue, g_blobValue, g_nullValue};
200
201 auto rowDataImpl1 = new (std::nothrow) RelationalRowDataImpl(std::move(data1));
202 auto rowDataImpl2 = new (std::nothrow) RelationalRowDataImpl(std::move(data2));
203 auto rowDataImpl3 = new (std::nothrow) RelationalRowDataImpl(std::move(data3));
204 /**
205 * @tc.steps: step1. Create 2 row data set which contains 3 row data totally;
206 * @tc.expected: OK.
207 */
208 RelationalRowDataSet rowDataSet1;
209 rowDataSet1.Insert(rowDataImpl1);
210
211 RelationalRowDataSet rowDataSet2;
212 rowDataSet2.SetRowData({ rowDataImpl2, rowDataImpl3 });
213
214 /**
215 * @tc.steps: step2. Put row data set;
216 * @tc.expected: The count is in expect.
217 */
218 RelationalResultSetImpl resultSet;
219 resultSet.Put("", 1, std::move(rowDataSet2));
220 resultSet.Put("", 2, std::move(rowDataSet1));
221 EXPECT_EQ(resultSet.GetCount(), 3);
222 }
223
224 /**
225 * @tc.name: EmptyResultSet
226 * @tc.desc: Empty result set.
227 * @tc.type: FUNC
228 * @tc.require: AR000GK58G
229 * @tc.author: lidongwei
230 */
231 HWTEST_F(DistributedDBRelationalResultSetTest, EmptyResultSet, TestSize.Level1)
232 {
233 ResultSet *resultSet = new (std::nothrow) RelationalResultSetImpl;
234 ASSERT_NE(resultSet, nullptr);
235
236 EXPECT_EQ(resultSet->GetCount(), 0); // 0 row data
237 EXPECT_EQ(resultSet->GetPosition(), -1); // the init position=-1
238 EXPECT_FALSE(resultSet->MoveToFirst()); // move fail. position=-1
239 EXPECT_FALSE(resultSet->MoveToLast()); // move fail. position=-1
240 EXPECT_FALSE(resultSet->MoveToNext()); // move fail. position=-1
241 EXPECT_FALSE(resultSet->MoveToPrevious()); // move fail. position=-1
242 EXPECT_FALSE(resultSet->Move(1)); // move fail. position=-1
243 EXPECT_FALSE(resultSet->MoveToPosition(0)); // move fail. position=1
244 EXPECT_FALSE(resultSet->IsFirst()); // position=1, not the first one
245 EXPECT_FALSE(resultSet->IsLast()); // position=1, not the last one
246 EXPECT_TRUE(resultSet->IsBeforeFirst()); // empty result set, always true
247 EXPECT_TRUE(resultSet->IsAfterLast()); // empty result set, always true
248 EXPECT_FALSE(resultSet->IsClosed()); // not closed
249 Entry entry;
250 EXPECT_EQ(resultSet->GetEntry(entry), DBStatus::NOT_SUPPORT); // for relational result set, not support get entry.
251 ResultSet::ColumnType columnType;
252 EXPECT_EQ(resultSet->GetColumnType(0, columnType), DBStatus::NOT_FOUND); // the invalid position
253 int columnIndex = -1;
254 EXPECT_EQ(resultSet->GetColumnIndex("", columnIndex), DBStatus::NOT_FOUND); // empty result set
255 int64_t value = 0;
256 EXPECT_EQ(resultSet->Get(0, value), DBStatus::NOT_FOUND); // the invalid position
257 std::map<std::string, VariantData> data;
258 EXPECT_EQ(resultSet->GetRow(data), DBStatus::NOT_FOUND); // the invalid position
259 delete resultSet;
260 }
261
262 /**
263 * @tc.name: NormalResultSet
264 * @tc.desc: Normal result set.
265 * @tc.type: FUNC
266 * @tc.require: AR000GK58G
267 * @tc.author: lidongwei
268 */
269 HWTEST_F(DistributedDBRelationalResultSetTest, NormalResultSet, TestSize.Level1)
270 {
271 auto *resultSet = new (std::nothrow) RelationalResultSetImpl;
272 ASSERT_NE(resultSet, nullptr);
273
274 /**
275 * @tc.steps: step1. Create a result set which contains two row data;
276 * @tc.expected: OK.
277 */
278 RelationalRowDataSet rowDataSet1;
279 EXPECT_EQ(rowDataSet1.Insert(new (std::nothrow) RelationalRowDataImpl({g_strValue, g_int64Value})), E_OK);
280 RelationalRowDataSet rowDataSet2;
281 rowDataSet2.SetColNames({"column 1", "column 2"});
282 EXPECT_EQ(rowDataSet2.Insert(new (std::nothrow) RelationalRowDataImpl({g_nullValue, g_blobValue})), E_OK);
283
284 EXPECT_EQ(resultSet->Put("", 2, std::move(rowDataSet2)), E_OK); // the second one
285 EXPECT_EQ(resultSet->Put("", 1, std::move(rowDataSet1)), E_OK); // the first one
286
287 /**
288 * @tc.steps: step2. Check the result set;
289 * @tc.expected: All the interface is running in expect.
290 */
291 EXPECT_EQ(resultSet->GetCount(), 2); // two row data
292 EXPECT_EQ(resultSet->GetPosition(), -1); // the init position=-1
293 EXPECT_TRUE(resultSet->MoveToFirst()); // move ok. position=0
294 EXPECT_TRUE(resultSet->MoveToLast()); // move ok. position=1
295 EXPECT_FALSE(resultSet->MoveToNext()); // move fail. position=2
296 EXPECT_TRUE(resultSet->MoveToPrevious()); // move ok. position=1
297 EXPECT_FALSE(resultSet->Move(1)); // move fail. position=2
298 EXPECT_TRUE(resultSet->MoveToPosition(0)); // move ok. position=0
299 EXPECT_TRUE(resultSet->IsFirst()); // position=0, the first one
300 EXPECT_FALSE(resultSet->IsLast()); // position=0, not the last one
301 EXPECT_FALSE(resultSet->IsBeforeFirst()); // position=0, not before the first
302 EXPECT_FALSE(resultSet->IsAfterLast()); // position=0, not after the last
303 EXPECT_FALSE(resultSet->IsClosed()); // not closed
304
305 Entry entry;
306 EXPECT_EQ(resultSet->GetEntry(entry), DBStatus::NOT_SUPPORT); // for relational result set, not support get entry.
307
308 ResultSet::ColumnType columnType;
309 EXPECT_EQ(resultSet->GetColumnType(0, columnType), DBStatus::OK);
310 EXPECT_EQ(columnType, ResultSet::ColumnType::STRING);
311
312 std::vector<std::string> expectCols { "column 1", "column 2" };
313 std::vector<std::string> colNames;
314 resultSet->GetColumnNames(colNames);
315 EXPECT_EQ(colNames, expectCols);
316
317 int columnIndex = -1;
318 EXPECT_EQ(resultSet->GetColumnIndex("", columnIndex), DBStatus::NONEXISTENT); // the invalid column name
319 EXPECT_EQ(resultSet->GetColumnIndex("column 1", columnIndex), DBStatus::OK);
320 EXPECT_EQ(columnIndex, 0);
321
322 int64_t value = 0;
323 EXPECT_EQ(resultSet->Get(1, value), DBStatus::OK);
324 EXPECT_EQ(value, INT64_VALUE);
325
326 std::map<std::string, VariantData> data;
327 EXPECT_EQ(resultSet->GetRow(data), DBStatus::OK);
328 EXPECT_EQ(std::get<std::string>(data["column 1"]), STR_VALUE);
329 EXPECT_EQ(std::get<int64_t>(data["column 2"]), INT64_VALUE);
330 delete resultSet;
331 }
332
333
334 HWTEST_F(DistributedDBRelationalResultSetTest, Test001, TestSize.Level1)
335 {
336 auto *resultSet = new (std::nothrow) RelationalResultSetImpl;
337 ASSERT_NE(resultSet, nullptr);
338
339 /**
340 * @tc.steps: step1. Create a result set which contains two row data;
341 * @tc.expected: OK.
342 */
343 RelationalRowDataSet rowDataSet1;
344 RowData rowData = {g_blobValue, g_doubleValue, g_int64Value, g_nullValue, g_strValue};
345 EXPECT_EQ(rowDataSet1.Insert(new (std::nothrow) RelationalRowDataImpl(std::move(rowData))), E_OK);
346 EXPECT_EQ(resultSet->Put("", 1, std::move(rowDataSet1)), E_OK); // the first one
347
348 EXPECT_EQ(resultSet->MoveToFirst(), true);
349 ResultSet::ColumnType columnType;
350 EXPECT_EQ(resultSet->GetColumnType(0, columnType), DBStatus::OK);
351 EXPECT_EQ(columnType, ResultSet::ColumnType::BLOB);
352 EXPECT_EQ(resultSet->GetColumnType(1, columnType), DBStatus::OK);
353 EXPECT_EQ(columnType, ResultSet::ColumnType::DOUBLE);
354 EXPECT_EQ(resultSet->GetColumnType(2, columnType), DBStatus::OK);
355 EXPECT_EQ(columnType, ResultSet::ColumnType::INT64);
356 EXPECT_EQ(resultSet->GetColumnType(3, columnType), DBStatus::OK);
357 EXPECT_EQ(columnType, ResultSet::ColumnType::NULL_VALUE);
358 EXPECT_EQ(resultSet->GetColumnType(4, columnType), DBStatus::OK);
359 EXPECT_EQ(columnType, ResultSet::ColumnType::STRING);
360
361 delete resultSet;
362 }
363
364 /**
365 * @tc.name: ResultSetTest001
366 * @tc.desc: Test get rowData and close
367 * @tc.type: FUNC
368 * @tc.require:
369 * @tc.author: chenchaohao
370 */
371 HWTEST_F(DistributedDBRelationalResultSetTest, ResultSetTest001, TestSize.Level0)
372 {
373 auto *resultSet = new (std::nothrow) RelationalResultSetImpl;
374 ASSERT_NE(resultSet, nullptr);
375
376 /**
377 * @tc.steps: step1. Create a result set which contains five row data;
378 * @tc.expected: OK.
379 */
380 RelationalRowDataSet rowDataSet1;
381 RowData rowData = {g_blobValue, g_doubleValue, g_int64Value, g_nullValue, g_strValue};
382 rowDataSet1.SetColNames({"column 1", "column 2", "column 3", "column 4", "column 5"});
383 EXPECT_EQ(rowDataSet1.Insert(new (std::nothrow) RelationalRowDataImpl(std::move(rowData))), E_OK);
384 EXPECT_EQ(resultSet->Put("", 1, std::move(rowDataSet1)), E_OK); // the first one
385 EXPECT_EQ(resultSet->MoveToFirst(), true);
386
387 /**
388 * @tc.steps: step2. Check data
389 * @tc.expected: OK.
390 */
391 std::map<std::string, VariantData> data;
392 EXPECT_EQ(resultSet->GetRow(data), DBStatus::OK);
393 EXPECT_EQ(std::get<std::vector<uint8_t>>(data["column 1"]), BLOB_VALUE);
394 EXPECT_EQ(std::get<double>(data["column 2"]), DOUBLE_VALUE);
395 EXPECT_EQ(std::get<int64_t>(data["column 3"]), INT64_VALUE);
396 EXPECT_EQ(std::get<std::string>(data["column 5"]), STR_VALUE);
397
398 /**
399 * @tc.steps: step3. Check close twice
400 * @tc.expected: OK.
401 */
402 resultSet->Close();
403 EXPECT_EQ(resultSet->GetCount(), 0);
404 resultSet->Close();
405 EXPECT_EQ(resultSet->GetCount(), 0);
406
407 delete resultSet;
408 }
409
410 /**
411 * @tc.name: ResultSetTest002
412 * @tc.desc: Test get data in null resultSet
413 * @tc.type: FUNC
414 * @tc.require:
415 * @tc.author: chenchaohao
416 */
417 HWTEST_F(DistributedDBRelationalResultSetTest, ResultSetTest002, TestSize.Level0)
418 {
419 auto *resultSet = new (std::nothrow) RelationalResultSetImpl;
420 ASSERT_NE(resultSet, nullptr);
421
422 /**
423 * @tc.steps: step1. check whether status is not found when get null resultSet
424 * @tc.expected: OK.
425 */
426 std::vector<uint8_t> blob;
427 EXPECT_EQ(resultSet->Get(0, blob), DBStatus::NOT_FOUND);
428 std::string strValue = "";
429 EXPECT_EQ(resultSet->Get(0, strValue), DBStatus::NOT_FOUND);
430 int64_t intValue = 0;
431 EXPECT_EQ(resultSet->Get(0, intValue), DBStatus::NOT_FOUND);
432 double doubleValue = 0.0;
433 EXPECT_EQ(resultSet->Get(0, doubleValue), DBStatus::NOT_FOUND);
434 bool isNull = true;
435 EXPECT_EQ(resultSet->IsColumnNull(0, isNull), DBStatus::NOT_FOUND);
436
437 delete resultSet;
438 }
439 #endif
440