aboutsummaryrefslogtreecommitdiffstats
path: root/demos/modules/gwin/widgets/main.c
blob: 8252002bee16b897d321daabc325c472049248b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
/*
 * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu <joel@unormal.org>
 * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of the <organization> nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "gfx.h"

/**
 * This demo demonstrates many of the GWIN widgets.
 * On the "Radio" tab try playing with the color radio buttons.
 * On the "Checkbox" tab try playing with the "Disable All" checkbox.
 */

/**
 * The image files must be stored on a GFILE file-system.
 * Use either GFILE_NEED_NATIVEFS or GFILE_NEED_ROMFS (or both).
 *
 * The ROMFS uses the file "romfs_files.h" to describe the set of files in the ROMFS.
 */

/**
 * The code can either use the Tabset control or use Radio buttons set to the Tab style.
 * Change this in your gfxconf.h file by defining GWIN_NEED_TABSET (or not). It is
 * defined by default in this demo.
 */

/* Our custom yellow style */
static const GWidgetStyle YellowWidgetStyle = {
	Yellow,							// window background
	HTML2COLOR(0x800000),			// focus

	// enabled color set
	{
		HTML2COLOR(0x0000FF),		// text
		HTML2COLOR(0x404040),		// edge
		HTML2COLOR(0xE0E0E0),		// fill
		HTML2COLOR(0x00E000)		// progress - active area
	},

	// disabled color set
	{
		HTML2COLOR(0xC0C0C0),		// text
		HTML2COLOR(0x808080),		// edge
		HTML2COLOR(0xE0E0E0),		// fill
		HTML2COLOR(0xC0E0C0)		// progress - active area
	},

	// pressed color set
	{
		HTML2COLOR(0xFF00FF),		// text
		HTML2COLOR(0x404040),		// edge
		HTML2COLOR(0x808080),		// fill
		HTML2COLOR(0x00E000),		// progress - active area
	}
};

/* The variables we need */
static font_t		font;
static GListener	gl;
static GHandle		ghConsole;
static GTimer		FlashTimer;

#if GWIN_NEED_TABSET
	static GHandle		ghTabset;
#else
	static GHandle		ghTabButtons, ghTabSliders, ghTabCheckboxes, ghTabLabels, ghTabRadios, ghTabLists, ghTabImages, ghTabProgressbar;
#endif
static GHandle		ghPgButtons, ghPgSliders, ghPgCheckboxes, ghPgLabels, ghPgRadios, ghPgLists, ghPgImages, ghPgProgressbars;
static GHandle		ghButton1, ghButton2, ghButton3, ghButton4;
static GHandle		ghSlider1, ghSlider2, ghSlider3, ghSlider4;
static GHandle		ghCheckbox1, ghCheckbox2, ghCheckbox3, ghCheckDisableAll;
static GHandle		ghLabelSlider1, ghLabelSlider2, ghLabelSlider3, ghLabelSlider4, ghLabelRadio1;
static GHandle		ghRadio1, ghRadio2;
static GHandle		ghRadioBlack, ghRadioWhite, ghRadioYellow;
static GHandle		ghList1, ghList2, ghList3, ghList4;
static GHandle		ghImage1;
static GHandle		ghProgressbar1;
static gdispImage	imgYesNo;

/* Some useful macros */
#define	ScrWidth			gdispGetWidth()
#define	ScrHeight			gdispGetHeight()

#define BUTTON_PADDING		20
#define TAB_HEIGHT			30
#define LABEL_HEIGHT		15
#define BUTTON_WIDTH		50
#define BUTTON_HEIGHT		30
#define LIST_WIDTH			75
#define LIST_HEIGHT			80
#define SLIDER_WIDTH		20
#define CHECKBOX_WIDTH		80
#define CHECKBOX_HEIGHT		20
#define RADIO_WIDTH			50
#define RADIO_HEIGHT		20
#define COLOR_WIDTH			80
#define DISABLEALL_WIDTH	100
#define GROUP_TABS			0
#define GROUP_YESNO			1
#define GROUP_COLORS		2

#if !GWIN_NEED_TABSET
	// Wrap tabs onto the next line if they don't fit.
	static void settabtext(GWidgetInit *pwi, char *txt) {
		if (pwi->g.x >= ScrWidth) {
			pwi->g.x = 0;
			pwi->g.y += pwi->g.height;
		}
		pwi->text = txt;
		pwi->g.width = gdispGetStringWidth(pwi->text, font) + BUTTON_PADDING;
		if (pwi->g.x + pwi->g.width > ScrWidth) {
			pwi->g.x = 0;
			pwi->g.y += pwi->g.height;
		}
	}

	/**
	 * Set the visibility of widgets based on which tab is selected.
	 */
	static void setTab(GHandle tab) {
		/* Make sure everything is invisible first */
		gwinHide(ghPgButtons);
		gwinHide(ghPgSliders);
		gwinHide(ghPgCheckboxes);
		gwinHide(ghPgLabels);
		gwinHide(ghPgRadios);
		gwinHide(ghPgLists);
		gwinHide(ghPgImages);
		gwinHide(ghPgProgressbars);

		/* Turn on widgets depending on the tab selected */
		if (tab == ghTabButtons)
			gwinShow(ghPgButtons);
		else if (tab == ghTabSliders)
			gwinShow(ghPgSliders);
		else if (tab == ghTabCheckboxes)
			gwinShow(ghPgCheckboxes);
		else if (tab == ghTabLabels)
			gwinShow(ghPgLabels);
		else if (tab == ghTabRadios)
			gwinShow(ghPgRadios);
		else if (tab == ghTabLists)
			gwinShow(ghPgLists);
		else if (tab == ghTabImages)
			gwinShow(ghPgImages);
		else if (tab == ghTabProgressbar)
			gwinShow(ghPgProgressbars);
	}
#endif

// Wrap buttons onto the next line if they don't fit.
static void setbtntext(GWidgetInit *pwi, coord_t maxwidth, char *txt) {
	if (pwi->g.x >= maxwidth) {
		pwi->g.x = 5;
		pwi->g.y += pwi->g.height+1;
	}
	pwi->text = txt;
	pwi->g.width = gdispGetStringWidth(pwi->text, font) + BUTTON_PADDING;
	if (pwi->g.x + pwi->g.width > maxwidth) {
		pwi->g.x = 5;
		pwi->g.y += pwi->g.height+1;
	}
}

/**
 * Create all the widgets.
 * With the exception of the Pages they are all initially visible.
 *
 * This routine is complicated by the fact that we want a dynamic
 * layout so it looks good on small and large displays.
 * It is tested to work on 320x272 as a minimum LCD size.
 */
