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 
31 extern "C" {
32 #include <sys/types.h>
33 }
34 
35 #include <iostream>
36 
37 #include <atf-c++.hpp>
38 
39 #include "utils/defs.hpp"
40 
41 using utils::auto_array;
42 
43 
44 namespace {
45 
46 
47 /// Mock class to capture calls to the new and delete operators.
48 class test_array {
49 public:
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 
106 ssize_t test_array::m_nblocks = 0;
107 
108 
109 }  // anonymous namespace
110 
111 
112 ATF_TEST_CASE(scope);
113 ATF_TEST_CASE_HEAD(scope)
114 {
115     set_md_var("descr", "Tests the automatic scope handling in the "
116                "auto_array smart pointer class");
117 }
118 ATF_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 
129 ATF_TEST_CASE(copy);
130 ATF_TEST_CASE_HEAD(copy)
131 {
132     set_md_var("descr", "Tests the auto_array smart pointer class' copy "
133                "constructor");
134 }
135 ATF_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 
152 ATF_TEST_CASE(copy_ref);
153 ATF_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 }
158 ATF_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 
175 ATF_TEST_CASE(get);
176 ATF_TEST_CASE_HEAD(get)
177 {
178     set_md_var("descr", "Tests the auto_array smart pointer class' get "
179                "method");
180 }
181 ATF_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 
189 ATF_TEST_CASE(release);
190 ATF_TEST_CASE_HEAD(release)
191 {
192     set_md_var("descr", "Tests the auto_array smart pointer class' release "
193                "method");
194 }
195 ATF_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 
210 ATF_TEST_CASE(reset);
211 ATF_TEST_CASE_HEAD(reset)
212 {
213     set_md_var("descr", "Tests the auto_array smart pointer class' reset "
214                "method");
215 }
216 ATF_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 
234 ATF_TEST_CASE(assign);
235 ATF_TEST_CASE_HEAD(assign)
236 {
237     set_md_var("descr", "Tests the auto_array smart pointer class' "
238                "assignment operator");
239 }
240 ATF_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 
258 ATF_TEST_CASE(assign_ref);
259 ATF_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 }
265 ATF_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 
283 ATF_TEST_CASE(access);
284 ATF_TEST_CASE_HEAD(access)
285 {
286     set_md_var("descr", "Tests the auto_array smart pointer class' access "
287                "operator");
288 }
289 ATF_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 
301 ATF_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