mirror of https://github.com/qt/qtgrpc.git
Deprecate QHash<QBA,QBA> metadata in favor of QMultiHash
Even though gRPC provides some leeway, as "Access to metadata is language dependent", we have yet to see an implementation which doesn't support multiple values per key. Common implementations like grpc-c++, grpc-go or grpc-java provide this and we should do it aswell. Ref: https://grpc.io/docs/what-is-grpc/core-concepts/#metadata Ref: https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md#constructing-metadata Use a base class to implement common functionality for the options classes. Also use a new common class in the tests. The QMultiHash overload is selected when the 'QtGrpc::MultiValue' argument is used in 'metadata' calls. We update the documentation accordingly. Deprecation is scheduled for Qt 6.13 Users with a custom Qt build - those who care - should be rewarded with minimal traces of this "accident" and should not suffer from potential performance/storage overhead. Therefore we deprecate QtGrpc::MultiValue for those builds, effectively providing Qt 7 behavior. [ChangeLog][Deprecation Notice] Deprecate the metadata()/setMetadata() methods on QGrpcCallOptions and QGrpcChannelOptions that use QHash in favor of the new overloads that use QMultiHash. This is more in line with the gRPC specification. Fixes: QTBUG-136471 Change-Id: I58d14d2c304c06de269c99ba5383beee86d12f77 Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
parent
9a1cc11111
commit
778371b8ea
|
@ -11,6 +11,7 @@ qt_internal_add_module(Grpc
|
|||
qabstractgrpcchannel.h qabstractgrpcchannel_p.h qabstractgrpcchannel.cpp
|
||||
qgrpchttp2channel.h qgrpchttp2channel.cpp
|
||||
qgrpcclientbase.h qgrpcclientbase.cpp
|
||||
qgrpccommonoptions_p.h qgrpccommonoptions.cpp
|
||||
qgrpccalloptions.h qgrpccalloptions.cpp
|
||||
qgrpcchanneloptions.h qgrpcchanneloptions.cpp
|
||||
qtgrpcglobal.h
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtGrpc/private/qgrpccommonoptions_p.h>
|
||||
#include <QtGrpc/private/qtgrpclogging_p.h>
|
||||
#include <QtGrpc/qgrpccalloptions.h>
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
|
@ -23,13 +25,27 @@ using namespace Qt::StringLiterals;
|
|||
These options supersede the ones set via QGrpcChannelOptions.
|
||||
|
||||
To configure the default options shared by RPCs, use QGrpcChannelOptions.
|
||||
|
||||
\code
|
||||
QGrpcCallOptions callOpts;
|
||||
// Set the metadata for an individial RPC
|
||||
callOpts.setMetadata({
|
||||
{ "header" , "value1" },
|
||||
{ "header" , "value2" },
|
||||
});
|
||||
const auto &md = callOpts.metadata(QtGrpc::MultiValue);
|
||||
qDebug() << "Call Metadata: " << md;
|
||||
|
||||
// Set a 2-second deadline for an individial RPC
|
||||
callOpts.setDeadlineTimeout(2s);
|
||||
qDebug() << "Call timeout: " << callOpts.deadlineTimeout();
|
||||
\endcode
|
||||
*/
|
||||
|
||||
class QGrpcCallOptionsPrivate : public QSharedData
|
||||
class QGrpcCallOptionsPrivate : public QGrpcCommonOptions
|
||||
{
|
||||
public:
|
||||
std::optional<std::chrono::milliseconds> timeout;
|
||||
QHash<QByteArray, QByteArray> metadata;
|
||||
QGrpcCallOptionsPrivate() = default;
|
||||
};
|
||||
|
||||
QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QGrpcCallOptionsPrivate)
|
||||
|
@ -92,98 +108,152 @@ QGrpcCallOptions::operator QVariant() const
|
|||
*/
|
||||
|
||||
/*!
|
||||
Sets the \a timeout for a specific RPC and returns a reference to the
|
||||
updated object.
|
||||
\include qgrpccommonoptions.cpp set-deadline-timeout
|
||||
|
||||
//! [set-deadline-desc]
|
||||
A deadline sets the limit for how long a client is willing to wait for a
|
||||
response from a server. The actual deadline is computed by adding the \a
|
||||
timeout to the start time of the RPC.
|
||||
\note Setting this field \b{overrides} the corresponding channel options field
|
||||
— see \l{QGrpcChannelOptions::setDeadlineTimeout()}
|
||||
|
||||
The deadline applies to the entire lifetime of an RPC, which includes
|
||||
receiving the final QGrpcStatus for a previously started call and can thus
|
||||
be unwanted for (long-lived) streams.
|
||||
//! [set-deadline-desc]
|
||||
|
||||
\note Setting this field overrides the value set by
|
||||
QGrpcChannelOptions::setDeadline() for a specific RPC.
|
||||
\sa deadlineTimeout()
|
||||
*/
|
||||
QGrpcCallOptions &QGrpcCallOptions::setDeadlineTimeout(std::chrono::milliseconds timeout)
|
||||
{
|
||||
if (d_ptr->timeout == timeout)
|
||||
if (d_ptr->deadlineTimeout() == timeout)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcCallOptions);
|
||||
d->timeout = timeout;
|
||||
d->setDeadlineTimeout(timeout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
\include qgrpccommonoptions.cpp deadline-timeout
|
||||
*/
|
||||
std::optional<std::chrono::milliseconds> QGrpcCallOptions::deadlineTimeout() const noexcept
|
||||
{
|
||||
Q_D(const QGrpcCallOptions);
|
||||
return d->deadlineTimeout();
|
||||
}
|
||||
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
|
||||
/*!
|
||||
\fn const QHash<QByteArray, QByteArray> &QGrpcCallOptions::metadata() const &
|
||||
\fn QHash<QByteArray, QByteArray> QGrpcCallOptions::metadata() &&
|
||||
\deprecated [6.13] Use the QMultiHash overload instead.
|
||||
|
||||
\include qgrpccommonoptions.cpp metadata
|
||||
|
||||
\sa setMetadata()
|
||||
*/
|
||||
const QHash<QByteArray, QByteArray> &QGrpcCallOptions::metadata() const & noexcept
|
||||
{
|
||||
Q_D(const QGrpcCallOptions);
|
||||
return d->metadata();
|
||||
}
|
||||
QHash<QByteArray, QByteArray> QGrpcCallOptions::metadata() &&
|
||||
{
|
||||
Q_D(QGrpcCallOptions);
|
||||
if (d->ref.loadRelaxed() != 1)
|
||||
return d->metadata();
|
||||
return std::move(*d_ptr).metadata();
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(const QHash<QByteArray, QByteArray> &metadata)
|
||||
\fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata)
|
||||
\deprecated [6.13] Use the QMultiHash overload instead.
|
||||
|
||||
Sets the client \a metadata for a specific RPC and returns a reference to the
|
||||
updated object.
|
||||
\include qgrpccommonoptions.cpp set-metadata
|
||||
|
||||
//! [set-metadata-desc]
|
||||
QGrpcHttp2Channel converts the metadata into appropriate HTTP/2 headers
|
||||
which will be added to the HTTP/2 request.
|
||||
//! [set-metadata-desc]
|
||||
//! [merge-md-note]
|
||||
\note Call metadata is \b{merged} with any channel-level metadata when the
|
||||
RPC starts — see
|
||||
//! [merge-md-note]
|
||||
\l{QGrpcChannelOptions::setMetadata(const QMultiHash<QByteArray,
|
||||
QByteArray>&)}{QGrpcChannelOptions::setMetadata(QMultiHash)}.
|
||||
|
||||
\note Setting this field overrides the value set by
|
||||
QGrpcChannelOptions::setMetadata() for a specific RPC.
|
||||
\sa metadata()
|
||||
*/
|
||||
QGrpcCallOptions &QGrpcCallOptions::setMetadata(const QHash<QByteArray, QByteArray> &metadata)
|
||||
{
|
||||
if (d_ptr->metadata == metadata)
|
||||
if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcCallOptions);
|
||||
d->metadata = metadata;
|
||||
d->setMetadata(metadata);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QGrpcCallOptions &QGrpcCallOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata)
|
||||
{
|
||||
if (d_ptr->metadata == metadata)
|
||||
if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcCallOptions);
|
||||
d->metadata = std::move(metadata);
|
||||
d->setMetadata(std::move(metadata));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the timeout duration that is used to calculate the deadline for a
|
||||
specific RPC.
|
||||
|
||||
If this field is unset, returns an empty \c {std::optional}.
|
||||
*/
|
||||
std::optional<std::chrono::milliseconds> QGrpcCallOptions::deadlineTimeout() const noexcept
|
||||
{
|
||||
Q_D(const QGrpcCallOptions);
|
||||
return d->timeout;
|
||||
}
|
||||
#endif // QT_DEPRECATED_SINCE(6, 13)
|
||||
|
||||
/*!
|
||||
\fn const QHash<QByteArray, QByteArray> &QGrpcCallOptions::metadata() const &
|
||||
\fn QHash<QByteArray, QByteArray> QGrpcCallOptions::metadata() &&
|
||||
\since 6.10
|
||||
\fn const QMultiHash<QByteArray, QByteArray> &QGrpcCallOptions::metadata(QtGrpc::MultiValueTag) const &
|
||||
\fn QMultiHash<QByteArray, QByteArray> QGrpcCallOptions::metadata(QtGrpc::MultiValueTag) &&
|
||||
|
||||
Returns the client metadata for a specific RPC.
|
||||
If this field is unset, returns empty metadata.
|
||||
\include qgrpccommonoptions.cpp metadata-multi
|
||||
|
||||
\sa {setMetadata(const QMultiHash<QByteArray, QByteArray>&)}{setMetadata}
|
||||
*/
|
||||
const QHash<QByteArray, QByteArray> &QGrpcCallOptions::metadata() const & noexcept
|
||||
const QMultiHash<QByteArray, QByteArray> &
|
||||
QGrpcCallOptions::metadata(QtGrpc::MultiValueTag tag) const & noexcept
|
||||
{
|
||||
Q_D(const QGrpcCallOptions);
|
||||
return d->metadata;
|
||||
return d->metadata(tag);
|
||||
}
|
||||
|
||||
QHash<QByteArray, QByteArray> QGrpcCallOptions::metadata() &&
|
||||
QMultiHash<QByteArray, QByteArray> QGrpcCallOptions::metadata(QtGrpc::MultiValueTag tag) &&
|
||||
{
|
||||
Q_D(QGrpcCallOptions);
|
||||
if (d->ref.loadRelaxed() != 1) // return copy if shared
|
||||
return { d->metadata };
|
||||
return std::move(d->metadata);
|
||||
if (d->ref.loadRelaxed() != 1)
|
||||
return d->metadata(tag);
|
||||
return std::move(*d_ptr).metadata(tag);
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.10
|
||||
\fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata)
|
||||
\fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata)
|
||||
\fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> metadata)
|
||||
|
||||
\include qgrpccommonoptions.cpp set-metadata-multi
|
||||
|
||||
\include qgrpccalloptions.cpp merge-md-note
|
||||
\l{QGrpcChannelOptions::setMetadata(const QMultiHash<QByteArray,
|
||||
QByteArray>&)}{QGrpcChannelOptions::setMetadata(QMultiHash)}.
|
||||
|
||||
\sa metadata(QtGrpc::MultiValueTag)
|
||||
*/
|
||||
QGrpcCallOptions &QGrpcCallOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata)
|
||||
{
|
||||
if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcCallOptions);
|
||||
d->setMetadata(metadata);
|
||||
return *this;
|
||||
}
|
||||
QGrpcCallOptions &QGrpcCallOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata)
|
||||
{
|
||||
if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcCallOptions);
|
||||
d->setMetadata(std::move(metadata));
|
||||
return *this;
|
||||
}
|
||||
QGrpcCallOptions &
|
||||
QGrpcCallOptions::setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> list)
|
||||
{
|
||||
return setMetadata(QMultiHash<QByteArray, QByteArray>(list));
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
@ -198,7 +268,7 @@ QDebug operator<<(QDebug debug, const QGrpcCallOptions &callOpts)
|
|||
const QDebugStateSaver save(debug);
|
||||
debug.nospace().noquote();
|
||||
debug << "QGrpcCallOptions(deadline: " << callOpts.deadlineTimeout()
|
||||
<< ", metadata: " << callOpts.metadata() << ')';
|
||||
<< ", metadata: " << callOpts.metadata(QtGrpc::MultiValue) << ')';
|
||||
return debug;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
#define QGRPCALLOPTIONS_H
|
||||
|
||||
#include <QtGrpc/qtgrpcglobal.h>
|
||||
#include <QtGrpc/qtgrpcnamespace.h>
|
||||
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qshareddata.h>
|
||||
#include <QtCore/qstringfwd.h>
|
||||
#include <QtCore/qtclasshelpermacros.h>
|
||||
#include <QtCore/qtdeprecationdefinitions.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
|
@ -42,10 +44,24 @@ public:
|
|||
deadlineTimeout() const noexcept;
|
||||
Q_GRPC_EXPORT QGrpcCallOptions &setDeadlineTimeout(std::chrono::milliseconds timeout);
|
||||
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
QT_DEPRECATED_VERSION_X_6_13("Use metadata(QtGrpc::MultiValue) for QMultiHash")
|
||||
[[nodiscard]] Q_GRPC_EXPORT const QHash<QByteArray, QByteArray> &metadata() const & noexcept;
|
||||
QT_DEPRECATED_VERSION_X_6_13("Use metadata(QtGrpc::MultiValue) for QMultiHash")
|
||||
[[nodiscard]] Q_GRPC_EXPORT QHash<QByteArray, QByteArray> metadata() &&;
|
||||
QT_DEPRECATED_VERSION_X_6_13("Use the QMultiHash overload")
|
||||
Q_GRPC_EXPORT QGrpcCallOptions &setMetadata(const QHash<QByteArray, QByteArray> &metadata);
|
||||
QT_DEPRECATED_VERSION_X_6_13("Use the QMultiHash overload")
|
||||
Q_GRPC_EXPORT QGrpcCallOptions &setMetadata(QHash<QByteArray, QByteArray> &&metadata);
|
||||
#endif
|
||||
[[nodiscard]] Q_GRPC_EXPORT const QMultiHash<QByteArray, QByteArray> &
|
||||
metadata(QtGrpc::MultiValueTag) const & noexcept;
|
||||
[[nodiscard]] Q_GRPC_EXPORT QMultiHash<QByteArray, QByteArray>
|
||||
metadata(QtGrpc::MultiValueTag) &&;
|
||||
Q_GRPC_EXPORT QGrpcCallOptions &setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata);
|
||||
Q_GRPC_EXPORT QGrpcCallOptions &setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata);
|
||||
Q_GRPC_EXPORT QGrpcCallOptions &
|
||||
setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> list);
|
||||
|
||||
private:
|
||||
QExplicitlySharedDataPointer<QGrpcCallOptionsPrivate> d_ptr;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtGrpc/private/qgrpccommonoptions_p.h>
|
||||
#include <QtGrpc/qgrpcchanneloptions.h>
|
||||
#include <QtGrpc/qgrpcserializationformat.h>
|
||||
#include <QtGrpc/qtgrpcnamespace.h>
|
||||
|
@ -25,17 +26,34 @@ using namespace QtGrpc;
|
|||
to all remote procedure calls (RPCs) that operate on the associated
|
||||
channel, which is used to communicate with services.
|
||||
|
||||
Override options for specific RPCs with QGrcCallOptions.
|
||||
Override options for specific RPCs with QGrpcCallOptions.
|
||||
|
||||
\code
|
||||
QGrpcChannelOptions channelOpts;
|
||||
// Apply common metadata to every RPC
|
||||
channelOpts.setMetadata({
|
||||
{ "header" , "value1" },
|
||||
{ "header" , "value2" },
|
||||
});
|
||||
const auto &md = channelOpts.metadata(QtGrpc::MultiValue);
|
||||
qDebug() << "Channel Metadata: " << md;
|
||||
|
||||
// Apply a 2-second deadline to every RPC
|
||||
channelOpts.setDeadlineTimeout(2s);
|
||||
qDebug() << "Channel timeout: " << channelOpts.deadlineTimeout();
|
||||
|
||||
// Configure SSL/TLS configuration
|
||||
channelOpts.setSslConfiguration(QSslConfiguration());
|
||||
\endcode
|
||||
|
||||
|
||||
\note It is up to the channel's implementation to determine the specifics
|
||||
of these options.
|
||||
*/
|
||||
|
||||
class QGrpcChannelOptionsPrivate : public QSharedData
|
||||
class QGrpcChannelOptionsPrivate : public QGrpcCommonOptions
|
||||
{
|
||||
public:
|
||||
std::optional<std::chrono::milliseconds> timeout;
|
||||
QHash<QByteArray, QByteArray> metadata;
|
||||
QGrpcSerializationFormat serializationFormat;
|
||||
#if QT_CONFIG(ssl)
|
||||
std::optional<QSslConfiguration> sslConfiguration;
|
||||
|
@ -101,57 +119,151 @@ QGrpcChannelOptions::operator QVariant() const
|
|||
}
|
||||
|
||||
/*!
|
||||
Sets the \a timeout for the channel and returns a reference to the updated
|
||||
object.
|
||||
\include qgrpccommonoptions.cpp set-deadline-timeout
|
||||
|
||||
\include qgrpccalloptions.cpp set-deadline-desc
|
||||
//! [channel-note]
|
||||
\note Setting this field applies to all RPCs that operate on the channel,
|
||||
except those overriden by
|
||||
//! [channel-note]
|
||||
\l{QGrpcCallOptions::setDeadlineTimeout()}
|
||||
|
||||
\note The deadline set via the channel options applies to all RPCs that
|
||||
operate on the channel, except those overridden by
|
||||
QGrpcCallOptions::setDeadline().
|
||||
\sa deadlineTimeout()
|
||||
*/
|
||||
QGrpcChannelOptions &QGrpcChannelOptions::setDeadlineTimeout(std::chrono::milliseconds timeout)
|
||||
{
|
||||
if (d_ptr->timeout == timeout)
|
||||
if (d_ptr->deadlineTimeout() == timeout)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcChannelOptions);
|
||||
d->timeout = timeout;
|
||||
d->setDeadlineTimeout(timeout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
|
||||
/*!
|
||||
\fn const QHash<QByteArray, QByteArray> &QGrpcChannelOptions::metadata() const &
|
||||
\fn QHash<QByteArray, QByteArray> QGrpcChannelOptions::metadata() &&
|
||||
\deprecated [6.13] Use \l{metadata(QtGrpc::MultiValueTag)}{metadata(QtGrpc::MultiValue)} instead.
|
||||
|
||||
\include qgrpccommonoptions.cpp metadata
|
||||
|
||||
\sa metadata(QtGrpc::MultiValueTag), setMetadata()
|
||||
*/
|
||||
const QHash<QByteArray, QByteArray> &QGrpcChannelOptions::metadata() const & noexcept
|
||||
{
|
||||
Q_D(const QGrpcChannelOptions);
|
||||
return d->metadata();
|
||||
}
|
||||
QHash<QByteArray, QByteArray> QGrpcChannelOptions::metadata() &&
|
||||
{
|
||||
Q_D(QGrpcChannelOptions);
|
||||
if (d->ref.loadRelaxed() != 1) // return copy if shared
|
||||
return d->metadata();
|
||||
return std::move(*d_ptr).metadata();
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(const QHash<QByteArray, QByteArray> &metadata)
|
||||
\fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata)
|
||||
\deprecated [6.13] Use the QMultiHash overload instead.
|
||||
|
||||
Sets the client \a metadata for the channel and returns a reference to the
|
||||
updated object.
|
||||
\include qgrpccommonoptions.cpp set-metadata
|
||||
|
||||
\include qgrpccalloptions.cpp set-metadata-desc
|
||||
//! [merge-md-note]
|
||||
\note This metadata is included in every RPC made through the channel.
|
||||
Channel metadata is \b{merged} with any call-specific metadata when the RPC
|
||||
starts — see
|
||||
//! [merge-md-note]
|
||||
\l{QGrpcCallOptions::setMetadata(const QMultiHash<QByteArray,
|
||||
QByteArray>&)}{QGrpcCallOptions::setMetadata(QMultiHash)}
|
||||
|
||||
\note The metadata set via the channel options applies to all RPCs that
|
||||
operate on the channel, except those overridden by
|
||||
QGrpcCallOptions::setMetadata().
|
||||
\sa metadata()
|
||||
*/
|
||||
QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(const QHash<QByteArray, QByteArray> &metadata)
|
||||
{
|
||||
if (d_ptr->metadata == metadata)
|
||||
if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcChannelOptions);
|
||||
d->metadata = metadata;
|
||||
d->setMetadata(metadata);
|
||||
return *this;
|
||||
}
|
||||
QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata)
|
||||
{
|
||||
if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcChannelOptions);
|
||||
d->setMetadata(std::move(metadata));
|
||||
return *this;
|
||||
}
|
||||
|
||||
QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata)
|
||||
#endif // QT_DEPRECATED_SINCE(6, 13)
|
||||
|
||||
/*!
|
||||
\since 6.10
|
||||
\fn const QMultiHash<QByteArray, QByteArray> &QGrpcChannelOptions::metadata(QtGrpc::MultiValueTag) const &
|
||||
\fn QMultiHash<QByteArray, QByteArray> QGrpcChannelOptions::metadata(QtGrpc::MultiValueTag) &&
|
||||
|
||||
\include qgrpccommonoptions.cpp metadata-multi
|
||||
|
||||
\sa {setMetadata(const QMultiHash<QByteArray, QByteArray>&)}{setMetadata}
|
||||
*/
|
||||
const QMultiHash<QByteArray, QByteArray> &
|
||||
QGrpcChannelOptions::metadata(QtGrpc::MultiValueTag tag) const & noexcept
|
||||
{
|
||||
if (d_ptr->metadata == metadata)
|
||||
Q_D(const QGrpcChannelOptions);
|
||||
return d->metadata(tag);
|
||||
}
|
||||
|
||||
QMultiHash<QByteArray, QByteArray>
|
||||
QGrpcChannelOptions::metadata(QtGrpc::MultiValueTag tag) &&
|
||||
{
|
||||
Q_D(QGrpcChannelOptions);
|
||||
if (d->ref.loadRelaxed() != 1)
|
||||
return d->metadata(tag);
|
||||
return std::move(*d_ptr).metadata(tag);
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.10
|
||||
\fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata)
|
||||
\fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata)
|
||||
\fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> list)
|
||||
|
||||
\include qgrpccommonoptions.cpp set-metadata-multi
|
||||
|
||||
\include qgrpcchanneloptions.cpp merge-md-note
|
||||
\l{QGrpcCallOptions::setMetadata(const QMultiHash<QByteArray,
|
||||
QByteArray>&)}{QGrpcCallOptions::setMetadata(QMultiHash)}
|
||||
|
||||
\sa metadata(QtGrpc::MultiValueTag)
|
||||
*/
|
||||
QGrpcChannelOptions &
|
||||
QGrpcChannelOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata)
|
||||
{
|
||||
if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcChannelOptions);
|
||||
d->metadata = std::move(metadata);
|
||||
d->setMetadata(metadata);
|
||||
return *this;
|
||||
}
|
||||
QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata)
|
||||
{
|
||||
if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
|
||||
return *this;
|
||||
d_ptr.detach();
|
||||
Q_D(QGrpcChannelOptions);
|
||||
d->setMetadata(std::move(metadata));
|
||||
return *this;
|
||||
}
|
||||
QGrpcChannelOptions &
|
||||
QGrpcChannelOptions::setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> list)
|
||||
{
|
||||
return setMetadata(QMultiHash<QByteArray, QByteArray>(list));
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.8
|
||||
|
@ -179,29 +291,7 @@ QGrpcChannelOptions::setSerializationFormat(const QGrpcSerializationFormat &form
|
|||
std::optional<std::chrono::milliseconds> QGrpcChannelOptions::deadlineTimeout() const noexcept
|
||||
{
|
||||
Q_D(const QGrpcChannelOptions);
|
||||
return d->timeout;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn const QHash<QByteArray, QByteArray> &QGrpcChannelOptions::metadata() const &
|
||||
\fn QHash<QByteArray, QByteArray> QGrpcChannelOptions::metadata() &&
|
||||
|
||||
Returns the client metadata for the channel.
|
||||
|
||||
If this field is unset, returns empty metadata.
|
||||
*/
|
||||
const QHash<QByteArray, QByteArray> &QGrpcChannelOptions::metadata() const & noexcept
|
||||
{
|
||||
Q_D(const QGrpcChannelOptions);
|
||||
return d->metadata;
|
||||
}
|
||||
|
||||
QHash<QByteArray, QByteArray> QGrpcChannelOptions::metadata() &&
|
||||
{
|
||||
Q_D(QGrpcChannelOptions);
|
||||
if (d->ref.loadRelaxed() != 1) // return copy if shared
|
||||
return { d->metadata };
|
||||
return std::move(d->metadata);
|
||||
return d->deadlineTimeout();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -258,7 +348,7 @@ QDebug operator<<(QDebug debug, const QGrpcChannelOptions &chOpts)
|
|||
const QDebugStateSaver save(debug);
|
||||
debug.nospace().noquote();
|
||||
debug << "QGrpcChannelOptions(deadline: " << chOpts.deadlineTimeout()
|
||||
<< ", metadata: " << chOpts.metadata()
|
||||
<< ", metadata: " << chOpts.metadata(QtGrpc::MultiValue)
|
||||
<< ", serializationFormat: " << chOpts.serializationFormat().suffix()
|
||||
<< ", sslConfiguration: ";
|
||||
# if QT_CONFIG(ssl)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#define QGRPCHANNELOPTIONS_H
|
||||
|
||||
#include <QtGrpc/qtgrpcglobal.h>
|
||||
#include <QtGrpc/qtgrpcnamespace.h>
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
# include <QtNetwork/qsslconfiguration.h>
|
||||
|
@ -14,7 +15,7 @@
|
|||
#include <QtCore/qshareddata.h>
|
||||
#include <QtCore/qstringfwd.h>
|
||||
#include <QtCore/qtclasshelpermacros.h>
|
||||
#include <QtCore/qurl.h>
|
||||
#include <QtCore/qtdeprecationdefinitions.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
|
@ -48,10 +49,25 @@ public:
|
|||
deadlineTimeout() const noexcept;
|
||||
Q_GRPC_EXPORT QGrpcChannelOptions &setDeadlineTimeout(std::chrono::milliseconds timeout);
|
||||
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
QT_DEPRECATED_VERSION_X_6_13("Use metadata(QtGrpc::MultiValue) for QMultiHash")
|
||||
[[nodiscard]] Q_GRPC_EXPORT const QHash<QByteArray, QByteArray> &metadata() const & noexcept;
|
||||
QT_DEPRECATED_VERSION_X_6_13("Use metadata(QtGrpc::MultiValue) for QMultiHash")
|
||||
[[nodiscard]] Q_GRPC_EXPORT QHash<QByteArray, QByteArray> metadata() &&;
|
||||
QT_DEPRECATED_VERSION_X_6_13("Use the QMultiHash overload")
|
||||
Q_GRPC_EXPORT QGrpcChannelOptions &setMetadata(const QHash<QByteArray, QByteArray> &metadata);
|
||||
QT_DEPRECATED_VERSION_X_6_13("Use the QMultiHash overload")
|
||||
Q_GRPC_EXPORT QGrpcChannelOptions &setMetadata(QHash<QByteArray, QByteArray> &&metadata);
|
||||
#endif
|
||||
[[nodiscard]] Q_GRPC_EXPORT const QMultiHash<QByteArray, QByteArray> &
|
||||
metadata(QtGrpc::MultiValueTag) const & noexcept;
|
||||
[[nodiscard]] Q_GRPC_EXPORT QMultiHash<QByteArray, QByteArray>
|
||||
metadata(QtGrpc::MultiValueTag) &&;
|
||||
Q_GRPC_EXPORT QGrpcChannelOptions &
|
||||
setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata);
|
||||
Q_GRPC_EXPORT QGrpcChannelOptions &setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata);
|
||||
Q_GRPC_EXPORT QGrpcChannelOptions &
|
||||
setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> list);
|
||||
|
||||
[[nodiscard]] Q_GRPC_EXPORT QGrpcSerializationFormat serializationFormat() const;
|
||||
Q_GRPC_EXPORT QGrpcChannelOptions &
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtGrpc/private/qgrpccommonoptions_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline QHash<QByteArray, QByteArray> mergeHash(const QMultiHash<QByteArray, QByteArray> &multiHash)
|
||||
{
|
||||
QHash<QByteArray, QByteArray> out;
|
||||
for (const auto &key : multiHash.uniqueKeys())
|
||||
out.insert(key, multiHash.value(key));
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*!
|
||||
//! [metadata]
|
||||
Returns the metadata. If this field is unset, returns empty
|
||||
metadata.
|
||||
//! [metadata]
|
||||
*/
|
||||
const QHash<QByteArray, QByteArray> &QGrpcCommonOptions::metadata() const &
|
||||
{
|
||||
m_deprecatedQHashRefUsed = true;
|
||||
if (m_metadataMulti != m_metadata)
|
||||
m_metadata = mergeHash(m_metadataMulti);
|
||||
return m_metadata;
|
||||
}
|
||||
QHash<QByteArray, QByteArray> QGrpcCommonOptions::metadata() &&
|
||||
{
|
||||
if (m_metadataMulti != m_metadata)
|
||||
m_metadata = mergeHash(m_metadataMulti);
|
||||
return std::move(m_metadata);
|
||||
}
|
||||
|
||||
/*!
|
||||
//! [set-metadata]
|
||||
Sets the \a metadata and returns a reference to the updated object.
|
||||
|
||||
When using QGrpcHttp2Channel, the metadata is converted to HTTP/2 headers
|
||||
and added to the gRPC request.
|
||||
//! [set-metadata]
|
||||
*/
|
||||
void QGrpcCommonOptions::setMetadata(const QHash<QByteArray, QByteArray> &md)
|
||||
{
|
||||
if (m_deprecatedQHashRefUsed)
|
||||
m_metadata = md;
|
||||
m_metadataMulti = QMultiHash<QByteArray, QByteArray>(md);
|
||||
}
|
||||
void QGrpcCommonOptions::setMetadata(QHash<QByteArray, QByteArray> &&md)
|
||||
{
|
||||
if (m_deprecatedQHashRefUsed)
|
||||
m_metadata = md;
|
||||
m_metadataMulti = QMultiHash<QByteArray, QByteArray>(std::move(md));
|
||||
}
|
||||
|
||||
#endif // QT_DEPRECATED_SINCE(6, 13)
|
||||
|
||||
/*!
|
||||
//! [deadline-timeout]
|
||||
Returns the timeout duration that is used to calculate the deadline for RPCs.
|
||||
|
||||
If this field is unset, returns an empty \c {std::optional}.
|
||||
//! [deadline-timeout]
|
||||
*/
|
||||
std::optional<std::chrono::milliseconds> QGrpcCommonOptions::deadlineTimeout() const noexcept
|
||||
{
|
||||
return m_timeout;
|
||||
}
|
||||
|
||||
/*!
|
||||
//! [set-deadline-timeout]
|
||||
Sets the \a timeout and returns a reference to the updated object.
|
||||
|
||||
A deadline sets the limit for how long a client is willing to wait for a
|
||||
response from a server. The actual deadline is computed by adding the \a
|
||||
timeout to the start time of the RPC.
|
||||
|
||||
The deadline applies to the entire lifetime of an RPC, which includes
|
||||
receiving the final QGrpcStatus for a previously started call and can thus
|
||||
be unwanted for (long-lived) streams.
|
||||
//! [set-deadline-timeout]
|
||||
*/
|
||||
void QGrpcCommonOptions::setDeadlineTimeout(std::chrono::milliseconds t)
|
||||
{
|
||||
m_timeout = t;
|
||||
}
|
||||
|
||||
/*!
|
||||
//! [metadata-multi]
|
||||
\include qgrpccommonoptions.cpp metadata
|
||||
Multiple values per key are supported.
|
||||
|
||||
\code
|
||||
const auto &md = opts.metadata(QtGrpc::MultiValue);
|
||||
\endcode
|
||||
//! [metadata-multi]
|
||||
*/
|
||||
const QMultiHash<QByteArray, QByteArray> &
|
||||
QGrpcCommonOptions::metadata(QtGrpc::MultiValueTag /*tag*/) const &
|
||||
{
|
||||
return m_metadataMulti;
|
||||
}
|
||||
QMultiHash<QByteArray, QByteArray> QGrpcCommonOptions::metadata(QtGrpc::MultiValueTag /*tag*/) &&
|
||||
{
|
||||
return std::move(m_metadataMulti);
|
||||
}
|
||||
|
||||
/*!
|
||||
//! [set-metadata-multi]
|
||||
\include qgrpccommonoptions.cpp set-metadata
|
||||
Multiple values per key are supported.
|
||||
//! [set-metadata-multi]
|
||||
*/
|
||||
void QGrpcCommonOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &md)
|
||||
{
|
||||
m_metadataMulti = md;
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
if (m_deprecatedQHashRefUsed)
|
||||
m_metadata = mergeHash(m_metadataMulti);
|
||||
#endif
|
||||
}
|
||||
|
||||
void QGrpcCommonOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&md)
|
||||
{
|
||||
m_metadataMulti = std::move(md);
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
if (m_deprecatedQHashRefUsed)
|
||||
m_metadata = mergeHash(m_metadataMulti);
|
||||
#endif
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#ifndef QTGRPCCOMMONOPTIONS_P_H
|
||||
#define QTGRPCCOMMONOPTIONS_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtGrpc/qtgrpcglobal.h>
|
||||
#include <QtGrpc/qtgrpcnamespace.h>
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qshareddata.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QGrpcCommonOptions : public QSharedData
|
||||
{
|
||||
public:
|
||||
QGrpcCommonOptions() = default;
|
||||
virtual ~QGrpcCommonOptions() = default;
|
||||
|
||||
[[nodiscard]] std::optional<std::chrono::milliseconds> deadlineTimeout() const noexcept;
|
||||
void setDeadlineTimeout(std::chrono::milliseconds t);
|
||||
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
const QHash<QByteArray, QByteArray> &metadata() const &;
|
||||
QHash<QByteArray, QByteArray> metadata() &&;
|
||||
void setMetadata(const QHash<QByteArray, QByteArray> &md);
|
||||
void setMetadata(QHash<QByteArray, QByteArray> &&md);
|
||||
#endif
|
||||
const QMultiHash<QByteArray, QByteArray> &metadata(QtGrpc::MultiValueTag /*tag*/) const &;
|
||||
QMultiHash<QByteArray, QByteArray> metadata(QtGrpc::MultiValueTag /*tag*/) &&;
|
||||
void setMetadata(const QMultiHash<QByteArray, QByteArray> &md);
|
||||
void setMetadata(QMultiHash<QByteArray, QByteArray> &&md);
|
||||
|
||||
private:
|
||||
std::optional<std::chrono::milliseconds> m_timeout;
|
||||
QMultiHash<QByteArray, QByteArray> m_metadataMulti;
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
mutable QHash<QByteArray, QByteArray> m_metadata;
|
||||
mutable bool m_deprecatedQHashRefUsed = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline bool operator==(const QMultiHash<QByteArray, QByteArray> &multiHash,
|
||||
const QHash<QByteArray, QByteArray> &hash)
|
||||
{
|
||||
if (hash.size() != multiHash.size())
|
||||
return false;
|
||||
for (const auto &[k, v] : hash.asKeyValueRange()) {
|
||||
const auto [f, l] = multiHash.equal_range(k);
|
||||
if (f == l || std::next(f) != l || *f != v)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool operator!=(const QMultiHash<QByteArray, QByteArray> &multiHash,
|
||||
const QHash<QByteArray, QByteArray> &hash)
|
||||
{
|
||||
return !(multiHash == hash);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
|
@ -553,8 +553,8 @@ void Http2Handler::prepareInitialRequest(QGrpcOperationContext *operationContext
|
|||
}
|
||||
};
|
||||
|
||||
iterateMetadata(channelOptions.metadata());
|
||||
iterateMetadata(operationContext->callOptions().metadata());
|
||||
iterateMetadata(channelOptions.metadata(QtGrpc::MultiValue));
|
||||
iterateMetadata(operationContext->callOptions().metadata(QtGrpc::MultiValue));
|
||||
|
||||
writeMessage(operationContext->argument());
|
||||
}
|
||||
|
@ -688,8 +688,8 @@ QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri, QGrpcHttp2Ch
|
|||
: defaultContentType;
|
||||
bool warnAboutFormatConflict = !formatSuffix.isEmpty();
|
||||
|
||||
const auto it = channelOptions.metadata().constFind(ContentTypeHeader.data());
|
||||
if (it != channelOptions.metadata().cend()) {
|
||||
const auto it = channelOptions.metadata(QtGrpc::MultiValue).constFind(ContentTypeHeader.data());
|
||||
if (it != channelOptions.metadata(QtGrpc::MultiValue).cend()) {
|
||||
if (formatSuffix.isEmpty() && it.value() != DefaultContentType) {
|
||||
if (it.value() == "application/grpc+json") {
|
||||
channelOptions.setSerializationFormat(SerializationFormat::Json);
|
||||
|
|
|
@ -47,6 +47,14 @@ enum class StatusCode : quint8 {
|
|||
};
|
||||
Q_ENUM_NS(StatusCode)
|
||||
|
||||
// ### Qt7: remove QHash metadata interfaces.
|
||||
enum class MultiValueTag : quint8 { Allow QT_DEPRECATED_X("use QtGrpc::MultiValue") };
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_DEPRECATED
|
||||
QT_WARNING_DISABLE_CLANG("-Wunused-const-variable")
|
||||
inline static constexpr auto MultiValue = QtGrpc::MultiValueTag::Allow;
|
||||
QT_WARNING_POP
|
||||
|
||||
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
|
||||
} // namespace QtGrpc
|
||||
|
||||
|
|
|
@ -82,3 +82,21 @@
|
|||
\sa{https://github.com/grpc/grpc/blob/master/doc/statuscodes.md}{gRPC status codes}
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.10
|
||||
\enum QtGrpc::MultiValueTag
|
||||
\brief Tag type used to access QMultiHash metadata.
|
||||
\omitvalue Allow
|
||||
\note This type is an implementation detail. Use QtGrpc::MultiValue for public API access.
|
||||
|
||||
\sa QtGrpc::MultiValue, QGrpcChannelOptions::metadata(QtGrpc::MultiValueTag),
|
||||
QGrpcCallOptions::metadata(QtGrpc::MultiValueTag)
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.10
|
||||
\variable QtGrpc::MultiValue
|
||||
\brief Tag used to access QMultiHash metadata.
|
||||
\sa QGrpcChannelOptions::metadata(QtGrpc::MultiValueTag),
|
||||
QGrpcCallOptions::metadata(QtGrpc::MultiValueTag)
|
||||
*/
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
explicit QQmlGrpcMetadata(QObject *parent = nullptr);
|
||||
~QQmlGrpcMetadata() override;
|
||||
|
||||
const QHash<QByteArray, QByteArray> &metadata() const & noexcept { return m_metadata; }
|
||||
const QMultiHash<QByteArray, QByteArray> &metadata() const & noexcept { return m_metadata; }
|
||||
void metadata() && = delete;
|
||||
|
||||
const QVariantMap &data() const { return m_variantdata; }
|
||||
|
@ -48,7 +48,7 @@ Q_SIGNALS:
|
|||
|
||||
private:
|
||||
QVariantMap m_variantdata;
|
||||
QHash<QByteArray, QByteArray> m_metadata;
|
||||
QMultiHash<QByteArray, QByteArray> m_metadata;
|
||||
|
||||
Q_DISABLE_COPY_MOVE(QQmlGrpcMetadata)
|
||||
};
|
||||
|
|
|
@ -10,6 +10,8 @@ endif()
|
|||
qt_internal_add_test(tst_qgrpccalloptions
|
||||
SOURCES
|
||||
tst_qgrpccalloptions.cpp
|
||||
INCLUDE_DIRECTORIES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../shared"
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
Qt::Test
|
||||
|
|
|
@ -1,129 +1,32 @@
|
|||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <grpccommonoptions.h>
|
||||
|
||||
#include <QtGrpc/qgrpccalloptions.h>
|
||||
|
||||
#include <QtTest/qtest.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class QGrpcCallOptionsTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void hasSpecialMemberFunctions() const;
|
||||
void hasImplicitQVariant() const;
|
||||
void hasMemberSwap() const;
|
||||
void propertyMetadata() const;
|
||||
void propertyDeadline() const;
|
||||
void streamsToDebug() const;
|
||||
void hasSpecialMemberFunctions() const { common.hasSpecialMemberFunctions(); }
|
||||
void hasImplicitQVariant() const { common.hasImplicitQVariant(); }
|
||||
void hasMemberSwap() const { common.hasMemberSwap(); }
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
void deprecatedPropertyMetadata() const { common.deprecatedPropertyMetadata(); }
|
||||
void propertyMetadataCompat() const { common.propertyMetadataCompat(); }
|
||||
#endif
|
||||
void propertyMetadata() const { common.propertyMetadata(); }
|
||||
void propertyDeadline() const { common.propertyDeadline(); }
|
||||
void streamsToDebug() const { common.streamsToDebug(); }
|
||||
|
||||
private:
|
||||
GrpcCommonOptionsTest<QGrpcCallOptions> common;
|
||||
};
|
||||
|
||||
void QGrpcCallOptionsTest::hasSpecialMemberFunctions() const
|
||||
{
|
||||
QGrpcCallOptions o1;
|
||||
QVERIFY(!o1.deadlineTimeout());
|
||||
QVERIFY(o1.metadata().empty());
|
||||
|
||||
o1.setDeadlineTimeout(100ms);
|
||||
|
||||
QGrpcCallOptions o2(o1);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
|
||||
QGrpcCallOptions o3 = o1;
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o3.deadlineTimeout());
|
||||
|
||||
QGrpcCallOptions o4(std::move(o1));
|
||||
QCOMPARE_EQ(o4.deadlineTimeout(), o2.deadlineTimeout());
|
||||
|
||||
o1 = std::move(o4);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
}
|
||||
|
||||
void QGrpcCallOptionsTest::hasImplicitQVariant() const
|
||||
{
|
||||
QGrpcCallOptions o1;
|
||||
o1.setDeadlineTimeout(250ms);
|
||||
o1.setMetadata({
|
||||
{ "keyA", "valA" },
|
||||
{ "keyB", "valB" },
|
||||
});
|
||||
|
||||
QVariant v = o1;
|
||||
QCOMPARE_EQ(v.metaType(), QMetaType::fromType<QGrpcCallOptions>());
|
||||
const auto o2 = v.value<QGrpcCallOptions>();
|
||||
QCOMPARE_EQ(o1.metadata(), o2.metadata());
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
}
|
||||
|
||||
void QGrpcCallOptionsTest::hasMemberSwap() const
|
||||
{
|
||||
constexpr std::chrono::milliseconds Dur = 50ms;
|
||||
|
||||
QGrpcCallOptions o1;
|
||||
o1.setDeadlineTimeout(Dur);
|
||||
QGrpcCallOptions o2;
|
||||
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QVERIFY(!o2.deadlineTimeout());
|
||||
o2.swap(o1);
|
||||
QCOMPARE_EQ(o2.deadlineTimeout(), Dur);
|
||||
QVERIFY(!o1.deadlineTimeout());
|
||||
swap(o2, o1);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QVERIFY(!o2.deadlineTimeout());
|
||||
}
|
||||
|
||||
void QGrpcCallOptionsTest::propertyMetadata() const
|
||||
{
|
||||
QHash<QByteArray, QByteArray> md = {
|
||||
{ "keyA", "valA" },
|
||||
{ "keyB", "valB" },
|
||||
};
|
||||
|
||||
QGrpcCallOptions o1;
|
||||
auto o1Detach = o1;
|
||||
o1.setMetadata(md);
|
||||
QCOMPARE_EQ(o1.metadata(), md);
|
||||
QCOMPARE_NE(o1.metadata(), o1Detach.metadata());
|
||||
|
||||
QGrpcCallOptions o2;
|
||||
auto o2Detach = o2;
|
||||
o2.setMetadata(std::move(md));
|
||||
QCOMPARE_EQ(o2.metadata(), o1.metadata());
|
||||
QCOMPARE_NE(o2.metadata(), o2Detach.metadata());
|
||||
|
||||
QCOMPARE_EQ(std::move(o1).metadata(), o2.metadata());
|
||||
}
|
||||
|
||||
void QGrpcCallOptionsTest::propertyDeadline() const
|
||||
{
|
||||
constexpr std::chrono::milliseconds Dur = 50ms;
|
||||
|
||||
QGrpcCallOptions o1;
|
||||
auto o1Detach = o1;
|
||||
o1.setDeadlineTimeout(Dur);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QCOMPARE_NE(o1.deadlineTimeout(), o1Detach.deadlineTimeout());
|
||||
}
|
||||
|
||||
void QGrpcCallOptionsTest::streamsToDebug() const
|
||||
{
|
||||
QGrpcCallOptions o;
|
||||
QString storage;
|
||||
QDebug dbg(&storage);
|
||||
dbg.noquote().nospace();
|
||||
|
||||
dbg << o;
|
||||
QVERIFY(!storage.isEmpty());
|
||||
|
||||
std::unique_ptr<char[]> ustr(QTest::toString(o));
|
||||
QCOMPARE_EQ(storage, QString::fromUtf8(ustr.get()));
|
||||
}
|
||||
|
||||
QTEST_MAIN(QGrpcCallOptionsTest)
|
||||
|
||||
#include "tst_qgrpccalloptions.moc"
|
||||
|
|
|
@ -10,6 +10,8 @@ endif()
|
|||
qt_internal_add_test(tst_qgrpcchanneloptions
|
||||
SOURCES
|
||||
tst_qgrpcchanneloptions.cpp
|
||||
INCLUDE_DIRECTORIES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../shared"
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
Qt::Test
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <grpccommonoptions.h>
|
||||
|
||||
#include <QtGrpc/qgrpcchanneloptions.h>
|
||||
#include <QtGrpc/qgrpcserializationformat.h>
|
||||
|
||||
|
@ -8,116 +10,31 @@
|
|||
|
||||
#include <cstring>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class QGrpcChannelOptionsTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void hasSpecialMemberFunctions() const;
|
||||
void hasImplicitQVariant() const;
|
||||
void hasMemberSwap() const;
|
||||
void propertyMetadata() const;
|
||||
void propertyDeadline() const;
|
||||
void hasSpecialMemberFunctions() const { common.hasSpecialMemberFunctions(); }
|
||||
void hasImplicitQVariant() const { common.hasImplicitQVariant(); }
|
||||
void hasMemberSwap() const { common.hasMemberSwap(); }
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
void deprecatedPropertyMetadata() const { common.deprecatedPropertyMetadata(); }
|
||||
void propertyMetadataCompat() const { common.propertyMetadataCompat(); }
|
||||
#endif
|
||||
void propertyMetadata() const { common.propertyMetadata(); }
|
||||
void propertyDeadline() const { common.propertyDeadline(); }
|
||||
void streamsToDebug() const { common.streamsToDebug(); }
|
||||
|
||||
void propertySerializationFormat() const;
|
||||
#if QT_CONFIG(ssl)
|
||||
void propertySslConfiguration() const;
|
||||
#endif
|
||||
void streamsToDebug() const;
|
||||
|
||||
private:
|
||||
GrpcCommonOptionsTest<QGrpcChannelOptions> common;
|
||||
};
|
||||
|
||||
void QGrpcChannelOptionsTest::hasSpecialMemberFunctions() const
|
||||
{
|
||||
QGrpcChannelOptions o1;
|
||||
QVERIFY(!o1.deadlineTimeout());
|
||||
QVERIFY(o1.metadata().empty());
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
QVERIFY(!o1.sslConfiguration());
|
||||
#endif
|
||||
|
||||
o1.setDeadlineTimeout(100ms);
|
||||
|
||||
QGrpcChannelOptions o2(o1);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
|
||||
QGrpcChannelOptions o3 = o1;
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o3.deadlineTimeout());
|
||||
|
||||
QGrpcChannelOptions o4(std::move(o1));
|
||||
QCOMPARE_EQ(o4.deadlineTimeout(), o2.deadlineTimeout());
|
||||
|
||||
o1 = std::move(o4);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
}
|
||||
|
||||
void QGrpcChannelOptionsTest::hasImplicitQVariant() const
|
||||
{
|
||||
QGrpcChannelOptions o1;
|
||||
o1.setDeadlineTimeout(250ms);
|
||||
o1.setMetadata({
|
||||
{ "keyA", "valA" },
|
||||
{ "keyB", "valB" },
|
||||
});
|
||||
|
||||
QVariant v = o1;
|
||||
QCOMPARE_EQ(v.metaType(), QMetaType::fromType<QGrpcChannelOptions>());
|
||||
const auto o2 = v.value<QGrpcChannelOptions>();
|
||||
QCOMPARE_EQ(o1.metadata(), o2.metadata());
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
}
|
||||
|
||||
void QGrpcChannelOptionsTest::hasMemberSwap() const
|
||||
{
|
||||
constexpr std::chrono::milliseconds Dur = 50ms;
|
||||
|
||||
QGrpcChannelOptions o1;
|
||||
o1.setDeadlineTimeout(Dur);
|
||||
QGrpcChannelOptions o2;
|
||||
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QVERIFY(!o2.deadlineTimeout());
|
||||
o2.swap(o1);
|
||||
QCOMPARE_EQ(o2.deadlineTimeout(), Dur);
|
||||
swap(o2, o1);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QVERIFY(!o2.deadlineTimeout());
|
||||
}
|
||||
|
||||
void QGrpcChannelOptionsTest::propertyMetadata() const
|
||||
{
|
||||
QHash<QByteArray, QByteArray> md = {
|
||||
{ "keyA", "valA" },
|
||||
{ "keyB", "valB" },
|
||||
};
|
||||
|
||||
QGrpcChannelOptions o1;
|
||||
auto o1Detach = o1;
|
||||
o1.setMetadata(md);
|
||||
QCOMPARE_EQ(o1.metadata(), md);
|
||||
QCOMPARE_NE(o1.metadata(), o1Detach.metadata());
|
||||
|
||||
QGrpcChannelOptions o2;
|
||||
auto o2Detach = o2;
|
||||
o2.setMetadata(std::move(md));
|
||||
QCOMPARE_EQ(o2.metadata(), o1.metadata());
|
||||
QCOMPARE_NE(o1.metadata(), o2Detach.metadata());
|
||||
|
||||
QCOMPARE_EQ(std::move(o1).metadata(), o2.metadata());
|
||||
}
|
||||
|
||||
void QGrpcChannelOptionsTest::propertyDeadline() const
|
||||
{
|
||||
constexpr std::chrono::milliseconds Dur = 50ms;
|
||||
|
||||
QGrpcChannelOptions o1;
|
||||
auto o1Detach = o1;
|
||||
o1.setDeadlineTimeout(Dur);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QCOMPARE_NE(o1.deadlineTimeout(), o1Detach.deadlineTimeout());
|
||||
}
|
||||
|
||||
void QGrpcChannelOptionsTest::propertySerializationFormat() const
|
||||
{
|
||||
QGrpcSerializationFormat fmt(QtGrpc::SerializationFormat::Json);
|
||||
|
@ -147,20 +64,6 @@ void QGrpcChannelOptionsTest::propertySslConfiguration() const
|
|||
}
|
||||
#endif
|
||||
|
||||
void QGrpcChannelOptionsTest::streamsToDebug() const
|
||||
{
|
||||
QGrpcChannelOptions o;
|
||||
QString storage;
|
||||
QDebug dbg(&storage);
|
||||
dbg.nospace().noquote();
|
||||
|
||||
dbg << o;
|
||||
QVERIFY(!storage.isEmpty());
|
||||
|
||||
std::unique_ptr<char[]> ustr(QTest::toString(o));
|
||||
QCOMPARE_EQ(storage, QString::fromUtf8(ustr.get()));
|
||||
}
|
||||
|
||||
QTEST_MAIN(QGrpcChannelOptionsTest)
|
||||
|
||||
#include "tst_qgrpcchanneloptions.moc"
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtTest/qtest.h>
|
||||
|
||||
#include <QtGrpc/qtgrpcnamespace.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qhash.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
template <typename T>
|
||||
class GrpcCommonOptionsTest
|
||||
{
|
||||
public:
|
||||
void hasSpecialMemberFunctions() const
|
||||
{
|
||||
T o1;
|
||||
QVERIFY(!o1.deadlineTimeout());
|
||||
QVERIFY(o1.metadata(QtGrpc::MultiValue).empty());
|
||||
|
||||
o1.setDeadlineTimeout(100ms);
|
||||
|
||||
T o2(o1);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
|
||||
T o3 = o1;
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o3.deadlineTimeout());
|
||||
|
||||
T o4(std::move(o1));
|
||||
QCOMPARE_EQ(o4.deadlineTimeout(), o2.deadlineTimeout());
|
||||
|
||||
o1 = std::move(o4);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
}
|
||||
void hasImplicitQVariant() const
|
||||
{
|
||||
T o1;
|
||||
o1.setDeadlineTimeout(250ms);
|
||||
o1.setMetadata({
|
||||
{ "keyA", "valA" },
|
||||
{ "keyB", "valB" },
|
||||
});
|
||||
|
||||
QVariant v = o1;
|
||||
QCOMPARE_EQ(v.metaType(), QMetaType::fromType<T>());
|
||||
const auto o2 = v.value<T>();
|
||||
QCOMPARE_EQ(o1.metadata(QtGrpc::MultiValue), o2.metadata(QtGrpc::MultiValue));
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout());
|
||||
}
|
||||
void hasMemberSwap() const
|
||||
{
|
||||
constexpr std::chrono::milliseconds Dur = 50ms;
|
||||
|
||||
T o1;
|
||||
o1.setDeadlineTimeout(Dur);
|
||||
T o2;
|
||||
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QVERIFY(!o2.deadlineTimeout());
|
||||
o2.swap(o1);
|
||||
QCOMPARE_EQ(o2.deadlineTimeout(), Dur);
|
||||
QVERIFY(!o1.deadlineTimeout());
|
||||
swap(o2, o1);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QVERIFY(!o2.deadlineTimeout());
|
||||
}
|
||||
|
||||
#if QT_DEPRECATED_SINCE(6, 13)
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_DEPRECATED
|
||||
|
||||
void deprecatedPropertyMetadata() const
|
||||
{
|
||||
QHash<QByteArray, QByteArray> data = {
|
||||
{ "keyA", "valA" },
|
||||
{ "keyB", "valB" },
|
||||
};
|
||||
|
||||
// cref setter
|
||||
T o1;
|
||||
auto o1Detach = o1;
|
||||
o1.setMetadata(data);
|
||||
QCOMPARE_EQ(o1.metadata(), data);
|
||||
QCOMPARE_NE(o1.metadata(), o1Detach.metadata());
|
||||
|
||||
// rvalue setter
|
||||
T o2;
|
||||
auto o2Detach = o2;
|
||||
auto dataMoved = data;
|
||||
o2.setMetadata(std::move(dataMoved));
|
||||
QCOMPARE_EQ(o2.metadata(), data);
|
||||
QCOMPARE_NE(o2.metadata(), o2Detach.metadata());
|
||||
|
||||
// rvalue-this getter
|
||||
T o3;
|
||||
o3.setMetadata(data);
|
||||
auto movedMd = std::move(o3).metadata();
|
||||
QCOMPARE_EQ(movedMd, data);
|
||||
}
|
||||
void propertyMetadataCompat() const
|
||||
{
|
||||
auto toMulti = [](const QHash<QByteArray, QByteArray> &m) {
|
||||
return QMultiHash<QByteArray, QByteArray>(m);
|
||||
};
|
||||
QMultiHash<QByteArray, QByteArray> multiMd = {
|
||||
{ "keyA", "valA1" },
|
||||
{ "keyA", "valA2" },
|
||||
{ "keyB", "valB1" },
|
||||
{ "keyB", "valB2" },
|
||||
{ "keyC", "valC" },
|
||||
};
|
||||
QHash<QByteArray, QByteArray> md = {
|
||||
{ "keyA", "valA2" },
|
||||
{ "keyB", "valB2" },
|
||||
{ "keyC", "valC" },
|
||||
};
|
||||
|
||||
T o1;
|
||||
o1.setMetadata(md);
|
||||
|
||||
const auto &mdRef = o1.metadata();
|
||||
const auto &multiMdRef = o1.metadata(QtGrpc::MultiValue);
|
||||
|
||||
QCOMPARE_EQ(mdRef, md);
|
||||
QCOMPARE_EQ(multiMdRef, toMulti(mdRef));
|
||||
QCOMPARE_NE(typeid(mdRef), typeid(multiMdRef));
|
||||
|
||||
// Check that the handed out reference gets updates for QMultiHash setter
|
||||
o1.setMetadata(multiMd);
|
||||
QCOMPARE_EQ(multiMdRef, multiMd);
|
||||
QCOMPARE_EQ(mdRef, md);
|
||||
multiMd.insert("keyD", "valD");
|
||||
o1.setMetadata(multiMd);
|
||||
QCOMPARE_EQ(multiMdRef, multiMd);
|
||||
QCOMPARE_NE(mdRef, md);
|
||||
md.insert("keyD", "valD");
|
||||
QCOMPARE_EQ(mdRef, md);
|
||||
// Check that the handed out reference gets updates for QHash setter
|
||||
o1.setMetadata(md);
|
||||
QCOMPARE_EQ(multiMdRef, toMulti(md));
|
||||
QCOMPARE_EQ(mdRef, md);
|
||||
|
||||
// Check shared state mutation due to lazy evaluation in metadata()
|
||||
auto mdCopy = md;
|
||||
T o2;
|
||||
o2.setMetadata(mdCopy);
|
||||
auto o2Detach = o2;
|
||||
const auto &o2Md = o2.metadata();
|
||||
const auto &o2DetachMd = o2Detach.metadata();
|
||||
QCOMPARE_EQ(o2Md, mdCopy);
|
||||
QCOMPARE_EQ(o2Md, o2DetachMd);
|
||||
mdCopy.insert("keyX", "valX");
|
||||
o2.setMetadata(mdCopy); // trigger new merge
|
||||
const auto &o2MdAfter = o2.metadata();
|
||||
const auto &o2DetachMdAfter = o2Detach.metadata();
|
||||
QCOMPARE_NE(o2MdAfter, o2DetachMdAfter);
|
||||
|
||||
T o3A;
|
||||
T o3B = o3A;
|
||||
const auto &o3aMd = o3A.metadata();
|
||||
o3B.setMetadata(QHash<QByteArray, QByteArray>{
|
||||
{"keyA","valA"}, {"keyB","valB"}
|
||||
});
|
||||
// o3aMd is not affected by the update since o3B deprecatedQHashRef is used
|
||||
QCOMPARE_NE(o3aMd, o3B.metadata());
|
||||
o3A.setMetadata(QHash<QByteArray, QByteArray>{
|
||||
{"keyA","valA"}, {"keyB","valB"}, {"keyC","valC"},
|
||||
});
|
||||
// o3aMd is updated accoringly though
|
||||
QCOMPARE_EQ(o3aMd, o3A.metadata());
|
||||
QCOMPARE_NE(o3B.metadata(), o3A.metadata());
|
||||
}
|
||||
|
||||
QT_WARNING_POP
|
||||
#endif
|
||||
void propertyMetadata() const
|
||||
{
|
||||
std::initializer_list<std::pair<QByteArray, QByteArray>> list = {
|
||||
{ "keyA", "valA1" },
|
||||
{ "keyA", "valA2" },
|
||||
{ "keyB", "valB" },
|
||||
};
|
||||
QMultiHash<QByteArray, QByteArray> data(list);
|
||||
|
||||
// cref setter
|
||||
T o1;
|
||||
auto o1Detach = o1;
|
||||
o1.setMetadata(data);
|
||||
QCOMPARE_EQ(o1.metadata(QtGrpc::MultiValue), data);
|
||||
QCOMPARE_NE(o1.metadata(QtGrpc::MultiValue), o1Detach.metadata(QtGrpc::MultiValue));
|
||||
|
||||
// rvalue setter
|
||||
T o2;
|
||||
auto o2Detach = o2;
|
||||
auto dataMoved = data;
|
||||
o2.setMetadata(std::move(dataMoved));
|
||||
QCOMPARE_EQ(o2.metadata(QtGrpc::MultiValue), data);
|
||||
QCOMPARE_NE(o2.metadata(QtGrpc::MultiValue), o2Detach.metadata(QtGrpc::MultiValue));
|
||||
|
||||
// rvalue-this getter
|
||||
T o3;
|
||||
o3.setMetadata(data);
|
||||
auto movedMd = std::move(o3).metadata(QtGrpc::MultiValue);
|
||||
QCOMPARE_EQ(movedMd, data);
|
||||
|
||||
// std::initializer_list setter
|
||||
T o4;
|
||||
o4.setMetadata(list);
|
||||
QCOMPARE_EQ(o4.metadata(QtGrpc::MultiValue), data);
|
||||
}
|
||||
void propertyDeadline() const
|
||||
{
|
||||
constexpr std::chrono::milliseconds Dur = 50ms;
|
||||
|
||||
T o1;
|
||||
auto o1Detach = o1;
|
||||
o1.setDeadlineTimeout(Dur);
|
||||
QCOMPARE_EQ(o1.deadlineTimeout(), Dur);
|
||||
QCOMPARE_NE(o1.deadlineTimeout(), o1Detach.deadlineTimeout());
|
||||
}
|
||||
void streamsToDebug() const
|
||||
{
|
||||
T o;
|
||||
QString storage;
|
||||
QDebug dbg(&storage);
|
||||
dbg.noquote().nospace();
|
||||
|
||||
dbg << o;
|
||||
QVERIFY(!storage.isEmpty());
|
||||
|
||||
std::unique_ptr<char[]> ustr(QTest::toString(o));
|
||||
QCOMPARE_EQ(storage, QString::fromUtf8(ustr.get()));
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue