~ci-train-bot/unity-api/unity-api-ubuntu-zesty-2272

« back to all changes in this revision

Viewing changes to test/gtest/unity/util/GObjectMemory/GObjectMemory_test.cpp

  • Committer: Bileto Bot
  • Date: 2017-01-19 13:54:08 UTC
  • mfrom: (264.1.1 trunk)
  • Revision ID: ci-train-bot@canonical.com-20170119135408-2ttw0u9ysq1psw3i
unity::util - add GObject shared memory utility classes
and helper methods.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2013-2017 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU Lesser General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
 
17
 *              Pete Woods <pete.woods@canonical.com>
 
18
 */
 
19
 
 
20
#include <unity/util/GObjectMemory.h>
 
21
#include <glib-object.h>
 
22
#include <gtest/gtest.h>
 
23
#include <list>
 
24
#include <string>
 
25
#include <unordered_set>
 
26
 
 
27
using namespace std;
 
28
using namespace unity::util;
 
29
 
 
30
namespace
 
31
{
 
32
 
 
33
typedef pair<string, int> Deleted;
 
34
static list<Deleted> DELETED_OBJECTS;
 
35
 
 
36
//
 
37
// Below here is a basic implementation of a GObject type
 
38
//
 
39
 
 
40
// "public" header
 
41
 
 
42
G_BEGIN_DECLS
 
43
 
 
44
#define FOO_TYPE_BAR foo_bar_get_type()
 
45
G_DECLARE_FINAL_TYPE (FooBar, foo_bar, FOO, BAR, GObject)
 
46
 
 
47
FooBar *foo_bar_new();
 
48
 
 
49
FooBar *foo_bar_new_full(const gchar* const name, guint id);
 
50
 
 
51
G_END_DECLS
 
52
 
 
53
// private implementation
 
54
 
 
55
struct _FooBar
 
56
{
 
57
    GObject parent_instance;
 
58
 
 
59
    gchar *name;
 
60
 
 
61
    guint id;
 
62
};
 
63
 
 
64
G_DEFINE_TYPE (FooBar, foo_bar, G_TYPE_OBJECT)
 
65
 
 
66
enum
 
67
{
 
68
    PROP_NAME = 1,
 
69
    PROP_ID,
 
70
    N_PROPERTIES
 
71
};
 
72
 
 
73
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
 
74
 
 
75
static void foo_bar_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
 
76
{
 
77
    FooBar *self = FOO_BAR(object);
 
78
 
 
79
    switch (property_id)
 
80
    {
 
81
    case PROP_NAME:
 
82
        g_free(self->name);
 
83
        self->name = g_value_dup_string(value);
 
84
        break;
 
85
 
 
86
    case PROP_ID:
 
87
        self->id = g_value_get_uint(value);
 
88
        break;
 
89
 
 
90
    default:
 
91
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
 
92
        break;
 
93
    }
 
94
}
 
95
 
 
96
static void foo_bar_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
 
97
{
 
98
    FooBar *self = FOO_BAR(object);
 
99
 
 
100
    switch (property_id)
 
101
    {
 
102
    case PROP_NAME:
 
103
        g_value_set_string(value, self->name);
 
104
        break;
 
105
 
 
106
    case PROP_ID:
 
107
        g_value_set_uint(value, self->id);
 
108
        break;
 
109
 
 
110
    default:
 
111
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
 
112
        break;
 
113
    }
 
114
}
 
115
 
 
116
static void foo_bar_finalize(GObject *gobject)
 
117
{
 
118
    FooBar* self = FOO_BAR(gobject);
 
119
 
 
120
    DELETED_OBJECTS.emplace_back(Deleted(string(self->name == NULL ? "" : self->name), self->id));
 
121
 
 
122
    g_free(self->name);
 
123
 
 
124
    G_OBJECT_CLASS (foo_bar_parent_class)->finalize(gobject);
 
125
}
 
126
 
 
127
static void foo_bar_class_init(FooBarClass *klass)
 
128
{
 
129
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
130
 
 
131
    object_class->set_property = foo_bar_set_property;
 
132
    object_class->get_property = foo_bar_get_property;
 
133
    object_class->finalize = foo_bar_finalize;
 
134
 
 
135
    obj_properties[PROP_NAME] =
 
136
      g_param_spec_string ("name",
 
137
                           "Name",
 
138
                           "Name of the file to load and display from.",
 
139
                           "default-name"  /* default value */,
 
140
                           (GParamFlags) (G_PARAM_READWRITE));
 
141
 
 
142
    obj_properties[PROP_ID] =
 
143
      g_param_spec_uint ("id",
 
144
                         "ID",
 
145
                         "ID of this dummy class",
 
146
                         0  /* minimum value */,
 
147
                         10 /* maximum value */,
 
148
                         2  /* default value */,
 
149
                         (GParamFlags) G_PARAM_READWRITE);
 
150
 
 
151
    g_object_class_install_properties (object_class,
 
152
                                       N_PROPERTIES,
 
153
                                       obj_properties);
 
154
}
 
155
 
 
156
static void foo_bar_init(FooBar *)
 
157
{
 
158
}
 
159
 
 
160
FooBar *foo_bar_new()
 
161
{
 
162
    return FOO_BAR(g_object_new(FOO_TYPE_BAR, NULL));
 
163
}
 
164
 
 
165
FooBar *foo_bar_new_full(const gchar* const name, guint id)
 
166
{
 
167
    return FOO_BAR(g_object_new(FOO_TYPE_BAR, "name", name, "id", id, NULL));
 
168
}
 
169
 
 
170
//
 
171
// Test cases
 
172
//
 
173
 
 
174
class GObjectMemoryTest: public testing::Test
 
175
{
 
176
protected:
 
177
    void SetUp() override
 
178
    {
 
179
        DELETED_OBJECTS.clear();
 
180
    }
 
181
};
 
182
 
 
183
TEST_F(GObjectMemoryTest, trivial)
 
184
{
 
185
    auto basic = unique_gobject(foo_bar_new());
 
186
    EXPECT_TRUE(bool(basic));
 
187
    EXPECT_TRUE(G_IS_OBJECT(basic.get()));
 
188
}
 
189
 
 
190
TEST_F(GObjectMemoryTest, compare)
 
191
{
 
192
    FooBar* o1 = foo_bar_new();
 
193
    FooBar* o2 = foo_bar_new();
 
194
    if (o1 > o2) {
 
195
        std::swap(o1, o2);
 
196
    }
 
197
    ASSERT_TRUE(o1 < o2);
 
198
    auto u1 = unique_gobject(o1);
 
199
    auto u2 = unique_gobject(o2);
 
200
 
 
201
    EXPECT_TRUE(!(u1 == nullptr));
 
202
    EXPECT_TRUE(u1 != nullptr);
 
203
    EXPECT_TRUE(u1 != u2);
 
204
    EXPECT_TRUE(!(u1 == u2));
 
205
    EXPECT_TRUE(u1 < u2);
 
206
    EXPECT_TRUE(!(u2 < u1));
 
207
    EXPECT_TRUE(!(u1 == u2));
 
208
    EXPECT_TRUE(!(u2 == u1));
 
209
    EXPECT_TRUE(u1 <= u2);
 
210
    EXPECT_TRUE(!(u2 <= u1));
 
211
}
 
212
 
 
213
// This is its own thing due to need to avoid double release.
 
214
 
 
215
TEST_F(GObjectMemoryTest, equality)
 
216
{
 
217
    FooBar* o = foo_bar_new();
 
218
    auto u1 = unique_gobject(o);
 
219
    g_object_ref(o);
 
220
    auto u2 = unique_gobject(o);
 
221
    EXPECT_TRUE(u1 == u2);
 
222
    EXPECT_TRUE(u2 == u1);
 
223
    EXPECT_TRUE(!(u1 != u2));
 
224
    EXPECT_TRUE(!(u2 != u1));
 
225
}
 
226
 
 
227
TEST_F(GObjectMemoryTest, release)
 
228
{
 
229
    FooBar* o = foo_bar_new();
 
230
    auto u = unique_gobject(o);
 
231
    EXPECT_TRUE(u != nullptr);
 
232
    EXPECT_TRUE(u.get() != nullptr);
 
233
    EXPECT_TRUE(o == u.release());
 
234
    EXPECT_TRUE(!u);
 
235
    EXPECT_TRUE(u.get() == nullptr);
 
236
    g_object_unref(o);
 
237
}
 
238
 
 
239
TEST_F(GObjectMemoryTest, refcount)
 
240
{
 
241
    GObject* o = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
 
242
    EXPECT_EQ(1, o->ref_count);
 
243
    g_object_ref(o);
 
244
 
 
245
    {
 
246
        EXPECT_EQ(2, o->ref_count);
 
247
        auto u = unique_gobject<GObject>(o);
 
248
        EXPECT_EQ(2, o->ref_count);
 
249
        // Now it dies and refcount is reduced.
 
250
    }
 
251
 
 
252
    EXPECT_EQ(1, o->ref_count);
 
253
    g_object_unref(o);
 
254
}
 
255
 
 
256
TEST_F(GObjectMemoryTest, swap)
 
257
{
 
258
    FooBar* o1 = foo_bar_new();
 
259
    FooBar* o2 = foo_bar_new();
 
260
    auto u1 = unique_gobject(o1);
 
261
    auto u2 = unique_gobject(o2);
 
262
 
 
263
    u1.swap(u2);
 
264
    EXPECT_EQ(o2, u1.get());
 
265
    EXPECT_EQ(o1, u2.get());
 
266
 
 
267
    std::swap(u1, u2);
 
268
    EXPECT_EQ(o1, u1.get());
 
269
    EXPECT_EQ(o2, u2.get());
 
270
}
 
271
 
 
272
TEST_F(GObjectMemoryTest, floating)
 
273
{
 
274
    GObject* o = G_OBJECT(g_object_new(G_TYPE_INITIALLY_UNOWNED, nullptr));
 
275
    auto u = unique_gobject<GObject>(o);
 
276
    // it should have sunk the reference
 
277
    EXPECT_TRUE(g_object_is_floating(u.get()) == FALSE);
 
278
}
 
279
 
 
280
TEST_F(GObjectMemoryTest, move)
 
281
{
 
282
    GObject* o1 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
 
283
    GObject* o2 = G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr));
 
