Index: tests/RefCntTest.cpp |
diff --git a/tests/RefCntTest.cpp b/tests/RefCntTest.cpp |
index f5345b6a54162354d782bf5466af19f4f1e83e1e..72d226419aacf5729bb9a4163143c6e7e313f701 100644 |
--- a/tests/RefCntTest.cpp |
+++ b/tests/RefCntTest.cpp |
@@ -272,6 +272,80 @@ DEF_TEST(sk_sp, reporter) { |
check(reporter, 1, 1, 1, 0); |
paint.set(nullptr); |
check(reporter, 1, 2, 1, 1); |
+ |
+ { |
+ sk_sp<SkRefCnt> empty; |
+ sk_sp<SkRefCnt> notEmpty = sk_make_sp<SkRefCnt>(); |
+ REPORTER_ASSERT(reporter, empty == sk_sp<SkRefCnt>()); |
+ |
+ REPORTER_ASSERT(reporter, notEmpty != empty); |
+ REPORTER_ASSERT(reporter, empty != notEmpty); |
+ |
+ REPORTER_ASSERT(reporter, nullptr == empty); |
+ REPORTER_ASSERT(reporter, empty == nullptr); |
+ REPORTER_ASSERT(reporter, empty == empty); |
+ |
+ REPORTER_ASSERT(reporter, nullptr <= empty); |
+ REPORTER_ASSERT(reporter, empty <= nullptr); |
+ REPORTER_ASSERT(reporter, empty <= empty); |
+ |
+ REPORTER_ASSERT(reporter, nullptr >= empty); |
+ REPORTER_ASSERT(reporter, empty >= nullptr); |
+ REPORTER_ASSERT(reporter, empty >= empty); |
+ } |
+ |
+ { |
+ sk_sp<SkRefCnt> a = sk_make_sp<SkRefCnt>(); |
+ sk_sp<SkRefCnt> b = sk_make_sp<SkRefCnt>(); |
+ REPORTER_ASSERT(reporter, a != b); |
+ REPORTER_ASSERT(reporter, (a < b) != (b < a)); |
+ REPORTER_ASSERT(reporter, (b > a) != (a > b)); |
+ REPORTER_ASSERT(reporter, (a <= b) != (b <= a)); |
+ REPORTER_ASSERT(reporter, (b >= a) != (a >= b)); |
+ |
+ REPORTER_ASSERT(reporter, a == a); |
+ REPORTER_ASSERT(reporter, a <= a); |
+ REPORTER_ASSERT(reporter, a >= a); |
+ } |
+ |
+ // http://wg21.cmeerw.net/lwg/issue998 |
+ { |
+ class foo : public SkRefCnt { |
+ public: |
+ foo() : bar(this) {} |
+ void reset() { bar.reset(); } |
+ private: |
+ sk_sp<foo> bar; |
+ }; |
+ // The following should properly delete the object and not cause undefined behavior. |
+ // This is an ugly example, but the same issue can arise in more subtle ways. |
+ (new foo)->reset(); |
+ } |
+ |
+ // https://crrev.com/0d4ef2583a6f19c3e61be04d36eb1a60b133832c |
+ { |
+ struct StructB; |
+ struct StructA : public SkRefCnt { |
+ sk_sp<StructB> b; |
+ }; |
+ |
+ struct StructB : public SkRefCnt { |
+ sk_sp<StructA> a; |
+ ~StructB() override {}; // Some clang versions don't emit this implicitly. |
+ }; |
+ |
+ // Create a reference cycle. |
+ StructA* a = new StructA; |
+ a->b.reset(new StructB); |
+ a->b->a.reset(a); |
+ |
+ // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|) |
+ // to be deleted before the call to reset() returns. This tests that the |
+ // implementation of sk_sp::reset() doesn't access |this| after it |
+ // deletes the underlying pointer. This behaviour is consistent with the |
+ // definition of unique_ptr::reset in C++11. |
+ a->b.reset(); |
+ } |
} |
namespace { |