1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2014 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#include <bzlib.h>
8#include <dm.h>
9#include <gzip.h>
10#include <log.h>
11#include <malloc.h>
12#include <mapmem.h>
13#include <os.h>
14#include <video.h>
15#include <video_console.h>
16#include <asm/test.h>
17#include <asm/sdl.h>
18#include <dm/test.h>
19#include <dm/uclass-internal.h>
20#include <test/test.h>
21#include <test/ut.h>
22
23/*
24 * These tests use the standard sandbox frame buffer, the resolution of which
25 * is defined in the device tree. This only supports 16bpp so the tests only
26 * test that code path. It would be possible to adjust this fairly easily,
27 * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
28 * in sandbox_sdl_sync() would also need to change to handle the different
29 * surface depth.
30 */
31/* Basic test of the video uclass */
32static int dm_test_video_base(struct unit_test_state *uts)
33{
34	struct video_priv *priv;
35	struct udevice *dev;
36
37	ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
38	ut_asserteq(1366, video_get_xsize(dev));
39	ut_asserteq(768, video_get_ysize(dev));
40	priv = dev_get_uclass_priv(dev);
41	ut_asserteq(priv->fb_size, 1366 * 768 * 2);
42
43	return 0;
44}
45DM_TEST(dm_test_video_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
46
47/**
48 * compress_frame_buffer() - Compress the frame buffer and return its size
49 *
50 * We want to write tests which perform operations on the video console and
51 * check that the frame buffer ends up with the correct contents. But it is
52 * painful to store 'known good' images for comparison with the frame
53 * buffer. As an alternative, we can compress the frame buffer and check the
54 * size of the compressed data. This provides a pretty good level of
55 * certainty and the resulting tests need only check a single value.
56 *
57 * If the copy framebuffer is enabled, this compares it to the main framebuffer
58 * too.
59 *
60 * @uts:	Test state
61 * @dev:	Video device
62 * Return: compressed size of the frame buffer, or -ve on error
63 */
64static int compress_frame_buffer(struct unit_test_state *uts,
65				 struct udevice *dev)
66{
67	struct video_priv *priv = dev_get_uclass_priv(dev);
68	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
69	uint destlen;
70	void *dest;
71	int ret;
72
73	destlen = priv->fb_size;
74	dest = malloc(priv->fb_size);
75	if (!dest)
76		return -ENOMEM;
77	ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
78				       priv->fb, priv->fb_size,
79				       3, 0, 0);
80	free(dest);
81	if (ret)
82		return ret;
83
84	/* Check here that the copy frame buffer is working correctly */
85	if (IS_ENABLED(CONFIG_VIDEO_COPY)) {
86		ut_assertf(!memcmp(uc_priv->fb, uc_priv->copy_fb,
87				   uc_priv->fb_size),
88				   "Copy framebuffer does not match fb");
89	}
90
91	return destlen;
92}
93
94/*
95 * Call this function at any point to halt and show the current display. Be
96 * sure to run the test with the -l flag.
97 */
98static void __maybe_unused see_output(void)
99{
100	video_sync_all();
101	while (1);
102}
103
104/* Select the video console driver to use for a video device */
105static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
106{
107	struct sandbox_sdl_plat *plat;
108	struct udevice *dev;
109
110	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
111	ut_assert(!device_active(dev));
112	plat = dev_get_plat(dev);
113	plat->vidconsole_drv_name = "vidconsole0";
114
115	return 0;
116}
117
118/**
119 * video_get_nologo() - Disable the logo on the video device and return it
120 *
121 * @uts: Test state
122 * @devp: Returns video device
123 * Return: 0 if OK, -ve on error
124 */
125static int video_get_nologo(struct unit_test_state *uts, struct udevice **devp)
126{
127	struct video_uc_plat *uc_plat;
128	struct udevice *dev;
129
130	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
131	ut_assertnonnull(dev);
132	uc_plat = dev_get_uclass_plat(dev);
133	uc_plat->hide_logo = true;
134
135	/* now probe it */
136	ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
137	ut_assertnonnull(dev);
138	*devp = dev;
139
140	return 0;
141}
142
143/* Test text output works on the video console */
144static int dm_test_video_text(struct unit_test_state *uts)
145{
146	struct udevice *dev, *con;
147	int i;
148
149#define WHITE		0xffff
150#define SCROLL_LINES	100
151
152	ut_assertok(select_vidconsole(uts, "vidconsole0"));
153	ut_assertok(video_get_nologo(uts, &dev));
154	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
155	ut_assertok(vidconsole_select_font(con, "8x16", 0));
156	ut_asserteq(46, compress_frame_buffer(uts, dev));
157
158	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
159	vidconsole_putc_xy(con, 0, 0, 'a');
160	ut_asserteq(79, compress_frame_buffer(uts, dev));
161
162	vidconsole_putc_xy(con, 0, 0, ' ');
163	ut_asserteq(46, compress_frame_buffer(uts, dev));
164
165	for (i = 0; i < 20; i++)
166		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
167	ut_asserteq(273, compress_frame_buffer(uts, dev));
168
169	vidconsole_set_row(con, 0, WHITE);
170	ut_asserteq(46, compress_frame_buffer(uts, dev));
171
172	for (i = 0; i < 20; i++)
173		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
174	ut_asserteq(273, compress_frame_buffer(uts, dev));
175
176	return 0;
177}
178DM_TEST(dm_test_video_text, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
179
180static int dm_test_video_text_12x22(struct unit_test_state *uts)
181{
182	struct udevice *dev, *con;
183	int i;
184
185#define WHITE		0xffff
186#define SCROLL_LINES	100
187
188	ut_assertok(select_vidconsole(uts, "vidconsole0"));
189	ut_assertok(video_get_nologo(uts, &dev));
190	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
191	ut_assertok(vidconsole_select_font(con, "12x22", 0));
192	ut_asserteq(46, compress_frame_buffer(uts, dev));
193
194	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
195	vidconsole_putc_xy(con, 0, 0, 'a');
196	ut_asserteq(89, compress_frame_buffer(uts, dev));
197
198	vidconsole_putc_xy(con, 0, 0, ' ');
199	ut_asserteq(46, compress_frame_buffer(uts, dev));
200
201	for (i = 0; i < 20; i++)
202		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
203	ut_asserteq(363, compress_frame_buffer(uts, dev));
204
205	vidconsole_set_row(con, 0, WHITE);
206	ut_asserteq(46, compress_frame_buffer(uts, dev));
207
208	for (i = 0; i < 20; i++)
209		vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
210	ut_asserteq(363, compress_frame_buffer(uts, dev));
211
212	return 0;
213}
214DM_TEST(dm_test_video_text_12x22, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
215
216/* Test handling of special characters in the console */
217static int dm_test_video_chars(struct unit_test_state *uts)
218{
219	struct udevice *dev, *con;
220	const char *test_string = "Well\b\b\b\bxhe is\r \n\ta very \amodest  \bman\n\t\tand Has much to\b\bto be modest about.";
221
222	ut_assertok(select_vidconsole(uts, "vidconsole0"));
223	ut_assertok(video_get_nologo(uts, &dev));
224	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
225	ut_assertok(vidconsole_select_font(con, "8x16", 0));
226	vidconsole_put_string(con, test_string);
227	ut_asserteq(466, compress_frame_buffer(uts, dev));
228
229	return 0;
230}
231DM_TEST(dm_test_video_chars, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
232
233#ifdef CONFIG_VIDEO_ANSI
234#define ANSI_ESC "\x1b"
235/* Test handling of ANSI escape sequences */
236static int dm_test_video_ansi(struct unit_test_state *uts)
237{
238	struct udevice *dev, *con;
239
240	ut_assertok(select_vidconsole(uts, "vidconsole0"));
241	ut_assertok(video_get_nologo(uts, &dev));
242	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
243	ut_assertok(vidconsole_select_font(con, "8x16", 0));
244
245	/* reference clear: */
246	video_clear(con->parent);
247	video_sync(con->parent, false);
248	ut_asserteq(46, compress_frame_buffer(uts, dev));
249
250	/* test clear escape sequence: [2J */
251	vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
252	ut_asserteq(46, compress_frame_buffer(uts, dev));
253
254	/* test set-cursor: [%d;%df */
255	vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
256	ut_asserteq(143, compress_frame_buffer(uts, dev));
257
258	/* test colors (30-37 fg color, 40-47 bg color) */
259	vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
260	vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
261	ut_asserteq(272, compress_frame_buffer(uts, dev));
262
263	return 0;
264}
265DM_TEST(dm_test_video_ansi, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
266#endif
267
268/**
269 * check_vidconsole_output() - Run a text console test
270 *
271 * @uts:	Test state
272 * @rot:	Console rotation (0=normal orientation, 1=90 degrees clockwise,
273 *		2=upside down, 3=90 degree counterclockwise)
274 * @wrap_size:	Expected size of compressed frame buffer for the wrap test
275 * @scroll_size: Same for the scroll test
276 * Return: 0 on success
277 */
278static int check_vidconsole_output(struct unit_test_state *uts, int rot,
279				   int wrap_size, int scroll_size)
280{
281	struct udevice *dev, *con;
282	struct sandbox_sdl_plat *plat;
283	int i;
284
285	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
286	ut_assert(!device_active(dev));
287	plat = dev_get_plat(dev);
288	plat->rot = rot;
289
290	ut_assertok(video_get_nologo(uts, &dev));
291	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
292	ut_assertok(vidconsole_select_font(con, "8x16", 0));
293	ut_asserteq(46, compress_frame_buffer(uts, dev));
294
295	/* Check display wrap */
296	for (i = 0; i < 120; i++)
297		vidconsole_put_char(con, 'A' + i % 50);
298	ut_asserteq(wrap_size, compress_frame_buffer(uts, dev));
299
300	/* Check display scrolling */
301	for (i = 0; i < SCROLL_LINES; i++) {
302		vidconsole_put_char(con, 'A' + i % 50);
303		vidconsole_put_char(con, '\n');
304	}
305	ut_asserteq(scroll_size, compress_frame_buffer(uts, dev));
306
307	/* If we scroll enough, the screen becomes blank again */
308	for (i = 0; i < SCROLL_LINES; i++)
309		vidconsole_put_char(con, '\n');
310	ut_asserteq(46, compress_frame_buffer(uts, dev));
311
312	return 0;
313}
314
315/* Test text output through the console uclass */
316static int dm_test_video_context(struct unit_test_state *uts)
317{
318	ut_assertok(select_vidconsole(uts, "vidconsole0"));
319	ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
320
321	return 0;
322}
323DM_TEST(dm_test_video_context, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
324
325/* Test rotated text output through the console uclass */
326static int dm_test_video_rotation1(struct unit_test_state *uts)
327{
328	ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
329
330	return 0;
331}
332DM_TEST(dm_test_video_rotation1, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
333
334/* Test rotated text output through the console uclass */
335static int dm_test_video_rotation2(struct unit_test_state *uts)
336{
337	ut_assertok(check_vidconsole_output(uts, 2, 783, 445));
338
339	return 0;
340}
341DM_TEST(dm_test_video_rotation2, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
342
343/* Test rotated text output through the console uclass */
344static int dm_test_video_rotation3(struct unit_test_state *uts)
345{
346	ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
347
348	return 0;
349}
350DM_TEST(dm_test_video_rotation3, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
351
352/* Read a file into memory and return a pointer to it */
353static int read_file(struct unit_test_state *uts, const char *fname,
354		     ulong *addrp)
355{
356	int buf_size = 100000;
357	ulong addr = 0;
358	int size, fd;
359	char *buf;
360
361	buf = map_sysmem(addr, 0);
362	ut_assert(buf != NULL);
363	fd = os_open(fname, OS_O_RDONLY);
364	ut_assert(fd >= 0);
365	size = os_read(fd, buf, buf_size);
366	os_close(fd);
367	ut_assert(size >= 0);
368	ut_assert(size < buf_size);
369	*addrp = addr;
370
371	return 0;
372}
373
374/* Test drawing a bitmap file */
375static int dm_test_video_bmp(struct unit_test_state *uts)
376{
377	struct udevice *dev;
378	ulong addr;
379
380	ut_assertok(video_get_nologo(uts, &dev));
381	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
382
383	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
384	ut_asserteq(1368, compress_frame_buffer(uts, dev));
385
386	return 0;
387}
388DM_TEST(dm_test_video_bmp, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
389
390/* Test drawing a bitmap file on a 8bpp display */
391static int dm_test_video_bmp8(struct unit_test_state *uts)
392{
393	struct udevice *dev;
394	ulong addr;
395
396	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
397	ut_assertnonnull(dev);
398	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP8));
399
400	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
401
402	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
403	ut_asserteq(1247, compress_frame_buffer(uts, dev));
404
405	return 0;
406}
407DM_TEST(dm_test_video_bmp8, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
408
409/* Test drawing a bitmap file on a 16bpp display */
410static int dm_test_video_bmp16(struct unit_test_state *uts)
411{
412	ulong src, src_len = ~0UL;
413	uint dst_len = ~0U;
414	struct udevice *dev;
415	ulong dst = 0x10000;
416
417	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
418	ut_assertnonnull(dev);
419	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP16));
420
421	ut_assertok(read_file(uts, "tools/logos/denx-16bpp.bmp.gz", &src));
422	ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
423			   &src_len));
424
425	ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
426	ut_asserteq(3700, compress_frame_buffer(uts, dev));
427
428	return 0;
429}
430DM_TEST(dm_test_video_bmp16, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
431
432/* Test drawing a 24bpp bitmap file on a 16bpp display */
433static int dm_test_video_bmp24(struct unit_test_state *uts)
434{
435	ulong src, src_len = ~0UL;
436	uint dst_len = ~0U;
437	struct udevice *dev;
438	ulong dst = 0x10000;
439
440	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
441	ut_assertnonnull(dev);
442	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP16));
443
444	ut_assertok(read_file(uts, "tools/logos/denx-24bpp.bmp.gz", &src));
445	ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
446			   &src_len));
447
448	ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
449	ut_asserteq(3656, compress_frame_buffer(uts, dev));
450
451	return 0;
452}
453DM_TEST(dm_test_video_bmp24, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
454
455/* Test drawing a 24bpp bitmap file on a 32bpp display */
456static int dm_test_video_bmp24_32(struct unit_test_state *uts)
457{
458	ulong src, src_len = ~0UL;
459	uint dst_len = ~0U;
460	struct udevice *dev;
461	ulong dst = 0x10000;
462
463	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
464	ut_assertnonnull(dev);
465	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
466
467	ut_assertok(read_file(uts, "tools/logos/denx-24bpp.bmp.gz", &src));
468	ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
469			   &src_len));
470
471	ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
472	ut_asserteq(6827, compress_frame_buffer(uts, dev));
473
474	return 0;
475}
476DM_TEST(dm_test_video_bmp24_32, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
477
478/* Test drawing a bitmap file on a 32bpp display */
479static int dm_test_video_bmp32(struct unit_test_state *uts)
480{
481	struct udevice *dev;
482	ulong addr;
483
484	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
485	ut_assertnonnull(dev);
486	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
487	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
488
489	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
490	ut_asserteq(2024, compress_frame_buffer(uts, dev));
491
492	return 0;
493}
494DM_TEST(dm_test_video_bmp32, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
495
496/* Test drawing a compressed bitmap file */
497static int dm_test_video_bmp_comp(struct unit_test_state *uts)
498{
499	struct udevice *dev;
500	ulong addr;
501
502	ut_assertok(video_get_nologo(uts, &dev));
503	ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
504
505	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
506	ut_asserteq(1368, compress_frame_buffer(uts, dev));
507
508	return 0;
509}
510DM_TEST(dm_test_video_bmp_comp, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
511
512/* Test drawing a bitmap file on a 32bpp display */
513static int dm_test_video_comp_bmp32(struct unit_test_state *uts)
514{
515	struct udevice *dev;
516	ulong addr;
517
518	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
519	ut_assertnonnull(dev);
520	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
521
522	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
523
524	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
525	ut_asserteq(2024, compress_frame_buffer(uts, dev));
526
527	return 0;
528}
529DM_TEST(dm_test_video_comp_bmp32, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
530
531/* Test drawing a bitmap file on a 8bpp display */
532static int dm_test_video_comp_bmp8(struct unit_test_state *uts)
533{
534	struct udevice *dev;
535	ulong addr;
536
537	ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
538	ut_assertnonnull(dev);
539	ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP8));
540
541	ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
542
543	ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
544	ut_asserteq(1247, compress_frame_buffer(uts, dev));
545
546	return 0;
547}
548DM_TEST(dm_test_video_comp_bmp8, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
549
550/* Test TrueType console */
551static int dm_test_video_truetype(struct unit_test_state *uts)
552{
553	struct udevice *dev, *con;
554	const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye";
555
556	ut_assertok(video_get_nologo(uts, &dev));
557	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
558	vidconsole_put_string(con, test_string);
559	ut_asserteq(12174, compress_frame_buffer(uts, dev));
560
561	return 0;
562}
563DM_TEST(dm_test_video_truetype, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
564
565/* Test scrolling TrueType console */
566static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
567{
568	struct sandbox_sdl_plat *plat;
569	struct udevice *dev, *con;
570	const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye";
571
572	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
573	ut_assert(!device_active(dev));
574	plat = dev_get_plat(dev);
575	plat->font_size = 100;
576
577	ut_assertok(video_get_nologo(uts, &dev));
578	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
579	vidconsole_put_string(con, test_string);
580	ut_asserteq(34287, compress_frame_buffer(uts, dev));
581
582	return 0;
583}
584DM_TEST(dm_test_video_truetype_scroll, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
585
586/* Test TrueType backspace, within and across lines */
587static int dm_test_video_truetype_bs(struct unit_test_state *uts)
588{
589	struct sandbox_sdl_plat *plat;
590	struct udevice *dev, *con;
591	const char *test_string = "...Criticism may or may\b\b\b\b\b\bnot be agreeable, but seldom it is necessary\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bit is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things.";
592
593	ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
594	ut_assert(!device_active(dev));
595	plat = dev_get_plat(dev);
596	plat->font_size = 100;
597
598	ut_assertok(video_get_nologo(uts, &dev));
599	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
600	vidconsole_put_string(con, test_string);
601	ut_asserteq(29471, compress_frame_buffer(uts, dev));
602
603	return 0;
604}
605DM_TEST(dm_test_video_truetype_bs, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
606