From nobody Sat May 18 23:55:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1499084824595595.2042613786964; Mon, 3 Jul 2017 05:27:04 -0700 (PDT) Received: from localhost ([::1]:34737 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0RT-0007dZ-4G for importer@patchew.org; Mon, 03 Jul 2017 08:27:03 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35447) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0Pk-0006V1-TH for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dS0Pk-00085j-0Y for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:16 -0400 Received: from mx1.redhat.com ([209.132.183.28]:42612) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dS0Ph-00083X-KZ; Mon, 03 Jul 2017 08:25:13 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B0580C058ED7; Mon, 3 Jul 2017 12:25:12 +0000 (UTC) Received: from localhost (unknown [10.40.205.14]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2FC4A895A8; Mon, 3 Jul 2017 12:25:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com B0580C058ED7 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=mreitz@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com B0580C058ED7 From: Max Reitz To: qemu-block@nongnu.org Date: Mon, 3 Jul 2017 14:25:01 +0200 Message-Id: <20170703122505.32017-2-mreitz@redhat.com> In-Reply-To: <20170703122505.32017-1-mreitz@redhat.com> References: <20170703122505.32017-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 03 Jul 2017 12:25:12 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 1/5] qapi/qnull: Add own header X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Markus Armbruster , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Reviewed-by: Markus Armbruster Signed-off-by: Max Reitz Reviewed-by: Eric Blake --- include/qapi/qmp/qnull.h | 26 ++++++++++++++++++++++++++ include/qapi/qmp/qobject.h | 8 -------- include/qapi/qmp/types.h | 1 + qobject/qnull.c | 2 +- tests/check-qnull.c | 2 +- 5 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 include/qapi/qmp/qnull.h diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h new file mode 100644 index 0000000..48edad4 --- /dev/null +++ b/include/qapi/qmp/qnull.h @@ -0,0 +1,26 @@ +/* + * QNull + * + * Copyright (C) 2015 Red Hat, Inc. + * + * Authors: + * Markus Armbruster + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 + * or later. See the COPYING.LIB file in the top-level directory. + */ + +#ifndef QNULL_H +#define QNULL_H + +#include "qapi/qmp/qobject.h" + +extern QObject qnull_; + +static inline QObject *qnull(void) +{ + qobject_incref(&qnull_); + return &qnull_; +} + +#endif /* QNULL_H */ diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index b8ddbca..ef1d1a9 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -93,12 +93,4 @@ static inline QType qobject_type(const QObject *obj) return obj->type; } =20 -extern QObject qnull_; - -static inline QObject *qnull(void) -{ - qobject_incref(&qnull_); - return &qnull_; -} - #endif /* QOBJECT_H */ diff --git a/include/qapi/qmp/types.h b/include/qapi/qmp/types.h index a4bc662..749ac44 100644 --- a/include/qapi/qmp/types.h +++ b/include/qapi/qmp/types.h @@ -19,5 +19,6 @@ #include "qapi/qmp/qstring.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" +#include "qapi/qmp/qnull.h" =20 #endif /* QAPI_QMP_TYPES_H */ diff --git a/qobject/qnull.c b/qobject/qnull.c index c124d05..43918f1 100644 --- a/qobject/qnull.c +++ b/qobject/qnull.c @@ -12,7 +12,7 @@ =20 #include "qemu/osdep.h" #include "qemu-common.h" -#include "qapi/qmp/qobject.h" +#include "qapi/qmp/qnull.h" =20 QObject qnull_ =3D { .type =3D QTYPE_QNULL, diff --git a/tests/check-qnull.c b/tests/check-qnull.c index 8dd1c96..4a67b9a 100644 --- a/tests/check-qnull.c +++ b/tests/check-qnull.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" =20 -#include "qapi/qmp/qobject.h" +#include "qapi/qmp/qnull.h" #include "qemu-common.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" --=20 2.9.4 From nobody Sat May 18 23:55:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1499084937733893.008833053407; Mon, 3 Jul 2017 05:28:57 -0700 (PDT) Received: from localhost ([::1]:34748 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0TI-0000pb-83 for importer@patchew.org; Mon, 03 Jul 2017 08:28:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35564) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0Pw-0006ec-MH for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dS0Pu-0008Br-Rv for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:28 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57108) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dS0Pp-000892-Al; Mon, 03 Jul 2017 08:25:21 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4B6B840F18; Mon, 3 Jul 2017 12:25:20 +0000 (UTC) Received: from localhost (unknown [10.40.205.14]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 24D268E83A; Mon, 3 Jul 2017 12:25:14 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 4B6B840F18 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=mreitz@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 4B6B840F18 From: Max Reitz To: qemu-block@nongnu.org Date: Mon, 3 Jul 2017 14:25:02 +0200 Message-Id: <20170703122505.32017-3-mreitz@redhat.com> In-Reply-To: <20170703122505.32017-1-mreitz@redhat.com> References: <20170703122505.32017-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Mon, 03 Jul 2017 12:25:20 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 2/5] qapi: Add qobject_is_equal() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Markus Armbruster , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This generic function (along with its implementations for different types) determines whether two QObjects are equal. Signed-off-by: Max Reitz Reviewed-by: Eric Blake --- include/qapi/qmp/qbool.h | 1 + include/qapi/qmp/qdict.h | 1 + include/qapi/qmp/qlist.h | 1 + include/qapi/qmp/qnull.h | 2 ++ include/qapi/qmp/qnum.h | 1 + include/qapi/qmp/qobject.h | 9 ++++++++ include/qapi/qmp/qstring.h | 1 + qobject/qbool.c | 8 +++++++ qobject/qdict.c | 29 +++++++++++++++++++++++++ qobject/qlist.c | 32 ++++++++++++++++++++++++++++ qobject/qnull.c | 9 ++++++++ qobject/qnum.c | 53 ++++++++++++++++++++++++++++++++++++++++++= ++++ qobject/qobject.c | 29 +++++++++++++++++++++++++ qobject/qstring.c | 9 ++++++++ 14 files changed, 185 insertions(+) diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h index a41111c..f77ea86 100644 --- a/include/qapi/qmp/qbool.h +++ b/include/qapi/qmp/qbool.h @@ -24,6 +24,7 @@ typedef struct QBool { QBool *qbool_from_bool(bool value); bool qbool_get_bool(const QBool *qb); QBool *qobject_to_qbool(const QObject *obj); +bool qbool_is_equal(const QObject *x, const QObject *y); void qbool_destroy_obj(QObject *obj); =20 #endif /* QBOOL_H */ diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 363e431..84f8ea7 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -42,6 +42,7 @@ void qdict_del(QDict *qdict, const char *key); int qdict_haskey(const QDict *qdict, const char *key); QObject *qdict_get(const QDict *qdict, const char *key); QDict *qobject_to_qdict(const QObject *obj); +bool qdict_is_equal(const QObject *x, const QObject *y); void qdict_iter(const QDict *qdict, void (*iter)(const char *key, QObject *obj, void *opaque), void *opaque); diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h index c4b5fda..24e1e9f 100644 --- a/include/qapi/qmp/qlist.h +++ b/include/qapi/qmp/qlist.h @@ -58,6 +58,7 @@ QObject *qlist_peek(QList *qlist); int qlist_empty(const QList *qlist); size_t qlist_size(const QList *qlist); QList *qobject_to_qlist(const QObject *obj); +bool qlist_is_equal(const QObject *x, const QObject *y); void qlist_destroy_obj(QObject *obj); =20 static inline const QListEntry *qlist_first(const QList *qlist) diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h index 48edad4..f4fbcae 100644 --- a/include/qapi/qmp/qnull.h +++ b/include/qapi/qmp/qnull.h @@ -23,4 +23,6 @@ static inline QObject *qnull(void) return &qnull_; } =20 +bool qnull_is_equal(const QObject *x, const QObject *y); + #endif /* QNULL_H */ diff --git a/include/qapi/qmp/qnum.h b/include/qapi/qmp/qnum.h index 09d745c..237d01b 100644 --- a/include/qapi/qmp/qnum.h +++ b/include/qapi/qmp/qnum.h @@ -48,6 +48,7 @@ double qnum_get_double(QNum *qn); char *qnum_to_string(QNum *qn); =20 QNum *qobject_to_qnum(const QObject *obj); +bool qnum_is_equal(const QObject *x, const QObject *y); void qnum_destroy_obj(QObject *obj); =20 #endif /* QNUM_H */ diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index ef1d1a9..38ac688 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -68,6 +68,15 @@ static inline void qobject_incref(QObject *obj) } =20 /** + * qobject_is_equal(): Return whether the two objects are equal. + * + * Any of the pointers may be NULL; return true if both are. Always + * return false if only one is (therefore a QNull object is not + * considered equal to a NULL pointer). + */ +bool qobject_is_equal(const QObject *x, const QObject *y); + +/** * qobject_destroy(): Free resources used by the object */ void qobject_destroy(QObject *obj); diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index 10076b7..65c05a9 100644 --- a/include/qapi/qmp/qstring.h +++ b/include/qapi/qmp/qstring.h @@ -31,6 +31,7 @@ void qstring_append_int(QString *qstring, int64_t value); void qstring_append(QString *qstring, const char *str); void qstring_append_chr(QString *qstring, int c); QString *qobject_to_qstring(const QObject *obj); +bool qstring_is_equal(const QObject *x, const QObject *y); void qstring_destroy_obj(QObject *obj); =20 #endif /* QSTRING_H */ diff --git a/qobject/qbool.c b/qobject/qbool.c index 0606bbd..ac825fc 100644 --- a/qobject/qbool.c +++ b/qobject/qbool.c @@ -52,6 +52,14 @@ QBool *qobject_to_qbool(const QObject *obj) } =20 /** + * qbool_is_equal(): Test whether the two QBools are equal + */ +bool qbool_is_equal(const QObject *x, const QObject *y) +{ + return qobject_to_qbool(x)->value =3D=3D qobject_to_qbool(y)->value; +} + +/** * qbool_destroy_obj(): Free all memory allocated by a * QBool object */ diff --git a/qobject/qdict.c b/qobject/qdict.c index 576018e..e8f15f1 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -403,6 +403,35 @@ void qdict_del(QDict *qdict, const char *key) } =20 /** + * qdict_is_equal(): Test whether the two QDicts are equal + * + * Here, equality means whether they contain the same keys and whether + * the respective values are in turn equal (i.e. invoking + * qobject_is_equal() on them yields true). + */ +bool qdict_is_equal(const QObject *x, const QObject *y) +{ + const QDict *dict_x =3D qobject_to_qdict(x); + const QDict *dict_y =3D qobject_to_qdict(y); + const QDictEntry *e; + + if (qdict_size(dict_x) !=3D qdict_size(dict_y)) { + return false; + } + + for (e =3D qdict_first(dict_x); e; e =3D qdict_next(dict_x, e)) { + const QObject *obj_x =3D qdict_entry_value(e); + const QObject *obj_y =3D qdict_get(dict_y, qdict_entry_key(e)); + + if (!qobject_is_equal(obj_x, obj_y)) { + return false; + } + } + + return true; +} + +/** * qdict_destroy_obj(): Free all the memory allocated by a QDict */ void qdict_destroy_obj(QObject *obj) diff --git a/qobject/qlist.c b/qobject/qlist.c index 86b60cb..3ef57d3 100644 --- a/qobject/qlist.c +++ b/qobject/qlist.c @@ -140,6 +140,38 @@ QList *qobject_to_qlist(const QObject *obj) } =20 /** + * qlist_is_equal(): Test whether the two QLists are equal + * + * In order to be considered equal, the respective two objects at each + * index of the two lists have to compare equal (regarding + * qobject_is_equal()), and both lists have to have the same number of + * elements. + * That means both lists have to contain equal objects in equal order. + */ +bool qlist_is_equal(const QObject *x, const QObject *y) +{ + const QList *list_x =3D qobject_to_qlist(x); + const QList *list_y =3D qobject_to_qlist(y); + const QListEntry *entry_x, *entry_y; + + entry_x =3D qlist_first(list_x); + entry_y =3D qlist_first(list_y); + + while (entry_x && entry_y) { + if (!qobject_is_equal(qlist_entry_obj(entry_x), + qlist_entry_obj(entry_y))) + { + return false; + } + + entry_x =3D qlist_next(entry_x); + entry_y =3D qlist_next(entry_y); + } + + return !entry_x && !entry_y; +} + +/** * qlist_destroy_obj(): Free all the memory allocated by a QList */ void qlist_destroy_obj(QObject *obj) diff --git a/qobject/qnull.c b/qobject/qnull.c index 43918f1..4b9cdbc 100644 --- a/qobject/qnull.c +++ b/qobject/qnull.c @@ -18,3 +18,12 @@ QObject qnull_ =3D { .type =3D QTYPE_QNULL, .refcnt =3D 1, }; + +/** + * qnull_is_equal(): Always return true because any two QNull objects + * are equal. + */ +bool qnull_is_equal(const QObject *x, const QObject *y) +{ + return true; +} diff --git a/qobject/qnum.c b/qobject/qnum.c index 476e81c..784d061 100644 --- a/qobject/qnum.c +++ b/qobject/qnum.c @@ -213,6 +213,59 @@ QNum *qobject_to_qnum(const QObject *obj) } =20 /** + * qnum_is_equal(): Test whether the two QNums are equal + */ +bool qnum_is_equal(const QObject *x, const QObject *y) +{ + QNum *num_x =3D qobject_to_qnum(x); + QNum *num_y =3D qobject_to_qnum(y); + + switch (num_x->kind) { + case QNUM_I64: + switch (num_y->kind) { + case QNUM_I64: + /* Comparison in native int64_t type */ + return num_x->u.i64 =3D=3D num_y->u.i64; + case QNUM_U64: + /* Implicit conversion of x to uin64_t, so we have to + * check its sign before */ + return num_x->u.i64 >=3D 0 && num_x->u.i64 =3D=3D num_y->u.u64; + case QNUM_DOUBLE: + /* Implicit conversion of x to double; no overflow + * possible */ + return num_x->u.i64 =3D=3D num_y->u.dbl; + } + abort(); + case QNUM_U64: + switch (num_y->kind) { + case QNUM_I64: + return qnum_is_equal(y, x); + case QNUM_U64: + /* Comparison in native uint64_t type */ + return num_x->u.u64 =3D=3D num_y->u.u64; + case QNUM_DOUBLE: + /* Implicit conversion of x to double; no overflow + * possible */ + return num_x->u.u64 =3D=3D num_y->u.dbl; + } + abort(); + case QNUM_DOUBLE: + switch (num_y->kind) { + case QNUM_I64: + return qnum_is_equal(y, x); + case QNUM_U64: + return qnum_is_equal(y, x); + case QNUM_DOUBLE: + /* Comparison in native double type */ + return num_x->u.dbl =3D=3D num_y->u.dbl; + } + abort(); + } + + abort(); +} + +/** * qnum_destroy_obj(): Free all memory allocated by a * QNum object */ diff --git a/qobject/qobject.c b/qobject/qobject.c index b0cafb6..b2a5360 100644 --- a/qobject/qobject.c +++ b/qobject/qobject.c @@ -27,3 +27,32 @@ void qobject_destroy(QObject *obj) assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX); qdestroy[obj->type](obj); } + + +static bool (*qis_equal[QTYPE__MAX])(const QObject *, const QObject *) =3D= { + [QTYPE_NONE] =3D NULL, /* No such object exists */ + [QTYPE_QNULL] =3D qnull_is_equal, + [QTYPE_QNUM] =3D qnum_is_equal, + [QTYPE_QSTRING] =3D qstring_is_equal, + [QTYPE_QDICT] =3D qdict_is_equal, + [QTYPE_QLIST] =3D qlist_is_equal, + [QTYPE_QBOOL] =3D qbool_is_equal, +}; + +bool qobject_is_equal(const QObject *x, const QObject *y) +{ + /* We cannot test x =3D=3D y because an object does not need to be + * equal to itself (e.g. NaN floats are not). */ + + if (!x && !y) { + return true; + } + + if (!x || !y || x->type !=3D y->type) { + return false; + } + + assert(QTYPE_NONE < x->type && x->type < QTYPE__MAX); + + return qis_equal[x->type](x, y); +} diff --git a/qobject/qstring.c b/qobject/qstring.c index 5da7b5f..74182a1 100644 --- a/qobject/qstring.c +++ b/qobject/qstring.c @@ -129,6 +129,15 @@ const char *qstring_get_str(const QString *qstring) } =20 /** + * qstring_is_equal(): Test whether the two QStrings are equal + */ +bool qstring_is_equal(const QObject *x, const QObject *y) +{ + return !strcmp(qobject_to_qstring(x)->string, + qobject_to_qstring(y)->string); +} + +/** * qstring_destroy_obj(): Free all memory allocated by a QString * object */ --=20 2.9.4 From nobody Sat May 18 23:55:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1499084961944627.868817903163; Mon, 3 Jul 2017 05:29:21 -0700 (PDT) Received: from localhost ([::1]:34749 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0Tg-0001MV-OH for importer@patchew.org; Mon, 03 Jul 2017 08:29:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35577) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0Px-0006er-9w for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dS0Pw-0008DQ-DR for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:29 -0400 Received: from mx1.redhat.com ([209.132.183.28]:61763) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dS0Pt-0008At-FE; Mon, 03 Jul 2017 08:25:25 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6A3CDC04B938; Mon, 3 Jul 2017 12:25:24 +0000 (UTC) Received: from localhost (unknown [10.40.205.14]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E9A468C060; Mon, 3 Jul 2017 12:25:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 6A3CDC04B938 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=mreitz@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 6A3CDC04B938 From: Max Reitz To: qemu-block@nongnu.org Date: Mon, 3 Jul 2017 14:25:03 +0200 Message-Id: <20170703122505.32017-4-mreitz@redhat.com> In-Reply-To: <20170703122505.32017-1-mreitz@redhat.com> References: <20170703122505.32017-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Mon, 03 Jul 2017 12:25:24 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 3/5] block: qobject_is_equal() in bdrv_reopen_prepare() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Markus Armbruster , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Currently, bdrv_reopen_prepare() assumes that all BDS options are strings. However, this is not the case if the BDS has been created through the json: pseudo-protocol or blockdev-add. Note that the user-invokable reopen command is an HMP command, so you can only specify strings there. Therefore, specifying a non-string option with the "same" value as it was when originally created will now return an error because the values are supposedly similar (and there is no way for the user to circumvent this but to just not specify the option again -- however, this is still strictly better than just crashing). Signed-off-by: Max Reitz Reviewed-by: Eric Blake --- block.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/block.c b/block.c index 913bb43..45eb248 100644 --- a/block.c +++ b/block.c @@ -2947,19 +2947,24 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_sta= te, BlockReopenQueue *queue, const QDictEntry *entry =3D qdict_first(reopen_state->options); =20 do { - QString *new_obj =3D qobject_to_qstring(entry->value); - const char *new =3D qstring_get_str(new_obj); - /* - * Caution: while qdict_get_try_str() is fine, getting - * non-string types would require more care. When - * bs->options come from -blockdev or blockdev_add, its - * members are typed according to the QAPI schema, but - * when they come from -drive, they're all QString. - */ - const char *old =3D qdict_get_try_str(reopen_state->bs->option= s, - entry->key); - - if (!old || strcmp(new, old)) { + QObject *new =3D entry->value; + QObject *old =3D qdict_get(reopen_state->bs->options, entry->k= ey); + + /* TODO: When using -drive to specify blockdev options, all va= lues + * will be strings; however, when using -blockdev, blockdev-ad= d or + * filenames using the json:{} pseudo-protocol, they will be + * correctly typed. + * In contrast, reopening options are (currently) always strin= gs + * (because you can only specify them through qemu-io; all oth= er + * callers do not specify any options). + * Therefore, when using anything other than -drive to create = a BDS, + * this cannot detect non-string options as unchanged, because + * qobject_is_equal() always returns false for objects of diff= erent + * type. In the future, this should be remedied by correctly = typing + * all options. For now, this is not too big of an issue beca= use + * the user simply can not specify options which cannot be cha= nged + * anyway, so they will stay unchanged. */ + if (!qobject_is_equal(new, old)) { error_setg(errp, "Cannot change the option '%s'", entry->k= ey); ret =3D -EINVAL; goto error; --=20 2.9.4 From nobody Sat May 18 23:55:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1499085043876915.1438301740119; Mon, 3 Jul 2017 05:30:43 -0700 (PDT) Received: from localhost ([::1]:34758 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0Uz-0002ng-N1 for importer@patchew.org; Mon, 03 Jul 2017 08:30:41 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35609) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0Q1-0006ir-LS for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dS0Py-0008G0-JH for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36114) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dS0Pw-0008Cr-DP; Mon, 03 Jul 2017 08:25:28 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 88FE82AD8E; Mon, 3 Jul 2017 12:25:27 +0000 (UTC) Received: from localhost (unknown [10.40.205.14]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DE3108C060; Mon, 3 Jul 2017 12:25:26 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 88FE82AD8E Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=mreitz@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 88FE82AD8E From: Max Reitz To: qemu-block@nongnu.org Date: Mon, 3 Jul 2017 14:25:04 +0200 Message-Id: <20170703122505.32017-5-mreitz@redhat.com> In-Reply-To: <20170703122505.32017-1-mreitz@redhat.com> References: <20170703122505.32017-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Mon, 03 Jul 2017 12:25:27 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 4/5] iotests: Add test for non-string option reopening X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Markus Armbruster , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Reviewed-by: Kevin Wolf Signed-off-by: Max Reitz --- tests/qemu-iotests/133 | 9 +++++++++ tests/qemu-iotests/133.out | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133 index 9d35a6a..af6b3e1 100755 --- a/tests/qemu-iotests/133 +++ b/tests/qemu-iotests/133 @@ -83,6 +83,15 @@ $QEMU_IO -c 'reopen -o driver=3Dqcow2' $TEST_IMG $QEMU_IO -c 'reopen -o file.driver=3Dfile' $TEST_IMG $QEMU_IO -c 'reopen -o backing.driver=3Dqcow2' $TEST_IMG =20 +echo +echo "=3D=3D=3D Check that reopening works with non-string options =3D=3D= =3D" +echo + +# Using the json: pseudo-protocol we can create non-string options +# (Invoke 'info' just so we get some output afterwards) +IMGOPTSSYNTAX=3Dfalse $QEMU_IO -f null-co -c 'reopen' -c 'info' \ + "json:{'driver': 'null-co', 'size': 65536}" + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/133.out b/tests/qemu-iotests/133.out index cc86b94..f4a85ae 100644 --- a/tests/qemu-iotests/133.out +++ b/tests/qemu-iotests/133.out @@ -19,4 +19,9 @@ Cannot change the option 'driver' =20 =3D=3D=3D Check that unchanged driver is okay =3D=3D=3D =20 + +=3D=3D=3D Check that reopening works with non-string options =3D=3D=3D + +format name: null-co +format name: null-co *** done --=20 2.9.4 From nobody Sat May 18 23:55:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 149908486520227.47462113876054; Mon, 3 Jul 2017 05:27:45 -0700 (PDT) Received: from localhost ([::1]:34739 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0S6-0008AV-I0 for importer@patchew.org; Mon, 03 Jul 2017 08:27:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35632) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dS0Q7-0006nt-Gt for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dS0Q5-0008K7-D7 for qemu-devel@nongnu.org; Mon, 03 Jul 2017 08:25:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44432) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dS0Q0-0008Gt-Sv; Mon, 03 Jul 2017 08:25:33 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D483CC045776; Mon, 3 Jul 2017 12:25:31 +0000 (UTC) Received: from localhost (unknown [10.40.205.14]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 150486FDA8; Mon, 3 Jul 2017 12:25:29 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com D483CC045776 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=mreitz@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com D483CC045776 From: Max Reitz To: qemu-block@nongnu.org Date: Mon, 3 Jul 2017 14:25:05 +0200 Message-Id: <20170703122505.32017-6-mreitz@redhat.com> In-Reply-To: <20170703122505.32017-1-mreitz@redhat.com> References: <20170703122505.32017-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 03 Jul 2017 12:25:32 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3 5/5] tests: Add check-qobject for equality tests X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Markus Armbruster , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add a new test file (check-qobject.c) for unit tests that concern QObjects as a whole. Its only purpose for now is to test the qobject_is_equal() function. Signed-off-by: Max Reitz Reviewed-by: Eric Blake --- tests/Makefile.include | 4 +- tests/check-qobject.c | 312 +++++++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 tests/check-qobject.c diff --git a/tests/Makefile.include b/tests/Makefile.include index c738e92..ff0022d 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -18,6 +18,7 @@ check-unit-y +=3D tests/check-qlist$(EXESUF) gcov-files-check-qlist-y =3D qobject/qlist.c check-unit-y +=3D tests/check-qnull$(EXESUF) gcov-files-check-qnull-y =3D qobject/qnull.c +check-unit-y +=3D tests/check-qobject$(EXESUF) check-unit-y +=3D tests/check-qjson$(EXESUF) gcov-files-check-qjson-y =3D qobject/qjson.c check-unit-y +=3D tests/test-qobject-output-visitor$(EXESUF) @@ -507,7 +508,7 @@ GENERATED_FILES +=3D tests/test-qapi-types.h tests/test= -qapi-visit.h \ tests/test-qmp-introspect.h =20 test-obj-y =3D tests/check-qnum.o tests/check-qstring.o tests/check-qdict.= o \ - tests/check-qlist.o tests/check-qnull.o \ + tests/check-qlist.o tests/check-qnull.o tests/check-qobject.o \ tests/check-qjson.o \ tests/test-coroutine.o tests/test-string-output-visitor.o \ tests/test-string-input-visitor.o tests/test-qobject-output-visitor.o \ @@ -540,6 +541,7 @@ tests/check-qstring$(EXESUF): tests/check-qstring.o $(t= est-util-obj-y) tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y) tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y) tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y) +tests/check-qobject$(EXESUF): tests/check-qobject.o $(test-util-obj-y) tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y) tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom= -obj-y) tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-o= bj-y) diff --git a/tests/check-qobject.c b/tests/check-qobject.c new file mode 100644 index 0000000..a68cb1e --- /dev/null +++ b/tests/check-qobject.c @@ -0,0 +1,312 @@ +/* + * Generic QObject unit-tests. + * + * Copyright (C) 2017 Red Hat Inc. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or l= ater. + * See the COPYING.LIB file in the top-level directory. + */ +#include "qemu/osdep.h" + +#include "qapi/qmp/types.h" +#include "qemu-common.h" + +/* Marks the end of the test_equality() argument list. + * We cannot use NULL there because that is a valid argument. */ +static QObject _test_equality_end_of_arguments; + +/** + * Test whether all variadic QObject *arguments are equal (@expected + * is true) or whether they are all not equal (@expected is false). + * Every QObject is tested to be equal to itself (to test + * reflexivity), all tests are done both ways (to test symmetry), and + * transitivity is not assumed but checked (each object is compared to + * every other one). + * + * Note that qobject_is_equal() is not really an equivalence relation, + * so this function may not be used for all objects (reflexivity is + * not guaranteed). + */ +static void do_test_equality(bool expected, ...) +{ + va_list ap_count, ap_extract; + QObject **args; + int arg_count =3D 0; + int i, j; + + va_start(ap_count, expected); + va_copy(ap_extract, ap_count); + while (va_arg(ap_count, QObject *) !=3D &_test_equality_end_of_argumen= ts) { + arg_count++; + } + va_end(ap_count); + + args =3D g_new(QObject *, arg_count); + for (i =3D 0; i < arg_count; i++) { + args[i] =3D va_arg(ap_extract, QObject *); + } + va_end(ap_extract); + + for (i =3D 0; i < arg_count; i++) { + g_assert(qobject_is_equal(args[i], args[i]) =3D=3D true); + + for (j =3D i + 1; j < arg_count; j++) { + g_assert(qobject_is_equal(args[i], args[j]) =3D=3D expected); + } + } +} + +#define test_equality(expected, ...) \ + do_test_equality(expected, __VA_ARGS__, &_test_equality_end_of_argumen= ts) + +static void do_free_all(int _, ...) +{ + va_list ap; + QObject *obj; + + va_start(ap, _); + while ((obj =3D va_arg(ap, QObject *)) !=3D NULL) { + qobject_decref(obj); + } + va_end(ap); +} + +#define free_all(...) \ + do_free_all(0, __VA_ARGS__, NULL) + +static void qobject_is_equal_null_test(void) +{ + test_equality(false, qnull(), NULL); +} + +static void qobject_is_equal_num_test(void) +{ + QNum *u0, *i0, *d0, *d0p25, *dnan, *um42, *im42, *dm42; + QString *s0, *s_empty; + QBool *bfalse; + + u0 =3D qnum_from_uint(0u); + i0 =3D qnum_from_int(0); + d0 =3D qnum_from_double(0.0); + d0p25 =3D qnum_from_double(0.25); + dnan =3D qnum_from_double(0.0 / 0.0); + um42 =3D qnum_from_uint((uint64_t)-42); + im42 =3D qnum_from_int(-42); + dm42 =3D qnum_from_int(-42.0); + + s0 =3D qstring_from_str("0"); + s_empty =3D qstring_new(); + bfalse =3D qbool_from_bool(false); + + /* The internal representation should not matter, as long as the + * precision is sufficient */ + test_equality(true, u0, i0, d0); + + /* No automatic type conversion */ + test_equality(false, u0, s0, s_empty, bfalse, qnull(), NULL); + test_equality(false, i0, s0, s_empty, bfalse, qnull(), NULL); + test_equality(false, d0, s0, s_empty, bfalse, qnull(), NULL); + + /* Do not round */ + test_equality(false, u0, d0p25); + test_equality(false, i0, d0p25); + + /* Do not assume any object is equal to itself */ + g_assert(qobject_is_equal(QOBJECT(dnan), QOBJECT(dnan)) =3D=3D false); + + /* No unsigned overflow */ + test_equality(false, um42, im42); + test_equality(false, um42, dm42); + test_equality(true, im42, dm42); + + free_all(u0, i0, d0, d0p25, dnan, um42, im42, dm42, s0, s_empty, bfals= e); +} + +static void qobject_is_equal_bool_test(void) +{ + QBool *btrue_0, *btrue_1, *bfalse_0, *bfalse_1; + + /* Automatic type conversion is tested in the QNum test */ + + btrue_0 =3D qbool_from_bool(true); + btrue_1 =3D qbool_from_bool(true); + bfalse_0 =3D qbool_from_bool(false); + bfalse_1 =3D qbool_from_bool(false); + + test_equality(true, btrue_0, btrue_1); + test_equality(true, bfalse_0, bfalse_1); + test_equality(false, btrue_0, bfalse_0); + test_equality(false, btrue_1, bfalse_1); + + free_all(btrue_0, btrue_1, bfalse_0, bfalse_1); +} + +static void qobject_is_equal_string_test(void) +{ + QString *str_base, *str_whitespace_0, *str_whitespace_1, *str_whitespa= ce_2; + QString *str_whitespace_3, *str_case, *str_built; + + str_base =3D qstring_from_str("foo"); + str_whitespace_0 =3D qstring_from_str(" foo"); + str_whitespace_1 =3D qstring_from_str("foo "); + str_whitespace_2 =3D qstring_from_str("foo\b"); + str_whitespace_3 =3D qstring_from_str("fooo\b"); + str_case =3D qstring_from_str("Foo"); + + /* Should yield "foo" */ + str_built =3D qstring_from_substr("form", 0, 1); + qstring_append_chr(str_built, 'o'); + + test_equality(false, str_base, str_whitespace_0, str_whitespace_1, + str_whitespace_2, str_whitespace_3, str_case); + + test_equality(true, str_base, str_built); + + free_all(str_base, str_whitespace_0, str_whitespace_1, str_whitespace_= 2, + str_whitespace_3, str_case, str_built); +} + +static void qobject_is_equal_list_test(void) +{ + QList *list_0, *list_1, *list_cloned; + QList *list_reordered, *list_longer, *list_shorter; + + list_0 =3D qlist_new(); + list_1 =3D qlist_new(); + list_reordered =3D qlist_new(); + list_longer =3D qlist_new(); + list_shorter =3D qlist_new(); + + qlist_append_int(list_0, 1); + qlist_append_int(list_0, 2); + qlist_append_int(list_0, 3); + + qlist_append_int(list_1, 1); + qlist_append_int(list_1, 2); + qlist_append_int(list_1, 3); + + qlist_append_int(list_reordered, 1); + qlist_append_int(list_reordered, 3); + qlist_append_int(list_reordered, 2); + + qlist_append_int(list_longer, 1); + qlist_append_int(list_longer, 2); + qlist_append_int(list_longer, 3); + qlist_append_obj(list_longer, qnull()); + + qlist_append_int(list_shorter, 1); + qlist_append_int(list_shorter, 2); + + list_cloned =3D qlist_copy(list_0); + + test_equality(true, list_0, list_1, list_cloned); + test_equality(false, list_0, list_reordered, list_longer, list_shorter= ); + + /* With a NaN in it, the list should no longer compare equal to + * itself */ + qlist_append(list_0, qnum_from_double(0.0 / 0.0)); + g_assert(qobject_is_equal(QOBJECT(list_0), QOBJECT(list_0)) =3D=3D fal= se); + + free_all(list_0, list_1, list_cloned, list_reordered, list_longer, lis= t_shorter); +} + +static void qobject_is_equal_dict_test(void) +{ + Error *local_err =3D NULL; + QDict *dict_0, *dict_1, *dict_cloned; + QDict *dict_different_key, *dict_different_value, *dict_different_null= _key; + QDict *dict_longer, *dict_shorter, *dict_nested; + QDict *dict_crumpled; + + dict_0 =3D qdict_new(); + dict_1 =3D qdict_new(); + dict_different_key =3D qdict_new(); + dict_different_value =3D qdict_new(); + dict_different_null_key =3D qdict_new(); + dict_longer =3D qdict_new(); + dict_shorter =3D qdict_new(); + dict_nested =3D qdict_new(); + + qdict_put_int(dict_0, "f.o", 1); + qdict_put_int(dict_0, "bar", 2); + qdict_put_int(dict_0, "baz", 3); + qdict_put_obj(dict_0, "null", qnull()); + + qdict_put_int(dict_1, "f.o", 1); + qdict_put_int(dict_1, "bar", 2); + qdict_put_int(dict_1, "baz", 3); + qdict_put_obj(dict_1, "null", qnull()); + + qdict_put_int(dict_different_key, "F.o", 1); + qdict_put_int(dict_different_key, "bar", 2); + qdict_put_int(dict_different_key, "baz", 3); + qdict_put_obj(dict_different_key, "null", qnull()); + + qdict_put_int(dict_different_value, "f.o", 42); + qdict_put_int(dict_different_value, "bar", 2); + qdict_put_int(dict_different_value, "baz", 3); + qdict_put_obj(dict_different_value, "null", qnull()); + + qdict_put_int(dict_different_null_key, "f.o", 1); + qdict_put_int(dict_different_null_key, "bar", 2); + qdict_put_int(dict_different_null_key, "baz", 3); + qdict_put_obj(dict_different_null_key, "none", qnull()); + + qdict_put_int(dict_longer, "f.o", 1); + qdict_put_int(dict_longer, "bar", 2); + qdict_put_int(dict_longer, "baz", 3); + qdict_put_int(dict_longer, "xyz", 4); + qdict_put_obj(dict_longer, "null", qnull()); + + qdict_put_int(dict_shorter, "f.o", 1); + qdict_put_int(dict_shorter, "bar", 2); + qdict_put_int(dict_shorter, "baz", 3); + + qdict_put(dict_nested, "f", qdict_new()); + qdict_put_int(qdict_get_qdict(dict_nested, "f"), "o", 1); + qdict_put_int(dict_nested, "bar", 2); + qdict_put_int(dict_nested, "baz", 3); + qdict_put_obj(dict_nested, "null", qnull()); + + dict_cloned =3D qdict_clone_shallow(dict_0); + + test_equality(true, dict_0, dict_1, dict_cloned); + test_equality(false, dict_0, dict_different_key, dict_different_value, + dict_different_null_key, dict_longer, dict_shorte= r, + dict_nested); + + dict_crumpled =3D qobject_to_qdict(qdict_crumple(dict_1, &local_err)); + g_assert(!local_err); + test_equality(true, dict_crumpled, dict_nested); + + qdict_flatten(dict_nested); + test_equality(true, dict_0, dict_nested); + + /* Containing an NaN value will make this dict compare unequal to + * itself */ + qdict_put(dict_0, "NaN", qnum_from_double(0.0 / 0.0)); + g_assert(qobject_is_equal(QOBJECT(dict_0), QOBJECT(dict_0)) =3D=3D fal= se); + + free_all(dict_0, dict_1, dict_cloned, dict_different_key, + dict_different_value, dict_different_null_key, dict_longer, + dict_shorter, dict_nested, dict_crumpled); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/public/qobject_is_equal_null", + qobject_is_equal_null_test); + g_test_add_func("/public/qobject_is_equal_num", qobject_is_equal_num_t= est); + g_test_add_func("/public/qobject_is_equal_bool", + qobject_is_equal_bool_test); + g_test_add_func("/public/qobject_is_equal_string", + qobject_is_equal_string_test); + g_test_add_func("/public/qobject_is_equal_list", + qobject_is_equal_list_test); + g_test_add_func("/public/qobject_is_equal_dict", + qobject_is_equal_dict_test); + + return g_test_run(); +} --=20 2.9.4