284
    g_object_ref(o1);
 
285
    auto u1 = unique_gobject<GObject>(o1);
 
286
    auto u2 = unique_gobject<GObject>(o2);
 
287
    u1 = std::move(u2);
 
288
    EXPECT_TRUE(u1.get() == o2);
 
289
    EXPECT_TRUE(!u2);
 
290
    EXPECT_TRUE(o1->ref_count == 1);
 
291
    g_object_unref(o1);
 
292
}
 
293
 
 
294
TEST_F(GObjectMemoryTest, null)
 
295
{
 
296
    FooBar* o1 = NULL;
 
297
    FooBar* o3 = foo_bar_new();
 
298
    auto u1 = unique_gobject(o1);
 
299
    auto u2 = unique_gobject<FooBar>(nullptr);
 
300
    auto u3 = unique_gobject(o3);
 
301
 
 
302
    EXPECT_TRUE(!u1);
 
303
    EXPECT_TRUE(!u2);
 
304
    u3 = nullptr;
 
305
    EXPECT_TRUE(!u3);
 
306
}
 
307
 
 
308
TEST_F(GObjectMemoryTest, reset)
 
309
{
 
310
    FooBar* o1 = foo_bar_new();
 
311
    FooBar* o2 = foo_bar_new();
 
312
    auto u = unique_gobject(o1);
 
313
 
 
314
    u.reset(o2);
 
315
    EXPECT_EQ(o2, u.get());
 
316
    u.reset(nullptr);
 
317
    EXPECT_TRUE(!u);
 
318
}
 
