2 * Unit test suite for rich edit control
4 * Copyright 2006 Google (Thomas Kho)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <wine/test.h>
26 static HMODULE hmoduleRichEdit
;
28 static HWND
new_window(LPCTSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
30 hwnd
= CreateWindow(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
31 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
32 hmoduleRichEdit
, NULL
);
33 ok(hwnd
!= NULL
, "class: %s, error: %d\n", lpClassName
, (int) GetLastError());
37 static HWND
new_richedit(HWND parent
) {
38 return new_window(RICHEDIT_CLASS
, ES_MULTILINE
, parent
);
41 static const char haystack
[] = "WINEWine wineWine wine WineWine";
53 struct find_s find_tests
[] = {
54 /* Find in empty text */
55 {0, -1, "foo", FR_DOWN
, -1, 0},
56 {0, -1, "foo", 0, -1, 0},
57 {0, -1, "", FR_DOWN
, -1, 0},
58 {20, 5, "foo", FR_DOWN
, -1, 0},
59 {5, 20, "foo", FR_DOWN
, -1, 0}
62 struct find_s find_tests2
[] = {
64 {0, -1, "foo", FR_DOWN
| FR_MATCHCASE
, -1, 0},
65 {5, 20, "WINE", FR_DOWN
| FR_MATCHCASE
, -1, 0},
67 /* Subsequent finds */
68 {0, -1, "Wine", FR_DOWN
| FR_MATCHCASE
, 4, 0},
69 {5, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 13, 0},
70 {14, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23, 0},
71 {24, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27, 0},
74 {19, 20, "Wine", FR_MATCHCASE
, 13, 1},
75 {10, 20, "Wine", FR_MATCHCASE
, 4, 1},
76 {20, 10, "Wine", FR_MATCHCASE
, 13, 0},
78 /* Case-insensitive */
79 {1, 31, "wInE", FR_DOWN
, 4, 1},
80 {1, 31, "Wine", FR_DOWN
, 4, 0},
82 /* High-to-low ranges */
83 {20, 5, "Wine", FR_DOWN
, -1, 1},
84 {2, 1, "Wine", FR_DOWN
, -1, 0},
85 {30, 29, "Wine", FR_DOWN
, -1, 0},
86 {20, 5, "Wine", 0, 13, 0},
89 {5, 10, "", FR_DOWN
, -1, 0},
90 {10, 5, "", FR_DOWN
, -1, 0},
91 {0, -1, "", FR_DOWN
, -1, 0},
92 {10, 5, "", 0, -1, 0},
94 /* Whole-word search */
95 {0, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18, 1},
96 {0, -1, "win", FR_DOWN
| FR_WHOLEWORD
, -1, 1},
99 {-20, 20, "Wine", FR_DOWN
, -1, 0},
100 {-20, 20, "Wine", FR_DOWN
, -1, 0},
101 {-15, -20, "Wine", FR_DOWN
, -1, 0},
102 {1<<12, 1<<13, "Wine", FR_DOWN
, -1, 0},
104 /* Check the case noted in bug 4479 where matches at end aren't recognized */
105 {23, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23, 0},
106 {27, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27, 0},
107 {27, 32, "Wine", FR_DOWN
| FR_MATCHCASE
, 27, 0},
108 {13, 31, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23, 0},
109 {13, 32, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23, 0},
111 /* The backwards case of bug 4479; bounds look right
112 * Fails because backward find is wrong */
113 {19, 20, "WINE", FR_MATCHCASE
, 0, 1},
114 {0, 20, "WINE", FR_MATCHCASE
, -1, 1}
117 static void check_EM_FINDTEXT(HWND hwnd
, char *name
, struct find_s
*f
, int id
) {
120 memset(&ft
, 0, sizeof(ft
));
121 ft
.chrg
.cpMin
= f
->start
;
122 ft
.chrg
.cpMax
= f
->end
;
123 ft
.lpstrText
= f
->needle
;
124 findloc
= SendMessage(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
) &ft
);
125 ok(findloc
== f
->expected_loc
,
126 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d\n",
127 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
130 static void check_EM_FINDTEXTEX(HWND hwnd
, char *name
, struct find_s
*f
,
134 memset(&ft
, 0, sizeof(ft
));
135 ft
.chrg
.cpMin
= f
->start
;
136 ft
.chrg
.cpMax
= f
->end
;
137 ft
.lpstrText
= f
->needle
;
138 findloc
= SendMessage(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
) &ft
);
139 ok(findloc
== f
->expected_loc
,
140 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
141 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
142 ok(ft
.chrgText
.cpMin
== f
->expected_loc
,
143 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %ld\n",
144 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ft
.chrgText
.cpMin
);
145 ok(ft
.chrgText
.cpMax
== ((f
->expected_loc
== -1) ? -1
146 : f
->expected_loc
+ strlen(f
->needle
)),
147 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %ld\n",
148 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ft
.chrgText
.cpMax
);
151 static void run_tests_EM_FINDTEXT(HWND hwnd
, char *name
, struct find_s
*find
,
156 for (i
= 0; i
< num_tests
; i
++) {
157 if (find
[i
]._todo_wine
) {
159 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
);
160 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
);
163 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
);
164 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
);
169 static void test_EM_FINDTEXT(void)
171 HWND hwndRichEdit
= new_richedit(NULL
);
173 /* Empty rich edit control */
174 run_tests_EM_FINDTEXT(hwndRichEdit
, "1", find_tests
,
175 sizeof(find_tests
)/sizeof(struct find_s
));
177 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) haystack
);
180 run_tests_EM_FINDTEXT(hwndRichEdit
, "2", find_tests2
,
181 sizeof(find_tests2
)/sizeof(struct find_s
));
183 DestroyWindow(hwndRichEdit
);
186 static int get_scroll_pos_y(HWND hwnd
)
189 SendMessage(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
) &p
);
190 ok(p
.x
!= -1 && p
.y
!= -1, "p.x:%ld p.y:%ld\n", p
.x
, p
.y
);
194 static void move_cursor(HWND hwnd
, long charindex
)
197 cr
.cpMax
= charindex
;
198 cr
.cpMin
= charindex
;
199 SendMessage(hwnd
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
202 static void line_scroll(HWND hwnd
, int amount
)
204 SendMessage(hwnd
, EM_LINESCROLL
, 0, amount
);
207 static void test_EM_SCROLLCARET(void)
210 HWND hwndRichEdit
= new_richedit(NULL
);
211 const char text
[] = "aa\n"
212 "this is a long line of text that should be longer than the "
221 /* Can't verify this */
222 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
224 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
226 /* Caret above visible window */
227 line_scroll(hwndRichEdit
, 3);
228 prevY
= get_scroll_pos_y(hwndRichEdit
);
229 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
230 curY
= get_scroll_pos_y(hwndRichEdit
);
231 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
233 /* Caret below visible window */
234 move_cursor(hwndRichEdit
, sizeof(text
) - 1);
235 line_scroll(hwndRichEdit
, -3);
236 prevY
= get_scroll_pos_y(hwndRichEdit
);
237 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
238 curY
= get_scroll_pos_y(hwndRichEdit
);
239 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
241 /* Caret in visible window */
242 move_cursor(hwndRichEdit
, sizeof(text
) - 2);
243 prevY
= get_scroll_pos_y(hwndRichEdit
);
244 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
245 curY
= get_scroll_pos_y(hwndRichEdit
);
246 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
248 /* Caret still in visible window */
249 line_scroll(hwndRichEdit
, -1);
250 prevY
= get_scroll_pos_y(hwndRichEdit
);
251 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
252 curY
= get_scroll_pos_y(hwndRichEdit
);
253 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
255 DestroyWindow(hwndRichEdit
);
263 /* Must explicitly LoadLibrary(). The test has no references to functions in
264 * RICHED20.DLL, so the linker doesn't actually link to it. */
265 hmoduleRichEdit
= LoadLibrary("RICHED20.DLL");
266 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
269 test_EM_SCROLLCARET();
271 /* Set the environment variable WINETEST_RICHED20 to keep windows
272 * responsive and open for 30 seconds. This is useful for debugging.
274 * The message pump uses PeekMessage() to empty the queue and then sleeps for
275 * 50ms before retrying the queue. */
276 end
= time(NULL
) + 30;
277 if (getenv( "WINETEST_RICHED20" )) {
278 while (time(NULL
) < end
) {
279 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
280 TranslateMessage(&msg
);
281 DispatchMessage(&msg
);
288 ok(FreeLibrary(hmoduleRichEdit
) != 0, "error: %d\n", (int) GetLastError());