test: Add test for serializing/deserializing NULL strings
[platform/upstream/gstreamer.git] / tests / check / gst / gststructure.c
1 /* GStreamer
2  * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
3  *
4  * gststructure.c: Unit tests for GstStructure
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22
23 #include <gst/gststructure.h>
24 #include <gst/check/gstcheck.h>
25
26
27 GST_START_TEST (test_from_string_int)
28 {
29   const char *strings[] = {
30     "video/x-raw, width = (int) 123456",
31     "video/x-raw, stride = (int) -123456",
32     "video/x-raw, red_mask = (int) 0xFFFF",
33     "video/x-raw, red_mask = (int) 0x0000FFFF",
34     "video/x-raw, red_mask = (int) 0x7FFFFFFF",
35     "video/x-raw, red_mask = (int) 0x80000000",
36     "video/x-raw, red_mask = (int) 0xFF000000",
37     /* result from
38      * gst-launch ... ! "video/x-raw, red_mask=(int)0xFF000000" ! ... */
39     "video/x-raw,\\ red_mask=(int)0xFF000000",
40   };
41   gint results[] = {
42     123456,
43     -123456,
44     0xFFFF,
45     0xFFFF,
46     0x7FFFFFFF,
47     (gint) 0x80000000,
48     (gint) 0xFF000000,
49     (gint) 0xFF000000,
50   };
51   GstStructure *structure;
52   int i;
53
54   for (i = 0; i < G_N_ELEMENTS (strings); ++i) {
55     const char *s;
56     const gchar *name;
57     gint value;
58
59     s = strings[i];
60
61     structure = gst_structure_from_string (s, NULL);
62     fail_if (structure == NULL, "Could not get structure from string %s", s);
63     name = gst_structure_nth_field_name (structure, 0);
64     fail_unless (gst_structure_get_int (structure, name, &value));
65     fail_unless (value == results[i],
66         "Value %d is not the expected result %d for string %s",
67         value, results[i], s);
68
69     /* cleanup */
70     gst_structure_free (structure);
71   }
72 }
73
74 GST_END_TEST;
75
76 GST_START_TEST (test_from_string_uint)
77 {
78   const char *strings[] = {
79     "taglist, bar = (uint) 123456",
80     "taglist, bar = (uint) 0xFFFF",
81     "taglist, bar = (uint) 0x0000FFFF",
82     "taglist, bar = (uint) 0x7FFFFFFF",
83     "taglist, bar = (uint) 0x80000000",
84     "taglist, bar = (uint) 0xFF000000"
85   };
86   guint results[] = {
87     123456,
88     0xFFFF,
89     0xFFFF,
90     0x7FFFFFFF,
91     0x80000000,
92     0xFF000000,
93   };
94   GstStructure *structure;
95   int i;
96
97   for (i = 0; i < G_N_ELEMENTS (strings); ++i) {
98     const char *s;
99     const gchar *name;
100     guint value;
101
102     s = strings[i];
103
104     structure = gst_structure_from_string (s, NULL);
105     fail_if (structure == NULL, "Could not get structure from string %s", s);
106     name = gst_structure_nth_field_name (structure, 0);
107     fail_unless (gst_structure_get_uint (structure, name, &value));
108     fail_unless (value == results[i],
109         "Value %u is not the expected result %u for string %s",
110         value, results[i], s);
111
112     /* cleanup */
113     gst_structure_free (structure);
114   }
115 }
116
117 GST_END_TEST;
118
119 /* Test type conversions from string */
120 GST_START_TEST (test_from_string)
121 {
122   GstStructure *structure;
123   const gchar *s;
124   const GValue *val;
125
126   s = "test-string,value=1";
127   structure = gst_structure_from_string (s, NULL);
128   fail_if (structure == NULL, "Could not get structure from string %s", s);
129   fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
130   fail_unless (G_VALUE_HOLDS_INT (val));
131   gst_structure_free (structure);
132
133   s = "test-string,value=1.0";
134   structure = gst_structure_from_string (s, NULL);
135   fail_if (structure == NULL, "Could not get structure from string %s", s);
136   fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
137   fail_unless (G_VALUE_HOLDS_DOUBLE (val));
138   gst_structure_free (structure);
139
140   s = "test-string,value=1/1";
141   structure = gst_structure_from_string (s, NULL);
142   fail_if (structure == NULL, "Could not get structure from string %s", s);
143   fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
144   fail_unless (GST_VALUE_HOLDS_FRACTION (val));
145   gst_structure_free (structure);
146
147   s = "test-string,value=bar";
148   structure = gst_structure_from_string (s, NULL);
149   fail_if (structure == NULL, "Could not get structure from string %s", s);
150   fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
151   fail_unless (G_VALUE_HOLDS_STRING (val));
152   gst_structure_free (structure);
153
154   s = "test-string,value=true";
155   structure = gst_structure_from_string (s, NULL);
156   fail_if (structure == NULL, "Could not get structure from string %s", s);
157   fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
158   fail_unless (G_VALUE_HOLDS_BOOLEAN (val));
159   fail_unless_equals_int (g_value_get_boolean (val), TRUE);
160   gst_structure_free (structure);
161
162   /* Tests for flagset deserialisation */
163   s = "foobar,value=0010:ffff";
164   structure = gst_structure_from_string (s, NULL);
165   fail_if (structure == NULL, "Could not get structure from string %s", s);
166   fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
167   fail_unless (GST_VALUE_HOLDS_FLAG_SET (val));
168   gst_structure_free (structure);
169
170   /* In the presence of the hex values, the strings don't matter as long as they
171    * have the right form */
172   s = "foobar,value=0010:ffff:+random+other/not-the-other";
173   structure = gst_structure_from_string (s, NULL);
174   fail_if (structure == NULL, "Could not get structure from string %s", s);
175   fail_unless ((val = gst_structure_get_value (structure, "value")) != NULL);
176   fail_unless (GST_VALUE_HOLDS_FLAG_SET (val));
177   gst_structure_free (structure);
178
179   /* Test that a timecode string is deserialised as a string, not a flagset:
180    * https://bugzilla.gnome.org/show_bug.cgi?id=779755 */
181   s = "foobar,timecode=00:01:00:00";
182   structure = gst_structure_from_string (s, NULL);
183   fail_if (structure == NULL, "Could not get structure from string %s", s);
184   fail_unless ((val = gst_structure_get_value (structure, "timecode")) != NULL);
185   fail_unless (G_VALUE_HOLDS_STRING (val));
186   gst_structure_free (structure);
187
188   s = "0.10:decoder-video/mpeg, abc=(boolean)false";
189   ASSERT_CRITICAL (structure = gst_structure_from_string (s, NULL));
190   fail_unless (structure == NULL, "Could not get structure from string %s", s);
191
192   /* make sure we bail out correctly in case of an error or if parsing fails */
193   s = "***foo***, abc=(boolean)false";
194   structure = gst_structure_from_string (s, NULL);
195   fail_unless (structure == NULL);
196
197   /* assert that we get a warning if the structure wasn't entirely consumed, but
198    * we didn't provide an end pointer */
199   s = "foo/bar; other random data";
200   ASSERT_WARNING (structure = gst_structure_from_string (s, NULL));
201   fail_if (structure == NULL, "Could not get structure from string %s", s);
202   gst_structure_free (structure);
203
204   /* make sure we handle \ as last character in various things, run with valgrind */
205   s = "foo,test=\"foobar\\";
206   structure = gst_structure_from_string (s, NULL);
207   fail_unless (structure == NULL);
208   s = "\\";
209   structure = gst_structure_from_string (s, NULL);
210   fail_unless (structure == NULL);
211   s = "foobar,test\\";
212   structure = gst_structure_from_string (s, NULL);
213   fail_unless (structure == NULL);
214   s = "foobar,test=(string)foo\\";
215   structure = gst_structure_from_string (s, NULL);
216   fail_unless (structure == NULL);
217 }
218
219 GST_END_TEST;
220
221
222 GST_START_TEST (test_to_string)
223 {
224   GstStructure *st1;
225
226   ASSERT_CRITICAL (st1 = gst_structure_new_empty ("Foo\nwith-newline"));
227   fail_unless (st1 == NULL);
228
229   ASSERT_CRITICAL (st1 = gst_structure_new_empty ("Foo with whitespace"));
230   fail_unless (st1 == NULL);
231   ASSERT_CRITICAL (st1 = gst_structure_new_empty ("1st"));
232   fail_unless (st1 == NULL);
233 }
234
235 GST_END_TEST;
236
237
238 GST_START_TEST (test_to_from_string)
239 {
240   GstStructure *st1, *st2;
241   gchar *str;
242
243   /* test escaping/unescaping */
244   st1 = gst_structure_new ("FooBar-123/0_1", "num", G_TYPE_INT, 9173,
245       "string", G_TYPE_STRING, "Something Like Face/Off", NULL);
246   str = gst_structure_to_string (st1);
247   st2 = gst_structure_from_string (str, NULL);
248   g_free (str);
249
250   fail_unless (st2 != NULL);
251   fail_unless (gst_structure_is_equal (st1, st2),
252       "Structures did not match:\n\tStructure 1: %" GST_PTR_FORMAT
253       "\n\tStructure 2: %" GST_PTR_FORMAT "\n", st1, st2);
254
255   gst_structure_free (st1);
256   gst_structure_free (st2);
257
258   /* Test NULL strings */
259   st1 = gst_structure_new ("test", "mynullstr", G_TYPE_STRING, NULL, NULL);
260   fail_unless (st1 != NULL);
261   str = gst_structure_to_string (st1);
262   fail_unless (strcmp (str, "test, mynullstr=(string)NULL;") == 0,
263       "Failed to serialize to right string: %s", str);
264
265   st2 = gst_structure_from_string (str, NULL);
266   fail_unless (st2 != NULL);
267   g_free (str);
268
269   fail_unless (gst_structure_is_equal (st1, st2),
270       "Structures did not match:\n\tStructure 1: %" GST_PTR_FORMAT
271       "\n\tStructure 2: %" GST_PTR_FORMAT "\n", st1, st2);
272
273   gst_structure_free (st1);
274   gst_structure_free (st2);
275 }
276
277 GST_END_TEST;
278
279 /* Added to make sure taglists are properly serialized/deserialized after bug
280  * https://bugzilla.gnome.org/show_bug.cgi?id=733131 */
281 GST_START_TEST (test_to_from_string_tag_event)
282 {
283   GstEvent *tagevent;
284   GstTagList *taglist;
285   GstStructure *st1, *st2;
286   gchar *str;
287
288   /* empty taglist */
289   taglist = gst_tag_list_new_empty ();
290   tagevent = gst_event_new_tag (taglist);
291
292   st1 = (GstStructure *) gst_event_get_structure (tagevent);
293   str = gst_structure_to_string (st1);
294   fail_unless (str != NULL);
295
296   st2 = gst_structure_new_from_string (str);
297   fail_unless (st2 != NULL);
298   fail_unless (gst_structure_is_equal (st1, st2));
299   gst_event_unref (tagevent);
300   gst_structure_free (st2);
301   g_free (str);
302
303   /* taglist with data */
304   taglist = gst_tag_list_new ("title", "TEST TITLE", NULL);
305   tagevent = gst_event_new_tag (taglist);
306
307   st1 = (GstStructure *) gst_event_get_structure (tagevent);
308   str = gst_structure_to_string (st1);
309   fail_unless (str != NULL);
310
311   st2 = gst_structure_new_from_string (str);
312   fail_unless (st2 != NULL);
313   fail_unless (gst_structure_is_equal (st1, st2));
314   gst_event_unref (tagevent);
315   gst_structure_free (st2);
316   g_free (str);
317 }
318
319 GST_END_TEST;
320
321 GST_START_TEST (test_complete_structure)
322 {
323   GstStructure *structure;
324   const gchar *s;
325
326   s = "GstEventSeek, rate=(double)1, format=(GstFormat)GST_FORMAT_TIME, flags=(GstSeekFlags)GST_SEEK_FLAG_NONE, start_type=(GstSeekType)GST_SEEK_TYPE_SET, start=(gint64)1000000000, stop_type=(GstSeekType)GST_SEEK_TYPE_NONE, stop=(gint64)0";
327   structure = gst_structure_from_string (s, NULL);
328   fail_if (structure == NULL, "Could not get structure from string %s", s);
329   /* FIXME: TODO: add checks for correct serialization of members ? */
330   gst_structure_free (structure);
331 }
332
333 GST_END_TEST;
334
335 GST_START_TEST (test_string_properties)
336 {
337   GstStructure *st1, *st2;
338   gchar *str;
339
340   /* test escaping/unescaping */
341   st1 = gst_structure_new ("RandomStructure", "prop1", G_TYPE_STRING, "foo",
342       "prop2", G_TYPE_STRING, "", "prop3", G_TYPE_STRING, NULL,
343       "prop4", G_TYPE_STRING, "NULL", NULL);
344   str = gst_structure_to_string (st1);
345   st2 = gst_structure_from_string (str, NULL);
346   g_free (str);
347
348   fail_unless (st2 != NULL);
349   fail_unless (gst_structure_is_equal (st1, st2),
350       "Structures did not match:\n\tStructure 1: %" GST_PTR_FORMAT
351       "\n\tStructure 2: %" GST_PTR_FORMAT "\n", st1, st2);
352
353   gst_structure_free (st1);
354   gst_structure_free (st2);
355 }
356
357 GST_END_TEST;
358
359 GST_START_TEST (test_structure_new)
360 {
361   GstStructure *s;
362   GError *e;
363   GQuark domain;
364   gboolean bool;
365   gint num, den;
366   GstClockTime clocktime;
367   guint64 uint64;
368
369   s = gst_structure_new ("name",
370       "key", G_TYPE_STRING, "value",
371       "bool", G_TYPE_BOOLEAN, TRUE,
372       "fraction", GST_TYPE_FRACTION, 1, 5,
373       "clocktime", GST_TYPE_CLOCK_TIME, GST_CLOCK_TIME_NONE,
374       "uint64", G_TYPE_UINT64, (guint64) 1234, NULL);
375
376   fail_unless (gst_structure_get_field_type (s, "unknown") == G_TYPE_INVALID);
377   /* test setting a different name */
378   gst_structure_set_name (s, "newname");
379   fail_unless (strcmp (gst_structure_get_string (s, "key"), "value") == 0);
380   fail_unless (gst_structure_has_field (s, "key"));
381   fail_unless_equals_int (gst_structure_n_fields (s), 5);
382   /* test removing a field */
383   gst_structure_remove_field (s, "key");
384   fail_if (gst_structure_get_string (s, "key"));
385   fail_if (gst_structure_has_field (s, "key"));
386   fail_unless_equals_int (gst_structure_n_fields (s), 4);
387
388   fail_unless (gst_structure_get_boolean (s, "bool", &bool));
389   fail_unless (bool);
390
391   fail_unless (gst_structure_get_fraction (s, "fraction", &num, &den));
392   fail_unless_equals_int (num, 1);
393   fail_unless_equals_int (den, 5);
394
395   fail_unless (gst_structure_get_clock_time (s, "clocktime", &clocktime));
396   fail_unless_equals_uint64 (clocktime, GST_CLOCK_TIME_NONE);
397
398   fail_unless (gst_structure_get_uint64 (s, "uint64", &uint64));
399   fail_unless_equals_uint64 (uint64, 1234);
400
401   gst_structure_free (s);
402
403   domain = g_quark_from_static_string ("test");
404   e = g_error_new (domain, 0, "a test error");
405   s = gst_structure_new ("name", "key", G_TYPE_ERROR, e, NULL);
406   g_error_free (e);
407   gst_structure_free (s);
408
409   ASSERT_CRITICAL (gst_structure_free (gst_structure_new_empty
410           ("0.10:decoder-video/mpeg")));
411
412   /* make sure we bail out correctly in case of an error or if parsing fails */
413   ASSERT_CRITICAL (s = gst_structure_new ("^joo\nba\ndoo^",
414           "abc", G_TYPE_BOOLEAN, FALSE, NULL));
415   fail_unless (s == NULL);
416 }
417
418 GST_END_TEST;
419
420 GST_START_TEST (test_fixate)
421 {
422   GstStructure *s;
423
424   s = gst_structure_new ("name",
425       "int", G_TYPE_INT, 5,
426       "intrange", GST_TYPE_INT_RANGE, 5, 10,
427       "intrange2", GST_TYPE_INT_RANGE, 5, 10, NULL);
428
429   fail_if (gst_structure_fixate_field_nearest_int (s, "int", 5));
430   fail_unless (gst_structure_fixate_field_nearest_int (s, "intrange", 5));
431   fail_if (gst_structure_fixate_field_nearest_int (s, "intrange", 5));
432   fail_unless (gst_structure_fixate_field_nearest_int (s, "intrange2", 15));
433   fail_if (gst_structure_fixate_field_nearest_int (s, "intrange2", 15));
434   gst_structure_free (s);
435 }
436
437 GST_END_TEST;
438
439 GST_START_TEST (test_fixate_frac_list)
440 {
441   GstStructure *s, *s2;
442   GValue list = { 0 };
443   GValue frac = { 0 };
444   gchar *str;
445   gint num, denom;
446
447   g_value_init (&list, GST_TYPE_LIST);
448   g_value_init (&frac, GST_TYPE_FRACTION);
449
450   gst_value_set_fraction (&frac, 30, 1);
451   gst_value_list_append_value (&list, &frac);
452   gst_value_set_fraction (&frac, 15, 1);
453   gst_value_list_append_value (&list, &frac);
454   gst_value_set_fraction (&frac, 10, 1);
455   gst_value_list_append_value (&list, &frac);
456
457   s = gst_structure_new_empty ("name");
458   gst_structure_set_value (s, "frac", &list);
459   g_value_unset (&frac);
460   g_value_unset (&list);
461
462   str = gst_structure_to_string (s);
463   GST_DEBUG ("list %s", str);
464   g_free (str);
465
466   /* take copy */
467   s2 = gst_structure_copy (s);
468
469   /* fixate to the nearest fraction, this should give 15/1 */
470   fail_unless (gst_structure_fixate_field_nearest_fraction (s, "frac", 14, 1));
471
472   fail_unless (gst_structure_get_fraction (s, "frac", &num, &denom));
473   fail_unless (num == 15);
474   fail_unless (denom == 1);
475
476   gst_structure_free (s);
477   s = s2;
478
479   /* fixate to the nearest fraction, this should give 30/1 */
480   fail_unless (gst_structure_fixate_field_nearest_fraction (s, "frac", G_MAXINT,
481           1));
482
483   fail_unless (gst_structure_get_fraction (s, "frac", &num, &denom));
484   fail_unless (num == 30);
485   fail_unless (denom == 1);
486   gst_structure_free (s);
487 }
488
489 GST_END_TEST;
490
491 GST_START_TEST (test_is_subset_equal_array_list)
492 {
493   GstStructure *s1, *s2;
494
495   s1 = gst_structure_from_string ("test/test, channels=(int){ 1, 2 }", NULL);
496   fail_if (s1 == NULL);
497   s2 = gst_structure_from_string ("test/test, channels=(int)[ 1, 2 ]", NULL);
498   fail_if (s2 == NULL);
499
500   fail_unless (gst_structure_is_subset (s1, s2));
501
502   gst_structure_free (s1);
503   gst_structure_free (s2);
504 }
505
506 GST_END_TEST;
507
508 GST_START_TEST (test_is_subset_different_name)
509 {
510   GstStructure *s1, *s2;
511
512   s1 = gst_structure_from_string ("test/test, channels=(int)1", NULL);
513   fail_if (s1 == NULL);
514   s2 = gst_structure_from_string ("test/baz, channels=(int)1", NULL);
515   fail_if (s2 == NULL);
516
517   fail_unless (!gst_structure_is_subset (s1, s2));
518
519   gst_structure_free (s1);
520   gst_structure_free (s2);
521 }
522
523 GST_END_TEST;
524
525 GST_START_TEST (test_is_subset_superset_missing_fields)
526 {
527   GstStructure *s1, *s2;
528
529   /* a missing field is equivalent to any value */
530   s1 = gst_structure_from_string ("test/test, channels=(int)1, rate=(int)1",
531       NULL);
532   fail_if (s1 == NULL);
533   s2 = gst_structure_from_string ("test/test, channels=(int)1", NULL);
534   fail_if (s2 == NULL);
535
536   fail_unless (gst_structure_is_subset (s1, s2));
537
538   gst_structure_free (s1);
539   gst_structure_free (s2);
540 }
541
542 GST_END_TEST;
543
544 GST_START_TEST (test_is_subset_superset_extra_fields)
545 {
546   GstStructure *s1, *s2;
547
548   /* a missing field is equivalent to any value */
549   s1 = gst_structure_from_string ("test/test, channels=(int)1", NULL);
550   fail_if (s1 == NULL);
551   s2 = gst_structure_from_string ("test/test, channels=(int)1, rate=(int)1",
552       NULL);
553   fail_if (s2 == NULL);
554
555   fail_unless (!gst_structure_is_subset (s1, s2));
556
557   gst_structure_free (s1);
558   gst_structure_free (s2);
559 }
560
561 GST_END_TEST;
562
563 GST_START_TEST (test_is_subset_superset_extra_values)
564 {
565   GstStructure *s1, *s2;
566
567   s1 = gst_structure_from_string ("test/test, channels=(int)1", NULL);
568   fail_if (s1 == NULL);
569   s2 = gst_structure_from_string ("test/test, channels=(int)[ 1, 2 ]", NULL);
570   fail_if (s2 == NULL);
571
572   fail_unless (gst_structure_is_subset (s1, s2));
573
574   gst_structure_free (s1);
575   gst_structure_free (s2);
576 }
577
578 GST_END_TEST;
579
580
581 GST_START_TEST (test_structure_nested)
582 {
583   GstStructure *sp, *sc1, *sc2;
584   gchar *str;
585
586   sc1 = gst_structure_new ("Camera",
587       "XResolution", G_TYPE_INT, 72, "YResolution", G_TYPE_INT, 73, NULL);
588   fail_unless (sc1 != NULL);
589
590   sc2 = gst_structure_new ("Image-Data",
591       "Orientation", G_TYPE_STRING, "top-left",
592       "Comment", G_TYPE_STRING, "super photo", NULL);
593   fail_unless (sc2 != NULL);
594
595   sp = gst_structure_new ("Exif", "Camera", GST_TYPE_STRUCTURE, sc1,
596       "Image Data", GST_TYPE_STRUCTURE, sc2, NULL);
597   fail_unless (sp != NULL);
598
599   fail_unless (gst_structure_n_fields (sp) == 2);
600
601   fail_unless (gst_structure_has_field_typed (sp, "Camera",
602           GST_TYPE_STRUCTURE));
603
604   str = gst_structure_to_string (sp);
605   fail_unless (str != NULL);
606
607   GST_DEBUG ("serialized to '%s'", str);
608
609   fail_unless (g_str_equal (str,
610           "Exif"
611           ", Camera=(structure)\"Camera\\,\\ XResolution\\=\\(int\\)72\\,\\ YResolution\\=\\(int\\)73\\;\""
612           ", Image Data=(structure)\"Image-Data\\,\\ Orientation\\=\\(string\\)top-left\\,\\ Comment\\=\\(string\\)\\\"super\\\\\\ photo\\\"\\;\";"));
613
614   g_free (str);
615   str = NULL;
616
617   gst_structure_free (sc1);
618   gst_structure_free (sc2);
619   gst_structure_free (sp);
620 }
621
622 GST_END_TEST;
623
624 GST_START_TEST (test_structure_nested_from_and_to_string)
625 {
626   GstStructure *s;
627   const gchar *str1;
628   gchar *str2, *end = NULL;
629
630   str1 = "main"
631       ", main-sub1=(structure)\"type-b\\,\\ machine-type\\=\\(int\\)0\\;\""
632       ", main-sub2=(structure)\"type-a\\,\\ plugin-filename\\=\\(string\\)\\\"/home/user/lib/lib\\\\\\ with\\\\\\ spaces.dll\\\"\\,\\ machine-type\\=\\(int\\)1\\;\""
633       ", main-sub3=(structure)\"type-b\\,\\ plugin-filename\\=\\(string\\)/home/user/lib/lib_no_spaces.so\\,\\ machine-type\\=\\(int\\)1\\;\""
634       ";";
635
636   s = gst_structure_from_string (str1, &end);
637   fail_unless (s != NULL);
638
639   GST_DEBUG ("not parsed part : %s", end);
640   fail_unless (*end == '\0');
641
642   fail_unless (gst_structure_n_fields (s) == 3);
643
644   fail_unless (gst_structure_has_field_typed (s, "main-sub1",
645           GST_TYPE_STRUCTURE));
646
647   str2 = gst_structure_to_string (s);
648   fail_unless (str2 != NULL);
649
650   fail_unless (g_str_equal (str1, str2));
651
652   g_free (str2);
653
654   gst_structure_free (s);
655 }
656
657 GST_END_TEST;
658
659 GST_START_TEST (test_vararg_getters)
660 {
661   GstStructure *s;
662   GstBuffer *buf, *buf2;
663   gboolean ret;
664   GstCaps *caps, *caps2;
665   GstMapInfo info;
666   gdouble d;
667   gint64 i64;
668   gchar *c;
669   gint i, num, denom;
670   guint8 *data;
671
672   buf = gst_buffer_new_and_alloc (3);
673
674   fail_unless (gst_buffer_map (buf, &info, GST_MAP_WRITE));
675   data = info.data;
676   data[0] = 0xf0;
677   data[1] = 0x66;
678   data[2] = 0x0d;
679   gst_buffer_unmap (buf, &info);
680
681   caps = gst_caps_new_empty_simple ("video/x-foo");
682
683   s = gst_structure_new ("test", "int", G_TYPE_INT, 12345678, "string",
684       G_TYPE_STRING, "Hello World!", "buf", GST_TYPE_BUFFER, buf, "caps",
685       GST_TYPE_CAPS, caps, "int64", G_TYPE_INT64, G_GINT64_CONSTANT (-99),
686       "double", G_TYPE_DOUBLE, G_MAXDOUBLE, "frag", GST_TYPE_FRACTION, 39, 14,
687       NULL);
688
689   /* first the plain one */
690   ret = gst_structure_get (s, "double", G_TYPE_DOUBLE, &d, "string",
691       G_TYPE_STRING, &c, "caps", GST_TYPE_CAPS, &caps2, "buf",
692       GST_TYPE_BUFFER, &buf2, "frag", GST_TYPE_FRACTION, &num, &denom, "int",
693       G_TYPE_INT, &i, "int64", G_TYPE_INT64, &i64, NULL);
694
695   fail_unless (ret);
696   fail_unless_equals_string (c, "Hello World!");
697   fail_unless_equals_int (i, 12345678);
698   fail_unless_equals_float (d, G_MAXDOUBLE);
699   fail_unless_equals_int (num, 39);
700   fail_unless_equals_int (denom, 14);
701   fail_unless (i64 == -99);
702   fail_unless (caps == caps2);
703   fail_unless (buf == buf2);
704
705   /* expected failures */
706   ASSERT_CRITICAL (gst_structure_get (s, NULL, G_TYPE_INT, &i, NULL));
707   fail_if (gst_structure_get (s, "int", G_TYPE_INT, &i, "double",
708           G_TYPE_FLOAT, &d, NULL));
709   fail_if (gst_structure_get (s, "int", G_TYPE_INT, &i, "dooble",
710           G_TYPE_DOUBLE, &d, NULL));
711
712   g_free (c);
713   c = NULL;
714   gst_caps_unref (caps2);
715   caps2 = NULL;
716   gst_buffer_unref (buf2);
717   buf2 = NULL;
718
719   /* and now the _id variant */
720   ret = gst_structure_id_get (s, g_quark_from_static_string ("double"),
721       G_TYPE_DOUBLE, &d, g_quark_from_static_string ("string"), G_TYPE_STRING,
722       &c, g_quark_from_static_string ("caps"), GST_TYPE_CAPS, &caps2,
723       g_quark_from_static_string ("buf"), GST_TYPE_BUFFER, &buf2,
724       g_quark_from_static_string ("int"), G_TYPE_INT, &i,
725       g_quark_from_static_string ("int64"), G_TYPE_INT64, &i64, NULL);
726
727   fail_unless (ret);
728   fail_unless_equals_string (c, "Hello World!");
729   fail_unless_equals_int (i, 12345678);
730   fail_unless_equals_float (d, G_MAXDOUBLE);
731   fail_unless (i64 == -99);
732   fail_unless (caps == caps2);
733   fail_unless (buf == buf2);
734
735   /* expected failures */
736   ASSERT_CRITICAL (gst_structure_get (s, 0, G_TYPE_INT, &i, NULL));
737   fail_if (gst_structure_id_get (s, g_quark_from_static_string ("int"),
738           G_TYPE_INT, &i, g_quark_from_static_string ("double"), G_TYPE_FLOAT,
739           &d, NULL));
740   fail_if (gst_structure_id_get (s, g_quark_from_static_string ("int"),
741           G_TYPE_INT, &i, g_quark_from_static_string ("dooble"), G_TYPE_DOUBLE,
742           &d, NULL));
743
744   g_free (c);
745   gst_caps_unref (caps2);
746   gst_buffer_unref (buf2);
747
748   /* finally make sure NULL as return location is handled gracefully */
749   ret = gst_structure_get (s, "double", G_TYPE_DOUBLE, NULL, "string",
750       G_TYPE_STRING, NULL, "caps", GST_TYPE_CAPS, NULL, "buf",
751       GST_TYPE_BUFFER, NULL, "int", G_TYPE_INT, &i, "frag", GST_TYPE_FRACTION,
752       NULL, NULL, "int64", G_TYPE_INT64, &i64, NULL);
753
754   ASSERT_WARNING (gst_structure_get (s, "frag", GST_TYPE_FRACTION, NULL,
755           &denom, NULL));
756   ASSERT_WARNING (gst_structure_get (s, "frag", GST_TYPE_FRACTION, &num,
757           NULL, NULL));
758
759   /* clean up */
760   gst_caps_unref (caps);
761   gst_buffer_unref (buf);
762   gst_structure_free (s);
763 }
764
765 GST_END_TEST;
766
767 static gboolean
768 foreach_func (GQuark field_id, const GValue * value, gpointer user_data)
769 {
770   gint *sum = user_data;
771   gint v = 0;
772
773   if (G_VALUE_HOLDS_INT (value))
774     v = g_value_get_int (value);
775   *sum += v;
776
777   return TRUE;
778 }
779
780 GST_START_TEST (test_foreach)
781 {
782   GstStructure *s;
783   gint sum = 0;
784
785   s = gst_structure_new ("foo/bar", "baz", G_TYPE_INT, 1, "bla", G_TYPE_INT, 3,
786       NULL);
787   fail_unless (gst_structure_foreach (s, foreach_func, &sum));
788   fail_unless_equals_int (sum, 4);
789   gst_structure_free (s);
790
791 }
792
793 GST_END_TEST;
794
795 static gboolean
796 map_func (GQuark field_id, GValue * value, gpointer user_data)
797 {
798   if (G_VALUE_HOLDS_INT (value))
799     g_value_set_int (value, 123);
800
801   return TRUE;
802 }
803
804 GST_START_TEST (test_map_in_place)
805 {
806   GstStructure *s, *s2;
807
808   s = gst_structure_new ("foo/bar", "baz", G_TYPE_INT, 1, "bla", G_TYPE_INT, 3,
809       NULL);
810   s2 = gst_structure_new ("foo/bar", "baz", G_TYPE_INT, 123, "bla", G_TYPE_INT,
811       123, NULL);
812   fail_unless (gst_structure_map_in_place (s, map_func, NULL));
813   fail_unless (gst_structure_is_equal (s, s2));
814   gst_structure_free (s);
815   gst_structure_free (s2);
816
817 }
818
819 GST_END_TEST;
820
821 static gboolean
822 filter_map_func (GQuark field_id, GValue * value, gpointer user_data)
823 {
824   if (strcmp (g_quark_to_string (field_id), "bla") == 0)
825     return FALSE;
826
827   if (G_VALUE_HOLDS_INT (value))
828     g_value_set_int (value, 2);
829
830   return TRUE;
831 }
832
833 GST_START_TEST (test_filter_and_map_in_place)
834 {
835   GstStructure *s, *s2;
836
837   s = gst_structure_new ("foo/bar", "baz", G_TYPE_INT, 1, "bla", G_TYPE_INT, 3,
838       NULL);
839   s2 = gst_structure_new ("foo/bar", "baz", G_TYPE_INT, 2, NULL);
840   gst_structure_filter_and_map_in_place (s, filter_map_func, NULL);
841   fail_unless (gst_structure_is_equal (s, s2));
842   gst_structure_free (s);
843   gst_structure_free (s2);
844 }
845
846 GST_END_TEST;
847
848 GST_START_TEST (test_flagset)
849 {
850   GstStructure *s;
851   GType test_flagset_type;
852   guint test_flags =
853       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP | GST_SEEK_FLAG_SNAP_AFTER;
854   guint test_mask = GST_FLAG_SET_MASK_EXACT;
855   guint out_flags, out_mask;
856
857   test_flagset_type = gst_flagset_register (GST_TYPE_SEEK_FLAGS);
858   fail_unless (g_type_is_a (test_flagset_type, GST_TYPE_FLAG_SET));
859
860   /* Check that we can retrieve a non-standard flagset from the structure */
861   s = gst_structure_new ("test-struct", "test-flagset", test_flagset_type,
862       test_flags, test_mask, NULL);
863   fail_unless (gst_structure_get_flagset (s, "test-flagset", &out_flags,
864           &out_mask));
865
866   fail_unless (out_flags == test_flags);
867   fail_unless (out_mask == test_mask);
868   gst_structure_free (s);
869 }
870
871 GST_END_TEST;
872
873 static Suite *
874 gst_structure_suite (void)
875 {
876   Suite *s = suite_create ("GstStructure");
877   TCase *tc_chain = tcase_create ("general");
878
879   suite_add_tcase (s, tc_chain);
880   tcase_add_test (tc_chain, test_from_string_int);
881   tcase_add_test (tc_chain, test_from_string_uint);
882   tcase_add_test (tc_chain, test_from_string);
883   tcase_add_test (tc_chain, test_to_string);
884   tcase_add_test (tc_chain, test_to_from_string);
885   tcase_add_test (tc_chain, test_to_from_string_tag_event);
886   tcase_add_test (tc_chain, test_string_properties);
887   tcase_add_test (tc_chain, test_complete_structure);
888   tcase_add_test (tc_chain, test_structure_new);
889   tcase_add_test (tc_chain, test_fixate);
890   tcase_add_test (tc_chain, test_fixate_frac_list);
891   tcase_add_test (tc_chain, test_is_subset_equal_array_list);
892   tcase_add_test (tc_chain, test_is_subset_different_name);
893   tcase_add_test (tc_chain, test_is_subset_superset_missing_fields);
894   tcase_add_test (tc_chain, test_is_subset_superset_extra_fields);
895   tcase_add_test (tc_chain, test_is_subset_superset_extra_values);
896   tcase_add_test (tc_chain, test_structure_nested);
897   tcase_add_test (tc_chain, test_structure_nested_from_and_to_string);
898   tcase_add_test (tc_chain, test_vararg_getters);
899   tcase_add_test (tc_chain, test_foreach);
900   tcase_add_test (tc_chain, test_map_in_place);
901   tcase_add_test (tc_chain, test_filter_and_map_in_place);
902   tcase_add_test (tc_chain, test_flagset);
903   return s;
904 }
905
906 GST_CHECK_MAIN (gst_structure);