319
 
 
320
TEST_F(GObjectMemoryTest, sizeoftest) {
 
321
    EXPECT_EQ(sizeof(FooBar*), sizeof(unique_ptr<FooBar>));
 
322
}
 
323
 
 
324
TEST_F(GObjectMemoryTest, hash)
 
325
{
 
326
    unordered_set<shared_ptr<FooBar>> s;
 
327
    auto a = share_gobject(foo_bar_new());
 
328
    auto b = share_gobject(foo_bar_new());
 
329
    auto c = share_gobject(foo_bar_new());
 
330
 
 
331
    s.emplace(a);
 
332
    EXPECT_EQ(1, s.size());
 
333
    EXPECT_FALSE(s.end() == s.find(a));
 
334
 
 
335
    s.emplace(b);
 
336
    EXPECT_EQ(2, s.size());
 
337
    EXPECT_FALSE(s.end() == s.find(b));
 
338
 
 
339
    s.emplace(c);
 
340
    EXPECT_EQ(3, s.size());
 
341
    EXPECT_FALSE(s.end() == s.find(c));
 
342
 
 
343
    // Shouldn't add the duplicates
 
344
    s.emplace(a);
 
345
    s.emplace(b);
 
346
    s.emplace(c);
 
347
    EXPECT_EQ(3, s.size());
 
348
 
 
349
    s.erase(a);
 
350
    EXPECT_EQ(2, s.size());
 
351
 
 
352
    s.erase(b);
 
353
    EXPECT_EQ(1, s.size());
 
354
 
 
355
    s.erase(c);
 
356
    EXPECT_TRUE(s.empty());
 
357
}
 
358
 
 
359
TEST_F(GObjectMemoryTest, uniquePtrDeletesGObjects)
 
360
{
 
361
    {
 
362
        auto a = unique_gobject(foo_bar_new_full("a", 1));
 
363
        auto b = unique_gobject(foo_bar_new_full("b", 2));
 
364
    }
 
365
    EXPECT_EQ(list<Deleted>({{"b", 2}, {"a", 1}}), DELETED_OBJECTS);
 
366
}
 
367
 
 
368
TEST_F(GObjectMemoryTest, sharedPtrDeletesGObjects)
 