static void createWidgets(void) {
	GWidgetInit		wi;
	coord_t			border, pagewidth;

	gwinWidgetClearInit(&wi);

	// Calculate page borders based on screen size
	border = ScrWidth < 450 ? 1 : 5;

	// Create the Tabs
	#if GWIN_NEED_TABSET
		wi.g.show = TRUE;
		wi.g.x = border; wi.g.y = 0;
		wi.g.width = ScrWidth - 2*border; wi.g.height = ScrHeight-wi.g.y-border;
		ghTabset			= gwinTabsetCreate(0, &wi, GWIN_TABSET_BORDER);
		ghPgButtons			= gwinTabsetAddTab(ghTabset, "Buttons", FALSE);
		ghPgSliders			= gwinTabsetAddTab(ghTabset, "Sliders", FALSE);
		ghPgCheckboxes		= gwinTabsetAddTab(ghTabset, "Checkbox", FALSE);
		ghPgRadios			= gwinTabsetAddTab(ghTabset, "Radios", FALSE);
		ghPgLists			= gwinTabsetAddTab(ghTabset, "Lists", FALSE);
		ghPgLabels			= gwinTabsetAddTab(ghTabset, "Labels", FALSE);
		ghPgImages			= gwinTabsetAddTab(ghTabset, "Images", FALSE);
		ghPgProgressbars	= gwinTabsetAddTab(ghTabset, "Progressbar", FALSE);

		pagewidth = gwinGetInnerWidth(ghTabset)/2;

		// Console - we apply some special colors before making it visible
		//	We put the console on the tabset itself rather than a tab-page.
		//	This makes it appear on every page :)
		wi.g.parent = ghTabset;
		wi.g.x = pagewidth;
		wi.g.width = pagewidth;
		ghConsole = gwinConsoleCreate(0, &wi.g);
	    gwinSetColor(ghConsole, Black);
	    gwinSetBgColor(ghConsole, HTML2COLOR(0xF0F0F0));

	#else
		wi.g.show = TRUE; wi.customDraw = gwinRadioDraw_Tab;
		wi.g.height = TAB_HEIGHT; wi.g.y = 0;
		wi.g.x = 0; setbtntext(&wi, ScrWidth, "Buttons");
		ghTabButtons     = gwinRadioCreate(0, &wi, GROUP_TABS);
		wi.g.x += wi.g.width; settabtext(&wi, "Sliders");
		ghTabSliders     = gwinRadioCreate(0, &wi, GROUP_TABS);
		wi.g.x += wi.g.width; settabtext(&wi, "Checkbox");
		ghTabCheckboxes  = gwinRadioCreate(0, &wi, GROUP_TABS);
		wi.g.x += wi.g.width; settabtext(&wi, "Radios");
		ghTabRadios      = gwinRadioCreate(0, &wi, GROUP_TABS);
		wi.g.x += wi.g.width; settabtext(&wi, "Lists");
		ghTabLists       = gwinRadioCreate(0, &wi, GROUP_TABS);
		wi.g.x += wi.g.width; settabtext(&wi, "Labels");
		ghTabLabels      = gwinRadioCreate(0, &wi, GROUP_TABS);
		wi.g.x += wi.g.width; settabtext(&wi, "Images");
		ghTabImages      = gwinRadioCreate(0, &wi, GROUP_TABS);
		wi.g.x += wi.g.width; settabtext(&wi, "Progressbar");
		ghTabProgressbar = gwinRadioCreate(0, &wi, GROUP_TABS);
		wi.g.y += wi.g.height;
		wi.customDraw = 0;

		// Create the Pages
		wi.g.show = FALSE;
		wi.g.x = border; wi.g.y += border;
		wi.g.width = ScrWidth/2 - border; wi.g.height = ScrHeight-wi.g.y-border;
		ghPgButtons			= gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER);
		ghPgSliders			= gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER);
		ghPgCheckboxes		= gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER);
		ghPgRadios			= gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER);
		ghPgLists			= gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER);
		ghPgLabels			= gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER);
		ghPgImages			= gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER);
		ghPgProgressbars	= gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER);
		wi.g.show = TRUE;

		// Console - we apply some special colors before making it visible
		wi.g.x = ScrWidth/2+border;
		wi.g.width = ScrWidth/2 - 2*border;
		ghConsole = gwinConsoleCreate(0, &wi.g);
	    gwinSetColor(ghConsole, Black);
	    gwinSetBgColor(ghConsole, HTML2COLOR(0xF0F0F0));

	    pagewidth = gwinGetInnerWidth(ghPgButtons);
	#endif

    // Buttons
	wi.g.parent = ghPgButtons;
	wi.g.width = BUTTON_WIDTH; wi.g.height = BUTTON_HEIGHT; wi.g.y = 5;
	wi.g.x = 5; setbtntext(&wi, pagewidth, "Button 1");
	ghButton1 = gwinButtonCreate(0, &wi);
	wi.g.x += wi.g.width+3; setbtntext(&wi, pagewidth, "Button 2");
	ghButton2 = gwinButtonCreate(0, &wi);
	wi.g.x += wi.g.width+3; setbtntext(&wi, pagewidth, "Button 3");
	ghButton3 = gwinButtonCreate(0, &wi);
	wi.g.x += wi.g.width+3; setbtntext(&wi, pagewidth, "Button 4");
	ghButton4 = gwinButtonCreate(0, &wi);

	// Horizontal Sliders
	wi.g.parent = ghPgSliders;
	wi.g.width = pagewidth - 10; wi.g.height = SLIDER_WIDTH;
	wi.g.x = 5; wi.g.y = 5; wi.text = "S1";
	ghSlider1 = gwinSliderCreate(0, &wi);
	gwinSliderSetPosition(ghSlider1, 33);
	wi.g.y += wi.g.height + 1; wi.text = "S2";
	ghSlider2 = gwinSliderCreate(0, &wi);
	gwinSliderSetPosition(ghSlider2, 86);

	// Vertical Sliders
	wi.g.y += wi.g.height + 5;
	wi.g.width = SLIDER_WIDTH; wi.g.height = gwinGetInnerHeight(ghPgSliders) - 5 - wi.g.y;
	wi.g.x = 5; wi.text = "S3";
	ghSlider3 = gwinSliderCreate(0, &wi);
	gwinSliderSetPosition(ghSlider3, 13);
	wi.g.x += wi.g.width+1; wi.text = "S4";
	ghSlider4 = gwinSliderCreate(0, &wi);
	gwinSliderSetPosition(ghSlider4, 76);

	// Checkboxes - for the 2nd and 3rd checkbox we apply special drawing before making it visible
	wi.g.parent = ghPgCheckboxes;
	wi.g.width = CHECKBOX_WIDTH; wi.g.height = CHECKBOX_HEIGHT; wi.g.x = 5;
	wi.g.y = 5; wi.text = "C1";
	ghCheckbox1 = gwinCheckboxCreate(0, &wi);
	wi.customDraw = gwinCheckboxDraw_CheckOnRight;
	wi.g.y += wi.g.height+1; wi.text = "C2";
	ghCheckbox2 = gwinCheckboxCreate(0, &wi);
	wi.customDraw = gwinCheckboxDraw_Button;
	wi.g.y += wi.g.height+1; wi.text = "C3"; wi.g.width = BUTTON_WIDTH; wi.g.height = BUTTON_HEIGHT;
	ghCheckbox3 = gwinCheckboxCreate(0, &wi);
	wi.g.y += wi.g.height+1; wi.text = "Disable All";
	wi.customDraw = 0; wi.g.width = DISABLEALL_WIDTH; wi.g.height = CHECKBOX_HEIGHT;
	ghCheckDisableAll = gwinCheckboxCreate(0, &wi);

    // Labels
	wi.g.parent = ghPgLabels;
	wi.g.width = pagewidth-10;	wi.g.height = LABEL_HEIGHT;
	wi.g.x = wi.g.y = 5; wi.text = "N/A";
	ghLabelSlider1 = gwinLabelCreate(0, &wi);
	gwinLabelSetAttribute(ghLabelSlider1, 100, "Slider 1:");
	wi.g.y += LABEL_HEIGHT + 2;
	ghLabelSlider2 = gwinLabelCreate(0, &wi);
	gwinLabelSetAttribute(ghLabelSlider2, 100, "Slider 2:");
	wi.g.y += LABEL_HEIGHT + 2;
	ghLabelSlider3 = gwinLabelCreate(0, &wi);
	gwinLabelSetAttribute(ghLabelSlider3, 100, "Slider 3:");
	wi.g.y += LABEL_HEIGHT + 2;
	ghLabelSlider4 = gwinLabelCreate(0, &wi);
	gwinLabelSetAttribute(ghLabelSlider4, 100, "Slider 4:");
	wi.g.y += LABEL_HEIGHT + 2;
	ghLabelRadio1 = gwinLabelCreate(0, &wi);
	gwinLabelSetAttribute(ghLabelRadio1, 100, "RadioButton 1:");


	// Radio Buttons
	wi.g.parent = ghPgRadios;
	wi.g.width = RADIO_WIDTH; wi.g.height = RADIO_HEIGHT; wi.g.y = 5;
	wi.g.x = 5; wi.text = "Yes";
	ghRadio1 = gwinRadioCreate(0, &wi, GROUP_YESNO);
	wi.g.x += wi.g.width; wi.text = "No"; if (wi.g.x + wi.g.width > pagewidth) { wi.g.x = 5; wi.g.y += RADIO_HEIGHT; }
	ghRadio2 = gwinRadioCreate(0, &wi, GROUP_YESNO);
	gwinRadioPress(ghRadio1);
	wi.g.width = COLOR_WIDTH; wi.g.y += RADIO_HEIGHT+5;
	wi.g.x = 5; wi.text = "Black";
	ghRadioBlack = gwinRadioCreate(0, &wi, GROUP_COLORS);
	wi.g.x += wi.g.width; wi.text = "White"; if (wi.g.x + wi.g.width > pagewidth) { wi.g.x = 5; wi.g.y += RADIO_HEIGHT; }
	ghRadioWhite = gwinRadioCreate(0, &wi, GROUP_COLORS);
	wi.g.x += wi.g.width; wi.text = "Yellow"; if (wi.g.x + wi.g.width > pagewidth) { wi.g.x = 5; wi.g.y += RADIO_HEIGHT; }
	ghRadioYellow = gwinRadioCreate(0, &wi, GROUP_COLORS);
	gwinRadioPress(ghRadioWhite);

	// Lists
	border = pagewidth < 10+2*LIST_WIDTH ? 2 : 5;
	wi.g.parent = ghPgLists;
	wi.g.width = LIST_WIDTH; wi.g.height = LIST_HEIGHT; wi.g.y = border;
	wi.g.x = border; wi.text = "L1";
	ghList1 = gwinListCreate(0, &wi, FALSE);
	gwinListAddItem(ghList1, "Item 0", FALSE);
	gwinListAddItem(ghList1, "Item 1", FALSE);
	gwinListAddItem(ghList1, "Item 2", FALSE);
	gwinListAddItem(ghList1, "Item 3", FALSE);
	gwinListAddItem(ghList1, "Item 4", FALSE);
	gwinListAddItem(ghList1, "Item 5", FALSE);
	gwinListAddItem(ghList1, "Item 6", FALSE);
	gwinListAddItem(ghList1, "Item 7", FALSE);
	gwinListAddItem(ghList1, "Item 8", FALSE);
	gwinListAddItem(ghList1, "Item 9", FALSE);
	gwinListAddItem(ghList1, "Item 10", FALSE);
	gwinListAddItem(ghList1, "Item 11", FALSE);
	gwinListAddItem(ghList1, "Item 12", FALSE);
	gwinListAddItem(ghList1, "Item 13", FALSE);
	wi.text = "L2"; wi.g.x += LIST_WIDTH+border; if (wi.g.x + LIST_WIDTH > pagewidth) { wi.g.x = border; wi.g.y += LIST_HEIGHT+border; }
	ghList2 = gwinListCreate(0, &wi, TRUE);
	gwinListAddItem(ghList2, "Item 0", FALSE);
	gwinListAddItem(ghList2, "Item 1", FALSE);
	gwinListAddItem(ghList2, "Item 2", FALSE);
	gwinListAddItem(ghList2, "Item 3", FALSE);
	gwinListAddItem(ghList2, "Item 4", FALSE);
	gwinListAddItem(ghList2, "Item 5", FALSE);
	gwinListAddItem(ghList2, "Item 6", FALSE);
	gwinListAddItem(ghList2, "Item 7", FALSE);
	gwinListAddItem(ghList2, "Item 8", FALSE);
	gwinListAddItem(ghList2, "Item 9", FALSE);
	gwinListAddItem(ghList2, "Item 10", FALSE);
	gwinListAddItem(ghList2, "Item 11", FALSE);
	gwinListAddItem(ghList2, "Item 12", FALSE);
	gwinListAddItem(ghList2, "Item 13", FALSE);
	wi.text = "L3"; wi.g.x += LIST_WIDTH+border; if (wi.g.x + LIST_WIDTH > pagewidth) { wi.g.x = border; wi.g.y += LIST_HEIGHT+border; }
	ghList3 = gwinListCreate(0, &wi, TRUE);
	gwinListAddItem(ghList3, "Item 0", FALSE);
	gwinListAddItem(ghList3, "Item 1", FALSE);
	gwinListAddItem(ghList3, "Item 2", FALSE);
	gwinListAddItem(ghList3, "Item 3", FALSE);
	gdispImageOpenFile(&imgYesNo, "image_yesno.gif");
	gwinListItemSetImage(ghList3, 1, &imgYesNo);
	gwinListItemSetImage(ghList3, 3, &imgYesNo);
	wi.text = "L4"; wi.g.x += LIST_WIDTH+border; if (wi.g.x + LIST_WIDTH > pagewidth) { wi.g.x = border; wi.g.y += LIST_HEIGHT+border; }
	ghList4 = gwinListCreate(0, &wi, TRUE);
	gwinListAddItem(ghList4, "Item 0", FALSE);
	gwinListAddItem(ghList4, "Item 1", FALSE);
	gwinListAddItem(ghList4, "Item 2", FALSE);
	gwinListAddItem(ghList4, "Item 3", FALSE);
	gwinListAddItem(ghList4, "Item 4", FALSE);
	gwinListAddItem(ghList4, "Item 5", FALSE);
	gwinListAddItem(ghList4, "Item 6", FALSE);
	gwinListAddItem(ghList4, "Item 7", FALSE);
	gwinListAddItem(ghList4, "Item 8", FALSE);
	gwinListAddItem(ghList4, "Item 9", FALSE);
	gwinListAddItem(ghList4, "Item 10", FALSE);
	gwinListAddItem(ghList4, "Item 11", FALSE);
	gwinListAddItem(ghList4, "Item 12", FALSE);
	gwinListAddItem(ghList4, "Item 13", FALSE);
	gwinListSetScroll(ghList4, scrollSmooth);

	// Image
	wi.g.parent = ghPgImages;
	wi.g.x = wi.g.y = 0; wi.g.width = pagewidth; wi.g.height = gwinGetInnerHeight(ghPgImages);
	ghImage1 = gwinImageCreate(0, &wi.g);
	gwinImageOpenFile(ghImage1, "romfs_img_ugfx.gif");

	// Progressbar
	wi.g.parent = ghPgProgressbars;
	wi.g.width = pagewidth-10; wi.g.height = SLIDER_WIDTH; wi.g.y = 5;
	wi.g.x = 5; wi.text = "Progressbar 1";
	ghProgressbar1 = gwinProgressbarCreate(0, &wi);
	gwinProgressbarSetResolution(ghProgressbar1, 10);
}

