summaryrefslogtreecommitdiffstats
path: root/yql/essentials/public/udf/udf_debug_checks_ut/udf_debug_checks_ut.cpp
blob: 23dd5d85064e9b8d8b5e561fb0aa84caa3eff7ff (plain) (blame)
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