// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <Foundation/Foundation.h>
#import <vector>
#import "base/memory/ref_counted.h"
#import "testing/platform_test.h"
// This test verifies assumptions about the murky world of interaction between
// C++ objects and blocks. Just to make sure.
namespace {
using BlockTest = 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(BlockTest, 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());
@autoreleasepool {
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(4);
heap_block = [stack_block copy];
stack_block(4);
}
heap_block(2);
}
EXPECT_TRUE(object->HasOneRef());
{
scoped_refptr<RefCountedObject> object_test2_ptr(object);
EXPECT_EQ(2, object->refcount());
}
EXPECT_TRUE(object->HasOneRef());
object->Release();
}
TEST_F(BlockTest, 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();
}
} // namespace