/**
 * Set the value of the labels
 */
static void setLabels(void) {
	char tmp[20];

	// The sliders
	snprintg(tmp, sizeof(tmp), "%d%%", gwinSliderGetPosition(ghSlider1));
	gwinSetText(ghLabelSlider1, tmp, TRUE);
	snprintg(tmp, sizeof(tmp), "%d%%", gwinSliderGetPosition(ghSlider2));
	gwinSetText(ghLabelSlider2, tmp, TRUE);
	snprintg(tmp, sizeof(tmp), "%d%%", gwinSliderGetPosition(ghSlider3));
	gwinSetText(ghLabelSlider3, tmp, TRUE);
	snprintg(tmp, sizeof(tmp), "%d%%", gwinSliderGetPosition(ghSlider4));
	gwinSetText(ghLabelSlider4, tmp, TRUE);

	// The radio buttons
	if (gwinRadioIsPressed(ghRadio1))
		gwinSetText(ghLabelRadio1, "Yes", TRUE);
	else if (gwinRadioIsPressed(ghRadio2))
		gwinSetText(ghLabelRadio1, "No", TRUE);
}

/**
 * Control the progress bar auto-increment
 */
static void setProgressbar(bool_t onoff) {
	if (onoff)
		gwinProgressbarStart(ghProgressbar1, 500);
	else {
		gwinProgressbarStop(ghProgressbar1);		// Stop the progress bar
		gwinProgressbarReset(ghProgressbar1);
	}
}

