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