user: Tests for when the menu is incorrect because of duplication of a
[wine] / dlls / user / tests / edit.c
1 /* Unit test suite for edit control.
2  *
3  * Copyright 2004 Vitaliy Margolen
4  * Copyright 2005 C. Scott Ananian
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <assert.h>
22 #include <windows.h>
23 #include <windowsx.h>
24 #include <commctrl.h>
25
26 #include "wine/test.h"
27
28 #ifndef ES_COMBO
29 #define ES_COMBO 0x200
30 #endif
31
32 #define ID_EDITTEST2 99
33 #define MAXLEN 200
34
35 struct edit_notify {
36     int en_change, en_maxtext, en_update;
37 };
38
39 static struct edit_notify notifications;
40
41 static HINSTANCE hinst;
42 static HWND hwndET2;
43 static char szEditTest2Class[] = "EditTest2Class";
44 static char szEditTest3Class[] = "EditTest3Class";
45 static char szEditTextPositionClass[] = "EditTextPositionWindowClass";
46
47 static HWND create_editcontrol (DWORD style, DWORD exstyle)
48 {
49     HWND handle;
50
51     handle = CreateWindowEx(exstyle,
52                           "EDIT",
53                           "Test Text",
54                           ES_AUTOHSCROLL | ES_AUTOVSCROLL | style,
55                           10, 10, 300, 300,
56                           NULL, NULL, hinst, NULL);
57     assert (handle);
58     if (winetest_interactive)
59         ShowWindow (handle, SW_SHOW);
60     return handle;
61 }
62
63 static HWND create_child_editcontrol (DWORD style, DWORD exstyle)
64 {
65     HWND parentWnd;
66     HWND editWnd;
67     RECT rect;
68     
69     rect.left = 0;
70     rect.top = 0;
71     rect.right = 300;
72     rect.bottom = 300;
73     assert(AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE));
74     
75     parentWnd = CreateWindowEx(0,
76                             szEditTextPositionClass,
77                             "Edit Test",
78                             WS_OVERLAPPEDWINDOW,
79                             CW_USEDEFAULT, CW_USEDEFAULT,
80                             rect.right - rect.left, rect.bottom - rect.top,
81                             NULL, NULL, hinst, NULL);
82     assert(parentWnd);
83
84     editWnd = CreateWindowEx(exstyle,
85                             "EDIT",
86                             "Test Text",
87                             WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL | style,
88                             0, 0, 300, 300,
89                             parentWnd, NULL, hinst, NULL);
90     assert(editWnd);
91     if (winetest_interactive)
92         ShowWindow (parentWnd, SW_SHOW);
93     return editWnd;
94 }
95
96 static void destroy_child_editcontrol (HWND hwndEdit)
97 {
98     if (GetParent(hwndEdit))
99         DestroyWindow(GetParent(hwndEdit));
100     else {
101         trace("Edit control has no parent!\n");
102         DestroyWindow(hwndEdit);
103     }
104 }
105
106 static LONG get_edit_style (HWND hwnd)
107 {
108     return GetWindowLongA( hwnd, GWL_STYLE ) & (
109         ES_LEFT |
110 /* FIXME: not implemented
111         ES_CENTER |
112         ES_RIGHT |
113         ES_OEMCONVERT |
114 */
115         ES_MULTILINE |
116         ES_UPPERCASE |
117         ES_LOWERCASE |
118         ES_PASSWORD |
119         ES_AUTOVSCROLL |
120         ES_AUTOHSCROLL |
121         ES_NOHIDESEL |
122         ES_COMBO |
123         ES_READONLY |
124         ES_WANTRETURN |
125         ES_NUMBER
126         );
127 }
128
129 static void set_client_height(HWND Wnd, unsigned Height)
130 {
131     RECT ClientRect, WindowRect;
132
133     GetWindowRect(Wnd, &WindowRect);
134     GetClientRect(Wnd, &ClientRect);
135     SetWindowPos(Wnd, NULL, 0, 0,
136                  WindowRect.right - WindowRect.left,
137                  Height + (WindowRect.bottom - WindowRect.top) -
138                  (ClientRect.bottom - ClientRect.top),
139                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
140
141     /* Workaround for a bug in Windows' edit control
142        (multi-line mode) */
143     GetWindowRect(Wnd, &WindowRect);             
144     SetWindowPos(Wnd, NULL, 0, 0,
145                  WindowRect.right - WindowRect.left + 1,
146                  WindowRect.bottom - WindowRect.top + 1,
147                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
148     SetWindowPos(Wnd, NULL, 0, 0,
149                  WindowRect.right - WindowRect.left,
150                  WindowRect.bottom - WindowRect.top,
151                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
152
153     GetClientRect(Wnd, &ClientRect);
154     ok(ClientRect.bottom - ClientRect.top == Height,
155         "The client height should be %ld, but is %ld\n",
156         (long)Height, (long)(ClientRect.bottom - ClientRect.top));
157 }
158
159 static void test_edit_control_1(void)
160 {
161     HWND hwEdit;
162     MSG msMessage;
163     int i;
164     LONG r;
165
166     msMessage.message = WM_KEYDOWN;
167
168     trace("EDIT: Single line\n");
169     hwEdit = create_editcontrol(0, 0);
170     r = get_edit_style(hwEdit);
171     ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%lx\n", r); 
172     for (i=0;i<65535;i++)
173     {
174         msMessage.wParam = i;
175         r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
176         ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
177             "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
178     }
179     DestroyWindow (hwEdit);
180
181     trace("EDIT: Single line want returns\n");
182     hwEdit = create_editcontrol(ES_WANTRETURN, 0);
183     r = get_edit_style(hwEdit);
184     ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%lx\n", r); 
185     for (i=0;i<65535;i++)
186     {
187         msMessage.wParam = i;
188         r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
189         ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
190             "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
191     }
192     DestroyWindow (hwEdit);
193
194     trace("EDIT: Multiline line\n");
195     hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL, 0);
196     r = get_edit_style(hwEdit);
197     ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%lx\n", r); 
198     for (i=0;i<65535;i++)
199     {
200         msMessage.wParam = i;
201         r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
202         ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
203             "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
204     }
205     DestroyWindow (hwEdit);
206
207     trace("EDIT: Multi line want returns\n");
208     hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL | ES_WANTRETURN, 0);
209     r = get_edit_style(hwEdit);
210     ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%lx\n", r); 
211     for (i=0;i<65535;i++)
212     {
213         msMessage.wParam = i;
214         r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
215         ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
216             "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
217     }
218     DestroyWindow (hwEdit);
219 }
220
221 /* WM_SETTEXT is implemented by selecting all text, and then replacing the
222  * selection.  This test checks that the first 'select all' doesn't generate
223  * an UPDATE message which can escape and (via a handler) change the
224  * selection, which would cause WM_SETTEXT to break.  This old bug
225  * was fixed 18-Mar-2005; we check here to ensure it doesn't regress.
226  */
227 static void test_edit_control_2(void)
228 {
229     HWND hwndMain;
230     char szLocalString[MAXLEN];
231
232     /* Create main and edit windows. */
233     hwndMain = CreateWindow(szEditTest2Class, "ET2", WS_OVERLAPPEDWINDOW,
234                             0, 0, 200, 200, NULL, NULL, hinst, NULL);
235     assert(hwndMain);
236     if (winetest_interactive)
237         ShowWindow (hwndMain, SW_SHOW);
238
239     hwndET2 = CreateWindow("EDIT", NULL,
240                            WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,
241                            0, 0, 150, 50, /* important this not be 0 size. */
242                            hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
243     assert(hwndET2);
244     if (winetest_interactive)
245         ShowWindow (hwndET2, SW_SHOW);
246
247     trace("EDIT: SETTEXT atomicity\n");
248     /* Send messages to "type" in the word 'foo'. */
249     SendMessage(hwndET2, WM_CHAR, 'f', 1);
250     SendMessage(hwndET2, WM_CHAR, 'o', 1);
251     SendMessage(hwndET2, WM_CHAR, 'o', 1);
252     /* 'foo' should have been changed to 'bar' by the UPDATE handler. */
253     GetWindowText(hwndET2, szLocalString, MAXLEN);
254     ok(lstrcmp(szLocalString, "bar")==0,
255        "Wrong contents of edit: %s\n", szLocalString);
256
257     /* OK, done! */
258     DestroyWindow (hwndET2);
259     DestroyWindow (hwndMain);
260 }
261
262 static void ET2_check_change(void) {
263    char szLocalString[MAXLEN];
264    /* This EN_UPDATE handler changes any 'foo' to 'bar'. */
265    GetWindowText(hwndET2, szLocalString, MAXLEN);
266    if (lstrcmp(szLocalString, "foo")==0) {
267        lstrcpy(szLocalString, "bar");
268        SendMessage(hwndET2, WM_SETTEXT, 0, (LPARAM) szLocalString);
269    }
270    /* always leave the cursor at the end. */
271    SendMessage(hwndET2, EM_SETSEL, MAXLEN - 1, MAXLEN - 1);
272 }
273 static void ET2_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
274 {
275     if (id==ID_EDITTEST2 && codeNotify == EN_UPDATE)
276         ET2_check_change();
277 }
278 static LRESULT CALLBACK ET2_WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
279 {
280     switch (iMsg) {
281         HANDLE_MSG(hwnd, WM_COMMAND, ET2_OnCommand);
282     }
283     return DefWindowProc(hwnd, iMsg, wParam, lParam);
284 }
285
286 static void zero_notify(void)
287 {
288     notifications.en_change = 0;
289     notifications.en_maxtext = 0;
290     notifications.en_update = 0;
291 }
292
293 #define test_notify(enchange, enmaxtext, enupdate) \
294     ok(notifications.en_change == enchange, "expected %d EN_CHANGE notifications, " \
295     "got %d\n", enchange, notifications.en_change); \
296     ok(notifications.en_maxtext == enmaxtext, "expected %d EN_MAXTEXT notifications, " \
297     "got %d\n", enmaxtext, notifications.en_maxtext); \
298     ok(notifications.en_update == enupdate, "expected %d EN_UPDATE notifications, " \
299     "got %d\n", enupdate, notifications.en_update)
300
301
302 static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
303 {
304     switch (msg) {
305         case WM_COMMAND:
306             switch (HIWORD(wParam)) {
307                 case EN_MAXTEXT:
308                     notifications.en_maxtext++;
309                     break;
310                 case EN_UPDATE:
311                     notifications.en_update++;
312                     break;
313                 case EN_CHANGE:
314                     notifications.en_change++;
315                     break;
316             }
317             break;
318     }
319     return DefWindowProcA(hWnd, msg, wParam, lParam);
320 }
321
322 /* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notificatisons sent in response
323  * to these messages.
324  */
325 static void test_edit_control_3(void)
326 {
327     HWND hWnd;
328     HWND hParent;
329     int len;
330     static const char *str = "this is a long string.";
331     static const char *str2 = "this is a long string.\r\nthis is a long string.\r\nthis is a long string.\r\nthis is a long string.";
332
333     trace("EDIT: Test notifications\n");
334
335     hParent = CreateWindowExA(0,
336               szEditTest3Class,
337               NULL,
338               0,
339               CW_USEDEFAULT, CW_USEDEFAULT, 10, 10,
340               NULL, NULL, NULL, NULL);
341     assert(hParent);
342
343     trace("EDIT: Single line, no ES_AUTOHSCROLL\n");
344     hWnd = CreateWindowExA(0,
345               "EDIT",
346               NULL,
347               0,
348               10, 10, 50, 50,
349               hParent, NULL, NULL, NULL);
350     assert(hWnd);
351
352     zero_notify();
353     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
354     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
355     ok(lstrlenA(str) > len, "text should have been truncated\n");
356     test_notify(1, 1, 1);
357
358     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
359     zero_notify();
360     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
361     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
362     ok(1 == len, "wrong text length, expected 1, got %d\n", len);
363     test_notify(1, 0, 1);
364
365     zero_notify();
366     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
367     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
368     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
369     test_notify(1, 0, 1);
370
371     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
372
373     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
374     zero_notify();
375     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
376     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
377     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
378     test_notify(1, 1, 1);
379
380     zero_notify();
381     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
382     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
383     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
384     test_notify(1, 0, 1);
385
386     DestroyWindow(hWnd);
387
388     trace("EDIT: Single line, ES_AUTOHSCROLL\n");
389     hWnd = CreateWindowExA(0,
390               "EDIT",
391               NULL,
392               ES_AUTOHSCROLL,
393               10, 10, 50, 50,
394               hParent, NULL, NULL, NULL);
395     assert(hWnd);
396
397     zero_notify();
398     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
399     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
400     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
401     test_notify(1, 0, 1);
402
403     zero_notify();
404     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
405     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
406     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
407     test_notify(1, 0, 1);
408
409     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
410
411     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
412     zero_notify();
413     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
414     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
415     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
416     test_notify(1, 1, 1);
417
418     zero_notify();
419     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
420     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
421     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
422     test_notify(1, 0, 1);
423
424     DestroyWindow(hWnd);
425
426     trace("EDIT: Multline, no ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
427     hWnd = CreateWindowExA(0,
428               "EDIT",
429               NULL,
430               ES_MULTILINE,
431               10, 10, 50, 50,
432               hParent, NULL, NULL, NULL);
433     assert(hWnd);
434
435     zero_notify();
436     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
437     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
438     ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
439     test_notify(1, 1, 1);
440
441     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
442     zero_notify();
443     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
444     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
445     ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
446     test_notify(1, 0, 1);
447
448     zero_notify();
449     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
450     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
451     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
452     test_notify(0, 0, 0);
453
454     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
455
456     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
457     zero_notify();
458     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
459     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
460     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
461     test_notify(1, 1, 1);
462
463     zero_notify();
464     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
465     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
466     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
467     test_notify(0, 0, 0);
468
469     DestroyWindow(hWnd);
470
471     trace("EDIT: Multline, ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
472     hWnd = CreateWindowExA(0,
473               "EDIT",
474               NULL,
475               ES_MULTILINE | ES_AUTOHSCROLL,
476               10, 10, 50, 50,
477               hParent, NULL, NULL, NULL);
478     assert(hWnd);
479
480     zero_notify();
481     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
482     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
483     ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
484     test_notify(1, 1, 1);
485
486     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
487     zero_notify();
488     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
489     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
490     ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
491     test_notify(1, 0, 1);
492
493     zero_notify();
494     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
495     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
496     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
497     test_notify(0, 0, 0);
498
499     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
500
501     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
502     zero_notify();
503     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
504     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
505     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
506     test_notify(1, 1, 1);
507
508     zero_notify();
509     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
510     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
511     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
512     test_notify(0, 0, 0);
513
514     DestroyWindow(hWnd);
515
516     trace("EDIT: Multline, ES_AUTOHSCROLL and ES_AUTOVSCROLL\n");
517     hWnd = CreateWindowExA(0,
518               "EDIT",
519               NULL,
520               ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
521               10, 10, 50, 50,
522               hParent, NULL, NULL, NULL);
523     assert(hWnd);
524
525     zero_notify();
526     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
527     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
528     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
529     test_notify(1, 0, 1);
530
531     zero_notify();
532     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
533     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
534     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
535     test_notify(0, 0, 0);
536
537     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
538
539     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
540     zero_notify();
541     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
542     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
543     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
544     test_notify(1, 1, 1);
545
546     zero_notify();
547     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
548     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
549     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
550     test_notify(0, 0, 0);
551
552     DestroyWindow(hWnd);
553 }
554
555 /* Test EM_CHARFROMPOS and EM_POSFROMCHAR
556  */
557 static void test_edit_control_4(void)
558 {
559     HWND hwEdit;
560     int lo, hi, mid;
561     int ret;
562     int i;
563
564     trace("EDIT: Test EM_CHARFROMPOS and EM_POSFROMCHAR\n");
565     hwEdit = create_editcontrol(0, 0);
566     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
567     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
568     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
569     mid = lo + (hi - lo) / 2;
570
571     for (i = lo; i < mid; i++) {
572        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
573        ok(0 == ret, "expected 0 got %d\n", ret);
574     }
575     for (i = mid; i <= hi; i++) {
576        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
577        ok(1 == ret, "expected 1 got %d\n", ret);
578     }
579     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
580     ok(-1 == ret, "expected -1 got %d\n", ret);
581     DestroyWindow(hwEdit);
582
583     hwEdit = create_editcontrol(ES_RIGHT, 0);
584     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
585     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
586     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
587     mid = lo + (hi - lo) / 2;
588
589     for (i = lo; i < mid; i++) {
590        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
591        ok(0 == ret, "expected 0 got %d\n", ret);
592     }
593     for (i = mid; i <= hi; i++) {
594        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
595        ok(1 == ret, "expected 1 got %d\n", ret);
596     }
597     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
598     ok(-1 == ret, "expected -1 got %d\n", ret);
599     DestroyWindow(hwEdit);
600
601     hwEdit = create_editcontrol(ES_CENTER, 0);
602     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
603     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
604     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
605     mid = lo + (hi - lo) / 2;
606
607     for (i = lo; i < mid; i++) {
608        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
609        ok(0 == ret, "expected 0 got %d\n", ret);
610     }
611     for (i = mid; i <= hi; i++) {
612        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
613        ok(1 == ret, "expected 1 got %d\n", ret);
614     }
615     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
616     ok(-1 == ret, "expected -1 got %d\n", ret);
617     DestroyWindow(hwEdit);
618
619     hwEdit = create_editcontrol(ES_MULTILINE, 0);
620     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
621     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
622     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
623     mid = lo + (hi - lo) / 2 +1;
624
625     for (i = lo; i < mid; i++) {
626        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
627        ok(0 == ret, "expected 0 got %d\n", ret);
628     }
629     for (i = mid; i <= hi; i++) {
630        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
631        ok(1 == ret, "expected 1 got %d\n", ret);
632     }
633     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
634     ok(-1 == ret, "expected -1 got %d\n", ret);
635     DestroyWindow(hwEdit);
636
637     hwEdit = create_editcontrol(ES_MULTILINE | ES_RIGHT, 0);
638     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
639     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
640     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
641     mid = lo + (hi - lo) / 2 +1;
642
643     for (i = lo; i < mid; i++) {
644        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
645        ok(0 == ret, "expected 0 got %d\n", ret);
646     }
647     for (i = mid; i <= hi; i++) {
648        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
649        ok(1 == ret, "expected 1 got %d\n", ret);
650     }
651     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
652     ok(-1 == ret, "expected -1 got %d\n", ret);
653     DestroyWindow(hwEdit);
654
655     hwEdit = create_editcontrol(ES_MULTILINE | ES_CENTER, 0);
656     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
657     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
658     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
659     mid = lo + (hi - lo) / 2 +1;
660
661     for (i = lo; i < mid; i++) {
662        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
663        ok(0 == ret, "expected 0 got %d\n", ret);
664     }
665     for (i = mid; i <= hi; i++) {
666        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
667        ok(1 == ret, "expected 1 got %d\n", ret);
668     }
669     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
670     ok(-1 == ret, "expected -1 got %d\n", ret);
671     DestroyWindow(hwEdit);
672 }
673
674 /* Test if creating edit control without ES_AUTOHSCROLL and ES_AUTOVSCROLL
675  * truncates text that doesn't fit.
676  */
677 static void test_edit_control_5(void)
678 {
679     static const char *str = "test\r\ntest";
680     HWND hWnd;
681     int len;
682
683     hWnd = CreateWindowEx(0,
684               "EDIT",
685               str,
686               0,
687               10, 10, 1, 1,
688               NULL, NULL, NULL, NULL);
689     assert(hWnd);
690
691     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
692     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
693     DestroyWindow(hWnd);
694
695     hWnd = CreateWindowEx(0,
696               "EDIT",
697               str,
698               ES_MULTILINE,
699               10, 10, 1, 1,
700               NULL, NULL, NULL, NULL);
701     assert(hWnd);
702
703     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
704     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
705     DestroyWindow(hWnd);
706 }
707
708 static void test_margins(void)
709 {
710     HWND hwEdit;
711     RECT old_rect, new_rect;
712     INT old_left_margin, old_right_margin;
713     DWORD old_margins, new_margins;
714
715     hwEdit = create_editcontrol(WS_BORDER, 0);
716     
717     old_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
718     old_left_margin = LOWORD(old_margins);
719     old_right_margin = HIWORD(old_margins);
720     
721     /* Check if setting the margins works */
722     
723     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0));
724     new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
725     ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
726     ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins));
727     
728     SendMessage(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10));
729     new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
730     ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
731     ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins));
732     
733     
734     /* The size of the rectangle must decrease if we increase the margin */
735     
736     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
737     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
738     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20));
739     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
740     ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n");
741     ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n");
742     ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n");
743     ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n");
744     
745     
746     /* If we set the margin to same value as the current margin,
747        the rectangle must not change */
748     
749     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
750     old_rect.left = 1;
751     old_rect.right = 99;
752     old_rect.top = 1;
753     old_rect.bottom = 99;
754     SendMessage(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect);    
755     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
756     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
757     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
758     ok(new_rect.left == old_rect.left, "The left border of the rectangle has changed\n");
759     ok(new_rect.right == old_rect.right, "The right border of the rectangle has changed\n");
760     ok(new_rect.top == old_rect.top, "The top border of the rectangle has changed\n");
761     ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle has changed\n");
762     
763     DestroyWindow (hwEdit);
764 }
765
766 #define edit_pos_ok(exp, got, txt) \
767     ok(exp == got, "wrong " #txt " expected %d got %ld\n", exp, got);
768
769 #define check_pos(hwEdit, set_height, test_top, test_height, test_left) \
770 do { \
771     RECT format_rect; \
772     int left_margin; \
773     set_client_height(hwEdit, set_height); \
774     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM) &format_rect); \
775     left_margin = LOWORD(SendMessage(hwEdit, EM_GETMARGINS, 0, 0)); \
776     edit_pos_ok(test_top, format_rect.top, vertical position); \
777     edit_pos_ok((int)test_height, format_rect.bottom - format_rect.top, height); \
778     edit_pos_ok(test_left, format_rect.left - left_margin, left); \
779 } while(0)
780
781 void test_text_position_style(DWORD style)
782 {
783     HWND hwEdit;
784     HFONT font, oldFont;
785     HDC dc;
786     TEXTMETRIC metrics;
787     INT b, bm, b2, b3;
788     BOOL single_line = !(style & ES_MULTILINE);
789
790     b = GetSystemMetrics(SM_CYBORDER) + 1;
791     b2 = 2 * b;
792     b3 = 3 * b;
793     bm = b2 - 1;
794     
795     /* Get a stock font for which we can determine the metrics */
796     assert(font = GetStockObject(SYSTEM_FONT));
797     assert(dc = GetDC(NULL));
798     oldFont = SelectObject(dc, font);
799     assert(GetTextMetrics(dc, &metrics));    
800     SelectObject(dc, oldFont);
801     ReleaseDC(NULL, dc);
802     
803     /* Windows' edit control has some bugs in multi-line mode:
804      * - Sometimes the format rectangle doesn't get updated
805      *   (see workaround in set_client_height())
806      * - If the height of the control is smaller than the height of a text
807      *   line, the format rectangle is still as high as a text line
808      *   (higher than the client rectangle) and the caret is not shown
809      */
810     
811     /* Edit controls that are in a parent window */
812        
813     hwEdit = create_child_editcontrol(style, 0);
814     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
815     if (single_line)
816     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 0);
817     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 0);
818     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 0);
819     check_pos(hwEdit, metrics.tmHeight +  2, 0, metrics.tmHeight    , 0);
820     check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight    , 0);
821     destroy_child_editcontrol(hwEdit);
822
823     hwEdit = create_child_editcontrol(style | WS_BORDER, 0);
824     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
825     if (single_line)
826     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, b);
827     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , b);
828     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , b);
829     check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight    , b);
830     check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight    , b);
831     check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight    , b);
832     destroy_child_editcontrol(hwEdit);
833
834     hwEdit = create_child_editcontrol(style, WS_EX_CLIENTEDGE);
835     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
836     if (single_line)
837     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 1);
838     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 1);
839     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 1);
840     check_pos(hwEdit, metrics.tmHeight +  2, 1, metrics.tmHeight    , 1);
841     check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight    , 1);
842     destroy_child_editcontrol(hwEdit);
843
844     hwEdit = create_child_editcontrol(style | WS_BORDER, WS_EX_CLIENTEDGE);
845     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
846     if (single_line)
847     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 1);
848     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 1);
849     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 1);
850     check_pos(hwEdit, metrics.tmHeight +  2, 1, metrics.tmHeight    , 1);
851     check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight    , 1);
852     destroy_child_editcontrol(hwEdit);
853
854
855     /* Edit controls that are popup windows */
856     
857     hwEdit = create_editcontrol(style | WS_POPUP, 0);
858     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
859     if (single_line)
860     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 0);
861     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 0);
862     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 0);
863     check_pos(hwEdit, metrics.tmHeight +  2, 0, metrics.tmHeight    , 0);
864     check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight    , 0);
865     DestroyWindow(hwEdit);
866
867     hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, 0);
868     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
869     if (single_line)
870     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, b);
871     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , b);
872     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , b);
873     check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight    , b);
874     check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight    , b);
875     check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight    , b);
876     DestroyWindow(hwEdit);
877
878     hwEdit = create_editcontrol(style | WS_POPUP, WS_EX_CLIENTEDGE);
879     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
880     if (single_line)
881     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 1);
882     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 1);
883     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 1);
884     check_pos(hwEdit, metrics.tmHeight +  2, 1, metrics.tmHeight    , 1);
885     check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight    , 1);
886     DestroyWindow(hwEdit);
887
888     hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE);
889     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
890     if (single_line)
891     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 1);
892     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 1);
893     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 1);
894     check_pos(hwEdit, metrics.tmHeight +  2, 1, metrics.tmHeight    , 1);
895     check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight    , 1);
896     DestroyWindow(hwEdit);
897 }
898
899 void test_text_position(void)
900 {
901     trace("EDIT: Text position (Single line)\n");
902     test_text_position_style(0);
903     trace("EDIT: Text position (Multi line)\n");
904     test_text_position_style(ES_MULTILINE);
905 }
906
907 static BOOL RegisterWindowClasses (void)
908 {
909     WNDCLASSA test2;
910     WNDCLASSA test3;
911     WNDCLASSA text_position;
912     
913     test2.style = 0;
914     test2.lpfnWndProc = ET2_WndProc;
915     test2.cbClsExtra = 0;
916     test2.cbWndExtra = 0;
917     test2.hInstance = hinst;
918     test2.hIcon = NULL;
919     test2.hCursor = LoadCursorA (NULL, IDC_ARROW);
920     test2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
921     test2.lpszMenuName = NULL;
922     test2.lpszClassName = szEditTest2Class;
923     if (!RegisterClassA(&test2)) return FALSE;
924
925     test3.style = 0;
926     test3.lpfnWndProc = edit3_wnd_procA;
927     test3.cbClsExtra = 0;
928     test3.cbWndExtra = 0;
929     test3.hInstance = hinst;
930     test3.hIcon = 0;
931     test3.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
932     test3.hbrBackground = GetStockObject(WHITE_BRUSH);
933     test3.lpszMenuName = NULL;
934     test3.lpszClassName = szEditTest3Class;
935     if (!RegisterClassA(&test3)) return FALSE;
936
937     text_position.style = CS_HREDRAW | CS_VREDRAW;
938     text_position.cbClsExtra = 0;
939     text_position.cbWndExtra = 0;
940     text_position.hInstance = hinst;
941     text_position.hIcon = NULL;
942     text_position.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
943     text_position.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
944     text_position.lpszMenuName = NULL;
945     text_position.lpszClassName = szEditTextPositionClass;
946     text_position.lpfnWndProc = DefWindowProc;
947     if (!RegisterClassA(&text_position)) return FALSE;
948
949     return TRUE;
950 }
951
952 static void UnregisterWindowClasses (void)
953 {
954     UnregisterClassA(szEditTest2Class, hinst);
955     UnregisterClassA(szEditTest3Class, hinst);
956     UnregisterClassA(szEditTextPositionClass, hinst);
957 }
958
959 START_TEST(edit)
960 {
961     hinst = GetModuleHandleA(NULL);
962     assert(RegisterWindowClasses());
963
964     test_edit_control_1();
965     test_edit_control_2();
966     test_edit_control_3();
967     test_edit_control_4();
968     test_edit_control_5();
969     test_margins();
970     test_text_position();
971     
972     UnregisterWindowClasses();
973 }