Fix subclassing to support nested messages.
[wine] / dlls / kernel / tests / console.c
1 /*
2  * Unit tests for console API
3  *
4  * Copyright (c) 2003 Eric Pouech
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 "wine/test.h"
22 #include <windows.h>
23 #include <stdio.h>
24
25 /* DEFAULT_ATTRIB is used for all initial filling of the console.
26  * all modifications are made with TEST_ATTRIB so that we could check
27  * what has to be modified or not
28  */
29 #define TEST_ATTRIB    (BACKGROUND_BLUE | FOREGROUND_GREEN)
30 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
31 /* when filling the screen with non-blank chars, this macro defines
32  * what character should be at position 'c'
33  */
34 #define CONTENT(c)    ('A' + (((c).Y * 17 + (c).X) % 23))
35
36 #define okCURSOR(hCon, c) do { \
37   CONSOLE_SCREEN_BUFFER_INFO __sbi; \
38   BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
39                 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
40   ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
41      (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
42 } while (0)
43
44 #define okCHAR(hCon, c, ch, attr) do { \
45   char __ch; WORD __attr; DWORD __len; BOOL expect; \
46   expect = ReadConsoleOutputCharacter((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
47   ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
48   expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
49   ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
50 } while (0)
51
52 /* FIXME: this could be optimized on a speed point of view */
53 static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
54 {
55     COORD       c;
56     WORD        attr = DEFAULT_ATTRIB;
57     char        ch;
58     DWORD       len;
59
60     for (c.X = 0; c.X < sbSize.X; c.X++)
61     {
62         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
63         {
64             ch = (content) ? CONTENT(c) : ' ';
65             WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
66             WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
67         }
68     }
69 }
70
71 static void testCursor(HANDLE hCon, COORD sbSize)
72 {
73     COORD               c;
74
75     c.X = c.Y = 0;
76     ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
77     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
78        ERROR_INVALID_HANDLE, GetLastError());
79
80     c.X = c.Y = 0;
81     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
82     okCURSOR(hCon, c);
83
84     c.X = sbSize.X - 1;
85     c.Y = sbSize.Y - 1;
86     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
87     okCURSOR(hCon, c);
88
89     c.X = sbSize.X;
90     c.Y = sbSize.Y - 1;
91     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
92     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
93        ERROR_INVALID_PARAMETER, GetLastError());
94
95     c.X = sbSize.X - 1;
96     c.Y = sbSize.Y;
97     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
98     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
99        ERROR_INVALID_PARAMETER, GetLastError());
100
101     c.X = -1;
102     c.Y = 0;
103     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
104     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
105        ERROR_INVALID_PARAMETER, GetLastError());
106
107     c.X = 0;
108     c.Y = -1;
109     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
110     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
111        ERROR_INVALID_PARAMETER, GetLastError());
112 }
113
114 static void testWriteSimple(HANDLE hCon, COORD sbSize)
115 {
116     COORD               c;
117     DWORD               len;
118     const char*         mytest = "abcdefg";
119     const int   mylen = strlen(mytest);
120
121     /* single line write */
122     c.X = c.Y = 0;
123     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
124
125     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
126     c.Y = 0;
127     for (c.X = 0; c.X < mylen; c.X++)
128     {
129         okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
130     }
131
132     okCURSOR(hCon, c);
133     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
134 }
135
136 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
137 {
138     COORD               c;
139     DWORD               len, mode;
140     const char*         mytest = "abcd\nf\tg";
141     const int   mylen = strlen(mytest);
142     int                 p;
143
144     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
145        "clearing wrap at EOL & processed output\n");
146
147     /* write line, wrapping disabled, buffer exceeds sb width */
148     c.X = sbSize.X - 3; c.Y = 0;
149     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
150
151     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
152     c.Y = 0;
153     for (p = mylen - 3; p < mylen; p++)
154     {
155         c.X = sbSize.X - 3 + p % 3;
156         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
157     }
158
159     c.X = 0; c.Y = 1;
160     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
161
162     p = sbSize.X - 3 + mylen % 3;
163     c.X = p; c.Y = 0;
164     okCURSOR(hCon, c);
165
166     /* write line, wrapping disabled, strings end on end of line */
167     c.X = sbSize.X - mylen; c.Y = 0;
168     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
169
170     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
171     c.Y = 0;
172     for (p = 0; p < mylen; p++)
173     {
174         c.X = sbSize.X - mylen + p;
175         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
176     }
177
178     c.X = 0; c.Y = 1;
179     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
180
181     p = sbSize.X - mylen;
182     c.X = p; c.Y = 0;
183     okCURSOR(hCon, c);
184 }
185
186 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
187 {
188     COORD               c;
189     DWORD               len, mode;
190     const char*         mytest = "abcd\nf\tg";
191     const int   mylen = strlen(mytest);
192     const int   mylen2 = strchr(mytest, '\n') - mytest;
193     int                 p;
194
195     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT),
196        "clearing wrap at EOL & setting processed output\n");
197
198     /* write line, wrapping disabled, buffer exceeds sb width */
199     c.X = sbSize.X - 5; c.Y = 0;
200     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
201
202     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
203     c.Y = 0;
204     for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
205     {
206         okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
207     }
208     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
209
210     c.X = 0; c.Y++;
211     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
212     for (c.X = 1; c.X < 8; c.X++)
213         okCHAR(hCon, c, ' ', TEST_ATTRIB);
214     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
215     c.X++;
216     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
217
218     okCURSOR(hCon, c);
219
220     /* write line, wrapping disabled, strings end on end of line */
221     c.X = sbSize.X - 4; c.Y = 0;
222     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
223
224     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
225     c.Y = 0;
226     for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
227     {
228         okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
229     }
230     c.X = 0; c.Y++;
231     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
232     for (c.X = 1; c.X < 8; c.X++)
233         okCHAR(hCon, c, ' ', TEST_ATTRIB);
234     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
235     c.X++;
236     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
237
238     okCURSOR(hCon, c);
239
240     /* write line, wrapping disabled, strings end after end of line */
241     c.X = sbSize.X - 3; c.Y = 0;
242     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
243
244     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
245     c.Y = 0;
246     for (p = mylen2 - 3; p < mylen2; p++)
247     {
248         c.X = sbSize.X - 3 + p % 3;
249         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
250     }
251     c.X = 0; c.Y = 1;
252     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
253     for (c.X = 1; c.X < 8; c.X++)
254         okCHAR(hCon, c, ' ', TEST_ATTRIB);
255     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
256     c.X++;
257     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
258
259     okCURSOR(hCon, c);
260 }
261
262 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
263 {
264     COORD               c;
265     DWORD               len, mode;
266     const char*         mytest = "abcd\nf\tg";
267     const int   mylen = strlen(mytest);
268     int                 p;
269
270     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
271        "setting wrap at EOL & clearing processed output\n");
272
273     /* write line, wrapping enabled, buffer doesn't exceed sb width */
274     c.X = sbSize.X - 9; c.Y = 0;
275     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
276
277     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
278     c.Y = 0;
279     for (p = 0; p < mylen; p++)
280     {
281         c.X = sbSize.X - 9 + p;
282         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
283     }
284     c.X = sbSize.X - 9 + mylen;
285     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
286     c.X = 0; c.Y = 1;
287     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
288
289     /* write line, wrapping enabled, buffer does exceed sb width */
290     c.X = sbSize.X - 3; c.Y = 0;
291     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
292
293     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
294     c.Y = 0;
295     for (p = 0; p < 3; p++)
296     {
297         c.X = sbSize.X - 3 + p;
298         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
299     }
300
301     c.Y = 1;
302     for (p = 0; p < mylen - 3; p++)
303     {
304         c.X = p;
305         okCHAR(hCon, c, mytest[p + 3], TEST_ATTRIB);
306     }
307     c.X = mylen - 3;
308     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
309
310     okCURSOR(hCon, c);
311 }
312
313 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
314 {
315     COORD               c;
316     DWORD               len, mode;
317     const char*         mytest = "abcd\nf\tg";
318     const int   mylen = strlen(mytest);
319     int                 p;
320
321     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
322        "setting wrap at EOL & processed output\n");
323
324     /* write line, wrapping enabled, buffer doesn't exceed sb width */
325     c.X = sbSize.X - 9; c.Y = 0;
326     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
327
328     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
329     for (p = 0; p < 4; p++)
330     {
331         c.X = sbSize.X - 9 + p;
332         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
333     }
334     c.X = sbSize.X - 9 + p;
335     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
336     c.X = 0; c.Y++;
337     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
338     for (c.X = 1; c.X < 8; c.X++)
339         okCHAR(hCon, c, ' ', TEST_ATTRIB);
340     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
341     c.X++;
342     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
343     okCURSOR(hCon, c);
344
345     /* write line, wrapping enabled, buffer does exceed sb width */
346     c.X = sbSize.X - 3; c.Y = 2;
347     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
348
349     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
350     for (p = 0; p < 3; p++)
351     {
352         c.X = sbSize.X - 3 + p;
353         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
354     }
355     c.X = 0; c.Y++;
356     okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
357     c.X++;
358     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
359
360     c.X = 0; c.Y++;
361     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
362     for (c.X = 1; c.X < 8; c.X++)
363         okCHAR(hCon, c, ' ', TEST_ATTRIB);
364     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
365     c.X++;
366     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
367     okCURSOR(hCon, c);
368 }
369
370 static void testWrite(HANDLE hCon, COORD sbSize)
371 {
372     /* FIXME: should in fact insure that the sb is at least 10 character wide */
373     ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
374     resetContent(hCon, sbSize, FALSE);
375     testWriteSimple(hCon, sbSize);
376     resetContent(hCon, sbSize, FALSE);
377     testWriteNotWrappedNotProcessed(hCon, sbSize);
378     resetContent(hCon, sbSize, FALSE);
379     testWriteNotWrappedProcessed(hCon, sbSize);
380     resetContent(hCon, sbSize, FALSE);
381     testWriteWrappedNotProcessed(hCon, sbSize);
382     resetContent(hCon, sbSize, FALSE);
383     testWriteWrappedProcessed(hCon, sbSize);
384 }
385
386 #if 0
387 static void testScroll(HANDLE hCon, COORD sbSize)
388 {
389     SMALL_RECT  scroll, clip;
390     COORD       dst, c, tc;
391     CHAR_INFO   ci;
392
393 #define W 11
394 #define H 7
395
396     /* no clipping, src & dst rect don't overlap */
397     resetContent(hCon, sbSize, TRUE);
398
399 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
400 #define IN_SRECT2(r,d,c) ((d).X <= (c).X && (c).X <= (d).X + (r).Right - (r).Left && (d).Y <= (c).Y && (c).Y <= (d).Y + (r).Bottom - (r).Top)
401
402     scroll.Left = 0;
403     scroll.Right = W - 1;
404     scroll.Top = 0;
405     scroll.Bottom = H - 1;
406     dst.X = W + 3;
407     dst.Y = H + 3;
408     ci.Char.UnicodeChar = '#';
409     ci.Attributes = TEST_ATTRIB;
410
411     clip.Left = 0;
412     clip.Right = sbSize.X - 1;
413     clip.Top = 0;
414     clip.Bottom = sbSize.Y - 1;
415
416     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
417
418     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
419     {
420         for (c.X = 0; c.X < sbSize.X; c.X++)
421         {
422             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
423             {
424                 tc.X = c.X - dst.X;
425                 tc.Y = c.Y - dst.Y;
426                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
427             }
428             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
429                 okCHAR(hCon, c, '#', TEST_ATTRIB);
430             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
431         }
432     }
433
434     /* no clipping, src & dst rect do overlap */
435     resetContent(hCon, sbSize, TRUE);
436
437     scroll.Left = 0;
438     scroll.Right = W - 1;
439     scroll.Top = 0;
440     scroll.Bottom = H - 1;
441     dst.X = W /2;
442     dst.Y = H / 2;
443     ci.Char.UnicodeChar = '#';
444     ci.Attributes = TEST_ATTRIB;
445
446     clip.Left = 0;
447     clip.Right = sbSize.X - 1;
448     clip.Top = 0;
449     clip.Bottom = sbSize.Y - 1;
450
451     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
452
453     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
454     {
455         for (c.X = 0; c.X < sbSize.X; c.X++)
456         {
457             if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
458             {
459                 tc.X = c.X - dst.X;
460                 tc.Y = c.Y - dst.Y;
461                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
462             }
463             else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
464             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
465         }
466     }
467
468     /* clipping, src & dst rect don't overlap */
469     resetContent(hCon, sbSize, TRUE);
470
471     scroll.Left = 0;
472     scroll.Right = W - 1;
473     scroll.Top = 0;
474     scroll.Bottom = H - 1;
475     dst.X = W + 3;
476     dst.Y = H + 3;
477     ci.Char.UnicodeChar = '#';
478     ci.Attributes = TEST_ATTRIB;
479
480     clip.Left = W / 2;
481     clip.Right = min(W + W / 2, sbSize.X - 1);
482     clip.Top = H / 2;
483     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
484
485     ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
486
487     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
488     {
489         for (c.X = 0; c.X < sbSize.X; c.X++)
490         {
491             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
492             {
493                 tc.X = c.X - dst.X;
494                 tc.Y = c.Y - dst.Y;
495                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
496             }
497             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
498                 okCHAR(hCon, c, '#', TEST_ATTRIB);
499             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
500         }
501     }
502
503     /* clipping, src & dst rect do overlap */
504     resetContent(hCon, sbSize, TRUE);
505
506     scroll.Left = 0;
507     scroll.Right = W - 1;
508     scroll.Top = 0;
509     scroll.Bottom = H - 1;
510     dst.X = W / 2 - 3;
511     dst.Y = H / 2 - 3;
512     ci.Char.UnicodeChar = '#';
513     ci.Attributes = TEST_ATTRIB;
514
515     clip.Left = W / 2;
516     clip.Right = min(W + W / 2, sbSize.X - 1);
517     clip.Top = H / 2;
518     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
519
520     ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
521
522     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
523     {
524         for (c.X = 0; c.X < sbSize.X; c.X++)
525         {
526             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
527             {
528                 tc.X = c.X - dst.X;
529                 tc.Y = c.Y - dst.Y;
530                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
531             }
532             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
533                 okCHAR(hCon, c, '#', TEST_ATTRIB);
534             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
535         }
536     }
537 }
538 #endif
539
540 START_TEST(console)
541 {
542     HANDLE hConIn, hConOut;
543     BOOL ret;
544     CONSOLE_SCREEN_BUFFER_INFO  sbi;
545
546     /* be sure we have a clean console (and that's our own)
547      * FIXME: this will make the test fail (currently) if we don't run
548      * under X11
549      * Another solution would be to rerun the test under wineconsole with
550      * the curses backend
551      */
552
553     hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
554     hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
555
556     /* first, we need to be sure we're attached to a console */
557     if (hConIn == INVALID_HANDLE_VALUE || hConOut == INVALID_HANDLE_VALUE)
558     {
559         /* we're not attached to a console, let's do it */
560         AllocConsole();
561         hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
562         hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
563     }
564     /* now verify everything's ok */
565     ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
566     ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
567
568     ok(ret = GetConsoleScreenBufferInfo(hConOut, &sbi), "Getting sb info\n");
569     if (!ret) return;
570
571     /* Non interactive tests */
572     testCursor(hConOut, sbi.dwSize);
573     /* will test wrapped (on/off) & processed (on/off) strings output */
574     testWrite(hConOut, sbi.dwSize);
575     /* will test line scrolling at the bottom of the screen */
576     /* testBottomScroll(); */
577     /* will test all the scrolling operations */
578     /* this one is disabled for now, Wine's result are way too bad */
579     /* testScroll(hCon, sbi.dwSize); */
580     /* will test sb creation / modification... */
581     /* testScreenBuffer() */
582
583     /* still to be done: events generation, access rights & access on objects */
584 }