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, 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, 0},
114 {0, 20, "WINE", FR_MATCHCASE, -1, 0}
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);
258 static void test_EM_SETTEXTMODE(void)
260 HWND hwndRichEdit = new_richedit(NULL);
261 CHARFORMAT2 cf2, cf2test;
265 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
266 /*Insert text into the control*/
268 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
270 /*Attempt to change the control to plain text mode*/
271 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
272 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
274 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
275 If rich text is pasted, it should have the same formatting as the rest
276 of the text in the control*/
279 *NOTE: If the default text was already italicized, the test will simply
280 reverse; in other words, it will copy a regular "wine" into a plain
281 text window that uses an italicized format*/
282 cf2.cbSize = sizeof(CHARFORMAT2);
283 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
286 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
287 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
289 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
290 however, SCF_ALL has been implemented*/
291 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
292 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
294 /*Select the string "wine"*/
297 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
299 /*Copy the italicized "wine" to the clipboard*/
300 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
302 /*Reset the formatting to default*/
303 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
304 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
306 /*Clear the text in the control*/
307 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
309 /*Switch to Plain Text Mode*/
310 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
311 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
313 /*Input "wine" again in normal format*/
314 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
316 /*Paste the italicized "wine" into the control*/
317 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
319 /*Select a character from the first "wine" string*/
322 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
324 /*Retrieve its formatting*/
325 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
328 /*Select a character from the second "wine" string*/
331 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
333 /*Retrieve its formatting*/
334 cf2test.cbSize = sizeof(CHARFORMAT2);
335 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
338 /*Compare the two formattings*/
339 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
340 "two formats found in plain text mode - cf2.dwEffects: %f cf2test.dwEffects: %f\n",(double) cf2.dwEffects, (double) cf2test.dwEffects);
341 /*Test TM_RICHTEXT by: switching back to Rich Text mode
342 printing "wine" in the current format(normal)
343 pasting "wine" from the clipboard(italicized)
344 comparing the two formats(should differ)*/
346 /*Attempt to switch with text in control*/
347 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
348 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
351 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
353 /*Switch into Rich Text mode*/
354 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
355 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
357 /*Print "wine" in normal formatting into the control*/
358 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
360 /*Paste italicized "wine" into the control*/
361 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
363 /*Select text from the first "wine" string*/
366 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
368 /*Retrieve its formatting*/
369 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
372 /*Select text from the second "wine" string*/
375 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
377 /*Retrieve its formatting*/
378 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
381 /*Test that the two formattings are not the same*/
382 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
383 "expected different formats - cf2.dwMask: %f, cf2test.dwMask: %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
384 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
386 DestroyWindow(hwndRichEdit);
389 static void test_TM_PLAINTEXT()
391 /*Tests plain text properties*/
393 HWND hwndRichEdit = new_richedit(NULL);
394 CHARFORMAT2 cf2, cf2test;
397 /*Switch to plain text mode*/
399 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
400 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
402 /*Fill control with text*/
404 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
406 /*Select some text and bold it*/
410 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
411 cf2.cbSize = sizeof(CHARFORMAT2);
412 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
415 cf2.dwMask = CFM_BOLD | cf2.dwMask;
416 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
418 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
420 /*Get the formatting of those characters*/
422 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
424 /*Get the formatting of some other characters*/
425 cf2test.cbSize = sizeof(CHARFORMAT2);
428 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
429 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
431 /*Test that they are the same as plain text allows only one formatting*/
433 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
434 "two selections' formats differ - cf2.dwMask: %f, cf2test.dwMask %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
435 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
437 /*Fill the control with a "wine" string, which when inserted will be bold*/
439 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
441 /*Copy the bolded "wine" string*/
445 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
446 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
448 /*Swap back to rich text*/
450 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
451 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
453 /*Set the default formatting to bold italics*/
455 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
456 cf2.dwMask |= CFM_ITALIC;
457 cf2.dwEffects ^= CFE_ITALIC;
458 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
460 /*Set the text in the control to "wine", which will be bold and italicized*/
462 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
464 /*Paste the plain text "wine" string, which should take the insert
465 formatting, which at the moment is bold italics*/
467 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
469 /*Select the first "wine" string and retrieve its formatting*/
473 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
474 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
476 /*Select the second "wine" string and retrieve its formatting*/
480 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
481 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
483 /*Compare the two formattings. They should be the same.*/
485 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
486 "Copied text retained formatting - cf2.dwMask: %f, cf2test.dwMask: %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
487 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
488 DestroyWindow(hwndRichEdit);
491 /* FIXME: Extra '\r' appended at end of gotten text*/
492 static void test_WM_GETTEXT()
494 HWND hwndRichEdit = new_richedit(NULL);
495 static const char text[] = "Hello. My name is RichEdit!";
496 char buffer[1024] = {0};
499 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
500 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
501 result = strcmp(buffer,text);
504 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
508 /* FIXME: need to test unimplemented options and robustly test wparam */
509 static void test_EM_SETOPTIONS()
511 HWND hwndRichEdit = new_richedit(NULL);
512 static const char text[] = "Hello. My name is RichEdit!";
513 char buffer[1024] = {0};
515 /* NEGATIVE TESTING - NO OPTIONS SET */
516 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
517 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
519 /* testing no readonly by sending 'a' to the control*/
520 SetFocus(hwndRichEdit);
521 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
522 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
524 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
525 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
527 /* READONLY - sending 'a' to the control */
528 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
529 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
530 SetFocus(hwndRichEdit);
531 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
532 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
533 ok(buffer[0]==text[0],
534 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
536 DestroyWindow(hwndRichEdit);
539 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url)
541 CHARFORMAT2W text_format;
542 int link_present = 0;
543 text_format.cbSize = sizeof(text_format);
544 SendMessage(hwnd, EM_SETSEL, 0, 0);
545 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
546 link_present = text_format.dwEffects & CFE_LINK;
548 { /* control text is url; should get CFE_LINK */
549 ok(0 != link_present, "URL Case: CFE_LINK not set.\n");
553 ok(0 == link_present, "Non-URL Case: CFE_LINK set.\n");
557 static HWND new_static_wnd(HWND parent) {
558 return new_window("Static", 0, parent);
561 static void test_EM_AUTOURLDETECT(void)
568 {"http://www.winehq.org", 1},
569 {"http//winehq.org", 0},
570 {"ww.winehq.org", 0},
571 {"www.winehq.org", 1},
572 {"ftp://192.168.1.1", 1},
573 {"ftp//192.168.1.1", 0},
574 {"mailto:your@email.com", 1},
575 {"prospero:prosperoserver", 1},
577 {"news:newserver", 1},
578 {"wais:waisserver", 1}
583 HWND hwndRichEdit, parent;
585 parent = new_static_wnd(NULL);
586 hwndRichEdit = new_richedit(parent);
587 /* Try and pass EM_AUTOURLDETECT some test wParam values */
588 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
589 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
590 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
591 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
592 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
593 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
594 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
595 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
596 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
597 /* for each url, check the text to see if CFE_LINK effect is present */
598 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
599 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
600 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
601 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
602 check_CFE_LINK_rcvd(hwndRichEdit, 0);
603 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
604 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
605 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
606 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url);
608 DestroyWindow(hwndRichEdit);
609 DestroyWindow(parent);
612 static void test_EM_SCROLL()
615 int r; /* return value */
616 int expr; /* expected return value */
617 HWND hwndRichEdit = new_richedit(NULL);
618 int y_before, y_after; /* units of lines of text */
620 /* test a richedit box containing a single line of text */
621 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
623 for (i = 0; i < 4; i++) {
624 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
626 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
627 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
628 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
629 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
630 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
631 "(i == %d)\n", y_after, i);
635 * test a richedit box that will scroll. There are two general
636 * cases: the case without any long lines and the case with a long
639 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
641 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
643 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
644 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
645 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
646 "LONG LINE \nb\nc\nd\ne");
647 for (j = 0; j < 12; j++) /* reset scrol position to top */
648 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
650 /* get first visible line */
651 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
652 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
654 /* get new current first visible line */
655 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
657 ok(((r & 0xffffff00) == 0x00010000) &&
658 ((r & 0x000000ff) != 0x00000000),
659 "EM_SCROLL page down didn't scroll by a small positive number of "
660 "lines (r == 0x%08x)\n", r);
661 ok(y_after > y_before, "EM_SCROLL page down not functioning "
662 "(line %d scrolled to line %d\n", y_before, y_after);
666 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
667 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
668 ok(((r & 0xffffff00) == 0x0001ff00),
669 "EM_SCROLL page up didn't scroll by a small negative number of lines "
670 "(r == 0x%08x)\n", r);
671 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
672 "%d scrolled to line %d\n", y_before, y_after);
676 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
678 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
680 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
681 "(r == 0x%08x)\n", r);
682 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
683 "1 line (%d scrolled to %d)\n", y_before, y_after);
687 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
689 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
691 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
692 "(r == 0x%08x)\n", r);
693 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
694 "line (%d scrolled to %d)\n", y_before, y_after);
698 r = SendMessage(hwndRichEdit, EM_SCROLL,
699 SB_LINEUP, 0); /* lineup beyond top */
701 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
704 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
705 ok(y_before == y_after,
706 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
710 r = SendMessage(hwndRichEdit, EM_SCROLL,
711 SB_PAGEUP, 0);/*page up beyond top */
713 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
716 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
717 ok(y_before == y_after,
718 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
720 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
721 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
722 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
723 r = SendMessage(hwndRichEdit, EM_SCROLL,
724 SB_PAGEDOWN, 0); /* page down beyond bot */
725 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
728 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
729 ok(y_before == y_after,
730 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
733 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
734 SendMessage(hwndRichEdit, EM_SCROLL,
735 SB_LINEDOWN, 0); /* line down beyond bot */
736 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
739 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
740 ok(y_before == y_after,
741 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
744 DestroyWindow(hwndRichEdit);
752 /* Must explicitly LoadLibrary(). The test has no references to functions in
753 * RICHED20.DLL, so the linker doesn't actually link to it. */
754 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
755 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
757 test_EM_SCROLLCARET();
759 test_EM_SETTEXTMODE();
761 test_EM_SETOPTIONS();
763 test_EM_AUTOURLDETECT();
765 /* Set the environment variable WINETEST_RICHED20 to keep windows
766 * responsive and open for 30 seconds. This is useful for debugging.
768 * The message pump uses PeekMessage() to empty the queue and then sleeps for
769 * 50ms before retrying the queue. */
770 end = time(NULL) + 30;
771 if (getenv( "WINETEST_RICHED20" )) {
772 while (time(NULL) < end) {
773 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
774 TranslateMessage(&msg);
775 DispatchMessage(&msg);
782 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());