1 /*
2  * Copyright (c) 2015-2016, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 
31 #include <cstring>
32 
33 #include "gtest/gtest.h"
34 #include "hs.h"
35 #include "test_util.h"
36 
37 using namespace std;
38 using namespace testing;
39 
TEST(ExtParam,LargeMinOffset)40 TEST(ExtParam, LargeMinOffset) {
41     hs_expr_ext ext;
42     memset(&ext, 0, sizeof(ext));
43     ext.min_offset = 100000;
44     ext.flags = HS_EXT_FLAG_MIN_OFFSET;
45 
46     pattern p("hatstand.*teakettle", 0, 0, ext);
47     hs_database_t *db = buildDB(p, HS_MODE_NOSTREAM);
48     ASSERT_TRUE(db != nullptr);
49 
50     hs_scratch_t *scratch = nullptr;
51     hs_error_t err = hs_alloc_scratch(db, &scratch);
52     ASSERT_EQ(HS_SUCCESS, err);
53     ASSERT_TRUE(scratch != nullptr);
54 
55     CallBackContext c;
56 
57     // First, scan a matching corpus that's shorter than our min_offset and
58     // ensure it doesn't match.
59     string corpus = "hatstand" + string(80000, '_') + "teakettle";
60     err = hs_scan(db, corpus.c_str(), corpus.length(), 0, scratch, record_cb,
61                   (void *)&c);
62     ASSERT_EQ(HS_SUCCESS, err);
63     ASSERT_EQ(0U, c.matches.size());
64 
65     // Try exactly at the min_offset.
66     corpus = "hatstand" + string(99983, '_') + "teakettle";
67     err = hs_scan(db, corpus.c_str(), corpus.length(), 0, scratch, record_cb,
68                   (void *)&c);
69     ASSERT_EQ(HS_SUCCESS, err);
70     ASSERT_EQ(1U, c.matches.size());
71     ASSERT_EQ(MatchRecord(100000, 0), c.matches[0]);
72 
73     err = hs_free_scratch(scratch);
74     ASSERT_EQ(HS_SUCCESS, err);
75     hs_free_database(db);
76 }
77 
TEST(ExtParam,LargeExactOffset)78 TEST(ExtParam, LargeExactOffset) {
79     hs_expr_ext ext;
80     memset(&ext, 0, sizeof(ext));
81     ext.min_offset = 200000;
82     ext.max_offset = 200000;
83     ext.flags = HS_EXT_FLAG_MIN_OFFSET | HS_EXT_FLAG_MAX_OFFSET;
84 
85     pattern p("hatstand.*teakettle", 0, 0, ext);
86     hs_database_t *db = buildDB(p, HS_MODE_NOSTREAM);
87     ASSERT_TRUE(db != nullptr);
88 
89     hs_scratch_t *scratch = nullptr;
90     hs_error_t err = hs_alloc_scratch(db, &scratch);
91     ASSERT_EQ(HS_SUCCESS, err);
92     ASSERT_TRUE(scratch != nullptr);
93 
94     CallBackContext c;
95 
96     // First, scan a matching corpus that's shorter than our min_offset and
97     // ensure it doesn't match.
98     string corpus = "hatstand" + string(199982, '_') + "teakettle";
99     err = hs_scan(db, corpus.c_str(), corpus.length(), 0, scratch, record_cb,
100                   (void *)&c);
101     ASSERT_EQ(HS_SUCCESS, err);
102     ASSERT_EQ(0U, c.matches.size());
103 
104     // Try the exact match.
105     corpus = "hatstand" + string(199983, '_') + "teakettle";
106     err = hs_scan(db, corpus.c_str(), corpus.length(), 0, scratch, record_cb,
107                   (void *)&c);
108     ASSERT_EQ(HS_SUCCESS, err);
109     ASSERT_EQ(1U, c.matches.size());
110     ASSERT_EQ(MatchRecord(200000, 0), c.matches[0]);
111 
112     // Try one byte too far.
113     c.clear();
114     corpus = "hatstand" + string(199984, '_') + "teakettle";
115     err = hs_scan(db, corpus.c_str(), corpus.length(), 0, scratch, record_cb,
116                   (void *)&c);
117     ASSERT_EQ(HS_SUCCESS, err);
118     ASSERT_EQ(0U, c.matches.size());
119 
120     err = hs_free_scratch(scratch);
121     ASSERT_EQ(HS_SUCCESS, err);
122     hs_free_database(db);
123 }
124 
TEST(ExtParam,LargeMinLength)125 TEST(ExtParam, LargeMinLength) {
126     hs_expr_ext ext;
127     memset(&ext, 0, sizeof(ext));
128     ext.min_length = 100000;
129     ext.flags = HS_EXT_FLAG_MIN_LENGTH;
130 
131     pattern p("hatstand.*teakettle", 0, 0, ext);
132     hs_database_t *db = buildDB(p, HS_MODE_NOSTREAM);
133     ASSERT_TRUE(db != nullptr);
134 
135     hs_scratch_t *scratch = nullptr;
136     hs_error_t err = hs_alloc_scratch(db, &scratch);
137     ASSERT_EQ(HS_SUCCESS, err);
138     ASSERT_TRUE(scratch != nullptr);
139 
140     CallBackContext c;
141 
142     // First, scan a matching corpus that contains a match that's a bit too
143     // short.
144     string corpus = string(10000, '_') + "hatstand" + string(80000, '_') + "teakettle";
145     err = hs_scan(db, corpus.c_str(), corpus.length(), 0, scratch, record_cb,
146                   (void *)&c);
147     ASSERT_EQ(HS_SUCCESS, err);
148     ASSERT_EQ(0U, c.matches.size());
149 
150     // Now, a match of the right length.
151     corpus = string(10000, '_') + "hatstand" + string(99983, '_') + "teakettle";
152     err = hs_scan(db, corpus.c_str(), corpus.length(), 0, scratch, record_cb,
153                   (void *)&c);
154     ASSERT_EQ(HS_SUCCESS, err);
155     ASSERT_EQ(1U, c.matches.size());
156     ASSERT_EQ(MatchRecord(110000, 0), c.matches[0]);
157 
158     err = hs_free_scratch(scratch);
159     ASSERT_EQ(HS_SUCCESS, err);
160     hs_free_database(db);
161 }
162