summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpechatnov <[email protected]>2025-03-20 13:43:00 +0300
committerpechatnov <[email protected]>2025-03-20 14:01:03 +0300
commit947f03db644bc892f3ba032c6b5ff6302eb696bc (patch)
tree5d65359ea7f7ca1070aeec660249349eb312c310
parentdaa0fae61cb590ee620443fde726dae156c60d4e (diff)
YT: Parse strings '10G', '8Ki' as TSize (~i64)
commit_hash:3957ea35dac5850782a055f4e9f77151da63874b
-rw-r--r--yt/yt/core/ya.make1
-rw-r--r--yt/yt/core/ytree/public.h4
-rw-r--r--yt/yt/core/ytree/serialize.cpp23
-rw-r--r--yt/yt/core/ytree/serialize.h4
-rw-r--r--yt/yt/core/ytree/size-inl.h121
-rw-r--r--yt/yt/core/ytree/size.cpp102
-rw-r--r--yt/yt/core/ytree/size.h48
-rw-r--r--yt/yt/core/ytree/unittests/size_ut.cpp213
-rw-r--r--yt/yt/core/ytree/unittests/ya.make1
-rw-r--r--yt/yt/core/ytree/unittests/yson_struct_ut.cpp33
10 files changed, 546 insertions, 4 deletions
diff --git a/yt/yt/core/ya.make b/yt/yt/core/ya.make
index 81e4e3fe30e..a87958125de 100644
--- a/yt/yt/core/ya.make
+++ b/yt/yt/core/ya.make
@@ -288,6 +288,7 @@ SRCS(
ytree/request_complexity_limiter.cpp
ytree/request_complexity_limits.cpp
ytree/serialize.cpp
+ ytree/size.cpp
ytree/static_service_dispatcher.cpp
ytree/system_attribute_provider.cpp
ytree/tree_builder.cpp
diff --git a/yt/yt/core/ytree/public.h b/yt/yt/core/ytree/public.h
index c4bf9e3014f..368840528c1 100644
--- a/yt/yt/core/ytree/public.h
+++ b/yt/yt/core/ytree/public.h
@@ -132,4 +132,8 @@ DECLARE_REFCOUNTED_CLASS(TReadRequestComplexityLimiter)
////////////////////////////////////////////////////////////////////////////////
+class TSize;
+
+////////////////////////////////////////////////////////////////////////////////
+
} // namespace NYT::NYTree
diff --git a/yt/yt/core/ytree/serialize.cpp b/yt/yt/core/ytree/serialize.cpp
index b0ebda38717..b3949aef33f 100644
--- a/yt/yt/core/ytree/serialize.cpp
+++ b/yt/yt/core/ytree/serialize.cpp
@@ -1,5 +1,6 @@
#include "serialize.h"
+#include "size.h"
#include "tree_visitor.h"
#include <yt/yt/core/misc/blob.h>
@@ -173,6 +174,13 @@ void Serialize(IInputStream& input, IYsonConsumer* consumer)
Serialize(TYsonInput(&input), consumer);
}
+// TSize
+void Serialize(const TSize& value, NYson::IYsonConsumer* consumer)
+{
+ Serialize(value.Underlying(), consumer);
+}
+
+
// TStatisticPath.
void Serialize(const NStatisticPath::TStatisticPath& path, IYsonConsumer* consumer)
{
@@ -360,6 +368,21 @@ void Deserialize(TGuid& value, INodePtr node)
value = TGuid::FromString(node->AsString()->GetValue());
}
+// TSize
+void Deserialize(TSize& value, INodePtr node)
+{
+ if (node->GetType() == ENodeType::Int64) {
+ value = TSize(node->AsInt64()->GetValue());
+ } else if (node->GetType() == ENodeType::Uint64) {
+ value = TSize(CheckedIntegralCast<i64>(node->AsUint64()->GetValue()));
+ } else if (node->GetType() == ENodeType::String) {
+ value = TSize::FromString(node->AsString()->GetValue());
+ } else {
+ THROW_ERROR_EXCEPTION("Cannot parse TSize value from %Qlv",
+ node->GetType());
+ }
+}
+
// TStatisticPath.
void Deserialize(NStatisticPath::TStatisticPath& value, INodePtr node)
{
diff --git a/yt/yt/core/ytree/serialize.h b/yt/yt/core/ytree/serialize.h
index 98622249f08..138c77e1d62 100644
--- a/yt/yt/core/ytree/serialize.h
+++ b/yt/yt/core/ytree/serialize.h
@@ -178,6 +178,8 @@ void Serialize(
template <class T, class TTag>
void Serialize(const TStrongTypedef<T, TTag>& value, NYson::IYsonConsumer* consumer);
+void Serialize(const TSize& value, NYson::IYsonConsumer* consumer);
+
void Serialize(const NStatisticPath::TStatisticPath& path, NYson::IYsonConsumer* consumer);
////////////////////////////////////////////////////////////////////////////////
@@ -285,6 +287,8 @@ void Deserialize(
template <class T, class TTag>
void Deserialize(TStrongTypedef<T, TTag>& value, INodePtr node);
+void Deserialize(TSize& value, INodePtr node);
+
void Deserialize(NStatisticPath::TStatisticPath& path, INodePtr node);
////////////////////////////////////////////////////////////////////////////////
diff --git a/yt/yt/core/ytree/size-inl.h b/yt/yt/core/ytree/size-inl.h
new file mode 100644
index 00000000000..6cd360967f7
--- /dev/null
+++ b/yt/yt/core/ytree/size-inl.h
@@ -0,0 +1,121 @@
+#ifndef YTREE_SIZE_INL_H_
+#error "Direct inclusion of this file is not allowed, include size.h"
+// For the sake of sane code completion.
+#include "size.h"
+#endif
+
+namespace NYT::NYTree {
+
+////////////////////////////////////////////////////////////////////////////////
+
+constexpr TSize::TSize()
+ : Underlying_(0)
+{ }
+
+constexpr TSize::TSize(TUnderlying underlying)
+ : Underlying_(underlying)
+{ }
+
+constexpr TSize::operator const TUnderlying&() const
+{
+ return Underlying_;
+}
+
+constexpr TSize::operator TUnderlying&()
+{
+ return Underlying_;
+}
+
+constexpr TSize::TUnderlying& TSize::Underlying() &
+{
+ return Underlying_;
+}
+
+constexpr const TSize::TUnderlying& TSize::Underlying() const &
+{
+ return Underlying_;
+}
+
+constexpr TSize::TUnderlying TSize::Underlying() &&
+{
+ return Underlying_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYTree
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace std {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <>
+struct hash<NYT::NYTree::TSize>
+{
+ size_t operator()(const NYT::NYTree::TSize& value) const
+ {
+ return std::hash<NYT::NYTree::TSize::TUnderlying>()(value.Underlying());
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <>
+class numeric_limits<NYT::NYTree::TSize>
+{
+public:
+ #define XX(name) \
+ static constexpr decltype(numeric_limits<NYT::NYTree::TSize::TUnderlying>::name) name = numeric_limits<NYT::NYTree::TSize::TUnderlying>::name;
+
+ XX(is_specialized)
+ XX(is_signed)
+ XX(digits)
+ XX(digits10)
+ XX(max_digits10)
+ XX(is_integer)
+ XX(is_exact)
+ XX(radix)
+ XX(min_exponent)
+ XX(min_exponent10)
+ XX(max_exponent)
+ XX(max_exponent10)
+ XX(has_infinity)
+ XX(has_quiet_NaN)
+ XX(has_signaling_NaN)
+ XX(has_denorm)
+ XX(has_denorm_loss)
+ XX(is_iec559)
+ XX(is_bounded)
+ XX(is_modulo)
+ XX(traps)
+ XX(tinyness_before)
+ XX(round_style)
+
+ #undef XX
+
+ #define XX(name) \
+ static constexpr NYT::NYTree::TSize name() noexcept \
+ { \
+ return NYT::NYTree::TSize(numeric_limits<NYT::NYTree::TSize::TUnderlying>::name()); \
+ }
+
+ XX(min)
+ XX(max)
+ XX(lowest)
+ XX(epsilon)
+ XX(round_error)
+ XX(infinity)
+ XX(quiet_NaN)
+ XX(signaling_NaN)
+ XX(denorm_min)
+
+ #undef XX
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace std
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/yt/yt/core/ytree/size.cpp b/yt/yt/core/ytree/size.cpp
new file mode 100644
index 00000000000..ec29ebb9a4c
--- /dev/null
+++ b/yt/yt/core/ytree/size.cpp
@@ -0,0 +1,102 @@
+#include "size.h"
+
+#include <yt/yt/core/misc/error.h>
+
+#include <util/string/cast.h>
+
+namespace NYT {
+
+namespace NYTree {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use suffixes for 1000, ..., 1000 ** 6 and 1024, ..., 1024 ** 6.
+// 1000 ** 6 < 1024 ** 6 = 2 ** 60 < std::numeric_limits<TSize::TUnderlying>::max().
+constexpr int MaxMultiplierOrder = 6;
+using TMultipliers = std::array<std::array<TSize::TUnderlying, MaxMultiplierOrder + 1>, 2>;
+
+constexpr TMultipliers Multipliers = std::invoke([] {
+ TMultipliers result;
+ result[0][0] = 1;
+ result[1][0] = 1;
+ for (int i = 1; i <= MaxMultiplierOrder; ++i) {
+ result[0][i] = result[0][i - 1] * 1000;
+ result[1][i] = result[1][i - 1] * 1024;
+ }
+ return result;
+});
+
+TSize::TUnderlying DeserializeSizeWithSuffixesImpl(TStringBuf originalValue)
+{
+ TStringBuf value = originalValue;
+
+ bool basedOnPowerOf2 = value.ChopSuffix("i");
+ int order =
+ value.ChopSuffix("K") ? 1 :
+ value.ChopSuffix("M") ? 2 :
+ value.ChopSuffix("G") ? 3 :
+ value.ChopSuffix("T") ? 4 :
+ value.ChopSuffix("P") ? 5 :
+ value.ChopSuffix("E") ? 6 : 0;
+
+ TSize::TUnderlying multiplier = Multipliers[static_cast<int>(basedOnPowerOf2)][order];
+ TSize::TUnderlying result = FromString<TSize::TUnderlying>(value);
+
+ bool tooLargeValue = result < 0
+ ? result < std::numeric_limits<TSize::TUnderlying>::lowest() / multiplier
+ : result > std::numeric_limits<TSize::TUnderlying>::max() / multiplier;
+ THROW_ERROR_EXCEPTION_IF(tooLargeValue, "Cannot parse too large value %Qlv as 64-bit integral type", originalValue);
+
+ return result * multiplier;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+TSize TSize::FromString(TStringBuf serializedValue)
+{
+ return TSize(DeserializeSizeWithSuffixesImpl(serializedValue));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYTree
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <>
+NYT::NYTree::TSize FromStringImpl<NYT::NYTree::TSize, char>(const char* data, size_t size)
+{
+ return NYT::NYTree::TSize::FromString(TStringBuf(data, size));
+}
+
+template<>
+bool TryFromStringImpl<NYT::NYTree::TSize, char>(const char* data, size_t size, NYT::NYTree::TSize& value)
+{
+ try {
+ value = NYT::NYTree::TSize::FromString(TStringBuf(data, size));
+ return true;
+ } catch (const std::exception&) {
+ return false;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <>
+void Out<NYT::NYTree::TSize>(IOutputStream& out, const NYT::NYTree::TSize& value) {
+ out << value.Underlying();
+}
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/yt/yt/core/ytree/size.h b/yt/yt/core/ytree/size.h
new file mode 100644
index 00000000000..1f15c9c68b9
--- /dev/null
+++ b/yt/yt/core/ytree/size.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "public.h"
+
+namespace NYT::NYTree {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Semi-strong typedef for integral type with advanced parsing from string.
+//! Constructor/FromString<TSize> parses "2M" as 2'000'000 and "1Ki" as 1024.
+//! Supported suffixes: K, Ki, M, Mi, G, Gi, T, Ti, P, Pi, E, Ei.
+class TSize
+{
+public:
+ using TUnderlying = i64;
+
+ constexpr TSize();
+
+ constexpr explicit TSize(TUnderlying value);
+
+ TSize(const TSize&) = default;
+ TSize(TSize&&) = default;
+
+ static TSize FromString(TStringBuf serializedValue);
+
+ TSize& operator=(const TSize&) = default;
+ TSize& operator=(TSize&&) = default;
+
+ constexpr operator const TUnderlying&() const;
+ constexpr operator TUnderlying&();
+
+ constexpr auto operator<=>(const TSize& rhs) const = default;
+
+ constexpr TUnderlying& Underlying() &;
+ constexpr const TUnderlying& Underlying() const &;
+ constexpr TUnderlying Underlying() &&;
+
+private:
+ TUnderlying Underlying_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYTree
+
+#define YTREE_SIZE_INL_H_
+#include "size-inl.h"
+#undef YTREE_SIZE_INL_H_
diff --git a/yt/yt/core/ytree/unittests/size_ut.cpp b/yt/yt/core/ytree/unittests/size_ut.cpp
new file mode 100644
index 00000000000..77a407b947c
--- /dev/null
+++ b/yt/yt/core/ytree/unittests/size_ut.cpp
@@ -0,0 +1,213 @@
+#include <yt/yt/core/test_framework/framework.h>
+
+#include <yt/yt/core/ytree/size.h>
+
+namespace NYT::NYTree {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define XX(name) \
+ static_assert(std::numeric_limits<TSize>::name == std::numeric_limits<i64>::name);
+
+XX(is_signed)
+XX(digits)
+XX(digits10)
+XX(max_digits10)
+XX(is_integer)
+XX(is_exact)
+XX(radix)
+XX(min_exponent)
+XX(min_exponent10)
+XX(max_exponent)
+XX(max_exponent10)
+XX(has_infinity)
+XX(has_quiet_NaN)
+XX(has_signaling_NaN)
+XX(has_denorm)
+XX(has_denorm_loss)
+XX(is_iec559)
+XX(is_bounded)
+XX(is_modulo)
+XX(traps)
+XX(tinyness_before)
+XX(round_style)
+
+#undef XX
+
+#define XX(name) \
+ static_assert(std::numeric_limits<TSize>::name() == TSize(std::numeric_limits<i64>::name()));
+
+XX(min)
+XX(max)
+XX(lowest)
+XX(epsilon)
+XX(round_error)
+XX(infinity)
+XX(quiet_NaN)
+XX(signaling_NaN)
+XX(denorm_min)
+
+#undef XX
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TYTreeSizeTest, Simple)
+{
+ EXPECT_EQ(TSize(1), TSize(1));
+ EXPECT_NE(TSize(1), TSize(2));
+
+ EXPECT_EQ(TSize(1), 1);
+ EXPECT_LE(0, TSize(1));
+ EXPECT_GE(TSize(1), 0);
+ EXPECT_EQ(1u, TSize(1));
+
+ EXPECT_TRUE(TSize(1));
+ EXPECT_FALSE(TSize(0));
+
+ EXPECT_EQ(TSize(10) + 100, 110);
+ EXPECT_EQ(100 + TSize(10), 110);
+ EXPECT_EQ(10 * TSize(10), 100);
+ EXPECT_EQ(TSize(10) * 10, 100);
+ EXPECT_EQ(TSize(10) / 10, 1);
+ EXPECT_EQ(10 / TSize(10), 1);
+ EXPECT_EQ(10 - TSize(10), 0);
+ EXPECT_EQ(TSize(10) - 10, 0);
+
+ {
+ EXPECT_EQ(TSize(10).Underlying(), 10);
+
+ TSize a{56};
+ a.Underlying() = 55;
+ EXPECT_EQ(a.Underlying(), 55);
+
+ const TSize b{58};
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(b.Underlying())>>);
+ EXPECT_EQ(b.Underlying(), 58);
+ EXPECT_EQ(b, 58);
+ }
+}
+
+TEST(TYTreeSizeTest, Serialize)
+{
+ EXPECT_EQ(ToString(TSize(1)), TString{"1"});
+ EXPECT_EQ(Format("|%v|", TSize(42)), TString{"|42|"});
+
+ {
+ TSize v;
+ EXPECT_TRUE(::TryFromString("21", 2, v));
+ EXPECT_EQ(TSize(21), v);
+ EXPECT_FALSE(::TryFromString("", 0, v));
+ }
+
+ EXPECT_EQ(TSize(46), FromString<TSize>("46"));
+
+ {
+ TStringBuilder builder;
+ Format(&builder, "%v", TSize(42));
+ EXPECT_EQ(builder.Flush(), "42");
+ }
+
+ {
+ TStringStream stream;
+ stream << TSize(42);
+ EXPECT_EQ(stream.Str(), "42");
+ }
+}
+
+TEST(TYTreeSizeTest, Constexpr)
+{
+ static_assert(TSize(1) == TSize(1));
+ static_assert(TSize(1000).Underlying() == 1000);
+}
+
+TEST(TYTreeSizeTest, Hash)
+{
+ for (i64 i = -1000; i < 1000; ++i) {
+ EXPECT_EQ(THash<TSize>()(TSize(i)), THash<i64>()(i));
+ EXPECT_EQ(std::hash<TSize>()(TSize(i)), std::hash<i64>()(i));
+ }
+}
+
+i64 DeserializeString(TStringBuf value)
+{
+ return TSize::FromString(value).Underlying();
+}
+
+TEST(TYTreeSizeTest, FromString)
+{
+ EXPECT_EQ(0, DeserializeString("0"));
+ EXPECT_EQ(127, DeserializeString("127"));
+ EXPECT_EQ(-2, DeserializeString("-2"));
+
+ EXPECT_EQ(1000, DeserializeString("1K"));
+ EXPECT_EQ(3000000, DeserializeString("3M"));
+ EXPECT_EQ(-1024, DeserializeString("-1Ki"));
+ EXPECT_EQ(2000000000, DeserializeString("2G"));
+ EXPECT_THROW(DeserializeString("2000000000000P"), std::exception);
+
+ EXPECT_EQ(0, DeserializeString("0E"));
+ EXPECT_EQ(1000, DeserializeString("1K"));
+ EXPECT_EQ(1000'000, DeserializeString("1M"));
+ EXPECT_EQ(1000'000'000, DeserializeString("1G"));
+ EXPECT_EQ(1000'000'000'000, DeserializeString("1T"));
+ EXPECT_EQ(1000'000'000'000'000, DeserializeString("1P"));
+ EXPECT_EQ(1000'000'000'000'000'000, DeserializeString("1E"));
+ EXPECT_EQ(0LL, DeserializeString("0Ei"));
+ EXPECT_EQ(1024LL, DeserializeString("1Ki"));
+ EXPECT_EQ(1024LL * 1024, DeserializeString("1Mi"));
+ EXPECT_EQ(1024LL * 1024 * 1024, DeserializeString("1Gi"));
+ EXPECT_EQ(1024LL * 1024 * 1024 * 1024, DeserializeString("1Ti"));
+ EXPECT_EQ(1024LL * 1024 * 1024 * 1024 * 1024, DeserializeString("1Pi"));
+ EXPECT_EQ(1024LL * 1024 * 1024 * 1024 * 1024 * 1024, DeserializeString("1Ei"));
+
+ EXPECT_THROW(DeserializeString("G"), std::exception);
+ EXPECT_THROW(DeserializeString("Gi"), std::exception);
+ EXPECT_THROW(DeserializeString("1GG"), std::exception);
+ EXPECT_THROW(DeserializeString("1KG"), std::exception);
+ EXPECT_THROW(DeserializeString("1KiG"), std::exception);
+ EXPECT_THROW(DeserializeString("1Ki2"), std::exception);
+}
+
+TEST(TYTreeSizeTest, FromStringBoundaryCases)
+{
+ EXPECT_EQ(std::numeric_limits<i64>::max(), DeserializeString("9223372036854775807"));
+ EXPECT_EQ(std::numeric_limits<i64>::lowest(), DeserializeString("-9223372036854775808"));
+ EXPECT_THROW(DeserializeString("9223372036854775808"), std::exception);
+ EXPECT_THROW(DeserializeString("-9223372036854775809"), std::exception);
+
+ EXPECT_EQ(9'223'372'036'854'775'000LL, DeserializeString("9223372036854775K"));
+ EXPECT_EQ(-9'223'372'036'854'775'000LL, DeserializeString("-9223372036854775K"));
+ EXPECT_THROW(DeserializeString("9223372036854776K"), std::exception);
+ EXPECT_THROW(DeserializeString("-9223372036854776K"), std::exception);
+
+ EXPECT_EQ(9'223'372'036'854'000'000LL, DeserializeString("9223372036854M"));
+ EXPECT_EQ(-9'223'372'036'854'000'000LL, DeserializeString("-9223372036854M"));
+ EXPECT_THROW(DeserializeString("9223372036855M"), std::exception);
+ EXPECT_THROW(DeserializeString("-9223372036855M"), std::exception);
+
+ EXPECT_EQ(9'223'372'036'000'000'000LL, DeserializeString("9223372036G"));
+ EXPECT_EQ(-9'223'372'036'000'000'000LL, DeserializeString("-9223372036G"));
+ EXPECT_THROW(DeserializeString("9223372037G"), std::exception);
+ EXPECT_THROW(DeserializeString("-9223372037G"), std::exception);
+
+ EXPECT_EQ(9'223'372'000'000'000'000LL, DeserializeString("9223372T"));
+ EXPECT_EQ(-9'223'372'000'000'000'000LL, DeserializeString("-9223372T"));
+ EXPECT_THROW(DeserializeString("9223373T"), std::exception);
+ EXPECT_THROW(DeserializeString("-9223373T"), std::exception);
+
+ EXPECT_EQ(9'223'000'000'000'000'000LL, DeserializeString("9223P"));
+ EXPECT_EQ(-9'223'000'000'000'000'000LL, DeserializeString("-9223P"));
+ EXPECT_THROW(DeserializeString("9224P"), std::exception);
+ EXPECT_THROW(DeserializeString("-9224P"), std::exception);
+
+ EXPECT_EQ(9'000'000'000'000'000'000LL, DeserializeString("9E"));
+ EXPECT_EQ(-9'000'000'000'000'000'000LL, DeserializeString("-9E"));
+ EXPECT_THROW(DeserializeString("10E"), std::exception);
+ EXPECT_THROW(DeserializeString("-10E"), std::exception);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT::NYTree
diff --git a/yt/yt/core/ytree/unittests/ya.make b/yt/yt/core/ytree/unittests/ya.make
index 172b7702944..256b8c014bc 100644
--- a/yt/yt/core/ytree/unittests/ya.make
+++ b/yt/yt/core/ytree/unittests/ya.make
@@ -10,6 +10,7 @@ SRCS(
resolver_ut.cpp
serialize_ut.cpp
service_combiner_ut.cpp
+ size_ut.cpp
text_yson_convert_ut.cpp
tree_builder_ut.cpp
lazy_ypath_service_ut.cpp
diff --git a/yt/yt/core/ytree/unittests/yson_struct_ut.cpp b/yt/yt/core/ytree/unittests/yson_struct_ut.cpp
index f38c233f446..1708ccbec83 100644
--- a/yt/yt/core/ytree/unittests/yson_struct_ut.cpp
+++ b/yt/yt/core/ytree/unittests/yson_struct_ut.cpp
@@ -5,6 +5,7 @@
#include <yt/yt/core/ytree/ephemeral_node_factory.h>
#include <yt/yt/core/ytree/fluent.h>
#include <yt/yt/core/ytree/polymorphic_yson_struct.h>
+#include <yt/yt/core/ytree/size.h>
#include <yt/yt/core/ytree/tree_builder.h>
#include <yt/yt/core/ytree/tree_visitor.h>
#include <yt/yt/core/ytree/ypath_client.h>
@@ -42,6 +43,8 @@ struct TTestSubconfig
bool MyBool;
std::vector<TString> MyStringList;
ETestEnum MyEnum;
+ TDuration MyDuration;
+ TSize MySize;
REGISTER_YSON_STRUCT(TTestSubconfig);
@@ -59,6 +62,10 @@ struct TTestSubconfig
.Default();
registrar.Parameter("my_enum", &TThis::MyEnum)
.Default(ETestEnum::Value1);
+ registrar.Parameter("my_duration", &TThis::MyDuration)
+ .Default(TDuration::Seconds(1));
+ registrar.Parameter("my_size", &TThis::MySize)
+ .Default(TSize::FromString("8K"));
}
};
@@ -135,6 +142,8 @@ auto GetCompleteConfigNode(int offset = 0)
.Item().Value("ListItem1")
.Item().Value("ListItem2")
.EndList()
+ .Item("my_duration").Value("2h")
+ .Item("my_size").Value("2M")
.EndMap()
.Item("sub_list").BeginList()
.Item().BeginMap()
@@ -147,6 +156,8 @@ auto GetCompleteConfigNode(int offset = 0)
.Item().Value("ListItem1")
.Item().Value("ListItem2")
.EndList()
+ .Item("my_duration").Value("2h")
+ .Item("my_size").Value(2'000'000)
.EndMap()
.Item().BeginMap()
.Item("my_int").Value(99 + offset)
@@ -158,6 +169,8 @@ auto GetCompleteConfigNode(int offset = 0)
.Item().Value("ListItem1")
.Item().Value("ListItem2")
.EndList()
+ .Item("my_duration").Value("2h")
+ .Item("my_size").Value("2000K")
.EndMap()
.EndList()
.Item("sub_map").BeginMap()
@@ -171,6 +184,8 @@ auto GetCompleteConfigNode(int offset = 0)
.Item().Value("ListItem1")
.Item().Value("ListItem2")
.EndList()
+ .Item("my_duration").Value("2h")
+ .Item("my_size").Value(2'000'000)
.EndMap()
.Item("sub2").BeginMap()
.Item("my_int").Value(99 + offset)
@@ -182,6 +197,8 @@ auto GetCompleteConfigNode(int offset = 0)
.Item().Value("ListItem1")
.Item().Value("ListItem2")
.EndList()
+ .Item("my_duration").Value(2 * 60 * 60 * 1000)
+ .Item("my_size").Value(2'000'000)
.EndMap()
.EndMap()
.EndMap();
@@ -189,7 +206,7 @@ auto GetCompleteConfigNode(int offset = 0)
void TestCompleteSubconfig(TTestSubconfig* subconfig, int offset = 0)
{
- for (auto field : {"my_int", "my_uint", "my_bool", "my_enum", "my_string_list"}) {
+ for (auto field : {"my_int", "my_uint", "my_bool", "my_enum", "my_string_list", "my_duration", "my_size"}) {
EXPECT_TRUE(subconfig->IsSet(field));
}
@@ -201,6 +218,8 @@ void TestCompleteSubconfig(TTestSubconfig* subconfig, int offset = 0)
EXPECT_EQ("ListItem1", subconfig->MyStringList[1]);
EXPECT_EQ("ListItem2", subconfig->MyStringList[2]);
EXPECT_EQ(ETestEnum::Value2, subconfig->MyEnum);
+ EXPECT_EQ(TDuration::Hours(2), subconfig->MyDuration);
+ EXPECT_EQ(2'000'000, subconfig->MySize);
}
void TestCompleteConfig(TIntrusivePtr<TTestConfig> config, int offset = 0)
@@ -695,14 +714,18 @@ TEST(TYsonStructTest, Save)
"\"my_enum\"=\"value1\";"
"\"my_int\"=200;"
"\"my_uint\"=50u;"
- "\"my_string_list\"=[]}";
+ "\"my_string_list\"=[];"
+ "\"my_duration\"=1000;"
+ "\"my_size\"=8000}";
TString subconfigYsonOrigin =
"{\"my_bool\"=%false;"
"\"my_enum\"=\"value1\";"
"\"my_int\"=100;"
"\"my_uint\"=50u;"
- "\"my_string_list\"=[]}";
+ "\"my_string_list\"=[];"
+ "\"my_duration\"=1000;"
+ "\"my_size\"=8000}";
TString expectedYson;
expectedYson += "{\"my_string\"=\"hello!\";";
@@ -713,7 +736,9 @@ TEST(TYsonStructTest, Save)
EXPECT_TRUE(AreNodesEqual(
ConvertToNode(TYsonString(expectedYson)),
- ConvertToNode(TYsonString(output.AsStringBuf()))));
+ ConvertToNode(TYsonString(output.AsStringBuf()))))
+ << "Expected: " << expectedYson
+ << ", got: " << output.AsStringBuf();
}
TEST(TYsonStructTest, TestConfigUpdate)