// Copyright 2018 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fxcrt/autorestorer.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/pseudo_retainable.h" TEST(fxcrt, AutoRestorer) { int x = 5; { AutoRestorer restorer(&x); x = 6; EXPECT_EQ(6, x); } EXPECT_EQ(5, x); } TEST(fxcrt, AutoRestorerNoOp) { int x = 5; { AutoRestorer restorer(&x); EXPECT_EQ(5, x); } EXPECT_EQ(5, x); } TEST(fxcrt, AutoRestorerAbandon) { int x = 5; { AutoRestorer restorer(&x); x = 6; EXPECT_EQ(6, x); restorer.AbandonRestoration(); } EXPECT_EQ(6, x); } TEST(fxcrt, AutoRestorerUnownedPtr) { int x = 5; int y = 6; UnownedPtr ptr(&x); { AutoRestorer> restorer(&ptr); ptr = &y; EXPECT_EQ(&y, ptr); } EXPECT_EQ(&x, ptr); } TEST(fxcrt, AutoRestorerUnownedNoOp) { int x = 5; UnownedPtr ptr(&x); { AutoRestorer> restorer(&ptr); EXPECT_EQ(&x, ptr); } EXPECT_EQ(&x, ptr); } TEST(fxcrt, AutoRestorerUnownedPtrAbandon) { int x = 5; int y = 6; UnownedPtr ptr(&x); { AutoRestorer> restorer(&ptr); ptr = &y; EXPECT_EQ(&y, ptr); restorer.AbandonRestoration(); } EXPECT_EQ(&y, ptr); } TEST(fxcrt, AutoRestorerRetainPtr) { PseudoRetainable obj1; PseudoRetainable obj2; RetainPtr ptr(&obj1); EXPECT_EQ(1, obj1.retain_count()); EXPECT_EQ(0, obj1.release_count()); { AutoRestorer> restorer(&ptr); // |obj1| is kept alive by restorer in case it need to be restored. EXPECT_EQ(2, obj1.retain_count()); EXPECT_EQ(0, obj1.release_count()); ptr.Reset(&obj2); EXPECT_EQ(&obj2, ptr.Get()); // |obj1| released by |ptr| assignment. EXPECT_TRUE(obj1.alive()); EXPECT_EQ(2, obj1.retain_count()); EXPECT_EQ(1, obj1.release_count()); // |obj2| now kept alive by |ptr|. EXPECT_TRUE(obj1.alive()); EXPECT_EQ(1, obj2.retain_count()); EXPECT_EQ(0, obj2.release_count()); } EXPECT_EQ(&obj1, ptr.Get()); // |obj1| now kept alive again by |ptr|. EXPECT_TRUE(obj1.alive()); EXPECT_EQ(3, obj1.retain_count()); EXPECT_EQ(2, obj1.release_count()); // |obj2| dead. EXPECT_FALSE(obj2.alive()); EXPECT_EQ(1, obj2.retain_count()); EXPECT_EQ(1, obj2.release_count()); } TEST(fxcrt, AutoRestorerRetainPtrNoOp) { PseudoRetainable obj1; RetainPtr ptr(&obj1); EXPECT_EQ(1, obj1.retain_count()); EXPECT_EQ(0, obj1.release_count()); { AutoRestorer> restorer(&ptr); EXPECT_EQ(2, obj1.retain_count()); EXPECT_EQ(0, obj1.release_count()); } EXPECT_EQ(&obj1, ptr.Get()); // Self-reassignement avoided ref churn. EXPECT_TRUE(obj1.alive()); EXPECT_EQ(2, obj1.retain_count()); EXPECT_EQ(1, obj1.release_count()); } TEST(fxcrt, AutoRestorerRetainPtrAbandon) { PseudoRetainable obj1; PseudoRetainable obj2; RetainPtr ptr(&obj1); EXPECT_EQ(1, obj1.retain_count()); EXPECT_EQ(0, obj1.release_count()); { AutoRestorer> restorer(&ptr); // |obj1| is kept alive by restorer in case it need to be restored. EXPECT_EQ(2, obj1.retain_count()); EXPECT_EQ(0, obj1.release_count()); ptr.Reset(&obj2); EXPECT_EQ(&obj2, ptr.Get()); // |obj1| released by |ptr| assignment. EXPECT_EQ(2, obj1.retain_count()); EXPECT_EQ(1, obj1.release_count()); // |obj2| now kept alive by |ptr|. EXPECT_EQ(1, obj2.retain_count()); EXPECT_EQ(0, obj2.release_count()); restorer.AbandonRestoration(); } EXPECT_EQ(&obj2, ptr.Get()); // |obj1| now dead as a result of abandonment. EXPECT_FALSE(obj1.alive()); EXPECT_EQ(2, obj1.retain_count()); EXPECT_EQ(2, obj1.release_count()); // |obj2| kept alive by |ptr|. EXPECT_TRUE(obj2.alive()); EXPECT_EQ(1, obj2.retain_count()); EXPECT_EQ(0, obj2.release_count()); }