1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
#include <yql/essentials/public/udf/udf_value.h>
#include <library/cpp/testing/gtest/gtest.h>
#include <cstdlib>
#include <utility>
using namespace NYql::NUdf;
namespace {
// Boxed value that violates the invariant: returns non-Ok/false but writes
// a non-trivial (boxed) value to result/key/payload. Used to trigger
// Y_DEBUG_ABORT_UNLESS in TBoxedValueAccessor::Fetch, Next, NextPair.
class TBoxedValue: public TBoxedValueBase {
public:
explicit TBoxedValue(TUnboxedValue result)
: Result_(std::move(result))
{
}
// Fetch: return Finish but assign non-trivial boxed value -> abort
EFetchStatus Fetch(TUnboxedValue& result) override {
result = Result_;
return EFetchStatus::Finish;
}
// Next: return false but assign non-trivial boxed value -> abort
bool Next(TUnboxedValue& value) override {
value = Result_;
return false;
}
// NextPair: return false but assign non-trivial boxed values -> abort
bool NextPair(TUnboxedValue& key, TUnboxedValue& payload) override {
key = Result_;
payload = Result_;
return false;
}
static IBoxedValuePtr CreateEvil() {
IBoxedValuePtr inner(new TBoxedValue(TUnboxedValue()));
TUnboxedValue boxedResult(TUnboxedValuePod(std::move(inner)));
return new TBoxedValue(boxedResult);
}
private:
TUnboxedValue Result_;
};
TEST(TBoxedValueAccessorDebugChecks, FetchNonOkButReplacesResultWithNonTrivial_Aborts) {
IBoxedValuePtr value(TBoxedValue::CreateEvil());
EXPECT_DEBUG_DEATH(
({
TUnboxedValue result;
TBoxedValueAccessor::Fetch(*value, result);
}),
"");
}
TEST(TBoxedValueAccessorDebugChecks, NextReturnsFalseButReplacesResultWithNonTrivial_Aborts) {
IBoxedValuePtr value(TBoxedValue::CreateEvil());
EXPECT_DEBUG_DEATH(
({
TUnboxedValue result;
TBoxedValueAccessor::Next(*value, result);
}),
"");
}
TEST(TBoxedValueAccessorDebugChecks, NextPairReturnsFalseButReplacesKeyPayloadWithNonTrivial_Aborts) {
IBoxedValuePtr value(TBoxedValue::CreateEvil());
EXPECT_DEBUG_DEATH(
({
TUnboxedValue key;
TUnboxedValue payload;
TBoxedValueAccessor::NextPair(*value, key, payload);
}),
"");
}
TEST(TBoxedValueAccessorDebugChecks, NextPairReturnsFalseButReplacesWithInvalid_Success) {
IBoxedValuePtr value(new TBoxedValue(TUnboxedValue::Invalid()));
TUnboxedValue key;
TUnboxedValue payload;
TBoxedValueAccessor::NextPair(*value, key, payload);
}
} // namespace
|