1 | #include "catch.hpp" |
2 | #include "test_helpers.hpp" |
3 | |
4 | using namespace duckdb; |
5 | using namespace std; |
6 | |
7 | /* Test Case disclaimer |
8 | * |
9 | * Assertions built using the Domain Testing technique |
10 | * at: https://bbst.courses/wp-content/uploads/2018/01/Kaner-Intro-to-Domain-Testing-2018.pdf |
11 | * |
12 | */ |
13 | TEST_CASE("Contains test" , "[function]" ) { |
14 | unique_ptr<QueryResult> result; |
15 | DuckDB db(nullptr); |
16 | Connection con(db); |
17 | con.EnableQueryVerification(); |
18 | |
19 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE strings(s VARCHAR, off INTEGER, length INTEGER);" )); |
20 | REQUIRE_NO_FAIL(con.Query("INSERT INTO strings VALUES ('hello', 1, 2), " |
21 | "('world', 2, 3), ('b', 1, 1), (NULL, 2, 2)" )); |
22 | |
23 | // Test first letter |
24 | result = con.Query("SELECT contains(s,'h') FROM strings" ); |
25 | REQUIRE(CHECK_COLUMN(result, 0, {true, false, false, Value(nullptr)})); |
26 | |
27 | // Test second letter |
28 | result = con.Query("SELECT contains(s,'e') FROM strings" ); |
29 | REQUIRE(CHECK_COLUMN(result, 0, {true, false, false, Value(nullptr)})); |
30 | |
31 | // Test last letter |
32 | result = con.Query("SELECT contains(s,'d') FROM strings" ); |
33 | REQUIRE(CHECK_COLUMN(result, 0, {false, true, false, Value(nullptr)})); |
34 | |
35 | // Test multiple letters |
36 | result = con.Query("SELECT contains(s,'he') FROM strings" ); |
37 | REQUIRE(CHECK_COLUMN(result, 0, {true, false, false, Value(nullptr)})); |
38 | |
39 | // Test multiple letters in the middle |
40 | result = con.Query("SELECT contains(s,'ello') FROM strings" ); |
41 | REQUIRE(CHECK_COLUMN(result, 0, {true, false, false, Value(nullptr)})); |
42 | |
43 | // Test multiple letters at the end |
44 | result = con.Query("SELECT contains(s,'lo') FROM strings" ); |
45 | REQUIRE(CHECK_COLUMN(result, 0, {true, false, false, Value(nullptr)})); |
46 | |
47 | // Test no match |
48 | result = con.Query("SELECT contains(s,'he-man') FROM strings" ); |
49 | REQUIRE(CHECK_COLUMN(result, 0, {false, false, false, Value(nullptr)})); |
50 | |
51 | // Test matching needle in multiple rows |
52 | result = con.Query("SELECT contains(s,'o') FROM strings" ); |
53 | REQUIRE(CHECK_COLUMN(result, 0, {true, true, false, Value(nullptr)})); |
54 | |
55 | // Test NULL constant in different places |
56 | result = con.Query("SELECT contains(NULL,'o') FROM strings" ); |
57 | REQUIRE(CHECK_COLUMN(result, 0, {Value(nullptr), Value(nullptr), Value(nullptr), Value(nullptr)})); |
58 | result = con.Query("SELECT contains(s,NULL) FROM strings" ); |
59 | REQUIRE(CHECK_COLUMN(result, 0, {Value(nullptr), Value(nullptr), Value(nullptr), Value(nullptr)})); |
60 | result = con.Query("SELECT contains(NULL,NULL) FROM strings" ); |
61 | REQUIRE(CHECK_COLUMN(result, 0, {Value(nullptr), Value(nullptr), Value(nullptr), Value(nullptr)})); |
62 | |
63 | // Test empty pattern |
64 | result = con.Query("SELECT contains(s,'') FROM strings" ); |
65 | REQUIRE(CHECK_COLUMN(result, 0, {true, true, true, Value(nullptr)})); |
66 | } |
67 | |
68 | /* Inspired by the substring test case and C language UTF-8 tests |
69 | * |
70 | */ |
71 | TEST_CASE("Contains test with UTF8" , "[function]" ) { |
72 | unique_ptr<QueryResult> result; |
73 | DuckDB db(nullptr); |
74 | Connection con(db); |
75 | con.EnableQueryVerification(); |
76 | string atomo = "\xc3\xa1tomo" ; // length 6 |
77 | string portg = "ol\xc3\xa1 mundo" ; // olá mundo length 9 |
78 | string nihao = "\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c" ; //你好世界 length 4 |
79 | string potpourri = "two \xc3\xb1 three \xE2\x82\xA1 four \xF0\x9F\xA6\x86 end" ; |
80 | |
81 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE strings(s VARCHAR);" )); |
82 | REQUIRE_NO_FAIL(con.Query("INSERT INTO strings VALUES ('" + atomo + "')" )); |
83 | REQUIRE_NO_FAIL(con.Query("INSERT INTO strings VALUES ('" + portg + "')" )); |
84 | REQUIRE_NO_FAIL(con.Query("INSERT INTO strings VALUES ('" + nihao + "')" )); |
85 | REQUIRE_NO_FAIL(con.Query("INSERT INTO strings VALUES ('" + potpourri + "')" )); |
86 | |
87 | // Test one matching UTF8 letter |
88 | result = con.Query("SELECT contains(s,'\xc3\xa1') FROM strings" ); |
89 | REQUIRE(CHECK_COLUMN(result, 0, {true, true, false, false})); |
90 | |
91 | // Test a sentence with an UTF-8 |
92 | result = con.Query("SELECT contains(s,'ol\xc3\xa1 mundo') FROM strings" ); |
93 | REQUIRE(CHECK_COLUMN(result, 0, {false, true, false, false})); |
94 | |
95 | // Test an entire UTF-8 word |
96 | result = con.Query("SELECT contains(s,'\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c') FROM strings" ); |
97 | REQUIRE(CHECK_COLUMN(result, 0, {false, false, true, false})); |
98 | |
99 | // Test a substring of the haystack from the beginning |
100 | result = con.Query("SELECT contains(s,'two \xc3\xb1 thr') FROM strings" ); |
101 | REQUIRE(CHECK_COLUMN(result, 0, {false, false, false, true})); |
102 | |
103 | // Test a single UTF8 substring of the haystack in the middle |
104 | result = con.Query("SELECT contains(s,'\xc3\xb1') FROM strings" ); |
105 | REQUIRE(CHECK_COLUMN(result, 0, {false, false, false, true})); |
106 | |
107 | // Test a multiple UTF8 substring of the haystack in the middle |
108 | result = con.Query("SELECT contains(s,'\xE2\x82\xA1 four \xF0\x9F\xA6\x86 e') FROM strings" ); |
109 | REQUIRE(CHECK_COLUMN(result, 0, {false, false, false, true})); |
110 | |
111 | // Test a substring of the haystack from the middle to the end |
112 | result = con.Query("SELECT contains(s,'\xF0\x9F\xA6\x86 end') FROM strings" ); |
113 | REQUIRE(CHECK_COLUMN(result, 0, {false, false, false, true})); |
114 | } |
115 | |