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, 0},
75 {10, 20, "Wine", FR_MATCHCASE, 4, 0},
76 {20, 10, "Wine", FR_MATCHCASE, 13, 0},
78 /* Case-insensitive */
79 {1, 31, "wInE", FR_DOWN, 4, 0},
80 {1, 31, "Wine", FR_DOWN, 4, 0},
82 /* High-to-low ranges */
83 {20, 5, "Wine", FR_DOWN, -1, 0},
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, 0},
96 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0},
97 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
98 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0},
99 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0},
100 {11, -1, "winewine", FR_WHOLEWORD, 0, 0},
101 {31, -1, "winewine", FR_WHOLEWORD, 23, 0},
104 {5, 200, "XXX", FR_DOWN, -1, 0},
105 {-20, 20, "Wine", FR_DOWN, -1, 0},
106 {-20, 20, "Wine", FR_DOWN, -1, 0},
107 {-15, -20, "Wine", FR_DOWN, -1, 0},
108 {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0},
110 /* Check the case noted in bug 4479 where matches at end aren't recognized */
111 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
112 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
113 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
114 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
115 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
117 /* The backwards case of bug 4479; bounds look right
118 * Fails because backward find is wrong */
119 {19, 20, "WINE", FR_MATCHCASE, 0, 0},
120 {0, 20, "WINE", FR_MATCHCASE, -1, 0}
123 static void check_EM_FINDTEXT(HWND hwnd, char *name, struct find_s *f, int id) {
126 memset(&ft, 0, sizeof(ft));
127 ft.chrg.cpMin = f->start;
128 ft.chrg.cpMax = f->end;
129 ft.lpstrText = f->needle;
130 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
131 ok(findloc == f->expected_loc,
132 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d\n",
133 name, id, f->needle, f->start, f->end, f->flags, findloc);
136 static void check_EM_FINDTEXTEX(HWND hwnd, char *name, struct find_s *f,
140 memset(&ft, 0, sizeof(ft));
141 ft.chrg.cpMin = f->start;
142 ft.chrg.cpMax = f->end;
143 ft.lpstrText = f->needle;
144 findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
145 ok(findloc == f->expected_loc,
146 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
147 name, id, f->needle, f->start, f->end, f->flags, findloc);
148 ok(ft.chrgText.cpMin == f->expected_loc,
149 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %ld\n",
150 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin);
151 ok(ft.chrgText.cpMax == ((f->expected_loc == -1) ? -1
152 : f->expected_loc + strlen(f->needle)),
153 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %ld\n",
154 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax);
157 static void run_tests_EM_FINDTEXT(HWND hwnd, char *name, struct find_s *find,
162 for (i = 0; i < num_tests; i++) {
163 if (find[i]._todo_wine) {
165 check_EM_FINDTEXT(hwnd, name, &find[i], i);
166 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
169 check_EM_FINDTEXT(hwnd, name, &find[i], i);
170 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
175 static void test_EM_FINDTEXT(void)
177 HWND hwndRichEdit = new_richedit(NULL);
179 /* Empty rich edit control */
180 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
181 sizeof(find_tests)/sizeof(struct find_s));
183 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
186 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
187 sizeof(find_tests2)/sizeof(struct find_s));
189 DestroyWindow(hwndRichEdit);
192 static int get_scroll_pos_y(HWND hwnd)
195 SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM) &p);
196 ok(p.x != -1 && p.y != -1, "p.x:%ld p.y:%ld\n", p.x, p.y);
200 static void move_cursor(HWND hwnd, long charindex)
203 cr.cpMax = charindex;
204 cr.cpMin = charindex;
205 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
208 static void line_scroll(HWND hwnd, int amount)
210 SendMessage(hwnd, EM_LINESCROLL, 0, amount);
213 static void test_EM_SCROLLCARET(void)
216 HWND hwndRichEdit = new_richedit(NULL);
217 const char text[] = "aa\n"
218 "this is a long line of text that should be longer than the "
227 /* Can't verify this */
228 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
230 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
232 /* Caret above visible window */
233 line_scroll(hwndRichEdit, 3);
234 prevY = get_scroll_pos_y(hwndRichEdit);
235 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
236 curY = get_scroll_pos_y(hwndRichEdit);
237 ok(prevY != curY, "%d == %d\n", prevY, curY);
239 /* Caret below visible window */
240 move_cursor(hwndRichEdit, sizeof(text) - 1);
241 line_scroll(hwndRichEdit, -3);
242 prevY = get_scroll_pos_y(hwndRichEdit);
243 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
244 curY = get_scroll_pos_y(hwndRichEdit);
245 ok(prevY != curY, "%d == %d\n", prevY, curY);
247 /* Caret in visible window */
248 move_cursor(hwndRichEdit, sizeof(text) - 2);
249 prevY = get_scroll_pos_y(hwndRichEdit);
250 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
251 curY = get_scroll_pos_y(hwndRichEdit);
252 ok(prevY == curY, "%d != %d\n", prevY, curY);
254 /* Caret still in visible window */
255 line_scroll(hwndRichEdit, -1);
256 prevY = get_scroll_pos_y(hwndRichEdit);
257 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
258 curY = get_scroll_pos_y(hwndRichEdit);
259 ok(prevY == curY, "%d != %d\n", prevY, curY);
261 DestroyWindow(hwndRichEdit);
264 static void test_EM_SETTEXTMODE(void)
266 HWND hwndRichEdit = new_richedit(NULL);
267 CHARFORMAT2 cf2, cf2test;
271 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
272 /*Insert text into the control*/
274 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
276 /*Attempt to change the control to plain text mode*/
277 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
278 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
280 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
281 If rich text is pasted, it should have the same formatting as the rest
282 of the text in the control*/
285 *NOTE: If the default text was already italicized, the test will simply
286 reverse; in other words, it will copy a regular "wine" into a plain
287 text window that uses an italicized format*/
288 cf2.cbSize = sizeof(CHARFORMAT2);
289 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
292 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
293 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
295 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
296 however, SCF_ALL has been implemented*/
297 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
298 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
300 /*Select the string "wine"*/
303 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
305 /*Copy the italicized "wine" to the clipboard*/
306 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
308 /*Reset the formatting to default*/
309 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
310 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
312 /*Clear the text in the control*/
313 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
315 /*Switch to Plain Text Mode*/
316 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
317 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
319 /*Input "wine" again in normal format*/
320 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
322 /*Paste the italicized "wine" into the control*/
323 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
325 /*Select a character from the first "wine" string*/
328 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
330 /*Retrieve its formatting*/
331 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
334 /*Select a character from the second "wine" string*/
337 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
339 /*Retrieve its formatting*/
340 cf2test.cbSize = sizeof(CHARFORMAT2);
341 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
344 /*Compare the two formattings*/
345 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
346 "two formats found in plain text mode - cf2.dwEffects: %f cf2test.dwEffects: %f\n",(double) cf2.dwEffects, (double) cf2test.dwEffects);
347 /*Test TM_RICHTEXT by: switching back to Rich Text mode
348 printing "wine" in the current format(normal)
349 pasting "wine" from the clipboard(italicized)
350 comparing the two formats(should differ)*/
352 /*Attempt to switch with text in control*/
353 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
354 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
357 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
359 /*Switch into Rich Text mode*/
360 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
361 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
363 /*Print "wine" in normal formatting into the control*/
364 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
366 /*Paste italicized "wine" into the control*/
367 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
369 /*Select text from the first "wine" string*/
372 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
374 /*Retrieve its formatting*/
375 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
378 /*Select text from the second "wine" string*/
381 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
383 /*Retrieve its formatting*/
384 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
387 /*Test that the two formattings are not the same*/
388 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
389 "expected different formats - cf2.dwMask: %f, cf2test.dwMask: %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
390 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
392 DestroyWindow(hwndRichEdit);
395 static void test_TM_PLAINTEXT()
397 /*Tests plain text properties*/
399 HWND hwndRichEdit = new_richedit(NULL);
400 CHARFORMAT2 cf2, cf2test;
403 /*Switch to plain text mode*/
405 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
406 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
408 /*Fill control with text*/
410 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
412 /*Select some text and bold it*/
416 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
417 cf2.cbSize = sizeof(CHARFORMAT2);
418 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
421 cf2.dwMask = CFM_BOLD | cf2.dwMask;
422 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
424 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
426 /*Get the formatting of those characters*/
428 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
430 /*Get the formatting of some other characters*/
431 cf2test.cbSize = sizeof(CHARFORMAT2);
434 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
435 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
437 /*Test that they are the same as plain text allows only one formatting*/
439 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
440 "two selections' formats differ - cf2.dwMask: %f, cf2test.dwMask %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
441 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
443 /*Fill the control with a "wine" string, which when inserted will be bold*/
445 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
447 /*Copy the bolded "wine" string*/
451 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
452 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
454 /*Swap back to rich text*/
456 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
457 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
459 /*Set the default formatting to bold italics*/
461 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
462 cf2.dwMask |= CFM_ITALIC;
463 cf2.dwEffects ^= CFE_ITALIC;
464 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
466 /*Set the text in the control to "wine", which will be bold and italicized*/
468 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
470 /*Paste the plain text "wine" string, which should take the insert
471 formatting, which at the moment is bold italics*/
473 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
475 /*Select the first "wine" string and retrieve its formatting*/
479 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
480 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
482 /*Select the second "wine" string and retrieve its formatting*/
486 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
487 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
489 /*Compare the two formattings. They should be the same.*/
491 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
492 "Copied text retained formatting - cf2.dwMask: %f, cf2test.dwMask: %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
493 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
494 DestroyWindow(hwndRichEdit);
497 /* FIXME: Extra '\r' appended at end of gotten text*/
498 static void test_WM_GETTEXT()
500 HWND hwndRichEdit = new_richedit(NULL);
501 static const char text[] = "Hello. My name is RichEdit!";
502 char buffer[1024] = {0};
505 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
506 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
507 result = strcmp(buffer,text);
510 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
514 /* FIXME: need to test unimplemented options and robustly test wparam */
515 static void test_EM_SETOPTIONS()
517 HWND hwndRichEdit = new_richedit(NULL);
518 static const char text[] = "Hello. My name is RichEdit!";
519 char buffer[1024] = {0};
521 /* NEGATIVE TESTING - NO OPTIONS SET */
522 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
523 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
525 /* testing no readonly by sending 'a' to the control*/
526 SetFocus(hwndRichEdit);
527 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
528 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
530 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
531 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
533 /* READONLY - sending 'a' to the control */
534 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
535 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
536 SetFocus(hwndRichEdit);
537 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
538 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
539 ok(buffer[0]==text[0],
540 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
542 DestroyWindow(hwndRichEdit);
545 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url)
547 CHARFORMAT2W text_format;
548 int link_present = 0;
549 text_format.cbSize = sizeof(text_format);
550 SendMessage(hwnd, EM_SETSEL, 0, 0);
551 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
552 link_present = text_format.dwEffects & CFE_LINK;
554 { /* control text is url; should get CFE_LINK */
555 ok(0 != link_present, "URL Case: CFE_LINK not set.\n");
559 ok(0 == link_present, "Non-URL Case: CFE_LINK set.\n");
563 static HWND new_static_wnd(HWND parent) {
564 return new_window("Static", 0, parent);
567 static void test_EM_AUTOURLDETECT(void)
574 {"http://www.winehq.org", 1},
575 {"http//winehq.org", 0},
576 {"ww.winehq.org", 0},
577 {"www.winehq.org", 1},
578 {"ftp://192.168.1.1", 1},
579 {"ftp//192.168.1.1", 0},
580 {"mailto:your@email.com", 1},
581 {"prospero:prosperoserver", 1},
583 {"news:newserver", 1},
584 {"wais:waisserver", 1}
589 HWND hwndRichEdit, parent;
591 parent = new_static_wnd(NULL);
592 hwndRichEdit = new_richedit(parent);
593 /* Try and pass EM_AUTOURLDETECT some test wParam values */
594 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
595 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
596 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
597 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
598 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
599 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
600 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
601 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
602 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
603 /* for each url, check the text to see if CFE_LINK effect is present */
604 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
605 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
606 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
607 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
608 check_CFE_LINK_rcvd(hwndRichEdit, 0);
609 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
610 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
611 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
612 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url);
614 DestroyWindow(hwndRichEdit);
615 DestroyWindow(parent);
618 static void test_EM_SCROLL()
621 int r; /* return value */
622 int expr; /* expected return value */
623 HWND hwndRichEdit = new_richedit(NULL);
624 int y_before, y_after; /* units of lines of text */
626 /* test a richedit box containing a single line of text */
627 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
629 for (i = 0; i < 4; i++) {
630 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
632 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
633 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
634 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
635 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
636 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
637 "(i == %d)\n", y_after, i);
641 * test a richedit box that will scroll. There are two general
642 * cases: the case without any long lines and the case with a long
645 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
647 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
649 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
650 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
651 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
652 "LONG LINE \nb\nc\nd\ne");
653 for (j = 0; j < 12; j++) /* reset scrol position to top */
654 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
656 /* get first visible line */
657 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
658 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
660 /* get new current first visible line */
661 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
663 ok(((r & 0xffffff00) == 0x00010000) &&
664 ((r & 0x000000ff) != 0x00000000),
665 "EM_SCROLL page down didn't scroll by a small positive number of "
666 "lines (r == 0x%08x)\n", r);
667 ok(y_after > y_before, "EM_SCROLL page down not functioning "
668 "(line %d scrolled to line %d\n", y_before, y_after);
672 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
673 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
674 ok(((r & 0xffffff00) == 0x0001ff00),
675 "EM_SCROLL page up didn't scroll by a small negative number of lines "
676 "(r == 0x%08x)\n", r);
677 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
678 "%d scrolled to line %d\n", y_before, y_after);
682 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
684 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
686 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
687 "(r == 0x%08x)\n", r);
688 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
689 "1 line (%d scrolled to %d)\n", y_before, y_after);
693 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
695 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
697 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
698 "(r == 0x%08x)\n", r);
699 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
700 "line (%d scrolled to %d)\n", y_before, y_after);
704 r = SendMessage(hwndRichEdit, EM_SCROLL,
705 SB_LINEUP, 0); /* lineup beyond top */
707 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
710 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
711 ok(y_before == y_after,
712 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
716 r = SendMessage(hwndRichEdit, EM_SCROLL,
717 SB_PAGEUP, 0);/*page up beyond top */
719 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
722 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
723 ok(y_before == y_after,
724 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
726 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
727 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
728 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
729 r = SendMessage(hwndRichEdit, EM_SCROLL,
730 SB_PAGEDOWN, 0); /* page down beyond bot */
731 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
734 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
735 ok(y_before == y_after,
736 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
739 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
740 SendMessage(hwndRichEdit, EM_SCROLL,
741 SB_LINEDOWN, 0); /* line down beyond bot */
742 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
745 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
746 ok(y_before == y_after,
747 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
750 DestroyWindow(hwndRichEdit);
758 /* Must explicitly LoadLibrary(). The test has no references to functions in
759 * RICHED20.DLL, so the linker doesn't actually link to it. */
760 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
761 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
763 test_EM_SCROLLCARET();
765 test_EM_SETTEXTMODE();
767 test_EM_SETOPTIONS();
769 test_EM_AUTOURLDETECT();
771 /* Set the environment variable WINETEST_RICHED20 to keep windows
772 * responsive and open for 30 seconds. This is useful for debugging.
774 * The message pump uses PeekMessage() to empty the queue and then sleeps for
775 * 50ms before retrying the queue. */
776 end = time(NULL) + 30;
777 if (getenv( "WINETEST_RICHED20" )) {
778 while (time(NULL) < end) {
779 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
780 TranslateMessage(&msg);
781 DispatchMessage(&msg);
788 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());