1 /*
2  * Copyright (C) 2008 Aliaksey Kandratsenka
3  *
4  * This program is free software: you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see
16  * `http://www.gnu.org/licenses/'.
17  */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <memory.h>
21 #include <check.h>
22 
23 #include "scorer.h"
24 
25 static
26 struct scorer_query qry;
27 
28 static
_assert_scores(char * file,int line,int expected_score,char * string,char * pattern,unsigned * expected_match)29 void	_assert_scores(char *file, int line, int expected_score, char *string, char *pattern, unsigned *expected_match)
30 {
31 	int pat_len = strlen(pattern);
32 	int real_score;
33 	int i;
34 	unsigned match[pat_len];
35 
36 	qry.pattern = pattern;
37 	real_score = score_string(string, &qry, strlen(string), match);
38 	if (real_score != expected_score) {
39 		_ck_assert_msg(0, file, line, 0, "scoring %s against pattern %s should score 0x%x, not 0x%x",
40 			       string, pattern, expected_score, real_score,
41 			       0);
42 		return;
43 	}
44 	if (expected_match)
45 		for (i=0;i<pat_len;i++)
46 			if (expected_match[i] != match[i])
47 				_ck_assert_msg(0, file, line, 0,
48 					       "match differs in pos %d. Expected %d, got %d",
49 					       i, expected_match[i], match[i], 0);
50 	_ck_assert_msg(1, __FILE__, __LINE__, "cannot happen", 0);
51 }
52 
53 #define assert_scores(score, string, pattern, match) _assert_scores(__FILE__, __LINE__, (score), (string), (pattern), (match))
54 #define M(...) ((unsigned[]){__VA_ARGS__})
55 
START_TEST(test_empty_string)56 START_TEST(test_empty_string)
57 {
58 	int score;
59 
60 	qry.pattern = "a";
61 	score = score_string("", &qry, 0, 0);
62 
63 	fail_unless(score == -1, NULL);
64 }
65 END_TEST
66 
START_TEST(test_capital_pattern_chars_work)67 START_TEST(test_capital_pattern_chars_work)
68 {
69 	assert_scores(0x200000, "flexi_record", "FR", M(0,6));
70 }
71 END_TEST
72 
START_TEST(test_char_after_delimiter_handling)73 START_TEST(test_char_after_delimiter_handling)
74 {
75 	/* char right after delimiter must match start of word */
76 	assert_scores(0x200400, "some.owo.word", "s.wo", M(0,4,9,10));
77 	assert_scores(0x200400, "some.owoWord", "s.wo", M(0,4,8,9));
78 
79 	/* char right after delimiter must match start of word */
80 	assert_scores(0x200400, "some-owoWord", "s-wo", M(0,SCORER_MATCH_NONE,8,9));
81 }
82 END_TEST
83 
START_TEST(test_single_char_matches_work)84 START_TEST(test_single_char_matches_work)
85 {
86 	assert_scores(0, "asd", "s", M(1));
87 	assert_scores(0, "asd", "d", M(2));
88 	assert_scores(0x100000,"asd", "a", 0);
89 	assert_scores(0x100000, "asd", "ad", M(0,2));
90 	assert_scores(-1, "asd", "q", 0);
91 	assert_scores(-1, "asd", "ds", 0);
92 	assert_scores(0x400, "asd", "sd", M(1,2));
93 	assert_scores(0x100000, "asdaaas", "a", M(0));
94 }
95 END_TEST
96 
START_TEST(test_slash_handling)97 START_TEST(test_slash_handling)
98 {
99 	qry.right_match = 1;
100 	assert_scores(0x100201, "activerecord/lib/active_record", "ar", M(17,24));
101 	qry.right_match = 0;
102 	assert_scores(0x100000, "base.rb", "b", M(0));
103 	/* '/' works */
104 	assert_scores(0x200201, "activerecord/lib/octive_record/base.rb", "ar/b", M(0,24,30,31));
105 	qry.right_match = 1;
106 	assert_scores(0x200201, "activerecord/lib/octive_record/base.rb", "ar/b", M(0,24,30,31));
107 	qry.right_match = 0;
108 }
109 END_TEST
110 
START_TEST(test_right_match)111 START_TEST(test_right_match)
112 {
113 	qry.right_match = 1;
114 
115 	assert_scores(0, "sabababa", "a", M(7));
116 	assert_scores(0, "sabababa", "aa", M(5,7));
117 
118 	assert_scores(0, "sabababa", "b", M(6));
119 	assert_scores(0, "sabababa", "bb", M(4,6));
120 
121 	qry.right_match = 0;
122 
123 	assert_scores(0, "sabababa", "a", M(1));
124 	assert_scores(0, "sabababa", "aa", M(1,3));
125 
126 	assert_scores(0, "sabababa", "b", M(2));
127 	assert_scores(0, "sabababa", "bb", M(2,4));
128 }
129 END_TEST
130 
START_TEST(test_scorer_optimization_bug)131 START_TEST(test_scorer_optimization_bug)
132 {
133 	assert_scores(0x0101201, "ClassLoadingImpl.c", "clload", 0);
134 	assert_scores(0x0100800, "play", "pla", 0);
135 }
136 END_TEST
137 
138 static
setup(void)139 void setup(void)
140 {
141 	qry.right_match = 0;
142 }
143 
scorer_suite(void)144 Suite *scorer_suite (void)
145 {
146 	Suite *s = suite_create ("Scorer");
147 
148 #define T(name)							\
149 	do {							\
150 		TCase *tc = tcase_create(#name);		\
151 		tcase_add_test(tc, name);			\
152 		tcase_add_checked_fixture(tc, setup, 0);	\
153 		suite_add_tcase(s, tc);				\
154 	} while (0)
155 
156 	T(test_char_after_delimiter_handling);
157 	T(test_capital_pattern_chars_work);
158 	T(test_single_char_matches_work);
159 	T(test_slash_handling);
160 	T(test_right_match);
161 	T(test_empty_string);
162 	T(test_scorer_optimization_bug);
163 
164 	return s;
165 #undef T
166 }
167 
main(void)168 int main(void)
169 {
170 	int number_failed;
171 	Suite *s = scorer_suite();
172 	SRunner *sr = srunner_create(s);
173 
174 	prepare_scorer();
175 
176 	srunner_run_all(sr, CK_NORMAL);
177 
178 	number_failed = srunner_ntests_failed(sr);
179 	srunner_free (sr);
180 
181 	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
182 }
183