check/: Added checks.
authorWim Taymans <wim.taymans@gmail.com>
Mon, 7 Mar 2005 18:33:37 +0000 (18:33 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Mon, 7 Mar 2005 18:33:37 +0000 (18:33 +0000)
Original commit message from CVS:
* check/.cvsignore:
* check/Makefile.am:
* check/gst-libs/.cvsignore:
* check/gst-libs/gdp.c: (START_TEST), (gst_object_suite), (main):
* check/gst/.cvsignore:
* check/gst/gstbus.c: (pound_bus_with_messages), (pull_messages),
(START_TEST), (gstbus_suite), (main):
* check/gst/gstcaps.c: (START_TEST), (gst_caps_suite), (main):
* check/gst/gstdata.c: (START_TEST), (thread_ref), (thread_unref),
(gst_data_suite), (main):
* check/gst/gstiterator.c: (make_list_of_ints), (START_TEST),
(add_fold_func), (gstiterator_suite), (main):
* check/gst/gstobject.c: (gst_fake_object_get_type), (START_TEST),
(thread_name_object), (thread_name_object_default),
(gst_object_name_compare), (gst_object_suite), (main):
* check/gst/gstpad.c: (START_TEST), (thread_link_unlink),
(gst_pad_suite), (main):
* check/gstcheck.c: (gst_check_log_message_func),
(gst_check_log_critical_func), (gst_check_init):
* check/gstcheck.h:
* check/pipelines/simple_launch_lines.c: (setup_pipeline),
(run_pipeline), (START_TEST), (simple_launch_lines_suite), (main):
Added checks.

29 files changed:
ChangeLog
check/.gitignore [new file with mode: 0644]
check/Makefile.am [new file with mode: 0644]
check/gst-libs/.gitignore [new file with mode: 0644]
check/gst-libs/gdp.c [new file with mode: 0644]
check/gst/.gitignore [new file with mode: 0644]
check/gst/gstbus.c [new file with mode: 0644]
check/gst/gstcaps.c [new file with mode: 0644]
check/gst/gstdata.c [new file with mode: 0644]
check/gst/gstiterator.c [new file with mode: 0644]
check/gst/gstobject.c [new file with mode: 0644]
check/gst/gstpad.c [new file with mode: 0644]
check/gstcheck.c [new file with mode: 0644]
check/gstcheck.h [new file with mode: 0644]
check/pipelines/simple_launch_lines.c [new file with mode: 0644]
tests/check/.gitignore [new file with mode: 0644]
tests/check/Makefile.am [new file with mode: 0644]
tests/check/gst/.gitignore [new file with mode: 0644]
tests/check/gst/gstbus.c [new file with mode: 0644]
tests/check/gst/gstcaps.c [new file with mode: 0644]
tests/check/gst/gstdata.c [new file with mode: 0644]
tests/check/gst/gstiterator.c [new file with mode: 0644]
tests/check/gst/gstobject.c [new file with mode: 0644]
tests/check/gst/gstpad.c [new file with mode: 0644]
tests/check/gstcheck.c [new file with mode: 0644]
tests/check/gstcheck.h [new file with mode: 0644]
tests/check/libs/.gitignore [new file with mode: 0644]
tests/check/libs/gdp.c [new file with mode: 0644]
tests/check/pipelines/simple-launch-lines.c [new file with mode: 0644]

index 026736d..313f327 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,31 @@
 2005-03-07  Wim Taymans  <wim@fluendo.com>
 
+       * check/.cvsignore:
+       * check/Makefile.am:
+       * check/gst-libs/.cvsignore:
+       * check/gst-libs/gdp.c: (START_TEST), (gst_object_suite), (main):
+       * check/gst/.cvsignore:
+       * check/gst/gstbus.c: (pound_bus_with_messages), (pull_messages),
+       (START_TEST), (gstbus_suite), (main):
+       * check/gst/gstcaps.c: (START_TEST), (gst_caps_suite), (main):
+       * check/gst/gstdata.c: (START_TEST), (thread_ref), (thread_unref),
+       (gst_data_suite), (main):
+       * check/gst/gstiterator.c: (make_list_of_ints), (START_TEST),
+       (add_fold_func), (gstiterator_suite), (main):
+       * check/gst/gstobject.c: (gst_fake_object_get_type), (START_TEST),
+       (thread_name_object), (thread_name_object_default),
+       (gst_object_name_compare), (gst_object_suite), (main):
+       * check/gst/gstpad.c: (START_TEST), (thread_link_unlink),
+       (gst_pad_suite), (main):
+       * check/gstcheck.c: (gst_check_log_message_func),
+       (gst_check_log_critical_func), (gst_check_init):
+       * check/gstcheck.h:
+       * check/pipelines/simple_launch_lines.c: (setup_pipeline),
+       (run_pipeline), (START_TEST), (simple_launch_lines_suite), (main):
+       Added checks.
+
+2005-03-07  Wim Taymans  <wim@fluendo.com>
+
        * gst/gstiterator.c: (gst_iterator_init), (gst_iterator_new),
        (gst_list_iterator_next), (gst_list_iterator_resync),
        (gst_list_iterator_free), (gst_iterator_new_list),
diff --git a/check/.gitignore b/check/.gitignore
new file mode 100644 (file)
index 0000000..5d45c6c
--- /dev/null
@@ -0,0 +1 @@
+test-registry.xml
diff --git a/check/Makefile.am b/check/Makefile.am
new file mode 100644 (file)
index 0000000..47208ce
--- /dev/null
@@ -0,0 +1,43 @@
+TESTS_ENVIRONMENT=\
+       GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/check \
+       GST_REGISTRY=$(top_builddir)/check/test-registry.xml
+
+plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
+
+# make all tests depend on the versioned gst-register
+$(TESTS): $(top_builddir)/tools/gst-register-@GST_MAJORMINOR@
+
+# rebuild gst-register-@GST_MAJORMINOR@ if needed
+$(top_builddir)/tools/gst-register-@GST_MAJORMINOR@:
+       cd $(top_builddir)/tools && make
+
+# override to _not_ install the test plugins
+install-pluginLTLIBRARIES:
+
+# This rule is here so make distcheck works on machines where core
+# dumps have PIDs appended
+CLEANFILES = core.*
+
+TESTS = $(top_builddir)/tools/gst-register-@GST_MAJORMINOR@ \
+       gst/gstcaps     \
+       gst/gstdata     \
+       gst/gstiterator \
+       gst/gstobject   \
+       gst-libs/gdp    
+
+check_PROGRAMS = $(TESTS)
+
+noinst_LTLIBRARIES = libgstcheck.la
+
+libgstcheck_la_SOURCES = gstcheck.c
+libgstcheck_la_LIBADD = $(GST_OBJ_LIBS)
+noinst_HEADERS = gstcheck.h
+
+AM_CFLAGS = $(GST_OBJ_CFLAGS) $(CHECK_CFLAGS)
+LDADD = $(GST_OBJ_LIBS) $(CHECK_LIBS) libgstcheck.la
+
+gst_libs_gdp_SOURCES = \
+       gst-libs/gdp.c \
+       $(top_srcdir)/libs/gst/dataprotocol/dataprotocol.c
+# remove GST_ENABLE_NEW when dataprotocol has been declared API-stable
+gst_libs_gdp_CFLAGS = $(AM_CFLAGS) -DGST_ENABLE_NEW
diff --git a/check/gst-libs/.gitignore b/check/gst-libs/.gitignore
new file mode 100644 (file)
index 0000000..5ad589e
--- /dev/null
@@ -0,0 +1 @@
+gdp
diff --git a/check/gst-libs/gdp.c b/check/gst-libs/gdp.c
new file mode 100644 (file)
index 0000000..df79c8d
--- /dev/null
@@ -0,0 +1,277 @@
+/* GStreamer
+ *
+ * unit test for data protocol
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../gstcheck.h"
+
+#include <gst/dataprotocol/dataprotocol.h>
+#include "libs/gst/dataprotocol/dp-private.h"   /* private header */
+
+/* test our method of reading and writing headers using TO/FROM_BE */
+START_TEST (test_conversion)
+{
+  guint8 array[9];
+  guint8 write_array[9];
+  guint16 read_two, expect_two;
+  guint32 read_four, expect_four;
+  guint64 read_eight, expect_eight;
+  int i;
+
+  for (i = 0; i < 9; ++i) {
+    array[i] = i * 0x10;
+  }
+
+  /* read 8 16 bits */
+  for (i = 0; i < 8; ++i) {
+    read_two = GST_READ_UINT16_BE (array + i);
+    expect_two = array[i] * (1 << 8) + array[i + 1];
+    fail_unless (read_two == expect_two,
+        "GST_READ_UINT16_BE %d: read %d != %d\n", i, read_two, expect_two);
+  }
+
+  /* write 8 16 bits */
+  for (i = 0; i < 8; ++i) {
+    GST_WRITE_UINT16_BE (&write_array[i], read_two);
+    fail_unless (memcmp (array + 7, write_array + i, 2) == 0,
+        "GST_WRITE_UINT16_BE %d: memcmp failed", i);
+  }
+
+  /* read 5 32 bits */
+  for (i = 0; i < 5; ++i) {
+    read_four = GST_READ_UINT32_BE (array + i);
+    expect_four = array[i] * (1 << 24) + array[i + 1] * (1 << 16)
+        + array[i + 2] * (1 << 8) + array[i + 3];
+    fail_unless (read_four == expect_four,
+        "GST_READ_UINT32_BE %d: read %d != %d\n", i, read_four, expect_four);
+  }
+
+  /* read 2 64 bits */
+  for (i = 0; i < 2; ++i) {
+    read_eight = GST_READ_UINT64_BE (array + i);
+    expect_eight = array[i] * (1LL << 56) + array[i + 1] * (1LL << 48)
+        + array[i + 2] * (1LL << 40) + array[i + 3] * (1LL << 32)
+        + array[i + 4] * (1 << 24) + array[i + 5] * (1 << 16)
+        + array[i + 6] * (1 << 8) + array[i + 7];
+    fail_unless (read_eight == expect_eight,
+        "GST_READ_UINT64_BE %d: read %" G_GUINT64_FORMAT
+        " != %" G_GUINT64_FORMAT "\n", i, read_eight, expect_eight);
+  }
+
+  /* write 1 64 bit */
+  GST_WRITE_UINT64_BE (&write_array[0], read_eight);
+  fail_unless (memcmp (array + 1, write_array, 8) == 0,
+      "GST_WRITE_UINT64_BE: memcmp failed");
+}
+
+END_TEST
+/* test creation of header from buffer and back again */
+START_TEST (test_buffer)
+{
+  GstBuffer *buffer;
+  GstBuffer *newbuffer;
+
+  guint header_length;
+  guint8 *header;
+
+  /* create buffer */
+  g_message ("Creating a new 8-byte buffer with ts 0.5 sec, dur 1 sec\n");
+  buffer = gst_buffer_new_and_alloc (8);
+  GST_BUFFER_TIMESTAMP (buffer) = (GstClockTime) (GST_SECOND * 0.5);
+  GST_BUFFER_DURATION (buffer) = (GstClockTime) GST_SECOND;
+  GST_BUFFER_OFFSET (buffer) = (guint64) 10;
+  GST_BUFFER_OFFSET_END (buffer) = (guint64) 19;
+  GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_IN_CAPS);
+  GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_SUBBUFFER);
+  memmove (GST_BUFFER_DATA (buffer), "a buffer", 8);
+
+  /* create a buffer with CRC checking */
+  fail_unless (gst_dp_header_from_buffer (buffer, GST_DP_HEADER_FLAG_CRC,
+          &header_length, &header), "Could not create header from buffer.");
+
+  /* validate the header */
+  fail_unless (gst_dp_validate_header (header_length, header),
+      "Could not validate header");
+  /* create a new, empty buffer with the right size */
+  newbuffer = gst_dp_buffer_from_header (header_length, header);
+  fail_unless (newbuffer != NULL, "Could not create a new buffer from header");
+  fail_unless (GST_IS_BUFFER (newbuffer), "Created buffer is not a GstBuffer");
+  /* read/copy the data */
+  memmove (GST_BUFFER_DATA (newbuffer), GST_BUFFER_DATA (buffer),
+      GST_BUFFER_SIZE (buffer));
+  /* validate the buffer */
+  fail_unless (gst_dp_validate_payload (header_length, header,
+          GST_BUFFER_DATA (newbuffer)), "Could not validate payload");
+
+  g_message ("new buffer timestamp: %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (newbuffer)));
+  g_message ("new buffer duration: %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_BUFFER_DURATION (newbuffer)));
+  g_message ("new buffer offset: %" G_GUINT64_FORMAT "\n",
+      GST_BUFFER_OFFSET (newbuffer));
+  g_message ("new buffer offset_end: %" G_GUINT64_FORMAT "\n",
+      GST_BUFFER_OFFSET_END (newbuffer));
+  fail_unless (GST_BUFFER_TIMESTAMP (newbuffer) ==
+      GST_BUFFER_TIMESTAMP (buffer), "Timestamps don't match !");
+  fail_unless (GST_BUFFER_DURATION (newbuffer) == GST_BUFFER_DURATION (buffer),
+      "Durations don't match !");
+  fail_unless (GST_BUFFER_OFFSET (newbuffer) == GST_BUFFER_OFFSET (buffer),
+      "Offsets don't match !");
+  fail_unless (GST_BUFFER_OFFSET_END (newbuffer) ==
+      GST_BUFFER_OFFSET_END (buffer), "Offset ends don't match !");
+  fail_if (GST_BUFFER_FLAG_IS_SET (newbuffer, GST_BUFFER_SUBBUFFER),
+      "GST_BUFFER_SUBBUFFER flag should not have been copied !");
+  fail_unless (GST_BUFFER_FLAG_IS_SET (newbuffer, GST_BUFFER_IN_CAPS),
+      "GST_BUFFER_IN_CAPS flag should have been copied !");
+
+  g_free (header);
+}
+
+END_TEST
+START_TEST (test_caps)
+{
+  gchar *string, *newstring;
+  GstCaps *caps, *newcaps;
+
+  guint header_length;
+  guint8 *header, *payload;
+
+  caps = gst_caps_from_string ("audio/x-raw-float, "
+      "rate = (int) [ 11025, 48000 ], "
+      "channels = (int) [ 1, 2 ], " "endianness = (int) BYTE_ORDER, "
+      "width = (int) 32, " "buffer-frames = (int) 0");
+  string = gst_caps_to_string (caps);
+  g_message ("Created caps: %s\n", string);
+  fail_unless (gst_dp_packet_from_caps (caps, 0, &header_length, &header,
+          &payload), "Could not create packet from caps.");
+
+  /* validate the packet */
+  fail_unless (gst_dp_validate_packet (header_length, header, payload),
+      "Could not validate packet");
+  newcaps = gst_dp_caps_from_packet (header_length, header, payload);
+  fail_unless (newcaps != NULL, "Could not create caps from packet");
+  //g_return_val_if_fail (GST_IS_CAPS (newcaps), -1);
+  newstring = gst_caps_to_string (newcaps);
+  g_message ("Received caps: %s\n", newstring);
+  fail_unless (strcmp (string, newstring) == 0,
+      "Created caps do not match original caps");
+  g_free (string);
+  g_free (newstring);
+}
+
+END_TEST
+START_TEST (test_event)
+{
+  GstEvent *send;
+  GstEvent *receive;
+  guint header_length;
+  guint8 *header, *payload;
+
+  g_message ("Testing EOS event at 1s\n");
+  send = gst_event_new (GST_EVENT_EOS);
+  GST_EVENT_TIMESTAMP (send) = GST_SECOND;
+  fail_unless (gst_dp_packet_from_event (send, GST_DP_HEADER_FLAG_CRC,
+          &header_length, &header, &payload),
+      "Could not create packet from eos event");
+
+  receive = gst_dp_event_from_packet (header_length, header, payload);
+
+  g_message ("EOS, timestamp %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_EVENT_TIMESTAMP (receive)));
+  fail_unless (GST_EVENT_TYPE (receive) == GST_EVENT_EOS,
+      "Received event is not EOS");
+  fail_unless (GST_EVENT_TIMESTAMP (receive) == GST_SECOND,
+      "EOS timestamp is not 1.0 sec");
+  gst_event_unref (send);
+  gst_event_unref (receive);
+
+  g_message ("Testing FLUSH event at 2s\n");
+  send = gst_event_new (GST_EVENT_FLUSH);
+  GST_EVENT_TIMESTAMP (send) = GST_SECOND * 2;
+  fail_unless (gst_dp_packet_from_event (send, GST_DP_HEADER_FLAG_CRC,
+          &header_length, &header, &payload),
+      "Could not create packet from flush event");
+
+  receive = gst_dp_event_from_packet (header_length, header, payload);
+
+  g_message ("Flush, timestamp %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_EVENT_TIMESTAMP (receive)));
+  fail_unless (GST_EVENT_TYPE (receive) == GST_EVENT_FLUSH,
+      "Received event is not flush");
+  fail_unless (GST_EVENT_TIMESTAMP (receive) == GST_SECOND * 2,
+      "Flush timestamp is not 2.0 sec");
+  gst_event_unref (send);
+  gst_event_unref (receive);
+
+  g_message ("Testing SEEK event with 1 second at 3 seconds\n");
+  send = gst_event_new_seek (GST_FORMAT_TIME, GST_SECOND);
+  GST_EVENT_TIMESTAMP (send) = GST_SECOND * 3;
+  fail_unless (gst_dp_packet_from_event (send, GST_DP_HEADER_FLAG_CRC,
+          &header_length, &header, &payload),
+      "Could not create packet from seek event");
+
+  receive = gst_dp_event_from_packet (header_length, header, payload);
+
+  g_message ("Seek, timestamp %" GST_TIME_FORMAT ", to %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_EVENT_TIMESTAMP (receive)),
+      GST_TIME_ARGS (GST_EVENT_SEEK_OFFSET (receive)));
+  fail_unless (GST_EVENT_TYPE (receive) == GST_EVENT_SEEK,
+      "Returned event is not seek");
+  fail_unless (GST_EVENT_TIMESTAMP (receive) == GST_SECOND * 3,
+      "Seek timestamp is not 3.0 sec");
+  fail_unless (GST_EVENT_SEEK_FORMAT (receive) == GST_FORMAT_TIME,
+      "Seek format is not time");
+  fail_unless (GST_EVENT_SEEK_OFFSET (receive) == GST_SECOND,
+      "Seek offset is not 1.0 sec");
+  gst_event_unref (send);
+  gst_event_unref (receive);
+}
+END_TEST Suite *
+gst_object_suite (void)
+{
+  Suite *s = suite_create ("data protocol");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_conversion);
+  tcase_add_test (tc_chain, test_buffer);
+  tcase_add_test (tc_chain, test_caps);
+  tcase_add_test (tc_chain, test_event);
+
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_object_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+  gst_dp_init ();
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/check/gst/.gitignore b/check/gst/.gitignore
new file mode 100644 (file)
index 0000000..4693cc3
--- /dev/null
@@ -0,0 +1,3 @@
+gstobject
+gstcaps
+gstdata
diff --git a/check/gst/gstbus.c b/check/gst/gstbus.c
new file mode 100644 (file)
index 0000000..9d28bc9
--- /dev/null
@@ -0,0 +1,130 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * gstbus.c: Unit test for the message bus
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "../gstcheck.h"
+
+
+static GstBus *test_bus = NULL;
+
+#define NUM_MESSAGES 1000
+#define NUM_THREADS 10
+
+static gpointer
+pound_bus_with_messages (gpointer data)
+{
+  gint thread_id = GPOINTER_TO_INT (data);
+  gint i;
+
+  for (i = 0; i < NUM_MESSAGES; i++) {
+    GstMessage *m;
+    GstStructure *s;
+
+    s = gst_structure_new ("test_message",
+        "thread_id", G_TYPE_INT, thread_id, "msg_id", G_TYPE_INT, i, NULL);
+    m = gst_message_new_application (s);
+    gst_bus_post (test_bus, m);
+  }
+  return NULL;
+}
+
+static void
+pull_messages ()
+{
+  GstMessage *m;
+  const GstStructure *s;
+  guint message_ids[NUM_THREADS];
+  gint i;
+
+  for (i = 0; i < NUM_THREADS; i++)
+    message_ids[i] = 0;
+
+  while (1) {
+    gint _t, _i;
+
+    m = gst_bus_pop (test_bus);
+    if (!m)
+      break;
+    g_return_if_fail (GST_MESSAGE_TYPE (m) == GST_MESSAGE_APPLICATION);
+
+    s = gst_message_get_structure (m);
+    if (!gst_structure_get_int (s, "thread_id", &_t))
+      g_critical ("Invalid message");
+    if (!gst_structure_get_int (s, "msg_id", &_i))
+      g_critical ("Invalid message");
+
+    g_return_if_fail (_t < NUM_THREADS);
+    g_return_if_fail (_i == message_ids[_t]++);
+
+    gst_message_unref (m);
+  }
+
+  for (i = 0; i < NUM_THREADS; i++)
+    g_return_if_fail (message_ids[i] == NUM_MESSAGES);
+}
+
+START_TEST (test_hammer_bus)
+{
+  GThread *threads[NUM_THREADS];
+  gint i;
+
+  test_bus = gst_bus_new ();
+
+  for (i = 0; i < NUM_THREADS; i++)
+    threads[i] = g_thread_create (pound_bus_with_messages, GINT_TO_POINTER (i),
+        TRUE, NULL);
+
+  for (i = 0; i < NUM_THREADS; i++)
+    g_thread_join (threads[i]);
+
+  pull_messages ();
+
+  gst_object_unref ((GstObject *) test_bus);
+}
+END_TEST Suite *
+gstbus_suite (void)
+{
+  Suite *s = suite_create ("GstBus");
+  TCase *tc_chain = tcase_create ("stresstest");
+
+  tcase_set_timeout (tc_chain, 0);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_hammer_bus);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gstbus_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/check/gst/gstcaps.c b/check/gst/gstcaps.c
new file mode 100644 (file)
index 0000000..4eefe72
--- /dev/null
@@ -0,0 +1,91 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * gstcaps.c: Unit test for GstCaps
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "../gstcheck.h"
+
+
+START_TEST (test_double_append)
+{
+  GstStructure *s1;
+  GstCaps *c1;
+
+  c1 = gst_caps_new_any ();
+  s1 = gst_structure_from_string ("audio/x-raw-int,rate=44100", NULL);
+  gst_caps_append_structure (c1, s1);
+  ASSERT_CRITICAL (gst_caps_append_structure (c1, s1));
+}
+
+END_TEST
+START_TEST (test_mutability)
+{
+  GstStructure *s1;
+  GstCaps *c1;
+  gint ret;
+
+  c1 = gst_caps_new_any ();
+  s1 = gst_structure_from_string ("audio/x-raw-int,rate=44100", NULL);
+  gst_structure_set (s1, "rate", G_TYPE_INT, 48000, NULL);
+  gst_caps_append_structure (c1, s1);
+  gst_structure_set (s1, "rate", G_TYPE_INT, 22500, NULL);
+  gst_caps_ref (c1);
+  ASSERT_CRITICAL (gst_structure_set (s1, "rate", G_TYPE_INT, 11250, NULL));
+  fail_unless (gst_structure_get_int (s1, "rate", &ret));
+  fail_unless (ret == 22500);
+  ASSERT_CRITICAL (gst_caps_set_simple (c1, "rate", G_TYPE_INT, 11250, NULL));
+  fail_unless (gst_structure_get_int (s1, "rate", &ret));
+  fail_unless (ret == 22500);
+  gst_caps_unref (c1);
+  gst_structure_set (s1, "rate", G_TYPE_INT, 11250, NULL);
+  fail_unless (gst_structure_get_int (s1, "rate", &ret));
+  fail_unless (ret == 11250);
+  gst_caps_set_simple (c1, "rate", G_TYPE_INT, 1, NULL);
+  fail_unless (gst_structure_get_int (s1, "rate", &ret));
+  fail_unless (ret == 1);
+}
+END_TEST Suite *
+gst_caps_suite (void)
+{
+  Suite *s = suite_create ("GstCaps");
+  TCase *tc_chain = tcase_create ("mutability");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_double_append);
+  tcase_add_test (tc_chain, test_mutability);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_caps_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/check/gst/gstdata.c b/check/gst/gstdata.c
new file mode 100644 (file)
index 0000000..59c931e
--- /dev/null
@@ -0,0 +1,196 @@
+/* GStreamer
+ *
+ * unit test for GstData
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../gstcheck.h"
+
+START_TEST (test_copy)
+{
+  GstBuffer *buffer, *copy;
+
+  buffer = gst_buffer_new_and_alloc (4);
+
+  copy = GST_BUFFER (gst_data_copy (GST_DATA (buffer)));
+
+  fail_if (copy == NULL, "Copy of buffer returned NULL");
+  fail_unless (GST_BUFFER_SIZE (copy) == 4,
+      "Copy of buffer has different size");
+}
+
+END_TEST
+START_TEST (test_is_writable)
+{
+  GstBuffer *buffer;
+  GstData *data;
+
+  buffer = gst_buffer_new_and_alloc (4);
+  data = GST_DATA (buffer);
+
+  fail_unless (gst_data_is_writable (data),
+      "A buffer with one ref should be writable");
+
+  GST_DATA_FLAG_SET (data, GST_DATA_READONLY);
+  fail_if (gst_data_is_writable (data),
+      "A buffer with READONLY set should not be writable");
+  GST_DATA_FLAG_UNSET (data, GST_DATA_READONLY);
+  fail_unless (gst_data_is_writable (data),
+      "A buffer with one ref and READONLY not set should be writable");
+
+  fail_if (gst_data_ref (data) == NULL, "Could not ref the data");
+
+  fail_if (gst_data_is_writable (data),
+      "A buffer with two refs should not be writable");
+}
+
+END_TEST
+START_TEST (test_copy_on_write)
+{
+  GstBuffer *buffer;
+  GstData *data, *data2, *data3;
+
+  buffer = gst_buffer_new_and_alloc (4);
+  data = GST_DATA (buffer);
+
+  data2 = gst_data_copy_on_write (data);
+  fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer");
+  fail_unless (data == data2,
+      "copy_on_write returned a copy for a buffer with refcount 1");
+
+  data2 = gst_data_ref (data);
+  data3 = gst_data_copy_on_write (data);
+  fail_unless (GST_IS_BUFFER (data3), "copy_on_write did not return a buffer");
+  fail_if (data == data3,
+      "copy_on_write returned same object for a buffer with refcount > 1");
+
+  fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1,
+      "refcount of original data object should be back to 1");
+
+  data2 = gst_data_copy_on_write (data);
+  fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer");
+  fail_unless (data == data2,
+      "copy_on_write returned a copy for a buffer with refcount 1");
+
+}
+
+END_TEST gint num_threads = 10;
+gint refs_per_thread = 10000;
+
+/* test thread-safe refcounting of GstData */
+void
+thread_ref (GstData * data)
+{
+  int j;
+
+  THREAD_START ();
+
+  for (j = 0; j < refs_per_thread; ++j) {
+    fail_if (gst_data_ref (data) == NULL, "Could not ref data from thread");
+
+    if (j % num_threads == 0)
+      THREAD_SWITCH ();
+  }
+}
+
+START_TEST (test_ref_threaded)
+{
+  GstBuffer *buffer;
+  GstData *data;
+  gint expected;
+
+  buffer = gst_buffer_new_and_alloc (4);
+
+  data = GST_DATA (buffer);
+
+  MAIN_START_THREADS (num_threads, thread_ref, data);
+
+  MAIN_STOP_THREADS ();
+
+  expected = num_threads * refs_per_thread + 1;
+  fail_unless (GST_DATA_REFCOUNT_VALUE (data) == expected,
+      "Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), expected);
+}
+END_TEST void
+thread_unref (GstData * data)
+{
+  int j;
+
+  THREAD_START ();
+
+  for (j = 0; j < refs_per_thread; ++j) {
+    gst_data_unref (data);
+
+    if (j % num_threads == 0)
+      THREAD_SWITCH ();
+  }
+}
+
+START_TEST (test_unref_threaded)
+{
+  GstBuffer *buffer;
+  GstData *data;
+
+  buffer = gst_buffer_new_and_alloc (4);
+
+  data = GST_DATA (buffer);
+
+  gst_data_ref_by_count (data, num_threads * refs_per_thread);
+
+  MAIN_START_THREADS (num_threads, thread_unref, data);
+
+  MAIN_STOP_THREADS ();
+
+  fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1,
+      "Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), 1);
+
+  /* final unref */
+  gst_data_unref (data);
+}
+END_TEST Suite *
+gst_data_suite (void)
+{
+  Suite *s = suite_create ("GstData");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_copy);
+  tcase_add_test (tc_chain, test_is_writable);
+  tcase_add_test (tc_chain, test_copy_on_write);
+  tcase_add_test (tc_chain, test_ref_threaded);
+  tcase_add_test (tc_chain, test_unref_threaded);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_data_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/check/gst/gstiterator.c b/check/gst/gstiterator.c
new file mode 100644 (file)
index 0000000..aa9a27e
--- /dev/null
@@ -0,0 +1,182 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * gstiterator.c: Unit test for iterators
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "../gstcheck.h"
+
+
+static GList *
+make_list_of_ints (gint n)
+{
+  GList *ret = NULL;
+  gint i;
+
+  for (i = 0; i < n; i++)
+    ret = g_list_prepend (ret, GINT_TO_POINTER (i));
+
+  return g_list_reverse (ret);
+}
+
+#define NUM_ELEMENTS 10
+
+START_TEST (test_manual_iteration)
+{
+  GList *l;
+  guint32 cookie = 0;
+  GMutex *m;
+  GstIterator *iter;
+  GstIteratorResult res;
+  gpointer item;
+  gint i = 0;
+
+  l = make_list_of_ints (NUM_ELEMENTS);
+  m = g_mutex_new ();
+
+  iter = gst_iterator_new_list (m, &cookie, &l, NULL, NULL, NULL);
+
+  g_return_if_fail (iter != NULL);
+
+  while (1) {
+    res = gst_iterator_next (iter, &item);
+    if (i < NUM_ELEMENTS) {
+      g_return_if_fail (res == GST_ITERATOR_OK);
+      g_return_if_fail (GPOINTER_TO_INT (item) == i);
+      i++;
+      continue;
+    } else {
+      g_return_if_fail (res == GST_ITERATOR_DONE);
+      break;
+    }
+  }
+
+  gst_iterator_free (iter);
+}
+
+END_TEST
+START_TEST (test_resync)
+{
+  GList *l;
+  guint32 cookie = 0;
+  GMutex *m;
+  GstIterator *iter;
+  GstIteratorResult res;
+  gpointer item;
+  gint i = 0;
+  gboolean hacked_list = FALSE;
+
+  l = make_list_of_ints (NUM_ELEMENTS);
+  m = g_mutex_new ();
+
+  iter = gst_iterator_new_list (m, &cookie, &l, NULL, NULL, NULL);
+
+  g_return_if_fail (iter != NULL);
+
+  while (1) {
+    res = gst_iterator_next (iter, &item);
+    if (i < NUM_ELEMENTS / 2) {
+      g_return_if_fail (res == GST_ITERATOR_OK);
+      g_return_if_fail (GPOINTER_TO_INT (item) == i);
+      i++;
+      continue;
+    } else if (!hacked_list) {
+      /* here's where we test resync */
+      g_return_if_fail (res == GST_ITERATOR_OK);
+      l = g_list_prepend (l, GINT_TO_POINTER (-1));
+      cookie++;
+      hacked_list = TRUE;
+      continue;
+    } else {
+      g_return_if_fail (res == GST_ITERATOR_RESYNC);
+      gst_iterator_resync (iter);
+      res = gst_iterator_next (iter, &item);
+      g_return_if_fail (res == GST_ITERATOR_OK);
+      g_return_if_fail (GPOINTER_TO_INT (item) == -1);
+      break;
+    }
+  }
+
+  gst_iterator_free (iter);
+}
+END_TEST static gboolean
+add_fold_func (gpointer item, GValue * ret, gpointer user_data)
+{
+  g_value_set_int (ret, g_value_get_int (ret) + GPOINTER_TO_INT (item));
+  return TRUE;
+}
+
+START_TEST (test_fold)
+{
+  GList *l;
+  guint32 cookie = 0;
+  GMutex *m;
+  GstIterator *iter;
+  GstIteratorResult res;
+  gint i, expected;
+  GValue ret = { 0, };
+
+  l = make_list_of_ints (NUM_ELEMENTS);
+  m = g_mutex_new ();
+  iter = gst_iterator_new_list (m, &cookie, &l, NULL, NULL, NULL);
+  g_return_if_fail (iter != NULL);
+
+  expected = 0;
+  for (i = 0; i < NUM_ELEMENTS; i++)
+    expected += i;
+
+  g_value_init (&ret, G_TYPE_INT);
+  g_value_set_int (&ret, 0);
+
+  res = gst_iterator_fold (iter, add_fold_func, &ret, NULL);
+
+  g_return_if_fail (res == GST_ITERATOR_DONE);
+  g_return_if_fail (g_value_get_int (&ret) == expected);
+}
+END_TEST Suite *
+gstiterator_suite (void)
+{
+  Suite *s = suite_create ("GstIterator");
+  TCase *tc_chain = tcase_create ("correctness");
+
+  tcase_set_timeout (tc_chain, 0);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_manual_iteration);
+  tcase_add_test (tc_chain, test_resync);
+  tcase_add_test (tc_chain, test_fold);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gstiterator_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/check/gst/gstobject.c b/check/gst/gstobject.c
new file mode 100644 (file)
index 0000000..52f92e9
--- /dev/null
@@ -0,0 +1,364 @@
+/* GStreamer
+ *
+ * unit test for GstObject
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../gstcheck.h"
+
+/*
+  Create a fake subclass
+ */
+typedef struct _GstFakeObjectClass GstFakeObjectClass;
+typedef struct _GstFakeObject GstFakeObject;
+
+struct _GstFakeObject
+{
+  GstObject object;
+};
+
+struct _GstFakeObjectClass
+{
+  GstObjectClass parent_class;
+};
+
+GType _gst_fake_object_type = 0;
+
+//static GstObjectClass *parent_class = NULL;
+//static guint gst_fake_object_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_fake_object_get_type (void)
+{
+  if (!_gst_fake_object_type) {
+    static const GTypeInfo fake_object_info = {
+      sizeof (GstFakeObjectClass),
+      NULL,                     //gst_fake_object_base_class_init,
+      NULL,                     //gst_fake_object_base_class_finalize,
+      NULL,                     //(GClassInitFunc) gst_fake_object_class_init,
+      NULL,
+      NULL,
+      sizeof (GstFakeObject),
+      0,
+      NULL,                     //(GInstanceInitFunc) gst_fake_object_init,
+      NULL
+    };
+
+    _gst_fake_object_type = g_type_register_static (GST_TYPE_OBJECT,
+        "GstFakeObject", &fake_object_info, 0);
+  }
+  return _gst_fake_object_type;
+}
+
+/* g_object_new on abstract GstObject should fail */
+START_TEST (test_fail_abstract_new)
+{
+  GstObject *object;
+
+  ASSERT_CRITICAL (object = g_object_new (gst_object_get_type (), NULL));
+  fail_unless (object == NULL, "Created an instance of abstract GstObject");
+}
+
+END_TEST
+/* g_object_new on GstFakeObject should succeed */
+START_TEST (test_fake_object_new)
+{
+  GstObject *object;
+
+  object = g_object_new (gst_fake_object_get_type (), NULL);
+  fail_if (object == NULL, "Failed to create instance of GstFakeObject");
+  fail_unless (GST_IS_OBJECT (object),
+      "GstFakeObject instance is not a GstObject");
+}
+
+END_TEST
+/* GstFakeObject name tests */
+START_TEST (test_fake_object_name)
+{
+  GstObject *object;
+  gchar *name;
+  gchar *name2;
+
+  object = g_object_new (gst_fake_object_get_type (), NULL);
+
+  name = gst_object_get_name (object);
+  fail_if (name == NULL, "Newly created object has no name");
+  fail_if (strncmp (name, "fakeobject", 10) != 0,
+      "Random name %s does not start with Gst", name);
+
+  /* give a random name by setting with NULL;
+   * GstFakeObject class -> fakeobject%d */
+  gst_object_set_name (object, NULL);
+  name = gst_object_get_name (object);
+  fail_if (name == NULL, "Random name was not assigned");
+  fail_if (strncmp (name, "fakeobject", 10) != 0,
+      "Random name %s does not start with Gst", name);
+  g_free (name);
+
+  gst_object_set_name (object, "fake");
+  name = gst_object_get_name (object);
+  fail_if (name == NULL, "Failed to get name of GstFakeObject");
+  fail_if (strcmp (name, "fake") != 0, "Name of GstFakeObject is not 'fake'");
+
+  /* change the gotten name to see that it's a copy and not the original */
+  name[0] = 'm';
+  name2 = gst_object_get_name (object);
+  fail_if (strcmp (name2, "fake") != 0,
+      "Copy of object name affected actual object name");
+  g_free (name);
+  g_free (name2);
+}
+
+END_TEST
+/* thread function for threaded name change test */
+    gpointer thread_name_object (GstObject * object)
+{
+  gchar *thread_id = g_strdup_printf ("%p", g_thread_self ());
+
+  THREAD_START ();
+
+  /* give main thread a head start */
+  g_usleep (100000);
+
+  /* write our name repeatedly */
+  g_message ("THREAD %s: starting loop\n", thread_id);
+  while (THREAD_TEST_RUNNING ()) {
+    gst_object_set_name (object, thread_id);
+    /* a minimal sleep invokes a thread switch */
+    THREAD_SWITCH ();
+  }
+
+  /* thread is done, so let's return */
+  g_message ("THREAD %s: set name\n", thread_id);
+  g_free (thread_id);
+
+  return NULL;
+}
+
+/*
+ * main thread sets and gets name while other threads set the name
+ * constantly; fails because lock is released inbetween set and get
+ */
+
+START_TEST (test_fake_object_name_threaded_wrong)
+{
+  GstObject *object;
+  gchar *name;
+  gint i;
+  gboolean expected_failure = FALSE;
+
+  g_message ("\nTEST: set/get without lock\n");
+
+  object = g_object_new (gst_fake_object_get_type (), NULL);
+  gst_object_set_name (object, "main");
+
+  MAIN_START_THREADS (5, thread_name_object, object);
+
+  /* start looping and set/get name repeatedly */
+  for (i = 0; i < 1000; ++i) {
+    gst_object_set_name (object, "main");
+    THREAD_SWITCH ();
+    name = gst_object_get_name (object);
+    if (strcmp (name, "main") != 0) {
+      g_message ("MAIN: expected failure during run %d\n", i);
+      expected_failure = TRUE;
+      g_free (name);
+      break;
+    }
+    g_free (name);
+  }
+  MAIN_STOP_THREADS ();
+
+  fail_unless (expected_failure, "name did not get changed");
+}
+
+END_TEST
+/*
+ * main thread sets and gets name directly on struct inside the object lock
+ * succeed because lock is held during set/get, and threads are locked out
+ */
+START_TEST (test_fake_object_name_threaded_right)
+{
+  GstObject *object;
+  gchar *name;
+  gint i;
+
+  g_message ("\nTEST: set/get inside lock\n");
+
+  object = g_object_new (gst_fake_object_get_type (), NULL);
+  gst_object_set_name (object, "main");
+
+  MAIN_START_THREADS (5, thread_name_object, object);
+
+  /* start looping and set/get name repeatedly */
+  for (i = 0; i < 1000; ++i) {
+    GST_LOCK (object);
+    g_free (GST_OBJECT_NAME (object));
+    GST_OBJECT_NAME (object) = g_strdup ("main");
+    THREAD_SWITCH ();
+    name = g_strdup (GST_OBJECT_NAME (object));
+    GST_UNLOCK (object);
+
+    fail_unless (strcmp (name, "main") == 0,
+        "Name got changed while lock held during run %d", i);
+    g_free (name);
+  }
+  MAIN_STOP_THREADS ();
+}
+
+END_TEST
+/*
+ * main thread creates lots of objects
+ * child threads sets default names on objects
+ * then main thread checks uniqueness of object names
+ */
+    GList * object_list = NULL;
+gint num_objects = 1000;
+gint num_threads = 5;
+
+/* thread function for threaded default name change test */
+gpointer
+thread_name_object_default (int *i)
+{
+  int j;
+
+  THREAD_START ();
+
+  for (j = *i; j < num_objects; j += num_threads) {
+    GstObject *o = GST_OBJECT (g_list_nth_data (object_list, j));
+
+    /* g_message ("THREAD %p: setting default name on object %d\n",
+       g_thread_self (), j); */
+    gst_object_set_name (o, NULL);
+    THREAD_SWITCH ();
+  }
+
+  /* thread is done, so let's return */
+  g_message ("THREAD %p: set name\n", g_thread_self ());
+  g_free (i);
+
+  return NULL;
+}
+
+static gint
+gst_object_name_compare (GstObject * o, GstObject * p)
+{
+  gint result;
+
+  GST_LOCK (o);
+  GST_LOCK (p);
+
+  if (o->name == NULL && p->name == NULL) {
+    result = 0;
+  } else if (o->name == NULL) {
+    result = -1;
+  } else if (p->name == NULL) {
+    result = 1;
+  } else {
+    result = strcmp (o->name, p->name);
+  }
+
+  GST_UNLOCK (p);
+  GST_UNLOCK (o);
+
+  return result;
+}
+
+START_TEST (test_fake_object_name_threaded_unique)
+{
+  GstObject *object;
+  gint i;
+  gint *ip;
+  gchar *name1, *name2;
+  GList *l;
+
+  g_message ("\nTEST: uniqueness of default names\n");
+
+  for (i = 0; i < num_objects; ++i) {
+    object = g_object_new (gst_fake_object_get_type (), NULL);
+    object_list = g_list_append (object_list, object);
+  }
+
+  MAIN_INIT ();
+
+  mark_point ();
+  for (i = 0; i < num_threads; ++i) {
+    ip = g_new (gint, 1);
+    *ip = i;
+    MAIN_START_THREAD_FUNCTION (i, thread_name_object_default, ip);
+  }
+
+  mark_point ();
+  MAIN_SYNCHRONIZE ();
+  mark_point ();
+  MAIN_STOP_THREADS ();
+
+  /* sort GList based on object name */
+  /* FIXME: sort and test */
+  g_list_sort (object_list, (GCompareFunc) gst_object_name_compare);
+
+  name1 = gst_object_get_name (GST_OBJECT (object_list->data));
+  for (l = object_list->next; l->next; l = l->next) {
+    g_message ("object with name %s\n", name1);
+    name2 = gst_object_get_name (GST_OBJECT (l->data));
+    fail_if (strcmp (name1, name2) == 0, "Two objects with name %s", name2);
+    g_free (name1);
+    name1 = name2;
+  }
+
+  /* free stuff */
+  g_list_foreach (object_list, (GFunc) g_object_unref, NULL);
+}
+
+END_TEST
+/* test: try renaming a parented object, make sure it fails */
+    Suite * gst_object_suite (void)
+{
+  Suite *s = suite_create ("GstObject");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_fake_object_new);
+  tcase_add_test (tc_chain, test_fake_object_name);
+  tcase_add_test (tc_chain, test_fake_object_name_threaded_wrong);
+  tcase_add_test (tc_chain, test_fake_object_name_threaded_right);
+  tcase_add_test (tc_chain, test_fake_object_name_threaded_unique);
+  //tcase_add_checked_fixture (tc_chain, setup, teardown);
+
+  /* SEGV tests go last so we can debug the others */
+  tcase_add_test_raise_signal (tc_chain, test_fail_abstract_new, SIGSEGV);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_object_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/check/gst/gstpad.c b/check/gst/gstpad.c
new file mode 100644 (file)
index 0000000..3875900
--- /dev/null
@@ -0,0 +1,127 @@
+/* GStreamer
+ * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * gstpad.c: Unit test for GstPad
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../gstcheck.h"
+
+START_TEST (test_link)
+{
+  GstPad *src, *sink;
+  GstPadTemplate *srct;         //, *sinkt;
+  GstCaps *srcc;
+
+  GstPadLinkReturn ret;
+  gchar *name;
+
+  src = gst_pad_new ("source", GST_PAD_SRC);
+  fail_if (src == NULL);
+
+  name = gst_pad_get_name (src);
+  fail_unless (strcmp (name, "source") == 0);
+
+  sink = gst_pad_new ("sink", GST_PAD_SINK);
+  fail_if (sink == NULL);
+
+  /* linking without templates should fail */
+  ret = gst_pad_link (src, sink);
+  fail_unless (ret == GST_PAD_LINK_NOFORMAT);
+
+  ASSERT_CRITICAL (gst_pad_get_pad_template (NULL));
+
+  srct = gst_pad_get_pad_template (src);
+  fail_unless (srct == NULL);
+
+  /* create caps */
+  srcc = gst_caps_new_any ();
+  gst_pad_set_caps (src, srcc);
+  gst_pad_set_caps (sink, srcc);
+
+  /* linking with any caps should succeed */
+  ret = gst_pad_link (src, sink);
+  fail_unless (ret == GST_PAD_LINK_OK);
+}
+
+END_TEST
+/* threaded link/unlink */
+/* use globals */
+    GstPad * src, *sink;
+
+void
+thread_link_unlink (gpointer data)
+{
+  THREAD_START ();
+
+  while (THREAD_TEST_RUNNING ()) {
+    gst_pad_link (src, sink);
+    gst_pad_unlink (src, sink);
+    THREAD_SWITCH ();
+  }
+}
+
+START_TEST (test_link_unlink_threaded)
+{
+  GstCaps *caps;
+  int i;
+
+  src = gst_pad_new ("source", GST_PAD_SRC);
+  fail_if (src == NULL);
+  sink = gst_pad_new ("sink", GST_PAD_SINK);
+  fail_if (sink == NULL);
+
+  caps = gst_caps_new_any ();
+  gst_pad_set_caps (src, caps);
+  gst_pad_set_caps (sink, caps);
+
+  MAIN_START_THREADS (5, thread_link_unlink, NULL);
+  for (i = 0; i < 1000; ++i) {
+    gst_pad_is_linked (src);
+    gst_pad_is_linked (sink);
+    THREAD_SWITCH ();
+  }
+  MAIN_STOP_THREADS ();
+}
+END_TEST Suite *
+gst_pad_suite (void)
+{
+  Suite *s = suite_create ("GstPad");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_link);
+  tcase_add_test (tc_chain, test_link_unlink_threaded);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_pad_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/check/gstcheck.c b/check/gstcheck.c
new file mode 100644 (file)
index 0000000..53af0a6
--- /dev/null
@@ -0,0 +1,85 @@
+/* GStreamer
+ *
+ * Common code for GStreamer unittests
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstcheck.h"
+
+
+/* logging function for tests
+ * a test uses g_message() to log a debug line
+ * a gst unit test can be run with GST_TEST_DEBUG env var set to see the
+ * messages
+ */
+
+gboolean _gst_check_threads_running = FALSE;
+GList *thread_list = NULL;
+GMutex *mutex;
+GCond *start_cond;              /* used to notify main thread of thread startups */
+GCond *sync_cond;               /* used to synchronize all threads and main thread */
+
+gboolean _gst_check_debug = FALSE;
+gboolean _gst_check_raised_critical = FALSE;
+gboolean _gst_check_expecting_log = FALSE;
+
+void gst_check_log_message_func
+    (const gchar * log_domain, GLogLevelFlags log_level,
+    const gchar * message, gpointer user_data)
+{
+  if (_gst_check_debug) {
+    g_print (message);
+  }
+}
+
+void gst_check_log_critical_func
+    (const gchar * log_domain, GLogLevelFlags log_level,
+    const gchar * message, gpointer user_data)
+{
+  if (!_gst_check_expecting_log) {
+    g_print ("\n\nUnexpected critical/warning: %s\n", message);
+    fail ("Unexpected critical/warning: %s", message);
+  }
+
+  if (_gst_check_debug) {
+    g_print ("\nExpected critical/warning: %s\n", message);
+  }
+
+  if (log_level & G_LOG_LEVEL_CRITICAL)
+    _gst_check_raised_critical = TRUE;
+}
+
+/* initialize GStreamer testing */
+void
+gst_check_init (int *argc, char **argv[])
+{
+  gst_init (argc, argv);
+
+  if (g_getenv ("GST_TEST_DEBUG"))
+    _gst_check_debug = TRUE;
+
+  g_log_set_handler (NULL, G_LOG_LEVEL_MESSAGE, gst_check_log_message_func,
+      NULL);
+  g_log_set_handler (NULL, G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
+      gst_check_log_critical_func, NULL);
+  g_log_set_handler ("GStreamer", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
+      gst_check_log_critical_func, NULL);
+  g_log_set_handler ("GLib-GObject", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
+      gst_check_log_critical_func, NULL);
+}
diff --git a/check/gstcheck.h b/check/gstcheck.h
new file mode 100644 (file)
index 0000000..ce452eb
--- /dev/null
@@ -0,0 +1,150 @@
+/* GStreamer
+ *
+ * Common code for GStreamer unittests
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CHECK_H__
+#define __GST_CHECK_H__
+
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <check.h>
+
+#include <gst/gst.h>
+
+
+/* logging function for tests
+ * a test uses g_message() to log a debug line
+ * a gst unit test can be run with GST_TEST_DEBUG env var set to see the
+ * messages
+ */
+extern gboolean _gst_check_threads_running;
+extern gboolean _gst_check_raised_critical;
+extern gboolean _gst_check_expecting_log;
+
+void gst_check_init (int *argc, char **argv[]);
+
+/***
+ * thread test macros and variables
+ */
+extern GList *thread_list;
+extern GMutex *mutex;
+extern GCond *start_cond;      /* used to notify main thread of thread startups */
+extern GCond *sync_cond;       /* used to synchronize all threads and main thread */
+
+#define MAIN_START_THREADS(count, function, data)              \
+MAIN_INIT();                                                   \
+MAIN_START_THREAD_FUNCTIONS(count, function, data);            \
+MAIN_SYNCHRONIZE();
+
+#define MAIN_INIT()                    \
+G_STMT_START {                         \
+  _gst_check_threads_running = TRUE;   \
+                                       \
+  mutex = g_mutex_new ();              \
+  start_cond = g_cond_new ();          \
+  sync_cond = g_cond_new ();           \
+} G_STMT_END;
+
+#define MAIN_START_THREAD_FUNCTIONS(count, function, data)     \
+G_STMT_START {                                                 \
+  int i;                                                       \
+  for (i = 0; i < count; ++i) {                                        \
+    MAIN_START_THREAD_FUNCTION (i, function, data);            \
+  }                                                            \
+} G_STMT_END;
+
+#define MAIN_START_THREAD_FUNCTION(i, function, data)          \
+G_STMT_START {                                                 \
+    GThread *thread = NULL;                                    \
+    g_message ("MAIN: creating thread %d\n", i);               \
+    g_mutex_lock (mutex);                                      \
+    thread = g_thread_create ((GThreadFunc) function, data,    \
+       TRUE, NULL);                                            \
+    /* wait for thread to signal us that it's ready */         \
+    g_message ("MAIN: waiting for thread %d\n", i);            \
+    g_cond_wait (start_cond, mutex);                           \
+    g_mutex_unlock (mutex);                                    \
+                                                               \
+    thread_list = g_list_append (thread_list, thread);         \
+} G_STMT_END;
+
+
+#define MAIN_SYNCHRONIZE()             \
+G_STMT_START {                         \
+  g_message ("MAIN: synchronizing\n"); \
+  g_cond_broadcast (sync_cond);                \
+  g_message ("MAIN: synchronized\n");  \
+} G_STMT_END;
+
+#define MAIN_STOP_THREADS()                                    \
+G_STMT_START {                                                 \
+  _gst_check_threads_running = FALSE;                          \
+                                                               \
+  /* join all threads */                                       \
+  g_message ("MAIN: joining\n");                               \
+  g_list_foreach (thread_list, (GFunc) g_thread_join, NULL);   \
+  g_message ("MAIN: joined\n");                                        \
+} G_STMT_END;
+
+#define THREAD_START()                                         \
+THREAD_STARTED();                                              \
+THREAD_SYNCHRONIZE();
+
+#define THREAD_STARTED()                                       \
+G_STMT_START {                                                 \
+  /* signal main thread that we started */                     \
+  g_message ("THREAD %p: started\n", g_thread_self ());                \
+  g_mutex_lock (mutex);                                                \
+  g_cond_signal (start_cond);                                  \
+} G_STMT_END;
+
+#define THREAD_SYNCHRONIZE()                                   \
+G_STMT_START {                                                 \
+  /* synchronize everyone */                                   \
+  g_message ("THREAD %p: syncing\n", g_thread_self ());                \
+  g_cond_wait (sync_cond, mutex);                              \
+  g_message ("THREAD %p: synced\n", g_thread_self ());         \
+  g_mutex_unlock (mutex);                                      \
+} G_STMT_END;
+
+#define THREAD_SWITCH()                                                \
+G_STMT_START {                                                 \
+  /* a minimal sleep is a context switch */                    \
+  g_usleep (1);                                                        \
+} G_STMT_END;
+
+#define THREAD_TEST_RUNNING()  (_gst_check_threads_running == TRUE)
+
+#define ASSERT_CRITICAL(code)                                  \
+G_STMT_START {                                                 \
+  _gst_check_expecting_log = TRUE;                             \
+  _gst_check_raised_critical = FALSE;                          \
+  code;                                                                \
+  _fail_unless (_gst_check_raised_critical, __FILE__, __LINE__, \
+                "Expected g_critical, got nothing: '"#code"'"); \
+  _gst_check_expecting_log = FALSE;                            \
+} G_STMT_END
+
+
+#endif /* __GST_CHECK_H__ */
+
diff --git a/check/pipelines/simple_launch_lines.c b/check/pipelines/simple_launch_lines.c
new file mode 100644 (file)
index 0000000..f812392
--- /dev/null
@@ -0,0 +1,127 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * simple_launch_lines.c: Unit test for simple pipelines
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "../gstcheck.h"
+
+
+static GstElement *
+setup_pipeline (gchar * pipe_descr)
+{
+  GstElement *pipeline;
+
+  pipeline = gst_parse_launch (pipe_descr, NULL);
+  g_return_val_if_fail (GST_IS_PIPELINE (pipeline), NULL);
+  return pipeline;
+}
+
+/* events is a mask of expected events. tevent is the expected terminal event.
+   the poll call will time out after half a second.
+ */
+static void
+run_pipeline (GstElement * pipe, gchar * descr,
+    GstMessageType events, GstMessageType tevent)
+{
+  GstBus *bus;
+  GstMessageType revent;
+
+  bus = gst_element_get_bus (pipe);
+  g_assert (bus);
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+  while (1) {
+    revent = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
+
+    /* always have to pop the message before getting back into poll */
+    if (revent != GST_MESSAGE_UNKNOWN)
+      gst_message_unref (gst_bus_pop (bus));
+
+    if (revent == tevent) {
+      break;
+    } else if (revent == GST_MESSAGE_UNKNOWN) {
+      g_critical ("Unexpected timeout in gst_bus_poll, looking for %d: %s",
+          tevent, descr);
+      break;
+    } else if (revent & events) {
+      continue;
+    }
+    g_critical ("Unexpected message received of type %d, looking for %d: %s",
+        revent, tevent, descr);
+  }
+
+  gst_element_set_state (pipe, GST_STATE_NULL);
+  gst_object_unref (GST_OBJECT (pipe));
+}
+
+START_TEST (test_2_elements)
+{
+  gchar *s;
+
+  s = "fakesrc has-loop=false ! fakesink has-loop=true";
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN);
+
+  s = "fakesrc has-loop=true ! fakesink has-loop=false";
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN);
+
+  s = "fakesrc has-loop=false num-buffers=10 ! fakesink has-loop=true";
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_EOS);
+
+  s = "fakesrc has-loop=true num-buffers=10 ! fakesink has-loop=false";
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_EOS);
+
+  s = "fakesrc has-loop=false ! fakesink has-loop=false";
+  ASSERT_CRITICAL (run_pipeline (setup_pipeline (s), s,
+          GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN));
+}
+END_TEST Suite *
+simple_launch_lines_suite (void)
+{
+  Suite *s = suite_create ("Pipelines");
+  TCase *tc_chain = tcase_create ("linear");
+
+  /* time out after 20s, not the default 3 */
+  tcase_set_timeout (tc_chain, 20);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_2_elements);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = simple_launch_lines_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/tests/check/.gitignore b/tests/check/.gitignore
new file mode 100644 (file)
index 0000000..5d45c6c
--- /dev/null
@@ -0,0 +1 @@
+test-registry.xml
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
new file mode 100644 (file)
index 0000000..47208ce
--- /dev/null
@@ -0,0 +1,43 @@
+TESTS_ENVIRONMENT=\
+       GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/check \
+       GST_REGISTRY=$(top_builddir)/check/test-registry.xml
+
+plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
+
+# make all tests depend on the versioned gst-register
+$(TESTS): $(top_builddir)/tools/gst-register-@GST_MAJORMINOR@
+
+# rebuild gst-register-@GST_MAJORMINOR@ if needed
+$(top_builddir)/tools/gst-register-@GST_MAJORMINOR@:
+       cd $(top_builddir)/tools && make
+
+# override to _not_ install the test plugins
+install-pluginLTLIBRARIES:
+
+# This rule is here so make distcheck works on machines where core
+# dumps have PIDs appended
+CLEANFILES = core.*
+
+TESTS = $(top_builddir)/tools/gst-register-@GST_MAJORMINOR@ \
+       gst/gstcaps     \
+       gst/gstdata     \
+       gst/gstiterator \
+       gst/gstobject   \
+       gst-libs/gdp    
+
+check_PROGRAMS = $(TESTS)
+
+noinst_LTLIBRARIES = libgstcheck.la
+
+libgstcheck_la_SOURCES = gstcheck.c
+libgstcheck_la_LIBADD = $(GST_OBJ_LIBS)
+noinst_HEADERS = gstcheck.h
+
+AM_CFLAGS = $(GST_OBJ_CFLAGS) $(CHECK_CFLAGS)
+LDADD = $(GST_OBJ_LIBS) $(CHECK_LIBS) libgstcheck.la
+
+gst_libs_gdp_SOURCES = \
+       gst-libs/gdp.c \
+       $(top_srcdir)/libs/gst/dataprotocol/dataprotocol.c
+# remove GST_ENABLE_NEW when dataprotocol has been declared API-stable
+gst_libs_gdp_CFLAGS = $(AM_CFLAGS) -DGST_ENABLE_NEW
diff --git a/tests/check/gst/.gitignore b/tests/check/gst/.gitignore
new file mode 100644 (file)
index 0000000..4693cc3
--- /dev/null
@@ -0,0 +1,3 @@
+gstobject
+gstcaps
+gstdata
diff --git a/tests/check/gst/gstbus.c b/tests/check/gst/gstbus.c
new file mode 100644 (file)
index 0000000..9d28bc9
--- /dev/null
@@ -0,0 +1,130 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * gstbus.c: Unit test for the message bus
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "../gstcheck.h"
+
+
+static GstBus *test_bus = NULL;
+
+#define NUM_MESSAGES 1000
+#define NUM_THREADS 10
+
+static gpointer
+pound_bus_with_messages (gpointer data)
+{
+  gint thread_id = GPOINTER_TO_INT (data);
+  gint i;
+
+  for (i = 0; i < NUM_MESSAGES; i++) {
+    GstMessage *m;
+    GstStructure *s;
+
+    s = gst_structure_new ("test_message",
+        "thread_id", G_TYPE_INT, thread_id, "msg_id", G_TYPE_INT, i, NULL);
+    m = gst_message_new_application (s);
+    gst_bus_post (test_bus, m);
+  }
+  return NULL;
+}
+
+static void
+pull_messages ()
+{
+  GstMessage *m;
+  const GstStructure *s;
+  guint message_ids[NUM_THREADS];
+  gint i;
+
+  for (i = 0; i < NUM_THREADS; i++)
+    message_ids[i] = 0;
+
+  while (1) {
+    gint _t, _i;
+
+    m = gst_bus_pop (test_bus);
+    if (!m)
+      break;
+    g_return_if_fail (GST_MESSAGE_TYPE (m) == GST_MESSAGE_APPLICATION);
+
+    s = gst_message_get_structure (m);
+    if (!gst_structure_get_int (s, "thread_id", &_t))
+      g_critical ("Invalid message");
+    if (!gst_structure_get_int (s, "msg_id", &_i))
+      g_critical ("Invalid message");
+
+    g_return_if_fail (_t < NUM_THREADS);
+    g_return_if_fail (_i == message_ids[_t]++);
+
+    gst_message_unref (m);
+  }
+
+  for (i = 0; i < NUM_THREADS; i++)
+    g_return_if_fail (message_ids[i] == NUM_MESSAGES);
+}
+
+START_TEST (test_hammer_bus)
+{
+  GThread *threads[NUM_THREADS];
+  gint i;
+
+  test_bus = gst_bus_new ();
+
+  for (i = 0; i < NUM_THREADS; i++)
+    threads[i] = g_thread_create (pound_bus_with_messages, GINT_TO_POINTER (i),
+        TRUE, NULL);
+
+  for (i = 0; i < NUM_THREADS; i++)
+    g_thread_join (threads[i]);
+
+  pull_messages ();
+
+  gst_object_unref ((GstObject *) test_bus);
+}
+END_TEST Suite *
+gstbus_suite (void)
+{
+  Suite *s = suite_create ("GstBus");
+  TCase *tc_chain = tcase_create ("stresstest");
+
+  tcase_set_timeout (tc_chain, 0);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_hammer_bus);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gstbus_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/tests/check/gst/gstcaps.c b/tests/check/gst/gstcaps.c
new file mode 100644 (file)
index 0000000..4eefe72
--- /dev/null
@@ -0,0 +1,91 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * gstcaps.c: Unit test for GstCaps
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "../gstcheck.h"
+
+
+START_TEST (test_double_append)
+{
+  GstStructure *s1;
+  GstCaps *c1;
+
+  c1 = gst_caps_new_any ();
+  s1 = gst_structure_from_string ("audio/x-raw-int,rate=44100", NULL);
+  gst_caps_append_structure (c1, s1);
+  ASSERT_CRITICAL (gst_caps_append_structure (c1, s1));
+}
+
+END_TEST
+START_TEST (test_mutability)
+{
+  GstStructure *s1;
+  GstCaps *c1;
+  gint ret;
+
+  c1 = gst_caps_new_any ();
+  s1 = gst_structure_from_string ("audio/x-raw-int,rate=44100", NULL);
+  gst_structure_set (s1, "rate", G_TYPE_INT, 48000, NULL);
+  gst_caps_append_structure (c1, s1);
+  gst_structure_set (s1, "rate", G_TYPE_INT, 22500, NULL);
+  gst_caps_ref (c1);
+  ASSERT_CRITICAL (gst_structure_set (s1, "rate", G_TYPE_INT, 11250, NULL));
+  fail_unless (gst_structure_get_int (s1, "rate", &ret));
+  fail_unless (ret == 22500);
+  ASSERT_CRITICAL (gst_caps_set_simple (c1, "rate", G_TYPE_INT, 11250, NULL));
+  fail_unless (gst_structure_get_int (s1, "rate", &ret));
+  fail_unless (ret == 22500);
+  gst_caps_unref (c1);
+  gst_structure_set (s1, "rate", G_TYPE_INT, 11250, NULL);
+  fail_unless (gst_structure_get_int (s1, "rate", &ret));
+  fail_unless (ret == 11250);
+  gst_caps_set_simple (c1, "rate", G_TYPE_INT, 1, NULL);
+  fail_unless (gst_structure_get_int (s1, "rate", &ret));
+  fail_unless (ret == 1);
+}
+END_TEST Suite *
+gst_caps_suite (void)
+{
+  Suite *s = suite_create ("GstCaps");
+  TCase *tc_chain = tcase_create ("mutability");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_double_append);
+  tcase_add_test (tc_chain, test_mutability);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_caps_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/tests/check/gst/gstdata.c b/tests/check/gst/gstdata.c
new file mode 100644 (file)
index 0000000..59c931e
--- /dev/null
@@ -0,0 +1,196 @@
+/* GStreamer
+ *
+ * unit test for GstData
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../gstcheck.h"
+
+START_TEST (test_copy)
+{
+  GstBuffer *buffer, *copy;
+
+  buffer = gst_buffer_new_and_alloc (4);
+
+  copy = GST_BUFFER (gst_data_copy (GST_DATA (buffer)));
+
+  fail_if (copy == NULL, "Copy of buffer returned NULL");
+  fail_unless (GST_BUFFER_SIZE (copy) == 4,
+      "Copy of buffer has different size");
+}
+
+END_TEST
+START_TEST (test_is_writable)
+{
+  GstBuffer *buffer;
+  GstData *data;
+
+  buffer = gst_buffer_new_and_alloc (4);
+  data = GST_DATA (buffer);
+
+  fail_unless (gst_data_is_writable (data),
+      "A buffer with one ref should be writable");
+
+  GST_DATA_FLAG_SET (data, GST_DATA_READONLY);
+  fail_if (gst_data_is_writable (data),
+      "A buffer with READONLY set should not be writable");
+  GST_DATA_FLAG_UNSET (data, GST_DATA_READONLY);
+  fail_unless (gst_data_is_writable (data),
+      "A buffer with one ref and READONLY not set should be writable");
+
+  fail_if (gst_data_ref (data) == NULL, "Could not ref the data");
+
+  fail_if (gst_data_is_writable (data),
+      "A buffer with two refs should not be writable");
+}
+
+END_TEST
+START_TEST (test_copy_on_write)
+{
+  GstBuffer *buffer;
+  GstData *data, *data2, *data3;
+
+  buffer = gst_buffer_new_and_alloc (4);
+  data = GST_DATA (buffer);
+
+  data2 = gst_data_copy_on_write (data);
+  fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer");
+  fail_unless (data == data2,
+      "copy_on_write returned a copy for a buffer with refcount 1");
+
+  data2 = gst_data_ref (data);
+  data3 = gst_data_copy_on_write (data);
+  fail_unless (GST_IS_BUFFER (data3), "copy_on_write did not return a buffer");
+  fail_if (data == data3,
+      "copy_on_write returned same object for a buffer with refcount > 1");
+
+  fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1,
+      "refcount of original data object should be back to 1");
+
+  data2 = gst_data_copy_on_write (data);
+  fail_unless (GST_IS_BUFFER (data2), "copy_on_write did not return a buffer");
+  fail_unless (data == data2,
+      "copy_on_write returned a copy for a buffer with refcount 1");
+
+}
+
+END_TEST gint num_threads = 10;
+gint refs_per_thread = 10000;
+
+/* test thread-safe refcounting of GstData */
+void
+thread_ref (GstData * data)
+{
+  int j;
+
+  THREAD_START ();
+
+  for (j = 0; j < refs_per_thread; ++j) {
+    fail_if (gst_data_ref (data) == NULL, "Could not ref data from thread");
+
+    if (j % num_threads == 0)
+      THREAD_SWITCH ();
+  }
+}
+
+START_TEST (test_ref_threaded)
+{
+  GstBuffer *buffer;
+  GstData *data;
+  gint expected;
+
+  buffer = gst_buffer_new_and_alloc (4);
+
+  data = GST_DATA (buffer);
+
+  MAIN_START_THREADS (num_threads, thread_ref, data);
+
+  MAIN_STOP_THREADS ();
+
+  expected = num_threads * refs_per_thread + 1;
+  fail_unless (GST_DATA_REFCOUNT_VALUE (data) == expected,
+      "Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), expected);
+}
+END_TEST void
+thread_unref (GstData * data)
+{
+  int j;
+
+  THREAD_START ();
+
+  for (j = 0; j < refs_per_thread; ++j) {
+    gst_data_unref (data);
+
+    if (j % num_threads == 0)
+      THREAD_SWITCH ();
+  }
+}
+
+START_TEST (test_unref_threaded)
+{
+  GstBuffer *buffer;
+  GstData *data;
+
+  buffer = gst_buffer_new_and_alloc (4);
+
+  data = GST_DATA (buffer);
+
+  gst_data_ref_by_count (data, num_threads * refs_per_thread);
+
+  MAIN_START_THREADS (num_threads, thread_unref, data);
+
+  MAIN_STOP_THREADS ();
+
+  fail_unless (GST_DATA_REFCOUNT_VALUE (data) == 1,
+      "Refcount of data is %d != %d", GST_DATA_REFCOUNT_VALUE (data), 1);
+
+  /* final unref */
+  gst_data_unref (data);
+}
+END_TEST Suite *
+gst_data_suite (void)
+{
+  Suite *s = suite_create ("GstData");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_copy);
+  tcase_add_test (tc_chain, test_is_writable);
+  tcase_add_test (tc_chain, test_copy_on_write);
+  tcase_add_test (tc_chain, test_ref_threaded);
+  tcase_add_test (tc_chain, test_unref_threaded);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_data_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/tests/check/gst/gstiterator.c b/tests/check/gst/gstiterator.c
new file mode 100644 (file)
index 0000000..aa9a27e
--- /dev/null
@@ -0,0 +1,182 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * gstiterator.c: Unit test for iterators
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "../gstcheck.h"
+
+
+static GList *
+make_list_of_ints (gint n)
+{
+  GList *ret = NULL;
+  gint i;
+
+  for (i = 0; i < n; i++)
+    ret = g_list_prepend (ret, GINT_TO_POINTER (i));
+
+  return g_list_reverse (ret);
+}
+
+#define NUM_ELEMENTS 10
+
+START_TEST (test_manual_iteration)
+{
+  GList *l;
+  guint32 cookie = 0;
+  GMutex *m;
+  GstIterator *iter;
+  GstIteratorResult res;
+  gpointer item;
+  gint i = 0;
+
+  l = make_list_of_ints (NUM_ELEMENTS);
+  m = g_mutex_new ();
+
+  iter = gst_iterator_new_list (m, &cookie, &l, NULL, NULL, NULL);
+
+  g_return_if_fail (iter != NULL);
+
+  while (1) {
+    res = gst_iterator_next (iter, &item);
+    if (i < NUM_ELEMENTS) {
+      g_return_if_fail (res == GST_ITERATOR_OK);
+      g_return_if_fail (GPOINTER_TO_INT (item) == i);
+      i++;
+      continue;
+    } else {
+      g_return_if_fail (res == GST_ITERATOR_DONE);
+      break;
+    }
+  }
+
+  gst_iterator_free (iter);
+}
+
+END_TEST
+START_TEST (test_resync)
+{
+  GList *l;
+  guint32 cookie = 0;
+  GMutex *m;
+  GstIterator *iter;
+  GstIteratorResult res;
+  gpointer item;
+  gint i = 0;
+  gboolean hacked_list = FALSE;
+
+  l = make_list_of_ints (NUM_ELEMENTS);
+  m = g_mutex_new ();
+
+  iter = gst_iterator_new_list (m, &cookie, &l, NULL, NULL, NULL);
+
+  g_return_if_fail (iter != NULL);
+
+  while (1) {
+    res = gst_iterator_next (iter, &item);
+    if (i < NUM_ELEMENTS / 2) {
+      g_return_if_fail (res == GST_ITERATOR_OK);
+      g_return_if_fail (GPOINTER_TO_INT (item) == i);
+      i++;
+      continue;
+    } else if (!hacked_list) {
+      /* here's where we test resync */
+      g_return_if_fail (res == GST_ITERATOR_OK);
+      l = g_list_prepend (l, GINT_TO_POINTER (-1));
+      cookie++;
+      hacked_list = TRUE;
+      continue;
+    } else {
+      g_return_if_fail (res == GST_ITERATOR_RESYNC);
+      gst_iterator_resync (iter);
+      res = gst_iterator_next (iter, &item);
+      g_return_if_fail (res == GST_ITERATOR_OK);
+      g_return_if_fail (GPOINTER_TO_INT (item) == -1);
+      break;
+    }
+  }
+
+  gst_iterator_free (iter);
+}
+END_TEST static gboolean
+add_fold_func (gpointer item, GValue * ret, gpointer user_data)
+{
+  g_value_set_int (ret, g_value_get_int (ret) + GPOINTER_TO_INT (item));
+  return TRUE;
+}
+
+START_TEST (test_fold)
+{
+  GList *l;
+  guint32 cookie = 0;
+  GMutex *m;
+  GstIterator *iter;
+  GstIteratorResult res;
+  gint i, expected;
+  GValue ret = { 0, };
+
+  l = make_list_of_ints (NUM_ELEMENTS);
+  m = g_mutex_new ();
+  iter = gst_iterator_new_list (m, &cookie, &l, NULL, NULL, NULL);
+  g_return_if_fail (iter != NULL);
+
+  expected = 0;
+  for (i = 0; i < NUM_ELEMENTS; i++)
+    expected += i;
+
+  g_value_init (&ret, G_TYPE_INT);
+  g_value_set_int (&ret, 0);
+
+  res = gst_iterator_fold (iter, add_fold_func, &ret, NULL);
+
+  g_return_if_fail (res == GST_ITERATOR_DONE);
+  g_return_if_fail (g_value_get_int (&ret) == expected);
+}
+END_TEST Suite *
+gstiterator_suite (void)
+{
+  Suite *s = suite_create ("GstIterator");
+  TCase *tc_chain = tcase_create ("correctness");
+
+  tcase_set_timeout (tc_chain, 0);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_manual_iteration);
+  tcase_add_test (tc_chain, test_resync);
+  tcase_add_test (tc_chain, test_fold);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gstiterator_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/tests/check/gst/gstobject.c b/tests/check/gst/gstobject.c
new file mode 100644 (file)
index 0000000..52f92e9
--- /dev/null
@@ -0,0 +1,364 @@
+/* GStreamer
+ *
+ * unit test for GstObject
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../gstcheck.h"
+
+/*
+  Create a fake subclass
+ */
+typedef struct _GstFakeObjectClass GstFakeObjectClass;
+typedef struct _GstFakeObject GstFakeObject;
+
+struct _GstFakeObject
+{
+  GstObject object;
+};
+
+struct _GstFakeObjectClass
+{
+  GstObjectClass parent_class;
+};
+
+GType _gst_fake_object_type = 0;
+
+//static GstObjectClass *parent_class = NULL;
+//static guint gst_fake_object_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_fake_object_get_type (void)
+{
+  if (!_gst_fake_object_type) {
+    static const GTypeInfo fake_object_info = {
+      sizeof (GstFakeObjectClass),
+      NULL,                     //gst_fake_object_base_class_init,
+      NULL,                     //gst_fake_object_base_class_finalize,
+      NULL,                     //(GClassInitFunc) gst_fake_object_class_init,
+      NULL,
+      NULL,
+      sizeof (GstFakeObject),
+      0,
+      NULL,                     //(GInstanceInitFunc) gst_fake_object_init,
+      NULL
+    };
+
+    _gst_fake_object_type = g_type_register_static (GST_TYPE_OBJECT,
+        "GstFakeObject", &fake_object_info, 0);
+  }
+  return _gst_fake_object_type;
+}
+
+/* g_object_new on abstract GstObject should fail */
+START_TEST (test_fail_abstract_new)
+{
+  GstObject *object;
+
+  ASSERT_CRITICAL (object = g_object_new (gst_object_get_type (), NULL));
+  fail_unless (object == NULL, "Created an instance of abstract GstObject");
+}
+
+END_TEST
+/* g_object_new on GstFakeObject should succeed */
+START_TEST (test_fake_object_new)
+{
+  GstObject *object;
+
+  object = g_object_new (gst_fake_object_get_type (), NULL);
+  fail_if (object == NULL, "Failed to create instance of GstFakeObject");
+  fail_unless (GST_IS_OBJECT (object),
+      "GstFakeObject instance is not a GstObject");
+}
+
+END_TEST
+/* GstFakeObject name tests */
+START_TEST (test_fake_object_name)
+{
+  GstObject *object;
+  gchar *name;
+  gchar *name2;
+
+  object = g_object_new (gst_fake_object_get_type (), NULL);
+
+  name = gst_object_get_name (object);
+  fail_if (name == NULL, "Newly created object has no name");
+  fail_if (strncmp (name, "fakeobject", 10) != 0,
+      "Random name %s does not start with Gst", name);
+
+  /* give a random name by setting with NULL;
+   * GstFakeObject class -> fakeobject%d */
+  gst_object_set_name (object, NULL);
+  name = gst_object_get_name (object);
+  fail_if (name == NULL, "Random name was not assigned");
+  fail_if (strncmp (name, "fakeobject", 10) != 0,
+      "Random name %s does not start with Gst", name);
+  g_free (name);
+
+  gst_object_set_name (object, "fake");
+  name = gst_object_get_name (object);
+  fail_if (name == NULL, "Failed to get name of GstFakeObject");
+  fail_if (strcmp (name, "fake") != 0, "Name of GstFakeObject is not 'fake'");
+
+  /* change the gotten name to see that it's a copy and not the original */
+  name[0] = 'm';
+  name2 = gst_object_get_name (object);
+  fail_if (strcmp (name2, "fake") != 0,
+      "Copy of object name affected actual object name");
+  g_free (name);
+  g_free (name2);
+}
+
+END_TEST
+/* thread function for threaded name change test */
+    gpointer thread_name_object (GstObject * object)
+{
+  gchar *thread_id = g_strdup_printf ("%p", g_thread_self ());
+
+  THREAD_START ();
+
+  /* give main thread a head start */
+  g_usleep (100000);
+
+  /* write our name repeatedly */
+  g_message ("THREAD %s: starting loop\n", thread_id);
+  while (THREAD_TEST_RUNNING ()) {
+    gst_object_set_name (object, thread_id);
+    /* a minimal sleep invokes a thread switch */
+    THREAD_SWITCH ();
+  }
+
+  /* thread is done, so let's return */
+  g_message ("THREAD %s: set name\n", thread_id);
+  g_free (thread_id);
+
+  return NULL;
+}
+
+/*
+ * main thread sets and gets name while other threads set the name
+ * constantly; fails because lock is released inbetween set and get
+ */
+
+START_TEST (test_fake_object_name_threaded_wrong)
+{
+  GstObject *object;
+  gchar *name;
+  gint i;
+  gboolean expected_failure = FALSE;
+
+  g_message ("\nTEST: set/get without lock\n");
+
+  object = g_object_new (gst_fake_object_get_type (), NULL);
+  gst_object_set_name (object, "main");
+
+  MAIN_START_THREADS (5, thread_name_object, object);
+
+  /* start looping and set/get name repeatedly */
+  for (i = 0; i < 1000; ++i) {
+    gst_object_set_name (object, "main");
+    THREAD_SWITCH ();
+    name = gst_object_get_name (object);
+    if (strcmp (name, "main") != 0) {
+      g_message ("MAIN: expected failure during run %d\n", i);
+      expected_failure = TRUE;
+      g_free (name);
+      break;
+    }
+    g_free (name);
+  }
+  MAIN_STOP_THREADS ();
+
+  fail_unless (expected_failure, "name did not get changed");
+}
+
+END_TEST
+/*
+ * main thread sets and gets name directly on struct inside the object lock
+ * succeed because lock is held during set/get, and threads are locked out
+ */
+START_TEST (test_fake_object_name_threaded_right)
+{
+  GstObject *object;
+  gchar *name;
+  gint i;
+
+  g_message ("\nTEST: set/get inside lock\n");
+
+  object = g_object_new (gst_fake_object_get_type (), NULL);
+  gst_object_set_name (object, "main");
+
+  MAIN_START_THREADS (5, thread_name_object, object);
+
+  /* start looping and set/get name repeatedly */
+  for (i = 0; i < 1000; ++i) {
+    GST_LOCK (object);
+    g_free (GST_OBJECT_NAME (object));
+    GST_OBJECT_NAME (object) = g_strdup ("main");
+    THREAD_SWITCH ();
+    name = g_strdup (GST_OBJECT_NAME (object));
+    GST_UNLOCK (object);
+
+    fail_unless (strcmp (name, "main") == 0,
+        "Name got changed while lock held during run %d", i);
+    g_free (name);
+  }
+  MAIN_STOP_THREADS ();
+}
+
+END_TEST
+/*
+ * main thread creates lots of objects
+ * child threads sets default names on objects
+ * then main thread checks uniqueness of object names
+ */
+    GList * object_list = NULL;
+gint num_objects = 1000;
+gint num_threads = 5;
+
+/* thread function for threaded default name change test */
+gpointer
+thread_name_object_default (int *i)
+{
+  int j;
+
+  THREAD_START ();
+
+  for (j = *i; j < num_objects; j += num_threads) {
+    GstObject *o = GST_OBJECT (g_list_nth_data (object_list, j));
+
+    /* g_message ("THREAD %p: setting default name on object %d\n",
+       g_thread_self (), j); */
+    gst_object_set_name (o, NULL);
+    THREAD_SWITCH ();
+  }
+
+  /* thread is done, so let's return */
+  g_message ("THREAD %p: set name\n", g_thread_self ());
+  g_free (i);
+
+  return NULL;
+}
+
+static gint
+gst_object_name_compare (GstObject * o, GstObject * p)
+{
+  gint result;
+
+  GST_LOCK (o);
+  GST_LOCK (p);
+
+  if (o->name == NULL && p->name == NULL) {
+    result = 0;
+  } else if (o->name == NULL) {
+    result = -1;
+  } else if (p->name == NULL) {
+    result = 1;
+  } else {
+    result = strcmp (o->name, p->name);
+  }
+
+  GST_UNLOCK (p);
+  GST_UNLOCK (o);
+
+  return result;
+}
+
+START_TEST (test_fake_object_name_threaded_unique)
+{
+  GstObject *object;
+  gint i;
+  gint *ip;
+  gchar *name1, *name2;
+  GList *l;
+
+  g_message ("\nTEST: uniqueness of default names\n");
+
+  for (i = 0; i < num_objects; ++i) {
+    object = g_object_new (gst_fake_object_get_type (), NULL);
+    object_list = g_list_append (object_list, object);
+  }
+
+  MAIN_INIT ();
+
+  mark_point ();
+  for (i = 0; i < num_threads; ++i) {
+    ip = g_new (gint, 1);
+    *ip = i;
+    MAIN_START_THREAD_FUNCTION (i, thread_name_object_default, ip);
+  }
+
+  mark_point ();
+  MAIN_SYNCHRONIZE ();
+  mark_point ();
+  MAIN_STOP_THREADS ();
+
+  /* sort GList based on object name */
+  /* FIXME: sort and test */
+  g_list_sort (object_list, (GCompareFunc) gst_object_name_compare);
+
+  name1 = gst_object_get_name (GST_OBJECT (object_list->data));
+  for (l = object_list->next; l->next; l = l->next) {
+    g_message ("object with name %s\n", name1);
+    name2 = gst_object_get_name (GST_OBJECT (l->data));
+    fail_if (strcmp (name1, name2) == 0, "Two objects with name %s", name2);
+    g_free (name1);
+    name1 = name2;
+  }
+
+  /* free stuff */
+  g_list_foreach (object_list, (GFunc) g_object_unref, NULL);
+}
+
+END_TEST
+/* test: try renaming a parented object, make sure it fails */
+    Suite * gst_object_suite (void)
+{
+  Suite *s = suite_create ("GstObject");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_fake_object_new);
+  tcase_add_test (tc_chain, test_fake_object_name);
+  tcase_add_test (tc_chain, test_fake_object_name_threaded_wrong);
+  tcase_add_test (tc_chain, test_fake_object_name_threaded_right);
+  tcase_add_test (tc_chain, test_fake_object_name_threaded_unique);
+  //tcase_add_checked_fixture (tc_chain, setup, teardown);
+
+  /* SEGV tests go last so we can debug the others */
+  tcase_add_test_raise_signal (tc_chain, test_fail_abstract_new, SIGSEGV);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_object_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/tests/check/gst/gstpad.c b/tests/check/gst/gstpad.c
new file mode 100644 (file)
index 0000000..3875900
--- /dev/null
@@ -0,0 +1,127 @@
+/* GStreamer
+ * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * gstpad.c: Unit test for GstPad
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../gstcheck.h"
+
+START_TEST (test_link)
+{
+  GstPad *src, *sink;
+  GstPadTemplate *srct;         //, *sinkt;
+  GstCaps *srcc;
+
+  GstPadLinkReturn ret;
+  gchar *name;
+
+  src = gst_pad_new ("source", GST_PAD_SRC);
+  fail_if (src == NULL);
+
+  name = gst_pad_get_name (src);
+  fail_unless (strcmp (name, "source") == 0);
+
+  sink = gst_pad_new ("sink", GST_PAD_SINK);
+  fail_if (sink == NULL);
+
+  /* linking without templates should fail */
+  ret = gst_pad_link (src, sink);
+  fail_unless (ret == GST_PAD_LINK_NOFORMAT);
+
+  ASSERT_CRITICAL (gst_pad_get_pad_template (NULL));
+
+  srct = gst_pad_get_pad_template (src);
+  fail_unless (srct == NULL);
+
+  /* create caps */
+  srcc = gst_caps_new_any ();
+  gst_pad_set_caps (src, srcc);
+  gst_pad_set_caps (sink, srcc);
+
+  /* linking with any caps should succeed */
+  ret = gst_pad_link (src, sink);
+  fail_unless (ret == GST_PAD_LINK_OK);
+}
+
+END_TEST
+/* threaded link/unlink */
+/* use globals */
+    GstPad * src, *sink;
+
+void
+thread_link_unlink (gpointer data)
+{
+  THREAD_START ();
+
+  while (THREAD_TEST_RUNNING ()) {
+    gst_pad_link (src, sink);
+    gst_pad_unlink (src, sink);
+    THREAD_SWITCH ();
+  }
+}
+
+START_TEST (test_link_unlink_threaded)
+{
+  GstCaps *caps;
+  int i;
+
+  src = gst_pad_new ("source", GST_PAD_SRC);
+  fail_if (src == NULL);
+  sink = gst_pad_new ("sink", GST_PAD_SINK);
+  fail_if (sink == NULL);
+
+  caps = gst_caps_new_any ();
+  gst_pad_set_caps (src, caps);
+  gst_pad_set_caps (sink, caps);
+
+  MAIN_START_THREADS (5, thread_link_unlink, NULL);
+  for (i = 0; i < 1000; ++i) {
+    gst_pad_is_linked (src);
+    gst_pad_is_linked (sink);
+    THREAD_SWITCH ();
+  }
+  MAIN_STOP_THREADS ();
+}
+END_TEST Suite *
+gst_pad_suite (void)
+{
+  Suite *s = suite_create ("GstPad");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_link);
+  tcase_add_test (tc_chain, test_link_unlink_threaded);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_pad_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/tests/check/gstcheck.c b/tests/check/gstcheck.c
new file mode 100644 (file)
index 0000000..53af0a6
--- /dev/null
@@ -0,0 +1,85 @@
+/* GStreamer
+ *
+ * Common code for GStreamer unittests
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstcheck.h"
+
+
+/* logging function for tests
+ * a test uses g_message() to log a debug line
+ * a gst unit test can be run with GST_TEST_DEBUG env var set to see the
+ * messages
+ */
+
+gboolean _gst_check_threads_running = FALSE;
+GList *thread_list = NULL;
+GMutex *mutex;
+GCond *start_cond;              /* used to notify main thread of thread startups */
+GCond *sync_cond;               /* used to synchronize all threads and main thread */
+
+gboolean _gst_check_debug = FALSE;
+gboolean _gst_check_raised_critical = FALSE;
+gboolean _gst_check_expecting_log = FALSE;
+
+void gst_check_log_message_func
+    (const gchar * log_domain, GLogLevelFlags log_level,
+    const gchar * message, gpointer user_data)
+{
+  if (_gst_check_debug) {
+    g_print (message);
+  }
+}
+
+void gst_check_log_critical_func
+    (const gchar * log_domain, GLogLevelFlags log_level,
+    const gchar * message, gpointer user_data)
+{
+  if (!_gst_check_expecting_log) {
+    g_print ("\n\nUnexpected critical/warning: %s\n", message);
+    fail ("Unexpected critical/warning: %s", message);
+  }
+
+  if (_gst_check_debug) {
+    g_print ("\nExpected critical/warning: %s\n", message);
+  }
+
+  if (log_level & G_LOG_LEVEL_CRITICAL)
+    _gst_check_raised_critical = TRUE;
+}
+
+/* initialize GStreamer testing */
+void
+gst_check_init (int *argc, char **argv[])
+{
+  gst_init (argc, argv);
+
+  if (g_getenv ("GST_TEST_DEBUG"))
+    _gst_check_debug = TRUE;
+
+  g_log_set_handler (NULL, G_LOG_LEVEL_MESSAGE, gst_check_log_message_func,
+      NULL);
+  g_log_set_handler (NULL, G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
+      gst_check_log_critical_func, NULL);
+  g_log_set_handler ("GStreamer", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
+      gst_check_log_critical_func, NULL);
+  g_log_set_handler ("GLib-GObject", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
+      gst_check_log_critical_func, NULL);
+}
diff --git a/tests/check/gstcheck.h b/tests/check/gstcheck.h
new file mode 100644 (file)
index 0000000..ce452eb
--- /dev/null
@@ -0,0 +1,150 @@
+/* GStreamer
+ *
+ * Common code for GStreamer unittests
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CHECK_H__
+#define __GST_CHECK_H__
+
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <check.h>
+
+#include <gst/gst.h>
+
+
+/* logging function for tests
+ * a test uses g_message() to log a debug line
+ * a gst unit test can be run with GST_TEST_DEBUG env var set to see the
+ * messages
+ */
+extern gboolean _gst_check_threads_running;
+extern gboolean _gst_check_raised_critical;
+extern gboolean _gst_check_expecting_log;
+
+void gst_check_init (int *argc, char **argv[]);
+
+/***
+ * thread test macros and variables
+ */
+extern GList *thread_list;
+extern GMutex *mutex;
+extern GCond *start_cond;      /* used to notify main thread of thread startups */
+extern GCond *sync_cond;       /* used to synchronize all threads and main thread */
+
+#define MAIN_START_THREADS(count, function, data)              \
+MAIN_INIT();                                                   \
+MAIN_START_THREAD_FUNCTIONS(count, function, data);            \
+MAIN_SYNCHRONIZE();
+
+#define MAIN_INIT()                    \
+G_STMT_START {                         \
+  _gst_check_threads_running = TRUE;   \
+                                       \
+  mutex = g_mutex_new ();              \
+  start_cond = g_cond_new ();          \
+  sync_cond = g_cond_new ();           \
+} G_STMT_END;
+
+#define MAIN_START_THREAD_FUNCTIONS(count, function, data)     \
+G_STMT_START {                                                 \
+  int i;                                                       \
+  for (i = 0; i < count; ++i) {                                        \
+    MAIN_START_THREAD_FUNCTION (i, function, data);            \
+  }                                                            \
+} G_STMT_END;
+
+#define MAIN_START_THREAD_FUNCTION(i, function, data)          \
+G_STMT_START {                                                 \
+    GThread *thread = NULL;                                    \
+    g_message ("MAIN: creating thread %d\n", i);               \
+    g_mutex_lock (mutex);                                      \
+    thread = g_thread_create ((GThreadFunc) function, data,    \
+       TRUE, NULL);                                            \
+    /* wait for thread to signal us that it's ready */         \
+    g_message ("MAIN: waiting for thread %d\n", i);            \
+    g_cond_wait (start_cond, mutex);                           \
+    g_mutex_unlock (mutex);                                    \
+                                                               \
+    thread_list = g_list_append (thread_list, thread);         \
+} G_STMT_END;
+
+
+#define MAIN_SYNCHRONIZE()             \
+G_STMT_START {                         \
+  g_message ("MAIN: synchronizing\n"); \
+  g_cond_broadcast (sync_cond);                \
+  g_message ("MAIN: synchronized\n");  \
+} G_STMT_END;
+
+#define MAIN_STOP_THREADS()                                    \
+G_STMT_START {                                                 \
+  _gst_check_threads_running = FALSE;                          \
+                                                               \
+  /* join all threads */                                       \
+  g_message ("MAIN: joining\n");                               \
+  g_list_foreach (thread_list, (GFunc) g_thread_join, NULL);   \
+  g_message ("MAIN: joined\n");                                        \
+} G_STMT_END;
+
+#define THREAD_START()                                         \
+THREAD_STARTED();                                              \
+THREAD_SYNCHRONIZE();
+
+#define THREAD_STARTED()                                       \
+G_STMT_START {                                                 \
+  /* signal main thread that we started */                     \
+  g_message ("THREAD %p: started\n", g_thread_self ());                \
+  g_mutex_lock (mutex);                                                \
+  g_cond_signal (start_cond);                                  \
+} G_STMT_END;
+
+#define THREAD_SYNCHRONIZE()                                   \
+G_STMT_START {                                                 \
+  /* synchronize everyone */                                   \
+  g_message ("THREAD %p: syncing\n", g_thread_self ());                \
+  g_cond_wait (sync_cond, mutex);                              \
+  g_message ("THREAD %p: synced\n", g_thread_self ());         \
+  g_mutex_unlock (mutex);                                      \
+} G_STMT_END;
+
+#define THREAD_SWITCH()                                                \
+G_STMT_START {                                                 \
+  /* a minimal sleep is a context switch */                    \
+  g_usleep (1);                                                        \
+} G_STMT_END;
+
+#define THREAD_TEST_RUNNING()  (_gst_check_threads_running == TRUE)
+
+#define ASSERT_CRITICAL(code)                                  \
+G_STMT_START {                                                 \
+  _gst_check_expecting_log = TRUE;                             \
+  _gst_check_raised_critical = FALSE;                          \
+  code;                                                                \
+  _fail_unless (_gst_check_raised_critical, __FILE__, __LINE__, \
+                "Expected g_critical, got nothing: '"#code"'"); \
+  _gst_check_expecting_log = FALSE;                            \
+} G_STMT_END
+
+
+#endif /* __GST_CHECK_H__ */
+
diff --git a/tests/check/libs/.gitignore b/tests/check/libs/.gitignore
new file mode 100644 (file)
index 0000000..5ad589e
--- /dev/null
@@ -0,0 +1 @@
+gdp
diff --git a/tests/check/libs/gdp.c b/tests/check/libs/gdp.c
new file mode 100644 (file)
index 0000000..df79c8d
--- /dev/null
@@ -0,0 +1,277 @@
+/* GStreamer
+ *
+ * unit test for data protocol
+ *
+ * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "../gstcheck.h"
+
+#include <gst/dataprotocol/dataprotocol.h>
+#include "libs/gst/dataprotocol/dp-private.h"   /* private header */
+
+/* test our method of reading and writing headers using TO/FROM_BE */
+START_TEST (test_conversion)
+{
+  guint8 array[9];
+  guint8 write_array[9];
+  guint16 read_two, expect_two;
+  guint32 read_four, expect_four;
+  guint64 read_eight, expect_eight;
+  int i;
+
+  for (i = 0; i < 9; ++i) {
+    array[i] = i * 0x10;
+  }
+
+  /* read 8 16 bits */
+  for (i = 0; i < 8; ++i) {
+    read_two = GST_READ_UINT16_BE (array + i);
+    expect_two = array[i] * (1 << 8) + array[i + 1];
+    fail_unless (read_two == expect_two,
+        "GST_READ_UINT16_BE %d: read %d != %d\n", i, read_two, expect_two);
+  }
+
+  /* write 8 16 bits */
+  for (i = 0; i < 8; ++i) {
+    GST_WRITE_UINT16_BE (&write_array[i], read_two);
+    fail_unless (memcmp (array + 7, write_array + i, 2) == 0,
+        "GST_WRITE_UINT16_BE %d: memcmp failed", i);
+  }
+
+  /* read 5 32 bits */
+  for (i = 0; i < 5; ++i) {
+    read_four = GST_READ_UINT32_BE (array + i);
+    expect_four = array[i] * (1 << 24) + array[i + 1] * (1 << 16)
+        + array[i + 2] * (1 << 8) + array[i + 3];
+    fail_unless (read_four == expect_four,
+        "GST_READ_UINT32_BE %d: read %d != %d\n", i, read_four, expect_four);
+  }
+
+  /* read 2 64 bits */
+  for (i = 0; i < 2; ++i) {
+    read_eight = GST_READ_UINT64_BE (array + i);
+    expect_eight = array[i] * (1LL << 56) + array[i + 1] * (1LL << 48)
+        + array[i + 2] * (1LL << 40) + array[i + 3] * (1LL << 32)
+        + array[i + 4] * (1 << 24) + array[i + 5] * (1 << 16)
+        + array[i + 6] * (1 << 8) + array[i + 7];
+    fail_unless (read_eight == expect_eight,
+        "GST_READ_UINT64_BE %d: read %" G_GUINT64_FORMAT
+        " != %" G_GUINT64_FORMAT "\n", i, read_eight, expect_eight);
+  }
+
+  /* write 1 64 bit */
+  GST_WRITE_UINT64_BE (&write_array[0], read_eight);
+  fail_unless (memcmp (array + 1, write_array, 8) == 0,
+      "GST_WRITE_UINT64_BE: memcmp failed");
+}
+
+END_TEST
+/* test creation of header from buffer and back again */
+START_TEST (test_buffer)
+{
+  GstBuffer *buffer;
+  GstBuffer *newbuffer;
+
+  guint header_length;
+  guint8 *header;
+
+  /* create buffer */
+  g_message ("Creating a new 8-byte buffer with ts 0.5 sec, dur 1 sec\n");
+  buffer = gst_buffer_new_and_alloc (8);
+  GST_BUFFER_TIMESTAMP (buffer) = (GstClockTime) (GST_SECOND * 0.5);
+  GST_BUFFER_DURATION (buffer) = (GstClockTime) GST_SECOND;
+  GST_BUFFER_OFFSET (buffer) = (guint64) 10;
+  GST_BUFFER_OFFSET_END (buffer) = (guint64) 19;
+  GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_IN_CAPS);
+  GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_SUBBUFFER);
+  memmove (GST_BUFFER_DATA (buffer), "a buffer", 8);
+
+  /* create a buffer with CRC checking */
+  fail_unless (gst_dp_header_from_buffer (buffer, GST_DP_HEADER_FLAG_CRC,
+          &header_length, &header), "Could not create header from buffer.");
+
+  /* validate the header */
+  fail_unless (gst_dp_validate_header (header_length, header),
+      "Could not validate header");
+  /* create a new, empty buffer with the right size */
+  newbuffer = gst_dp_buffer_from_header (header_length, header);
+  fail_unless (newbuffer != NULL, "Could not create a new buffer from header");
+  fail_unless (GST_IS_BUFFER (newbuffer), "Created buffer is not a GstBuffer");
+  /* read/copy the data */
+  memmove (GST_BUFFER_DATA (newbuffer), GST_BUFFER_DATA (buffer),
+      GST_BUFFER_SIZE (buffer));
+  /* validate the buffer */
+  fail_unless (gst_dp_validate_payload (header_length, header,
+          GST_BUFFER_DATA (newbuffer)), "Could not validate payload");
+
+  g_message ("new buffer timestamp: %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (newbuffer)));
+  g_message ("new buffer duration: %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_BUFFER_DURATION (newbuffer)));
+  g_message ("new buffer offset: %" G_GUINT64_FORMAT "\n",
+      GST_BUFFER_OFFSET (newbuffer));
+  g_message ("new buffer offset_end: %" G_GUINT64_FORMAT "\n",
+      GST_BUFFER_OFFSET_END (newbuffer));
+  fail_unless (GST_BUFFER_TIMESTAMP (newbuffer) ==
+      GST_BUFFER_TIMESTAMP (buffer), "Timestamps don't match !");
+  fail_unless (GST_BUFFER_DURATION (newbuffer) == GST_BUFFER_DURATION (buffer),
+      "Durations don't match !");
+  fail_unless (GST_BUFFER_OFFSET (newbuffer) == GST_BUFFER_OFFSET (buffer),
+      "Offsets don't match !");
+  fail_unless (GST_BUFFER_OFFSET_END (newbuffer) ==
+      GST_BUFFER_OFFSET_END (buffer), "Offset ends don't match !");
+  fail_if (GST_BUFFER_FLAG_IS_SET (newbuffer, GST_BUFFER_SUBBUFFER),
+      "GST_BUFFER_SUBBUFFER flag should not have been copied !");
+  fail_unless (GST_BUFFER_FLAG_IS_SET (newbuffer, GST_BUFFER_IN_CAPS),
+      "GST_BUFFER_IN_CAPS flag should have been copied !");
+
+  g_free (header);
+}
+
+END_TEST
+START_TEST (test_caps)
+{
+  gchar *string, *newstring;
+  GstCaps *caps, *newcaps;
+
+  guint header_length;
+  guint8 *header, *payload;
+
+  caps = gst_caps_from_string ("audio/x-raw-float, "
+      "rate = (int) [ 11025, 48000 ], "
+      "channels = (int) [ 1, 2 ], " "endianness = (int) BYTE_ORDER, "
+      "width = (int) 32, " "buffer-frames = (int) 0");
+  string = gst_caps_to_string (caps);
+  g_message ("Created caps: %s\n", string);
+  fail_unless (gst_dp_packet_from_caps (caps, 0, &header_length, &header,
+          &payload), "Could not create packet from caps.");
+
+  /* validate the packet */
+  fail_unless (gst_dp_validate_packet (header_length, header, payload),
+      "Could not validate packet");
+  newcaps = gst_dp_caps_from_packet (header_length, header, payload);
+  fail_unless (newcaps != NULL, "Could not create caps from packet");
+  //g_return_val_if_fail (GST_IS_CAPS (newcaps), -1);
+  newstring = gst_caps_to_string (newcaps);
+  g_message ("Received caps: %s\n", newstring);
+  fail_unless (strcmp (string, newstring) == 0,
+      "Created caps do not match original caps");
+  g_free (string);
+  g_free (newstring);
+}
+
+END_TEST
+START_TEST (test_event)
+{
+  GstEvent *send;
+  GstEvent *receive;
+  guint header_length;
+  guint8 *header, *payload;
+
+  g_message ("Testing EOS event at 1s\n");
+  send = gst_event_new (GST_EVENT_EOS);
+  GST_EVENT_TIMESTAMP (send) = GST_SECOND;
+  fail_unless (gst_dp_packet_from_event (send, GST_DP_HEADER_FLAG_CRC,
+          &header_length, &header, &payload),
+      "Could not create packet from eos event");
+
+  receive = gst_dp_event_from_packet (header_length, header, payload);
+
+  g_message ("EOS, timestamp %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_EVENT_TIMESTAMP (receive)));
+  fail_unless (GST_EVENT_TYPE (receive) == GST_EVENT_EOS,
+      "Received event is not EOS");
+  fail_unless (GST_EVENT_TIMESTAMP (receive) == GST_SECOND,
+      "EOS timestamp is not 1.0 sec");
+  gst_event_unref (send);
+  gst_event_unref (receive);
+
+  g_message ("Testing FLUSH event at 2s\n");
+  send = gst_event_new (GST_EVENT_FLUSH);
+  GST_EVENT_TIMESTAMP (send) = GST_SECOND * 2;
+  fail_unless (gst_dp_packet_from_event (send, GST_DP_HEADER_FLAG_CRC,
+          &header_length, &header, &payload),
+      "Could not create packet from flush event");
+
+  receive = gst_dp_event_from_packet (header_length, header, payload);
+
+  g_message ("Flush, timestamp %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_EVENT_TIMESTAMP (receive)));
+  fail_unless (GST_EVENT_TYPE (receive) == GST_EVENT_FLUSH,
+      "Received event is not flush");
+  fail_unless (GST_EVENT_TIMESTAMP (receive) == GST_SECOND * 2,
+      "Flush timestamp is not 2.0 sec");
+  gst_event_unref (send);
+  gst_event_unref (receive);
+
+  g_message ("Testing SEEK event with 1 second at 3 seconds\n");
+  send = gst_event_new_seek (GST_FORMAT_TIME, GST_SECOND);
+  GST_EVENT_TIMESTAMP (send) = GST_SECOND * 3;
+  fail_unless (gst_dp_packet_from_event (send, GST_DP_HEADER_FLAG_CRC,
+          &header_length, &header, &payload),
+      "Could not create packet from seek event");
+
+  receive = gst_dp_event_from_packet (header_length, header, payload);
+
+  g_message ("Seek, timestamp %" GST_TIME_FORMAT ", to %" GST_TIME_FORMAT "\n",
+      GST_TIME_ARGS (GST_EVENT_TIMESTAMP (receive)),
+      GST_TIME_ARGS (GST_EVENT_SEEK_OFFSET (receive)));
+  fail_unless (GST_EVENT_TYPE (receive) == GST_EVENT_SEEK,
+      "Returned event is not seek");
+  fail_unless (GST_EVENT_TIMESTAMP (receive) == GST_SECOND * 3,
+      "Seek timestamp is not 3.0 sec");
+  fail_unless (GST_EVENT_SEEK_FORMAT (receive) == GST_FORMAT_TIME,
+      "Seek format is not time");
+  fail_unless (GST_EVENT_SEEK_OFFSET (receive) == GST_SECOND,
+      "Seek offset is not 1.0 sec");
+  gst_event_unref (send);
+  gst_event_unref (receive);
+}
+END_TEST Suite *
+gst_object_suite (void)
+{
+  Suite *s = suite_create ("data protocol");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_conversion);
+  tcase_add_test (tc_chain, test_buffer);
+  tcase_add_test (tc_chain, test_caps);
+  tcase_add_test (tc_chain, test_event);
+
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = gst_object_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+  gst_dp_init ();
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}
diff --git a/tests/check/pipelines/simple-launch-lines.c b/tests/check/pipelines/simple-launch-lines.c
new file mode 100644 (file)
index 0000000..f812392
--- /dev/null
@@ -0,0 +1,127 @@
+/* GStreamer
+ * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
+ *
+ * simple_launch_lines.c: Unit test for simple pipelines
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "../gstcheck.h"
+
+
+static GstElement *
+setup_pipeline (gchar * pipe_descr)
+{
+  GstElement *pipeline;
+
+  pipeline = gst_parse_launch (pipe_descr, NULL);
+  g_return_val_if_fail (GST_IS_PIPELINE (pipeline), NULL);
+  return pipeline;
+}
+
+/* events is a mask of expected events. tevent is the expected terminal event.
+   the poll call will time out after half a second.
+ */
+static void
+run_pipeline (GstElement * pipe, gchar * descr,
+    GstMessageType events, GstMessageType tevent)
+{
+  GstBus *bus;
+  GstMessageType revent;
+
+  bus = gst_element_get_bus (pipe);
+  g_assert (bus);
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+  while (1) {
+    revent = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
+
+    /* always have to pop the message before getting back into poll */
+    if (revent != GST_MESSAGE_UNKNOWN)
+      gst_message_unref (gst_bus_pop (bus));
+
+    if (revent == tevent) {
+      break;
+    } else if (revent == GST_MESSAGE_UNKNOWN) {
+      g_critical ("Unexpected timeout in gst_bus_poll, looking for %d: %s",
+          tevent, descr);
+      break;
+    } else if (revent & events) {
+      continue;
+    }
+    g_critical ("Unexpected message received of type %d, looking for %d: %s",
+        revent, tevent, descr);
+  }
+
+  gst_element_set_state (pipe, GST_STATE_NULL);
+  gst_object_unref (GST_OBJECT (pipe));
+}
+
+START_TEST (test_2_elements)
+{
+  gchar *s;
+
+  s = "fakesrc has-loop=false ! fakesink has-loop=true";
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN);
+
+  s = "fakesrc has-loop=true ! fakesink has-loop=false";
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN);
+
+  s = "fakesrc has-loop=false num-buffers=10 ! fakesink has-loop=true";
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_EOS);
+
+  s = "fakesrc has-loop=true num-buffers=10 ! fakesink has-loop=false";
+  run_pipeline (setup_pipeline (s), s,
+      GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_EOS);
+
+  s = "fakesrc has-loop=false ! fakesink has-loop=false";
+  ASSERT_CRITICAL (run_pipeline (setup_pipeline (s), s,
+          GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN));
+}
+END_TEST Suite *
+simple_launch_lines_suite (void)
+{
+  Suite *s = suite_create ("Pipelines");
+  TCase *tc_chain = tcase_create ("linear");
+
+  /* time out after 20s, not the default 3 */
+  tcase_set_timeout (tc_chain, 20);
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_2_elements);
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = simple_launch_lines_suite ();
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}