1// Copyright 2010 The Kyua Authors.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9//   notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright
11//   notice, this list of conditions and the following disclaimer in the
12//   documentation and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors
14//   may be used to endorse or promote products derived from this software
15//   without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29#include "utils/auto_array.ipp"
30
31extern "C" {
32#include <sys/types.h>
33}
34
35#include <iostream>
36
37#include <atf-c++.hpp>
38
39#include "utils/defs.hpp"
40
41using utils::auto_array;
42
43
44namespace {
45
46
47/// Mock class to capture calls to the new and delete operators.
48class test_array {
49public:
50    /// User-settable cookie to disambiguate instances of this class.
51    int m_value;
52
53    /// The current balance of existing test_array instances.
54    static ssize_t m_nblocks;
55
56    /// Captures invalid calls to new on an array.
57    ///
58    /// \return Nothing; this always fails the test case.
59    void*
60    operator new(const size_t /* size */)
61    {
62        ATF_FAIL("New called but should have been new[]");
63        return new int(5);
64    }
65
66    /// Obtains memory for a new instance and increments m_nblocks.
67    ///
68    /// \param size The amount of memory to allocate, in bytes.
69    ///
70    /// \return A pointer to the allocated memory.
71    ///
72    /// \throw std::bad_alloc If the memory cannot be allocated.
73    void*
74    operator new[](const size_t size)
75    {
76        void* mem = ::operator new(size);
77        m_nblocks++;
78        std::cout << "Allocated 'test_array' object " << mem << "\n";
79        return mem;
80    }
81
82    /// Captures invalid calls to delete on an array.
83    ///
84    /// \return Nothing; this always fails the test case.
85    void
86    operator delete(void* /* mem */)
87    {
88        ATF_FAIL("Delete called but should have been delete[]");
89    }
90
91    /// Deletes a previously allocated array and decrements m_nblocks.
92    ///
93    /// \param mem The pointer to the memory to be deleted.
94    void
95    operator delete[](void* mem)
96    {
97        std::cout << "Releasing 'test_array' object " << mem << "\n";
98        if (m_nblocks == 0)
99            ATF_FAIL("Unbalanced delete[]");
100        m_nblocks--;
101        ::operator delete(mem);
102    }
103};
104
105
106ssize_t test_array::m_nblocks = 0;
107
108
109}  // anonymous namespace
110
111
112ATF_TEST_CASE(scope);
113ATF_TEST_CASE_HEAD(scope)
114{
115    set_md_var("descr", "Tests the automatic scope handling in the "
116               "auto_array smart pointer class");
117}
118ATF_TEST_CASE_BODY(scope)
119{
120    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
121    {
122        auto_array< test_array > t(new test_array[10]);
123        ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
124    }
125    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
126}
127
128
129ATF_TEST_CASE(copy);
130ATF_TEST_CASE_HEAD(copy)
131{
132    set_md_var("descr", "Tests the auto_array smart pointer class' copy "
133               "constructor");
134}
135ATF_TEST_CASE_BODY(copy)
136{
137    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
138    {
139        auto_array< test_array > t1(new test_array[10]);
140        ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
141
142        {
143            auto_array< test_array > t2(t1);
144            ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
145        }
146        ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
147    }
148    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
149}
150
151
152ATF_TEST_CASE(copy_ref);
153ATF_TEST_CASE_HEAD(copy_ref)
154{
155    set_md_var("descr", "Tests the auto_array smart pointer class' copy "
156               "constructor through the auxiliary ref object");
157}
158ATF_TEST_CASE_BODY(copy_ref)
159{
160    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
161    {
162        auto_array< test_array > t1(new test_array[10]);
163        ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
164
165        {
166            auto_array< test_array > t2 = t1;
167            ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
168        }
169        ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
170    }
171    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
172}
173
174
175ATF_TEST_CASE(get);
176ATF_TEST_CASE_HEAD(get)
177{
178    set_md_var("descr", "Tests the auto_array smart pointer class' get "
179               "method");
180}
181ATF_TEST_CASE_BODY(get)
182{
183    test_array* ta = new test_array[10];
184    auto_array< test_array > t(ta);
185    ATF_REQUIRE_EQ(t.get(), ta);
186}
187
188
189ATF_TEST_CASE(release);
190ATF_TEST_CASE_HEAD(release)
191{
192    set_md_var("descr", "Tests the auto_array smart pointer class' release "
193               "method");
194}
195ATF_TEST_CASE_BODY(release)
196{
197    test_array* ta1 = new test_array[10];
198    {
199        auto_array< test_array > t(ta1);
200        ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
201        test_array* ta2 = t.release();
202        ATF_REQUIRE_EQ(ta2, ta1);
203        ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
204    }
205    ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
206    delete [] ta1;
207}
208
209
210ATF_TEST_CASE(reset);
211ATF_TEST_CASE_HEAD(reset)
212{
213    set_md_var("descr", "Tests the auto_array smart pointer class' reset "
214               "method");
215}
216ATF_TEST_CASE_BODY(reset)
217{
218    test_array* ta1 = new test_array[10];
219    test_array* ta2 = new test_array[10];
220    ATF_REQUIRE_EQ(test_array::m_nblocks, 2);
221
222    {
223        auto_array< test_array > t(ta1);
224        ATF_REQUIRE_EQ(test_array::m_nblocks, 2);
225        t.reset(ta2);
226        ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
227        t.reset();
228        ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
229    }
230    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
231}
232
233
234ATF_TEST_CASE(assign);
235ATF_TEST_CASE_HEAD(assign)
236{
237    set_md_var("descr", "Tests the auto_array smart pointer class' "
238               "assignment operator");
239}
240ATF_TEST_CASE_BODY(assign)
241{
242    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
243    {
244        auto_array< test_array > t1(new test_array[10]);
245        ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
246
247        {
248            auto_array< test_array > t2;
249            t2 = t1;
250            ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
251        }
252        ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
253    }
254    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
255}
256
257
258ATF_TEST_CASE(assign_ref);
259ATF_TEST_CASE_HEAD(assign_ref)
260{
261    set_md_var("descr", "Tests the auto_array smart pointer class' "
262               "assignment operator through the auxiliary ref "
263               "object");
264}
265ATF_TEST_CASE_BODY(assign_ref)
266{
267    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
268    {
269        auto_array< test_array > t1(new test_array[10]);
270        ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
271
272        {
273            auto_array< test_array > t2;
274            t2 = t1;
275            ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
276        }
277        ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
278    }
279    ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
280}
281
282
283ATF_TEST_CASE(access);
284ATF_TEST_CASE_HEAD(access)
285{
286    set_md_var("descr", "Tests the auto_array smart pointer class' access "
287               "operator");
288}
289ATF_TEST_CASE_BODY(access)
290{
291    auto_array< test_array > t(new test_array[10]);
292
293    for (int i = 0; i < 10; i++)
294        t[i].m_value = i * 2;
295
296    for (int i = 0; i < 10; i++)
297        ATF_REQUIRE_EQ(t[i].m_value, i * 2);
298}
299
300
301ATF_INIT_TEST_CASES(tcs)
302{
303    ATF_ADD_TEST_CASE(tcs, scope);
304    ATF_ADD_TEST_CASE(tcs, copy);
305    ATF_ADD_TEST_CASE(tcs, copy_ref);
306    ATF_ADD_TEST_CASE(tcs, get);
307    ATF_ADD_TEST_CASE(tcs, release);
308    ATF_ADD_TEST_CASE(tcs, reset);
309    ATF_ADD_TEST_CASE(tcs, assign);
310    ATF_ADD_TEST_CASE(tcs, assign_ref);
311    ATF_ADD_TEST_CASE(tcs, access);
312}
313