diff options
Diffstat (limited to 'tests')
299 files changed, 2454 insertions, 1132 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index e9b182e2bd..7357d0a0d4 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -13,6 +13,7 @@ rcutorture test-aio test-base64 test-bitops +test-bitcnt test-blockjob test-blockjob-txn test-bufferiszero diff --git a/tests/Makefile.include b/tests/Makefile.include index 4841d582a1..22ea256e94 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -81,6 +81,7 @@ gcov-files-test-qht-y = util/qht.c check-unit-y += tests/test-qht-par$(EXESUF) gcov-files-test-qht-par-y = util/qht.c check-unit-y += tests/test-bitops$(EXESUF) +check-unit-y += tests/test-bitcnt$(EXESUF) check-unit-$(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) += tests/test-qdev-global-props$(EXESUF) check-unit-y += tests/check-qom-interface$(EXESUF) gcov-files-check-qom-interface-y = qom/object.c @@ -351,6 +352,24 @@ qapi-schema += base-cycle-direct.json qapi-schema += base-cycle-indirect.json qapi-schema += command-int.json qapi-schema += comments.json +qapi-schema += doc-bad-args.json +qapi-schema += doc-bad-symbol.json +qapi-schema += doc-duplicated-arg.json +qapi-schema += doc-duplicated-return.json +qapi-schema += doc-duplicated-since.json +qapi-schema += doc-empty-arg.json +qapi-schema += doc-empty-section.json +qapi-schema += doc-empty-symbol.json +qapi-schema += doc-interleaved-section.json +qapi-schema += doc-invalid-end.json +qapi-schema += doc-invalid-end2.json +qapi-schema += doc-invalid-return.json +qapi-schema += doc-invalid-section.json +qapi-schema += doc-invalid-start.json +qapi-schema += doc-missing-colon.json +qapi-schema += doc-missing-expr.json +qapi-schema += doc-missing-space.json +qapi-schema += doc-optional.json qapi-schema += double-data.json qapi-schema += double-type.json qapi-schema += duplicate-key.json @@ -444,6 +463,8 @@ qapi-schema += union-optional-branch.json qapi-schema += union-unknown.json qapi-schema += unknown-escape.json qapi-schema += unknown-expr-key.json + + check-qapi-schema-y := $(addprefix tests/qapi-schema/, $(qapi-schema)) GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h \ @@ -516,6 +537,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ hw/core/bus.o \ hw/core/irq.o \ hw/core/fw-path-provider.o \ + hw/core/reset.o \ $(test-qapi-obj-y) tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ migration/vmstate.o migration/qemu-file.o \ @@ -571,6 +593,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) tests/test-mul64$(EXESUF): tests/test-mul64.o $(test-util-obj-y) tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y) +tests/test-bitcnt$(EXESUF): tests/test-bitcnt.o $(test-util-obj-y) tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y) tests/test-crypto-hmac$(EXESUF): tests/test-crypto-hmac.o $(test-crypto-obj-y) tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y) @@ -689,7 +712,7 @@ tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y) tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y) tests/test-x86-cpuid-compat$(EXESUF): tests/test-x86-cpuid-compat.o $(qtest-obj-y) tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) -tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o +tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o contrib/libvhost-user/libvhost-user.o $(test-util-obj-y) tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT index 8053d71105..15c3135d65 100644 --- a/tests/acpi-test-data/pc/DSDT +++ b/tests/acpi-test-data/pc/DSDT Binary files differdiff --git a/tests/acpi-test-data/pc/DSDT.bridge b/tests/acpi-test-data/pc/DSDT.bridge index 850e71a973..d38586c95b 100644 --- a/tests/acpi-test-data/pc/DSDT.bridge +++ b/tests/acpi-test-data/pc/DSDT.bridge Binary files differdiff --git a/tests/acpi-test-data/pc/DSDT.cphp b/tests/acpi-test-data/pc/DSDT.cphp index 9f405cfd83..2dd70bf952 100644 --- a/tests/acpi-test-data/pc/DSDT.cphp +++ b/tests/acpi-test-data/pc/DSDT.cphp Binary files differdiff --git a/tests/acpi-test-data/pc/DSDT.ipmikcs b/tests/acpi-test-data/pc/DSDT.ipmikcs index 8ac48afb6a..2796d96b0e 100644 --- a/tests/acpi-test-data/pc/DSDT.ipmikcs +++ b/tests/acpi-test-data/pc/DSDT.ipmikcs Binary files differdiff --git a/tests/acpi-test-data/pc/DSDT.memhp b/tests/acpi-test-data/pc/DSDT.memhp new file mode 100644 index 0000000000..53f6d58243 --- /dev/null +++ b/tests/acpi-test-data/pc/DSDT.memhp Binary files differdiff --git a/tests/acpi-test-data/pc/SRAT.memhp b/tests/acpi-test-data/pc/SRAT.memhp new file mode 100644 index 0000000000..66ce9a8981 --- /dev/null +++ b/tests/acpi-test-data/pc/SRAT.memhp Binary files differdiff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT index 58fbb3d2e2..d11567c3dc 100644 --- a/tests/acpi-test-data/q35/DSDT +++ b/tests/acpi-test-data/q35/DSDT Binary files differdiff --git a/tests/acpi-test-data/q35/DSDT.bridge b/tests/acpi-test-data/q35/DSDT.bridge index c392802a95..412a6e9104 100644 --- a/tests/acpi-test-data/q35/DSDT.bridge +++ b/tests/acpi-test-data/q35/DSDT.bridge Binary files differdiff --git a/tests/acpi-test-data/q35/DSDT.cphp b/tests/acpi-test-data/q35/DSDT.cphp index a0ce6b3264..79902d0d30 100644 --- a/tests/acpi-test-data/q35/DSDT.cphp +++ b/tests/acpi-test-data/q35/DSDT.cphp Binary files differdiff --git a/tests/acpi-test-data/q35/DSDT.ipmibt b/tests/acpi-test-data/q35/DSDT.ipmibt index 0ea38e1e72..b658329c5b 100644 --- a/tests/acpi-test-data/q35/DSDT.ipmibt +++ b/tests/acpi-test-data/q35/DSDT.ipmibt Binary files differdiff --git a/tests/acpi-test-data/q35/DSDT.memhp b/tests/acpi-test-data/q35/DSDT.memhp new file mode 100644 index 0000000000..e46c1fb5a2 --- /dev/null +++ b/tests/acpi-test-data/q35/DSDT.memhp Binary files differdiff --git a/tests/acpi-test-data/q35/SRAT.memhp b/tests/acpi-test-data/q35/SRAT.memhp new file mode 100644 index 0000000000..66ce9a8981 --- /dev/null +++ b/tests/acpi-test-data/q35/SRAT.memhp Binary files differdiff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 812f830539..54048050c0 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -867,6 +867,28 @@ static void test_acpi_piix4_tcg_ipmi(void) free_test_data(&data); } +static void test_acpi_q35_tcg_memhp(void) +{ + test_data data; + + memset(&data, 0, sizeof(data)); + data.machine = MACHINE_Q35; + data.variant = ".memhp"; + test_acpi_one(" -m 128,slots=3,maxmem=1G -numa node", &data); + free_test_data(&data); +} + +static void test_acpi_piix4_tcg_memhp(void) +{ + test_data data; + + memset(&data, 0, sizeof(data)); + data.machine = MACHINE_PC; + data.variant = ".memhp"; + test_acpi_one(" -m 128,slots=3,maxmem=1G -numa node", &data); + free_test_data(&data); +} + int main(int argc, char *argv[]) { const char *arch = qtest_get_arch(); @@ -887,6 +909,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi); qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp); qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp); + qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp); + qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp); } ret = g_test_run(); boot_sector_cleanup(disk); diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c index 37debc11f9..c5637cc406 100644 --- a/tests/device-introspect-test.c +++ b/tests/device-introspect-test.c @@ -20,18 +20,24 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qapi/qmp/qstring.h" +#include "qapi/qmp/qbool.h" +#include "qapi/qmp/qdict.h" #include "libqtest.h" const char common_args[] = "-nodefaults -machine none"; -static QList *device_type_list(bool abstract) +static QList *qom_list_types(const char *implements, bool abstract) { QDict *resp; QList *ret; + QDict *args = qdict_new(); + qdict_put(args, "abstract", qbool_from_bool(abstract)); + if (implements) { + qdict_put(args, "implements", qstring_from_str(implements)); + } resp = qmp("{'execute': 'qom-list-types'," - " 'arguments': {'implements': 'device', 'abstract': %i}}", - abstract); + " 'arguments': %p }", args); g_assert(qdict_haskey(resp, "return")); ret = qdict_get_qlist(resp, "return"); QINCREF(ret); @@ -39,6 +45,11 @@ static QList *device_type_list(bool abstract) return ret; } +static QList *device_type_list(bool abstract) +{ + return qom_list_types("device", abstract); +} + static void test_one_device(const char *type) { QDict *resp; @@ -110,6 +121,48 @@ static void test_device_intro_concrete(void) qtest_end(); } +static void test_abstract_interfaces(void) +{ + QList *all_types; + QList *obj_types; + QListEntry *ae; + + qtest_start(common_args); + /* qom-list-types implements=interface would return any type + * that implements _any_ interface (not just interface types), + * so use a trick to find the interface type names: + * - list all object types + * - list all types, and look for items that are not + * on the first list + */ + all_types = qom_list_types(NULL, false); + obj_types = qom_list_types("object", false); + + QLIST_FOREACH_ENTRY(all_types, ae) { + QDict *at = qobject_to_qdict(qlist_entry_obj(ae)); + const char *aname = qdict_get_str(at, "name"); + QListEntry *oe; + const char *found = NULL; + + QLIST_FOREACH_ENTRY(obj_types, oe) { + QDict *ot = qobject_to_qdict(qlist_entry_obj(oe)); + const char *oname = qdict_get_str(ot, "name"); + if (!strcmp(aname, oname)) { + found = oname; + break; + } + } + + /* Using g_assert_cmpstr() will give more useful failure + * messages than g_assert(found) */ + g_assert_cmpstr(aname, ==, found); + } + + QDECREF(all_types); + QDECREF(obj_types); + qtest_end(); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -118,6 +171,7 @@ int main(int argc, char **argv) qtest_add_func("device/introspect/none", test_device_intro_none); qtest_add_func("device/introspect/abstract", test_device_intro_abstract); qtest_add_func("device/introspect/concrete", test_device_intro_concrete); + qtest_add_func("device/introspect/abstract-interfaces", test_abstract_interfaces); return g_test_run(); } diff --git a/tests/libqtest.c b/tests/libqtest.c index 6f6975248f..d8fba6647a 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -768,6 +768,10 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size) gchar **args; size_t i; + if (!size) { + return; + } + qtest_sendf(s, "read 0x%" PRIx64 " 0x%zx\n", addr, size); args = qtest_rsp(s, 2); @@ -858,7 +862,13 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size) { const uint8_t *ptr = data; size_t i; - char *enc = g_malloc(2 * size + 1); + char *enc; + + if (!size) { + return; + } + + enc = g_malloc(2 * size + 1); for (i = 0; i < size; i++) { sprintf(&enc[i * 2], "%02x", ptr[i]); diff --git a/tests/m25p80-test.c b/tests/m25p80-test.c index cb7ec81f1a..244aa33dd9 100644 --- a/tests/m25p80-test.c +++ b/tests/m25p80-test.c @@ -36,6 +36,9 @@ #define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */ #define R_CTRL0 0x10 #define CTRL_CE_STOP_ACTIVE (1 << 2) +#define CTRL_READMODE 0x0 +#define CTRL_FREADMODE 0x1 +#define CTRL_WRITEMODE 0x2 #define CTRL_USERMODE 0x3 #define ASPEED_FMC_BASE 0x1E620000 @@ -50,6 +53,8 @@ enum { READ = 0x03, PP = 0x02, WREN = 0x6, + RESET_ENABLE = 0x66, + RESET_MEMORY = 0x99, EN_4BYTE_ADDR = 0xB7, ERASE_SECTOR = 0xd8, }; @@ -76,6 +81,30 @@ static void spi_conf(uint32_t value) writel(ASPEED_FMC_BASE + R_CONF, conf); } +static void spi_conf_remove(uint32_t value) +{ + uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF); + + conf &= ~value; + writel(ASPEED_FMC_BASE + R_CONF, conf); +} + +static void spi_ce_ctrl(uint32_t value) +{ + uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL); + + conf |= value; + writel(ASPEED_FMC_BASE + R_CE_CTRL, conf); +} + +static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd) +{ + uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); + ctrl &= ~(CTRL_USERMODE | 0xff << 16); + ctrl |= mode | (cmd << 16); + writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); +} + static void spi_ctrl_start_user(void) { uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); @@ -95,6 +124,18 @@ static void spi_ctrl_stop_user(void) writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); } +static void flash_reset(void) +{ + spi_conf(CONF_ENABLE_W0); + + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, RESET_ENABLE); + writeb(ASPEED_FLASH_BASE, RESET_MEMORY); + spi_ctrl_stop_user(); + + spi_conf_remove(CONF_ENABLE_W0); +} + static void test_read_jedec(void) { uint32_t jedec = 0x0; @@ -108,6 +149,8 @@ static void test_read_jedec(void) jedec |= readb(ASPEED_FLASH_BASE); spi_ctrl_stop_user(); + flash_reset(); + g_assert_cmphex(jedec, ==, FLASH_JEDEC); } @@ -128,6 +171,18 @@ static void read_page(uint32_t addr, uint32_t *page) spi_ctrl_stop_user(); } +static void read_page_mem(uint32_t addr, uint32_t *page) +{ + int i; + + /* move out USER mode to use direct reads from the AHB bus */ + spi_ctrl_setmode(CTRL_READMODE, READ); + + for (i = 0; i < PAGE_SIZE / 4; i++) { + page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4)); + } +} + static void test_erase_sector(void) { uint32_t some_page_addr = 0x600 * PAGE_SIZE; @@ -155,6 +210,8 @@ static void test_erase_sector(void) for (i = 0; i < PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, 0xffffffff); } + + flash_reset(); } static void test_erase_all(void) @@ -182,6 +239,8 @@ static void test_erase_all(void) for (i = 0; i < PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, 0xffffffff); } + + flash_reset(); } static void test_write_page(void) @@ -195,6 +254,7 @@ static void test_write_page(void) spi_ctrl_start_user(); writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, WREN); writeb(ASPEED_FLASH_BASE, PP); writel(ASPEED_FLASH_BASE, make_be32(my_page_addr)); @@ -215,6 +275,77 @@ static void test_write_page(void) for (i = 0; i < PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, 0xffffffff); } + + flash_reset(); +} + +static void test_read_page_mem(void) +{ + uint32_t my_page_addr = 0x14000 * PAGE_SIZE; /* beyond 16MB */ + uint32_t some_page_addr = 0x15000 * PAGE_SIZE; + uint32_t page[PAGE_SIZE / 4]; + int i; + + /* Enable 4BYTE mode for controller. This is should be strapped by + * HW for CE0 anyhow. + */ + spi_ce_ctrl(1 << CRTL_EXTENDED0); + + /* Enable 4BYTE mode for flash. */ + spi_conf(CONF_ENABLE_W0); + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + spi_ctrl_stop_user(); + spi_conf_remove(CONF_ENABLE_W0); + + /* Check what was written */ + read_page_mem(my_page_addr, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, my_page_addr + i * 4); + } + + /* Check some other page. It should be full of 0xff */ + read_page_mem(some_page_addr, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0xffffffff); + } + + flash_reset(); +} + +static void test_write_page_mem(void) +{ + uint32_t my_page_addr = 0x15000 * PAGE_SIZE; + uint32_t page[PAGE_SIZE / 4]; + int i; + + /* Enable 4BYTE mode for controller. This is should be strapped by + * HW for CE0 anyhow. + */ + spi_ce_ctrl(1 << CRTL_EXTENDED0); + + /* Enable 4BYTE mode for flash. */ + spi_conf(CONF_ENABLE_W0); + spi_ctrl_start_user(); + writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); + writeb(ASPEED_FLASH_BASE, WREN); + spi_ctrl_stop_user(); + + /* move out USER mode to use direct writes to the AHB bus */ + spi_ctrl_setmode(CTRL_WRITEMODE, PP); + + for (i = 0; i < PAGE_SIZE / 4; i++) { + writel(ASPEED_FLASH_BASE + my_page_addr + i * 4, + make_be32(my_page_addr + i * 4)); + } + + /* Check what was written */ + read_page_mem(my_page_addr, page); + for (i = 0; i < PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, my_page_addr + i * 4); + } + + flash_reset(); } static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX"; @@ -242,6 +373,8 @@ int main(int argc, char **argv) qtest_add_func("/m25p80/erase_sector", test_erase_sector); qtest_add_func("/m25p80/erase_all", test_erase_all); qtest_add_func("/m25p80/write_page", test_write_page); + qtest_add_func("/m25p80/read_page_mem", test_read_page_mem); + qtest_add_func("/m25p80/write_page_mem", test_write_page_mem); ret = g_test_run(); diff --git a/tests/qapi-schema/alternate-any.err b/tests/qapi-schema/alternate-any.err index aaa0154731..395c8ab583 100644 --- a/tests/qapi-schema/alternate-any.err +++ b/tests/qapi-schema/alternate-any.err @@ -1 +1 @@ -tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any' +tests/qapi-schema/alternate-any.json:6: Alternate 'Alt' member 'one' cannot use type 'any' diff --git a/tests/qapi-schema/alternate-any.json b/tests/qapi-schema/alternate-any.json index e47a73a116..c958776767 100644 --- a/tests/qapi-schema/alternate-any.json +++ b/tests/qapi-schema/alternate-any.json @@ -1,4 +1,8 @@ # we do not allow the 'any' type as an alternate branch + +## +# @Alt: +## { 'alternate': 'Alt', 'data': { 'one': 'any', 'two': 'int' } } diff --git a/tests/qapi-schema/alternate-array.err b/tests/qapi-schema/alternate-array.err index 7b930c64ab..09628e9755 100644 --- a/tests/qapi-schema/alternate-array.err +++ b/tests/qapi-schema/alternate-array.err @@ -1 +1 @@ -tests/qapi-schema/alternate-array.json:5: Member 'two' of alternate 'Alt' cannot be an array +tests/qapi-schema/alternate-array.json:12: Member 'two' of alternate 'Alt' cannot be an array diff --git a/tests/qapi-schema/alternate-array.json b/tests/qapi-schema/alternate-array.json index f241aac122..c2f98ad608 100644 --- a/tests/qapi-schema/alternate-array.json +++ b/tests/qapi-schema/alternate-array.json @@ -1,7 +1,14 @@ # we do not allow array branches in alternates + +## +# @One: +## # TODO: should we support this? { 'struct': 'One', 'data': { 'name': 'str' } } +## +# @Alt: +## { 'alternate': 'Alt', 'data': { 'one': 'One', 'two': [ 'int' ] } } diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alternate-base.err index 30d8a34373..3b679140e0 100644 --- a/tests/qapi-schema/alternate-base.err +++ b/tests/qapi-schema/alternate-base.err @@ -1 +1 @@ -tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt' +tests/qapi-schema/alternate-base.json:11: Unknown key 'base' in alternate 'Alt' diff --git a/tests/qapi-schema/alternate-base.json b/tests/qapi-schema/alternate-base.json index 529430ecf2..9612b7925d 100644 --- a/tests/qapi-schema/alternate-base.json +++ b/tests/qapi-schema/alternate-base.json @@ -1,6 +1,13 @@ # we reject alternate with base type + +## +# @Base: +## { 'struct': 'Base', 'data': { 'string': 'str' } } +## +# @Alt: +## { 'alternate': 'Alt', 'base': 'Base', 'data': { 'number': 'int' } } diff --git a/tests/qapi-schema/alternate-clash.err b/tests/qapi-schema/alternate-clash.err index 604d8495eb..f07c3e8ad3 100644 --- a/tests/qapi-schema/alternate-clash.err +++ b/tests/qapi-schema/alternate-clash.err @@ -1 +1 @@ -tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1) +tests/qapi-schema/alternate-clash.json:11: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1) diff --git a/tests/qapi-schema/alternate-clash.json b/tests/qapi-schema/alternate-clash.json index 6d73bc527b..97ca7c80e7 100644 --- a/tests/qapi-schema/alternate-clash.json +++ b/tests/qapi-schema/alternate-clash.json @@ -4,5 +4,9 @@ # TODO: In the future, if alternates are simplified to not generate # the implicit Alt1Kind enum, we would still have a collision with the # resulting C union trying to have two members named 'a_b'. + +## +# @Alt1: +## { 'alternate': 'Alt1', 'data': { 'a-b': 'str', 'a_b': 'int' } } diff --git a/tests/qapi-schema/alternate-conflict-dict.err b/tests/qapi-schema/alternate-conflict-dict.err index 0f411f4faf..7cb023fdd8 100644 --- a/tests/qapi-schema/alternate-conflict-dict.err +++ b/tests/qapi-schema/alternate-conflict-dict.err @@ -1 +1 @@ -tests/qapi-schema/alternate-conflict-dict.json:6: Alternate 'Alt' member 'two' can't be distinguished from member 'one' +tests/qapi-schema/alternate-conflict-dict.json:16: Alternate 'Alt' member 'two' can't be distinguished from member 'one' diff --git a/tests/qapi-schema/alternate-conflict-dict.json b/tests/qapi-schema/alternate-conflict-dict.json index d566cca816..9f9d97fa2e 100644 --- a/tests/qapi-schema/alternate-conflict-dict.json +++ b/tests/qapi-schema/alternate-conflict-dict.json @@ -1,8 +1,18 @@ # we reject alternates with multiple object branches + +## +# @One: +## { 'struct': 'One', 'data': { 'name': 'str' } } +## +# @Two: +## { 'struct': 'Two', 'data': { 'value': 'int' } } +## +# @Alt: +## { 'alternate': 'Alt', 'data': { 'one': 'One', 'two': 'Two' } } diff --git a/tests/qapi-schema/alternate-conflict-string.err b/tests/qapi-schema/alternate-conflict-string.err index fc523b0879..6dbbacd1d2 100644 --- a/tests/qapi-schema/alternate-conflict-string.err +++ b/tests/qapi-schema/alternate-conflict-string.err @@ -1 +1 @@ -tests/qapi-schema/alternate-conflict-string.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one' +tests/qapi-schema/alternate-conflict-string.json:11: Alternate 'Alt' member 'two' can't be distinguished from member 'one' diff --git a/tests/qapi-schema/alternate-conflict-string.json b/tests/qapi-schema/alternate-conflict-string.json index 72f04a820a..12aafab808 100644 --- a/tests/qapi-schema/alternate-conflict-string.json +++ b/tests/qapi-schema/alternate-conflict-string.json @@ -1,6 +1,13 @@ # we reject alternates with multiple string-like branches + +## +# @Enum: +## { 'enum': 'Enum', 'data': [ 'hello', 'world' ] } +## +# @Alt: +## { 'alternate': 'Alt', 'data': { 'one': 'str', 'two': 'Enum' } } diff --git a/tests/qapi-schema/alternate-empty.err b/tests/qapi-schema/alternate-empty.err index bb06c5bfec..8245ce3103 100644 --- a/tests/qapi-schema/alternate-empty.err +++ b/tests/qapi-schema/alternate-empty.err @@ -1 +1 @@ -tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data' +tests/qapi-schema/alternate-empty.json:6: Alternate 'Alt' should have at least two branches in 'data' diff --git a/tests/qapi-schema/alternate-empty.json b/tests/qapi-schema/alternate-empty.json index fff15baf16..db54405240 100644 --- a/tests/qapi-schema/alternate-empty.json +++ b/tests/qapi-schema/alternate-empty.json @@ -1,2 +1,6 @@ # alternates must list at least two types to be useful + +## +# @Alt: +## { 'alternate': 'Alt', 'data': { 'i': 'int' } } diff --git a/tests/qapi-schema/alternate-nested.err b/tests/qapi-schema/alternate-nested.err index 4d1187e60e..1804ffbf47 100644 --- a/tests/qapi-schema/alternate-nested.err +++ b/tests/qapi-schema/alternate-nested.err @@ -1 +1 @@ -tests/qapi-schema/alternate-nested.json:4: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1' +tests/qapi-schema/alternate-nested.json:11: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1' diff --git a/tests/qapi-schema/alternate-nested.json b/tests/qapi-schema/alternate-nested.json index 8e22186491..9f83ebe2e0 100644 --- a/tests/qapi-schema/alternate-nested.json +++ b/tests/qapi-schema/alternate-nested.json @@ -1,5 +1,12 @@ # we reject a nested alternate branch + +## +# @Alt1: +## { 'alternate': 'Alt1', 'data': { 'name': 'str', 'value': 'int' } } +## +# @Alt2: +## { 'alternate': 'Alt2', 'data': { 'nested': 'Alt1', 'b': 'bool' } } diff --git a/tests/qapi-schema/alternate-unknown.err b/tests/qapi-schema/alternate-unknown.err index dea45dc730..cf5b9b6830 100644 --- a/tests/qapi-schema/alternate-unknown.err +++ b/tests/qapi-schema/alternate-unknown.err @@ -1 +1 @@ -tests/qapi-schema/alternate-unknown.json:2: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType' +tests/qapi-schema/alternate-unknown.json:6: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType' diff --git a/tests/qapi-schema/alternate-unknown.json b/tests/qapi-schema/alternate-unknown.json index 08c80dced0..941ba1fac4 100644 --- a/tests/qapi-schema/alternate-unknown.json +++ b/tests/qapi-schema/alternate-unknown.json @@ -1,3 +1,7 @@ # we reject an alternate with unknown type in branch + +## +# @Alt: +## { 'alternate': 'Alt', 'data': { 'unknown': 'MissingType', 'i': 'int' } } diff --git a/tests/qapi-schema/args-alternate.err b/tests/qapi-schema/args-alternate.err index 3086eae56b..2e6bf54245 100644 --- a/tests/qapi-schema/args-alternate.err +++ b/tests/qapi-schema/args-alternate.err @@ -1 +1 @@ -tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt' +tests/qapi-schema/args-alternate.json:11: 'data' for command 'oops' cannot use alternate type 'Alt' diff --git a/tests/qapi-schema/args-alternate.json b/tests/qapi-schema/args-alternate.json index 69e94d4819..49d0211a03 100644 --- a/tests/qapi-schema/args-alternate.json +++ b/tests/qapi-schema/args-alternate.json @@ -1,3 +1,11 @@ # we do not allow alternate arguments + +## +# @Alt: +## { 'alternate': 'Alt', 'data': { 'case1': 'int', 'case2': 'str' } } + +## +# @oops: +## { 'command': 'oops', 'data': 'Alt' } diff --git a/tests/qapi-schema/args-any.err b/tests/qapi-schema/args-any.err index bf9b5e0730..955504b10f 100644 --- a/tests/qapi-schema/args-any.err +++ b/tests/qapi-schema/args-any.err @@ -1 +1 @@ -tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any' +tests/qapi-schema/args-any.json:6: 'data' for command 'oops' cannot use built-in type 'any' diff --git a/tests/qapi-schema/args-any.json b/tests/qapi-schema/args-any.json index 58fe5e470e..f494479cc9 100644 --- a/tests/qapi-schema/args-any.json +++ b/tests/qapi-schema/args-any.json @@ -1,2 +1,6 @@ # we do not allow an 'any' argument + +## +# @oops: +## { 'command': 'oops', 'data': 'any' } diff --git a/tests/qapi-schema/args-array-empty.err b/tests/qapi-schema/args-array-empty.err index cb7ed33b3f..e85f7918ab 100644 --- a/tests/qapi-schema/args-array-empty.err +++ b/tests/qapi-schema/args-array-empty.err @@ -1 +1 @@ -tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name +tests/qapi-schema/args-array-empty.json:6: Member 'empty' of 'data' for command 'oops': array type must contain single type name diff --git a/tests/qapi-schema/args-array-empty.json b/tests/qapi-schema/args-array-empty.json index 652dcfb24a..78a0b88221 100644 --- a/tests/qapi-schema/args-array-empty.json +++ b/tests/qapi-schema/args-array-empty.json @@ -1,2 +1,6 @@ # we reject an array for data if it does not contain a known type + +## +# @oops: +## { 'command': 'oops', 'data': { 'empty': [ ] } } diff --git a/tests/qapi-schema/args-array-unknown.err b/tests/qapi-schema/args-array-unknown.err index cd7a0f98d7..77788de099 100644 --- a/tests/qapi-schema/args-array-unknown.err +++ b/tests/qapi-schema/args-array-unknown.err @@ -1 +1 @@ -tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType' +tests/qapi-schema/args-array-unknown.json:6: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType' diff --git a/tests/qapi-schema/args-array-unknown.json b/tests/qapi-schema/args-array-unknown.json index 6f3e883315..f680fc10d3 100644 --- a/tests/qapi-schema/args-array-unknown.json +++ b/tests/qapi-schema/args-array-unknown.json @@ -1,2 +1,6 @@ # we reject an array for data if it does not contain a known type + +## +# @oops: +## { 'command': 'oops', 'data': { 'array': [ 'NoSuchType' ] } } diff --git a/tests/qapi-schema/args-bad-boxed.err b/tests/qapi-schema/args-bad-boxed.err index ad0d417321..87a906137a 100644 --- a/tests/qapi-schema/args-bad-boxed.err +++ b/tests/qapi-schema/args-bad-boxed.err @@ -1 +1 @@ -tests/qapi-schema/args-bad-boxed.json:2: 'boxed' of command 'foo' should only use true value +tests/qapi-schema/args-bad-boxed.json:6: 'boxed' of command 'foo' should only use true value diff --git a/tests/qapi-schema/args-bad-boxed.json b/tests/qapi-schema/args-bad-boxed.json index dea0cd0aa5..4c0b28f291 100644 --- a/tests/qapi-schema/args-bad-boxed.json +++ b/tests/qapi-schema/args-bad-boxed.json @@ -1,2 +1,6 @@ # 'boxed' should only appear with value true + +## +# @foo: +## { 'command': 'foo', 'boxed': false } diff --git a/tests/qapi-schema/args-boxed-anon.err b/tests/qapi-schema/args-boxed-anon.err index f24f345218..3cfac0b923 100644 --- a/tests/qapi-schema/args-boxed-anon.err +++ b/tests/qapi-schema/args-boxed-anon.err @@ -1 +1 @@ -tests/qapi-schema/args-boxed-anon.json:2: 'data' for command 'foo' should be a type name +tests/qapi-schema/args-boxed-anon.json:6: 'data' for command 'foo' should be a type name diff --git a/tests/qapi-schema/args-boxed-anon.json b/tests/qapi-schema/args-boxed-anon.json index 95f60da2ed..2358e6abb1 100644 --- a/tests/qapi-schema/args-boxed-anon.json +++ b/tests/qapi-schema/args-boxed-anon.json @@ -1,2 +1,6 @@ # 'boxed' can only be used with named types + +## +# @foo: +## { 'command': 'foo', 'boxed': true, 'data': { 'string': 'str' } } diff --git a/tests/qapi-schema/args-boxed-empty.err b/tests/qapi-schema/args-boxed-empty.err index 039603e85c..963f495a9d 100644 --- a/tests/qapi-schema/args-boxed-empty.err +++ b/tests/qapi-schema/args-boxed-empty.err @@ -1 +1 @@ -tests/qapi-schema/args-boxed-empty.json:3: Cannot use 'boxed' with empty type +tests/qapi-schema/args-boxed-empty.json:11: Cannot use 'boxed' with empty type diff --git a/tests/qapi-schema/args-boxed-empty.json b/tests/qapi-schema/args-boxed-empty.json index 52717e065f..8e8cc26525 100644 --- a/tests/qapi-schema/args-boxed-empty.json +++ b/tests/qapi-schema/args-boxed-empty.json @@ -1,3 +1,11 @@ # 'boxed' requires a non-empty type + +## +# @Empty: +## { 'struct': 'Empty', 'data': {} } + +## +# @foo: +## { 'command': 'foo', 'boxed': true, 'data': 'Empty' } diff --git a/tests/qapi-schema/args-boxed-string.err b/tests/qapi-schema/args-boxed-string.err index d326b48aef..7623755208 100644 --- a/tests/qapi-schema/args-boxed-string.err +++ b/tests/qapi-schema/args-boxed-string.err @@ -1 +1 @@ -tests/qapi-schema/args-boxed-string.json:2: 'data' for command 'foo' cannot use built-in type 'str' +tests/qapi-schema/args-boxed-string.json:6: 'data' for command 'foo' cannot use built-in type 'str' diff --git a/tests/qapi-schema/args-boxed-string.json b/tests/qapi-schema/args-boxed-string.json index f91a1502e7..aecdf97ce9 100644 --- a/tests/qapi-schema/args-boxed-string.json +++ b/tests/qapi-schema/args-boxed-string.json @@ -1,2 +1,6 @@ # 'boxed' requires a complex (not built-in) type + +## +# @foo: +## { 'command': 'foo', 'boxed': true, 'data': 'str' } diff --git a/tests/qapi-schema/args-int.err b/tests/qapi-schema/args-int.err index dc1d2504ff..38b3202b09 100644 --- a/tests/qapi-schema/args-int.err +++ b/tests/qapi-schema/args-int.err @@ -1 +1 @@ -tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int' +tests/qapi-schema/args-int.json:6: 'data' for command 'oops' cannot use built-in type 'int' diff --git a/tests/qapi-schema/args-int.json b/tests/qapi-schema/args-int.json index a334d92e8c..7f4e1b7aa6 100644 --- a/tests/qapi-schema/args-int.json +++ b/tests/qapi-schema/args-int.json @@ -1,2 +1,6 @@ # we reject commands where data is not an array or complex type + +## +# @oops: +## { 'command': 'oops', 'data': 'int' } diff --git a/tests/qapi-schema/args-invalid.err b/tests/qapi-schema/args-invalid.err index fe1e94975b..5d3568d7c3 100644 --- a/tests/qapi-schema/args-invalid.err +++ b/tests/qapi-schema/args-invalid.err @@ -1 +1 @@ -tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name +tests/qapi-schema/args-invalid.json:4: 'data' for command 'foo' should be a dictionary or type name diff --git a/tests/qapi-schema/args-invalid.json b/tests/qapi-schema/args-invalid.json index db0981341b..1a7e63bb23 100644 --- a/tests/qapi-schema/args-invalid.json +++ b/tests/qapi-schema/args-invalid.json @@ -1,2 +1,5 @@ +## +# @foo: +## { 'command': 'foo', 'data': false } diff --git a/tests/qapi-schema/args-member-array-bad.err b/tests/qapi-schema/args-member-array-bad.err index 881b4d954f..825ffca9bf 100644 --- a/tests/qapi-schema/args-member-array-bad.err +++ b/tests/qapi-schema/args-member-array-bad.err @@ -1 +1 @@ -tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name +tests/qapi-schema/args-member-array-bad.json:6: Member 'member' of 'data' for command 'oops': array type must contain single type name diff --git a/tests/qapi-schema/args-member-array-bad.json b/tests/qapi-schema/args-member-array-bad.json index b2ff144ec6..e934f5c457 100644 --- a/tests/qapi-schema/args-member-array-bad.json +++ b/tests/qapi-schema/args-member-array-bad.json @@ -1,2 +1,6 @@ # we reject data if it does not contain a valid array type + +## +# @oops: +## { 'command': 'oops', 'data': { 'member': [ { 'nested': 'str' } ] } } diff --git a/tests/qapi-schema/args-member-case.err b/tests/qapi-schema/args-member-case.err index 19c4426601..a3fb2bdd60 100644 --- a/tests/qapi-schema/args-member-case.err +++ b/tests/qapi-schema/args-member-case.err @@ -1 +1 @@ -tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase +tests/qapi-schema/args-member-case.json:6: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase diff --git a/tests/qapi-schema/args-member-case.json b/tests/qapi-schema/args-member-case.json index 93439bee8b..811e658d66 100644 --- a/tests/qapi-schema/args-member-case.json +++ b/tests/qapi-schema/args-member-case.json @@ -1,2 +1,6 @@ # Member names should be 'lower-case' unless the struct/command is whitelisted + +## +# @no-way-this-will-get-whitelisted: +## { 'command': 'no-way-this-will-get-whitelisted', 'data': { 'Arg': 'int' } } diff --git a/tests/qapi-schema/args-member-unknown.err b/tests/qapi-schema/args-member-unknown.err index f6f82828ce..3db452b95a 100644 --- a/tests/qapi-schema/args-member-unknown.err +++ b/tests/qapi-schema/args-member-unknown.err @@ -1 +1 @@ -tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType' +tests/qapi-schema/args-member-unknown.json:6: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType' diff --git a/tests/qapi-schema/args-member-unknown.json b/tests/qapi-schema/args-member-unknown.json index 342a41ec90..e2fef9c46f 100644 --- a/tests/qapi-schema/args-member-unknown.json +++ b/tests/qapi-schema/args-member-unknown.json @@ -1,2 +1,6 @@ # we reject data if it does not contain a known type + +## +# @oops: +## { 'command': 'oops', 'data': { 'member': 'NoSuchType' } } diff --git a/tests/qapi-schema/args-name-clash.err b/tests/qapi-schema/args-name-clash.err index d953e8d241..23988cb5ca 100644 --- a/tests/qapi-schema/args-name-clash.err +++ b/tests/qapi-schema/args-name-clash.err @@ -1 +1 @@ -tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops) +tests/qapi-schema/args-name-clash.json:8: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops) diff --git a/tests/qapi-schema/args-name-clash.json b/tests/qapi-schema/args-name-clash.json index 61423cb893..991323b78d 100644 --- a/tests/qapi-schema/args-name-clash.json +++ b/tests/qapi-schema/args-name-clash.json @@ -1,4 +1,8 @@ # C member name collision # Reject members that clash when mapped to C names (we would have two 'a_b' # members). + +## +# @oops: +## { 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } } diff --git a/tests/qapi-schema/args-union.err b/tests/qapi-schema/args-union.err index f8ad223dde..ce0a34e16c 100644 --- a/tests/qapi-schema/args-union.err +++ b/tests/qapi-schema/args-union.err @@ -1 +1 @@ -tests/qapi-schema/args-union.json:3: 'data' for command 'oops' cannot use union type 'Uni' +tests/qapi-schema/args-union.json:10: 'data' for command 'oops' cannot use union type 'Uni' diff --git a/tests/qapi-schema/args-union.json b/tests/qapi-schema/args-union.json index 2fcaeaae16..57284b43c5 100644 --- a/tests/qapi-schema/args-union.json +++ b/tests/qapi-schema/args-union.json @@ -1,3 +1,10 @@ # use of union arguments requires 'boxed':true + +## +# @Uni: +## { 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } } +## +# oops: +## { 'command': 'oops', 'data': 'Uni' } diff --git a/tests/qapi-schema/args-unknown.err b/tests/qapi-schema/args-unknown.err index 4d91ec869f..ba6c6cf326 100644 --- a/tests/qapi-schema/args-unknown.err +++ b/tests/qapi-schema/args-unknown.err @@ -1 +1 @@ -tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType' +tests/qapi-schema/args-unknown.json:6: 'data' for command 'oops' uses unknown type 'NoSuchType' diff --git a/tests/qapi-schema/args-unknown.json b/tests/qapi-schema/args-unknown.json index 32aba43b3f..12666dc020 100644 --- a/tests/qapi-schema/args-unknown.json +++ b/tests/qapi-schema/args-unknown.json @@ -1,2 +1,6 @@ # we reject data if it does not contain a known type + +## +# @oops: +## { 'command': 'oops', 'data': 'NoSuchType' } diff --git a/tests/qapi-schema/bad-base.err b/tests/qapi-schema/bad-base.err index 154274bdd3..e668761c65 100644 --- a/tests/qapi-schema/bad-base.err +++ b/tests/qapi-schema/bad-base.err @@ -1 +1 @@ -tests/qapi-schema/bad-base.json:3: 'base' for struct 'MyType' cannot use union type 'Union' +tests/qapi-schema/bad-base.json:10: 'base' for struct 'MyType' cannot use union type 'Union' diff --git a/tests/qapi-schema/bad-base.json b/tests/qapi-schema/bad-base.json index a634331cdd..c3faa8242b 100644 --- a/tests/qapi-schema/bad-base.json +++ b/tests/qapi-schema/bad-base.json @@ -1,3 +1,10 @@ # we reject a base that is not a struct + +## +# @Union: +## { 'union': 'Union', 'data': { 'a': 'int', 'b': 'str' } } +## +# @MyType: +## { 'struct': 'MyType', 'base': 'Union', 'data': { 'c': 'int' } } diff --git a/tests/qapi-schema/bad-data.err b/tests/qapi-schema/bad-data.err index 8523ac4f46..c1b9e35313 100644 --- a/tests/qapi-schema/bad-data.err +++ b/tests/qapi-schema/bad-data.err @@ -1 +1 @@ -tests/qapi-schema/bad-data.json:2: 'data' for command 'oops' cannot be an array +tests/qapi-schema/bad-data.json:6: 'data' for command 'oops' cannot be an array diff --git a/tests/qapi-schema/bad-data.json b/tests/qapi-schema/bad-data.json index 832eeb76f4..51c444f4f8 100644 --- a/tests/qapi-schema/bad-data.json +++ b/tests/qapi-schema/bad-data.json @@ -1,2 +1,6 @@ # we ensure 'data' is a dictionary for all but enums + +## +# @oops: +## { 'command': 'oops', 'data': [ ] } diff --git a/tests/qapi-schema/bad-ident.err b/tests/qapi-schema/bad-ident.err index c4190602b5..b757aa21e7 100644 --- a/tests/qapi-schema/bad-ident.err +++ b/tests/qapi-schema/bad-ident.err @@ -1 +1 @@ -tests/qapi-schema/bad-ident.json:2: 'struct' does not allow optional name '*oops' +tests/qapi-schema/bad-ident.json:6: 'struct' does not allow optional name '*oops' diff --git a/tests/qapi-schema/bad-ident.json b/tests/qapi-schema/bad-ident.json index 763627ad23..b43df7a3e0 100644 --- a/tests/qapi-schema/bad-ident.json +++ b/tests/qapi-schema/bad-ident.json @@ -1,2 +1,6 @@ # we reject creating a type name with bad name + +## +# @*oops: +## { 'struct': '*oops', 'data': { 'i': 'int' } } diff --git a/tests/qapi-schema/bad-type-bool.err b/tests/qapi-schema/bad-type-bool.err index 62fd70baaf..72e026b46c 100644 --- a/tests/qapi-schema/bad-type-bool.err +++ b/tests/qapi-schema/bad-type-bool.err @@ -1 +1 @@ -tests/qapi-schema/bad-type-bool.json:2: 'struct' key must have a string value +tests/qapi-schema/bad-type-bool.json:6: 'struct' key must have a string value diff --git a/tests/qapi-schema/bad-type-bool.json b/tests/qapi-schema/bad-type-bool.json index bde17b56c4..1f9eddf938 100644 --- a/tests/qapi-schema/bad-type-bool.json +++ b/tests/qapi-schema/bad-type-bool.json @@ -1,2 +1,6 @@ # we reject an expression with a metatype that is not a string + +## +# @true: +## { 'struct': true, 'data': { } } diff --git a/tests/qapi-schema/bad-type-dict.err b/tests/qapi-schema/bad-type-dict.err index 0b2a2aeac4..d0d1f607e5 100644 --- a/tests/qapi-schema/bad-type-dict.err +++ b/tests/qapi-schema/bad-type-dict.err @@ -1 +1 @@ -tests/qapi-schema/bad-type-dict.json:2: 'command' key must have a string value +tests/qapi-schema/bad-type-dict.json:6: 'command' key must have a string value diff --git a/tests/qapi-schema/bad-type-dict.json b/tests/qapi-schema/bad-type-dict.json index 2a91b241f8..5952caab28 100644 --- a/tests/qapi-schema/bad-type-dict.json +++ b/tests/qapi-schema/bad-type-dict.json @@ -1,2 +1,6 @@ # we reject an expression with a metatype that is not a string + +## +# @foo: +## { 'command': { } } diff --git a/tests/qapi-schema/base-cycle-direct.err b/tests/qapi-schema/base-cycle-direct.err index 9c68f6543d..dd7f5aace6 100644 --- a/tests/qapi-schema/base-cycle-direct.err +++ b/tests/qapi-schema/base-cycle-direct.err @@ -1 +1 @@ -tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself +tests/qapi-schema/base-cycle-direct.json:6: Object Loopy contains itself diff --git a/tests/qapi-schema/base-cycle-direct.json b/tests/qapi-schema/base-cycle-direct.json index 4fc66d0516..9780f7e2ca 100644 --- a/tests/qapi-schema/base-cycle-direct.json +++ b/tests/qapi-schema/base-cycle-direct.json @@ -1,2 +1,6 @@ # we reject a loop in base classes + +## +# @Loopy: +## { 'struct': 'Loopy', 'base': 'Loopy', 'data': {} } diff --git a/tests/qapi-schema/base-cycle-indirect.err b/tests/qapi-schema/base-cycle-indirect.err index fc92fe47f8..f4198e4a40 100644 --- a/tests/qapi-schema/base-cycle-indirect.err +++ b/tests/qapi-schema/base-cycle-indirect.err @@ -1 +1 @@ -tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself +tests/qapi-schema/base-cycle-indirect.json:6: Object Base1 contains itself diff --git a/tests/qapi-schema/base-cycle-indirect.json b/tests/qapi-schema/base-cycle-indirect.json index 28667721a3..99926c4609 100644 --- a/tests/qapi-schema/base-cycle-indirect.json +++ b/tests/qapi-schema/base-cycle-indirect.json @@ -1,3 +1,10 @@ # we reject a loop in base classes + +## +# @Base1: +## { 'struct': 'Base1', 'base': 'Base2', 'data': {} } +## +# @Base2: +## { 'struct': 'Base2', 'base': 'Base1', 'data': {} } diff --git a/tests/qapi-schema/command-int.err b/tests/qapi-schema/command-int.err index 0f9300679b..3c834a97ab 100644 --- a/tests/qapi-schema/command-int.err +++ b/tests/qapi-schema/command-int.err @@ -1 +1 @@ -tests/qapi-schema/command-int.json:2: built-in 'int' is already defined +tests/qapi-schema/command-int.json:6: built-in 'int' is already defined diff --git a/tests/qapi-schema/command-int.json b/tests/qapi-schema/command-int.json index 9a62554fc6..5b51bf148b 100644 --- a/tests/qapi-schema/command-int.json +++ b/tests/qapi-schema/command-int.json @@ -1,2 +1,6 @@ # we reject collisions between commands and types + +## +# @int: +## { 'command': 'int', 'data': { 'character': 'str' } } diff --git a/tests/qapi-schema/comments.json b/tests/qapi-schema/comments.json index e643f3a74c..d31ef0d90a 100644 --- a/tests/qapi-schema/comments.json +++ b/tests/qapi-schema/comments.json @@ -1,4 +1,8 @@ # Unindented comment + +## +# @Status: +## { 'enum': 'Status', # Comment to the right of code # Indented comment 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out index 5d7c13cad1..a962fb2d2e 100644 --- a/tests/qapi-schema/comments.out +++ b/tests/qapi-schema/comments.out @@ -2,3 +2,4 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo prefix QTYPE enum Status ['good', 'bad', 'ugly'] object q_empty +doc symbol=Status expr=('enum', 'Status') diff --git a/tests/qapi-schema/doc-bad-args.err b/tests/qapi-schema/doc-bad-args.err new file mode 100644 index 0000000000..5d44d9b668 --- /dev/null +++ b/tests/qapi-schema/doc-bad-args.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-bad-args.json:3: The following documented members are not in the declaration: b diff --git a/tests/qapi-schema/doc-bad-args.exit b/tests/qapi-schema/doc-bad-args.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-bad-args.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-bad-args.json b/tests/qapi-schema/doc-bad-args.json new file mode 100644 index 0000000000..048e0fc5ef --- /dev/null +++ b/tests/qapi-schema/doc-bad-args.json @@ -0,0 +1,8 @@ +# Arguments listed in the doc comment must exist in the actual schema + +## +# @foo: +# @a: a +# @b: b +## +{ 'command': 'foo', 'data': {'a': 'int'} } diff --git a/tests/qapi-schema/doc-bad-args.out b/tests/qapi-schema/doc-bad-args.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-bad-args.out diff --git a/tests/qapi-schema/doc-bad-symbol.err b/tests/qapi-schema/doc-bad-symbol.err new file mode 100644 index 0000000000..ac4e5667cb --- /dev/null +++ b/tests/qapi-schema/doc-bad-symbol.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-bad-symbol.json:3: Definition of 'foo' follows documentation for 'food' diff --git a/tests/qapi-schema/doc-bad-symbol.exit b/tests/qapi-schema/doc-bad-symbol.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-bad-symbol.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-bad-symbol.json b/tests/qapi-schema/doc-bad-symbol.json new file mode 100644 index 0000000000..a7c15b3b8f --- /dev/null +++ b/tests/qapi-schema/doc-bad-symbol.json @@ -0,0 +1,6 @@ +# Documentation symbol mismatch with expression + +## +# @food: +## +{ 'command': 'foo', 'data': {'a': 'int'} } diff --git a/tests/qapi-schema/doc-bad-symbol.out b/tests/qapi-schema/doc-bad-symbol.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-bad-symbol.out diff --git a/tests/qapi-schema/doc-duplicated-arg.err b/tests/qapi-schema/doc-duplicated-arg.err new file mode 100644 index 0000000000..1c3f8e0a54 --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-arg.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-duplicated-arg.json:6:1: 'a' parameter name duplicated diff --git a/tests/qapi-schema/doc-duplicated-arg.exit b/tests/qapi-schema/doc-duplicated-arg.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-arg.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-duplicated-arg.json b/tests/qapi-schema/doc-duplicated-arg.json new file mode 100644 index 0000000000..035cae9745 --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-arg.json @@ -0,0 +1,7 @@ +# Do not allow duplicated argument + +## +# @foo: +# @a: +# @a: +## diff --git a/tests/qapi-schema/doc-duplicated-arg.out b/tests/qapi-schema/doc-duplicated-arg.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-arg.out diff --git a/tests/qapi-schema/doc-duplicated-return.err b/tests/qapi-schema/doc-duplicated-return.err new file mode 100644 index 0000000000..e48039f8e5 --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-return.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-duplicated-return.json:7:1: Duplicated 'Returns' section diff --git a/tests/qapi-schema/doc-duplicated-return.exit b/tests/qapi-schema/doc-duplicated-return.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-return.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-duplicated-return.json b/tests/qapi-schema/doc-duplicated-return.json new file mode 100644 index 0000000000..b44b5ae979 --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-return.json @@ -0,0 +1,8 @@ +# Do not allow duplicated Returns section + +## +# @foo: +# +# Returns: 0 +# Returns: 1 +## diff --git a/tests/qapi-schema/doc-duplicated-return.out b/tests/qapi-schema/doc-duplicated-return.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-return.out diff --git a/tests/qapi-schema/doc-duplicated-since.err b/tests/qapi-schema/doc-duplicated-since.err new file mode 100644 index 0000000000..3fb890744a --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-since.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-duplicated-since.json:7:1: Duplicated 'Since' section diff --git a/tests/qapi-schema/doc-duplicated-since.exit b/tests/qapi-schema/doc-duplicated-since.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-since.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-duplicated-since.json b/tests/qapi-schema/doc-duplicated-since.json new file mode 100644 index 0000000000..343cd872cb --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-since.json @@ -0,0 +1,8 @@ +# Do not allow duplicated Since section + +## +# @foo: +# +# Since: 0 +# Since: 1 +## diff --git a/tests/qapi-schema/doc-duplicated-since.out b/tests/qapi-schema/doc-duplicated-since.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-duplicated-since.out diff --git a/tests/qapi-schema/doc-empty-arg.err b/tests/qapi-schema/doc-empty-arg.err new file mode 100644 index 0000000000..2895518fa7 --- /dev/null +++ b/tests/qapi-schema/doc-empty-arg.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-empty-arg.json:5:1: Invalid parameter name diff --git a/tests/qapi-schema/doc-empty-arg.exit b/tests/qapi-schema/doc-empty-arg.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-empty-arg.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-empty-arg.json b/tests/qapi-schema/doc-empty-arg.json new file mode 100644 index 0000000000..8f76ede8f3 --- /dev/null +++ b/tests/qapi-schema/doc-empty-arg.json @@ -0,0 +1,6 @@ +# An invalid empty argument name + +## +# @foo: +# @: +## diff --git a/tests/qapi-schema/doc-empty-arg.out b/tests/qapi-schema/doc-empty-arg.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-empty-arg.out diff --git a/tests/qapi-schema/doc-empty-section.err b/tests/qapi-schema/doc-empty-section.err new file mode 100644 index 0000000000..00ad625e17 --- /dev/null +++ b/tests/qapi-schema/doc-empty-section.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-empty-section.json:3: Empty doc section 'Note' diff --git a/tests/qapi-schema/doc-empty-section.exit b/tests/qapi-schema/doc-empty-section.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-empty-section.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-empty-section.json b/tests/qapi-schema/doc-empty-section.json new file mode 100644 index 0000000000..f3384e9a3b --- /dev/null +++ b/tests/qapi-schema/doc-empty-section.json @@ -0,0 +1,8 @@ +# Tagged-section must not be empty + +## +# @foo: +# +# Note: +## +{ 'command': 'foo', 'data': {'a': 'int'} } diff --git a/tests/qapi-schema/doc-empty-section.out b/tests/qapi-schema/doc-empty-section.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-empty-section.out diff --git a/tests/qapi-schema/doc-empty-symbol.err b/tests/qapi-schema/doc-empty-symbol.err new file mode 100644 index 0000000000..1936ad094f --- /dev/null +++ b/tests/qapi-schema/doc-empty-symbol.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-empty-symbol.json:4:1: Invalid name diff --git a/tests/qapi-schema/doc-empty-symbol.exit b/tests/qapi-schema/doc-empty-symbol.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-empty-symbol.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-empty-symbol.json b/tests/qapi-schema/doc-empty-symbol.json new file mode 100644 index 0000000000..fb8fddc4ae --- /dev/null +++ b/tests/qapi-schema/doc-empty-symbol.json @@ -0,0 +1,5 @@ +# Invalid documentation symbol + +## +# @: +## diff --git a/tests/qapi-schema/doc-empty-symbol.out b/tests/qapi-schema/doc-empty-symbol.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-empty-symbol.out diff --git a/tests/qapi-schema/doc-interleaved-section.err b/tests/qapi-schema/doc-interleaved-section.err new file mode 100644 index 0000000000..d373eabc55 --- /dev/null +++ b/tests/qapi-schema/doc-interleaved-section.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-interleaved-section.json:15:1: '@foobar:' can't follow 'Note' section diff --git a/tests/qapi-schema/doc-interleaved-section.exit b/tests/qapi-schema/doc-interleaved-section.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-interleaved-section.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-interleaved-section.json b/tests/qapi-schema/doc-interleaved-section.json new file mode 100644 index 0000000000..adb29e98da --- /dev/null +++ b/tests/qapi-schema/doc-interleaved-section.json @@ -0,0 +1,21 @@ +# Arguments and sections must not be interleaved + +## +# @TestStruct: +# +# body +# +# @integer: foo +# blah +# +# bao +# +# Note: a section. +# +# @foobar: catch this +# +# Since: 2.3 +# +## +{ 'struct': 'TestStruct', + 'data': { 'integer': 'int', 'foobar': 'int' } } diff --git a/tests/qapi-schema/doc-interleaved-section.out b/tests/qapi-schema/doc-interleaved-section.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-interleaved-section.out diff --git a/tests/qapi-schema/doc-invalid-end.err b/tests/qapi-schema/doc-invalid-end.err new file mode 100644 index 0000000000..2bda28cb54 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-end.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-invalid-end.json:5:2: Documentation comment must end with '##' diff --git a/tests/qapi-schema/doc-invalid-end.exit b/tests/qapi-schema/doc-invalid-end.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-invalid-end.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-invalid-end.json b/tests/qapi-schema/doc-invalid-end.json new file mode 100644 index 0000000000..3583b23b18 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-end.json @@ -0,0 +1,5 @@ +# Documentation must end with '##' + +## +# An invalid comment +# diff --git a/tests/qapi-schema/doc-invalid-end.out b/tests/qapi-schema/doc-invalid-end.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-end.out diff --git a/tests/qapi-schema/doc-invalid-end2.err b/tests/qapi-schema/doc-invalid-end2.err new file mode 100644 index 0000000000..6fad9c789e --- /dev/null +++ b/tests/qapi-schema/doc-invalid-end2.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-invalid-end2.json:5:1: Junk after '##' at end of documentation comment diff --git a/tests/qapi-schema/doc-invalid-end2.exit b/tests/qapi-schema/doc-invalid-end2.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-invalid-end2.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-invalid-end2.json b/tests/qapi-schema/doc-invalid-end2.json new file mode 100644 index 0000000000..fa2d39d7c2 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-end2.json @@ -0,0 +1,5 @@ +# Documentation must end with '##' + +## +# +## invalid diff --git a/tests/qapi-schema/doc-invalid-end2.out b/tests/qapi-schema/doc-invalid-end2.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-end2.out diff --git a/tests/qapi-schema/doc-invalid-return.err b/tests/qapi-schema/doc-invalid-return.err new file mode 100644 index 0000000000..5aaba33bb4 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-return.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-invalid-return.json:3: 'Returns:' is only valid for commands diff --git a/tests/qapi-schema/doc-invalid-return.exit b/tests/qapi-schema/doc-invalid-return.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-invalid-return.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-invalid-return.json b/tests/qapi-schema/doc-invalid-return.json new file mode 100644 index 0000000000..1ba45de414 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-return.json @@ -0,0 +1,7 @@ +# Events can't have 'Returns' section + +## +# @foo: +# Returns: blah +## +{ 'event': 'foo' } diff --git a/tests/qapi-schema/doc-invalid-return.out b/tests/qapi-schema/doc-invalid-return.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-return.out diff --git a/tests/qapi-schema/doc-invalid-section.err b/tests/qapi-schema/doc-invalid-section.err new file mode 100644 index 0000000000..85bb67b829 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-section.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-invalid-section.json:3: Free-form documentation block must not contain @NAME: sections diff --git a/tests/qapi-schema/doc-invalid-section.exit b/tests/qapi-schema/doc-invalid-section.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-invalid-section.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-invalid-section.json b/tests/qapi-schema/doc-invalid-section.json new file mode 100644 index 0000000000..0578b8ae25 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-section.json @@ -0,0 +1,6 @@ +# Free-form documentation doesn't have tagged-sections + +## +# freeform +# @note: foo +## diff --git a/tests/qapi-schema/doc-invalid-section.out b/tests/qapi-schema/doc-invalid-section.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-section.out diff --git a/tests/qapi-schema/doc-invalid-start.err b/tests/qapi-schema/doc-invalid-start.err new file mode 100644 index 0000000000..149af2bfac --- /dev/null +++ b/tests/qapi-schema/doc-invalid-start.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-invalid-start.json:3:1: Junk after '##' at start of documentation comment diff --git a/tests/qapi-schema/doc-invalid-start.exit b/tests/qapi-schema/doc-invalid-start.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-invalid-start.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-invalid-start.json b/tests/qapi-schema/doc-invalid-start.json new file mode 100644 index 0000000000..4f6c15a38c --- /dev/null +++ b/tests/qapi-schema/doc-invalid-start.json @@ -0,0 +1,5 @@ +# Documentation must start with '##' + +## invalid +# +## diff --git a/tests/qapi-schema/doc-invalid-start.out b/tests/qapi-schema/doc-invalid-start.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-invalid-start.out diff --git a/tests/qapi-schema/doc-missing-colon.err b/tests/qapi-schema/doc-missing-colon.err new file mode 100644 index 0000000000..817398b8e4 --- /dev/null +++ b/tests/qapi-schema/doc-missing-colon.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-missing-colon.json:4:1: Line should end with : diff --git a/tests/qapi-schema/doc-missing-colon.exit b/tests/qapi-schema/doc-missing-colon.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-missing-colon.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-missing-colon.json b/tests/qapi-schema/doc-missing-colon.json new file mode 100644 index 0000000000..d88c06c6dd --- /dev/null +++ b/tests/qapi-schema/doc-missing-colon.json @@ -0,0 +1,5 @@ +# The symbol section must end with ':' + +## +# @missing-colon +## diff --git a/tests/qapi-schema/doc-missing-colon.out b/tests/qapi-schema/doc-missing-colon.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-missing-colon.out diff --git a/tests/qapi-schema/doc-missing-expr.err b/tests/qapi-schema/doc-missing-expr.err new file mode 100644 index 0000000000..c0e687cadd --- /dev/null +++ b/tests/qapi-schema/doc-missing-expr.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-missing-expr.json:3: Documention for 'bar' is not followed by the definition diff --git a/tests/qapi-schema/doc-missing-expr.exit b/tests/qapi-schema/doc-missing-expr.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-missing-expr.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-missing-expr.json b/tests/qapi-schema/doc-missing-expr.json new file mode 100644 index 0000000000..06ad7df8d6 --- /dev/null +++ b/tests/qapi-schema/doc-missing-expr.json @@ -0,0 +1,5 @@ +# Expression documentation must be followed by the actual expression + +## +# @bar: +## diff --git a/tests/qapi-schema/doc-missing-expr.out b/tests/qapi-schema/doc-missing-expr.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-missing-expr.out diff --git a/tests/qapi-schema/doc-missing-space.err b/tests/qapi-schema/doc-missing-space.err new file mode 100644 index 0000000000..d6b46ffd77 --- /dev/null +++ b/tests/qapi-schema/doc-missing-space.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-missing-space.json:5:1: Missing space after # diff --git a/tests/qapi-schema/doc-missing-space.exit b/tests/qapi-schema/doc-missing-space.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-missing-space.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-missing-space.json b/tests/qapi-schema/doc-missing-space.json new file mode 100644 index 0000000000..beb276bc64 --- /dev/null +++ b/tests/qapi-schema/doc-missing-space.json @@ -0,0 +1,6 @@ +# Documentation line must have a leading space + +## +# missing space: +#wef +## diff --git a/tests/qapi-schema/doc-missing-space.out b/tests/qapi-schema/doc-missing-space.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-missing-space.out diff --git a/tests/qapi-schema/doc-optional.err b/tests/qapi-schema/doc-optional.err new file mode 100644 index 0000000000..20d405af79 --- /dev/null +++ b/tests/qapi-schema/doc-optional.err @@ -0,0 +1 @@ +tests/qapi-schema/doc-optional.json:3: Description has #optional, but the declaration doesn't diff --git a/tests/qapi-schema/doc-optional.exit b/tests/qapi-schema/doc-optional.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/doc-optional.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/doc-optional.json b/tests/qapi-schema/doc-optional.json new file mode 100644 index 0000000000..06c855ec94 --- /dev/null +++ b/tests/qapi-schema/doc-optional.json @@ -0,0 +1,7 @@ +# Description #optional should match declaration + +## +# @foo: +# @a: a #optional +## +{ 'command': 'foo', 'data': {'a': 'int'} } diff --git a/tests/qapi-schema/doc-optional.out b/tests/qapi-schema/doc-optional.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/doc-optional.out diff --git a/tests/qapi-schema/double-type.err b/tests/qapi-schema/double-type.err index f9613c6d6b..424df9bedd 100644 --- a/tests/qapi-schema/double-type.err +++ b/tests/qapi-schema/double-type.err @@ -1 +1 @@ -tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar' +tests/qapi-schema/double-type.json:6: Unknown key 'command' in struct 'bar' diff --git a/tests/qapi-schema/double-type.json b/tests/qapi-schema/double-type.json index 911fa7af50..ab59523ff7 100644 --- a/tests/qapi-schema/double-type.json +++ b/tests/qapi-schema/double-type.json @@ -1,2 +1,6 @@ # we reject an expression with ambiguous metatype + +## +# @foo: +## { 'command': 'foo', 'struct': 'bar', 'data': { } } diff --git a/tests/qapi-schema/enum-bad-name.err b/tests/qapi-schema/enum-bad-name.err index 9c3c1002b7..157d1b0d69 100644 --- a/tests/qapi-schema/enum-bad-name.err +++ b/tests/qapi-schema/enum-bad-name.err @@ -1 +1 @@ -tests/qapi-schema/enum-bad-name.json:2: Member of enum 'MyEnum' uses invalid name 'not^possible' +tests/qapi-schema/enum-bad-name.json:6: Member of enum 'MyEnum' uses invalid name 'not^possible' diff --git a/tests/qapi-schema/enum-bad-name.json b/tests/qapi-schema/enum-bad-name.json index 8506562b31..978cb88994 100644 --- a/tests/qapi-schema/enum-bad-name.json +++ b/tests/qapi-schema/enum-bad-name.json @@ -1,2 +1,6 @@ # we ensure all enum names can map to C + +## +# @MyEnum: +## { 'enum': 'MyEnum', 'data': [ 'not^possible' ] } diff --git a/tests/qapi-schema/enum-bad-prefix.err b/tests/qapi-schema/enum-bad-prefix.err index 399f5f7af5..918915f7ab 100644 --- a/tests/qapi-schema/enum-bad-prefix.err +++ b/tests/qapi-schema/enum-bad-prefix.err @@ -1 +1 @@ -tests/qapi-schema/enum-bad-prefix.json:2: Enum 'MyEnum' requires a string for 'prefix' +tests/qapi-schema/enum-bad-prefix.json:6: Enum 'MyEnum' requires a string for 'prefix' diff --git a/tests/qapi-schema/enum-bad-prefix.json b/tests/qapi-schema/enum-bad-prefix.json index 996f628f6d..25f17a7b08 100644 --- a/tests/qapi-schema/enum-bad-prefix.json +++ b/tests/qapi-schema/enum-bad-prefix.json @@ -1,2 +1,6 @@ # The prefix must be a string type + +## +# @MyEnum: +## { 'enum': 'MyEnum', 'data': [ 'one' ], 'prefix': [ 'fish' ] } diff --git a/tests/qapi-schema/enum-clash-member.err b/tests/qapi-schema/enum-clash-member.err index 5403c78507..25249b63c4 100644 --- a/tests/qapi-schema/enum-clash-member.err +++ b/tests/qapi-schema/enum-clash-member.err @@ -1 +1 @@ -tests/qapi-schema/enum-clash-member.json:2: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum) +tests/qapi-schema/enum-clash-member.json:6: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum) diff --git a/tests/qapi-schema/enum-clash-member.json b/tests/qapi-schema/enum-clash-member.json index b6928b8bfd..fd52751941 100644 --- a/tests/qapi-schema/enum-clash-member.json +++ b/tests/qapi-schema/enum-clash-member.json @@ -1,2 +1,6 @@ # we reject enums where members will clash when mapped to C enum + +## +# @MyEnum: +## { 'enum': 'MyEnum', 'data': [ 'one-two', 'one_two' ] } diff --git a/tests/qapi-schema/enum-dict-member.err b/tests/qapi-schema/enum-dict-member.err index 8ca146ea59..9b7d2f111d 100644 --- a/tests/qapi-schema/enum-dict-member.err +++ b/tests/qapi-schema/enum-dict-member.err @@ -1 +1 @@ -tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum' requires a string name +tests/qapi-schema/enum-dict-member.json:6: Member of enum 'MyEnum' requires a string name diff --git a/tests/qapi-schema/enum-dict-member.json b/tests/qapi-schema/enum-dict-member.json index 79672e0f09..69d30f0c1e 100644 --- a/tests/qapi-schema/enum-dict-member.json +++ b/tests/qapi-schema/enum-dict-member.json @@ -1,2 +1,6 @@ # we reject any enum member that is not a string + +## +# @MyEnum: +## { 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] } diff --git a/tests/qapi-schema/enum-member-case.err b/tests/qapi-schema/enum-member-case.err index b652e9aacc..df96e2205a 100644 --- a/tests/qapi-schema/enum-member-case.err +++ b/tests/qapi-schema/enum-member-case.err @@ -1 +1 @@ -tests/qapi-schema/enum-member-case.json:3: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase +tests/qapi-schema/enum-member-case.json:10: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase diff --git a/tests/qapi-schema/enum-member-case.json b/tests/qapi-schema/enum-member-case.json index 2096b350ca..d2e4aba39d 100644 --- a/tests/qapi-schema/enum-member-case.json +++ b/tests/qapi-schema/enum-member-case.json @@ -1,3 +1,10 @@ # Member names should be 'lower-case' unless the enum is whitelisted + +## +# @UuidInfo: +## { 'enum': 'UuidInfo', 'data': [ 'Value' ] } # UuidInfo is whitelisted +## +# @NoWayThisWillGetWhitelisted: +## { 'enum': 'NoWayThisWillGetWhitelisted', 'data': [ 'Value' ] } diff --git a/tests/qapi-schema/enum-missing-data.err b/tests/qapi-schema/enum-missing-data.err index ba4873ae69..de4b9e8281 100644 --- a/tests/qapi-schema/enum-missing-data.err +++ b/tests/qapi-schema/enum-missing-data.err @@ -1 +1 @@ -tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from enum 'MyEnum' +tests/qapi-schema/enum-missing-data.json:6: Key 'data' is missing from enum 'MyEnum' diff --git a/tests/qapi-schema/enum-missing-data.json b/tests/qapi-schema/enum-missing-data.json index 558fd35e93..d7601f91fb 100644 --- a/tests/qapi-schema/enum-missing-data.json +++ b/tests/qapi-schema/enum-missing-data.json @@ -1,2 +1,6 @@ # we require that all QAPI enums have a data array + +## +# @MyEnum: +## { 'enum': 'MyEnum' } diff --git a/tests/qapi-schema/enum-wrong-data.err b/tests/qapi-schema/enum-wrong-data.err index 11b43471cf..c44e9b59dc 100644 --- a/tests/qapi-schema/enum-wrong-data.err +++ b/tests/qapi-schema/enum-wrong-data.err @@ -1 +1 @@ -tests/qapi-schema/enum-wrong-data.json:2: Enum 'MyEnum' requires an array for 'data' +tests/qapi-schema/enum-wrong-data.json:6: Enum 'MyEnum' requires an array for 'data' diff --git a/tests/qapi-schema/enum-wrong-data.json b/tests/qapi-schema/enum-wrong-data.json index 7b3e255c14..4b9e97878b 100644 --- a/tests/qapi-schema/enum-wrong-data.json +++ b/tests/qapi-schema/enum-wrong-data.json @@ -1,2 +1,6 @@ # we require that all qapi enums have an array for data + +## +# @MyEnum: +## { 'enum': 'MyEnum', 'data': { 'value': 'str' } } diff --git a/tests/qapi-schema/event-boxed-empty.err b/tests/qapi-schema/event-boxed-empty.err index 68ec6f2d2b..defe656e32 100644 --- a/tests/qapi-schema/event-boxed-empty.err +++ b/tests/qapi-schema/event-boxed-empty.err @@ -1 +1 @@ -tests/qapi-schema/event-boxed-empty.json:2: Use of 'boxed' requires 'data' +tests/qapi-schema/event-boxed-empty.json:6: Use of 'boxed' requires 'data' diff --git a/tests/qapi-schema/event-boxed-empty.json b/tests/qapi-schema/event-boxed-empty.json index cb145f1433..63b870b31b 100644 --- a/tests/qapi-schema/event-boxed-empty.json +++ b/tests/qapi-schema/event-boxed-empty.json @@ -1,2 +1,6 @@ # 'boxed' requires a non-empty type + +## +# @FOO: +## { 'event': 'FOO', 'boxed': true } diff --git a/tests/qapi-schema/event-case.json b/tests/qapi-schema/event-case.json index 3a92d8b610..6b05c5d247 100644 --- a/tests/qapi-schema/event-case.json +++ b/tests/qapi-schema/event-case.json @@ -1,3 +1,7 @@ # TODO: might be nice to enforce naming conventions; but until then this works # even though events should usually be ALL_CAPS + +## +# @oops: +## { 'event': 'oops' } diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out index 5a0f2bf805..2865714ad5 100644 --- a/tests/qapi-schema/event-case.out +++ b/tests/qapi-schema/event-case.out @@ -3,3 +3,4 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo event oops None boxed=False object q_empty +doc symbol=oops expr=('event', 'oops') diff --git a/tests/qapi-schema/event-nest-struct.err b/tests/qapi-schema/event-nest-struct.err index 5a42701b8f..17a6c3c7b9 100644 --- a/tests/qapi-schema/event-nest-struct.err +++ b/tests/qapi-schema/event-nest-struct.err @@ -1 +1 @@ -tests/qapi-schema/event-nest-struct.json:1: Member 'a' of 'data' for event 'EVENT_A' should be a type name +tests/qapi-schema/event-nest-struct.json:5: Member 'a' of 'data' for event 'EVENT_A' should be a type name diff --git a/tests/qapi-schema/event-nest-struct.json b/tests/qapi-schema/event-nest-struct.json index ee6f3ecb6f..328e0a64d3 100644 --- a/tests/qapi-schema/event-nest-struct.json +++ b/tests/qapi-schema/event-nest-struct.json @@ -1,2 +1,6 @@ +## +# @EVENT_A: +# event-nest-struct +## { 'event': 'EVENT_A', 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } } diff --git a/tests/qapi-schema/flat-union-array-branch.err b/tests/qapi-schema/flat-union-array-branch.err index 8ea91eadb2..e456094993 100644 --- a/tests/qapi-schema/flat-union-array-branch.err +++ b/tests/qapi-schema/flat-union-array-branch.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-array-branch.json:8: Member 'value1' of union 'TestUnion' cannot be an array +tests/qapi-schema/flat-union-array-branch.json:20: Member 'value1' of union 'TestUnion' cannot be an array diff --git a/tests/qapi-schema/flat-union-array-branch.json b/tests/qapi-schema/flat-union-array-branch.json index 0b98820a8f..51dde10392 100644 --- a/tests/qapi-schema/flat-union-array-branch.json +++ b/tests/qapi-schema/flat-union-array-branch.json @@ -1,10 +1,22 @@ +## +# @TestEnum: +## # we require flat union branches to be a struct { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @Base: +## { 'struct': 'Base', 'data': { 'enum1': 'TestEnum' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'Base', 'discriminator': 'enum1', diff --git a/tests/qapi-schema/flat-union-bad-base.err b/tests/qapi-schema/flat-union-bad-base.err index bee24a217a..072ffbaadd 100644 --- a/tests/qapi-schema/flat-union-bad-base.err +++ b/tests/qapi-schema/flat-union-bad-base.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-bad-base.json:8: 'string' (member of TestTypeA) collides with 'string' (base of TestUnion) +tests/qapi-schema/flat-union-bad-base.json:21: 'string' (member of TestTypeA) collides with 'string' (base of TestUnion) diff --git a/tests/qapi-schema/flat-union-bad-base.json b/tests/qapi-schema/flat-union-bad-base.json index 74dd421708..7713e7f0ad 100644 --- a/tests/qapi-schema/flat-union-bad-base.json +++ b/tests/qapi-schema/flat-union-bad-base.json @@ -1,10 +1,23 @@ # we allow anonymous base, but enforce no duplicate keys + +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': { 'enum1': 'TestEnum', 'string': 'str' }, 'discriminator': 'enum1', diff --git a/tests/qapi-schema/flat-union-bad-discriminator.err b/tests/qapi-schema/flat-union-bad-discriminator.err index c38cc8e4df..1be4e7b23a 100644 --- a/tests/qapi-schema/flat-union-bad-discriminator.err +++ b/tests/qapi-schema/flat-union-bad-discriminator.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-bad-discriminator.json:11: Discriminator of flat union 'TestUnion' requires a string name +tests/qapi-schema/flat-union-bad-discriminator.json:27: Discriminator of flat union 'TestUnion' requires a string name diff --git a/tests/qapi-schema/flat-union-bad-discriminator.json b/tests/qapi-schema/flat-union-bad-discriminator.json index cd10b9d901..ef92f9b583 100644 --- a/tests/qapi-schema/flat-union-bad-discriminator.json +++ b/tests/qapi-schema/flat-union-bad-discriminator.json @@ -1,13 +1,29 @@ # we require the discriminator to be a string naming a base-type member # this tests the old syntax for anonymous unions before we added alternates + +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @TestBase: +## { 'struct': 'TestBase', 'data': { 'enum1': 'TestEnum', 'kind': 'str' } } +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'TestBase', 'discriminator': {}, diff --git a/tests/qapi-schema/flat-union-base-any.err b/tests/qapi-schema/flat-union-base-any.err index 646f1c9cd1..c1ea2d76b3 100644 --- a/tests/qapi-schema/flat-union-base-any.err +++ b/tests/qapi-schema/flat-union-base-any.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-base-any.json:8: 'base' for union 'TestUnion' cannot use built-in type 'any' +tests/qapi-schema/flat-union-base-any.json:21: 'base' for union 'TestUnion' cannot use built-in type 'any' diff --git a/tests/qapi-schema/flat-union-base-any.json b/tests/qapi-schema/flat-union-base-any.json index fe66b713ef..3dfb02fa30 100644 --- a/tests/qapi-schema/flat-union-base-any.json +++ b/tests/qapi-schema/flat-union-base-any.json @@ -1,10 +1,23 @@ # we require the base to be an existing struct + +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'any', 'discriminator': 'enum1', diff --git a/tests/qapi-schema/flat-union-base-union.err b/tests/qapi-schema/flat-union-base-union.err index f138395e45..ccc5e85876 100644 --- a/tests/qapi-schema/flat-union-base-union.err +++ b/tests/qapi-schema/flat-union-base-union.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-base-union.json:14: 'base' for union 'TestUnion' cannot use union type 'UnionBase' +tests/qapi-schema/flat-union-base-union.json:30: 'base' for union 'TestUnion' cannot use union type 'UnionBase' diff --git a/tests/qapi-schema/flat-union-base-union.json b/tests/qapi-schema/flat-union-base-union.json index 98b4eba181..c63c6130b8 100644 --- a/tests/qapi-schema/flat-union-base-union.json +++ b/tests/qapi-schema/flat-union-base-union.json @@ -2,15 +2,31 @@ # TODO: It would be possible to allow a union as a base, as long as all # permutations of QMP names exposed by base do not clash with any QMP # member names added by local variants. + +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @UnionBase: +## { 'union': 'UnionBase', 'data': { 'kind1': 'TestTypeA', 'kind2': 'TestTypeB' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'UnionBase', 'discriminator': 'type', diff --git a/tests/qapi-schema/flat-union-clash-member.err b/tests/qapi-schema/flat-union-clash-member.err index 2adf69755a..fe12a07e2d 100644 --- a/tests/qapi-schema/flat-union-clash-member.err +++ b/tests/qapi-schema/flat-union-clash-member.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-clash-member.json:11: 'name' (member of Branch1) collides with 'name' (member of Base) +tests/qapi-schema/flat-union-clash-member.json:27: 'name' (member of Branch1) collides with 'name' (member of Base) diff --git a/tests/qapi-schema/flat-union-clash-member.json b/tests/qapi-schema/flat-union-clash-member.json index 9efc7719b8..9000b94f16 100644 --- a/tests/qapi-schema/flat-union-clash-member.json +++ b/tests/qapi-schema/flat-union-clash-member.json @@ -1,13 +1,29 @@ # We check for no duplicate keys between branch members and base # base's member 'name' clashes with Branch1's + +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @Base: +## { 'struct': 'Base', 'data': { 'enum1': 'TestEnum', '*name': 'str' } } +## +# @Branch1: +## { 'struct': 'Branch1', 'data': { 'name': 'str' } } +## +# @Branch2: +## { 'struct': 'Branch2', 'data': { 'value': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'Base', 'discriminator': 'enum1', diff --git a/tests/qapi-schema/flat-union-empty.err b/tests/qapi-schema/flat-union-empty.err index 15754f54eb..ead7bd4fcb 100644 --- a/tests/qapi-schema/flat-union-empty.err +++ b/tests/qapi-schema/flat-union-empty.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data' +tests/qapi-schema/flat-union-empty.json:14: Union 'Union' cannot have empty 'data' diff --git a/tests/qapi-schema/flat-union-empty.json b/tests/qapi-schema/flat-union-empty.json index 77f1d9abfb..afa8988205 100644 --- a/tests/qapi-schema/flat-union-empty.json +++ b/tests/qapi-schema/flat-union-empty.json @@ -1,4 +1,14 @@ # flat unions cannot be empty + +## +# @Empty: +## { 'enum': 'Empty', 'data': [ ] } +## +# @Base: +## { 'struct': 'Base', 'data': { 'type': 'Empty' } } +## +# @Union: +## { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } } diff --git a/tests/qapi-schema/flat-union-incomplete-branch.err b/tests/qapi-schema/flat-union-incomplete-branch.err index e826bf0789..c655bbfb4a 100644 --- a/tests/qapi-schema/flat-union-incomplete-branch.err +++ b/tests/qapi-schema/flat-union-incomplete-branch.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-incomplete-branch.json:6: Union 'TestUnion' data missing 'value2' branch +tests/qapi-schema/flat-union-incomplete-branch.json:16: Union 'TestUnion' data missing 'value2' branch diff --git a/tests/qapi-schema/flat-union-incomplete-branch.json b/tests/qapi-schema/flat-union-incomplete-branch.json index 25a411bc83..dea03775c7 100644 --- a/tests/qapi-schema/flat-union-incomplete-branch.json +++ b/tests/qapi-schema/flat-union-incomplete-branch.json @@ -1,8 +1,18 @@ # we require all branches of the union to be covered + +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': { 'type': 'TestEnum' }, 'discriminator': 'type', diff --git a/tests/qapi-schema/flat-union-inline.err b/tests/qapi-schema/flat-union-inline.err index 2333358d28..c2c3f7604b 100644 --- a/tests/qapi-schema/flat-union-inline.err +++ b/tests/qapi-schema/flat-union-inline.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-inline.json:7: Member 'value1' of union 'TestUnion' should be a type name +tests/qapi-schema/flat-union-inline.json:17: Member 'value1' of union 'TestUnion' should be a type name diff --git a/tests/qapi-schema/flat-union-inline.json b/tests/qapi-schema/flat-union-inline.json index 62c7cda617..400f0817a1 100644 --- a/tests/qapi-schema/flat-union-inline.json +++ b/tests/qapi-schema/flat-union-inline.json @@ -1,9 +1,19 @@ # we require branches to be a struct name # TODO: should we allow anonymous inline branch types? + +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @Base: +## { 'struct': 'Base', 'data': { 'enum1': 'TestEnum', 'kind': 'str' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'Base', 'discriminator': 'enum1', diff --git a/tests/qapi-schema/flat-union-int-branch.err b/tests/qapi-schema/flat-union-int-branch.err index faf01573b7..299cbb24b2 100644 --- a/tests/qapi-schema/flat-union-int-branch.err +++ b/tests/qapi-schema/flat-union-int-branch.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-int-branch.json:8: Member 'value1' of union 'TestUnion' cannot use built-in type 'int' +tests/qapi-schema/flat-union-int-branch.json:21: Member 'value1' of union 'TestUnion' cannot use built-in type 'int' diff --git a/tests/qapi-schema/flat-union-int-branch.json b/tests/qapi-schema/flat-union-int-branch.json index 9370c349e8..9603e172f8 100644 --- a/tests/qapi-schema/flat-union-int-branch.json +++ b/tests/qapi-schema/flat-union-int-branch.json @@ -1,10 +1,23 @@ # we require flat union branches to be a struct + +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @Base: +## { 'struct': 'Base', 'data': { 'enum1': 'TestEnum' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'Base', 'discriminator': 'enum1', diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err index ccf72d2dfe..455f2dc083 100644 --- a/tests/qapi-schema/flat-union-invalid-branch-key.err +++ b/tests/qapi-schema/flat-union-invalid-branch-key.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-invalid-branch-key.json:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum' +tests/qapi-schema/flat-union-invalid-branch-key.json:28: Discriminator value 'value_wrong' is not found in enum 'TestEnum' diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.json b/tests/qapi-schema/flat-union-invalid-branch-key.json index 95ff7746bf..00f28966ff 100644 --- a/tests/qapi-schema/flat-union-invalid-branch-key.json +++ b/tests/qapi-schema/flat-union-invalid-branch-key.json @@ -1,15 +1,30 @@ +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @TestBase: +## { 'struct': 'TestBase', 'data': { 'enum1': 'TestEnum' } } +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'TestBase', 'discriminator': 'enum1', diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err index 5f4055614e..f0e427b0a7 100644 --- a/tests/qapi-schema/flat-union-invalid-discriminator.err +++ b/tests/qapi-schema/flat-union-invalid-discriminator.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-invalid-discriminator.json:13: Discriminator 'enum_wrong' is not a member of base struct 'TestBase' +tests/qapi-schema/flat-union-invalid-discriminator.json:28: Discriminator 'enum_wrong' is not a member of base struct 'TestBase' diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.json b/tests/qapi-schema/flat-union-invalid-discriminator.json index 48b94c3a4d..c8700c7d71 100644 --- a/tests/qapi-schema/flat-union-invalid-discriminator.json +++ b/tests/qapi-schema/flat-union-invalid-discriminator.json @@ -1,15 +1,30 @@ +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @TestBase: +## { 'struct': 'TestBase', 'data': { 'enum1': 'TestEnum' } } +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'TestBase', 'discriminator': 'enum_wrong', diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err index 841c93b554..a2d0a81aa0 100644 --- a/tests/qapi-schema/flat-union-no-base.err +++ b/tests/qapi-schema/flat-union-no-base.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-no-base.json:9: Flat union 'TestUnion' must have a base +tests/qapi-schema/flat-union-no-base.json:22: Flat union 'TestUnion' must have a base diff --git a/tests/qapi-schema/flat-union-no-base.json b/tests/qapi-schema/flat-union-no-base.json index ffc4c6f0e6..641f68aea4 100644 --- a/tests/qapi-schema/flat-union-no-base.json +++ b/tests/qapi-schema/flat-union-no-base.json @@ -1,11 +1,24 @@ # flat unions require a base # TODO: simple unions should be able to use an enum discriminator + +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @Enum: +## { 'enum': 'Enum', 'data': [ 'value1', 'value2' ] } +## +# @TestUnion: +## { 'union': 'TestUnion', 'discriminator': 'Enum', 'data': { 'value1': 'TestTypeA', diff --git a/tests/qapi-schema/flat-union-optional-discriminator.err b/tests/qapi-schema/flat-union-optional-discriminator.err index aaabedb3bd..e15f8564dd 100644 --- a/tests/qapi-schema/flat-union-optional-discriminator.err +++ b/tests/qapi-schema/flat-union-optional-discriminator.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-optional-discriminator.json:6: Discriminator of flat union 'MyUnion' does not allow optional name '*switch' +tests/qapi-schema/flat-union-optional-discriminator.json:19: Discriminator of flat union 'MyUnion' does not allow optional name '*switch' diff --git a/tests/qapi-schema/flat-union-optional-discriminator.json b/tests/qapi-schema/flat-union-optional-discriminator.json index 08a8f7ef8b..9f19af5789 100644 --- a/tests/qapi-schema/flat-union-optional-discriminator.json +++ b/tests/qapi-schema/flat-union-optional-discriminator.json @@ -1,8 +1,21 @@ # we require the discriminator to be non-optional + +## +# @Enum: +## { 'enum': 'Enum', 'data': [ 'one', 'two' ] } +## +# @Base: +## { 'struct': 'Base', 'data': { '*switch': 'Enum' } } +## +# @Branch: +## { 'struct': 'Branch', 'data': { 'name': 'str' } } +## +# @MyUnion: +## { 'union': 'MyUnion', 'base': 'Base', 'discriminator': '*switch', diff --git a/tests/qapi-schema/flat-union-string-discriminator.err b/tests/qapi-schema/flat-union-string-discriminator.err index 200016bd5c..bc0c133aa9 100644 --- a/tests/qapi-schema/flat-union-string-discriminator.err +++ b/tests/qapi-schema/flat-union-string-discriminator.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-string-discriminator.json:13: Discriminator 'kind' must be of enumeration type +tests/qapi-schema/flat-union-string-discriminator.json:28: Discriminator 'kind' must be of enumeration type diff --git a/tests/qapi-schema/flat-union-string-discriminator.json b/tests/qapi-schema/flat-union-string-discriminator.json index 8af60333b6..47a17d2e4a 100644 --- a/tests/qapi-schema/flat-union-string-discriminator.json +++ b/tests/qapi-schema/flat-union-string-discriminator.json @@ -1,15 +1,30 @@ +## +# @TestEnum: +## { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } +## +# @TestBase: +## { 'struct': 'TestBase', 'data': { 'enum1': 'TestEnum', 'kind': 'str' } } +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'TestBase', 'discriminator': 'kind', diff --git a/tests/qapi-schema/ident-with-escape.json b/tests/qapi-schema/ident-with-escape.json index 56617501e7..c03404bee3 100644 --- a/tests/qapi-schema/ident-with-escape.json +++ b/tests/qapi-schema/ident-with-escape.json @@ -1,4 +1,8 @@ # we allow escape sequences in strings, if they map back to ASCII # { 'command': 'fooA', 'data': { 'bar1': 'str' } } + +## +# @fooA: +## { 'c\u006fmmand': '\u0066\u006f\u006FA', 'd\u0061ta': { '\u0062\u0061\u00721': '\u0073\u0074\u0072' } } diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out index 1d2722c02e..69fc908e68 100644 --- a/tests/qapi-schema/ident-with-escape.out +++ b/tests/qapi-schema/ident-with-escape.out @@ -5,3 +5,4 @@ command fooA q_obj_fooA-arg -> None object q_empty object q_obj_fooA-arg member bar1: str optional=False +doc symbol=fooA expr=('command', 'fooA') diff --git a/tests/qapi-schema/include-relpath-sub.json b/tests/qapi-schema/include-relpath-sub.json index 4bd4af4162..b4bd8a23d7 100644 --- a/tests/qapi-schema/include-relpath-sub.json +++ b/tests/qapi-schema/include-relpath-sub.json @@ -1,2 +1,5 @@ +## +# @Status: +## { 'enum': 'Status', 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out index 5d7c13cad1..a962fb2d2e 100644 --- a/tests/qapi-schema/include-relpath.out +++ b/tests/qapi-schema/include-relpath.out @@ -2,3 +2,4 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo prefix QTYPE enum Status ['good', 'bad', 'ugly'] object q_empty +doc symbol=Status expr=('enum', 'Status') diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out index 5d7c13cad1..a962fb2d2e 100644 --- a/tests/qapi-schema/include-repetition.out +++ b/tests/qapi-schema/include-repetition.out @@ -2,3 +2,4 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo prefix QTYPE enum Status ['good', 'bad', 'ugly'] object q_empty +doc symbol=Status expr=('enum', 'Status') diff --git a/tests/qapi-schema/include-simple-sub.json b/tests/qapi-schema/include-simple-sub.json index 4bd4af4162..b4bd8a23d7 100644 --- a/tests/qapi-schema/include-simple-sub.json +++ b/tests/qapi-schema/include-simple-sub.json @@ -1,2 +1,5 @@ +## +# @Status: +## { 'enum': 'Status', 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out index 5d7c13cad1..a962fb2d2e 100644 --- a/tests/qapi-schema/include-simple.out +++ b/tests/qapi-schema/include-simple.out @@ -2,3 +2,4 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo prefix QTYPE enum Status ['good', 'bad', 'ugly'] object q_empty +doc symbol=Status expr=('enum', 'Status') diff --git a/tests/qapi-schema/indented-expr.json b/tests/qapi-schema/indented-expr.json index 7115d3131e..d759be1877 100644 --- a/tests/qapi-schema/indented-expr.json +++ b/tests/qapi-schema/indented-expr.json @@ -1,2 +1,8 @@ +## +# @eins: +## { 'command' : 'eins' } +## +# @zwei: +## { 'command' : 'zwei' } diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out index e8171c935f..285d052257 100644 --- a/tests/qapi-schema/indented-expr.out +++ b/tests/qapi-schema/indented-expr.out @@ -5,3 +5,5 @@ command eins None -> None object q_empty command zwei None -> None gen=True success_response=True boxed=False +doc symbol=eins expr=('command', 'eins') +doc symbol=zwei expr=('command', 'zwei') diff --git a/tests/qapi-schema/missing-type.err b/tests/qapi-schema/missing-type.err index b3e7b14e42..74c4ef7324 100644 --- a/tests/qapi-schema/missing-type.err +++ b/tests/qapi-schema/missing-type.err @@ -1 +1 @@ -tests/qapi-schema/missing-type.json:2: Expression is missing metatype +tests/qapi-schema/missing-type.json:6: Expression is missing metatype diff --git a/tests/qapi-schema/missing-type.json b/tests/qapi-schema/missing-type.json index ff5349d3fe..c2fc62d0af 100644 --- a/tests/qapi-schema/missing-type.json +++ b/tests/qapi-schema/missing-type.json @@ -1,2 +1,6 @@ # we reject an expression with missing metatype + +## +# @foo: +## { 'data': { } } diff --git a/tests/qapi-schema/nested-struct-data.err b/tests/qapi-schema/nested-struct-data.err index da767bade2..379bd1d3f4 100644 --- a/tests/qapi-schema/nested-struct-data.err +++ b/tests/qapi-schema/nested-struct-data.err @@ -1 +1 @@ -tests/qapi-schema/nested-struct-data.json:2: Member 'a' of 'data' for command 'foo' should be a type name +tests/qapi-schema/nested-struct-data.json:6: Member 'a' of 'data' for command 'foo' should be a type name diff --git a/tests/qapi-schema/nested-struct-data.json b/tests/qapi-schema/nested-struct-data.json index efbe773ded..6106e15e86 100644 --- a/tests/qapi-schema/nested-struct-data.json +++ b/tests/qapi-schema/nested-struct-data.json @@ -1,3 +1,7 @@ # inline subtypes collide with our desired future use of defaults + +## +# @foo: +## { 'command': 'foo', 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } } diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 17194637ba..f4d8cc4230 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -3,67 +3,153 @@ # This file is a stress test of supported qapi constructs that must # parse and compile correctly. +## +# = Section +# == subsection +# +# Some text foo with *strong* and _emphasis_ +# 1. with a list +# 2. like that @foo +# +# And some code: +# | $ echo foo +# | -> do this +# | <- get that +# +# Note: is not a meta +## + +## +# @TestStruct: +# +# body with @var +# +# @integer: foo +# blah +# +# bao +# +# @boolean: bar +# @string: baz +# +# Example: +# +# -> { "execute": ... } +# <- { "return": ... } +# +# Since: 2.3 +# Note: a note +# +## { 'struct': 'TestStruct', 'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } } +## +# @NestedEnumsOne: # for testing enums +## { 'struct': 'NestedEnumsOne', 'data': { 'enum1': 'EnumOne', # Intentional forward reference '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } } +## +# @MyEnum: # An empty enum, although unusual, is currently acceptable +## { 'enum': 'MyEnum', 'data': [ ] } +## +# @Empty1: # Likewise for an empty struct, including an empty base +## { 'struct': 'Empty1', 'data': { } } +## +# @Empty2: +## { 'struct': 'Empty2', 'base': 'Empty1', 'data': { } } +## +# @user_def_cmd0: +## { 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' } +## +# @QEnumTwo: # for testing override of default naming heuristic +## { 'enum': 'QEnumTwo', 'prefix': 'QENUM_TWO', 'data': [ 'value1', 'value2' ] } +## +# @UserDefOne: # for testing nested structs +## { 'struct': 'UserDefOne', 'base': 'UserDefZero', # intentional forward reference 'data': { 'string': 'str', '*enum1': 'EnumOne' } } # intentional forward reference +## +# @EnumOne: +## { 'enum': 'EnumOne', 'data': [ 'value1', 'value2', 'value3' ] } +## +# @UserDefZero: +## { 'struct': 'UserDefZero', 'data': { 'integer': 'int' } } +## +# @UserDefTwoDictDict: +## { 'struct': 'UserDefTwoDictDict', 'data': { 'userdef': 'UserDefOne', 'string': 'str' } } +## +# @UserDefTwoDict: +## { 'struct': 'UserDefTwoDict', 'data': { 'string1': 'str', 'dict2': 'UserDefTwoDictDict', '*dict3': 'UserDefTwoDictDict' } } +## +# @UserDefTwo: +## { 'struct': 'UserDefTwo', 'data': { 'string0': 'str', 'dict1': 'UserDefTwoDict' } } +## +# @ForceArrays: # dummy struct to force generation of array types not otherwise mentioned +## { 'struct': 'ForceArrays', 'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'], 'unused3':['TestStruct'] } } +## +# @UserDefA: # for testing unions # Among other things, test that a name collision between branches does # not cause any problems (since only one branch can be in use at a time), # by intentionally using two branches that both have a C member 'a_b' +## { 'struct': 'UserDefA', 'data': { 'boolean': 'bool', '*a_b': 'int' } } +## +# @UserDefB: +## { 'struct': 'UserDefB', 'data': { 'intb': 'int', '*a-b': 'bool' } } +## +# @UserDefFlatUnion: +## { 'union': 'UserDefFlatUnion', 'base': 'UserDefUnionBase', # intentional forward reference 'discriminator': 'enum1', @@ -71,35 +157,71 @@ 'value2' : 'UserDefB', 'value3' : 'UserDefB' } } +## +# @UserDefUnionBase: +## { 'struct': 'UserDefUnionBase', 'base': 'UserDefZero', 'data': { 'string': 'str', 'enum1': 'EnumOne' } } +## +# @UserDefFlatUnion2: # this variant of UserDefFlatUnion defaults to a union that uses members with # allocated types to test corner cases in the cleanup/dealloc visitor +## { 'union': 'UserDefFlatUnion2', 'base': { '*integer': 'int', 'string': 'str', 'enum1': 'QEnumTwo' }, 'discriminator': 'enum1', 'data': { 'value1' : 'UserDefC', # intentional forward reference 'value2' : 'UserDefB' } } +## +# @WrapAlternate: +## { 'struct': 'WrapAlternate', 'data': { 'alt': 'UserDefAlternate' } } +## +# @UserDefAlternate: +## { 'alternate': 'UserDefAlternate', 'data': { 'udfu': 'UserDefFlatUnion', 's': 'str', 'i': 'int' } } +## +# @UserDefC: +## { 'struct': 'UserDefC', 'data': { 'string1': 'str', 'string2': 'str' } } # for testing use of 'number' within alternates +## +# @AltStrBool: +## { 'alternate': 'AltStrBool', 'data': { 's': 'str', 'b': 'bool' } } +## +# @AltStrNum: +## { 'alternate': 'AltStrNum', 'data': { 's': 'str', 'n': 'number' } } +## +# @AltNumStr: +## { 'alternate': 'AltNumStr', 'data': { 'n': 'number', 's': 'str' } } +## +# @AltStrInt: +## { 'alternate': 'AltStrInt', 'data': { 's': 'str', 'i': 'int' } } +## +# @AltIntNum: +## { 'alternate': 'AltIntNum', 'data': { 'i': 'int', 'n': 'number' } } +## +# @AltNumInt: +## { 'alternate': 'AltNumInt', 'data': { 'n': 'number', 'i': 'int' } } +## +# @UserDefNativeListUnion: # for testing native lists +## { 'union': 'UserDefNativeListUnion', 'data': { 'integer': ['int'], 's8': ['int8'], @@ -117,19 +239,61 @@ 'any': ['any'] } } # testing commands +## +# @user_def_cmd: +## { 'command': 'user_def_cmd', 'data': {} } +## +# @user_def_cmd1: +## { 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} } +## +# @user_def_cmd2: +## { 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' } +## +# Another comment +## + +## +# @guest-get-time: +# +# @guest-get-time body +# +# @a: an integer +# @b: #optional integer +# +# Returns: returns something +# +# Example: +# +# -> { "execute": "guest-get-time", ... } +# <- { "return": "42" } +# +## + # Returning a non-dictionary requires a name from the whitelist { 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' }, 'returns': 'int' } +## +# @guest-sync: +## { 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' } +## +# @boxed-struct: +## { 'command': 'boxed-struct', 'boxed': true, 'data': 'UserDefZero' } +## +# @boxed-union: +## { 'command': 'boxed-union', 'data': 'UserDefNativeListUnion', 'boxed': true } +## +# @UserDefOptions: +# # For testing integer range flattening in opts-visitor. The following schema # corresponds to the option format: # @@ -137,6 +301,7 @@ # # For simplicity, this example doesn't use [type=]discriminator nor optargs # specific to discriminator values. +## { 'struct': 'UserDefOptions', 'data': { '*i64' : [ 'int' ], @@ -146,35 +311,83 @@ '*u64x': 'uint64' } } # testing event +## +# @EventStructOne: +## { 'struct': 'EventStructOne', 'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } } +## +# @EVENT_A: +## { 'event': 'EVENT_A' } +## +# @EVENT_B: +## { 'event': 'EVENT_B', 'data': { } } +## +# @EVENT_C: +## { 'event': 'EVENT_C', 'data': { '*a': 'int', '*b': 'UserDefOne', 'c': 'str' } } +## +# @EVENT_D: +## { 'event': 'EVENT_D', 'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } } +## +# @EVENT_E: +## { 'event': 'EVENT_E', 'boxed': true, 'data': 'UserDefZero' } +## +# @EVENT_F: +## { 'event': 'EVENT_F', 'boxed': true, 'data': 'UserDefAlternate' } # test that we correctly compile downstream extensions, as well as munge # ticklish names +## +# @__org.qemu_x-Enum: +## { 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] } +## +# @__org.qemu_x-Base: +## { 'struct': '__org.qemu_x-Base', 'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } } +## +# @__org.qemu_x-Struct: +## { 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base', 'data': { '__org.qemu_x-member2': 'str', '*wchar-t': 'int' } } +## +# @__org.qemu_x-Union1: +## { 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } } +## +# @__org.qemu_x-Struct2: +## { 'struct': '__org.qemu_x-Struct2', 'data': { 'array': ['__org.qemu_x-Union1'] } } +## +# @__org.qemu_x-Union2: +## { 'union': '__org.qemu_x-Union2', 'base': '__org.qemu_x-Base', 'discriminator': '__org.qemu_x-member1', 'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } } +## +# @__org.qemu_x-Alt: +## { 'alternate': '__org.qemu_x-Alt', 'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } } +## +# @__ORG.QEMU_X-EVENT: +## { 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' } +## +# @__org.qemu_x-command: +## { 'command': '__org.qemu_x-command', 'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'], 'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' }, diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 9d99c4eebb..bc8d496ff4 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -232,3 +232,133 @@ command user_def_cmd1 q_obj_user_def_cmd1-arg -> None gen=True success_response=True boxed=False command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo gen=True success_response=True boxed=False +doc freeform + body= += Section +== subsection + +Some text foo with *strong* and _emphasis_ +1. with a list +2. like that @foo + +And some code: +| $ echo foo +| -> do this +| <- get that + +Note: is not a meta +doc symbol=TestStruct expr=('struct', 'TestStruct') + arg=integer +foo +blah + +bao + arg=boolean +bar + arg=string +baz + section=Example +-> { "execute": ... } +<- { "return": ... } + section=Since +2.3 + section=Note +a note + body= +body with @var +doc symbol=NestedEnumsOne expr=('struct', 'NestedEnumsOne') + body= +for testing enums +doc symbol=MyEnum expr=('enum', 'MyEnum') + body= +An empty enum, although unusual, is currently acceptable +doc symbol=Empty1 expr=('struct', 'Empty1') + body= +Likewise for an empty struct, including an empty base +doc symbol=Empty2 expr=('struct', 'Empty2') +doc symbol=user_def_cmd0 expr=('command', 'user_def_cmd0') +doc symbol=QEnumTwo expr=('enum', 'QEnumTwo') + body= +for testing override of default naming heuristic +doc symbol=UserDefOne expr=('struct', 'UserDefOne') + body= +for testing nested structs +doc symbol=EnumOne expr=('enum', 'EnumOne') +doc symbol=UserDefZero expr=('struct', 'UserDefZero') +doc symbol=UserDefTwoDictDict expr=('struct', 'UserDefTwoDictDict') +doc symbol=UserDefTwoDict expr=('struct', 'UserDefTwoDict') +doc symbol=UserDefTwo expr=('struct', 'UserDefTwo') +doc symbol=ForceArrays expr=('struct', 'ForceArrays') + body= +dummy struct to force generation of array types not otherwise mentioned +doc symbol=UserDefA expr=('struct', 'UserDefA') + body= +for testing unions +Among other things, test that a name collision between branches does +not cause any problems (since only one branch can be in use at a time), +by intentionally using two branches that both have a C member 'a_b' +doc symbol=UserDefB expr=('struct', 'UserDefB') +doc symbol=UserDefFlatUnion expr=('union', 'UserDefFlatUnion') +doc symbol=UserDefUnionBase expr=('struct', 'UserDefUnionBase') +doc symbol=UserDefFlatUnion2 expr=('union', 'UserDefFlatUnion2') + body= +this variant of UserDefFlatUnion defaults to a union that uses members with +allocated types to test corner cases in the cleanup/dealloc visitor +doc symbol=WrapAlternate expr=('struct', 'WrapAlternate') +doc symbol=UserDefAlternate expr=('alternate', 'UserDefAlternate') +doc symbol=UserDefC expr=('struct', 'UserDefC') +doc symbol=AltStrBool expr=('alternate', 'AltStrBool') +doc symbol=AltStrNum expr=('alternate', 'AltStrNum') +doc symbol=AltNumStr expr=('alternate', 'AltNumStr') +doc symbol=AltStrInt expr=('alternate', 'AltStrInt') +doc symbol=AltIntNum expr=('alternate', 'AltIntNum') +doc symbol=AltNumInt expr=('alternate', 'AltNumInt') +doc symbol=UserDefNativeListUnion expr=('union', 'UserDefNativeListUnion') + body= +for testing native lists +doc symbol=user_def_cmd expr=('command', 'user_def_cmd') +doc symbol=user_def_cmd1 expr=('command', 'user_def_cmd1') +doc symbol=user_def_cmd2 expr=('command', 'user_def_cmd2') +doc freeform + body= +Another comment +doc symbol=guest-get-time expr=('command', 'guest-get-time') + arg=a +an integer + arg=b +#optional integer + section=Returns +returns something + section=Example +-> { "execute": "guest-get-time", ... } +<- { "return": "42" } + body= +@guest-get-time body +doc symbol=guest-sync expr=('command', 'guest-sync') +doc symbol=boxed-struct expr=('command', 'boxed-struct') +doc symbol=boxed-union expr=('command', 'boxed-union') +doc symbol=UserDefOptions expr=('struct', 'UserDefOptions') + body= +For testing integer range flattening in opts-visitor. The following schema +corresponds to the option format: + +-userdef i64=3-6,i64=-5--1,u64=2,u16=1,u16=7-12 + +For simplicity, this example doesn't use [type=]discriminator nor optargs +specific to discriminator values. +doc symbol=EventStructOne expr=('struct', 'EventStructOne') +doc symbol=EVENT_A expr=('event', 'EVENT_A') +doc symbol=EVENT_B expr=('event', 'EVENT_B') +doc symbol=EVENT_C expr=('event', 'EVENT_C') +doc symbol=EVENT_D expr=('event', 'EVENT_D') +doc symbol=EVENT_E expr=('event', 'EVENT_E') +doc symbol=EVENT_F expr=('event', 'EVENT_F') +doc symbol=__org.qemu_x-Enum expr=('enum', '__org.qemu_x-Enum') +doc symbol=__org.qemu_x-Base expr=('struct', '__org.qemu_x-Base') +doc symbol=__org.qemu_x-Struct expr=('struct', '__org.qemu_x-Struct') +doc symbol=__org.qemu_x-Union1 expr=('union', '__org.qemu_x-Union1') +doc symbol=__org.qemu_x-Struct2 expr=('struct', '__org.qemu_x-Struct2') +doc symbol=__org.qemu_x-Union2 expr=('union', '__org.qemu_x-Union2') +doc symbol=__org.qemu_x-Alt expr=('alternate', '__org.qemu_x-Alt') +doc symbol=__ORG.QEMU_X-EVENT expr=('event', '__ORG.QEMU_X-EVENT') +doc symbol=__org.qemu_x-command expr=('command', '__org.qemu_x-command') diff --git a/tests/qapi-schema/redefined-builtin.err b/tests/qapi-schema/redefined-builtin.err index b2757225c4..ee0a2adf0b 100644 --- a/tests/qapi-schema/redefined-builtin.err +++ b/tests/qapi-schema/redefined-builtin.err @@ -1 +1 @@ -tests/qapi-schema/redefined-builtin.json:2: built-in 'size' is already defined +tests/qapi-schema/redefined-builtin.json:6: built-in 'size' is already defined diff --git a/tests/qapi-schema/redefined-builtin.json b/tests/qapi-schema/redefined-builtin.json index 45b8a550ad..6d3a940d5e 100644 --- a/tests/qapi-schema/redefined-builtin.json +++ b/tests/qapi-schema/redefined-builtin.json @@ -1,2 +1,6 @@ # we reject types that duplicate builtin names + +## +# @size: +## { 'struct': 'size', 'data': { 'myint': 'size' } } diff --git a/tests/qapi-schema/redefined-command.err b/tests/qapi-schema/redefined-command.err index 82ae256e63..1e297c43ba 100644 --- a/tests/qapi-schema/redefined-command.err +++ b/tests/qapi-schema/redefined-command.err @@ -1 +1 @@ -tests/qapi-schema/redefined-command.json:3: command 'foo' is already defined +tests/qapi-schema/redefined-command.json:10: command 'foo' is already defined diff --git a/tests/qapi-schema/redefined-command.json b/tests/qapi-schema/redefined-command.json index 247e401948..3a8cb9024c 100644 --- a/tests/qapi-schema/redefined-command.json +++ b/tests/qapi-schema/redefined-command.json @@ -1,3 +1,10 @@ # we reject commands defined more than once + +## +# @foo: +## { 'command': 'foo', 'data': { 'one': 'str' } } +## +# @foo: +## { 'command': 'foo', 'data': { '*two': 'str' } } diff --git a/tests/qapi-schema/redefined-event.err b/tests/qapi-schema/redefined-event.err index 35429cb481..912c785119 100644 --- a/tests/qapi-schema/redefined-event.err +++ b/tests/qapi-schema/redefined-event.err @@ -1 +1 @@ -tests/qapi-schema/redefined-event.json:3: event 'EVENT_A' is already defined +tests/qapi-schema/redefined-event.json:10: event 'EVENT_A' is already defined diff --git a/tests/qapi-schema/redefined-event.json b/tests/qapi-schema/redefined-event.json index 7717e91c18..ec7aeea0f0 100644 --- a/tests/qapi-schema/redefined-event.json +++ b/tests/qapi-schema/redefined-event.json @@ -1,3 +1,10 @@ # we reject duplicate events + +## +# @EVENT_A: +## { 'event': 'EVENT_A', 'data': { 'myint': 'int' } } +## +# @EVENT_A: +## { 'event': 'EVENT_A', 'data': { 'myint': 'int' } } diff --git a/tests/qapi-schema/redefined-type.err b/tests/qapi-schema/redefined-type.err index 06ea78c478..28d87c098c 100644 --- a/tests/qapi-schema/redefined-type.err +++ b/tests/qapi-schema/redefined-type.err @@ -1 +1 @@ -tests/qapi-schema/redefined-type.json:3: struct 'foo' is already defined +tests/qapi-schema/redefined-type.json:10: struct 'foo' is already defined diff --git a/tests/qapi-schema/redefined-type.json b/tests/qapi-schema/redefined-type.json index a09e768bae..7a8f3e1ec8 100644 --- a/tests/qapi-schema/redefined-type.json +++ b/tests/qapi-schema/redefined-type.json @@ -1,3 +1,10 @@ # we reject types defined more than once + +## +# @foo: +## { 'struct': 'foo', 'data': { 'one': 'str' } } +## +# @foo: +## { 'enum': 'foo', 'data': [ 'two' ] } diff --git a/tests/qapi-schema/reserved-command-q.err b/tests/qapi-schema/reserved-command-q.err index f939e044eb..5e17f3169b 100644 --- a/tests/qapi-schema/reserved-command-q.err +++ b/tests/qapi-schema/reserved-command-q.err @@ -1 +1 @@ -tests/qapi-schema/reserved-command-q.json:5: 'command' uses invalid name 'q-unix' +tests/qapi-schema/reserved-command-q.json:12: 'command' uses invalid name 'q-unix' diff --git a/tests/qapi-schema/reserved-command-q.json b/tests/qapi-schema/reserved-command-q.json index 99f8aae314..bba0860c99 100644 --- a/tests/qapi-schema/reserved-command-q.json +++ b/tests/qapi-schema/reserved-command-q.json @@ -1,5 +1,12 @@ # C entity name collision # We reject names like 'q-unix', because they can collide with the mangled # name for 'unix' in generated C. + +## +# @unix: +## { 'command': 'unix' } +## +# @q-unix: +## { 'command': 'q-unix' } diff --git a/tests/qapi-schema/reserved-enum-q.err b/tests/qapi-schema/reserved-enum-q.err index e1c3480ee2..acb2df811d 100644 --- a/tests/qapi-schema/reserved-enum-q.err +++ b/tests/qapi-schema/reserved-enum-q.err @@ -1 +1 @@ -tests/qapi-schema/reserved-enum-q.json:4: Member of enum 'Foo' uses invalid name 'q-Unix' +tests/qapi-schema/reserved-enum-q.json:8: Member of enum 'Foo' uses invalid name 'q-Unix' diff --git a/tests/qapi-schema/reserved-enum-q.json b/tests/qapi-schema/reserved-enum-q.json index 3593a765ea..6c7e7177c3 100644 --- a/tests/qapi-schema/reserved-enum-q.json +++ b/tests/qapi-schema/reserved-enum-q.json @@ -1,4 +1,8 @@ # C entity name collision # We reject names like 'q-unix', because they can collide with the mangled # name for 'unix' in generated C. + +## +# @Foo: +## { 'enum': 'Foo', 'data': [ 'unix', 'q-Unix' ] } diff --git a/tests/qapi-schema/reserved-member-has.err b/tests/qapi-schema/reserved-member-has.err index e755771446..9ace796055 100644 --- a/tests/qapi-schema/reserved-member-has.err +++ b/tests/qapi-schema/reserved-member-has.err @@ -1 +1 @@ -tests/qapi-schema/reserved-member-has.json:5: Member of 'data' for command 'oops' uses reserved name 'has-a' +tests/qapi-schema/reserved-member-has.json:9: Member of 'data' for command 'oops' uses reserved name 'has-a' diff --git a/tests/qapi-schema/reserved-member-has.json b/tests/qapi-schema/reserved-member-has.json index 45b9109bdc..f0d8905ca2 100644 --- a/tests/qapi-schema/reserved-member-has.json +++ b/tests/qapi-schema/reserved-member-has.json @@ -2,4 +2,8 @@ # We reject names like 'has-a', because they can collide with the flag # for an optional 'a' in generated C. # TODO we could munge the optional flag name to avoid the collision. + +## +# @oops: +## { 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } } diff --git a/tests/qapi-schema/reserved-member-q.err b/tests/qapi-schema/reserved-member-q.err index f3d5dd7818..1709a88462 100644 --- a/tests/qapi-schema/reserved-member-q.err +++ b/tests/qapi-schema/reserved-member-q.err @@ -1 +1 @@ -tests/qapi-schema/reserved-member-q.json:4: Member of 'data' for struct 'Foo' uses invalid name 'q-unix' +tests/qapi-schema/reserved-member-q.json:8: Member of 'data' for struct 'Foo' uses invalid name 'q-unix' diff --git a/tests/qapi-schema/reserved-member-q.json b/tests/qapi-schema/reserved-member-q.json index 62fed8fddf..f51e312917 100644 --- a/tests/qapi-schema/reserved-member-q.json +++ b/tests/qapi-schema/reserved-member-q.json @@ -1,4 +1,8 @@ # C member name collision # We reject names like 'q-unix', because they can collide with the mangled # name for 'unix' in generated C. + +## +# @Foo: +## { 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } } diff --git a/tests/qapi-schema/reserved-member-u.err b/tests/qapi-schema/reserved-member-u.err index 87d42296cc..6ec69a712a 100644 --- a/tests/qapi-schema/reserved-member-u.err +++ b/tests/qapi-schema/reserved-member-u.err @@ -1 +1 @@ -tests/qapi-schema/reserved-member-u.json:7: Member of 'data' for struct 'Oops' uses reserved name 'u' +tests/qapi-schema/reserved-member-u.json:11: Member of 'data' for struct 'Oops' uses reserved name 'u' diff --git a/tests/qapi-schema/reserved-member-u.json b/tests/qapi-schema/reserved-member-u.json index 1eaf0f301c..3a578e5b56 100644 --- a/tests/qapi-schema/reserved-member-u.json +++ b/tests/qapi-schema/reserved-member-u.json @@ -4,4 +4,8 @@ # This is true even for non-unions, because it is possible to convert a # struct to flat union while remaining backwards compatible in QMP. # TODO - we could munge the member name to 'q_u' to avoid the collision + +## +# @Oops: +## { 'struct': 'Oops', 'data': { 'u': 'str' } } diff --git a/tests/qapi-schema/reserved-member-underscore.err b/tests/qapi-schema/reserved-member-underscore.err index 65ff0da8ce..c9aefee3a8 100644 --- a/tests/qapi-schema/reserved-member-underscore.err +++ b/tests/qapi-schema/reserved-member-underscore.err @@ -1 +1 @@ -tests/qapi-schema/reserved-member-underscore.json:4: Member of 'data' for struct 'Oops' uses invalid name '_oops' +tests/qapi-schema/reserved-member-underscore.json:8: Member of 'data' for struct 'Oops' uses invalid name '_oops' diff --git a/tests/qapi-schema/reserved-member-underscore.json b/tests/qapi-schema/reserved-member-underscore.json index 4a3a017638..cc34b54b02 100644 --- a/tests/qapi-schema/reserved-member-underscore.json +++ b/tests/qapi-schema/reserved-member-underscore.json @@ -1,4 +1,8 @@ # C member name collision # We reject use of a single leading underscore in all names (names must # begin with a letter or a downstream extension double-underscore prefix). + +## +# @Oops: +## { 'struct': 'Oops', 'data': { '_oops': 'str' } } diff --git a/tests/qapi-schema/reserved-type-kind.err b/tests/qapi-schema/reserved-type-kind.err index 0a38efaad8..8698073062 100644 --- a/tests/qapi-schema/reserved-type-kind.err +++ b/tests/qapi-schema/reserved-type-kind.err @@ -1 +1 @@ -tests/qapi-schema/reserved-type-kind.json:2: enum 'UnionKind' should not end in 'Kind' +tests/qapi-schema/reserved-type-kind.json:6: enum 'UnionKind' should not end in 'Kind' diff --git a/tests/qapi-schema/reserved-type-kind.json b/tests/qapi-schema/reserved-type-kind.json index 9ecaba12bc..a094941561 100644 --- a/tests/qapi-schema/reserved-type-kind.json +++ b/tests/qapi-schema/reserved-type-kind.json @@ -1,2 +1,6 @@ # we reject types that would conflict with implicit union enum + +## +# @UnionKind: +## { 'enum': 'UnionKind', 'data': [ 'oops' ] } diff --git a/tests/qapi-schema/reserved-type-list.err b/tests/qapi-schema/reserved-type-list.err index 4510fa6d90..ec0531c4b9 100644 --- a/tests/qapi-schema/reserved-type-list.err +++ b/tests/qapi-schema/reserved-type-list.err @@ -1 +1 @@ -tests/qapi-schema/reserved-type-list.json:5: struct 'FooList' should not end in 'List' +tests/qapi-schema/reserved-type-list.json:9: struct 'FooList' should not end in 'List' diff --git a/tests/qapi-schema/reserved-type-list.json b/tests/qapi-schema/reserved-type-list.json index 98d53bf808..6effb78e7f 100644 --- a/tests/qapi-schema/reserved-type-list.json +++ b/tests/qapi-schema/reserved-type-list.json @@ -2,4 +2,8 @@ # We reserve names ending in 'List' for use by array types. # TODO - we could choose array names to avoid collision with user types, # in order to let this compile + +## +# @FooList: +## { 'struct': 'FooList', 'data': { 's': 'str' } } diff --git a/tests/qapi-schema/returns-alternate.err b/tests/qapi-schema/returns-alternate.err index dfbb419cac..2b81623ca3 100644 --- a/tests/qapi-schema/returns-alternate.err +++ b/tests/qapi-schema/returns-alternate.err @@ -1 +1 @@ -tests/qapi-schema/returns-alternate.json:3: 'returns' for command 'oops' cannot use alternate type 'Alt' +tests/qapi-schema/returns-alternate.json:10: 'returns' for command 'oops' cannot use alternate type 'Alt' diff --git a/tests/qapi-schema/returns-alternate.json b/tests/qapi-schema/returns-alternate.json index 972390c06b..005bf2d148 100644 --- a/tests/qapi-schema/returns-alternate.json +++ b/tests/qapi-schema/returns-alternate.json @@ -1,3 +1,10 @@ # we reject returns if it is an alternate type + +## +# @Alt: +## { 'alternate': 'Alt', 'data': { 'a': 'int', 'b': 'str' } } +## +# @oops: +## { 'command': 'oops', 'returns': 'Alt' } diff --git a/tests/qapi-schema/returns-array-bad.err b/tests/qapi-schema/returns-array-bad.err index 138095ccde..b53bdb0ade 100644 --- a/tests/qapi-schema/returns-array-bad.err +++ b/tests/qapi-schema/returns-array-bad.err @@ -1 +1 @@ -tests/qapi-schema/returns-array-bad.json:2: 'returns' for command 'oops': array type must contain single type name +tests/qapi-schema/returns-array-bad.json:6: 'returns' for command 'oops': array type must contain single type name diff --git a/tests/qapi-schema/returns-array-bad.json b/tests/qapi-schema/returns-array-bad.json index 09b0b1f182..30528fed29 100644 --- a/tests/qapi-schema/returns-array-bad.json +++ b/tests/qapi-schema/returns-array-bad.json @@ -1,2 +1,6 @@ # we reject an array return that is not a single type + +## +# @oops: +## { 'command': 'oops', 'returns': [ 'str', 'str' ] } diff --git a/tests/qapi-schema/returns-dict.err b/tests/qapi-schema/returns-dict.err index eb2d0c4661..1570a35d49 100644 --- a/tests/qapi-schema/returns-dict.err +++ b/tests/qapi-schema/returns-dict.err @@ -1 +1 @@ -tests/qapi-schema/returns-dict.json:2: 'returns' for command 'oops' should be a type name +tests/qapi-schema/returns-dict.json:6: 'returns' for command 'oops' should be a type name diff --git a/tests/qapi-schema/returns-dict.json b/tests/qapi-schema/returns-dict.json index 1cfef3ede7..6a3ed0f34d 100644 --- a/tests/qapi-schema/returns-dict.json +++ b/tests/qapi-schema/returns-dict.json @@ -1,2 +1,6 @@ # we reject inline struct return type + +## +# @oops: +## { 'command': 'oops', 'returns': { 'a': 'str' } } diff --git a/tests/qapi-schema/returns-unknown.err b/tests/qapi-schema/returns-unknown.err index 1f43e3ac9f..d76bcfe455 100644 --- a/tests/qapi-schema/returns-unknown.err +++ b/tests/qapi-schema/returns-unknown.err @@ -1 +1 @@ -tests/qapi-schema/returns-unknown.json:2: 'returns' for command 'oops' uses unknown type 'NoSuchType' +tests/qapi-schema/returns-unknown.json:6: 'returns' for command 'oops' uses unknown type 'NoSuchType' diff --git a/tests/qapi-schema/returns-unknown.json b/tests/qapi-schema/returns-unknown.json index 25bd498bff..3837f0e607 100644 --- a/tests/qapi-schema/returns-unknown.json +++ b/tests/qapi-schema/returns-unknown.json @@ -1,2 +1,6 @@ # we reject returns if it does not contain a known type + +## +# @oops: +## { 'command': 'oops', 'returns': 'NoSuchType' } diff --git a/tests/qapi-schema/returns-whitelist.err b/tests/qapi-schema/returns-whitelist.err index f47c1ee7ca..e77ea2da3f 100644 --- a/tests/qapi-schema/returns-whitelist.err +++ b/tests/qapi-schema/returns-whitelist.err @@ -1 +1 @@ -tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int' +tests/qapi-schema/returns-whitelist.json:26: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int' diff --git a/tests/qapi-schema/returns-whitelist.json b/tests/qapi-schema/returns-whitelist.json index e8b3cea396..0bc952db87 100644 --- a/tests/qapi-schema/returns-whitelist.json +++ b/tests/qapi-schema/returns-whitelist.json @@ -1,11 +1,27 @@ # we enforce that 'returns' be a dict or array of dict unless whitelisted + +## +# @human-monitor-command: +## { 'command': 'human-monitor-command', 'data': {'command-line': 'str', '*cpu-index': 'int'}, 'returns': 'str' } +## +# @TpmModel: +## { 'enum': 'TpmModel', 'data': [ 'tpm-tis' ] } +## +# @query-tpm-models: +## { 'command': 'query-tpm-models', 'returns': ['TpmModel'] } +## +# @guest-get-time: +## { 'command': 'guest-get-time', 'returns': 'int' } +## +# @no-way-this-will-get-whitelisted: +## { 'command': 'no-way-this-will-get-whitelisted', 'returns': [ 'int' ] } diff --git a/tests/qapi-schema/struct-base-clash-deep.err b/tests/qapi-schema/struct-base-clash-deep.err index e2d7943f21..1b7c0e9d12 100644 --- a/tests/qapi-schema/struct-base-clash-deep.err +++ b/tests/qapi-schema/struct-base-clash-deep.err @@ -1 +1 @@ -tests/qapi-schema/struct-base-clash-deep.json:10: 'name' (member of Sub) collides with 'name' (member of Base) +tests/qapi-schema/struct-base-clash-deep.json:20: 'name' (member of Sub) collides with 'name' (member of Base) diff --git a/tests/qapi-schema/struct-base-clash-deep.json b/tests/qapi-schema/struct-base-clash-deep.json index fa873ab5d4..646d680ad6 100644 --- a/tests/qapi-schema/struct-base-clash-deep.json +++ b/tests/qapi-schema/struct-base-clash-deep.json @@ -2,11 +2,21 @@ # Here, 'name' would have to appear twice on the wire, locally and # indirectly for the grandparent base; the collision doesn't care that # one instance is optional. + +## +# @Base: +## { 'struct': 'Base', 'data': { 'name': 'str' } } +## +# @Mid: +## { 'struct': 'Mid', 'base': 'Base', 'data': { 'value': 'int' } } +## +# @Sub: +## { 'struct': 'Sub', 'base': 'Mid', 'data': { '*name': 'str' } } diff --git a/tests/qapi-schema/struct-base-clash.err b/tests/qapi-schema/struct-base-clash.err index c52f33d27b..5fe6393efa 100644 --- a/tests/qapi-schema/struct-base-clash.err +++ b/tests/qapi-schema/struct-base-clash.err @@ -1 +1 @@ -tests/qapi-schema/struct-base-clash.json:5: 'name' (member of Sub) collides with 'name' (member of Base) +tests/qapi-schema/struct-base-clash.json:12: 'name' (member of Sub) collides with 'name' (member of Base) diff --git a/tests/qapi-schema/struct-base-clash.json b/tests/qapi-schema/struct-base-clash.json index 11aec80fe5..a8539958b5 100644 --- a/tests/qapi-schema/struct-base-clash.json +++ b/tests/qapi-schema/struct-base-clash.json @@ -1,7 +1,14 @@ # Reject attempts to duplicate QMP members # Here, 'name' would have to appear twice on the wire, locally and for base. + +## +# @Base: +## { 'struct': 'Base', 'data': { 'name': 'str' } } +## +# @Sub: +## { 'struct': 'Sub', 'base': 'Base', 'data': { 'name': 'str' } } diff --git a/tests/qapi-schema/struct-data-invalid.err b/tests/qapi-schema/struct-data-invalid.err index 6644f4c2ad..27163355bd 100644 --- a/tests/qapi-schema/struct-data-invalid.err +++ b/tests/qapi-schema/struct-data-invalid.err @@ -1 +1 @@ -tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be a dictionary or type name +tests/qapi-schema/struct-data-invalid.json:4: 'data' for struct 'foo' should be a dictionary or type name diff --git a/tests/qapi-schema/struct-data-invalid.json b/tests/qapi-schema/struct-data-invalid.json index 9adbc3bb6b..aa817bda34 100644 --- a/tests/qapi-schema/struct-data-invalid.json +++ b/tests/qapi-schema/struct-data-invalid.json @@ -1,2 +1,5 @@ +## +# @foo: +## { 'struct': 'foo', 'data': false } diff --git a/tests/qapi-schema/struct-member-invalid.err b/tests/qapi-schema/struct-member-invalid.err index 69a326d450..f2b105ba88 100644 --- a/tests/qapi-schema/struct-member-invalid.err +++ b/tests/qapi-schema/struct-member-invalid.err @@ -1 +1 @@ -tests/qapi-schema/struct-member-invalid.json:1: Member 'a' of 'data' for struct 'foo' should be a type name +tests/qapi-schema/struct-member-invalid.json:4: Member 'a' of 'data' for struct 'foo' should be a type name diff --git a/tests/qapi-schema/struct-member-invalid.json b/tests/qapi-schema/struct-member-invalid.json index 8f172f7a87..10c74262d3 100644 --- a/tests/qapi-schema/struct-member-invalid.json +++ b/tests/qapi-schema/struct-member-invalid.json @@ -1,2 +1,5 @@ +## +# @foo: +## { 'struct': 'foo', 'data': { 'a': false } } diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index ef74e2c4c8..b4cde4ff4f 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -55,3 +55,17 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor): schema = QAPISchema(sys.argv[1]) schema.visit(QAPISchemaTestVisitor()) + +for doc in schema.docs: + if doc.symbol: + print 'doc symbol=%s expr=%s' % \ + (doc.symbol, doc.expr.items()[0]) + else: + print 'doc freeform' + for arg, section in doc.args.iteritems(): + print ' arg=%s\n%s' % (arg, section) + for section in doc.sections: + print ' section=%s\n%s' % (section.name, section) + body = str(doc.body) + if body: + print ' body=\n%s' % body diff --git a/tests/qapi-schema/type-bypass-bad-gen.err b/tests/qapi-schema/type-bypass-bad-gen.err index a83c3c655d..bd5431f60b 100644 --- a/tests/qapi-schema/type-bypass-bad-gen.err +++ b/tests/qapi-schema/type-bypass-bad-gen.err @@ -1 +1 @@ -tests/qapi-schema/type-bypass-bad-gen.json:2: 'gen' of command 'foo' should only use false value +tests/qapi-schema/type-bypass-bad-gen.json:6: 'gen' of command 'foo' should only use false value diff --git a/tests/qapi-schema/type-bypass-bad-gen.json b/tests/qapi-schema/type-bypass-bad-gen.json index e8dec34249..7162c1a0ca 100644 --- a/tests/qapi-schema/type-bypass-bad-gen.json +++ b/tests/qapi-schema/type-bypass-bad-gen.json @@ -1,2 +1,6 @@ # 'gen' should only appear with value false + +## +# @foo: +## { 'command': 'foo', 'gen': 'whatever' } diff --git a/tests/qapi-schema/unicode-str.err b/tests/qapi-schema/unicode-str.err index f621cd6448..92ee277370 100644 --- a/tests/qapi-schema/unicode-str.err +++ b/tests/qapi-schema/unicode-str.err @@ -1 +1 @@ -tests/qapi-schema/unicode-str.json:2: 'command' uses invalid name 'é' +tests/qapi-schema/unicode-str.json:6: 'command' uses invalid name 'é' diff --git a/tests/qapi-schema/unicode-str.json b/tests/qapi-schema/unicode-str.json index 5253a1b9f3..75a08b3d93 100644 --- a/tests/qapi-schema/unicode-str.json +++ b/tests/qapi-schema/unicode-str.json @@ -1,2 +1,6 @@ # we don't support full Unicode strings, yet + +## +# @e: +## { 'command': 'é' } diff --git a/tests/qapi-schema/union-base-no-discriminator.err b/tests/qapi-schema/union-base-no-discriminator.err index 8b7a24260f..ca6ee92357 100644 --- a/tests/qapi-schema/union-base-no-discriminator.err +++ b/tests/qapi-schema/union-base-no-discriminator.err @@ -1 +1 @@ -tests/qapi-schema/union-base-no-discriminator.json:11: Simple union 'TestUnion' must not have a base +tests/qapi-schema/union-base-no-discriminator.json:23: Simple union 'TestUnion' must not have a base diff --git a/tests/qapi-schema/union-base-no-discriminator.json b/tests/qapi-schema/union-base-no-discriminator.json index 1409cf5c9e..cc6bac1424 100644 --- a/tests/qapi-schema/union-base-no-discriminator.json +++ b/tests/qapi-schema/union-base-no-discriminator.json @@ -1,13 +1,25 @@ +## +# @TestTypeA: +## # we reject simple unions with a base (or flat unions without discriminator) { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @Base: +## { 'struct': 'Base', 'data': { 'string': 'str' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'Base', 'data': { 'value1': 'TestTypeA', diff --git a/tests/qapi-schema/union-branch-case.err b/tests/qapi-schema/union-branch-case.err index 11521901d8..9095bae565 100644 --- a/tests/qapi-schema/union-branch-case.err +++ b/tests/qapi-schema/union-branch-case.err @@ -1 +1 @@ -tests/qapi-schema/union-branch-case.json:2: 'Branch' (branch of NoWayThisWillGetWhitelisted) should not use uppercase +tests/qapi-schema/union-branch-case.json:6: 'Branch' (branch of NoWayThisWillGetWhitelisted) should not use uppercase diff --git a/tests/qapi-schema/union-branch-case.json b/tests/qapi-schema/union-branch-case.json index e6565dc3b3..6de131548c 100644 --- a/tests/qapi-schema/union-branch-case.json +++ b/tests/qapi-schema/union-branch-case.json @@ -1,2 +1,6 @@ # Branch names should be 'lower-case' unless the union is whitelisted + +## +# @NoWayThisWillGetWhitelisted: +## { 'union': 'NoWayThisWillGetWhitelisted', 'data': { 'Branch': 'int' } } diff --git a/tests/qapi-schema/union-clash-branches.err b/tests/qapi-schema/union-clash-branches.err index e5b21135bb..640caeab8c 100644 --- a/tests/qapi-schema/union-clash-branches.err +++ b/tests/qapi-schema/union-clash-branches.err @@ -1 +1 @@ -tests/qapi-schema/union-clash-branches.json:4: 'a_b' (branch of TestUnion) collides with 'a-b' (branch of TestUnion) +tests/qapi-schema/union-clash-branches.json:8: 'a_b' (branch of TestUnion) collides with 'a-b' (branch of TestUnion) diff --git a/tests/qapi-schema/union-clash-branches.json b/tests/qapi-schema/union-clash-branches.json index 3bece8c948..6615665dfe 100644 --- a/tests/qapi-schema/union-clash-branches.json +++ b/tests/qapi-schema/union-clash-branches.json @@ -1,5 +1,9 @@ # Union branch name collision # Reject a union that would result in a collision in generated C names (this # would try to generate two members 'a_b'). + +## +# @TestUnion: +## { 'union': 'TestUnion', 'data': { 'a-b': 'int', 'a_b': 'str' } } diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-empty.err index 12c20221bd..749bc76fc5 100644 --- a/tests/qapi-schema/union-empty.err +++ b/tests/qapi-schema/union-empty.err @@ -1 +1 @@ -tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data' +tests/qapi-schema/union-empty.json:6: Union 'Union' cannot have empty 'data' diff --git a/tests/qapi-schema/union-empty.json b/tests/qapi-schema/union-empty.json index 1f0b13ca21..c9b0a1ef33 100644 --- a/tests/qapi-schema/union-empty.json +++ b/tests/qapi-schema/union-empty.json @@ -1,2 +1,6 @@ # unions cannot be empty + +## +# @Union: +## { 'union': 'Union', 'data': { } } diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err index 03d7b97a93..41e238f453 100644 --- a/tests/qapi-schema/union-invalid-base.err +++ b/tests/qapi-schema/union-invalid-base.err @@ -1 +1 @@ -tests/qapi-schema/union-invalid-base.json:8: 'base' for union 'TestUnion' cannot use built-in type 'int' +tests/qapi-schema/union-invalid-base.json:18: 'base' for union 'TestUnion' cannot use built-in type 'int' diff --git a/tests/qapi-schema/union-invalid-base.json b/tests/qapi-schema/union-invalid-base.json index 92be39df69..fd837cb80b 100644 --- a/tests/qapi-schema/union-invalid-base.json +++ b/tests/qapi-schema/union-invalid-base.json @@ -1,10 +1,20 @@ # a union base type must be a struct + +## +# @TestTypeA: +## { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } +## +# @TestTypeB: +## { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } +## +# @TestUnion: +## { 'union': 'TestUnion', 'base': 'int', 'discriminator': 'int', diff --git a/tests/qapi-schema/union-optional-branch.err b/tests/qapi-schema/union-optional-branch.err index 3ada1334dc..60523c07e4 100644 --- a/tests/qapi-schema/union-optional-branch.err +++ b/tests/qapi-schema/union-optional-branch.err @@ -1 +1 @@ -tests/qapi-schema/union-optional-branch.json:2: Member of union 'Union' does not allow optional name '*a' +tests/qapi-schema/union-optional-branch.json:6: Member of union 'Union' does not allow optional name '*a' diff --git a/tests/qapi-schema/union-optional-branch.json b/tests/qapi-schema/union-optional-branch.json index 591615fc68..7d2ee4c730 100644 --- a/tests/qapi-schema/union-optional-branch.json +++ b/tests/qapi-schema/union-optional-branch.json @@ -1,2 +1,6 @@ # union branches cannot be optional + +## +# @Union: +## { 'union': 'Union', 'data': { '*a': 'int', 'b': 'str' } } diff --git a/tests/qapi-schema/union-unknown.err b/tests/qapi-schema/union-unknown.err index 54fe456f9c..5568302205 100644 --- a/tests/qapi-schema/union-unknown.err +++ b/tests/qapi-schema/union-unknown.err @@ -1 +1 @@ -tests/qapi-schema/union-unknown.json:2: Member 'unknown' of union 'Union' uses unknown type 'MissingType' +tests/qapi-schema/union-unknown.json:6: Member 'unknown' of union 'Union' uses unknown type 'MissingType' diff --git a/tests/qapi-schema/union-unknown.json b/tests/qapi-schema/union-unknown.json index aa7e8143d8..5042b23197 100644 --- a/tests/qapi-schema/union-unknown.json +++ b/tests/qapi-schema/union-unknown.json @@ -1,3 +1,7 @@ # we reject a union with unknown type in branch + +## +# @Union: +## { 'union': 'Union', 'data': { 'unknown': 'MissingType' } } diff --git a/tests/qapi-schema/unknown-escape.err b/tests/qapi-schema/unknown-escape.err index 000e30ddf3..1a4ead632b 100644 --- a/tests/qapi-schema/unknown-escape.err +++ b/tests/qapi-schema/unknown-escape.err @@ -1 +1 @@ -tests/qapi-schema/unknown-escape.json:3:21: Unknown escape \x +tests/qapi-schema/unknown-escape.json:7:21: Unknown escape \x diff --git a/tests/qapi-schema/unknown-escape.json b/tests/qapi-schema/unknown-escape.json index 8e6891e52a..e3ae6793f2 100644 --- a/tests/qapi-schema/unknown-escape.json +++ b/tests/qapi-schema/unknown-escape.json @@ -1,3 +1,7 @@ # we only recognize JSON escape sequences, plus our \' extension (no \x) + +## +# @foo: +## # { 'command': 'foo', 'data': {} } { 'command': 'foo', 'dat\x61':{} } diff --git a/tests/qapi-schema/unknown-expr-key.err b/tests/qapi-schema/unknown-expr-key.err index 12f5ed5b43..b19a668bd6 100644 --- a/tests/qapi-schema/unknown-expr-key.err +++ b/tests/qapi-schema/unknown-expr-key.err @@ -1 +1 @@ -tests/qapi-schema/unknown-expr-key.json:2: Unknown key 'bogus' in struct 'bar' +tests/qapi-schema/unknown-expr-key.json:6: Unknown key 'bogus' in struct 'bar' diff --git a/tests/qapi-schema/unknown-expr-key.json b/tests/qapi-schema/unknown-expr-key.json index 3b2be00cc4..1b764c7b9d 100644 --- a/tests/qapi-schema/unknown-expr-key.json +++ b/tests/qapi-schema/unknown-expr-key.json @@ -1,2 +1,6 @@ # we reject an expression with unknown top-level keys + +## +# @bar: +## { 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { } } diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out index 8ff423f56b..dd879f1212 100644 --- a/tests/qemu-iotests/071.out +++ b/tests/qemu-iotests/071.out @@ -12,7 +12,7 @@ read 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 +blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkverify through file blockref === @@ -26,7 +26,7 @@ read 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 +blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkdebug through filename === @@ -56,7 +56,7 @@ QMP_VERSION {"return": {}} {"return": {}} {"return": {}} -blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 +blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkverify on existing raw block device === @@ -66,7 +66,7 @@ QMP_VERSION {"return": {}} {"return": {}} {"return": {}} -blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 +blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkdebug's set-state through QMP === diff --git a/tests/test-aio.c b/tests/test-aio.c index 5be99f8287..2754f154ce 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -128,7 +128,7 @@ static void *test_acquire_thread(void *opaque) static void set_event_notifier(AioContext *ctx, EventNotifier *notifier, EventNotifierHandler *handler) { - aio_set_event_notifier(ctx, notifier, false, handler); + aio_set_event_notifier(ctx, notifier, false, handler, NULL); } static void dummy_notifier_read(EventNotifier *n) @@ -388,7 +388,7 @@ static void test_aio_external_client(void) for (i = 1; i < 3; i++) { EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, true, event_ready_cb); + aio_set_event_notifier(ctx, &data.e, true, event_ready_cb, NULL); event_notifier_set(&data.e); for (j = 0; j < i; j++) { aio_disable_external(ctx); diff --git a/tests/test-bitcnt.c b/tests/test-bitcnt.c new file mode 100644 index 0000000000..e153dcb8a2 --- /dev/null +++ b/tests/test-bitcnt.c @@ -0,0 +1,140 @@ +/* + * Test bit count routines + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" + +struct bitcnt_test_data { + /* value to count */ + union { + uint8_t w8; + uint16_t w16; + uint32_t w32; + uint64_t w64; + } value; + /* expected result */ + int popct; +}; + +struct bitcnt_test_data eight_bit_data[] = { + { { .w8 = 0x00 }, .popct=0 }, + { { .w8 = 0x01 }, .popct=1 }, + { { .w8 = 0x03 }, .popct=2 }, + { { .w8 = 0x04 }, .popct=1 }, + { { .w8 = 0x0f }, .popct=4 }, + { { .w8 = 0x3f }, .popct=6 }, + { { .w8 = 0x40 }, .popct=1 }, + { { .w8 = 0xf0 }, .popct=4 }, + { { .w8 = 0x7f }, .popct=7 }, + { { .w8 = 0x80 }, .popct=1 }, + { { .w8 = 0xf1 }, .popct=5 }, + { { .w8 = 0xfe }, .popct=7 }, + { { .w8 = 0xff }, .popct=8 }, +}; + +static void test_ctpop8(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(eight_bit_data); i++) { + struct bitcnt_test_data *d = &eight_bit_data[i]; + g_assert(ctpop8(d->value.w8)==d->popct); + } +} + +struct bitcnt_test_data sixteen_bit_data[] = { + { { .w16 = 0x0000 }, .popct=0 }, + { { .w16 = 0x0001 }, .popct=1 }, + { { .w16 = 0x0003 }, .popct=2 }, + { { .w16 = 0x000f }, .popct=4 }, + { { .w16 = 0x003f }, .popct=6 }, + { { .w16 = 0x00f0 }, .popct=4 }, + { { .w16 = 0x0f0f }, .popct=8 }, + { { .w16 = 0x1f1f }, .popct=10 }, + { { .w16 = 0x4000 }, .popct=1 }, + { { .w16 = 0x4001 }, .popct=2 }, + { { .w16 = 0x7000 }, .popct=3 }, + { { .w16 = 0x7fff }, .popct=15 }, +}; + +static void test_ctpop16(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sixteen_bit_data); i++) { + struct bitcnt_test_data *d = &sixteen_bit_data[i]; + g_assert(ctpop16(d->value.w16)==d->popct); + } +} + +struct bitcnt_test_data thirtytwo_bit_data[] = { + { { .w32 = 0x00000000 }, .popct=0 }, + { { .w32 = 0x00000001 }, .popct=1 }, + { { .w32 = 0x0000000f }, .popct=4 }, + { { .w32 = 0x00000f0f }, .popct=8 }, + { { .w32 = 0x00001f1f }, .popct=10 }, + { { .w32 = 0x00004001 }, .popct=2 }, + { { .w32 = 0x00007000 }, .popct=3 }, + { { .w32 = 0x00007fff }, .popct=15 }, + { { .w32 = 0x55555555 }, .popct=16 }, + { { .w32 = 0xaaaaaaaa }, .popct=16 }, + { { .w32 = 0xff000000 }, .popct=8 }, + { { .w32 = 0xc0c0c0c0 }, .popct=8 }, + { { .w32 = 0x0ffffff0 }, .popct=24 }, + { { .w32 = 0x80000000 }, .popct=1 }, + { { .w32 = 0xffffffff }, .popct=32 }, +}; + +static void test_ctpop32(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(thirtytwo_bit_data); i++) { + struct bitcnt_test_data *d = &thirtytwo_bit_data[i]; + g_assert(ctpop32(d->value.w32)==d->popct); + } +} + +struct bitcnt_test_data sixtyfour_bit_data[] = { + { { .w64 = 0x0000000000000000ULL }, .popct=0 }, + { { .w64 = 0x0000000000000001ULL }, .popct=1 }, + { { .w64 = 0x000000000000000fULL }, .popct=4 }, + { { .w64 = 0x0000000000000f0fULL }, .popct=8 }, + { { .w64 = 0x0000000000001f1fULL }, .popct=10 }, + { { .w64 = 0x0000000000004001ULL }, .popct=2 }, + { { .w64 = 0x0000000000007000ULL }, .popct=3 }, + { { .w64 = 0x0000000000007fffULL }, .popct=15 }, + { { .w64 = 0x0000005500555555ULL }, .popct=16 }, + { { .w64 = 0x00aa0000aaaa00aaULL }, .popct=16 }, + { { .w64 = 0x000f000000f00000ULL }, .popct=8 }, + { { .w64 = 0x0c0c0000c0c0c0c0ULL }, .popct=12 }, + { { .w64 = 0xf00f00f0f0f0f000ULL }, .popct=24 }, + { { .w64 = 0x8000000000000000ULL }, .popct=1 }, + { { .w64 = 0xf0f0f0f0f0f0f0f0ULL }, .popct=32 }, + { { .w64 = 0xffffffffffffffffULL }, .popct=64 }, +}; + +static void test_ctpop64(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sixtyfour_bit_data); i++) { + struct bitcnt_test_data *d = &sixtyfour_bit_data[i]; + g_assert(ctpop64(d->value.w64)==d->popct); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/bitcnt/ctpop8", test_ctpop8); + g_test_add_func("/bitcnt/ctpop16", test_ctpop16); + g_test_add_func("/bitcnt/ctpop32", test_ctpop32); + g_test_add_func("/bitcnt/ctpop64", test_ctpop64); + return g_test_run(); +} diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c index aa88c3cf45..aaa9116fb7 100644 --- a/tests/test-io-channel-socket.c +++ b/tests/test-io-channel-socket.c @@ -156,12 +156,11 @@ struct TestIOChannelData { }; -static void test_io_channel_complete(Object *src, - Error *err, +static void test_io_channel_complete(QIOTask *task, gpointer opaque) { struct TestIOChannelData *data = opaque; - data->err = err != NULL; + data->err = qio_task_propagate_error(task, NULL); g_main_loop_quit(data->loop); } diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c index bd3ae2bf7a..8eaa208e1b 100644 --- a/tests/test-io-channel-tls.c +++ b/tests/test-io-channel-tls.c @@ -53,14 +53,13 @@ struct QIOChannelTLSHandshakeData { bool failed; }; -static void test_tls_handshake_done(Object *source, - Error *err, +static void test_tls_handshake_done(QIOTask *task, gpointer opaque) { struct QIOChannelTLSHandshakeData *data = opaque; data->finished = true; - data->failed = err != NULL; + data->failed = qio_task_propagate_error(task, NULL); } diff --git a/tests/test-io-task.c b/tests/test-io-task.c index e091c12e10..ff62272d5f 100644 --- a/tests/test-io-task.c +++ b/tests/test-io-task.c @@ -50,14 +50,13 @@ struct TestTaskData { }; -static void task_callback(Object *source, - Error *err, +static void task_callback(QIOTask *task, gpointer opaque) { struct TestTaskData *data = opaque; - data->source = source; - data->err = err; + data->source = qio_task_get_source(task); + qio_task_propagate_error(task, &data->err); } @@ -76,7 +75,6 @@ static void test_task_complete(void) g_assert(obj == src); object_unref(obj); - object_unref(src); g_assert(data.source == obj); g_assert(data.err == NULL); @@ -121,9 +119,9 @@ static void test_task_failure(void) error_setg(&err, "Some error"); - qio_task_abort(task, err); + qio_task_set_error(task, err); + qio_task_complete(task); - error_free(err); object_unref(obj); g_assert(data.source == obj); @@ -142,31 +140,28 @@ struct TestThreadWorkerData { GMainLoop *loop; }; -static int test_task_thread_worker(QIOTask *task, - Error **errp, - gpointer opaque) +static void test_task_thread_worker(QIOTask *task, + gpointer opaque) { struct TestThreadWorkerData *data = opaque; data->worker = g_thread_self(); if (data->fail) { - error_setg(errp, "Testing fail"); - return -1; + Error *err = NULL; + error_setg(&err, "Testing fail"); + qio_task_set_error(task, err); } - - return 0; } -static void test_task_thread_callback(Object *source, - Error *err, +static void test_task_thread_callback(QIOTask *task, gpointer opaque) { struct TestThreadWorkerData *data = opaque; - data->source = source; - data->err = err; + data->source = qio_task_get_source(task); + qio_task_propagate_error(task, &data->err); data->complete = g_thread_self(); diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index d2f529b831..9d87faf12b 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -544,6 +544,150 @@ static void test_arr_ptr_str_no0_load(void) } } +/* test QTAILQ migration */ +typedef struct TestQtailqElement TestQtailqElement; + +struct TestQtailqElement { + bool b; + uint8_t u8; + QTAILQ_ENTRY(TestQtailqElement) next; +}; + +typedef struct TestQtailq { + int16_t i16; + QTAILQ_HEAD(TestQtailqHead, TestQtailqElement) q; + int32_t i32; +} TestQtailq; + +static const VMStateDescription vmstate_q_element = { + .name = "test/queue-element", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(b, TestQtailqElement), + VMSTATE_UINT8(u8, TestQtailqElement), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_q = { + .name = "test/queue", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT16(i16, TestQtailq), + VMSTATE_QTAILQ_V(q, TestQtailq, 1, vmstate_q_element, TestQtailqElement, + next), + VMSTATE_INT32(i32, TestQtailq), + VMSTATE_END_OF_LIST() + } +}; + +uint8_t wire_q[] = { + /* i16 */ 0xfe, 0x0, + /* start of element 0 of q */ 0x01, + /* .b */ 0x01, + /* .u8 */ 0x82, + /* start of element 1 of q */ 0x01, + /* b */ 0x00, + /* u8 */ 0x41, + /* end of q */ 0x00, + /* i32 */ 0x00, 0x01, 0x11, 0x70, + QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ +}; + +static void test_save_q(void) +{ + TestQtailq obj_q = { + .i16 = -512, + .i32 = 70000, + }; + + TestQtailqElement obj_qe1 = { + .b = true, + .u8 = 130, + }; + + TestQtailqElement obj_qe2 = { + .b = false, + .u8 = 65, + }; + + QTAILQ_INIT(&obj_q.q); + QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next); + QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next); + + save_vmstate(&vmstate_q, &obj_q); + compare_vmstate(wire_q, sizeof(wire_q)); +} + +static void test_load_q(void) +{ + TestQtailq obj_q = { + .i16 = -512, + .i32 = 70000, + }; + + TestQtailqElement obj_qe1 = { + .b = true, + .u8 = 130, + }; + + TestQtailqElement obj_qe2 = { + .b = false, + .u8 = 65, + }; + + QTAILQ_INIT(&obj_q.q); + QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next); + QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next); + + QEMUFile *fsave = open_test_file(true); + + qemu_put_buffer(fsave, wire_q, sizeof(wire_q)); + g_assert(!qemu_file_get_error(fsave)); + qemu_fclose(fsave); + + QEMUFile *fload = open_test_file(false); + TestQtailq tgt; + + QTAILQ_INIT(&tgt.q); + vmstate_load_state(fload, &vmstate_q, &tgt, 1); + char eof = qemu_get_byte(fload); + g_assert(!qemu_file_get_error(fload)); + g_assert_cmpint(tgt.i16, ==, obj_q.i16); + g_assert_cmpint(tgt.i32, ==, obj_q.i32); + g_assert_cmpint(eof, ==, QEMU_VM_EOF); + + TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q); + TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q, TestQtailqHead); + TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q); + TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q, TestQtailqHead); + + while (1) { + g_assert_cmpint(qele_to->b, ==, qele_from->b); + g_assert_cmpint(qele_to->u8, ==, qele_from->u8); + if ((qele_from == qlast_from) || (qele_to == qlast_to)) { + break; + } + qele_from = QTAILQ_NEXT(qele_from, next); + qele_to = QTAILQ_NEXT(qele_to, next); + } + + g_assert_cmpint((uintptr_t) qele_from, ==, (uintptr_t) qlast_from); + g_assert_cmpint((uintptr_t) qele_to, ==, (uintptr_t) qlast_to); + + /* clean up */ + TestQtailqElement *qele; + while (!QTAILQ_EMPTY(&tgt.q)) { + qele = QTAILQ_LAST(&tgt.q, TestQtailqHead); + QTAILQ_REMOVE(&tgt.q, qele, next); + free(qele); + qele = NULL; + } + qemu_fclose(fload); +} + int main(int argc, char **argv) { temp_fd = mkstemp(temp_file); @@ -562,6 +706,9 @@ int main(int argc, char **argv) test_arr_ptr_str_no0_save); g_test_add_func("/vmstate/array/ptr/str/no0/load", test_arr_ptr_str_no0_load); + g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q); + g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q); + g_test_run(); close(temp_fd); diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c index 775e031069..8618c20d53 100644 --- a/tests/vhost-user-bridge.c +++ b/tests/vhost-user-bridge.c @@ -30,17 +30,9 @@ #define _FILE_OFFSET_BITS 64 #include "qemu/osdep.h" -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/unistd.h> -#include <sys/eventfd.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <linux/vhost.h> - -#include "qemu/atomic.h" +#include "qemu/iov.h" #include "standard-headers/linux/virtio_net.h" -#include "standard-headers/linux/virtio_ring.h" +#include "contrib/libvhost-user/libvhost-user.h" #define VHOST_USER_BRIDGE_DEBUG 1 @@ -64,6 +56,17 @@ typedef struct Dispatcher { Event events[FD_SETSIZE]; } Dispatcher; +typedef struct VubrDev { + VuDev vudev; + Dispatcher dispatcher; + int backend_udp_sock; + struct sockaddr_in backend_udp_dest; + int hdrlen; + int sock; + int ready; + int quit; +} VubrDev; + static void vubr_die(const char *s) { @@ -101,8 +104,6 @@ dispatcher_add(Dispatcher *dispr, int sock, void *ctx, CallbackFunc cb) return 0; } -/* dispatcher_remove() is not currently in use but may be useful - * in the future. */ static int dispatcher_remove(Dispatcher *dispr, int sock) { @@ -157,1039 +158,313 @@ dispatcher_wait(Dispatcher *dispr, uint32_t timeout) return 0; } -typedef struct VubrVirtq { - int call_fd; - int kick_fd; - uint32_t size; - uint16_t last_avail_index; - uint16_t last_used_index; - struct vring_desc *desc; - struct vring_avail *avail; - struct vring_used *used; - uint64_t log_guest_addr; - int enable; -} VubrVirtq; - -/* Based on qemu/hw/virtio/vhost-user.c */ - -#define VHOST_MEMORY_MAX_NREGIONS 8 -#define VHOST_USER_F_PROTOCOL_FEATURES 30 -/* v1.0 compliant. */ -#define VIRTIO_F_VERSION_1 32 - -#define VHOST_LOG_PAGE 4096 - -enum VhostUserProtocolFeature { - VHOST_USER_PROTOCOL_F_MQ = 0, - VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, - VHOST_USER_PROTOCOL_F_RARP = 2, - - VHOST_USER_PROTOCOL_F_MAX -}; - -#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1) - -typedef enum VhostUserRequest { - VHOST_USER_NONE = 0, - VHOST_USER_GET_FEATURES = 1, - VHOST_USER_SET_FEATURES = 2, - VHOST_USER_SET_OWNER = 3, - VHOST_USER_RESET_OWNER = 4, - VHOST_USER_SET_MEM_TABLE = 5, - VHOST_USER_SET_LOG_BASE = 6, - VHOST_USER_SET_LOG_FD = 7, - VHOST_USER_SET_VRING_NUM = 8, - VHOST_USER_SET_VRING_ADDR = 9, - VHOST_USER_SET_VRING_BASE = 10, - VHOST_USER_GET_VRING_BASE = 11, - VHOST_USER_SET_VRING_KICK = 12, - VHOST_USER_SET_VRING_CALL = 13, - VHOST_USER_SET_VRING_ERR = 14, - VHOST_USER_GET_PROTOCOL_FEATURES = 15, - VHOST_USER_SET_PROTOCOL_FEATURES = 16, - VHOST_USER_GET_QUEUE_NUM = 17, - VHOST_USER_SET_VRING_ENABLE = 18, - VHOST_USER_SEND_RARP = 19, - VHOST_USER_MAX -} VhostUserRequest; - -typedef struct VhostUserMemoryRegion { - uint64_t guest_phys_addr; - uint64_t memory_size; - uint64_t userspace_addr; - uint64_t mmap_offset; -} VhostUserMemoryRegion; - -typedef struct VhostUserMemory { - uint32_t nregions; - uint32_t padding; - VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; -} VhostUserMemory; - -typedef struct VhostUserLog { - uint64_t mmap_size; - uint64_t mmap_offset; -} VhostUserLog; - -typedef struct VhostUserMsg { - VhostUserRequest request; - -#define VHOST_USER_VERSION_MASK (0x3) -#define VHOST_USER_REPLY_MASK (0x1<<2) - uint32_t flags; - uint32_t size; /* the following payload size */ - union { -#define VHOST_USER_VRING_IDX_MASK (0xff) -#define VHOST_USER_VRING_NOFD_MASK (0x1<<8) - uint64_t u64; - struct vhost_vring_state state; - struct vhost_vring_addr addr; - VhostUserMemory memory; - VhostUserLog log; - } payload; - int fds[VHOST_MEMORY_MAX_NREGIONS]; - int fd_num; -} QEMU_PACKED VhostUserMsg; - -#define VHOST_USER_HDR_SIZE offsetof(VhostUserMsg, payload.u64) - -/* The version of the protocol we support */ -#define VHOST_USER_VERSION (0x1) - -#define MAX_NR_VIRTQUEUE (8) - -typedef struct VubrDevRegion { - /* Guest Physical address. */ - uint64_t gpa; - /* Memory region size. */ - uint64_t size; - /* QEMU virtual address (userspace). */ - uint64_t qva; - /* Starting offset in our mmaped space. */ - uint64_t mmap_offset; - /* Start address of mmaped space. */ - uint64_t mmap_addr; -} VubrDevRegion; - -typedef struct VubrDev { - int sock; - Dispatcher dispatcher; - uint32_t nregions; - VubrDevRegion regions[VHOST_MEMORY_MAX_NREGIONS]; - VubrVirtq vq[MAX_NR_VIRTQUEUE]; - int log_call_fd; - uint64_t log_size; - uint8_t *log_table; - int backend_udp_sock; - struct sockaddr_in backend_udp_dest; - int ready; - uint64_t features; - int hdrlen; -} VubrDev; - -static const char *vubr_request_str[] = { - [VHOST_USER_NONE] = "VHOST_USER_NONE", - [VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES", - [VHOST_USER_SET_FEATURES] = "VHOST_USER_SET_FEATURES", - [VHOST_USER_SET_OWNER] = "VHOST_USER_SET_OWNER", - [VHOST_USER_RESET_OWNER] = "VHOST_USER_RESET_OWNER", - [VHOST_USER_SET_MEM_TABLE] = "VHOST_USER_SET_MEM_TABLE", - [VHOST_USER_SET_LOG_BASE] = "VHOST_USER_SET_LOG_BASE", - [VHOST_USER_SET_LOG_FD] = "VHOST_USER_SET_LOG_FD", - [VHOST_USER_SET_VRING_NUM] = "VHOST_USER_SET_VRING_NUM", - [VHOST_USER_SET_VRING_ADDR] = "VHOST_USER_SET_VRING_ADDR", - [VHOST_USER_SET_VRING_BASE] = "VHOST_USER_SET_VRING_BASE", - [VHOST_USER_GET_VRING_BASE] = "VHOST_USER_GET_VRING_BASE", - [VHOST_USER_SET_VRING_KICK] = "VHOST_USER_SET_VRING_KICK", - [VHOST_USER_SET_VRING_CALL] = "VHOST_USER_SET_VRING_CALL", - [VHOST_USER_SET_VRING_ERR] = "VHOST_USER_SET_VRING_ERR", - [VHOST_USER_GET_PROTOCOL_FEATURES] = "VHOST_USER_GET_PROTOCOL_FEATURES", - [VHOST_USER_SET_PROTOCOL_FEATURES] = "VHOST_USER_SET_PROTOCOL_FEATURES", - [VHOST_USER_GET_QUEUE_NUM] = "VHOST_USER_GET_QUEUE_NUM", - [VHOST_USER_SET_VRING_ENABLE] = "VHOST_USER_SET_VRING_ENABLE", - [VHOST_USER_SEND_RARP] = "VHOST_USER_SEND_RARP", - [VHOST_USER_MAX] = "VHOST_USER_MAX", -}; - static void -print_buffer(uint8_t *buf, size_t len) +vubr_handle_tx(VuDev *dev, int qidx) { - int i; - printf("Raw buffer:\n"); - for (i = 0; i < len; i++) { - if (i % 16 == 0) { - printf("\n"); - } - if (i % 4 == 0) { - printf(" "); - } - printf("%02x ", buf[i]); - } - printf("\n............................................................\n"); -} + VuVirtq *vq = vu_get_queue(dev, qidx); + VubrDev *vubr = container_of(dev, VubrDev, vudev); + int hdrlen = vubr->hdrlen; + VuVirtqElement *elem = NULL; -/* Translate guest physical address to our virtual address. */ -static uint64_t -gpa_to_va(VubrDev *dev, uint64_t guest_addr) -{ - int i; - - /* Find matching memory region. */ - for (i = 0; i < dev->nregions; i++) { - VubrDevRegion *r = &dev->regions[i]; - - if ((guest_addr >= r->gpa) && (guest_addr < (r->gpa + r->size))) { - return guest_addr - r->gpa + r->mmap_addr + r->mmap_offset; - } - } - - assert(!"address not found in regions"); - return 0; -} - -/* Translate qemu virtual address to our virtual address. */ -static uint64_t -qva_to_va(VubrDev *dev, uint64_t qemu_addr) -{ - int i; + assert(qidx % 2); - /* Find matching memory region. */ - for (i = 0; i < dev->nregions; i++) { - VubrDevRegion *r = &dev->regions[i]; + for (;;) { + ssize_t ret; + unsigned int out_num; + struct iovec sg[VIRTQUEUE_MAX_SIZE], *out_sg; - if ((qemu_addr >= r->qva) && (qemu_addr < (r->qva + r->size))) { - return qemu_addr - r->qva + r->mmap_addr + r->mmap_offset; + elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); + if (!elem) { + break; } - } - - assert(!"address not found in regions"); - return 0; -} -static void -vubr_message_read(int conn_fd, VhostUserMsg *vmsg) -{ - char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))] = { }; - struct iovec iov = { - .iov_base = (char *)vmsg, - .iov_len = VHOST_USER_HDR_SIZE, - }; - struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = control, - .msg_controllen = sizeof(control), - }; - size_t fd_size; - struct cmsghdr *cmsg; - int rc; - - rc = recvmsg(conn_fd, &msg, 0); - - if (rc == 0) { - vubr_die("recvmsg"); - fprintf(stderr, "Peer disconnected.\n"); - exit(1); - } - if (rc < 0) { - vubr_die("recvmsg"); - } - - vmsg->fd_num = 0; - for (cmsg = CMSG_FIRSTHDR(&msg); - cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) - { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - fd_size = cmsg->cmsg_len - CMSG_LEN(0); - vmsg->fd_num = fd_size / sizeof(int); - memcpy(vmsg->fds, CMSG_DATA(cmsg), fd_size); + out_num = elem->out_num; + out_sg = elem->out_sg; + if (out_num < 1) { + fprintf(stderr, "virtio-net header not in first element\n"); break; } - } - - if (vmsg->size > sizeof(vmsg->payload)) { - fprintf(stderr, - "Error: too big message request: %d, size: vmsg->size: %u, " - "while sizeof(vmsg->payload) = %zu\n", - vmsg->request, vmsg->size, sizeof(vmsg->payload)); - exit(1); - } - - if (vmsg->size) { - rc = read(conn_fd, &vmsg->payload, vmsg->size); - if (rc == 0) { - vubr_die("recvmsg"); - fprintf(stderr, "Peer disconnected.\n"); - exit(1); + if (VHOST_USER_BRIDGE_DEBUG) { + iov_hexdump(out_sg, out_num, stderr, "TX:", 1024); } - if (rc < 0) { - vubr_die("recvmsg"); + + if (hdrlen) { + unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg), + out_sg, out_num, + hdrlen, -1); + out_num = sg_num; + out_sg = sg; } - assert(rc == vmsg->size); - } -} + struct msghdr msg = { + .msg_name = (struct sockaddr *) &vubr->backend_udp_dest, + .msg_namelen = sizeof(struct sockaddr_in), + .msg_iov = out_sg, + .msg_iovlen = out_num, + }; + do { + ret = sendmsg(vubr->backend_udp_sock, &msg, 0); + } while (ret == -1 && (errno == EAGAIN || errno == EINTR)); -static void -vubr_message_write(int conn_fd, VhostUserMsg *vmsg) -{ - int rc; + if (ret == -1) { + vubr_die("sendmsg()"); + } - do { - rc = write(conn_fd, vmsg, VHOST_USER_HDR_SIZE + vmsg->size); - } while (rc < 0 && errno == EINTR); + vu_queue_push(dev, vq, elem, 0); + vu_queue_notify(dev, vq); - if (rc < 0) { - vubr_die("write"); + free(elem); + elem = NULL; } -} -static void -vubr_backend_udp_sendbuf(VubrDev *dev, uint8_t *buf, size_t len) -{ - int slen = sizeof(struct sockaddr_in); - - if (sendto(dev->backend_udp_sock, buf, len, 0, - (struct sockaddr *) &dev->backend_udp_dest, slen) == -1) { - vubr_die("sendto()"); - } + free(elem); } -static int -vubr_backend_udp_recvbuf(VubrDev *dev, uint8_t *buf, size_t buflen) +static void +iov_restore_front(struct iovec *front, struct iovec *iov, size_t bytes) { - int slen = sizeof(struct sockaddr_in); - int rc; + struct iovec *cur; - rc = recvfrom(dev->backend_udp_sock, buf, buflen, 0, - (struct sockaddr *) &dev->backend_udp_dest, - (socklen_t *)&slen); - if (rc == -1) { - vubr_die("recvfrom()"); + for (cur = front; front != iov; cur++) { + bytes -= cur->iov_len; } - return rc; + cur->iov_base -= bytes; + cur->iov_len += bytes; } static void -vubr_consume_raw_packet(VubrDev *dev, uint8_t *buf, uint32_t len) +iov_truncate(struct iovec *iov, unsigned iovc, size_t bytes) { - int hdrlen = dev->hdrlen; - DPRINT(" hdrlen = %d\n", dev->hdrlen); + unsigned i; - if (VHOST_USER_BRIDGE_DEBUG) { - print_buffer(buf, len); - } - vubr_backend_udp_sendbuf(dev, buf + hdrlen, len - hdrlen); -} + for (i = 0; i < iovc; i++, iov++) { + if (bytes < iov->iov_len) { + iov->iov_len = bytes; + return; + } -/* Kick the log_call_fd if required. */ -static void -vubr_log_kick(VubrDev *dev) -{ - if (dev->log_call_fd != -1) { - DPRINT("Kicking the QEMU's log...\n"); - eventfd_write(dev->log_call_fd, 1); + bytes -= iov->iov_len; } -} -/* Kick the guest if necessary. */ -static void -vubr_virtqueue_kick(VubrVirtq *vq) -{ - if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { - DPRINT("Kicking the guest...\n"); - eventfd_write(vq->call_fd, 1); - } + assert(!"couldn't truncate iov"); } static void -vubr_log_page(uint8_t *log_table, uint64_t page) +vubr_backend_recv_cb(int sock, void *ctx) { - DPRINT("Logged dirty guest page: %"PRId64"\n", page); - atomic_or(&log_table[page / 8], 1 << (page % 8)); -} + VubrDev *vubr = (VubrDev *) ctx; + VuDev *dev = &vubr->vudev; + VuVirtq *vq = vu_get_queue(dev, 0); + VuVirtqElement *elem = NULL; + struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; + struct virtio_net_hdr_mrg_rxbuf mhdr; + unsigned mhdr_cnt = 0; + int hdrlen = vubr->hdrlen; + int i = 0; + struct virtio_net_hdr hdr = { + .flags = 0, + .gso_type = VIRTIO_NET_HDR_GSO_NONE + }; -static void -vubr_log_write(VubrDev *dev, uint64_t address, uint64_t length) -{ - uint64_t page; + DPRINT("\n\n *** IN UDP RECEIVE CALLBACK ***\n\n"); + DPRINT(" hdrlen = %d\n", hdrlen); - if (!(dev->features & (1ULL << VHOST_F_LOG_ALL)) || - !dev->log_table || !length) { + if (!vu_queue_enabled(dev, vq) || + !vu_queue_avail_bytes(dev, vq, hdrlen, 0)) { + DPRINT("Got UDP packet, but no available descriptors on RX virtq.\n"); return; } - assert(dev->log_size > ((address + length - 1) / VHOST_LOG_PAGE / 8)); - - page = address / VHOST_LOG_PAGE; - while (page * VHOST_LOG_PAGE < address + length) { - vubr_log_page(dev->log_table, page); - page += VHOST_LOG_PAGE; - } - vubr_log_kick(dev); -} - -static void -vubr_post_buffer(VubrDev *dev, VubrVirtq *vq, uint8_t *buf, int32_t len) -{ - struct vring_desc *desc = vq->desc; - struct vring_avail *avail = vq->avail; - struct vring_used *used = vq->used; - uint64_t log_guest_addr = vq->log_guest_addr; - int32_t remaining_len = len; - - unsigned int size = vq->size; - - uint16_t avail_index = atomic_mb_read(&avail->idx); - - /* We check the available descriptors before posting the - * buffer, so here we assume that enough available - * descriptors. */ - assert(vq->last_avail_index != avail_index); - uint16_t a_index = vq->last_avail_index % size; - uint16_t u_index = vq->last_used_index % size; - uint16_t d_index = avail->ring[a_index]; - - int i = d_index; - uint32_t written_len = 0; - do { - DPRINT("Post packet to guest on vq:\n"); - DPRINT(" size = %d\n", vq->size); - DPRINT(" last_avail_index = %d\n", vq->last_avail_index); - DPRINT(" last_used_index = %d\n", vq->last_used_index); - DPRINT(" a_index = %d\n", a_index); - DPRINT(" u_index = %d\n", u_index); - DPRINT(" d_index = %d\n", d_index); - DPRINT(" desc[%d].addr = 0x%016"PRIx64"\n", i, desc[i].addr); - DPRINT(" desc[%d].len = %d\n", i, desc[i].len); - DPRINT(" desc[%d].flags = %d\n", i, desc[i].flags); - DPRINT(" avail->idx = %d\n", avail_index); - DPRINT(" used->idx = %d\n", used->idx); - - if (!(desc[i].flags & VRING_DESC_F_WRITE)) { - /* FIXME: we should find writable descriptor. */ - fprintf(stderr, "Error: descriptor is not writable. Exiting.\n"); - exit(1); - } - - void *chunk_start = (void *)(uintptr_t)gpa_to_va(dev, desc[i].addr); - uint32_t chunk_len = desc[i].len; - uint32_t chunk_write_len = MIN(remaining_len, chunk_len); + struct iovec *sg; + ssize_t ret, total = 0; + unsigned int num; - memcpy(chunk_start, buf + written_len, chunk_write_len); - vubr_log_write(dev, desc[i].addr, chunk_write_len); - remaining_len -= chunk_write_len; - written_len += chunk_write_len; - - if ((remaining_len == 0) || !(desc[i].flags & VRING_DESC_F_NEXT)) { + elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); + if (!elem) { break; } - i = desc[i].next; - } while (1); - - if (remaining_len > 0) { - fprintf(stderr, - "Too long packet for RX, remaining_len = %d, Dropping...\n", - remaining_len); - return; - } - - /* Add descriptor to the used ring. */ - used->ring[u_index].id = d_index; - used->ring[u_index].len = len; - vubr_log_write(dev, - log_guest_addr + offsetof(struct vring_used, ring[u_index]), - sizeof(used->ring[u_index])); - - vq->last_avail_index++; - vq->last_used_index++; - - atomic_mb_set(&used->idx, vq->last_used_index); - vubr_log_write(dev, - log_guest_addr + offsetof(struct vring_used, idx), - sizeof(used->idx)); - - /* Kick the guest if necessary. */ - vubr_virtqueue_kick(vq); -} - -static int -vubr_process_desc(VubrDev *dev, VubrVirtq *vq) -{ - struct vring_desc *desc = vq->desc; - struct vring_avail *avail = vq->avail; - struct vring_used *used = vq->used; - uint64_t log_guest_addr = vq->log_guest_addr; - - unsigned int size = vq->size; - - uint16_t a_index = vq->last_avail_index % size; - uint16_t u_index = vq->last_used_index % size; - uint16_t d_index = avail->ring[a_index]; - - uint32_t i, len = 0; - size_t buf_size = 4096; - uint8_t buf[4096]; - - DPRINT("Chunks: "); - i = d_index; - do { - void *chunk_start = (void *)(uintptr_t)gpa_to_va(dev, desc[i].addr); - uint32_t chunk_len = desc[i].len; - - assert(!(desc[i].flags & VRING_DESC_F_WRITE)); - - if (len + chunk_len < buf_size) { - memcpy(buf + len, chunk_start, chunk_len); - DPRINT("%d ", chunk_len); - } else { - fprintf(stderr, "Error: too long packet. Dropping...\n"); + if (elem->in_num < 1) { + fprintf(stderr, "virtio-net contains no in buffers\n"); break; } - len += chunk_len; - - if (!(desc[i].flags & VRING_DESC_F_NEXT)) { - break; + sg = elem->in_sg; + num = elem->in_num; + if (i == 0) { + if (hdrlen == 12) { + mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg), + sg, elem->in_num, + offsetof(typeof(mhdr), num_buffers), + sizeof(mhdr.num_buffers)); + } + iov_from_buf(sg, elem->in_num, 0, &hdr, sizeof hdr); + total += hdrlen; + assert(iov_discard_front(&sg, &num, hdrlen) == hdrlen); } - i = desc[i].next; - } while (1); - DPRINT("\n"); - - if (!len) { - return -1; - } - - /* Add descriptor to the used ring. */ - used->ring[u_index].id = d_index; - used->ring[u_index].len = len; - vubr_log_write(dev, - log_guest_addr + offsetof(struct vring_used, ring[u_index]), - sizeof(used->ring[u_index])); - - vubr_consume_raw_packet(dev, buf, len); - - return 0; -} + struct msghdr msg = { + .msg_name = (struct sockaddr *) &vubr->backend_udp_dest, + .msg_namelen = sizeof(struct sockaddr_in), + .msg_iov = sg, + .msg_iovlen = elem->in_num, + .msg_flags = MSG_DONTWAIT, + }; + do { + ret = recvmsg(vubr->backend_udp_sock, &msg, 0); + } while (ret == -1 && (errno == EINTR)); -static void -vubr_process_avail(VubrDev *dev, VubrVirtq *vq) -{ - struct vring_avail *avail = vq->avail; - struct vring_used *used = vq->used; - uint64_t log_guest_addr = vq->log_guest_addr; - - while (vq->last_avail_index != atomic_mb_read(&avail->idx)) { - vubr_process_desc(dev, vq); - vq->last_avail_index++; - vq->last_used_index++; - } + if (i == 0) { + iov_restore_front(elem->in_sg, sg, hdrlen); + } - atomic_mb_set(&used->idx, vq->last_used_index); - vubr_log_write(dev, - log_guest_addr + offsetof(struct vring_used, idx), - sizeof(used->idx)); -} + if (ret == -1) { + if (errno == EWOULDBLOCK) { + vu_queue_rewind(dev, vq, 1); + break; + } -static void -vubr_backend_recv_cb(int sock, void *ctx) -{ - VubrDev *dev = (VubrDev *) ctx; - VubrVirtq *rx_vq = &dev->vq[0]; - uint8_t buf[4096]; - struct virtio_net_hdr_v1 *hdr = (struct virtio_net_hdr_v1 *)buf; - int hdrlen = dev->hdrlen; - int buflen = sizeof(buf); - int len; - - if (!dev->ready) { - return; - } + vubr_die("recvmsg()"); + } - DPRINT("\n\n *** IN UDP RECEIVE CALLBACK ***\n\n"); - DPRINT(" hdrlen = %d\n", hdrlen); + total += ret; + iov_truncate(elem->in_sg, elem->in_num, total); + vu_queue_fill(dev, vq, elem, total, i++); - uint16_t avail_index = atomic_mb_read(&rx_vq->avail->idx); + free(elem); + elem = NULL; + } while (false); /* could loop if DONTWAIT worked? */ - /* If there is no available descriptors, just do nothing. - * The buffer will be handled by next arrived UDP packet, - * or next kick on receive virtq. */ - if (rx_vq->last_avail_index == avail_index) { - DPRINT("Got UDP packet, but no available descriptors on RX virtq.\n"); - return; + if (mhdr_cnt) { + mhdr.num_buffers = i; + iov_from_buf(mhdr_sg, mhdr_cnt, + 0, + &mhdr.num_buffers, sizeof mhdr.num_buffers); } - memset(buf, 0, hdrlen); - /* TODO: support mergeable buffers. */ - if (hdrlen == 12) - hdr->num_buffers = 1; - len = vubr_backend_udp_recvbuf(dev, buf + hdrlen, buflen - hdrlen); + vu_queue_flush(dev, vq, i); + vu_queue_notify(dev, vq); - vubr_post_buffer(dev, rx_vq, buf, len + hdrlen); + free(elem); } static void -vubr_kick_cb(int sock, void *ctx) +vubr_receive_cb(int sock, void *ctx) { - VubrDev *dev = (VubrDev *) ctx; - eventfd_t kick_data; - ssize_t rc; + VubrDev *vubr = (VubrDev *)ctx; - rc = eventfd_read(sock, &kick_data); - if (rc == -1) { - vubr_die("eventfd_read()"); - } else { - DPRINT("Got kick_data: %016"PRIx64"\n", kick_data); - vubr_process_avail(dev, &dev->vq[1]); + if (!vu_dispatch(&vubr->vudev)) { + fprintf(stderr, "Error while dispatching\n"); } } -static int -vubr_none_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - DPRINT("Function %s() not implemented yet.\n", __func__); - return 0; -} +typedef struct WatchData { + VuDev *dev; + vu_watch_cb cb; + void *data; +} WatchData; -static int -vubr_get_features_exec(VubrDev *dev, VhostUserMsg *vmsg) +static void +watch_cb(int sock, void *ctx) { - vmsg->payload.u64 = - ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | - (1ULL << VHOST_F_LOG_ALL) | - (1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE) | - (1ULL << VHOST_USER_F_PROTOCOL_FEATURES)); - - vmsg->size = sizeof(vmsg->payload.u64); + struct WatchData *wd = ctx; - DPRINT("Sending back to guest u64: 0x%016"PRIx64"\n", vmsg->payload.u64); - - /* Reply */ - return 1; + wd->cb(wd->dev, VU_WATCH_IN, wd->data); } -static int -vubr_set_features_exec(VubrDev *dev, VhostUserMsg *vmsg) +static void +vubr_set_watch(VuDev *dev, int fd, int condition, + vu_watch_cb cb, void *data) { - DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); - - dev->features = vmsg->payload.u64; - if ((dev->features & (1ULL << VIRTIO_F_VERSION_1)) || - (dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) { - dev->hdrlen = 12; - } else { - dev->hdrlen = 10; - } + VubrDev *vubr = container_of(dev, VubrDev, vudev); + static WatchData watches[FD_SETSIZE]; + struct WatchData *wd = &watches[fd]; - return 0; -} - -static int -vubr_set_owner_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - return 0; + wd->cb = cb; + wd->data = data; + wd->dev = dev; + dispatcher_add(&vubr->dispatcher, fd, wd, watch_cb); } static void -vubr_close_log(VubrDev *dev) +vubr_remove_watch(VuDev *dev, int fd) { - if (dev->log_table) { - if (munmap(dev->log_table, dev->log_size) != 0) { - vubr_die("munmap()"); - } + VubrDev *vubr = container_of(dev, VubrDev, vudev); - dev->log_table = 0; - } - if (dev->log_call_fd != -1) { - close(dev->log_call_fd); - dev->log_call_fd = -1; - } -} - -static int -vubr_reset_device_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - vubr_close_log(dev); - dev->ready = 0; - dev->features = 0; - return 0; + dispatcher_remove(&vubr->dispatcher, fd); } static int -vubr_set_mem_table_exec(VubrDev *dev, VhostUserMsg *vmsg) +vubr_send_rarp_exec(VuDev *dev, VhostUserMsg *vmsg) { - int i; - VhostUserMemory *memory = &vmsg->payload.memory; - dev->nregions = memory->nregions; - - DPRINT("Nregions: %d\n", memory->nregions); - for (i = 0; i < dev->nregions; i++) { - void *mmap_addr; - VhostUserMemoryRegion *msg_region = &memory->regions[i]; - VubrDevRegion *dev_region = &dev->regions[i]; - - DPRINT("Region %d\n", i); - DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n", - msg_region->guest_phys_addr); - DPRINT(" memory_size: 0x%016"PRIx64"\n", - msg_region->memory_size); - DPRINT(" userspace_addr 0x%016"PRIx64"\n", - msg_region->userspace_addr); - DPRINT(" mmap_offset 0x%016"PRIx64"\n", - msg_region->mmap_offset); - - dev_region->gpa = msg_region->guest_phys_addr; - dev_region->size = msg_region->memory_size; - dev_region->qva = msg_region->userspace_addr; - dev_region->mmap_offset = msg_region->mmap_offset; - - /* We don't use offset argument of mmap() since the - * mapped address has to be page aligned, and we use huge - * pages. */ - mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset, - PROT_READ | PROT_WRITE, MAP_SHARED, - vmsg->fds[i], 0); - - if (mmap_addr == MAP_FAILED) { - vubr_die("mmap"); - } - dev_region->mmap_addr = (uint64_t)(uintptr_t)mmap_addr; - DPRINT(" mmap_addr: 0x%016"PRIx64"\n", dev_region->mmap_addr); - - close(vmsg->fds[i]); - } - + DPRINT("Function %s() not implemented yet.\n", __func__); return 0; } static int -vubr_set_log_base_exec(VubrDev *dev, VhostUserMsg *vmsg) +vubr_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply) { - int fd; - uint64_t log_mmap_size, log_mmap_offset; - void *rc; - - assert(vmsg->fd_num == 1); - fd = vmsg->fds[0]; - - assert(vmsg->size == sizeof(vmsg->payload.log)); - log_mmap_offset = vmsg->payload.log.mmap_offset; - log_mmap_size = vmsg->payload.log.mmap_size; - DPRINT("Log mmap_offset: %"PRId64"\n", log_mmap_offset); - DPRINT("Log mmap_size: %"PRId64"\n", log_mmap_size); - - rc = mmap(0, log_mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, - log_mmap_offset); - if (rc == MAP_FAILED) { - vubr_die("mmap"); + switch (vmsg->request) { + case VHOST_USER_SEND_RARP: + *do_reply = vubr_send_rarp_exec(dev, vmsg); + return 1; + default: + /* let the library handle the rest */ + return 0; } - dev->log_table = rc; - dev->log_size = log_mmap_size; - vmsg->size = sizeof(vmsg->payload.u64); - /* Reply */ - return 1; -} - -static int -vubr_set_log_fd_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - assert(vmsg->fd_num == 1); - dev->log_call_fd = vmsg->fds[0]; - DPRINT("Got log_call_fd: %d\n", vmsg->fds[0]); return 0; } -static int -vubr_set_vring_num_exec(VubrDev *dev, VhostUserMsg *vmsg) +static void +vubr_set_features(VuDev *dev, uint64_t features) { - unsigned int index = vmsg->payload.state.index; - unsigned int num = vmsg->payload.state.num; - - DPRINT("State.index: %d\n", index); - DPRINT("State.num: %d\n", num); - dev->vq[index].size = num; - return 0; -} + VubrDev *vubr = container_of(dev, VubrDev, vudev); -static int -vubr_set_vring_addr_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - struct vhost_vring_addr *vra = &vmsg->payload.addr; - unsigned int index = vra->index; - VubrVirtq *vq = &dev->vq[index]; - - DPRINT("vhost_vring_addr:\n"); - DPRINT(" index: %d\n", vra->index); - DPRINT(" flags: %d\n", vra->flags); - DPRINT(" desc_user_addr: 0x%016llx\n", vra->desc_user_addr); - DPRINT(" used_user_addr: 0x%016llx\n", vra->used_user_addr); - DPRINT(" avail_user_addr: 0x%016llx\n", vra->avail_user_addr); - DPRINT(" log_guest_addr: 0x%016llx\n", vra->log_guest_addr); - - vq->desc = (struct vring_desc *)(uintptr_t)qva_to_va(dev, vra->desc_user_addr); - vq->used = (struct vring_used *)(uintptr_t)qva_to_va(dev, vra->used_user_addr); - vq->avail = (struct vring_avail *)(uintptr_t)qva_to_va(dev, vra->avail_user_addr); - vq->log_guest_addr = vra->log_guest_addr; - - DPRINT("Setting virtq addresses:\n"); - DPRINT(" vring_desc at %p\n", vq->desc); - DPRINT(" vring_used at %p\n", vq->used); - DPRINT(" vring_avail at %p\n", vq->avail); - - vq->last_used_index = vq->used->idx; - - if (vq->last_avail_index != vq->used->idx) { - DPRINT("Last avail index != used index: %d != %d, resuming", - vq->last_avail_index, vq->used->idx); - vq->last_avail_index = vq->used->idx; + if ((features & (1ULL << VIRTIO_F_VERSION_1)) || + (features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) { + vubr->hdrlen = 12; + } else { + vubr->hdrlen = 10; } - - return 0; } -static int -vubr_set_vring_base_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - unsigned int index = vmsg->payload.state.index; - unsigned int num = vmsg->payload.state.num; - - DPRINT("State.index: %d\n", index); - DPRINT("State.num: %d\n", num); - dev->vq[index].last_avail_index = num; - - return 0; -} - -static int -vubr_get_vring_base_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - unsigned int index = vmsg->payload.state.index; - - DPRINT("State.index: %d\n", index); - vmsg->payload.state.num = dev->vq[index].last_avail_index; - vmsg->size = sizeof(vmsg->payload.state); - /* FIXME: this is a work-around for a bug in QEMU enabling - * too early vrings. When protocol features are enabled, - * we have to respect * VHOST_USER_SET_VRING_ENABLE request. */ - dev->ready = 0; - - if (dev->vq[index].call_fd != -1) { - close(dev->vq[index].call_fd); - dispatcher_remove(&dev->dispatcher, dev->vq[index].call_fd); - dev->vq[index].call_fd = -1; - } - if (dev->vq[index].kick_fd != -1) { - close(dev->vq[index].kick_fd); - dispatcher_remove(&dev->dispatcher, dev->vq[index].kick_fd); - dev->vq[index].kick_fd = -1; - } - - /* Reply */ - return 1; -} - -static int -vubr_set_vring_kick_exec(VubrDev *dev, VhostUserMsg *vmsg) +static uint64_t +vubr_get_features(VuDev *dev) { - uint64_t u64_arg = vmsg->payload.u64; - int index = u64_arg & VHOST_USER_VRING_IDX_MASK; - - DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); - - assert((u64_arg & VHOST_USER_VRING_NOFD_MASK) == 0); - assert(vmsg->fd_num == 1); - - if (dev->vq[index].kick_fd != -1) { - close(dev->vq[index].kick_fd); - dispatcher_remove(&dev->dispatcher, dev->vq[index].kick_fd); - } - dev->vq[index].kick_fd = vmsg->fds[0]; - DPRINT("Got kick_fd: %d for vq: %d\n", vmsg->fds[0], index); - - if (index % 2 == 1) { - /* TX queue. */ - dispatcher_add(&dev->dispatcher, dev->vq[index].kick_fd, - dev, vubr_kick_cb); - - DPRINT("Waiting for kicks on fd: %d for vq: %d\n", - dev->vq[index].kick_fd, index); - } - /* We temporarily use this hack to determine that both TX and RX - * queues are set up and ready for processing. - * FIXME: we need to rely in VHOST_USER_SET_VRING_ENABLE and - * actual kicks. */ - if (dev->vq[0].kick_fd != -1 && - dev->vq[1].kick_fd != -1) { - dev->ready = 1; - DPRINT("vhost-user-bridge is ready for processing queues.\n"); - } - return 0; - + return 1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE | + 1ULL << VIRTIO_NET_F_MRG_RXBUF; } -static int -vubr_set_vring_call_exec(VubrDev *dev, VhostUserMsg *vmsg) +static void +vubr_queue_set_started(VuDev *dev, int qidx, bool started) { - uint64_t u64_arg = vmsg->payload.u64; - int index = u64_arg & VHOST_USER_VRING_IDX_MASK; + VuVirtq *vq = vu_get_queue(dev, qidx); - DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); - assert((u64_arg & VHOST_USER_VRING_NOFD_MASK) == 0); - assert(vmsg->fd_num == 1); - - if (dev->vq[index].call_fd != -1) { - close(dev->vq[index].call_fd); - dispatcher_remove(&dev->dispatcher, dev->vq[index].call_fd); + if (qidx % 2 == 1) { + vu_set_queue_handler(dev, vq, started ? vubr_handle_tx : NULL); } - dev->vq[index].call_fd = vmsg->fds[0]; - DPRINT("Got call_fd: %d for vq: %d\n", vmsg->fds[0], index); - - return 0; -} - -static int -vubr_set_vring_err_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); - return 0; -} - -static int -vubr_get_protocol_features_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - vmsg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD; - DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); - vmsg->size = sizeof(vmsg->payload.u64); - - /* Reply */ - return 1; } -static int -vubr_set_protocol_features_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - /* FIXME: unimplented */ - DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); - return 0; -} - -static int -vubr_get_queue_num_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - DPRINT("Function %s() not implemented yet.\n", __func__); - return 0; -} - -static int -vubr_set_vring_enable_exec(VubrDev *dev, VhostUserMsg *vmsg) +static void +vubr_panic(VuDev *dev, const char *msg) { - unsigned int index = vmsg->payload.state.index; - unsigned int enable = vmsg->payload.state.num; + VubrDev *vubr = container_of(dev, VubrDev, vudev); - DPRINT("State.index: %d\n", index); - DPRINT("State.enable: %d\n", enable); - dev->vq[index].enable = enable; - return 0; -} + fprintf(stderr, "PANIC: %s\n", msg); -static int -vubr_send_rarp_exec(VubrDev *dev, VhostUserMsg *vmsg) -{ - DPRINT("Function %s() not implemented yet.\n", __func__); - return 0; + dispatcher_remove(&vubr->dispatcher, dev->sock); + vubr->quit = 1; } -static int -vubr_execute_request(VubrDev *dev, VhostUserMsg *vmsg) -{ - /* Print out generic part of the request. */ - DPRINT( - "================== Vhost user message from QEMU ==================\n"); - DPRINT("Request: %s (%d)\n", vubr_request_str[vmsg->request], - vmsg->request); - DPRINT("Flags: 0x%x\n", vmsg->flags); - DPRINT("Size: %d\n", vmsg->size); - - if (vmsg->fd_num) { - int i; - DPRINT("Fds:"); - for (i = 0; i < vmsg->fd_num; i++) { - DPRINT(" %d", vmsg->fds[i]); - } - DPRINT("\n"); - } - - switch (vmsg->request) { - case VHOST_USER_NONE: - return vubr_none_exec(dev, vmsg); - case VHOST_USER_GET_FEATURES: - return vubr_get_features_exec(dev, vmsg); - case VHOST_USER_SET_FEATURES: - return vubr_set_features_exec(dev, vmsg); - case VHOST_USER_SET_OWNER: - return vubr_set_owner_exec(dev, vmsg); - case VHOST_USER_RESET_OWNER: - return vubr_reset_device_exec(dev, vmsg); - case VHOST_USER_SET_MEM_TABLE: - return vubr_set_mem_table_exec(dev, vmsg); - case VHOST_USER_SET_LOG_BASE: - return vubr_set_log_base_exec(dev, vmsg); - case VHOST_USER_SET_LOG_FD: - return vubr_set_log_fd_exec(dev, vmsg); - case VHOST_USER_SET_VRING_NUM: - return vubr_set_vring_num_exec(dev, vmsg); - case VHOST_USER_SET_VRING_ADDR: - return vubr_set_vring_addr_exec(dev, vmsg); - case VHOST_USER_SET_VRING_BASE: - return vubr_set_vring_base_exec(dev, vmsg); - case VHOST_USER_GET_VRING_BASE: - return vubr_get_vring_base_exec(dev, vmsg); - case VHOST_USER_SET_VRING_KICK: - return vubr_set_vring_kick_exec(dev, vmsg); - case VHOST_USER_SET_VRING_CALL: - return vubr_set_vring_call_exec(dev, vmsg); - case VHOST_USER_SET_VRING_ERR: - return vubr_set_vring_err_exec(dev, vmsg); - case VHOST_USER_GET_PROTOCOL_FEATURES: - return vubr_get_protocol_features_exec(dev, vmsg); - case VHOST_USER_SET_PROTOCOL_FEATURES: - return vubr_set_protocol_features_exec(dev, vmsg); - case VHOST_USER_GET_QUEUE_NUM: - return vubr_get_queue_num_exec(dev, vmsg); - case VHOST_USER_SET_VRING_ENABLE: - return vubr_set_vring_enable_exec(dev, vmsg); - case VHOST_USER_SEND_RARP: - return vubr_send_rarp_exec(dev, vmsg); - - case VHOST_USER_MAX: - assert(vmsg->request != VHOST_USER_MAX); - } - return 0; -} - -static void -vubr_receive_cb(int sock, void *ctx) -{ - VubrDev *dev = (VubrDev *) ctx; - VhostUserMsg vmsg; - int reply_requested; - - vubr_message_read(sock, &vmsg); - reply_requested = vubr_execute_request(dev, &vmsg); - if (reply_requested) { - /* Set the version in the flags when sending the reply */ - vmsg.flags &= ~VHOST_USER_VERSION_MASK; - vmsg.flags |= VHOST_USER_VERSION; - vmsg.flags |= VHOST_USER_REPLY_MASK; - vubr_message_write(sock, &vmsg); - } -} +static const VuDevIface vuiface = { + .get_features = vubr_get_features, + .set_features = vubr_set_features, + .process_msg = vubr_process_msg, + .queue_set_started = vubr_queue_set_started, +}; static void vubr_accept_cb(int sock, void *ctx) @@ -1204,36 +479,26 @@ vubr_accept_cb(int sock, void *ctx) vubr_die("accept()"); } DPRINT("Got connection from remote peer on sock %d\n", conn_fd); + + vu_init(&dev->vudev, + conn_fd, + vubr_panic, + vubr_set_watch, + vubr_remove_watch, + &vuiface); + dispatcher_add(&dev->dispatcher, conn_fd, ctx, vubr_receive_cb); + dispatcher_remove(&dev->dispatcher, sock); } static VubrDev * vubr_new(const char *path, bool client) { VubrDev *dev = (VubrDev *) calloc(1, sizeof(VubrDev)); - dev->nregions = 0; - int i; struct sockaddr_un un; CallbackFunc cb; size_t len; - for (i = 0; i < MAX_NR_VIRTQUEUE; i++) { - dev->vq[i] = (VubrVirtq) { - .call_fd = -1, .kick_fd = -1, - .size = 0, - .last_avail_index = 0, .last_used_index = 0, - .desc = 0, .avail = 0, .used = 0, - .enable = 0, - }; - } - - /* Init log */ - dev->log_call_fd = -1; - dev->log_size = 0; - dev->log_table = 0; - dev->ready = 0; - dev->features = 0; - /* Get a UNIX socket. */ dev->sock = socket(AF_UNIX, SOCK_STREAM, 0); if (dev->sock == -1) { @@ -1261,10 +526,17 @@ vubr_new(const char *path, bool client) if (connect(dev->sock, (struct sockaddr *)&un, len) == -1) { vubr_die("connect"); } + vu_init(&dev->vudev, + dev->sock, + vubr_panic, + vubr_set_watch, + vubr_remove_watch, + &vuiface); cb = vubr_receive_cb; } dispatcher_init(&dev->dispatcher); + dispatcher_add(&dev->dispatcher, dev->sock, (void *)dev, cb); return dev; @@ -1345,7 +617,7 @@ vubr_backend_udp_setup(VubrDev *dev, static void vubr_run(VubrDev *dev) { - while (1) { + while (!dev->quit) { /* timeout 200ms */ dispatcher_wait(&dev->dispatcher, 200000); /* Here one can try polling strategy. */ @@ -1421,6 +693,9 @@ main(int argc, char *argv[]) vubr_backend_udp_setup(dev, lhost, lport, rhost, rport); vubr_run(dev); + + vu_deinit(&dev->vudev); + return 0; out: diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 9c4f6cb406..060407b20e 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -16,61 +16,53 @@ #include "libqos/virtio-pci.h" #include "standard-headers/linux/virtio_ids.h" #include "standard-headers/linux/virtio_pci.h" +#include "hw/9pfs/9p.h" static const char mount_tag[] = "qtest"; -static char *test_share; +typedef struct { + QVirtioDevice *dev; + QOSState *qs; + QVirtQueue *vq; + char *test_share; + uint16_t p9_req_tag; +} QVirtIO9P; -static QOSState *qvirtio_9p_start(void) +static QVirtIO9P *qvirtio_9p_start(const char *driver) { const char *arch = qtest_get_arch(); const char *cmd = "-fsdev local,id=fsdev0,security_model=none,path=%s " - "-device virtio-9p-pci,fsdev=fsdev0,mount_tag=%s"; + "-device %s,fsdev=fsdev0,mount_tag=%s"; + QVirtIO9P *v9p = g_new0(QVirtIO9P, 1); - test_share = g_strdup("/tmp/qtest.XXXXXX"); - g_assert_nonnull(mkdtemp(test_share)); + v9p->test_share = g_strdup("/tmp/qtest.XXXXXX"); + g_assert_nonnull(mkdtemp(v9p->test_share)); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - return qtest_pc_boot(cmd, test_share, mount_tag); - } - if (strcmp(arch, "ppc64") == 0) { - return qtest_spapr_boot(cmd, test_share, mount_tag); + v9p->qs = qtest_pc_boot(cmd, v9p->test_share, driver, mount_tag); + } else if (strcmp(arch, "ppc64") == 0) { + v9p->qs = qtest_spapr_boot(cmd, v9p->test_share, driver, mount_tag); + } else { + g_printerr("virtio-9p tests are only available on x86 or ppc64\n"); + exit(EXIT_FAILURE); } - g_printerr("virtio-9p tests are only available on x86 or ppc64\n"); - exit(EXIT_FAILURE); -} - -static void qvirtio_9p_stop(QOSState *qs) -{ - qtest_shutdown(qs); - rmdir(test_share); - g_free(test_share); + return v9p; } -static void pci_nop(void) +static void qvirtio_9p_stop(QVirtIO9P *v9p) { - QOSState *qs; - - qs = qvirtio_9p_start(); - qvirtio_9p_stop(qs); + qtest_shutdown(v9p->qs); + rmdir(v9p->test_share); + g_free(v9p->test_share); + g_free(v9p); } -typedef struct { - QVirtioDevice *dev; - QOSState *qs; - QVirtQueue *vq; -} QVirtIO9P; - -static QVirtIO9P *qvirtio_9p_pci_init(QOSState *qs) +static QVirtIO9P *qvirtio_9p_pci_start(void) { - QVirtIO9P *v9p; - QVirtioPCIDevice *dev; - - v9p = g_new0(QVirtIO9P, 1); - - v9p->qs = qs; - dev = qvirtio_pci_device_find(v9p->qs->pcibus, VIRTIO_ID_9P); + QVirtIO9P *v9p = qvirtio_9p_start("virtio-9p-pci"); + QVirtioPCIDevice *dev = qvirtio_pci_device_find(v9p->qs->pcibus, + VIRTIO_ID_9P); g_assert_nonnull(dev); g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_9P); v9p->dev = (QVirtioDevice *) dev; @@ -84,26 +76,20 @@ static QVirtIO9P *qvirtio_9p_pci_init(QOSState *qs) return v9p; } -static void qvirtio_9p_pci_free(QVirtIO9P *v9p) +static void qvirtio_9p_pci_stop(QVirtIO9P *v9p) { qvirtqueue_cleanup(v9p->dev->bus, v9p->vq, v9p->qs->alloc); qvirtio_pci_device_disable(container_of(v9p->dev, QVirtioPCIDevice, vdev)); g_free(v9p->dev); - g_free(v9p); + qvirtio_9p_stop(v9p); } -static void pci_basic_config(void) +static void pci_config(QVirtIO9P *v9p) { - QVirtIO9P *v9p; - size_t tag_len; + size_t tag_len = qvirtio_config_readw(v9p->dev, 0); char *tag; int i; - QOSState *qs; - qs = qvirtio_9p_start(); - v9p = qvirtio_9p_pci_init(qs); - - tag_len = qvirtio_config_readw(v9p->dev, 0); g_assert_cmpint(tag_len, ==, strlen(mount_tag)); tag = g_malloc(tag_len); @@ -112,16 +98,406 @@ static void pci_basic_config(void) } g_assert_cmpmem(tag, tag_len, mount_tag, tag_len); g_free(tag); +} + +#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */ + +typedef struct { + QVirtIO9P *v9p; + uint16_t tag; + uint64_t t_msg; + uint32_t t_size; + uint64_t r_msg; + /* No r_size, it is hardcoded to P9_MAX_SIZE */ + size_t t_off; + size_t r_off; +} P9Req; + +static void v9fs_memwrite(P9Req *req, const void *addr, size_t len) +{ + memwrite(req->t_msg + req->t_off, addr, len); + req->t_off += len; +} + +static void v9fs_memskip(P9Req *req, size_t len) +{ + req->r_off += len; +} + +static void v9fs_memrewind(P9Req *req, size_t len) +{ + req->r_off -= len; +} + +static void v9fs_memread(P9Req *req, void *addr, size_t len) +{ + memread(req->r_msg + req->r_off, addr, len); + req->r_off += len; +} + +static void v9fs_uint16_write(P9Req *req, uint16_t val) +{ + uint16_t le_val = cpu_to_le16(val); + + v9fs_memwrite(req, &le_val, 2); +} + +static void v9fs_uint16_read(P9Req *req, uint16_t *val) +{ + v9fs_memread(req, val, 2); + le16_to_cpus(val); +} + +static void v9fs_uint32_write(P9Req *req, uint32_t val) +{ + uint32_t le_val = cpu_to_le32(val); + + v9fs_memwrite(req, &le_val, 4); +} + +static void v9fs_uint32_read(P9Req *req, uint32_t *val) +{ + v9fs_memread(req, val, 4); + le32_to_cpus(val); +} + +/* len[2] string[len] */ +static uint16_t v9fs_string_size(const char *string) +{ + size_t len = strlen(string); + + g_assert_cmpint(len, <=, UINT16_MAX); + + return 2 + len; +} + +static void v9fs_string_write(P9Req *req, const char *string) +{ + int len = strlen(string); + + g_assert_cmpint(len, <=, UINT16_MAX); + + v9fs_uint16_write(req, (uint16_t) len); + v9fs_memwrite(req, string, len); +} + +static void v9fs_string_read(P9Req *req, uint16_t *len, char **string) +{ + uint16_t local_len; + + v9fs_uint16_read(req, &local_len); + if (len) { + *len = local_len; + } + if (string) { + *string = g_malloc(local_len); + v9fs_memread(req, *string, local_len); + } else { + v9fs_memskip(req, local_len); + } +} + + typedef struct { + uint32_t size; + uint8_t id; + uint16_t tag; +} QEMU_PACKED P9Hdr; + +static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id, + uint16_t tag) +{ + P9Req *req = g_new0(P9Req, 1); + uint32_t t_size = 7 + size; /* 9P header has well-known size of 7 bytes */ + P9Hdr hdr = { + .size = cpu_to_le32(t_size), + .id = id, + .tag = cpu_to_le16(tag) + }; + + g_assert_cmpint(t_size, <=, P9_MAX_SIZE); - qvirtio_9p_pci_free(v9p); - qvirtio_9p_stop(qs); + req->v9p = v9p; + req->t_size = t_size; + req->t_msg = guest_alloc(v9p->qs->alloc, req->t_size); + v9fs_memwrite(req, &hdr, 7); + req->tag = tag; + return req; +} + +static void v9fs_req_send(P9Req *req) +{ + QVirtIO9P *v9p = req->v9p; + uint32_t free_head; + + req->r_msg = guest_alloc(v9p->qs->alloc, P9_MAX_SIZE); + free_head = qvirtqueue_add(v9p->vq, req->t_msg, req->t_size, false, true); + qvirtqueue_add(v9p->vq, req->r_msg, P9_MAX_SIZE, true, false); + qvirtqueue_kick(v9p->dev, v9p->vq, free_head); + req->t_off = 0; +} + +static void v9fs_req_recv(P9Req *req, uint8_t id) +{ + QVirtIO9P *v9p = req->v9p; + P9Hdr hdr; + int i; + + for (i = 0; i < 10; i++) { + qvirtio_wait_queue_isr(v9p->dev, v9p->vq, 1000 * 1000); + + v9fs_memread(req, &hdr, 7); + le32_to_cpus(&hdr.size); + le16_to_cpus(&hdr.tag); + if (hdr.size >= 7) { + break; + } + v9fs_memrewind(req, 7); + } + + g_assert_cmpint(hdr.size, >=, 7); + g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE); + g_assert_cmpint(hdr.tag, ==, req->tag); + + if (hdr.id != id && hdr.id == P9_RLERROR) { + uint32_t err; + v9fs_uint32_read(req, &err); + g_printerr("Received Rlerror (%d) instead of Response %d\n", err, id); + g_assert_not_reached(); + } + g_assert_cmpint(hdr.id, ==, id); +} + +static void v9fs_req_free(P9Req *req) +{ + QVirtIO9P *v9p = req->v9p; + + guest_free(v9p->qs->alloc, req->t_msg); + guest_free(v9p->qs->alloc, req->r_msg); + g_free(req); +} + +/* size[4] Rlerror tag[2] ecode[4] */ +static void v9fs_rlerror(P9Req *req, uint32_t *err) +{ + v9fs_req_recv(req, P9_RLERROR); + v9fs_uint32_read(req, err); + v9fs_req_free(req); +} + +/* size[4] Tversion tag[2] msize[4] version[s] */ +static P9Req *v9fs_tversion(QVirtIO9P *v9p, uint32_t msize, const char *version) +{ + P9Req *req = v9fs_req_init(v9p, 4 + v9fs_string_size(version), P9_TVERSION, + P9_NOTAG); + + v9fs_uint32_write(req, msize); + v9fs_string_write(req, version); + v9fs_req_send(req); + return req; +} + +/* size[4] Rversion tag[2] msize[4] version[s] */ +static void v9fs_rversion(P9Req *req, uint16_t *len, char **version) +{ + uint32_t msize; + + v9fs_req_recv(req, P9_RVERSION); + v9fs_uint32_read(req, &msize); + + g_assert_cmpint(msize, ==, P9_MAX_SIZE); + + if (len || version) { + v9fs_string_read(req, len, version); + } + + v9fs_req_free(req); +} + +/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */ +static P9Req *v9fs_tattach(QVirtIO9P *v9p, uint32_t fid, uint32_t n_uname) +{ + const char *uname = ""; /* ignored by QEMU */ + const char *aname = ""; /* ignored by QEMU */ + P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, + ++(v9p->p9_req_tag)); + + v9fs_uint32_write(req, fid); + v9fs_uint32_write(req, P9_NOFID); + v9fs_string_write(req, uname); + v9fs_string_write(req, aname); + v9fs_uint32_write(req, n_uname); + v9fs_req_send(req); + return req; +} + +typedef char v9fs_qid[13]; + +/* size[4] Rattach tag[2] qid[13] */ +static void v9fs_rattach(P9Req *req, v9fs_qid *qid) +{ + v9fs_req_recv(req, P9_RATTACH); + if (qid) { + v9fs_memread(req, qid, 13); + } + v9fs_req_free(req); +} + +/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ +static P9Req *v9fs_twalk(QVirtIO9P *v9p, uint32_t fid, uint32_t newfid, + uint16_t nwname, char *const wnames[]) +{ + P9Req *req; + int i; + uint32_t size = 4 + 4 + 2; + + for (i = 0; i < nwname; i++) { + size += v9fs_string_size(wnames[i]); + } + req = v9fs_req_init(v9p, size, P9_TWALK, ++(v9p->p9_req_tag)); + v9fs_uint32_write(req, fid); + v9fs_uint32_write(req, newfid); + v9fs_uint16_write(req, nwname); + for (i = 0; i < nwname; i++) { + v9fs_string_write(req, wnames[i]); + } + v9fs_req_send(req); + return req; +} + +/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */ +static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid) +{ + uint16_t local_nwqid; + + v9fs_req_recv(req, P9_RWALK); + v9fs_uint16_read(req, &local_nwqid); + if (nwqid) { + *nwqid = local_nwqid; + } + if (wqid) { + *wqid = g_malloc(local_nwqid * 13); + v9fs_memread(req, *wqid, local_nwqid * 13); + } + v9fs_req_free(req); +} + +static void fs_version(QVirtIO9P *v9p) +{ + const char *version = "9P2000.L"; + uint16_t server_len; + char *server_version; + P9Req *req; + + req = v9fs_tversion(v9p, P9_MAX_SIZE, version); + v9fs_rversion(req, &server_len, &server_version); + + g_assert_cmpmem(server_version, server_len, version, strlen(version)); + + g_free(server_version); +} + +static void fs_attach(QVirtIO9P *v9p) +{ + P9Req *req; + + fs_version(v9p); + req = v9fs_tattach(v9p, 0, getuid()); + v9fs_rattach(req, NULL); +} + +static void fs_walk(QVirtIO9P *v9p) +{ + char *wnames[P9_MAXWELEM], *paths[P9_MAXWELEM]; + char *last_path = v9p->test_share; + uint16_t nwqid; + v9fs_qid *wqid; + int i; + P9Req *req; + + for (i = 0; i < P9_MAXWELEM; i++) { + wnames[i] = g_strdup_printf("%s%d", __func__, i); + last_path = paths[i] = g_strdup_printf("%s/%s", last_path, wnames[i]); + g_assert(!mkdir(paths[i], 0700)); + } + + fs_attach(v9p); + req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames); + v9fs_rwalk(req, &nwqid, &wqid); + + g_assert_cmpint(nwqid, ==, P9_MAXWELEM); + + for (i = 0; i < P9_MAXWELEM; i++) { + rmdir(paths[P9_MAXWELEM - i - 1]); + g_free(paths[P9_MAXWELEM - i - 1]); + g_free(wnames[i]); + } + + g_free(wqid); +} + +static void fs_walk_no_slash(QVirtIO9P *v9p) +{ + char *const wnames[] = { g_strdup(" /") }; + P9Req *req; + uint32_t err; + + fs_attach(v9p); + req = v9fs_twalk(v9p, 0, 1, 1, wnames); + v9fs_rlerror(req, &err); + + g_assert_cmpint(err, ==, ENOENT); + + g_free(wnames[0]); +} + +static void fs_walk_dotdot(QVirtIO9P *v9p) +{ + char *const wnames[] = { g_strdup("..") }; + v9fs_qid root_qid, *wqid; + P9Req *req; + + fs_version(v9p); + req = v9fs_tattach(v9p, 0, getuid()); + v9fs_rattach(req, &root_qid); + + req = v9fs_twalk(v9p, 0, 1, 1, wnames); + v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */ + + g_assert_cmpmem(&root_qid, 13, wqid[0], 13); + + g_free(wqid); + g_free(wnames[0]); +} + +typedef void (*v9fs_test_fn)(QVirtIO9P *v9p); + +static void v9fs_run_pci_test(gconstpointer data) +{ + v9fs_test_fn fn = data; + QVirtIO9P *v9p = qvirtio_9p_pci_start(); + + if (fn) { + fn(v9p); + } + qvirtio_9p_pci_stop(v9p); +} + +static void v9fs_qtest_pci_add(const char *path, v9fs_test_fn fn) +{ + qtest_add_data_func(path, fn, v9fs_run_pci_test); } int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); - qtest_add_func("/virtio/9p/pci/nop", pci_nop); - qtest_add_func("/virtio/9p/pci/basic/configuration", pci_basic_config); + v9fs_qtest_pci_add("/virtio/9p/pci/nop", NULL); + v9fs_qtest_pci_add("/virtio/9p/pci/config", pci_config); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/version/basic", fs_version); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/attach/basic", fs_attach); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/basic", fs_walk); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/no_slash", fs_walk_no_slash); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/dotdot_from_root", + fs_walk_dotdot); return g_test_run(); } |