Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
#include "gtest/gtest.h"
#include "fmt/format.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/ToString.h"
#include "nsCOMPtr.h"
#include "nsISupports.h"
namespace mozilla {
#define NS_ONLYFORMATTABLE_IID \
{0xc5709378, 0x9a1d, 0x4b30, {0xb0, 0xae, 0x37, 0x96, 0x8d, 0x49, 0x20, 0xdb}}
// Currently, nsCOMPtr, RefPtr, mozilla::OwningNonNull, mozilla::StaticAutoPtr
// and mozilla::StaticRefPtr uses mozilla::DebugValue(std::ostream& aOut, T*
// aValue). Then, mozilla::DebugValue prefers the formatter of fmt. If it's not
// formattable, fallback to the stream.
// Thus, this class is printed with the format_as.
struct OnlyFormattable : public nsISupports {
NS_INLINE_DECL_STATIC_IID(NS_ONLYFORMATTABLE_IID)
NS_DECL_ISUPPORTS
explicit OnlyFormattable(const std::string& aValue) : mValue(aValue) {}
std::string mValue;
private:
virtual ~OnlyFormattable() = default;
};
NS_IMPL_ISUPPORTS(OnlyFormattable, OnlyFormattable)
inline auto format_as(const OnlyFormattable& aObj) {
return "formatted value: " + aObj.mValue;
}
#define NS_ONLYSTREAMABLE_IID \
{0xedb2a297, 0x0dfc, 0x4cf6, {0xa3, 0xbb, 0x3c, 0x80, 0xf7, 0xff, 0x0d, 0x5c}}
// This class is not formattable. Therefore, `operator<<` is used instead.
struct OnlyStreamable : public nsISupports {
NS_INLINE_DECL_STATIC_IID(NS_ONLYSTREAMABLE_IID)
NS_DECL_ISUPPORTS
explicit OnlyStreamable(const std::string& aValue) : mValue(aValue) {}
std::string mValue;
friend inline std::ostream& operator<<(std::ostream& aStream,
const OnlyStreamable& aObj) {
return aStream << "streamed value: " << aObj.mValue;
}
private:
virtual ~OnlyStreamable() = default;
};
NS_IMPL_ISUPPORTS(OnlyStreamable, OnlyStreamable)
#define NS_FORMATTABLEANDSTREAMABLE_IID \
{0xf477bebc, 0xbbbc, 0x4cbd, {0x85, 0x77, 0xc3, 0x92, 0xa1, 0xec, 0x4c, 0x55}}
// Finally, this class is formattable and supports stream. Because of
// mozilla::DebugValue, the format_as is used both for fmt and stream if printed
// via a pointer wrapper class.
struct FormattableAndStreamable : public nsISupports {
NS_INLINE_DECL_STATIC_IID(NS_FORMATTABLEANDSTREAMABLE_IID)
NS_DECL_ISUPPORTS
explicit FormattableAndStreamable(const std::string& aValue)
: mValue(aValue) {}
std::string mValue;
friend inline std::ostream& operator<<(std::ostream& aStream,
const FormattableAndStreamable& aObj) {
return aStream << "formatted or streamed value: " << aObj.mValue;
}
private:
virtual ~FormattableAndStreamable() = default;
};
NS_IMPL_ISUPPORTS(FormattableAndStreamable, FormattableAndStreamable)
inline auto format_as(const FormattableAndStreamable& aObj) {
return "formatted value: " + aObj.mValue;
}
TEST(FormattingAndStreaming, nsCOMPtr)
{
{
nsCOMPtr<OnlyFormattable> onlyFormattable =
MakeRefPtr<OnlyFormattable>("Foo");
EXPECT_EQ(fmt::format("{}", onlyFormattable),
fmt::format("{} @ {}", *onlyFormattable,
ToString(onlyFormattable.get())))
<< ": formatted only formattable object";
EXPECT_EQ(fmt::format("{}", ToString(onlyFormattable)),
fmt::format("{} @ {}", *onlyFormattable,
ToString(onlyFormattable.get())))
<< ": streamed only formattable object";
}
{
nsCOMPtr<OnlyStreamable> onlyStreamable = MakeRefPtr<OnlyStreamable>("Bar");
EXPECT_EQ(fmt::format("{}", onlyStreamable),
fmt::format("{} @ {}", ToString(*onlyStreamable),
ToString(onlyStreamable.get())))
<< ": formatted only streamable object";
EXPECT_EQ(fmt::format("{}", ToString(onlyStreamable)),
fmt::format("{} @ {}", ToString(*onlyStreamable),
ToString(onlyStreamable.get())))
<< ": streamed only streamable object";
}
{
nsCOMPtr<FormattableAndStreamable> formattableAndStreamable =
MakeRefPtr<FormattableAndStreamable>("Baz");
EXPECT_EQ(fmt::format("{}", formattableAndStreamable),
fmt::format("{} @ {}", *formattableAndStreamable,
ToString(formattableAndStreamable.get())))
<< ": formatted formattable and streamable object";
EXPECT_EQ(fmt::format("{}", ToString(formattableAndStreamable)),
fmt::format("{} @ {}", *formattableAndStreamable,
ToString(formattableAndStreamable.get())))
<< ": streamed formattable and streamable object";
}
}
TEST(FormattingAndStreaming, RefPtr)
{
{
RefPtr<OnlyFormattable> onlyFormattable =
MakeRefPtr<OnlyFormattable>("Foo");
EXPECT_EQ(fmt::format("{}", onlyFormattable),
fmt::format("{} @ {}", *onlyFormattable,
ToString(onlyFormattable.get())))
<< ": formatted only formattable object";
EXPECT_EQ(fmt::format("{}", ToString(onlyFormattable)),
fmt::format("{} @ {}", *onlyFormattable,
ToString(onlyFormattable.get())))
<< ": streamed only formattable object";
}
{
RefPtr<OnlyStreamable> onlyStreamable = MakeRefPtr<OnlyStreamable>("Bar");
EXPECT_EQ(fmt::format("{}", onlyStreamable),
fmt::format("{} @ {}", ToString(*onlyStreamable),
ToString(onlyStreamable.get())))
<< ": formatted only streamable object";
EXPECT_EQ(fmt::format("{}", ToString(onlyStreamable)),
fmt::format("{} @ {}", ToString(*onlyStreamable),
ToString(onlyStreamable.get())))
<< ": streamed only streamable object";
}
{
RefPtr<FormattableAndStreamable> formattableAndStreamable =
MakeRefPtr<FormattableAndStreamable>("Baz");
EXPECT_EQ(fmt::format("{}", formattableAndStreamable),
fmt::format("{} @ {}", *formattableAndStreamable,
ToString(formattableAndStreamable.get())))
<< ": formatted formattable and streamable object";
EXPECT_EQ(fmt::format("{}", ToString(formattableAndStreamable)),
fmt::format("{} @ {}", *formattableAndStreamable,
ToString(formattableAndStreamable.get())))
<< ": streamed formattable and streamable object";
}
}
TEST(FormattingAndStreaming, mozilla_OwningNonNull)
{
{
OwningNonNull<OnlyFormattable> onlyFormattable =
MakeRefPtr<OnlyFormattable>("Foo");
EXPECT_EQ(fmt::format("{}", onlyFormattable),
fmt::format("{} @ {}", *onlyFormattable,
ToString(onlyFormattable.get())))
<< ": formatted only formattable object";
EXPECT_EQ(fmt::format("{}", ToString(onlyFormattable)),
fmt::format("{} @ {}", *onlyFormattable,
ToString(onlyFormattable.get())))
<< ": streamed only formattable object";
}
{
OwningNonNull<OnlyStreamable> onlyStreamable =
MakeRefPtr<OnlyStreamable>("Bar");
EXPECT_EQ(fmt::format("{}", onlyStreamable),
fmt::format("{} @ {}", ToString(*onlyStreamable),
ToString(onlyStreamable.get())))
<< ": formatted only streamable object";
EXPECT_EQ(fmt::format("{}", ToString(onlyStreamable)),
fmt::format("{} @ {}", ToString(*onlyStreamable),
ToString(onlyStreamable.get())))
<< ": streamed only streamable object";
}
{
OwningNonNull<FormattableAndStreamable> formattableAndStreamable =
MakeRefPtr<FormattableAndStreamable>("Baz");
EXPECT_EQ(fmt::format("{}", formattableAndStreamable),
fmt::format("{} @ {}", *formattableAndStreamable,
ToString(formattableAndStreamable.get())))
<< ": formatted formattable and streamable object";
EXPECT_EQ(fmt::format("{}", ToString(formattableAndStreamable)),
fmt::format("{} @ {}", *formattableAndStreamable,
ToString(formattableAndStreamable.get())))
<< ": streamed formattable and streamable object";
}
}
template <typename T>
struct RefPtrWrapper {
RefPtr<T> mRefPtr;
friend inline std::ostream& operator<<(std::ostream& aStream,
const RefPtrWrapper& aObj) {
if constexpr (detail::supports_os<T>::value) {
return aStream << ToString(*aObj.mRefPtr);
} else {
return aStream << ToString(aObj.mRefPtr.get());
}
}
};
template <typename T>
inline auto format_as(const RefPtrWrapper<T>& aObj) {
if constexpr (fmt::is_formattable<T>::value) {
return fmt::format("{}", *aObj.mRefPtr);
} else {
return ToString(*aObj.mRefPtr);
}
}
StaticAutoPtr<RefPtrWrapper<OnlyFormattable>> sAutoOnlyFormattable;
StaticAutoPtr<RefPtrWrapper<OnlyStreamable>> sAutoOnlyStreamable;
StaticAutoPtr<RefPtrWrapper<FormattableAndStreamable>>
sAutoFormattableAndStreamable;
TEST(FormattingAndStreaming, mozilla_StaticAutoPtr)
{
{
sAutoOnlyFormattable =
new RefPtrWrapper{MakeRefPtr<OnlyFormattable>("Foo")};
EXPECT_EQ(fmt::format("{}", sAutoOnlyFormattable),
fmt::format("{} @ {}", *sAutoOnlyFormattable->mRefPtr,
ToString(sAutoOnlyFormattable.get())))
<< ": formatted only formattable object";
EXPECT_EQ(fmt::format("{}", ToString(sAutoOnlyFormattable)),
fmt::format("{} @ {}", *sAutoOnlyFormattable->mRefPtr,
ToString(sAutoOnlyFormattable.get())))
<< ": streamed only formattable object";
sAutoOnlyFormattable = nullptr;
}
{
sAutoOnlyStreamable = new RefPtrWrapper{MakeRefPtr<OnlyStreamable>("Bar")};
EXPECT_EQ(fmt::format("{}", sAutoOnlyStreamable),
fmt::format("{} @ {}", ToString(*sAutoOnlyStreamable),
ToString(sAutoOnlyStreamable.get())))
<< ": formatted only streamable object";
EXPECT_EQ(fmt::format("{}", ToString(sAutoOnlyStreamable)),
fmt::format("{} @ {}", ToString(*sAutoOnlyStreamable),
ToString(sAutoOnlyStreamable.get())))
<< ": streamed only streamable object";
sAutoOnlyStreamable = nullptr;
}
{
sAutoFormattableAndStreamable =
new RefPtrWrapper{MakeRefPtr<FormattableAndStreamable>("Baz")};
EXPECT_EQ(fmt::format("{}", sAutoFormattableAndStreamable),
fmt::format("{} @ {}", *sAutoFormattableAndStreamable->mRefPtr,
ToString(sAutoFormattableAndStreamable.get())))
<< ": formatted formattable and streamable object";
EXPECT_EQ(fmt::format("{}", ToString(sAutoFormattableAndStreamable)),
fmt::format("{} @ {}", *sAutoFormattableAndStreamable->mRefPtr,
ToString(sAutoFormattableAndStreamable.get())))
<< ": streamed formattable and streamable object";
sAutoFormattableAndStreamable = nullptr;
}
}
StaticRefPtr<OnlyFormattable> sOnlyFormattable;
StaticRefPtr<OnlyStreamable> sOnlyStreamable;
StaticRefPtr<FormattableAndStreamable> sFormattableAndStreamable;
TEST(FormattingAndStreaming, mozilla_StaticRefPtr)
{
{
sOnlyFormattable = MakeRefPtr<OnlyFormattable>("Foo");
EXPECT_EQ(fmt::format("{}", sOnlyFormattable),
fmt::format("{} @ {}", *sOnlyFormattable,
ToString(sOnlyFormattable.get())))
<< ": formatted only formattable object";
EXPECT_EQ(fmt::format("{}", ToString(sOnlyFormattable)),
fmt::format("{} @ {}", *sOnlyFormattable,
ToString(sOnlyFormattable.get())))
<< ": streamed only formattable object";
sOnlyFormattable = nullptr;
}
{
sOnlyStreamable = MakeRefPtr<OnlyStreamable>("Bar");
EXPECT_EQ(fmt::format("{}", sOnlyStreamable),
fmt::format("{} @ {}", ToString(*sOnlyStreamable),
ToString(sOnlyStreamable.get())))
<< ": formatted only streamable object";
EXPECT_EQ(fmt::format("{}", ToString(sOnlyStreamable)),
fmt::format("{} @ {}", ToString(*sOnlyStreamable),
ToString(sOnlyStreamable.get())))
<< ": streamed only streamable object";
sOnlyStreamable = nullptr;
}
{
sFormattableAndStreamable = MakeRefPtr<FormattableAndStreamable>("Baz");
EXPECT_EQ(fmt::format("{}", sFormattableAndStreamable),
fmt::format("{} @ {}", *sFormattableAndStreamable,
ToString(sFormattableAndStreamable.get())))
<< ": formatted formattable and streamable object";
EXPECT_EQ(fmt::format("{}", ToString(sFormattableAndStreamable)),
fmt::format("{} @ {}", *sFormattableAndStreamable,
ToString(sFormattableAndStreamable.get())))
<< ": streamed formattable and streamable object";
sFormattableAndStreamable = nullptr;
}
}
} // namespace mozilla