/**
 * Set the enabled state of every widget (except the tabs etc)
 */
static void setEnabled(bool_t ena) {
	gwinSetEnabled(ghPgButtons, ena);
	gwinSetEnabled(ghPgSliders, ena);
	gwinSetEnabled(ghPgLabels, ena);
	gwinSetEnabled(ghPgRadios, ena);
	gwinSetEnabled(ghPgLists, ena);
	gwinSetEnabled(ghPgImages, ena);
	gwinSetEnabled(ghPgProgressbars, ena);
	// Checkboxes we need to do individually so we don't disable the checkbox to re-enable everything
	gwinSetEnabled(ghCheckbox1, ena);
	gwinSetEnabled(ghCheckbox2, ena);
	gwinSetEnabled(ghCheckbox3, ena);
	//gwinSetEnabled(ghCheckDisableAll, TRUE);
}

static void FlashOffFn(void *param) {
	(void)	param;

	gwinNoFlash(ghCheckbox3);
}

int main(void) {
	GEvent *			pe;

	// Initialize the display
	gfxInit();

	// Set the widget defaults
	font = gdispOpenFont("*");			// Get the first defined font.
	gwinSetDefaultFont(font);
	gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE);
	gdispClear(White);

	// Create the gwin windows/widgets
	createWidgets();

    // Assign toggles and dials to specific buttons & sliders etc.
	#if GINPUT_NEED_TOGGLE
		gwinAttachToggle(ghButton1, 0, 0);
		gwinAttachToggle(ghButton2, 0, 1);
	#endif
	#if GINPUT_NEED_DIAL
		gwinAttachDial(ghSlider1, 0, 0);
		gwinAttachDial(ghSlider3, 0, 1);
	#endif

	// Make the console visible
	gwinShow(ghConsole);
	gwinClear(ghConsole);

    // We want to listen for widget events
	geventListenerInit(&gl);
	gwinAttachListener(&gl);
	gtimerInit(&FlashTimer);

	#if !GWIN_NEED_TABSET
		// Press the Tab we want visible
		gwinRadioPress(ghTabButtons);
	#endif

	while(1) {
		// Get an Event
		pe = geventEventWait(&gl, TIME_INFINITE);

		switch(pe->type) {
		case GEVENT_GWIN_BUTTON:
			gwinPrintf(ghConsole, "Button %s\n", gwinGetText(((GEventGWinButton *)pe)->gwin));
			break;

		case GEVENT_GWIN_SLIDER:
			gwinPrintf(ghConsole, "Slider %s=%d\n", gwinGetText(((GEventGWinSlider *)pe)->gwin), ((GEventGWinSlider *)pe)->position);
			break;

		case GEVENT_GWIN_CHECKBOX:
			gwinPrintf(ghConsole, "Checkbox %s=%s\n", gwinGetText(((GEventGWinCheckbox *)pe)->gwin), ((GEventGWinCheckbox *)pe)->isChecked ? "Checked" : "UnChecked");

			// If it is the Disable All checkbox then do that.
			if (((GEventGWinCheckbox *)pe)->gwin == ghCheckDisableAll) {
				gwinPrintf(ghConsole, "%s All\n", ((GEventGWinCheckbox *)pe)->isChecked ? "Disable" : "Enable");
				setEnabled(!((GEventGWinCheckbox *)pe)->isChecked);

			// If it is the toggle button checkbox start the flash.
			} else if (((GEventGWinCheckbox *)pe)->gwin == ghCheckbox3) {
				gwinFlash(ghCheckbox3);
				gtimerStart(&FlashTimer, FlashOffFn, 0, FALSE, 3000);
			}
			break;

		case GEVENT_GWIN_LIST:
			gwinPrintf(ghConsole, "List %s Item %d %s\n", gwinGetText(((GEventGWinList *)pe)->gwin), ((GEventGWinList *)pe)->item,
					gwinListItemIsSelected(((GEventGWinList *)pe)->gwin, ((GEventGWinList *)pe)->item) ? "Selected" : "Unselected");
			break;

		case GEVENT_GWIN_RADIO:
			gwinPrintf(ghConsole, "Radio Group %u=%s\n", ((GEventGWinRadio *)pe)->group, gwinGetText(((GEventGWinRadio *)pe)->gwin));

			switch(((GEventGWinRadio *)pe)->group) {
			#if !GWIN_NEED_TABSET
				case GROUP_TABS:

					// Set control visibility depending on the tab selected
					setTab(((GEventGWinRadio *)pe)->gwin);

					// We show the state of some of the GUI elements here
					setProgressbar(((GEventGWinRadio *)pe)->gwin == ghTabProgressbar);
					if (((GEventGWinRadio *)pe)->gwin == ghTabLabels)
						setLabels();
					break;
			#endif

			case GROUP_COLORS:
				{
					const GWidgetStyle	*pstyle;

					gwinPrintf(ghConsole, "Change Color Scheme\n");

					if (((GEventGWinRadio *)pe)->gwin == ghRadioYellow)
						pstyle = &YellowWidgetStyle;
					else if (((GEventGWinRadio *)pe)->gwin == ghRadioBlack)
						pstyle = &BlackWidgetStyle;
					else
						pstyle = &WhiteWidgetStyle;

					// Clear the screen to the new color
					gdispClear(pstyle->background);

					// Update the style on all controls
					gwinSetDefaultStyle(pstyle, TRUE);
				}
				break;
			}
			break;

		#if GWIN_NEED_TABSET
			case GEVENT_GWIN_TABSET:
				gwinPrintf(ghConsole, "TabPage %u (%s)\n", ((GEventGWinTabset *)pe)->nPage, gwinTabsetGetTitle(((GEventGWinTabset *)pe)->ghPage));

				// We show the state of some of the GUI elements here
				setProgressbar(((GEventGWinTabset *)pe)->ghPage == ghPgProgressbars);
				if (((GEventGWinTabset *)pe)->ghPage == ghPgLabels)
					setLabels();
				break;
		#endif

		default:
			gwinPrintf(ghConsole, "Unknown %d\n", pe->type);
			break;
		}
	}
	return 0;
}
n class="sb">`CreateConnection<MockPacketStream>()` and `PacketReader<MockPacketStream>` in tests. ``` MockPacketStream mock_stream; EXPECT_CALL(mock_stream, ...)...; .. set more expectations on mock_stream ... PacketReader<MockPacketStream> reader(&mock_stream); ... exercise reader ... ``` ## Mocking Free Functions ## It's possible to use Google Mock to mock a free function (i.e. a C-style function or a static method). You just need to rewrite your code to use an interface (abstract class). Instead of calling a free function (say, `OpenFile`) directly, introduce an interface for it and have a concrete subclass that calls the free function: ``` class FileInterface { public: ... virtual bool Open(const char* path, const char* mode) = 0; }; class File : public FileInterface { public: ... virtual bool Open(const char* path, const char* mode) { return OpenFile(path, mode); } }; ``` Your code should talk to `FileInterface` to open a file. Now it's easy to mock out the function. This may seem much hassle, but in practice you often have multiple related functions that you can put in the same interface, so the per-function syntactic overhead will be much lower. If you are concerned about the performance overhead incurred by virtual functions, and profiling confirms your concern, you can combine this with the recipe for [mocking non-virtual methods](#Mocking_Nonvirtual_Methods.md). ## The Nice, the Strict, and the Naggy ## If a mock method has no `EXPECT_CALL` spec but is called, Google Mock will print a warning about the "uninteresting call". The rationale is: * New methods may be added to an interface after a test is written. We shouldn't fail a test just because a method it doesn't know about is called. * However, this may also mean there's a bug in the test, so Google Mock shouldn't be silent either. If the user believes these calls are harmless, he can add an `EXPECT_CALL()` to suppress the warning. However, sometimes you may want to suppress all "uninteresting call" warnings, while sometimes you may want the opposite, i.e. to treat all of them as errors. Google Mock lets you make the decision on a per-mock-object basis. Suppose your test uses a mock class `MockFoo`: ``` TEST(...) { MockFoo mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` If a method of `mock_foo` other than `DoThis()` is called, it will be reported by Google Mock as a warning. However, if you rewrite your test to use `NiceMock<MockFoo>` instead, the warning will be gone, resulting in a cleaner test output: ``` using ::testing::NiceMock; TEST(...) { NiceMock<MockFoo> mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` `NiceMock<MockFoo>` is a subclass of `MockFoo`, so it can be used wherever `MockFoo` is accepted. It also works if `MockFoo`'s constructor takes some arguments, as `NiceMock<MockFoo>` "inherits" `MockFoo`'s constructors: ``` using ::testing::NiceMock; TEST(...) { NiceMock<MockFoo> mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... } ``` The usage of `StrictMock` is similar, except that it makes all uninteresting calls failures: ``` using ::testing::StrictMock; TEST(...) { StrictMock<MockFoo> mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... // The test will fail if a method of mock_foo other than DoThis() // is called. } ``` There are some caveats though (I don't like them just as much as the next guy, but sadly they are side effects of C++'s limitations): 1. `NiceMock<MockFoo>` and `StrictMock<MockFoo>` only work for mock methods defined using the `MOCK_METHOD*` family of macros **directly** in the `MockFoo` class. If a mock method is defined in a **base class** of `MockFoo`, the "nice" or "strict" modifier may not affect it, depending on the compiler. In particular, nesting `NiceMock` and `StrictMock` (e.g. `NiceMock<StrictMock<MockFoo> >`) is **not** supported. 1. The constructors of the base mock (`MockFoo`) cannot have arguments passed by non-const reference, which happens to be banned by the [Google C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). 1. During the constructor or destructor of `MockFoo`, the mock object is _not_ nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent with C++'s general rule: if a constructor or destructor calls a virtual method of `this` object, that method is treated as non-virtual. In other words, to the base class's constructor or destructor, `this` object behaves like an instance of the base class, not the derived class. This rule is required for safety. Otherwise a base constructor may use members of a derived class before they are initialized, or a base destructor may use members of a derived class after they have been destroyed.) Finally, you should be **very cautious** about when to use naggy or strict mocks, as they tend to make tests more brittle and harder to maintain. When you refactor your code without changing its externally visible behavior, ideally you should't need to update any tests. If your code interacts with a naggy mock, however, you may start to get spammed with warnings as the result of your change. Worse, if your code interacts with a strict mock, your tests may start to fail and you'll be forced to fix them. Our general recommendation is to use nice mocks (not yet the default) most of the time, use naggy mocks (the current default) when developing or debugging tests, and use strict mocks only as the last resort. ## Simplifying the Interface without Breaking Existing Code ## Sometimes a method has a long list of arguments that is mostly uninteresting. For example, ``` class LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const struct tm* tm_time, const char* message, size_t message_len) = 0; }; ``` This method's argument list is lengthy and hard to work with (let's say that the `message` argument is not even 0-terminated). If we mock it as is, using the mock will be awkward. If, however, we try to simplify this interface, we'll need to fix all clients depending on it, which is often infeasible. The trick is to re-dispatch the method in the mock class: ``` class ScopedMockLog : public LogSink { public: ... virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const tm* tm_time, const char* message, size_t message_len) { // We are only interested in the log severity, full file name, and // log message. Log(severity, full_filename, std::string(message, message_len)); } // Implements the mock method: // // void Log(LogSeverity severity, // const string& file_path, // const string& message); MOCK_METHOD3(Log, void(LogSeverity severity, const string& file_path, const string& message)); }; ``` By defining a new mock method with a trimmed argument list, we make the mock class much more user-friendly. ## Alternative to Mocking Concrete Classes ## Often you may find yourself using classes that don't implement interfaces. In order to test your code that uses such a class (let's call it `Concrete`), you may be tempted to make the methods of `Concrete` virtual and then mock it. Try not to do that. Making a non-virtual function virtual is a big decision. It creates an extension point where subclasses can tweak your class' behavior. This weakens your control on the class because now it's harder to maintain the class' invariants. You should make a function virtual only when there is a valid reason for a subclass to override it. Mocking concrete classes directly is problematic as it creates a tight coupling between the class and the tests - any small change in the class may invalidate your tests and make test maintenance a pain. To avoid such problems, many programmers have been practicing "coding to interfaces": instead of talking to the `Concrete` class, your code would define an interface and talk to it. Then you implement that interface as an adaptor on top of `Concrete`. In tests, you can easily mock that interface to observe how your code is doing. This technique incurs some overhead: * You pay the cost of virtual function calls (usually not a problem). * There is more abstraction for the programmers to learn. However, it can also bring significant benefits in addition to better testability: * `Concrete`'s API may not fit your problem domain very well, as you may not be the only client it tries to serve. By designing your own interface, you have a chance to tailor it to your need - you may add higher-level functionalities, rename stuff, etc instead of just trimming the class. This allows you to write your code (user of the interface) in a more natural way, which means it will be more readable, more maintainable, and you'll be more productive. * If `Concrete`'s implementation ever has to change, you don't have to rewrite everywhere it is used. Instead, you can absorb the change in your implementation of the interface, and your other code and tests will be insulated from this change. Some people worry that if everyone is practicing this technique, they will end up writing lots of redundant code. This concern is totally understandable. However, there are two reasons why it may not be the case: * Different projects may need to use `Concrete` in different ways, so the best interfaces for them will be different. Therefore, each of them will have its own domain-specific interface on top of `Concrete`, and they will not be the same code. * If enough projects want to use the same interface, they can always share it, just like they have been sharing `Concrete`. You can check in the interface and the adaptor somewhere near `Concrete` (perhaps in a `contrib` sub-directory) and let many projects use it. You need to weigh the pros and cons carefully for your particular problem, but I'd like to assure you that the Java community has been practicing this for a long time and it's a proven effective technique applicable in a wide variety of situations. :-) ## Delegating Calls to a Fake ## Some times you have a non-trivial fake implementation of an interface. For example: ``` class Foo { public: virtual ~Foo() {} virtual char DoThis(int n) = 0; virtual void DoThat(const char* s, int* p) = 0; }; class FakeFoo : public Foo { public: virtual char DoThis(int n) { return (n > 0) ? '+' : (n < 0) ? '-' : '0'; } virtual void DoThat(const char* s, int* p) { *p = strlen(s); } }; ``` Now you want to mock this interface such that you can set expectations on it. However, you also want to use `FakeFoo` for the default behavior, as duplicating it in the mock object is, well, a lot of work. When you define the mock class using Google Mock, you can have it delegate its default action to a fake class you already have, using this pattern: ``` using ::testing::_; using ::testing::Invoke; class MockFoo : public Foo { public: // Normal mock method definitions using Google Mock. MOCK_METHOD1(DoThis, char(int n)); MOCK_METHOD2(DoThat, void(const char* s, int* p)); // Delegates the default actions of the methods to a FakeFoo object. // This must be called *before* the custom ON_CALL() statements. void DelegateToFake() { ON_CALL(*this, DoThis(_)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThis)); ON_CALL(*this, DoThat(_, _)) .WillByDefault(Invoke(&fake_, &FakeFoo::DoThat)); } private: FakeFoo fake_; // Keeps an instance of the fake in the mock. }; ``` With that, you can use `MockFoo` in your tests as usual. Just remember that if you don't explicitly set an action in an `ON_CALL()` or `EXPECT_CALL()`, the fake will be called upon to do it: ``` using ::testing::_; TEST(AbcTest, Xyz) { MockFoo foo; foo.DelegateToFake(); // Enables the fake for delegation. // Put your ON_CALL(foo, ...)s here, if any. // No action specified, meaning to use the default action. EXPECT_CALL(foo, DoThis(5)); EXPECT_CALL(foo, DoThat(_, _)); int n = 0; EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. EXPECT_EQ(2, n); } ``` **Some tips:** * If you want, you can still override the default action by providing your own `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. * In `DelegateToFake()`, you only need to delegate the methods whose fake implementation you intend to use. * The general technique discussed here works for overloaded methods, but you'll need to tell the compiler which version you mean. To disambiguate a mock function (the one you specify inside the parentheses of `ON_CALL()`), see the "Selecting Between Overloaded Functions" section on this page; to disambiguate a fake function (the one you place inside `Invoke()`), use a `static_cast` to specify the function's type. For instance, if class `Foo` has methods `char DoThis(int n)` and `bool DoThis(double x) const`, and you want to invoke the latter, you need to write `Invoke(&fake_, static_cast<bool (FakeFoo::*)(double) const>(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` (The strange-looking thing inside the angled brackets of `static_cast` is the type of a function pointer to the second `DoThis()` method.). * Having to mix a mock and a fake is often a sign of something gone wrong. Perhaps you haven't got used to the interaction-based way of testing yet. Or perhaps your interface is taking on too many roles and should be split up. Therefore, **don't abuse this**. We would only recommend to do it as an intermediate step when you are refactoring your code. Regarding the tip on mixing a mock and a fake, here's an example on why it may be a bad sign: Suppose you have a class `System` for low-level system operations. In particular, it does file and I/O operations. And suppose you want to test how your code uses `System` to do I/O, and you just want the file operations to work normally. If you mock out the entire `System` class, you'll have to provide a fake implementation for the file operation part, which suggests that `System` is taking on too many roles. Instead, you can define a `FileOps` interface and an `IOOps` interface and split `System`'s functionalities into the two. Then you can mock `IOOps` without mocking `FileOps`. ## Delegating Calls to a Real Object ## When using testing doubles (mocks, fakes, stubs, and etc), sometimes their behaviors will differ from those of the real objects. This difference could be either intentional (as in simulating an error such that you can test the error handling code) or unintentional. If your mocks have different behaviors than the real objects by mistake, you could end up with code that passes the tests but fails in production. You can use the _delegating-to-real_ technique to ensure that your mock has the same behavior as the real object while retaining the ability to validate calls. This technique is very similar to the delegating-to-fake technique, the difference being that we use a real object instead of a fake. Here's an example: ``` using ::testing::_; using ::testing::AtLeast; using ::testing::Invoke; class MockFoo : public Foo { public: MockFoo() { // By default, all calls are delegated to the real object. ON_CALL(*this, DoThis()) .WillByDefault(Invoke(&real_, &Foo::DoThis)); ON_CALL(*this, DoThat(_)) .WillByDefault(Invoke(&real_, &Foo::DoThat)); ... } MOCK_METHOD0(DoThis, ...); MOCK_METHOD1(DoThat, ...); ... private: Foo real_; }; ... MockFoo mock; EXPECT_CALL(mock, DoThis()) .Times(3); EXPECT_CALL(mock, DoThat("Hi")) .Times(AtLeast(1)); ... use mock in test ... ``` With this, Google Mock will verify that your code made the right calls (with the right arguments, in the right order, called the right number of times, etc), and a real object will answer the calls (so the behavior will be the same as in production). This gives you the best of both worlds. ## Delegating Calls to a Parent Class ## Ideally, you should code to interfaces, whose methods are all pure virtual. In reality, sometimes you do need to mock a virtual method that is not pure (i.e, it already has an implementation). For example: ``` class Foo { public: virtual ~Foo(); virtual void Pure(int n) = 0; virtual int Concrete(const char* str) { ... } }; class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); }; ``` Sometimes you may want to call `Foo::Concrete()` instead of `MockFoo::Concrete()`. Perhaps you want to do it as part of a stub action, or perhaps your test doesn't need to mock `Concrete()` at all (but it would be oh-so painful to have to define a new mock class whenever you don't need to mock one of its methods). The trick is to leave a back door in your mock class for accessing the real methods in the base class: ``` class MockFoo : public Foo { public: // Mocking a pure method. MOCK_METHOD1(Pure, void(int n)); // Mocking a concrete method. Foo::Concrete() is shadowed. MOCK_METHOD1(Concrete, int(const char* str)); // Use this to call Concrete() defined in Foo. int FooConcrete(const char* str) { return Foo::Concrete(str); } }; ``` Now, you can call `Foo::Concrete()` inside an action by: ``` using ::testing::_; using ::testing::Invoke; ... EXPECT_CALL(foo, Concrete(_)) .WillOnce(Invoke(&foo, &MockFoo::FooConcrete)); ``` or tell the mock object that you don't want to mock `Concrete()`: ``` using ::testing::Invoke; ... ON_CALL(foo, Concrete(_)) .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete)); ``` (Why don't we just write `Invoke(&foo, &Foo::Concrete)`? If you do that, `MockFoo::Concrete()` will be called (and cause an infinite recursion) since `Foo::Concrete()` is virtual. That's just how C++ works.) # Using Matchers # ## Matching Argument Values Exactly ## You can specify exactly which arguments a mock method is expecting: ``` using ::testing::Return; ... EXPECT_CALL(foo, DoThis(5)) .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", bar)); ``` ## Using Simple Matchers ## You can use matchers to match arguments that have a certain property: ``` using ::testing::Ge; using ::testing::NotNull; using ::testing::Return; ... EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. .WillOnce(Return('a')); EXPECT_CALL(foo, DoThat("Hello", NotNull())); // The second argument must not be NULL. ``` A frequently used matcher is `_`, which matches anything: ``` using ::testing::_; using ::testing::NotNull; ... EXPECT_CALL(foo, DoThat(_, NotNull())); ``` ## Combining Matchers ## You can build complex matchers from existing ones using `AllOf()`, `AnyOf()`, and `Not()`: ``` using ::testing::AllOf; using ::testing::Gt; using ::testing::HasSubstr; using ::testing::Ne; using ::testing::Not; ... // The argument must be > 5 and != 10. EXPECT_CALL(foo, DoThis(AllOf(Gt(5), Ne(10)))); // The first argument must not contain sub-string "blah". EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), NULL)); ``` ## Casting Matchers ## Google Mock matchers are statically typed, meaning that the compiler can catch your mistake if you use a matcher of the wrong type (for example, if you use `Eq(5)` to match a `string` argument). Good for you! Sometimes, however, you know what you're doing and want the compiler to give you some slack. One example is that you have a matcher for `long` and the argument you want to match is `int`. While the two types aren't exactly the same, there is nothing really wrong with using a `Matcher<long>` to match an `int` - after all, we can first convert the `int` argument to a `long` before giving it to the matcher. To support this need, Google Mock gives you the `SafeMatcherCast<T>(m)` function. It casts a matcher `m` to type `Matcher<T>`. To ensure safety, Google Mock checks that (let `U` be the type `m` accepts): 1. Type `T` can be implicitly cast to type `U`; 1. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and 1. When `U` is a reference, `T` must also be a reference (as the underlying matcher may be interested in the address of the `U` value). The code won't compile if any of these conditions isn't met. Here's one example: ``` using ::testing::SafeMatcherCast; // A base class and a child class. class Base { ... }; class Derived : public Base { ... }; class MockFoo : public Foo { public: MOCK_METHOD1(DoThis, void(Derived* derived)); }; ... MockFoo foo; // m is a Matcher<Base*> we got from somewhere. EXPECT_CALL(foo, DoThis(SafeMatcherCast<Derived*>(m))); ``` If you find `SafeMatcherCast<T>(m)` too limiting, you can use a similar function `MatcherCast<T>(m)`. The difference is that `MatcherCast` works as long as you can `static_cast` type `T` to type `U`. `MatcherCast` essentially lets you bypass C++'s type system (`static_cast` isn't always safe as it could throw away information, for example), so be careful not to misuse/abuse it. ## Selecting Between Overloaded Functions ## If you expect an overloaded function to be called, the compiler may need some help on which overloaded version it is. To disambiguate functions overloaded on the const-ness of this object, use the `Const()` argument wrapper. ``` using ::testing::ReturnRef; class MockFoo : public Foo { ... MOCK_METHOD0(GetBar, Bar&()); MOCK_CONST_METHOD0(GetBar, const Bar&()); }; ... MockFoo foo; Bar bar1, bar2; EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). .WillOnce(ReturnRef(bar1)); EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). .WillOnce(ReturnRef(bar2)); ``` (`Const()` is defined by Google Mock and returns a `const` reference to its argument.) To disambiguate overloaded functions with the same number of arguments but different argument types, you may need to specify the exact type of a matcher, either by wrapping your matcher in `Matcher<type>()`, or using a matcher whose type is fixed (`TypedEq<type>`, `An<type>()`, etc): ``` using ::testing::An; using ::testing::Lt; using ::testing::Matcher; using ::testing::TypedEq; class MockPrinter : public Printer { public: MOCK_METHOD1(Print, void(int n)); MOCK_METHOD1(Print, void(char c)); }; TEST(PrinterTest, Print) { MockPrinter printer; EXPECT_CALL(printer, Print(An<int>())); // void Print(int); EXPECT_CALL(printer, Print(Matcher<int>(Lt(5)))); // void Print(int); EXPECT_CALL(printer, Print(TypedEq<char>('a'))); // void Print(char); printer.Print(3); printer.Print(6); printer.Print('a'); } ``` ## Performing Different Actions Based on the Arguments ## When a mock method is called, the _last_ matching expectation that's still active will be selected (think "newer overrides older"). So, you can make a method do different things depending on its argument values like this: ``` using ::testing::_; using ::testing::Lt; using ::testing::Return; ... // The default case. EXPECT_CALL(foo, DoThis(_)) .WillRepeatedly(Return('b')); // The more specific case. EXPECT_CALL(foo, DoThis(Lt(5))) .WillRepeatedly(Return('a')); ``` Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will be returned; otherwise `'b'` will be returned. ## Matching Multiple Arguments as a Whole ## Sometimes it's not enough to match the arguments individually. For example, we may want to say that the first argument must be less than the second argument. The `With()` clause allows us to match all arguments of a mock function as a whole. For example, ``` using ::testing::_; using ::testing::Lt; using ::testing::Ne; ... EXPECT_CALL(foo, InRange(Ne(0), _)) .With(Lt()); ``` says that the first argument of `InRange()` must not be 0, and must be less than the second argument. The expression inside `With()` must be a matcher of type `Matcher< ::testing::tuple<A1, ..., An> >`, where `A1`, ..., `An` are the types of the function arguments. You can also write `AllArgs(m)` instead of `m` inside `.With()`. The two forms are equivalent, but `.With(AllArgs(Lt()))` is more readable than `.With(Lt())`. You can use `Args<k1, ..., kn>(m)` to match the `n` selected arguments (as a tuple) against `m`. For example, ``` using ::testing::_; using ::testing::AllOf; using ::testing::Args; using ::testing::Lt; ... EXPECT_CALL(foo, Blah(_, _, _)) .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); ``` says that `Blah()` will be called with arguments `x`, `y`, and `z` where `x < y < z`. As a convenience and example, Google Mock provides some matchers for 2-tuples, including the `Lt()` matcher above. See the [CheatSheet](CheatSheet.md) for the complete list. Note that if you want to pass the arguments to a predicate of your own (e.g. `.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be written to take a `::testing::tuple` as its argument; Google Mock will pass the `n` selected arguments as _one_ single tuple to the predicate. ## Using Matchers as Predicates ## Have you noticed that a matcher is just a fancy predicate that also knows how to describe itself? Many existing algorithms take predicates as arguments (e.g. those defined in STL's `<algorithm>` header), and it would be a shame if Google Mock matchers are not allowed to participate. Luckily, you can use a matcher where a unary predicate functor is expected by wrapping it inside the `Matches()` function. For example, ``` #include <algorithm> #include <vector> std::vector<int> v; ... // How many elements in v are >= 10? const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); ``` Since you can build complex matchers from simpler ones easily using Google Mock, this gives you a way to conveniently construct composite predicates (doing the same using STL's `<functional>` header is just painful). For example, here's a predicate that's satisfied by any number that is >= 0, <= 100, and != 50: ``` Matches(AllOf(Ge(0), Le(100), Ne(50))) ``` ## Using Matchers in Google Test Assertions ## Since matchers are basically predicates that also know how to describe themselves, there is a way to take advantage of them in [Google Test](../../googletest/) assertions. It's called `ASSERT_THAT` and `EXPECT_THAT`: ``` ASSERT_THAT(value, matcher); // Asserts that value matches matcher. EXPECT_THAT(value, matcher); // The non-fatal version. ``` For example, in a Google Test test you can write: ``` #include "gmock/gmock.h" using ::testing::AllOf; using ::testing::Ge; using ::testing::Le; using ::testing::MatchesRegex; using ::testing::StartsWith; ... EXPECT_THAT(Foo(), StartsWith("Hello")); EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); ``` which (as you can probably guess) executes `Foo()`, `Bar()`, and `Baz()`, and verifies that: * `Foo()` returns a string that starts with `"Hello"`. * `Bar()` returns a string that matches regular expression `"Line \\d+"`. * `Baz()` returns a number in the range [5, 10]. The nice thing about these macros is that _they read like English_. They generate informative messages too. For example, if the first `EXPECT_THAT()` above fails, the message will be something like: ``` Value of: Foo() Actual: "Hi, world!" Expected: starts with "Hello" ``` **Credit:** The idea of `(ASSERT|EXPECT)_THAT` was stolen from the [Hamcrest](https://github.com/hamcrest/) project, which adds `assertThat()` to JUnit. ## Using Predicates as Matchers ## Google Mock provides a built-in set of matchers. In case you find them lacking, you can use an arbitray unary predicate function or functor as a matcher - as long as the predicate accepts a value of the type you want. You do this by wrapping the predicate inside the `Truly()` function, for example: ``` using ::testing::Truly; int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } ... // Bar() must be called with an even number. EXPECT_CALL(foo, Bar(Truly(IsEven))); ``` Note that the predicate function / functor doesn't have to return `bool`. It works as long as the return value can be used as the condition in statement `if (condition) ...`. ## Matching Arguments that Are Not Copyable ## When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, Google Mock saves away a copy of `bar`. When `Foo()` is called later, Google Mock compares the argument to `Foo()` with the saved copy of `bar`. This way, you don't need to worry about `bar` being modified or destroyed after the `EXPECT_CALL()` is executed. The same is true when you use matchers like `Eq(bar)`, `Le(bar)`, and so on. But what if `bar` cannot be copied (i.e. has no copy constructor)? You could define your own matcher function and use it with `Truly()`, as the previous couple of recipes have shown. Or, you may be able to get away from it if you can guarantee that `bar` won't be changed after the `EXPECT_CALL()` is executed. Just tell Google Mock that it should save a reference to `bar`, instead of a copy of it. Here's how: ``` using ::testing::Eq; using ::testing::ByRef; using ::testing::Lt; ... // Expects that Foo()'s argument == bar. EXPECT_CALL(mock_obj, Foo(Eq(ByRef(bar)))); // Expects that Foo()'s argument < bar. EXPECT_CALL(mock_obj, Foo(Lt(ByRef(bar)))); ``` Remember: if you do this, don't change `bar` after the `EXPECT_CALL()`, or the result is undefined. ## Validating a Member of an Object ## Often a mock function takes a reference to object as an argument. When matching the argument, you may not want to compare the entire object against a fixed object, as that may be over-specification. Instead, you may need to validate a certain member variable or the result of a certain getter method of the object. You can do this with `Field()` and `Property()`. More specifically, ``` Field(&Foo::bar, m) ``` is a matcher that matches a `Foo` object whose `bar` member variable satisfies matcher `m`. ``` Property(&Foo::baz, m) ``` is a matcher that matches a `Foo` object whose `baz()` method returns a value that satisfies matcher `m`. For example: > | `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | |:-----------------------------|:-----------------------------------| > | `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no argument and be declared as `const`. BTW, `Field()` and `Property()` can also match plain pointers to objects. For instance, ``` Field(&Foo::number, Ge(3)) ``` matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, the match will always fail regardless of the inner matcher. What if you want to validate more than one members at the same time? Remember that there is `AllOf()`. ## Validating the Value Pointed to by a Pointer Argument ## C++ functions often take pointers as arguments. You can use matchers like `IsNull()`, `NotNull()`, and other comparison matchers to match a pointer, but what if you want to make sure the value _pointed to_ by the pointer, instead of the pointer itself, has a certain property? Well, you can use the `Pointee(m)` matcher. `Pointee(m)` matches a pointer iff `m` matches the value the pointer points to. For example: ``` using ::testing::Ge; using ::testing::Pointee; ... EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); ``` expects `foo.Bar()` to be called with a pointer that points to a value greater than or equal to 3. One nice thing about `Pointee()` is that it treats a `NULL` pointer as a match failure, so you can write `Pointee(m)` instead of ``` AllOf(NotNull(), Pointee(m)) ``` without worrying that a `NULL` pointer will crash your test. Also, did we tell you that `Pointee()` works with both raw pointers **and** smart pointers (`linked_ptr`, `shared_ptr`, `scoped_ptr`, and etc)? What if you have a pointer to pointer? You guessed it - you can use nested `Pointee()` to probe deeper inside the value. For example, `Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer that points to a number less than 3 (what a mouthful...). ## Testing a Certain Property of an Object ## Sometimes you want to specify that an object argument has a certain property, but there is no existing matcher that does this. If you want good error messages, you should define a matcher. If you want to do it quick and dirty, you could get away with writing an ordinary function. Let's say you have a mock function that takes an object of type `Foo`, which has an `int bar()` method and an `int baz()` method, and you want to constrain that the argument's `bar()` value plus its `baz()` value is a given number. Here's how you can define a matcher to do it: ``` using ::testing::MatcherInterface; using ::testing::MatchResultListener; class BarPlusBazEqMatcher : public MatcherInterface<const Foo&> { public: explicit BarPlusBazEqMatcher(int expected_sum) : expected_sum_(expected_sum) {} virtual bool MatchAndExplain(const Foo& foo, MatchResultListener* listener) const { return (foo.bar() + foo.baz()) == expected_sum_; } virtual void DescribeTo(::std::ostream* os) const { *os << "bar() + baz() equals " << expected_sum_; } virtual void DescribeNegationTo(::std::ostream* os) const { *os << "bar() + baz() does not equal " << expected_sum_; } private: const int expected_sum_; }; inline Matcher<const Foo&> BarPlusBazEq(int expected_sum) { return MakeMatcher(new BarPlusBazEqMatcher(expected_sum)); } ... EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; ``` ## Matching Containers ## Sometimes an STL container (e.g. list, vector, map, ...) is passed to a mock function and you may want to validate it. Since most STL containers support the `==` operator, you can write `Eq(expected_container)` or simply `expected_container` to match a container exactly. Sometimes, though, you may want to be more flexible (for example, the first element must be an exact match, but the second element can be any positive number, and so on). Also, containers used in tests often have a small number of elements, and having to define the expected container out-of-line is a bit of a hassle. You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in such cases: ``` using ::testing::_; using ::testing::ElementsAre; using ::testing::Gt; ... MOCK_METHOD1(Foo, void(const vector<int>& numbers)); ... EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); ``` The above matcher says that the container must have 4 elements, which must be 1, greater than 0, anything, and 5 respectively. If you instead write: ``` using ::testing::_; using ::testing::Gt; using ::testing::UnorderedElementsAre; ... MOCK_METHOD1(Foo, void(const vector<int>& numbers)); ... EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); ``` It means that the container must have 4 elements, which under some permutation must be 1, greater than 0, anything, and 5 respectively. `ElementsAre()` and `UnorderedElementsAre()` are overloaded to take 0