1# Copyright (C) 2020 Red Hat Inc.
2#
3# Authors:
4#  Eduardo Habkost <ehabkost@redhat.com>
5#
6# This work is licensed under the terms of the GNU GPL, version 2.  See
7# the COPYING file in the top-level directory.
8from .regexps import *
9from .qom_macros import *
10from .qom_type_info import *
11
12def test_res() -> None:
13    def fullmatch(regexp, s):
14        return re.fullmatch(regexp, s, re.MULTILINE)
15
16    assert fullmatch(RE_IDENTIFIER, 'sizeof')
17    assert fullmatch(RE_IDENTIFIER, 'X86CPU')
18    assert fullmatch(RE_FUN_CALL, 'sizeof(X86CPU)')
19    assert fullmatch(RE_IDENTIFIER, 'X86_CPU_TYPE_NAME')
20    assert fullmatch(RE_SIMPLE_VALUE, '"base"')
21    print(RE_FUN_CALL)
22    assert fullmatch(RE_FUN_CALL, 'X86_CPU_TYPE_NAME("base")')
23    print(RE_TI_FIELD_INIT)
24    assert fullmatch(RE_TI_FIELD_INIT, '.name = X86_CPU_TYPE_NAME("base"),\n')
25
26
27    assert fullmatch(RE_MACRO_CONCAT, 'TYPE_ASPEED_GPIO "-ast2600"')
28    assert fullmatch(RE_EXPRESSION, 'TYPE_ASPEED_GPIO "-ast2600"')
29
30    print(RE_MACRO_DEFINE)
31    assert re.search(RE_MACRO_DEFINE, r'''
32    #define OFFSET_CHECK(c)                     \
33    do {                                        \
34        if (!(c)) {                             \
35            goto bad_offset;                    \
36        }                                       \
37    } while (0)
38    ''', re.MULTILINE)
39
40    print(RE_CHECK_MACRO)
41    print(CPP_SPACE)
42    assert not re.match(RE_CHECK_MACRO, r'''
43    #define OFFSET_CHECK(c)                     \
44    do {                                        \
45        if (!(c)) {                             \
46            goto bad_offset;                    \
47        }                                       \
48    } while (0)''', re.MULTILINE)
49
50    print(RE_CHECK_MACRO)
51    assert fullmatch(RE_CHECK_MACRO, r'''#define PCI_DEVICE(obj) \
52                     OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE)
53''')
54    assert fullmatch(RE_CHECK_MACRO, r'''#define COLLIE_MACHINE(obj) \
55                     OBJECT_CHECK(CollieMachineState, obj, TYPE_COLLIE_MACHINE)
56''')
57
58    print(RE_TYPEINFO_START)
59    assert re.search(RE_TYPEINFO_START, r'''
60    cc->open = qmp_chardev_open_file;
61}
62
63static const TypeInfo char_file_type_info = {
64    .name = TYPE_CHARDEV_FILE,
65#ifdef _WIN32
66    .parent = TYPE_CHARDEV_WIN,
67''', re.MULTILINE)
68    assert re.search(RE_TYPEINFO_START, r'''
69        TypeInfo ti = {
70            .name = armsse_variants[i].name,
71            .parent = TYPE_ARMSSE,
72            .class_init = armsse_class_init,
73            .class_data = (void *)&armsse_variants[i],
74        };''', re.MULTILINE)
75
76    print(RE_ARRAY_ITEM)
77    assert fullmatch(RE_ARRAY_ITEM, '{ TYPE_HOTPLUG_HANDLER },')
78    assert fullmatch(RE_ARRAY_ITEM, '{ TYPE_ACPI_DEVICE_IF },')
79    assert fullmatch(RE_ARRAY_ITEM, '{ }')
80    assert fullmatch(RE_ARRAY_CAST, '(InterfaceInfo[])')
81    assert fullmatch(RE_ARRAY, '''(InterfaceInfo[]) {
82            { TYPE_HOTPLUG_HANDLER },
83            { TYPE_ACPI_DEVICE_IF },
84            { }
85    }''')
86    print(RE_COMMENT)
87    assert fullmatch(RE_COMMENT, r'''/* multi-line
88                                      * comment
89                                      */''')
90
91    print(RE_TI_FIELDS)
92    assert fullmatch(RE_TI_FIELDS,
93    r'''/* could be TYPE_SYS_BUS_DEVICE (or LPC etc) */
94        .parent = TYPE_DEVICE,
95''')
96    assert fullmatch(RE_TI_FIELDS, r'''.name = TYPE_TPM_CRB,
97        /* could be TYPE_SYS_BUS_DEVICE (or LPC etc) */
98        .parent = TYPE_DEVICE,
99        .instance_size = sizeof(CRBState),
100        .class_init  = tpm_crb_class_init,
101        .interfaces = (InterfaceInfo[]) {
102            { TYPE_TPM_IF },
103            { }
104        }
105''')
106    assert fullmatch(RE_TI_FIELDS + SP + RE_COMMENTS,
107        r'''.name = TYPE_PALM_MISC_GPIO,
108            .parent = TYPE_SYS_BUS_DEVICE,
109            .instance_size = sizeof(PalmMiscGPIOState),
110            .instance_init = palm_misc_gpio_init,
111            /*
112             * No class init required: device has no internal state so does not
113             * need to set up reset or vmstate, and has no realize method.
114             */''')
115
116    print(TypeInfoVar.regexp)
117    test_empty = 'static const TypeInfo x86_base_cpu_type_info = {\n'+\
118                 '};\n';
119    assert fullmatch(TypeInfoVar.regexp, test_empty)
120
121    test_simple = r'''
122    static const TypeInfo x86_base_cpu_type_info = {
123        .name = X86_CPU_TYPE_NAME("base"),
124        .parent = TYPE_X86_CPU,
125        .class_init = x86_cpu_base_class_init,
126    };
127    '''
128    assert re.search(TypeInfoVar.regexp, test_simple, re.MULTILINE)
129
130    test_interfaces = r'''
131    static const TypeInfo acpi_ged_info = {
132        .name          = TYPE_ACPI_GED,
133        .parent        = TYPE_SYS_BUS_DEVICE,
134        .instance_size = sizeof(AcpiGedState),
135        .instance_init  = acpi_ged_initfn,
136        .class_init    = acpi_ged_class_init,
137        .interfaces = (InterfaceInfo[]) {
138            { TYPE_HOTPLUG_HANDLER },
139            { TYPE_ACPI_DEVICE_IF },
140            { }
141        }
142    };
143    '''
144    assert re.search(TypeInfoVar.regexp, test_interfaces, re.MULTILINE)
145
146    test_comments = r'''
147    static const TypeInfo palm_misc_gpio_info = {
148        .name = TYPE_PALM_MISC_GPIO,
149        .parent = TYPE_SYS_BUS_DEVICE,
150        .instance_size = sizeof(PalmMiscGPIOState),
151        .instance_init = palm_misc_gpio_init,
152        /*
153         * No class init required: device has no internal state so does not
154         * need to set up reset or vmstate, and has no realize method.
155         */
156    };
157    '''
158    assert re.search(TypeInfoVar.regexp, test_comments, re.MULTILINE)
159
160    test_comments = r'''
161    static const TypeInfo tpm_crb_info = {
162        .name = TYPE_TPM_CRB,
163        /* could be TYPE_SYS_BUS_DEVICE (or LPC etc) */
164        .parent = TYPE_DEVICE,
165        .instance_size = sizeof(CRBState),
166        .class_init  = tpm_crb_class_init,
167        .interfaces = (InterfaceInfo[]) {
168            { TYPE_TPM_IF },
169            { }
170        }
171    };
172    '''
173    assert re.search(TypeInfoVar.regexp, test_comments, re.MULTILINE)
174
175def test_struct_re():
176    print('---')
177    print(RE_STRUCT_TYPEDEF)
178    assert re.search(RE_STRUCT_TYPEDEF, r'''
179typedef struct TCGState {
180    AccelState parent_obj;
181
182    bool mttcg_enabled;
183    unsigned long tb_size;
184} TCGState;
185''', re.MULTILINE)
186
187    assert re.search(RE_STRUCT_TYPEDEF, r'''
188typedef struct {
189    ISADevice parent_obj;
190
191    QEMUSoundCard card;
192    uint32_t freq;
193    uint32_t port;
194    int ticking[2];
195    int enabled;
196    int active;
197    int bufpos;
198#ifdef DEBUG
199    int64_t exp[2];
200#endif
201    int16_t *mixbuf;
202    uint64_t dexp[2];
203    SWVoiceOut *voice;
204    int left, pos, samples;
205    QEMUAudioTimeStamp ats;
206    FM_OPL *opl;
207    PortioList port_list;
208} AdlibState;
209''', re.MULTILINE)
210
211    false_positive = r'''
212typedef struct dma_pagetable_entry {
213    int32_t frame;
214    int32_t owner;
215} A B C D E;
216struct foo {
217    int x;
218} some_variable;
219'''
220    assert not re.search(RE_STRUCT_TYPEDEF, false_positive, re.MULTILINE)
221
222def test_initial_includes():
223    print(InitialIncludes.regexp)
224    c = '''
225#ifndef HW_FLASH_H
226#define HW_FLASH_H
227
228/* NOR flash devices */
229
230#include "qom/object.h"
231#include "exec/hwaddr.h"
232
233/* pflash_cfi01.c */
234'''
235    print(repr(list(m.groupdict() for m in InitialIncludes.finditer(c))))
236    m = InitialIncludes.domatch(c)
237    assert m
238    print(repr(m.group(0)))
239    assert m.group(0).endswith('#include "exec/hwaddr.h"\n')
240
241    c = '''#ifndef QEMU_VIRTIO_9P_H
242#define QEMU_VIRTIO_9P_H
243
244#include "standard-headers/linux/virtio_9p.h"
245#include "hw/virtio/virtio.h"
246#include "9p.h"
247
248
249'''
250    print(repr(list(m.groupdict() for m in InitialIncludes.finditer(c))))
251    m = InitialIncludes.domatch(c)
252    assert m
253    print(repr(m.group(0)))
254    assert m.group(0).endswith('#include "9p.h"\n')
255
256    c = '''#include "qom/object.h"
257/*
258 * QEMU ES1370 emulation
259...
260 */
261
262/* #define DEBUG_ES1370 */
263/* #define VERBOSE_ES1370 */
264#define SILENT_ES1370
265
266#include "qemu/osdep.h"
267#include "hw/audio/soundhw.h"
268#include "audio/audio.h"
269#include "hw/pci/pci.h"
270#include "migration/vmstate.h"
271#include "qemu/module.h"
272#include "sysemu/dma.h"
273
274/* Missing stuff:
275   SCTRL_P[12](END|ST)INC
276'''
277    print(repr(list(m.groupdict() for m in InitialIncludes.finditer(c))))
278    m = InitialIncludes.domatch(c)
279    assert m
280    print(repr(m.group(0)))
281    assert m.group(0).endswith('#include "sysemu/dma.h"\n')
282
283