369
{
 
370
    {
 
371
        auto a = share_gobject(foo_bar_new_full("a", 1));
 
372
        auto b = share_gobject(foo_bar_new_full("b", 2));
 
373
    }
 
374
    EXPECT_EQ(list<Deleted>({{"b", 2}, {"a", 1}}), DELETED_OBJECTS);
 
375
}
 
376
 
 
377
TEST_F(GObjectMemoryTest, makeGObjectDeletesGObjects)
 
378
{
 
379
    {
 
380
        auto a = make_gobject<FooBar>(FOO_TYPE_BAR, "name", "a", "id", 1, nullptr);
 
381
        auto b = make_gobject<FooBar>(FOO_TYPE_BAR, "name", "b", "id", 2, nullptr);
 
382
        auto c = make_gobject<FooBar>(FOO_TYPE_BAR, "name", "c", "id", 3, nullptr);
 
383
    }
 
384
    EXPECT_EQ(list<Deleted>({{"c", 3}, {"b", 2}, {"a", 1}}), DELETED_OBJECTS);
 
385
}
 
386
 
 
387
TEST_F(GObjectMemoryTest, foo)
 
388
{
 
389
    {
 
390
        shared_ptr<FooBar> s;
 
391
        auto u = unique_gobject(foo_bar_new_full("hi", 6));
 
392
        s = move(u);
 
393
        // unique instance has been stolen from
 
394
        EXPECT_FALSE(u);
 
395
    }
 
396
    EXPECT_EQ(list<Deleted>({{"hi", 6}}), DELETED_OBJECTS);
 
397
    {
 
398
        shared_ptr<FooBar> s(unique_gobject(foo_bar_new_full("bye", 7)));
 
399
    }
 
400
    EXPECT_EQ(list<Deleted>({{"hi", 6}, {"bye", 7}}), DELETED_OBJECTS);
 
401
}
 
402
 
 
403
typedef pair<const char*, guint> GObjectMemoryMakeSharedTestParam;
 
404
 
 
405
class GObjectMemoryMakeHelperMethodsTest: public testing::TestWithParam<GObjectMemoryMakeSharedTestParam>
 
406
{
 
407
protected:
 
408
    /**
 
409
     * We test for multiple properties so that we can be sure the various
 
410
     * helper methods correctly pass through different data types and
 
411
     * multiple combinations of arguments correctly.
 
412
     */
 
413
    static void checkProperties(gpointer obj, const char* expectedName, guint expectedId)
 
414
    {
 
415
        char* name = NULL;
 
416
        guint id = 0;
 
417
 
 
418
        g_object_get(obj, "name", &name, "id", &id, NULL);
 
419
        EXPECT_STREQ(expectedName, name);
 
420
        EXPECT_EQ(expectedId, id);
 
421
 
 
422
        g_free(name);
 
423
    }
 
424
};
 
425
 
 
426
TEST_P(GObjectMemoryMakeHelperMethodsTest, make_gobject_passes_arguments)
 
427
{
 
428
    auto p = GetParam();
 
429
    auto obj = make_gobject<FooBar>(FOO_TYPE_BAR, "name", p.first, "id", p.second, nullptr);
 
430
    checkProperties(obj.get(), p.first, p.second);
 
431
}
 
432
 
 
433
TEST_P(GObjectMemoryMakeHelperMethodsTest, make_gobject_no_arguments)
 
434
{
 
435
    auto p = GetParam();
 
436
    auto obj = make_gobject<FooBar>(FOO_TYPE_BAR, nullptr);
 
437
    g_object_set(obj.get(), "name", p.first, "id", p.second, nullptr);
 
438
    checkProperties(obj.get(), p.first, p.second);
 
439
}
 
440
 
 
441
TEST_P(GObjectMemoryMakeHelperMethodsTest, unique_foo_bar_new)
 
442
{
 
443
    auto p = GetParam();
 
444
    auto obj = unique_gobject(foo_bar_new_full(p.first,p.second));
 
445
    checkProperties(obj.get(), p.first, p.second);
 
446
}
 
447
 
 
448
TEST_P(GObjectMemoryMakeHelperMethodsTest, share_foo_bar_new)
 
449
{
 
450
    auto p = GetParam();
 
451
    auto obj = share_gobject(foo_bar_new_full(p.first, p.second));
 
452
    checkProperties(obj.get(), p.first, p.second);
 
453
}
 
454
 
 
455
INSTANTIATE_TEST_CASE_P(BunchOfNames,
 
456
                        GObjectMemoryMakeHelperMethodsTest,
 
457
                        ::testing::Values(GObjectMemoryMakeSharedTestParam{"meeny", 1},
 
458
                                          GObjectMemoryMakeSharedTestParam{"miny", 2},
 
459
                                          GObjectMemoryMakeSharedTestParam{"moe", 3}));
 
460
 
 
461
}