diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/dbg_output | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/dbg_output')
-rw-r--r-- | library/cpp/dbg_output/DONT_COMMIT.h | 16 | ||||
-rw-r--r-- | library/cpp/dbg_output/auto.h | 22 | ||||
-rw-r--r-- | library/cpp/dbg_output/colorscheme.h | 100 | ||||
-rw-r--r-- | library/cpp/dbg_output/dump.cpp | 1 | ||||
-rw-r--r-- | library/cpp/dbg_output/dump.h | 106 | ||||
-rw-r--r-- | library/cpp/dbg_output/dumpers.cpp | 1 | ||||
-rw-r--r-- | library/cpp/dbg_output/dumpers.h | 173 | ||||
-rw-r--r-- | library/cpp/dbg_output/engine.cpp | 33 | ||||
-rw-r--r-- | library/cpp/dbg_output/engine.h | 180 | ||||
-rw-r--r-- | library/cpp/dbg_output/ut/dbg_output_ut.cpp | 106 | ||||
-rw-r--r-- | library/cpp/dbg_output/ut/ya.make | 9 | ||||
-rw-r--r-- | library/cpp/dbg_output/ya.make | 15 |
12 files changed, 762 insertions, 0 deletions
diff --git a/library/cpp/dbg_output/DONT_COMMIT.h b/library/cpp/dbg_output/DONT_COMMIT.h new file mode 100644 index 0000000000..e7b3182c20 --- /dev/null +++ b/library/cpp/dbg_output/DONT_COMMIT.h @@ -0,0 +1,16 @@ +#pragma once + +// Including this file is possible without modifying PEERDIR (for debug purposes). +// The latter is allowed only locally, so this file is named +// in such a way that including it prevents from committing the #include via ARC-1205. + +#define DBGDUMP_INLINE_IF_INCLUDED inline + +#include "dump.cpp" +#include "dumpers.cpp" +#include "engine.cpp" + +#include <library/cpp/colorizer/colors.cpp> +#include <library/cpp/colorizer/output.cpp> + +#undef DBGDUMP_INLINE_IF_INCLUDED diff --git a/library/cpp/dbg_output/auto.h b/library/cpp/dbg_output/auto.h new file mode 100644 index 0000000000..8d96167f6a --- /dev/null +++ b/library/cpp/dbg_output/auto.h @@ -0,0 +1,22 @@ +#pragma once + +#include <util/generic/va_args.h> + +// int a = 1, b = 2; Cout << LabeledDump(a, b, 1 + 2); yields {"a": 1, "b": 2, "1 + 2": 3} +#define LabeledDump(...) \ + '{' Y_PASS_VA_ARGS(Y_MAP_ARGS_WITH_LAST(__LABELED_DUMP_NONLAST__, __LABELED_DUMP_IMPL__, __VA_ARGS__)) << '}' +#define __LABELED_DUMP_IMPL__(x) << "\"" #x "\": " << DbgDump(x) +#define __LABELED_DUMP_NONLAST__(x) __LABELED_DUMP_IMPL__(x) << ", " + +// Usage: struct TMyStruct { int A, B; }; DEFINE_DUMPER(TMyStruct, A, B); Cout << TMyStruct{3, 4}; +// yields {"A": 3, "B": 4} +#define DEFINE_DUMPER(C, ...) \ + template <> \ + struct TDumper<C> { \ + template <class S> \ + static inline void Dump(S& s, const C& v) { \ + s << DumpRaw("{") Y_PASS_VA_ARGS(Y_MAP_ARGS_WITH_LAST(__DEFINE_DUMPER_NONLAST__, __DEFINE_DUMPER_IMPL__, __VA_ARGS__)) << DumpRaw("}"); \ + } \ + }; +#define __DEFINE_DUMPER_IMPL__(x) << DumpRaw("\"" #x "\": ") << v.x +#define __DEFINE_DUMPER_NONLAST__(x) __DEFINE_DUMPER_IMPL__(x) << DumpRaw(", ") diff --git a/library/cpp/dbg_output/colorscheme.h b/library/cpp/dbg_output/colorscheme.h new file mode 100644 index 0000000000..a5b9cf749a --- /dev/null +++ b/library/cpp/dbg_output/colorscheme.h @@ -0,0 +1,100 @@ +#pragma once + +#include "engine.h" +#include <library/cpp/colorizer/output.h> + +#ifndef DBG_OUTPUT_DEFAULT_COLOR_SCHEME +#define DBG_OUTPUT_DEFAULT_COLOR_SCHEME NDbgDump::NColorScheme::TPlain +#endif + +#define DBG_OUTPUT_COLOR_HANDLER(NAME) \ + template <class S> \ + inline void NAME(S& stream) + +namespace NDbgDump { + namespace NColorScheme { + /// Start by copying this one if you want to define a custom color scheme. + struct TPlain { + // Foreground color modifiers + DBG_OUTPUT_COLOR_HANDLER(Markup) { + Y_UNUSED(stream); + } + DBG_OUTPUT_COLOR_HANDLER(String) { + Y_UNUSED(stream); + } + DBG_OUTPUT_COLOR_HANDLER(Literal) { + Y_UNUSED(stream); + } + DBG_OUTPUT_COLOR_HANDLER(ResetType) { + Y_UNUSED(stream); + } + + // Background color modifiers + DBG_OUTPUT_COLOR_HANDLER(Key) { + Y_UNUSED(stream); + } + DBG_OUTPUT_COLOR_HANDLER(Value) { + Y_UNUSED(stream); + } + DBG_OUTPUT_COLOR_HANDLER(ResetRole) { + Y_UNUSED(stream); + } + }; + + /// Use this one if you want colors but are lazy enough to define a custom color scheme. + /// Be careful enough to use DumpRaw for avoiding an endless recursion. + /// Enforce controls whether colors should be applied even if stdout is not a TTY. + template <bool Enforce = false> + class TEyebleed { + public: + TEyebleed() { + if (Enforce) { + Colors.Enable(); + } + } + + // Foreground color modifiers + DBG_OUTPUT_COLOR_HANDLER(Markup) { + stream << DumpRaw(Colors.LightGreenColor()); + } + DBG_OUTPUT_COLOR_HANDLER(String) { + stream << DumpRaw(Colors.YellowColor()); + } + DBG_OUTPUT_COLOR_HANDLER(Literal) { + stream << DumpRaw(Colors.LightRedColor()); + } + DBG_OUTPUT_COLOR_HANDLER(ResetType) { + stream << DumpRaw(Colors.OldColor()); + } + + // Background color modifiers + // TODO: support backgrounds in library/cpp/colorizer + DBG_OUTPUT_COLOR_HANDLER(Key) { + if (Depth++ == 0 && Colors.IsTTY()) { + stream << DumpRaw(TStringBuf("\033[42m")); + } + } + DBG_OUTPUT_COLOR_HANDLER(Value) { + if (Depth++ == 0 && Colors.IsTTY()) { + stream << DumpRaw(TStringBuf("\033[44m")); + } + } + DBG_OUTPUT_COLOR_HANDLER(ResetRole) { + if (--Depth == 0 && Colors.IsTTY()) { + stream << DumpRaw(TStringBuf("\033[49m")); + } + } + + private: + NColorizer::TColors Colors; + size_t Depth = 0; + }; + } +} + +namespace NPrivate { + template <typename CS> + struct TColorSchemeContainer { + CS ColorScheme; + }; +} diff --git a/library/cpp/dbg_output/dump.cpp b/library/cpp/dbg_output/dump.cpp new file mode 100644 index 0000000000..ab09a93822 --- /dev/null +++ b/library/cpp/dbg_output/dump.cpp @@ -0,0 +1 @@ +#include "dump.h" diff --git a/library/cpp/dbg_output/dump.h b/library/cpp/dbg_output/dump.h new file mode 100644 index 0000000000..c7efa105ee --- /dev/null +++ b/library/cpp/dbg_output/dump.h @@ -0,0 +1,106 @@ +#pragma once + +#include "engine.h" +#include "dumpers.h" +#include "auto.h" +#include "colorscheme.h" + +#include <util/stream/format.h> +#include <util/system/type_name.h> +#include <util/generic/hash_set.h> +#include <utility> + +/* + * Cout << DbgDump(any) << Endl; + * Cout << DbgDumpDeep(any) << Endl; + * Cout << DbgDump(any).SetIndent(true) << Endl; + * + * specialize TDumper<your type> for extending dumper + */ + +namespace NPrivate { + template <class TColorScheme> + struct TTraitsShallow { + struct TDump: public TDumpBase, public TColorSchemeContainer<TColorScheme> { + template <typename... Args> + inline TDump(Args&&... args) + : TDumpBase(std::forward<Args>(args)...) + { + } + + template <class V> + inline void Pointer(const V* v) { + if (v) { + *this << DumpRaw("(") << DumpRaw(TypeName(v).data()) << DumpRaw(")") << Hex((size_t)v); + } else { + *this << DumpRaw("(") << DumpRaw(TypeName<V>().data()) << DumpRaw("*)nullptr"); + } + } + }; + }; + + template <class TColorScheme> + struct TTraitsDeep { + struct TDump: public TDumpBase, public TColorSchemeContainer<TColorScheme> { + template <typename... Args> + inline TDump(Args&&... args) + : TDumpBase(std::forward<Args>(args)...) + { + } + + template <class V> + inline void Pointer(const V* v) { + if (v && !Visited.contains((size_t)v)) { + Visited.insert((size_t)v); + *this << DumpRaw("(") << DumpRaw(TypeName(v).data()) << DumpRaw(")") << Hex((size_t)v) << DumpRaw(" -> ") << *v; + Visited.erase((size_t)v); + } else { + *this << DumpRaw("(") << DumpRaw(TypeName<V>().data()) << DumpRaw("*)nullptr"); + } + } + + THashSet<size_t> Visited; + }; + }; + + template <class T, class TTraits> + struct TDbgDump { + inline TDbgDump(const T* t) + : T_(t) + , Indent(false) + { + } + + inline void DumpTo(IOutputStream& out) const { + typename TTraits::TDump d(out, Indent); + + d << *T_; + } + + inline TDbgDump& SetIndent(bool v) noexcept { + Indent = v; + + return *this; + } + + const T* T_; + bool Indent; + }; + + template <class T, class TTraits> + static inline IOutputStream& operator<<(IOutputStream& out, const TDbgDump<T, TTraits>& d) { + d.DumpTo(out); + + return out; + } +} + +template <class T, class TColorScheme = DBG_OUTPUT_DEFAULT_COLOR_SCHEME> +static inline ::NPrivate::TDbgDump<T, ::NPrivate::TTraitsShallow<TColorScheme>> DbgDump(const T& t) { + return {std::addressof(t)}; +} + +template <class T, class TColorScheme = DBG_OUTPUT_DEFAULT_COLOR_SCHEME> +static inline ::NPrivate::TDbgDump<T, ::NPrivate::TTraitsDeep<TColorScheme>> DbgDumpDeep(const T& t) { + return {std::addressof(t)}; +} diff --git a/library/cpp/dbg_output/dumpers.cpp b/library/cpp/dbg_output/dumpers.cpp new file mode 100644 index 0000000000..b85d15755b --- /dev/null +++ b/library/cpp/dbg_output/dumpers.cpp @@ -0,0 +1 @@ +#include "dumpers.h" diff --git a/library/cpp/dbg_output/dumpers.h b/library/cpp/dbg_output/dumpers.h new file mode 100644 index 0000000000..4868e97da0 --- /dev/null +++ b/library/cpp/dbg_output/dumpers.h @@ -0,0 +1,173 @@ +#pragma once + +#include "engine.h" + +#include <util/generic/fwd.h> +#include <util/generic/strbuf.h> +#include <util/generic/string.h> + +//smart pointers +template <class T, class D> +struct TDumper<TAutoPtr<T, D>> { + template <class S> + static inline void Dump(S& s, const TAutoPtr<T, D>& v) { + s << DumpRaw("TAutoPtr(") << v.Get() << DumpRaw(")"); + } +}; + +template <class T, class D> +struct TDumper<THolder<T, D>> { + template <class S> + static inline void Dump(S& s, const THolder<T, D>& v) { + s << DumpRaw("THolder(") << v.Get() << DumpRaw(")"); + } +}; + +template <class T, class Ops> +struct TDumper<TIntrusivePtr<T, Ops>> { + template <class S> + static inline void Dump(S& s, const TIntrusivePtr<T, Ops>& v) { + s << DumpRaw("TIntrusivePtr(") << v.Get() << DumpRaw(")"); + } +}; + +template <class T, class C, class D> +struct TDumper<TSharedPtr<T, C, D>> { + template <class S> + static inline void Dump(S& s, const TSharedPtr<T, C, D>& v) { + s << DumpRaw("TSharedPtr(") << v.Get() << DumpRaw(")"); + } +}; + +template <class T, class C, class D> +struct TDumper<TCopyPtr<T, C, D>> { + template <class S> + static inline void Dump(S& s, const TCopyPtr<T, C, D>& v) { + s << DumpRaw("TCopyPtr(") << v.Get() << DumpRaw(")"); + } +}; + +//small ints +// Default dumper prints them via IOutputStream << (value), which results in raw +// chars, not integer values. Cast to a bigger int type to force printing as +// integers. +// NB: i8 = signed char != char != unsigned char = ui8 +template <> +struct TDumper<ui8>: public TDumper<i32> { +}; + +template <> +struct TDumper<i8>: public TDumper<i32> { +}; + +//chars +template <> +struct TDumper<char>: public TCharDumper { +}; + +template <> +struct TDumper<wchar16>: public TCharDumper { +}; + +//pairs +template <class A, class B> +struct TDumper<std::pair<A, B>> { + template <class S> + static inline void Dump(S& s, const std::pair<A, B>& v) { + s.ColorScheme.Key(s); + s.ColorScheme.Literal(s); + s << v.first; + s.ColorScheme.ResetType(s); + s.ColorScheme.ResetRole(s); + s.ColorScheme.Markup(s); + s << DumpRaw(" -> "); + s.ColorScheme.Value(s); + s.ColorScheme.Literal(s); + s << v.second; + s.ColorScheme.ResetType(s); + s.ColorScheme.ResetRole(s); + } +}; + +//sequences +template <class T, class A> +struct TDumper<TVector<T, A>>: public TSeqDumper { +}; + +template <class T, class A> +struct TDumper<std::vector<T, A>>: public TSeqDumper { +}; + +template <class T> +struct TDumper<TArrayRef<T>>: public TSeqDumper { +}; + +template <class T, size_t N> +struct TDumper<std::array<T, N>>: public TSeqDumper { +}; + +template <class T, class A> +struct TDumper<TDeque<T, A>>: public TSeqDumper { +}; + +template <class T, class A> +struct TDumper<TList<T, A>>: public TSeqDumper { +}; + +//associatives +template <class K, class V, class P, class A> +struct TDumper<TMap<K, V, P, A>>: public TAssocDumper { +}; + +template <class K, class V, class P, class A> +struct TDumper<TMultiMap<K, V, P, A>>: public TAssocDumper { +}; + +template <class T, class P, class A> +struct TDumper<TSet<T, P, A>>: public TAssocDumper { +}; + +template <class T, class P, class A> +struct TDumper<TMultiSet<T, P, A>>: public TAssocDumper { +}; + +template <class K, class V, class H, class P, class A> +struct TDumper<THashMap<K, V, H, P, A>>: public TAssocDumper { +}; + +template <class K, class V, class H, class P, class A> +struct TDumper<THashMultiMap<K, V, H, P, A>>: public TAssocDumper { +}; + +template <class T, class H, class P, class A> +struct TDumper<THashSet<T, H, P, A>>: public TAssocDumper { +}; + +template <class T, class H, class P, class A> +struct TDumper<THashMultiSet<T, H, P, A>>: public TAssocDumper { +}; + +//strings +template <> +struct TDumper<TString>: public TStrDumper { +}; + +template <> +struct TDumper<const char*>: public TStrDumper { +}; + +template <> +struct TDumper<TUtf16String>: public TStrDumper { +}; + +template <> +struct TDumper<const wchar16*>: public TStrDumper { +}; + +template <class C, class T, class A> +struct TDumper<std::basic_string<C, T, A>>: public TStrDumper { +}; + +template <class TChar> +struct TDumper<TBasicStringBuf<TChar>>: public TStrDumper { +}; diff --git a/library/cpp/dbg_output/engine.cpp b/library/cpp/dbg_output/engine.cpp new file mode 100644 index 0000000000..dcb9f02522 --- /dev/null +++ b/library/cpp/dbg_output/engine.cpp @@ -0,0 +1,33 @@ +#include "engine.h" + +#include <util/string/cast.h> +#include <util/string/escape.h> + +#if !defined(DBGDUMP_INLINE_IF_INCLUDED) +#define DBGDUMP_INLINE_IF_INCLUDED +#endif + +DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::String(const TStringBuf& s) { + if (s) { + Raw(TString(s).Quote()); + } else { + Raw("(empty)"); + } +} + +DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::String(const TWtringBuf& s) { + Raw("w"); + String(ToString(s)); +} + +DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::Raw(const TStringBuf& s) { + Stream().Write(s.data(), s.size()); +} + +DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::Char(char ch) { + Raw("'" + EscapeC(&ch, 1) + "'"); +} + +DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::Char(wchar16 ch) { + Raw("w'" + ToString(EscapeC(&ch, 1)) + "'"); +} diff --git a/library/cpp/dbg_output/engine.h b/library/cpp/dbg_output/engine.h new file mode 100644 index 0000000000..f13c728c39 --- /dev/null +++ b/library/cpp/dbg_output/engine.h @@ -0,0 +1,180 @@ +#pragma once + +#include <util/stream/output.h> + +#include <utility> +#include <util/generic/strbuf.h> + +template <class T> +struct TDumper { + template <class S> + static inline void Dump(S& s, const T& t) { + s.Stream() << t; + } +}; + +namespace NDumpPrivate { + template <class T, class V> + inline void Dump(T& t, const V& v) { + ::TDumper<V>::Dump(t, v); + } + + template <class T, class V> + inline T&& operator<<(T&& t, V&& v) { + Dump(t, v); + + return std::forward<T>(t); + } + + struct TADLBase { + }; +} + +struct TDumpBase: public ::NDumpPrivate::TADLBase { + inline TDumpBase(IOutputStream& out, bool indent) noexcept + : Out(&out) + , IndentLevel(0) + , Indent(indent) + { + } + + inline IOutputStream& Stream() const noexcept { + return *Out; + } + + void Char(char ch); + void Char(wchar16 ch); + + void String(const TStringBuf& s); + void String(const TWtringBuf& s); + + void Raw(const TStringBuf& s); + + IOutputStream* Out; + size_t IndentLevel; + bool Indent; +}; + +struct TIndentScope { + inline TIndentScope(TDumpBase& d) + : D(&d) + { + ++(D->IndentLevel); + } + + inline ~TIndentScope() { + --(D->IndentLevel); + } + + TDumpBase* D; +}; + +template <class TChar> +struct TRawLiteral { + const TBasicStringBuf<TChar> S; +}; + +template <class TChar> +static inline TRawLiteral<TChar> DumpRaw(const TBasicStringBuf<TChar>& s) noexcept { + return {s}; +} + +template <class TChar> +static inline TRawLiteral<TChar> DumpRaw(const TChar* s) noexcept { + return {s}; +} + +template <class C> +struct TDumper<TRawLiteral<C>> { + template <class S> + static inline void Dump(S& s, const TRawLiteral<C>& v) { + s.Raw(v.S); + } +}; + +struct TIndentNewLine { +}; + +static inline TIndentNewLine IndentNewLine() noexcept { + return {}; +} + +template <> +struct TDumper<TIndentNewLine> { + template <class S> + static inline void Dump(S& s, const TIndentNewLine&) { + if (s.Indent) { + s << DumpRaw("\n") << DumpRaw(TString(s.IndentLevel * 4, ' ').data()); + } + } +}; + +template <class P> +struct TDumper<const P*> { + template <class S> + static inline void Dump(S& s, const P* p) { + s.Pointer(p); + } +}; + +template <class P> +struct TDumper<P*>: public TDumper<const P*> { +}; + +struct TCharDumper { + template <class S, class V> + static inline void Dump(S& s, const V& v) { + s.Char(v); + } +}; + +template <class S, class V> +static inline void OutSequence(S& s, const V& v, const char* openTag, const char* closeTag) { + s.ColorScheme.Markup(s); + s << DumpRaw(openTag); + + { + TIndentScope scope(s); + size_t cnt = 0; + + for (const auto& x : v) { + if (cnt) { + s.ColorScheme.Markup(s); + s << DumpRaw(", "); + } + + s << IndentNewLine(); + s.ColorScheme.Literal(s); + s << x; + ++cnt; + } + } + + s << IndentNewLine(); + s.ColorScheme.Markup(s); + s << DumpRaw(closeTag); + s.ColorScheme.ResetType(s); +} + +struct TAssocDumper { + template <class S, class V> + static inline void Dump(S& s, const V& v) { + ::OutSequence(s, v, "{", "}"); + } +}; + +struct TSeqDumper { + template <class S, class V> + static inline void Dump(S& s, const V& v) { + ::OutSequence(s, v, "[", "]"); + } +}; + +struct TStrDumper { + template <class S, class V> + static inline void Dump(S& s, const V& v) { + s.ColorScheme.String(s); + s.String(v); + s.ColorScheme.ResetType(s); + } +}; diff --git a/library/cpp/dbg_output/ut/dbg_output_ut.cpp b/library/cpp/dbg_output/ut/dbg_output_ut.cpp new file mode 100644 index 0000000000..7b285c84cb --- /dev/null +++ b/library/cpp/dbg_output/ut/dbg_output_ut.cpp @@ -0,0 +1,106 @@ +#include <library/cpp/dbg_output/dump.h> +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/str.h> +#include <util/string/builder.h> +#include <util/string/escape.h> +#include <util/generic/map.h> + +namespace { + struct TX { + inline TX() { + N = this; + } + + TX* N; + }; +} + +template <> +struct TDumper<TX> { + template <class S> + static inline void Dump(S& s, const TX& x) { + s << DumpRaw("x") << x.N; + } +}; + +namespace TMyNS { + struct TMyStruct { + int A, B; + }; +} +DEFINE_DUMPER(TMyNS::TMyStruct, A, B) + +Y_UNIT_TEST_SUITE(TContainerPrintersTest) { + Y_UNIT_TEST(TestVectorInt) { + TStringStream out; + out << DbgDump(TVector<int>({1, 2, 3, 4, 5})); + UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "[1, 2, 3, 4, 5]"); + } + + Y_UNIT_TEST(TestMapCharToCharArray) { + TStringStream out; + + TMap<char, const char*> m; + + m['a'] = "SMALL LETTER A"; + m['b'] = nullptr; + + out << DbgDump(m); + + UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "{'a' -> \"SMALL LETTER A\", 'b' -> (empty)}"); + } + + Y_UNIT_TEST(TestVectorOfVectors) { + TStringStream out; + TVector<TVector<wchar16>> vec(2); + vec[0].push_back(0); + vec[1] = {wchar16('a')}; + out << DbgDump(vec); + UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "[[w'\\0'], [w'a']]"); + } + + Y_UNIT_TEST(TestInfinite) { + UNIT_ASSERT(!!(TStringBuilder() << DbgDumpDeep(TX()))); + } + + Y_UNIT_TEST(TestLabeledDump) { + TStringStream out; + int a = 1, b = 2; + out << LabeledDump(a, b, 1 + 2); + UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "{\"a\": 1, \"b\": 2, \"1 + 2\": 3}"); + } + + Y_UNIT_TEST(TestStructDumper) { + TStringStream out; + out << DbgDump(TMyNS::TMyStruct{3, 4}); + UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "{\"A\": 3, \"B\": 4}"); + } + + Y_UNIT_TEST(TestColors) { + using TComplex = TMap<TString, TMap<int, char>>; + TComplex test; + test["a"][1] = '7'; + test["b"][2] = '6'; + TStringStream out; + out << DbgDump<TComplex, NDbgDump::NColorScheme::TEyebleed</* Enforce = */ true>>(test); + UNIT_ASSERT_STRINGS_EQUAL( + EscapeC(out.Str()), + "\\x1B[1;32m{\\x1B[1;31m\\x1B[42m\\x1B[1;31m\\x1B[1;33m\\\"a\\\"\\x1B[22;39m\\x1B[22;39m" + "\\x1B[49m\\x1B[1;32m -> \\x1B[44m\\x1B[1;31m\\x1B[1;32m{\\x1B[1;31m\\x1B[1;31m1" + "\\x1B[22;39m\\x1B[1;32m -> \\x1B[1;31m'7'\\x1B[22;39m\\x1B[1;32m}" + "\\x1B[22;39m\\x1B[22;39m\\x1B[49m\\x1B[1;32m, \\x1B[1;31m\\x1B[42m\\x1B[1;31m\\x1B[1;33m" + "\\\"b\\\"\\x1B[22;39m\\x1B[22;39m\\x1B[49m\\x1B[1;32m -> " + "\\x1B[44m\\x1B[1;31m\\x1B[1;32m{\\x1B[1;31m\\x1B[1;31m2\\x1B[22;39m\\x1B[1;32m -> " + "\\x1B[1;31m'6'\\x1B[22;39m\\x1B[1;32m}\\x1B[22;39m\\x1B[22;39m\\x1B[49m\\x1B[1;32m}\\x1B[22;39m"); + } + + Y_UNIT_TEST(SmallIntOrChar) { + char c = 'e'; + i8 i = -100; + ui8 u = 10; + UNIT_ASSERT_VALUES_EQUAL(TStringBuilder() << DbgDump(c), "'e'"); + UNIT_ASSERT_VALUES_EQUAL(TStringBuilder() << DbgDump(i), "-100"); + UNIT_ASSERT_VALUES_EQUAL(TStringBuilder() << DbgDump(u), "10"); + } +} diff --git a/library/cpp/dbg_output/ut/ya.make b/library/cpp/dbg_output/ut/ya.make new file mode 100644 index 0000000000..201601295d --- /dev/null +++ b/library/cpp/dbg_output/ut/ya.make @@ -0,0 +1,9 @@ +UNITTEST_FOR(library/cpp/dbg_output) + +OWNER(pg) + +SRCS( + dbg_output_ut.cpp +) + +END() diff --git a/library/cpp/dbg_output/ya.make b/library/cpp/dbg_output/ya.make new file mode 100644 index 0000000000..7d54108f93 --- /dev/null +++ b/library/cpp/dbg_output/ya.make @@ -0,0 +1,15 @@ +LIBRARY() + +OWNER(pg) + +PEERDIR( + library/cpp/colorizer +) + +SRCS( + dump.cpp + dumpers.cpp + engine.cpp +) + +END() |