| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import <Foundation/Foundation.h> |
| #include <vector> |
| |
| #include "base/memory/ref_counted.h" |
| #include "testing/platform_test.h" |
| |
| #if defined(__has_feature) && __has_feature(objc_arc) |
| #error "This file must not be compiled with ARC." |
| #endif |
| |
| // This test verifies assumptions about the murky world of interaction between |
| // C++ objects and blocks. Just to make sure. |
| |
| namespace { |
| |
| using NoArcBlockTest = PlatformTest; |
| |
| class RefCountedObject : public base::RefCounted<RefCountedObject> { |
| public: |
| RefCountedObject() {} |
| |
| // Refcount is private in the superclass, fake it by counting how many times |
| // release can be called until there is one count left, then retain the count |
| // back. |
| int refcount() { |
| int count = 1; |
| while (!HasOneRef()) { |
| bool check = base::subtle::RefCountedBase::Release(); |
| EXPECT_FALSE(check); |
| ++count; |
| } |
| for (int ii = 1; ii < count; ii++) |
| base::subtle::RefCountedBase::AddRef(); |
| return count; |
| } |
| |
| protected: |
| friend base::RefCounted<RefCountedObject>; |
| virtual ~RefCountedObject() {} |
| }; |
| |
| TEST_F(NoArcBlockTest, BlockAndCPlusPlus) { |
| RefCountedObject* object = new RefCountedObject(); |
| object->AddRef(); |
| EXPECT_TRUE(object->HasOneRef()); |
| EXPECT_EQ(1, object->refcount()); |
| |
| { |
| scoped_refptr<RefCountedObject> object_test_ptr(object); |
| EXPECT_EQ(2, object->refcount()); |
| } |
| EXPECT_TRUE(object->HasOneRef()); |
| |
| void (^heap_block)(int) = nil; |
| { |
| scoped_refptr<RefCountedObject> object_ptr(object); |
| EXPECT_EQ(2, object->refcount()); |
| void* object_void_ptr = (void*)object; |
| |
| void (^stack_block)(int) = ^(int expected) { |
| EXPECT_EQ(object_void_ptr, object_ptr.get()); |
| EXPECT_EQ(expected, object_ptr.get()->refcount()); |
| }; |
| stack_block(3); |
| heap_block = [stack_block copy]; |
| stack_block(4); |
| } |
| heap_block(2); |
| [heap_block release]; |
| EXPECT_TRUE(object->HasOneRef()); |
| { |
| scoped_refptr<RefCountedObject> object_test2_ptr(object); |
| EXPECT_EQ(2, object->refcount()); |
| } |
| EXPECT_TRUE(object->HasOneRef()); |
| object->Release(); |
| } |
| |
| TEST_F(NoArcBlockTest, BlockAndVectors) { |
| void (^heap_block)(void) = nil; |
| { |
| std::vector<int> vector; |
| vector.push_back(0); |
| vector.push_back(1); |
| vector.push_back(2); |
| |
| void (^stack_block)(void) = ^{ |
| EXPECT_EQ(3ul, vector.size()); |
| EXPECT_EQ(2, vector[2]); |
| }; |
| stack_block(); |
| vector[2] = 42; |
| vector.push_back(22); |
| stack_block(); |
| heap_block = [stack_block copy]; |
| stack_block(); |
| } |
| heap_block(); |
| [heap_block release]; |
| } |
| |
| } // namespace |