1 | /* |
2 | * Copyright 2011 Collabora Ltd. |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * See the included COPYING file for more information. |
10 | */ |
11 | |
12 | #undef G_DISABLE_ASSERT |
13 | |
14 | #include <stdio.h> |
15 | #include <stdlib.h> |
16 | #include <string.h> |
17 | #include "glib.h" |
18 | |
19 | /* Keep in sync with glib/gbytes.c */ |
20 | struct _GBytes |
21 | { |
22 | gconstpointer data; |
23 | gsize size; |
24 | gint ref_count; |
25 | GDestroyNotify free_func; |
26 | gpointer user_data; |
27 | }; |
28 | |
29 | static const gchar *NYAN = "nyannyan" ; |
30 | static const gsize N_NYAN = 8; |
31 | |
32 | static void |
33 | test_new (void) |
34 | { |
35 | const gchar *data; |
36 | GBytes *bytes; |
37 | gsize size; |
38 | |
39 | data = "test" ; |
40 | bytes = g_bytes_new (data, size: 4); |
41 | g_assert (bytes != NULL); |
42 | g_assert (g_bytes_get_data (bytes, &size) != data); |
43 | g_assert_cmpuint (size, ==, 4); |
44 | g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4); |
45 | g_assert_cmpmem (data, 4, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes)); |
46 | |
47 | g_bytes_unref (bytes); |
48 | } |
49 | |
50 | static void |
51 | test_new_take (void) |
52 | { |
53 | gchar *data; |
54 | GBytes *bytes; |
55 | gsize size; |
56 | |
57 | data = g_strdup (str: "test" ); |
58 | bytes = g_bytes_new_take (data, size: 4); |
59 | g_assert (bytes != NULL); |
60 | g_assert (g_bytes_get_data (bytes, &size) == data); |
61 | g_assert_cmpuint (size, ==, 4); |
62 | g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4); |
63 | |
64 | g_bytes_unref (bytes); |
65 | } |
66 | |
67 | static void |
68 | test_new_static (void) |
69 | { |
70 | const gchar *data; |
71 | GBytes *bytes; |
72 | gsize size; |
73 | |
74 | data = "test" ; |
75 | bytes = g_bytes_new_static (data, size: 4); |
76 | g_assert (bytes != NULL); |
77 | g_assert (g_bytes_get_data (bytes, &size) == data); |
78 | g_assert_cmpuint (size, ==, 4); |
79 | g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4); |
80 | |
81 | g_bytes_unref (bytes); |
82 | } |
83 | |
84 | static void |
85 | test_new_from_bytes (void) |
86 | { |
87 | const gchar *data = "smile and wave" ; |
88 | GBytes *bytes; |
89 | GBytes *sub; |
90 | |
91 | bytes = g_bytes_new (data, size: 14); |
92 | sub = g_bytes_new_from_bytes (bytes, offset: 10, length: 4); |
93 | |
94 | g_assert (sub != NULL); |
95 | g_assert (g_bytes_get_data (sub, NULL) == ((gchar *)g_bytes_get_data (bytes, NULL)) + 10); |
96 | g_bytes_unref (bytes); |
97 | |
98 | g_assert_cmpmem (g_bytes_get_data (sub, NULL), g_bytes_get_size (sub), "wave" , 4); |
99 | g_bytes_unref (bytes: sub); |
100 | } |
101 | |
102 | /* Verify that creating slices of GBytes reference the top-most bytes |
103 | * at the correct offset. Ensure that intermediate GBytes are not referenced. |
104 | */ |
105 | static void |
106 | test_new_from_bytes_slice (void) |
107 | { |
108 | GBytes *bytes = g_bytes_new_static (data: "Some stupid data" , size: strlen (s: "Some stupid data" ) + 1); |
109 | GBytes *bytes1 = g_bytes_new_from_bytes (bytes, offset: 4, length: 13); |
110 | GBytes *bytes2 = g_bytes_new_from_bytes (bytes: bytes1, offset: 1, length: 12); |
111 | GBytes *bytes3 = g_bytes_new_from_bytes (bytes: bytes2, offset: 0, length: 6); |
112 | |
113 | g_assert_cmpint (bytes->ref_count, ==, 4); |
114 | g_assert_cmpint (bytes1->ref_count, ==, 1); |
115 | g_assert_cmpint (bytes2->ref_count, ==, 1); |
116 | g_assert_cmpint (bytes3->ref_count, ==, 1); |
117 | |
118 | g_assert_null (bytes->user_data); |
119 | g_assert (bytes1->user_data == bytes); |
120 | g_assert (bytes2->user_data == bytes); |
121 | g_assert (bytes3->user_data == bytes); |
122 | |
123 | g_assert_cmpint (17, ==, g_bytes_get_size (bytes)); |
124 | g_assert_cmpint (13, ==, g_bytes_get_size (bytes1)); |
125 | g_assert_cmpint (12, ==, g_bytes_get_size (bytes2)); |
126 | g_assert_cmpint (6, ==, g_bytes_get_size (bytes3)); |
127 | |
128 | g_assert_cmpint (0, ==, strncmp ("Some stupid data" , (gchar *)bytes->data, 17)); |
129 | g_assert_cmpint (0, ==, strncmp (" stupid data" , (gchar *)bytes1->data, 13)); |
130 | g_assert_cmpint (0, ==, strncmp ("stupid data" , (gchar *)bytes2->data, 12)); |
131 | g_assert_cmpint (0, ==, strncmp ("stupid" , (gchar *)bytes3->data, 6)); |
132 | |
133 | g_bytes_unref (bytes); |
134 | g_bytes_unref (bytes: bytes1); |
135 | g_bytes_unref (bytes: bytes2); |
136 | g_bytes_unref (bytes: bytes3); |
137 | } |
138 | |
139 | /* Ensure that referencing an entire GBytes just returns the same bytes |
140 | * instance (with incremented reference count) instead of a new instance. |
141 | */ |
142 | static void |
143 | test_new_from_bytes_shared_ref (void) |
144 | { |
145 | GBytes *bytes = g_bytes_new_static (data: "Some data" , size: strlen (s: "Some data" ) + 1); |
146 | GBytes *other = g_bytes_new_from_bytes (bytes, offset: 0, length: g_bytes_get_size (bytes)); |
147 | |
148 | g_assert (bytes == other); |
149 | g_assert_cmpint (bytes->ref_count, ==, 2); |
150 | |
151 | g_bytes_unref (bytes); |
152 | g_bytes_unref (bytes: other); |
153 | } |
154 | |
155 | static void |
156 | on_destroy_increment (gpointer data) |
157 | { |
158 | gint *count = data; |
159 | g_assert (count != NULL); |
160 | (*count)++; |
161 | } |
162 | |
163 | static void |
164 | test_new_with_free_func (void) |
165 | { |
166 | GBytes *bytes; |
167 | gchar *data; |
168 | gint count = 0; |
169 | gsize size; |
170 | |
171 | data = "test" ; |
172 | bytes = g_bytes_new_with_free_func (data, size: 4, free_func: on_destroy_increment, user_data: &count); |
173 | g_assert (bytes != NULL); |
174 | g_assert_cmpint (count, ==, 0); |
175 | g_assert (g_bytes_get_data (bytes, &size) == data); |
176 | g_assert_cmpuint (size, ==, 4); |
177 | g_assert_cmpuint (g_bytes_get_size (bytes), ==, 4); |
178 | |
179 | g_bytes_unref (bytes); |
180 | g_assert_cmpuint (count, ==, 1); |
181 | } |
182 | |
183 | static void |
184 | test_hash (void) |
185 | { |
186 | GBytes *bytes1; |
187 | GBytes *bytes2; |
188 | guint hash1; |
189 | guint hash2; |
190 | |
191 | bytes1 = g_bytes_new (data: "blah" , size: 4); |
192 | bytes2 = g_bytes_new (data: "blah" , size: 4); |
193 | |
194 | hash1 = g_bytes_hash (bytes: bytes1); |
195 | hash2 = g_bytes_hash (bytes: bytes2); |
196 | g_assert (hash1 == hash2); |
197 | |
198 | g_bytes_unref (bytes: bytes1); |
199 | g_bytes_unref (bytes: bytes2); |
200 | } |
201 | |
202 | static void |
203 | test_equal (void) |
204 | { |
205 | GBytes *bytes; |
206 | GBytes *bytes2; |
207 | |
208 | bytes = g_bytes_new (data: "blah" , size: 4); |
209 | |
210 | bytes2 = g_bytes_new (data: "blah" , size: 4); |
211 | g_assert (g_bytes_equal (bytes, bytes2)); |
212 | g_assert (g_bytes_equal (bytes2, bytes)); |
213 | g_bytes_unref (bytes: bytes2); |
214 | |
215 | bytes2 = g_bytes_new (data: "bla" , size: 3); |
216 | g_assert (!g_bytes_equal (bytes, bytes2)); |
217 | g_assert (!g_bytes_equal (bytes2, bytes)); |
218 | g_bytes_unref (bytes: bytes2); |
219 | |
220 | bytes2 = g_bytes_new (data: "true" , size: 4); |
221 | g_assert (!g_bytes_equal (bytes, bytes2)); |
222 | g_assert (!g_bytes_equal (bytes2, bytes)); |
223 | g_bytes_unref (bytes: bytes2); |
224 | |
225 | g_bytes_unref (bytes); |
226 | } |
227 | |
228 | static void |
229 | test_compare (void) |
230 | { |
231 | GBytes *bytes; |
232 | GBytes *bytes2; |
233 | |
234 | bytes = g_bytes_new (data: "blah" , size: 4); |
235 | |
236 | bytes2 = g_bytes_new (data: "blah" , size: 4); |
237 | g_assert_cmpint (g_bytes_compare (bytes, bytes2), ==, 0); |
238 | g_bytes_unref (bytes: bytes2); |
239 | |
240 | bytes2 = g_bytes_new (data: "bla" , size: 3); |
241 | g_assert_cmpint (g_bytes_compare (bytes, bytes2), >, 0); |
242 | g_bytes_unref (bytes: bytes2); |
243 | |
244 | bytes2 = g_bytes_new (data: "abcd" , size: 4); |
245 | g_assert_cmpint (g_bytes_compare (bytes, bytes2), >, 0); |
246 | g_bytes_unref (bytes: bytes2); |
247 | |
248 | bytes2 = g_bytes_new (data: "blahblah" , size: 8); |
249 | g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0); |
250 | g_bytes_unref (bytes: bytes2); |
251 | |
252 | bytes2 = g_bytes_new (data: "zyx" , size: 3); |
253 | g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0); |
254 | g_bytes_unref (bytes: bytes2); |
255 | |
256 | bytes2 = g_bytes_new (data: "zyxw" , size: 4); |
257 | g_assert_cmpint (g_bytes_compare (bytes, bytes2), <, 0); |
258 | g_bytes_unref (bytes: bytes2); |
259 | |
260 | g_bytes_unref (bytes); |
261 | } |
262 | |
263 | static void |
264 | test_to_data_transferred (void) |
265 | { |
266 | gconstpointer memory; |
267 | gpointer data; |
268 | gsize size; |
269 | GBytes *bytes; |
270 | |
271 | /* Memory transferred: one reference, and allocated with g_malloc */ |
272 | bytes = g_bytes_new (data: NYAN, size: N_NYAN); |
273 | memory = g_bytes_get_data (bytes, NULL); |
274 | data = g_bytes_unref_to_data (bytes, size: &size); |
275 | g_assert (data == memory); |
276 | g_assert_cmpmem (data, size, NYAN, N_NYAN); |
277 | g_free (mem: data); |
278 | } |
279 | |
280 | static void |
281 | test_to_data_two_refs (void) |
282 | { |
283 | gconstpointer memory; |
284 | gpointer data; |
285 | gsize size; |
286 | GBytes *bytes; |
287 | |
288 | /* Memory copied: two references */ |
289 | bytes = g_bytes_new (data: NYAN, size: N_NYAN); |
290 | bytes = g_bytes_ref (bytes); |
291 | memory = g_bytes_get_data (bytes, NULL); |
292 | data = g_bytes_unref_to_data (bytes, size: &size); |
293 | g_assert (data != memory); |
294 | g_assert_cmpmem (data, size, NYAN, N_NYAN); |
295 | g_free (mem: data); |
296 | g_assert (g_bytes_get_data (bytes, &size) == memory); |
297 | g_assert_cmpuint (size, ==, N_NYAN); |
298 | g_assert_cmpuint (g_bytes_get_size (bytes), ==, N_NYAN); |
299 | g_bytes_unref (bytes); |
300 | } |
301 | |
302 | static void |
303 | test_to_data_non_malloc (void) |
304 | { |
305 | gpointer data; |
306 | gsize size; |
307 | GBytes *bytes; |
308 | |
309 | /* Memory copied: non malloc memory */ |
310 | bytes = g_bytes_new_static (data: NYAN, size: N_NYAN); |
311 | g_assert (g_bytes_get_data (bytes, NULL) == NYAN); |
312 | data = g_bytes_unref_to_data (bytes, size: &size); |
313 | g_assert (data != (gpointer)NYAN); |
314 | g_assert_cmpmem (data, size, NYAN, N_NYAN); |
315 | g_free (mem: data); |
316 | } |
317 | |
318 | static void |
319 | test_to_array_transferred (void) |
320 | { |
321 | gconstpointer memory; |
322 | GByteArray *array; |
323 | GBytes *bytes; |
324 | |
325 | /* Memory transferred: one reference, and allocated with g_malloc */ |
326 | bytes = g_bytes_new (data: NYAN, size: N_NYAN); |
327 | memory = g_bytes_get_data (bytes, NULL); |
328 | array = g_bytes_unref_to_array (bytes); |
329 | g_assert (array != NULL); |
330 | g_assert (array->data == memory); |
331 | g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN); |
332 | g_byte_array_unref (array); |
333 | } |
334 | |
335 | static void |
336 | test_to_array_transferred_oversize (void) |
337 | { |
338 | g_test_message (format: "g_bytes_unref_to_array() can only take GBytes up to " |
339 | "G_MAXUINT in length; test that longer ones are rejected" ); |
340 | |
341 | if (sizeof (guint) >= sizeof (gsize)) |
342 | { |
343 | g_test_skip (msg: "Skipping test as guint is not smaller than gsize" ); |
344 | } |
345 | else if (g_test_undefined ()) |
346 | { |
347 | GByteArray *array = NULL; |
348 | GBytes *bytes = NULL; |
349 | gpointer data = g_memdup2 (mem: NYAN, byte_size: N_NYAN); |
350 | gsize len = ((gsize) G_MAXUINT) + 1; |
351 | |
352 | bytes = g_bytes_new_take (data, size: len); |
353 | g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL, |
354 | pattern: "g_byte_array_new_take: assertion 'len <= G_MAXUINT' failed" ); |
355 | array = g_bytes_unref_to_array (g_steal_pointer (&bytes)); |
356 | g_test_assert_expected_messages (); |
357 | g_assert_null (array); |
358 | |
359 | g_free (mem: data); |
360 | } |
361 | else |
362 | { |
363 | g_test_skip (msg: "Skipping test as testing undefined behaviour is disabled" ); |
364 | } |
365 | } |
366 | |
367 | static void |
368 | test_to_array_two_refs (void) |
369 | { |
370 | gconstpointer memory; |
371 | GByteArray *array; |
372 | GBytes *bytes; |
373 | gsize size; |
374 | |
375 | /* Memory copied: two references */ |
376 | bytes = g_bytes_new (data: NYAN, size: N_NYAN); |
377 | bytes = g_bytes_ref (bytes); |
378 | memory = g_bytes_get_data (bytes, NULL); |
379 | array = g_bytes_unref_to_array (bytes); |
380 | g_assert (array != NULL); |
381 | g_assert (array->data != memory); |
382 | g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN); |
383 | g_byte_array_unref (array); |
384 | g_assert (g_bytes_get_data (bytes, &size) == memory); |
385 | g_assert_cmpuint (size, ==, N_NYAN); |
386 | g_assert_cmpuint (g_bytes_get_size (bytes), ==, N_NYAN); |
387 | g_bytes_unref (bytes); |
388 | } |
389 | |
390 | static void |
391 | test_to_array_non_malloc (void) |
392 | { |
393 | GByteArray *array; |
394 | GBytes *bytes; |
395 | |
396 | /* Memory copied: non malloc memory */ |
397 | bytes = g_bytes_new_static (data: NYAN, size: N_NYAN); |
398 | g_assert (g_bytes_get_data (bytes, NULL) == NYAN); |
399 | array = g_bytes_unref_to_array (bytes); |
400 | g_assert (array != NULL); |
401 | g_assert (array->data != (gpointer)NYAN); |
402 | g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN); |
403 | g_byte_array_unref (array); |
404 | } |
405 | |
406 | static void |
407 | test_null (void) |
408 | { |
409 | GBytes *bytes; |
410 | gpointer data; |
411 | gsize size; |
412 | |
413 | bytes = g_bytes_new (NULL, size: 0); |
414 | |
415 | data = g_bytes_unref_to_data (bytes, size: &size); |
416 | |
417 | g_assert (data == NULL); |
418 | g_assert (size == 0); |
419 | } |
420 | |
421 | int |
422 | main (int argc, char *argv[]) |
423 | { |
424 | g_test_init (argc: &argc, argv: &argv, NULL); |
425 | |
426 | g_test_bug_base (uri_pattern: "https://bugzilla.gnome.org/" ); |
427 | |
428 | g_test_add_func (testpath: "/bytes/new" , test_func: test_new); |
429 | g_test_add_func (testpath: "/bytes/new-take" , test_func: test_new_take); |
430 | g_test_add_func (testpath: "/bytes/new-static" , test_func: test_new_static); |
431 | g_test_add_func (testpath: "/bytes/new-with-free-func" , test_func: test_new_with_free_func); |
432 | g_test_add_func (testpath: "/bytes/new-from-bytes" , test_func: test_new_from_bytes); |
433 | g_test_add_func (testpath: "/bytes/new-from-bytes-slice" , test_func: test_new_from_bytes_slice); |
434 | g_test_add_func (testpath: "/bytes/new-from-bytes-shared-ref" , test_func: test_new_from_bytes_shared_ref); |
435 | g_test_add_func (testpath: "/bytes/hash" , test_func: test_hash); |
436 | g_test_add_func (testpath: "/bytes/equal" , test_func: test_equal); |
437 | g_test_add_func (testpath: "/bytes/compare" , test_func: test_compare); |
438 | g_test_add_func (testpath: "/bytes/to-data/transferred" , test_func: test_to_data_transferred); |
439 | g_test_add_func (testpath: "/bytes/to-data/two-refs" , test_func: test_to_data_two_refs); |
440 | g_test_add_func (testpath: "/bytes/to-data/non-malloc" , test_func: test_to_data_non_malloc); |
441 | g_test_add_func (testpath: "/bytes/to-array/transferred" , test_func: test_to_array_transferred); |
442 | g_test_add_func (testpath: "/bytes/to-array/transferred/oversize" , test_func: test_to_array_transferred_oversize); |
443 | g_test_add_func (testpath: "/bytes/to-array/two-refs" , test_func: test_to_array_two_refs); |
444 | g_test_add_func (testpath: "/bytes/to-array/non-malloc" , test_func: test_to_array_non_malloc); |
445 | g_test_add_func (testpath: "/bytes/null" , test_func: test_null); |
446 | |
447 | return g_test_run (); |
448 | } |
449 | |