1 #include <stdio.h>
2 #include <string.h>
3 
4 #include "py/obj.h"
5 #include "py/objstr.h"
6 #include "py/runtime.h"
7 #include "py/gc.h"
8 #include "py/repl.h"
9 #include "py/mpz.h"
10 #include "py/builtin.h"
11 #include "py/emit.h"
12 #include "py/formatfloat.h"
13 #include "py/ringbuf.h"
14 #include "py/pairheap.h"
15 #include "py/stream.h"
16 #include "py/binary.h"
17 #include "py/bc.h"
18 
19 // expected output of this file is found in extra_coverage.py.exp
20 
21 #if defined(MICROPY_UNIX_COVERAGE)
22 
23 // stream testing object
24 typedef struct _mp_obj_streamtest_t {
25     mp_obj_base_t base;
26     uint8_t *buf;
27     size_t len;
28     size_t pos;
29     int error_code;
30 } mp_obj_streamtest_t;
31 
stest_set_buf(mp_obj_t o_in,mp_obj_t buf_in)32 STATIC mp_obj_t stest_set_buf(mp_obj_t o_in, mp_obj_t buf_in) {
33     mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in);
34     mp_buffer_info_t bufinfo;
35     mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
36     o->buf = m_new(uint8_t, bufinfo.len);
37     memcpy(o->buf, bufinfo.buf, bufinfo.len);
38     o->len = bufinfo.len;
39     o->pos = 0;
40     return mp_const_none;
41 }
42 STATIC MP_DEFINE_CONST_FUN_OBJ_2(stest_set_buf_obj, stest_set_buf);
43 
stest_set_error(mp_obj_t o_in,mp_obj_t err_in)44 STATIC mp_obj_t stest_set_error(mp_obj_t o_in, mp_obj_t err_in) {
45     mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in);
46     o->error_code = mp_obj_get_int(err_in);
47     return mp_const_none;
48 }
49 STATIC MP_DEFINE_CONST_FUN_OBJ_2(stest_set_error_obj, stest_set_error);
50 
stest_read(mp_obj_t o_in,void * buf,mp_uint_t size,int * errcode)51 STATIC mp_uint_t stest_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
52     mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in);
53     if (o->pos < o->len) {
54         if (size > o->len - o->pos) {
55             size = o->len - o->pos;
56         }
57         memcpy(buf, o->buf + o->pos, size);
58         o->pos += size;
59         return size;
60     } else if (o->error_code == 0) {
61         return 0;
62     } else {
63         *errcode = o->error_code;
64         return MP_STREAM_ERROR;
65     }
66 }
67 
stest_write(mp_obj_t o_in,const void * buf,mp_uint_t size,int * errcode)68 STATIC mp_uint_t stest_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
69     mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in);
70     (void)buf;
71     (void)size;
72     *errcode = o->error_code;
73     return MP_STREAM_ERROR;
74 }
75 
stest_ioctl(mp_obj_t o_in,mp_uint_t request,uintptr_t arg,int * errcode)76 STATIC mp_uint_t stest_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
77     mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in);
78     (void)arg;
79     (void)request;
80     (void)errcode;
81     if (o->error_code != 0) {
82         *errcode = o->error_code;
83         return MP_STREAM_ERROR;
84     }
85     return 0;
86 }
87 
88 STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
89     { MP_ROM_QSTR(MP_QSTR_set_buf), MP_ROM_PTR(&stest_set_buf_obj) },
90     { MP_ROM_QSTR(MP_QSTR_set_error), MP_ROM_PTR(&stest_set_error_obj) },
91     { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
92     { MP_ROM_QSTR(MP_QSTR_read1), MP_ROM_PTR(&mp_stream_read1_obj) },
93     { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
94     { MP_ROM_QSTR(MP_QSTR_write1), MP_ROM_PTR(&mp_stream_write1_obj) },
95     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
96     { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
97     { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },
98 };
99 
100 STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
101 
102 STATIC const mp_stream_p_t fileio_stream_p = {
103     .read = stest_read,
104     .write = stest_write,
105     .ioctl = stest_ioctl,
106 };
107 
108 STATIC const mp_obj_type_t mp_type_stest_fileio = {
109     { &mp_type_type },
110     .protocol = &fileio_stream_p,
111     .locals_dict = (mp_obj_dict_t *)&rawfile_locals_dict,
112 };
113 
114 // stream read returns non-blocking error
stest_read2(mp_obj_t o_in,void * buf,mp_uint_t size,int * errcode)115 STATIC mp_uint_t stest_read2(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
116     (void)o_in;
117     (void)buf;
118     (void)size;
119     *errcode = MP_EAGAIN;
120     return MP_STREAM_ERROR;
121 }
122 
123 STATIC const mp_rom_map_elem_t rawfile_locals_dict_table2[] = {
124     { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
125 };
126 
127 STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict2, rawfile_locals_dict_table2);
128 
129 STATIC const mp_stream_p_t textio_stream_p2 = {
130     .read = stest_read2,
131     .write = NULL,
132     .is_text = true,
133 };
134 
135 STATIC const mp_obj_type_t mp_type_stest_textio2 = {
136     { &mp_type_type },
137     .protocol = &textio_stream_p2,
138     .locals_dict = (mp_obj_dict_t *)&rawfile_locals_dict2,
139 };
140 
141 // str/bytes objects without a valid hash
142 STATIC const mp_obj_str_t str_no_hash_obj = {{&mp_type_str}, 0, 10, (const byte *)"0123456789"};
143 STATIC const mp_obj_str_t bytes_no_hash_obj = {{&mp_type_bytes}, 0, 10, (const byte *)"0123456789"};
144 
pairheap_lt(mp_pairheap_t * a,mp_pairheap_t * b)145 STATIC int pairheap_lt(mp_pairheap_t *a, mp_pairheap_t *b) {
146     return (uintptr_t)a < (uintptr_t)b;
147 }
148 
149 // ops array contain operations: x>=0 means push(x), x<0 means delete(-x)
pairheap_test(size_t nops,int * ops)150 STATIC void pairheap_test(size_t nops, int *ops) {
151     mp_pairheap_t node[8];
152     for (size_t i = 0; i < MP_ARRAY_SIZE(node); ++i) {
153         mp_pairheap_init_node(pairheap_lt, &node[i]);
154     }
155     mp_pairheap_t *heap = mp_pairheap_new(pairheap_lt);
156     printf("create:");
157     for (size_t i = 0; i < nops; ++i) {
158         if (ops[i] >= 0) {
159             heap = mp_pairheap_push(pairheap_lt, heap, &node[ops[i]]);
160         } else {
161             heap = mp_pairheap_delete(pairheap_lt, heap, &node[-ops[i]]);
162         }
163         if (mp_pairheap_is_empty(pairheap_lt, heap)) {
164             mp_printf(&mp_plat_print, " -");
165         } else {
166             mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]);
167             ;
168         }
169     }
170     printf("\npop all:");
171     while (!mp_pairheap_is_empty(pairheap_lt, heap)) {
172         mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]);
173         ;
174         heap = mp_pairheap_pop(pairheap_lt, heap);
175     }
176     printf("\n");
177 }
178 
179 // function to run extra tests for things that can't be checked by scripts
extra_coverage(void)180 STATIC mp_obj_t extra_coverage(void) {
181     // mp_printf (used by ports that don't have a native printf)
182     {
183         mp_printf(&mp_plat_print, "# mp_printf\n");
184         mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign
185         mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding
186         mp_printf(&mp_plat_print, "%ld\n", 123); // long
187         mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex
188         mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex
189         mp_printf(&mp_plat_print, "%.2s %.3s '%4.4s' '%5.5q' '%.3q'\n", "abc", "abc", "abc", MP_QSTR_True, MP_QSTR_True); // fixed string precision
190         mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision
191         mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools
192         #ifndef NDEBUG
193         mp_printf(&mp_plat_print, "%s\n", NULL); // null string
194         #else
195         mp_printf(&mp_plat_print, "(null)\n"); // without debugging mp_printf won't check for null
196         #endif
197         mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed
198         mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned
199         mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned
200         mp_printf(&mp_plat_print, "%X\n", 0x80000000); // should print unsigned
201         mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier
202         mp_printf(&mp_plat_print, "%%\n"); // literal % character
203     }
204 
205     // GC
206     {
207         mp_printf(&mp_plat_print, "# GC\n");
208 
209         // calling gc_free while GC is locked
210         gc_lock();
211         gc_free(NULL);
212         gc_unlock();
213 
214         // using gc_realloc to resize to 0, which means free the memory
215         void *p = gc_alloc(4, false);
216         mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false));
217 
218         // calling gc_nbytes with a non-heap pointer
219         mp_printf(&mp_plat_print, "%p\n", gc_nbytes(NULL));
220     }
221 
222     // vstr
223     {
224         mp_printf(&mp_plat_print, "# vstr\n");
225         vstr_t *vstr = vstr_new(16);
226         vstr_hint_size(vstr, 32);
227         vstr_add_str(vstr, "ts");
228         vstr_ins_byte(vstr, 1, 'e');
229         vstr_ins_char(vstr, 3, 't');
230         vstr_ins_char(vstr, 10, 's');
231         mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf);
232 
233         vstr_cut_head_bytes(vstr, 2);
234         mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf);
235 
236         vstr_cut_tail_bytes(vstr, 10);
237         mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf);
238 
239         vstr_printf(vstr, "t%cst", 'e');
240         mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf);
241 
242         vstr_cut_out_bytes(vstr, 3, 10);
243         mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf);
244 
245         VSTR_FIXED(fix, 4);
246         nlr_buf_t nlr;
247         if (nlr_push(&nlr) == 0) {
248             vstr_add_str(&fix, "large");
249             nlr_pop();
250         } else {
251             mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
252         }
253 
254         fix.len = fix.alloc;
255         if (nlr_push(&nlr) == 0) {
256             vstr_null_terminated_str(&fix);
257             nlr_pop();
258         } else {
259             mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
260         }
261     }
262 
263     // repl autocomplete
264     {
265         mp_printf(&mp_plat_print, "# repl\n");
266 
267         const char *str;
268         size_t len = mp_repl_autocomplete("__n", 3, &mp_plat_print, &str);
269         mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
270 
271         len = mp_repl_autocomplete("i", 1,  &mp_plat_print, &str);
272         mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
273         mp_repl_autocomplete("import ", 7,  &mp_plat_print, &str);
274         len = mp_repl_autocomplete("import ut", 9,  &mp_plat_print, &str);
275         mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
276         mp_repl_autocomplete("import utime", 12,  &mp_plat_print, &str);
277 
278         mp_store_global(MP_QSTR_sys, mp_import_name(MP_QSTR_sys, mp_const_none, MP_OBJ_NEW_SMALL_INT(0)));
279         mp_repl_autocomplete("sys.", 4, &mp_plat_print, &str);
280         len = mp_repl_autocomplete("sys.impl", 8, &mp_plat_print, &str);
281         mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
282     }
283 
284     // attrtuple
285     {
286         mp_printf(&mp_plat_print, "# attrtuple\n");
287 
288         static const qstr fields[] = {MP_QSTR_start, MP_QSTR_stop, MP_QSTR_step};
289         static const mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(2), MP_OBJ_NEW_SMALL_INT(3)};
290         mp_obj_print_helper(&mp_plat_print, mp_obj_new_attrtuple(fields, 3, items), PRINT_REPR);
291         mp_printf(&mp_plat_print, "\n");
292     }
293 
294     // str
295     {
296         mp_printf(&mp_plat_print, "# str\n");
297 
298         // intern string
299         mp_printf(&mp_plat_print, "%d\n", mp_obj_is_qstr(mp_obj_str_intern(mp_obj_new_str("intern me", 9))));
300     }
301 
302     // bytearray
303     {
304         mp_printf(&mp_plat_print, "# bytearray\n");
305 
306         // create a bytearray via mp_obj_new_bytearray
307         mp_buffer_info_t bufinfo;
308         mp_get_buffer_raise(mp_obj_new_bytearray(4, "data"), &bufinfo, MP_BUFFER_RW);
309         mp_printf(&mp_plat_print, "%.*s\n", bufinfo.len, bufinfo.buf);
310     }
311 
312     // mpz
313     {
314         mp_printf(&mp_plat_print, "# mpz\n");
315 
316         mp_uint_t value;
317         mpz_t mpz;
318         mpz_init_zero(&mpz);
319 
320         // mpz_as_uint_checked, with success
321         mpz_set_from_int(&mpz, 12345678);
322         mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value));
323         mp_printf(&mp_plat_print, "%d\n", (int)value);
324 
325         // mpz_as_uint_checked, with negative arg
326         mpz_set_from_int(&mpz, -1);
327         mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value));
328 
329         // mpz_as_uint_checked, with overflowing arg
330         mpz_set_from_int(&mpz, 1);
331         mpz_shl_inpl(&mpz, &mpz, 70);
332         mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value));
333 
334         // mpz_set_from_float with inf as argument
335         mpz_set_from_float(&mpz, 1.0 / 0.0);
336         mpz_as_uint_checked(&mpz, &value);
337         mp_printf(&mp_plat_print, "%d\n", (int)value);
338 
339         // mpz_set_from_float with 0 as argument
340         mpz_set_from_float(&mpz, 0);
341         mpz_as_uint_checked(&mpz, &value);
342         mp_printf(&mp_plat_print, "%d\n", (int)value);
343 
344         // mpz_set_from_float with 0<x<1 as argument
345         mpz_set_from_float(&mpz, 1e-10);
346         mpz_as_uint_checked(&mpz, &value);
347         mp_printf(&mp_plat_print, "%d\n", (int)value);
348 
349         // mpz_set_from_float with 1<=x<2 as argument
350         mpz_set_from_float(&mpz, 1.5);
351         mpz_as_uint_checked(&mpz, &value);
352         mp_printf(&mp_plat_print, "%d\n", (int)value);
353 
354         // mpz_set_from_float with 2<x as argument
355         mpz_set_from_float(&mpz, 12345);
356         mpz_as_uint_checked(&mpz, &value);
357         mp_printf(&mp_plat_print, "%d\n", (int)value);
358 
359         // mpz_mul_inpl with dest==rhs, lhs!=rhs
360         mpz_t mpz2;
361         mpz_set_from_int(&mpz, 2);
362         mpz_init_from_int(&mpz2, 3);
363         mpz_mul_inpl(&mpz, &mpz2, &mpz);
364         mpz_as_uint_checked(&mpz, &value);
365         mp_printf(&mp_plat_print, "%d\n", (int)value);
366     }
367 
368     // runtime utils
369     {
370         mp_printf(&mp_plat_print, "# runtime utils\n");
371 
372         // call mp_call_function_1_protected
373         mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), MP_OBJ_NEW_SMALL_INT(1));
374         // call mp_call_function_1_protected with invalid args
375         mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str("abc", 3));
376 
377         // call mp_call_function_2_protected
378         mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(1));
379         // call mp_call_function_2_protected with invalid args
380         mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str("abc", 3), mp_obj_new_str("abc", 3));
381 
382         // mp_obj_int_get_uint_checked with non-negative small-int
383         mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(1)));
384 
385         // mp_obj_int_get_uint_checked with non-negative big-int
386         mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(mp_obj_new_int_from_ll(2)));
387 
388         // mp_obj_int_get_uint_checked with negative small-int (should raise exception)
389         nlr_buf_t nlr;
390         if (nlr_push(&nlr) == 0) {
391             mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(-1));
392             nlr_pop();
393         } else {
394             mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
395         }
396 
397         // mp_obj_int_get_uint_checked with negative big-int (should raise exception)
398         if (nlr_push(&nlr) == 0) {
399             mp_obj_int_get_uint_checked(mp_obj_new_int_from_ll(-2));
400             nlr_pop();
401         } else {
402             mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
403         }
404 
405         // call mp_obj_new_exception_args (it's a part of the public C API and not used in the core)
406         mp_obj_print_exception(&mp_plat_print, mp_obj_new_exception_args(&mp_type_ValueError, 0, NULL));
407     }
408 
409     // warning
410     {
411         mp_emitter_warning(MP_PASS_CODE_SIZE, "test");
412     }
413 
414     // format float
415     {
416         mp_printf(&mp_plat_print, "# format float\n");
417 
418         // format with inadequate buffer size
419         char buf[5];
420         mp_format_float(1, buf, sizeof(buf), 'g', 0, '+');
421         mp_printf(&mp_plat_print, "%s\n", buf);
422 
423         // format with just enough buffer so that precision must be
424         // set from 0 to 1 twice
425         char buf2[8];
426         mp_format_float(1, buf2, sizeof(buf2), 'g', 0, '+');
427         mp_printf(&mp_plat_print, "%s\n", buf2);
428 
429         // format where precision is trimmed to avoid buffer overflow
430         mp_format_float(1, buf2, sizeof(buf2), 'e', 0, '+');
431         mp_printf(&mp_plat_print, "%s\n", buf2);
432     }
433 
434     // binary
435     {
436         mp_printf(&mp_plat_print, "# binary\n");
437 
438         // call function with float and double typecodes
439         float far[1];
440         double dar[1];
441         mp_binary_set_val_array_from_int('f', far, 0, 123);
442         mp_printf(&mp_plat_print, "%.0f\n", (double)far[0]);
443         mp_binary_set_val_array_from_int('d', dar, 0, 456);
444         mp_printf(&mp_plat_print, "%.0lf\n", dar[0]);
445     }
446 
447     // VM
448     {
449         mp_printf(&mp_plat_print, "# VM\n");
450 
451         // call mp_execute_bytecode with invalide bytecode (should raise NotImplementedError)
452         mp_obj_fun_bc_t fun_bc;
453         fun_bc.bytecode = (const byte *)"\x01"; // just needed for n_state
454         mp_code_state_t *code_state = m_new_obj_var(mp_code_state_t, mp_obj_t, 1);
455         code_state->fun_bc = &fun_bc;
456         code_state->ip = (const byte *)"\x00"; // just needed for an invalid opcode
457         code_state->sp = &code_state->state[0];
458         code_state->exc_sp_idx = 0;
459         code_state->old_globals = NULL;
460         mp_vm_return_kind_t ret = mp_execute_bytecode(code_state, MP_OBJ_NULL);
461         mp_printf(&mp_plat_print, "%d %d\n", ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError);
462     }
463 
464     // scheduler
465     {
466         mp_printf(&mp_plat_print, "# scheduler\n");
467 
468         // lock scheduler
469         mp_sched_lock();
470 
471         // schedule multiple callbacks; last one should fail
472         for (int i = 0; i < 5; ++i) {
473             mp_printf(&mp_plat_print, "sched(%d)=%d\n", i, mp_sched_schedule(MP_OBJ_FROM_PTR(&mp_builtin_print_obj), MP_OBJ_NEW_SMALL_INT(i)));
474         }
475 
476         // test nested locking/unlocking
477         mp_sched_lock();
478         mp_sched_unlock();
479 
480         // shouldn't do anything while scheduler is locked
481         mp_handle_pending(true);
482 
483         // unlock scheduler
484         mp_sched_unlock();
485         mp_printf(&mp_plat_print, "unlocked\n");
486 
487         // drain pending callbacks
488         while (mp_sched_num_pending()) {
489             mp_handle_pending(true);
490         }
491 
492         // setting the keyboard interrupt and raising it during mp_handle_pending
493         mp_sched_keyboard_interrupt();
494         nlr_buf_t nlr;
495         if (nlr_push(&nlr) == 0) {
496             mp_handle_pending(true);
497             nlr_pop();
498         } else {
499             mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
500         }
501 
502         // setting the keyboard interrupt (twice) and cancelling it during mp_handle_pending
503         mp_sched_keyboard_interrupt();
504         mp_sched_keyboard_interrupt();
505         mp_handle_pending(false);
506 
507         // setting keyboard interrupt and a pending event (intr should be handled first)
508         mp_sched_schedule(MP_OBJ_FROM_PTR(&mp_builtin_print_obj), MP_OBJ_NEW_SMALL_INT(10));
509         mp_sched_keyboard_interrupt();
510         if (nlr_push(&nlr) == 0) {
511             mp_handle_pending(true);
512             nlr_pop();
513         } else {
514             mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
515         }
516         mp_handle_pending(true);
517     }
518 
519     // ringbuf
520     {
521         byte buf[100];
522         ringbuf_t ringbuf = {buf, sizeof(buf), 0, 0};
523 
524         mp_printf(&mp_plat_print, "# ringbuf\n");
525 
526         // Single-byte put/get with empty ringbuf.
527         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
528         ringbuf_put(&ringbuf, 22);
529         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
530         mp_printf(&mp_plat_print, "%d\n", ringbuf_get(&ringbuf));
531         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
532 
533         // Two-byte put/get with empty ringbuf.
534         ringbuf_put16(&ringbuf, 0xaa55);
535         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
536         mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf));
537         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
538 
539         // Two-byte put with full ringbuf.
540         for (int i = 0; i < 99; ++i) {
541             ringbuf_put(&ringbuf, i);
542         }
543         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
544         mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x11bb));
545         // Two-byte put with one byte free.
546         ringbuf_get(&ringbuf);
547         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
548         mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x3377));
549         ringbuf_get(&ringbuf);
550         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
551         mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0xcc99));
552         for (int i = 0; i < 97; ++i) {
553             ringbuf_get(&ringbuf);
554         }
555         mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf));
556         mp_printf(&mp_plat_print, "%d %d\n", ringbuf_free(&ringbuf), ringbuf_avail(&ringbuf));
557 
558         // Two-byte put with wrap around on first byte:
559         ringbuf.iput = 0;
560         ringbuf.iget = 0;
561         for (int i = 0; i < 99; ++i) {
562             ringbuf_put(&ringbuf, i);
563             ringbuf_get(&ringbuf);
564         }
565         mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x11bb));
566         mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf));
567 
568         // Two-byte put with wrap around on second byte:
569         ringbuf.iput = 0;
570         ringbuf.iget = 0;
571         for (int i = 0; i < 98; ++i) {
572             ringbuf_put(&ringbuf, i);
573             ringbuf_get(&ringbuf);
574         }
575         mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x22ff));
576         mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf));
577 
578         // Two-byte get from empty ringbuf.
579         ringbuf.iput = 0;
580         ringbuf.iget = 0;
581         mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf));
582 
583         // Two-byte get from ringbuf with one byte available.
584         ringbuf.iput = 0;
585         ringbuf.iget = 0;
586         ringbuf_put(&ringbuf, 0xaa);
587         mp_printf(&mp_plat_print, "%d\n", ringbuf_get16(&ringbuf));
588     }
589 
590     // pairheap
591     {
592         mp_printf(&mp_plat_print, "# pairheap\n");
593 
594         // Basic case.
595         int t0[] = {0, 2, 1, 3};
596         pairheap_test(MP_ARRAY_SIZE(t0), t0);
597 
598         // All pushed in reverse order.
599         int t1[] = {7, 6, 5, 4, 3, 2, 1, 0};
600         pairheap_test(MP_ARRAY_SIZE(t1), t1);
601 
602         // Basic deletion.
603         int t2[] = {1, -1, -1, 1, 2, -2, 2, 3, -3};
604         pairheap_test(MP_ARRAY_SIZE(t2), t2);
605 
606         // Deletion of first child that has next node (the -3).
607         int t3[] = {1, 2, 3, 4, -1, -3};
608         pairheap_test(MP_ARRAY_SIZE(t3), t3);
609 
610         // Deletion of node that's not first child (the -2).
611         int t4[] = {1, 2, 3, 4, -2};
612         pairheap_test(MP_ARRAY_SIZE(t4), t4);
613 
614         // Deletion of node that's not first child and has children (the -3).
615         int t5[] = {3, 4, 5, 1, 2, -3};
616         pairheap_test(MP_ARRAY_SIZE(t5), t5);
617     }
618 
619     // mp_obj_is_type and derivatives
620     {
621         mp_printf(&mp_plat_print, "# mp_obj_is_type\n");
622 
623         // mp_obj_is_bool accepts only booleans
624         mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_bool(mp_const_true), mp_obj_is_bool(mp_const_false));
625         mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_bool(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_bool(mp_const_none));
626 
627         // mp_obj_is_integer accepts ints and booleans
628         mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_integer(mp_obj_new_int_from_ll(1)));
629         mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_const_true), mp_obj_is_integer(mp_const_false));
630         mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_obj_new_str("1", 1)), mp_obj_is_integer(mp_const_none));
631 
632         // mp_obj_is_int accepts small int and object ints
633         mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_int(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_int(mp_obj_new_int_from_ll(1)));
634     }
635 
636     mp_printf(&mp_plat_print, "# end coverage.c\n");
637 
638     mp_obj_streamtest_t *s = m_new_obj(mp_obj_streamtest_t);
639     s->base.type = &mp_type_stest_fileio;
640     s->buf = NULL;
641     s->len = 0;
642     s->pos = 0;
643     s->error_code = 0;
644     mp_obj_streamtest_t *s2 = m_new_obj(mp_obj_streamtest_t);
645     s2->base.type = &mp_type_stest_textio2;
646 
647     // return a tuple of data for testing on the Python side
648     mp_obj_t items[] = {(mp_obj_t)&str_no_hash_obj, (mp_obj_t)&bytes_no_hash_obj, MP_OBJ_FROM_PTR(s), MP_OBJ_FROM_PTR(s2)};
649     return mp_obj_new_tuple(MP_ARRAY_SIZE(items), items);
650 }
651 MP_DEFINE_CONST_FUN_OBJ_0(extra_coverage_obj, extra_coverage);
652 
653 #endif
654