pub const ext = @import("ext.zig");
const gstcheck = @This();

const std = @import("std");
const compat = @import("compat");
const gst = @import("gst1");
const gobject = @import("gobject2");
const glib = @import("glib2");
const gmodule = @import("gmodule2");
/// GstTestClock is an implementation of `gst.Clock` which has different
/// behaviour compared to `gst.SystemClock`. Time for `gst.SystemClock` advances
/// according to the system time, while time for `gstcheck.TestClock` changes only
/// when `gstcheck.TestClock.setTime` or `gstcheck.TestClock.advanceTime` are
/// called. `gstcheck.TestClock` provides unit tests with the possibility to
/// precisely advance the time in a deterministic manner, independent of the
/// system time or any other external factors.
///
/// ## Advancing the time of a
///
/// ```
///   `include` <gst/gst.h>
///   `include` <gst/check/gsttestclock.h>
///
///   GstClock *clock;
///   GstTestClock *test_clock;
///
///   clock = gst_test_clock_new ();
///   test_clock = GST_TEST_CLOCK (clock);
///   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
///   gst_test_clock_advance_time ( test_clock, 1 * GST_SECOND);
///   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
///   g_usleep (10 * G_USEC_PER_SEC);
///   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
///   gst_test_clock_set_time (test_clock, 42 * GST_SECOND);
///   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
///   ...
/// ```
///
/// `gst.Clock` allows for setting up single shot or periodic clock notifications
/// as well as waiting for these notifications synchronously (using
/// `gst.Clock.idWait`) or asynchronously (using `gst.Clock.idWaitAsync` or
/// `gst.Clock.idWaitAsync`). This is used by many GStreamer elements,
/// among them `GstBaseSrc` and `GstBaseSink`.
///
/// `gstcheck.TestClock` keeps track of these clock notifications. By calling
/// `gstcheck.TestClock.waitForNextPendingId` or
/// `gstcheck.TestClock.waitForMultiplePendingIds` a unit tests may wait for the
/// next one or several clock notifications to be requested. Additionally unit
/// tests may release blocked waits in a controlled fashion by calling
/// `gstcheck.TestClock.processNextClockId`. This way a unit test can control the
/// inaccuracy (jitter) of clock notifications, since the test can decide to
/// release blocked waits when the clock time has advanced exactly to, or past,
/// the requested clock notification time.
///
/// There are also interfaces for determining if a notification belongs to a
/// `gstcheck.TestClock` or not, as well as getting the number of requested clock
/// notifications so far.
///
/// N.B.: When a unit test waits for a certain amount of clock notifications to
/// be requested in `gstcheck.TestClock.waitForNextPendingId` or
/// `gstcheck.TestClock.waitForMultiplePendingIds` then these functions may block
/// for a long time. If they block forever then the expected clock notifications
/// were never requested from `gstcheck.TestClock`, and so the assumptions in the code
/// of the unit test are wrong. The unit test case runner in gstcheck is
/// expected to catch these cases either by the default test case timeout or the
/// one set for the unit test by calling tcase_set_timeout\(\).
///
/// The sample code below assumes that the element under test will delay a
/// buffer pushed on the source pad by some latency until it arrives on the sink
/// pad. Moreover it is assumed that the element will at some point call
/// `gst.Clock.idWait` to synchronously wait for a specific time. The first
/// buffer sent will arrive exactly on time only delayed by the latency. The
/// second buffer will arrive a little late (7ms) due to simulated jitter in the
/// clock notification.
///
/// ## Demonstration of how to work with clock notifications and
///
/// ```
///   `include` <gst/gst.h>
///   `include` <gst/check/gstcheck.h>
///   `include` <gst/check/gsttestclock.h>
///
///   GstClockTime latency;
///   GstElement *element;
///   GstPad *srcpad;
///   GstClock *clock;
///   GstTestClock *test_clock;
///   GstBuffer buf;
///   GstClockID pending_id;
///   GstClockID processed_id;
///
///   latency = 42 * GST_MSECOND;
///   element = create_element (latency, ...);
///   srcpad = get_source_pad (element);
///
///   clock = gst_test_clock_new ();
///   test_clock = GST_TEST_CLOCK (clock);
///   gst_element_set_clock (element, clock);
///
///   GST_INFO ("Set time, create and push the first buffer\n");
///   gst_test_clock_set_time (test_clock, 0);
///   buf = create_test_buffer (gst_clock_get_time (clock), ...);
///   gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK);
///
///   GST_INFO ("Block until element is waiting for a clock notification\n");
///   gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id);
///   GST_INFO ("Advance to the requested time of the clock notification\n");
///   gst_test_clock_advance_time (test_clock, latency);
///   GST_INFO ("Release the next blocking wait and make sure it is the one from element\n");
///   processed_id = gst_test_clock_process_next_clock_id (test_clock);
///   g_assert (processed_id == pending_id);
///   g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK);
///   gst_clock_id_unref (pending_id);
///   gst_clock_id_unref (processed_id);
///
///   GST_INFO ("Validate that element produced an output buffer and check its timestamp\n");
///   g_assert_cmpint (get_number_of_output_buffer (...), ==, 1);
///   buf = get_buffer_pushed_by_element (element, ...);
///   g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==, latency);
///   gst_buffer_unref (buf);
///   GST_INFO ("Check that element does not wait for any clock notification\n");
///   g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL));
///
///   GST_INFO ("Set time, create and push the second buffer\n");
///   gst_test_clock_advance_time (test_clock, 10 * GST_SECOND);
///   buf = create_test_buffer (gst_clock_get_time (clock), ...);
///   gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK);
///
///   GST_INFO ("Block until element is waiting for a new clock notification\n");
///   (gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id);
///   GST_INFO ("Advance past 7ms beyond the requested time of the clock notification\n");
///   gst_test_clock_advance_time (test_clock, latency + 7 * GST_MSECOND);
///   GST_INFO ("Release the next blocking wait and make sure it is the one from element\n");
///   processed_id = gst_test_clock_process_next_clock_id (test_clock);
///   g_assert (processed_id == pending_id);
///   g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK);
///   gst_clock_id_unref (pending_id);
///   gst_clock_id_unref (processed_id);
///
///   GST_INFO ("Validate that element produced an output buffer and check its timestamp\n");
///   g_assert_cmpint (get_number_of_output_buffer (...), ==, 1);
///   buf = get_buffer_pushed_by_element (element, ...);
///   g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==,
///       10 * GST_SECOND + latency + 7 * GST_MSECOND);
///   gst_buffer_unref (buf);
///   GST_INFO ("Check that element does not wait for any clock notification\n");
///   g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL));
///   ...
/// ```
///
/// Since `gstcheck.TestClock` is only supposed to be used in unit tests it calls
/// `g_assert`, `g_assert_cmpint` or `g_assert_cmpuint` to validate all function
/// arguments. This will highlight any issues with the unit test code itself.
pub const TestClock = extern struct {
    pub const Parent = gst.Clock;
    pub const Implements = [_]type{};
    pub const Class = gstcheck.TestClockClass;
    f_parent: gst.Clock,
    f_priv: ?*gstcheck.TestClockPrivate,

    pub const virtual_methods = struct {};

    pub const properties = struct {
        pub const clock_type = struct {
            pub const name = "clock-type";

            pub const Type = gst.ClockType;
        };

        /// When a `gstcheck.TestClock` is constructed it will have a certain start time set.
        /// If the clock was created using `gstcheck.TestClock.newWithStartTime` then
        /// this property contains the value of the `start_time` argument. If
        /// `gstcheck.TestClock.new` was called the clock started at time zero, and thus
        /// this property contains the value 0.
        pub const start_time = struct {
            pub const name = "start-time";

            pub const Type = u64;
        };
    };

    pub const signals = struct {};

    /// Finds the latest time inside the list.
    ///
    /// MT safe.
    extern fn gst_test_clock_id_list_get_latest_time(p_pending_list: ?*const glib.List) gst.ClockTime;
    pub const idListGetLatestTime = gst_test_clock_id_list_get_latest_time;

    /// Creates a new test clock with its time set to zero.
    ///
    /// MT safe.
    extern fn gst_test_clock_new() *gstcheck.TestClock;
    pub const new = gst_test_clock_new;

    /// Creates a new test clock with its time set to the specified time.
    ///
    /// MT safe.
    extern fn gst_test_clock_new_with_start_time(p_start_time: gst.ClockTime) *gstcheck.TestClock;
    pub const newWithStartTime = gst_test_clock_new_with_start_time;

    /// Advances the time of the `test_clock` by the amount given by `delta`. The
    /// time of `test_clock` is monotonically increasing, therefore providing a
    /// `delta` which is negative or zero is a programming error.
    ///
    /// MT safe.
    extern fn gst_test_clock_advance_time(p_test_clock: *TestClock, p_delta: gst.ClockTimeDiff) void;
    pub const advanceTime = gst_test_clock_advance_time;

    /// A "crank" consists of three steps:
    /// 1: Wait for a `gst.ClockID` to be registered with the `gstcheck.TestClock`.
    /// 2: Advance the `gstcheck.TestClock` to the time the `gst.ClockID` is waiting, unless
    ///    the clock time is already passed the clock id (Since: 1.18).
    /// 3: Release the `gst.ClockID` wait.
    /// A "crank" can be though of as the notion of
    /// manually driving the clock forward to its next logical step.
    extern fn gst_test_clock_crank(p_test_clock: *TestClock) c_int;
    pub const crank = gst_test_clock_crank;

    /// Retrieve the requested time for the next pending clock notification.
    ///
    /// MT safe.
    extern fn gst_test_clock_get_next_entry_time(p_test_clock: *TestClock) gst.ClockTime;
    pub const getNextEntryTime = gst_test_clock_get_next_entry_time;

    /// Checks whether `test_clock` was requested to provide the clock notification
    /// given by `id`.
    ///
    /// MT safe.
    extern fn gst_test_clock_has_id(p_test_clock: *TestClock, p_id: gst.ClockID) c_int;
    pub const hasId = gst_test_clock_has_id;

    /// Determine the number of pending clock notifications that have been
    /// requested from the `test_clock`.
    ///
    /// MT safe.
    extern fn gst_test_clock_peek_id_count(p_test_clock: *TestClock) c_uint;
    pub const peekIdCount = gst_test_clock_peek_id_count;

    /// Determines if the `pending_id` is the next clock notification scheduled to
    /// be triggered given the current time of the `test_clock`.
    ///
    /// MT safe.
    extern fn gst_test_clock_peek_next_pending_id(p_test_clock: *TestClock, p_pending_id: ?*gst.ClockID) c_int;
    pub const peekNextPendingId = gst_test_clock_peek_next_pending_id;

    /// Processes and releases the pending ID.
    ///
    /// MT safe.
    extern fn gst_test_clock_process_id(p_test_clock: *TestClock, p_pending_id: gst.ClockID) c_int;
    pub const processId = gst_test_clock_process_id;

    /// Processes and releases the pending IDs in the list.
    ///
    /// MT safe.
    extern fn gst_test_clock_process_id_list(p_test_clock: *TestClock, p_pending_list: ?*const glib.List) c_uint;
    pub const processIdList = gst_test_clock_process_id_list;

    /// MT safe.
    extern fn gst_test_clock_process_next_clock_id(p_test_clock: *TestClock) gst.ClockID;
    pub const processNextClockId = gst_test_clock_process_next_clock_id;

    /// Sets the time of `test_clock` to the time given by `new_time`. The time of
    /// `test_clock` is monotonically increasing, therefore providing a `new_time`
    /// which is earlier or equal to the time of the clock as given by
    /// `gst.Clock.getTime` is a programming error.
    ///
    /// MT safe.
    extern fn gst_test_clock_set_time(p_test_clock: *TestClock, p_new_time: gst.ClockTime) void;
    pub const setTime = gst_test_clock_set_time;

    /// Blocks until at least `count` clock notifications have been requested from
    /// `test_clock`, or the timeout expires.
    ///
    /// MT safe.
    extern fn gst_test_clock_timed_wait_for_multiple_pending_ids(p_test_clock: *TestClock, p_count: c_uint, p_timeout_ms: c_uint, p_pending_list: ?**glib.List) c_int;
    pub const timedWaitForMultiplePendingIds = gst_test_clock_timed_wait_for_multiple_pending_ids;

    /// Blocks until at least `count` clock notifications have been requested from
    /// `test_clock`. There is no timeout for this wait, see the main description of
    /// `gstcheck.TestClock`.
    ///
    /// MT safe.
    extern fn gst_test_clock_wait_for_multiple_pending_ids(p_test_clock: *TestClock, p_count: c_uint, p_pending_list: ?**glib.List) void;
    pub const waitForMultiplePendingIds = gst_test_clock_wait_for_multiple_pending_ids;

    /// Waits until a clock notification is requested from `test_clock`. There is no
    /// timeout for this wait, see the main description of `gstcheck.TestClock`. A reference
    /// to the pending clock notification is stored in `pending_id`.
    ///
    /// MT safe.
    extern fn gst_test_clock_wait_for_next_pending_id(p_test_clock: *TestClock, p_pending_id: ?*gst.ClockID) void;
    pub const waitForNextPendingId = gst_test_clock_wait_for_next_pending_id;

    /// Blocks until at least `count` clock notifications have been requested from
    /// `test_clock`. There is no timeout for this wait, see the main description of
    /// `gstcheck.TestClock`.
    extern fn gst_test_clock_wait_for_pending_id_count(p_test_clock: *TestClock, p_count: c_uint) void;
    pub const waitForPendingIdCount = gst_test_clock_wait_for_pending_id_count;

    extern fn gst_test_clock_get_type() usize;
    pub const getGObjectType = gst_test_clock_get_type;

    extern fn g_object_ref(p_self: *gstcheck.TestClock) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstcheck.TestClock) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *TestClock, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const CheckABIStruct = extern struct {
    /// The name of the structure
    f_name: ?[*:0]const u8,
    /// The current size of a structure
    f_size: c_int,
    /// The reference size of the structure
    f_abi_size: c_int,

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Opaque structure containing data about a log filter
/// function.
pub const CheckLogFilter = opaque {
    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// `gstcheck.Harness` is meant to make writing unit test for GStreamer much easier.
/// It can be thought of as a way of treating a `gst.Element` as a black box,
/// deterministically feeding it data, and controlling what data it outputs.
///
/// The basic structure of `gstcheck.Harness` is two "floating" `GstPads` that connect
/// to the harnessed `gst.Element` src and sink `GstPads` like so:
///
/// ```
///           __________________________
///  _____   |  _____            _____  |   _____
/// |     |  | |     |          |     | |  |     |
/// | src |--+-| sink|  Element | src |-+--| sink|
/// |_____|  | |_____|          |_____| |  |_____|
///          |__________________________|
///
/// ```
///
/// With this, you can now simulate any environment the `gst.Element` might find
/// itself in. By specifying the `gst.Caps` of the harness `GstPads`, using
/// functions like `gstcheck.Harness.setSrcCaps` or `gstcheck.Harness.setSinkCapsStr`,
/// you can test how the `gst.Element` interacts with different caps sets.
///
/// Your harnessed `gst.Element` can of course also be a bin, and using
/// `gstcheck.harnessNewParse` supporting standard gst-launch syntax, you can
/// easily test a whole pipeline instead of just one element.
///
/// You can then go on to push `GstBuffers` and `GstEvents` on to the srcpad,
/// using functions like `gstcheck.Harness.push` and `gstcheck.Harness.pushEvent`, and
/// then pull them out to examine them with `gstcheck.Harness.pull` and
/// `gstcheck.Harness.pullEvent`.
///
/// ## A simple buffer-in buffer-out example
///
/// ```
///   `include` <gst/gst.h>
///   `include` <gst/check/gstharness.h>
///   GstHarness *h;
///   GstBuffer *in_buf;
///   GstBuffer *out_buf;
///
///   // attach the harness to the src and sink pad of GstQueue
///   h = gst_harness_new ("queue");
///
///   // we must specify a caps before pushing buffers
///   gst_harness_set_src_caps_str (h, "mycaps");
///
///   // create a buffer of size 42
///   in_buf = gst_harness_create_buffer (h, 42);
///
///   // push the buffer into the queue
///   gst_harness_push (h, in_buf);
///
///   // pull the buffer from the queue
///   out_buf = gst_harness_pull (h);
///
///   // validate the buffer in is the same as buffer out
///   fail_unless (in_buf == out_buf);
///
///   // cleanup
///   gst_buffer_unref (out_buf);
///   gst_harness_teardown (h);
///
/// ```
///
/// Another main feature of the `gstcheck.Harness` is its integration with the
/// `gstcheck.TestClock`. Operating the `gstcheck.TestClock` can be very challenging, but
/// `gstcheck.Harness` simplifies some of the most desired actions a lot, like wanting
/// to manually advance the clock while at the same time releasing a `gst.ClockID`
/// that is waiting, with functions like `gstcheck.Harness.crankSingleClockWait`.
///
/// `gstcheck.Harness` also supports sub-harnesses, as a way of generating and
/// validating data. A sub-harness is another `gstcheck.Harness` that is managed by
/// the "parent" harness, and can either be created by using the standard
/// gst_harness_new type functions directly on the (GstHarness *)->src_harness,
/// or using the much more convenient `gstcheck.Harness.addSrc` or
/// `gstcheck.Harness.addSinkParse`. If you have a decoder-element you want to test,
/// (like vp8dec) it can be very useful to add a src-harness with both a
/// src-element (videotestsrc) and an encoder (vp8enc) to feed the decoder data
/// with different configurations, by simply doing:
///
/// ```
///   GstHarness * h = gst_harness_new ("vp8dec");
///   gst_harness_add_src_parse (h, "videotestsrc is-live=1 ! vp8enc", TRUE);
/// ```
///
/// and then feeding it data with:
///
/// ```
/// gst_harness_push_from_src (h);
/// ```
pub const Harness = extern struct {
    /// the element inside the harness
    f_element: ?*gst.Element,
    /// the internal harness source pad
    f_srcpad: ?*gst.Pad,
    /// the internal harness sink pad
    f_sinkpad: ?*gst.Pad,
    /// the source (input) harness (if any)
    f_src_harness: ?*gstcheck.Harness,
    /// the sink (output) harness (if any)
    f_sink_harness: ?*gstcheck.Harness,
    f_priv: ?*gstcheck.HarnessPrivate,

    /// Creates a new harness. Works like `gstcheck.harnessNewWithPadnames`, except it
    /// assumes the `gst.Element` sinkpad is named "sink" and srcpad is named "src"
    ///
    /// MT safe.
    extern fn gst_harness_new(p_element_name: [*:0]const u8) ?*gstcheck.Harness;
    pub const new = gst_harness_new;

    /// Creates a new empty harness. Use `gstcheck.Harness.addElementFull` to add
    /// an `gst.Element` to it.
    ///
    /// MT safe.
    extern fn gst_harness_new_empty() ?*gstcheck.Harness;
    pub const newEmpty = gst_harness_new_empty;

    /// Creates a new harness.
    ///
    /// MT safe.
    extern fn gst_harness_new_full(p_element: *gst.Element, p_hsrc: ?*gst.StaticPadTemplate, p_element_sinkpad_name: ?[*:0]const u8, p_hsink: ?*gst.StaticPadTemplate, p_element_srcpad_name: ?[*:0]const u8) ?*gstcheck.Harness;
    pub const newFull = gst_harness_new_full;

    /// Creates a new harness, parsing the `launchline` and putting that in a `gst.Bin`,
    /// and then attches the harness to the bin.
    ///
    /// MT safe.
    extern fn gst_harness_new_parse(p_launchline: [*:0]const u8) ?*gstcheck.Harness;
    pub const newParse = gst_harness_new_parse;

    /// Creates a new harness. Works in the same way as `gstcheck.harnessNewFull`, only
    /// that generic padtemplates are used for the harness src and sinkpads, which
    /// will be sufficient in most usecases.
    ///
    /// MT safe.
    extern fn gst_harness_new_with_element(p_element: *gst.Element, p_element_sinkpad_name: ?[*:0]const u8, p_element_srcpad_name: ?[*:0]const u8) ?*gstcheck.Harness;
    pub const newWithElement = gst_harness_new_with_element;

    /// Creates a new harness. Works like `gstcheck.harnessNewWithElement`,
    /// except you specify the factoryname of the `gst.Element`
    ///
    /// MT safe.
    extern fn gst_harness_new_with_padnames(p_element_name: [*:0]const u8, p_element_sinkpad_name: ?[*:0]const u8, p_element_srcpad_name: ?[*:0]const u8) ?*gstcheck.Harness;
    pub const newWithPadnames = gst_harness_new_with_padnames;

    /// Creates a new harness, like `gstcheck.harnessNewFull`, except it
    /// assumes the `gst.Element` sinkpad is named "sink" and srcpad is named "src"
    ///
    /// MT safe.
    extern fn gst_harness_new_with_templates(p_element_name: [*:0]const u8, p_hsrc: ?*gst.StaticPadTemplate, p_hsink: ?*gst.StaticPadTemplate) ?*gstcheck.Harness;
    pub const newWithTemplates = gst_harness_new_with_templates;

    /// Stop the running `gstcheck.HarnessThread`
    ///
    /// MT safe.
    extern fn gst_harness_stress_thread_stop(p_t: *gstcheck.HarnessThread) c_uint;
    pub const stressThreadStop = gst_harness_stress_thread_stop;

    /// Adds a `gst.Element` to an empty `gstcheck.Harness`
    ///
    /// MT safe.
    extern fn gst_harness_add_element_full(p_h: *Harness, p_element: *gst.Element, p_hsrc: ?*gst.StaticPadTemplate, p_element_sinkpad_name: ?[*:0]const u8, p_hsink: ?*gst.StaticPadTemplate, p_element_srcpad_name: ?[*:0]const u8) void;
    pub const addElementFull = gst_harness_add_element_full;

    /// Links the specified `gst.Pad` the `GstHarness` srcpad.
    ///
    /// MT safe.
    extern fn gst_harness_add_element_sink_pad(p_h: *Harness, p_sinkpad: *gst.Pad) void;
    pub const addElementSinkPad = gst_harness_add_element_sink_pad;

    /// Links the specified `gst.Pad` the `GstHarness` sinkpad. This can be useful if
    /// perhaps the srcpad did not exist at the time of creating the harness,
    /// like a demuxer that provides a sometimes-pad after receiving data.
    ///
    /// MT safe.
    extern fn gst_harness_add_element_src_pad(p_h: *Harness, p_srcpad: *gst.Pad) void;
    pub const addElementSrcPad = gst_harness_add_element_src_pad;

    /// Parses the `launchline` and puts that in a `gst.Bin`,
    /// and then attches the supplied `gstcheck.Harness` to the bin.
    ///
    /// MT safe.
    extern fn gst_harness_add_parse(p_h: *Harness, p_launchline: [*:0]const u8) void;
    pub const addParse = gst_harness_add_parse;

    /// A convenience function to allows you to call gst_pad_add_probe on a
    /// `gst.Pad` of a `gst.Element` that are residing inside the `gstcheck.Harness`,
    /// by using normal gst_pad_add_probe syntax
    ///
    /// MT safe.
    extern fn gst_harness_add_probe(p_h: *Harness, p_element_name: [*:0]const u8, p_pad_name: [*:0]const u8, p_mask: gst.PadProbeType, p_callback: gst.PadProbeCallback, p_user_data: ?*anyopaque, p_destroy_data: ?glib.DestroyNotify) void;
    pub const addProbe = gst_harness_add_probe;

    /// Add api with params as one of the supported metadata API to propose when
    /// receiving an allocation query.
    ///
    /// MT safe.
    extern fn gst_harness_add_propose_allocation_meta(p_h: *Harness, p_api: usize, p_params: ?*const gst.Structure) void;
    pub const addProposeAllocationMeta = gst_harness_add_propose_allocation_meta;

    /// Similar to gst_harness_add_sink_harness, this is a convenience to
    /// directly create a sink-harness using the `sink_element_name` name specified.
    ///
    /// MT safe.
    extern fn gst_harness_add_sink(p_h: *Harness, p_sink_element_name: [*:0]const u8) void;
    pub const addSink = gst_harness_add_sink;

    /// Similar to gst_harness_add_src, this allows you to send the data coming out
    /// of your harnessed `gst.Element` to a sink-element, allowing to test different
    /// responses the element output might create in sink elements. An example might
    /// be an existing sink providing some analytical data on the input it receives that
    /// can be useful to your testing. If the goal is to test a sink-element itself,
    /// this is better achieved using gst_harness_new directly on the sink.
    ///
    /// If a sink-harness already exists it will be replaced.
    ///
    /// MT safe.
    extern fn gst_harness_add_sink_harness(p_h: *Harness, p_sink_harness: *gstcheck.Harness) void;
    pub const addSinkHarness = gst_harness_add_sink_harness;

    /// Similar to gst_harness_add_sink, this allows you to specify a launch-line
    /// instead of just an element name. See gst_harness_add_src_parse for details.
    ///
    /// MT safe.
    extern fn gst_harness_add_sink_parse(p_h: *Harness, p_launchline: [*:0]const u8) void;
    pub const addSinkParse = gst_harness_add_sink_parse;

    /// Similar to gst_harness_add_src_harness, this is a convenience to
    /// directly create a src-harness using the `src_element_name` name specified.
    ///
    /// MT safe.
    extern fn gst_harness_add_src(p_h: *Harness, p_src_element_name: [*:0]const u8, p_has_clock_wait: c_int) void;
    pub const addSrc = gst_harness_add_src;

    /// A src-harness is a great way of providing the `gstcheck.Harness` with data.
    /// By adding a src-type `gst.Element`, it is then easy to use functions like
    /// gst_harness_push_from_src or gst_harness_src_crank_and_push_many
    /// to provide your harnessed element with input. The `has_clock_wait` variable
    /// is a great way to control you src-element with, in that you can have it
    /// produce a buffer for you by simply cranking the clock, and not have it
    /// spin out of control producing buffers as fast as possible.
    ///
    /// If a src-harness already exists it will be replaced.
    ///
    /// MT safe.
    extern fn gst_harness_add_src_harness(p_h: *Harness, p_src_harness: *gstcheck.Harness, p_has_clock_wait: c_int) void;
    pub const addSrcHarness = gst_harness_add_src_harness;

    /// Similar to gst_harness_add_src, this allows you to specify a launch-line,
    /// which can be useful for both having more then one `gst.Element` acting as your
    /// src (Like a src producing raw buffers, and then an encoder, providing encoded
    /// data), but also by allowing you to set properties like "is-live" directly on
    /// the elements.
    ///
    /// MT safe.
    extern fn gst_harness_add_src_parse(p_h: *Harness, p_launchline: [*:0]const u8, p_has_clock_wait: c_int) void;
    pub const addSrcParse = gst_harness_add_src_parse;

    /// The number of `GstBuffers` currently in the `gstcheck.Harness` sinkpad `glib.AsyncQueue`
    ///
    /// MT safe.
    extern fn gst_harness_buffers_in_queue(p_h: *Harness) c_uint;
    pub const buffersInQueue = gst_harness_buffers_in_queue;

    /// The total number of `GstBuffers` that has arrived on the `gstcheck.Harness` sinkpad.
    /// This number includes buffers that have been dropped as well as buffers
    /// that have already been pulled out.
    ///
    /// MT safe.
    extern fn gst_harness_buffers_received(p_h: *Harness) c_uint;
    pub const buffersReceived = gst_harness_buffers_received;

    /// Similar to `gstcheck.Harness.crankSingleClockWait`, this is the function to use
    /// if your harnessed element(s) are using more then one gst_clock_id_wait.
    /// Failing to do so can (and will) make it racy which `gst.ClockID` you actually
    /// are releasing, where as this function will process all the waits at the
    /// same time, ensuring that one thread can't register another wait before
    /// both are released.
    ///
    /// MT safe.
    extern fn gst_harness_crank_multiple_clock_waits(p_h: *Harness, p_waits: c_uint) c_int;
    pub const crankMultipleClockWaits = gst_harness_crank_multiple_clock_waits;

    /// A "crank" consists of three steps:
    /// 1: Wait for a `gst.ClockID` to be registered with the `gstcheck.TestClock`.
    /// 2: Advance the `gstcheck.TestClock` to the time the `gst.ClockID` is waiting for.
    /// 3: Release the `gst.ClockID` wait.
    /// Together, this provides an easy way to not have to think about the details
    /// around clocks and time, but still being able to write deterministic tests
    /// that are dependent on this. A "crank" can be though of as the notion of
    /// manually driving the clock forward to its next logical step.
    ///
    /// MT safe.
    extern fn gst_harness_crank_single_clock_wait(p_h: *Harness) c_int;
    pub const crankSingleClockWait = gst_harness_crank_single_clock_wait;

    /// Allocates a buffer using a `gst.BufferPool` if present, or else using the
    /// configured `gst.Allocator` and `gst.AllocationParams`
    ///
    /// MT safe.
    extern fn gst_harness_create_buffer(p_h: *Harness, p_size: usize) *gst.Buffer;
    pub const createBuffer = gst_harness_create_buffer;

    /// Allows you to dump the `GstBuffers` the `gstcheck.Harness` sinkpad `glib.AsyncQueue`
    /// to a file.
    ///
    /// MT safe.
    extern fn gst_harness_dump_to_file(p_h: *Harness, p_filename: [*:0]const u8) void;
    pub const dumpToFile = gst_harness_dump_to_file;

    /// The number of `GstEvents` currently in the `gstcheck.Harness` sinkpad `glib.AsyncQueue`
    ///
    /// MT safe.
    extern fn gst_harness_events_in_queue(p_h: *Harness) c_uint;
    pub const eventsInQueue = gst_harness_events_in_queue;

    /// The total number of `GstEvents` that has arrived on the `gstcheck.Harness` sinkpad
    /// This number includes events handled by the harness as well as events
    /// that have already been pulled out.
    ///
    /// MT safe.
    extern fn gst_harness_events_received(p_h: *Harness) c_uint;
    pub const eventsReceived = gst_harness_events_received;

    /// Most useful in conjunction with gst_harness_new_parse, this will scan the
    /// `GstElements` inside the `gstcheck.Harness`, and check if any of them matches
    /// `element_name`. Typical usecase being that you need to access one of the
    /// harnessed elements for properties and/or signals.
    ///
    /// MT safe.
    extern fn gst_harness_find_element(p_h: *Harness, p_element_name: [*:0]const u8) ?*gst.Element;
    pub const findElement = gst_harness_find_element;

    /// A convenience function to allows you to call g_object_get on a `gst.Element`
    /// that are residing inside the `gstcheck.Harness`, by using normal g_object_get
    /// syntax.
    ///
    /// MT safe.
    extern fn gst_harness_get(p_h: *Harness, p_element_name: [*:0]const u8, p_first_property_name: [*:0]const u8, ...) void;
    pub const get = gst_harness_get;

    /// Gets the `allocator` and its `params` that has been decided to use after an
    /// allocation query.
    ///
    /// MT safe.
    extern fn gst_harness_get_allocator(p_h: *Harness, p_allocator: ?**gst.Allocator, p_params: ?*gst.AllocationParams) void;
    pub const getAllocator = gst_harness_get_allocator;

    /// Get the timestamp of the last `gst.Buffer` pushed on the `gstcheck.Harness` srcpad,
    /// typically with gst_harness_push or gst_harness_push_from_src.
    ///
    /// MT safe.
    extern fn gst_harness_get_last_pushed_timestamp(p_h: *Harness) gst.ClockTime;
    pub const getLastPushedTimestamp = gst_harness_get_last_pushed_timestamp;

    /// Get the `gstcheck.TestClock`. Useful if specific operations on the testclock is
    /// needed.
    ///
    /// MT safe.
    extern fn gst_harness_get_testclock(p_h: *Harness) ?*gstcheck.TestClock;
    pub const getTestclock = gst_harness_get_testclock;

    /// This will set the harnessed `gst.Element` to `GST_STATE_PLAYING`.
    /// `GstElements` without a sink-`gst.Pad` and with the `GST_ELEMENT_FLAG_SOURCE`
    /// flag set is considered a src `gst.Element`
    /// Non-src `GstElements` (like sinks and filters) are automatically set to
    /// playing by the `gstcheck.Harness`, but src `GstElements` are not to avoid them
    /// starting to produce buffers.
    /// Hence, for src `gst.Element` you must call `gstcheck.Harness.play` explicitly.
    ///
    /// MT safe.
    extern fn gst_harness_play(p_h: *Harness) void;
    pub const play = gst_harness_play;

    /// Pulls a `gst.Buffer` from the `glib.AsyncQueue` on the `gstcheck.Harness` sinkpad. The pull
    /// will timeout in 60 seconds. This is the standard way of getting a buffer
    /// from a harnessed `gst.Element`.
    ///
    /// MT safe.
    extern fn gst_harness_pull(p_h: *Harness) ?*gst.Buffer;
    pub const pull = gst_harness_pull;

    /// Pulls an `gst.Event` from the `glib.AsyncQueue` on the `gstcheck.Harness` sinkpad.
    /// Timeouts after 60 seconds similar to gst_harness_pull.
    ///
    /// MT safe.
    extern fn gst_harness_pull_event(p_h: *Harness) ?*gst.Event;
    pub const pullEvent = gst_harness_pull_event;

    /// Pulls a `gst.Buffer` from the `glib.AsyncQueue` on the `gstcheck.Harness` sinkpad. The pull
    /// will block until an EOS event is received, or timeout in 60 seconds.
    /// MT safe.
    extern fn gst_harness_pull_until_eos(p_h: *Harness, p_buf: ?**gst.Buffer) c_int;
    pub const pullUntilEos = gst_harness_pull_until_eos;

    /// Pulls an `gst.Event` from the `glib.AsyncQueue` on the `gstcheck.Harness` srcpad.
    /// Timeouts after 60 seconds similar to gst_harness_pull.
    ///
    /// MT safe.
    extern fn gst_harness_pull_upstream_event(p_h: *Harness) ?*gst.Event;
    pub const pullUpstreamEvent = gst_harness_pull_upstream_event;

    /// Pushes a `gst.Buffer` on the `gstcheck.Harness` srcpad. The standard way of
    /// interacting with an harnessed element.
    ///
    /// MT safe.
    extern fn gst_harness_push(p_h: *Harness, p_buffer: *gst.Buffer) gst.FlowReturn;
    pub const push = gst_harness_push;

    /// Basically a gst_harness_push and a gst_harness_pull in one line. Reflects
    /// the fact that you often want to do exactly this in your test: Push one buffer
    /// in, and inspect the outcome.
    ///
    /// MT safe.
    extern fn gst_harness_push_and_pull(p_h: *Harness, p_buffer: *gst.Buffer) ?*gst.Buffer;
    pub const pushAndPull = gst_harness_push_and_pull;

    /// Pushes an `gst.Event` on the `gstcheck.Harness` srcpad.
    ///
    /// MT safe.
    extern fn gst_harness_push_event(p_h: *Harness, p_event: *gst.Event) c_int;
    pub const pushEvent = gst_harness_push_event;

    /// Transfer data from the src-`gstcheck.Harness` to the main-`gstcheck.Harness`. It consists
    /// of 4 steps:
    /// 1: Make sure the src is started. (see: gst_harness_play)
    /// 2: Crank the clock (see: gst_harness_crank_single_clock_wait)
    /// 3: Pull a `gst.Buffer` from the src-`gstcheck.Harness` (see: gst_harness_pull)
    /// 4: Push the same `gst.Buffer` into the main-`gstcheck.Harness` (see: gst_harness_push)
    ///
    /// MT safe.
    extern fn gst_harness_push_from_src(p_h: *Harness) gst.FlowReturn;
    pub const pushFromSrc = gst_harness_push_from_src;

    /// Transfer one `gst.Buffer` from the main-`gstcheck.Harness` to the sink-`gstcheck.Harness`.
    /// See gst_harness_push_from_src for details.
    ///
    /// MT safe.
    extern fn gst_harness_push_to_sink(p_h: *Harness) gst.FlowReturn;
    pub const pushToSink = gst_harness_push_to_sink;

    /// Pushes an `gst.Event` on the `gstcheck.Harness` sinkpad.
    ///
    /// MT safe.
    extern fn gst_harness_push_upstream_event(p_h: *Harness, p_event: *gst.Event) c_int;
    pub const pushUpstreamEvent = gst_harness_push_upstream_event;

    /// Get the min latency reported by any harnessed `gst.Element`.
    ///
    /// MT safe.
    extern fn gst_harness_query_latency(p_h: *Harness) gst.ClockTime;
    pub const queryLatency = gst_harness_query_latency;

    /// A convenience function to allows you to call g_object_set on a `gst.Element`
    /// that are residing inside the `gstcheck.Harness`, by using normal g_object_set
    /// syntax.
    ///
    /// MT safe.
    extern fn gst_harness_set(p_h: *Harness, p_element_name: [*:0]const u8, p_first_property_name: [*:0]const u8, ...) void;
    pub const set = gst_harness_set;

    /// Setting this will make the harness block in the chain-function, and
    /// then release when `gstcheck.Harness.pull` or `gstcheck.Harness.tryPull` is called.
    /// Can be useful when wanting to control a src-element that is not implementing
    /// `gst.Clock.idWait` so it can't be controlled by the `gstcheck.TestClock`, since
    /// it otherwise would produce buffers as fast as possible.
    ///
    /// MT safe.
    extern fn gst_harness_set_blocking_push_mode(p_h: *Harness) void;
    pub const setBlockingPushMode = gst_harness_set_blocking_push_mode;

    /// Sets the `GstHarness` srcpad and sinkpad caps.
    ///
    /// MT safe.
    extern fn gst_harness_set_caps(p_h: *Harness, p_in: *gst.Caps, p_out: *gst.Caps) void;
    pub const setCaps = gst_harness_set_caps;

    /// Sets the `GstHarness` srcpad and sinkpad caps using strings.
    ///
    /// MT safe.
    extern fn gst_harness_set_caps_str(p_h: *Harness, p_in: [*:0]const u8, p_out: [*:0]const u8) void;
    pub const setCapsStr = gst_harness_set_caps_str;

    /// When set to `TRUE`, instead of placing the buffers arriving from the harnessed
    /// `gst.Element` inside the sinkpads `glib.AsyncQueue`, they are instead unreffed.
    ///
    /// MT safe.
    extern fn gst_harness_set_drop_buffers(p_h: *Harness, p_drop_buffers: c_int) void;
    pub const setDropBuffers = gst_harness_set_drop_buffers;

    /// As a convenience, a src-harness will forward `GST_EVENT_STREAM_START`,
    /// `GST_EVENT_CAPS` and `GST_EVENT_SEGMENT` to the main-harness if forwarding
    /// is enabled, and forward any sticky-events from the main-harness to
    /// the sink-harness. It will also forward the `GST_QUERY_ALLOCATION`.
    ///
    /// If forwarding is disabled, the user will have to either manually push
    /// these events from the src-harness using `gstcheck.Harness.srcPushEvent`, or
    /// create and push them manually. While this will allow full control and
    /// inspection of these events, for the most cases having forwarding enabled
    /// will be sufficient when writing a test where the src-harness' main function
    /// is providing data for the main-harness.
    ///
    /// Forwarding is enabled by default.
    ///
    /// MT safe.
    extern fn gst_harness_set_forwarding(p_h: *Harness, p_forwarding: c_int) void;
    pub const setForwarding = gst_harness_set_forwarding;

    /// Sets the liveness reported by `gstcheck.Harness` when receiving a latency-query.
    /// The default is `TRUE`.
    extern fn gst_harness_set_live(p_h: *Harness, p_is_live: c_int) void;
    pub const setLive = gst_harness_set_live;

    /// Sets the `allocator` and `params` to propose when receiving an allocation
    /// query.
    ///
    /// MT safe.
    extern fn gst_harness_set_propose_allocator(p_h: *Harness, p_allocator: ?*gst.Allocator, p_params: ?*const gst.AllocationParams) void;
    pub const setProposeAllocator = gst_harness_set_propose_allocator;

    /// Sets the `GstHarness` sinkpad caps.
    ///
    /// MT safe.
    extern fn gst_harness_set_sink_caps(p_h: *Harness, p_caps: *gst.Caps) void;
    pub const setSinkCaps = gst_harness_set_sink_caps;

    /// Sets the `GstHarness` sinkpad caps using a string.
    ///
    /// MT safe.
    extern fn gst_harness_set_sink_caps_str(p_h: *Harness, p_str: [*:0]const u8) void;
    pub const setSinkCapsStr = gst_harness_set_sink_caps_str;

    /// Sets the `GstHarness` srcpad caps. This must be done before any buffers
    /// can legally be pushed from the harness to the element.
    ///
    /// MT safe.
    extern fn gst_harness_set_src_caps(p_h: *Harness, p_caps: *gst.Caps) void;
    pub const setSrcCaps = gst_harness_set_src_caps;

    /// Sets the `GstHarness` srcpad caps using a string. This must be done before
    /// any buffers can legally be pushed from the harness to the element.
    ///
    /// MT safe.
    extern fn gst_harness_set_src_caps_str(p_h: *Harness, p_str: [*:0]const u8) void;
    pub const setSrcCapsStr = gst_harness_set_src_caps_str;

    /// Advance the `gstcheck.TestClock` to a specific time.
    ///
    /// MT safe.
    extern fn gst_harness_set_time(p_h: *Harness, p_time: gst.ClockTime) c_int;
    pub const setTime = gst_harness_set_time;

    /// Sets the min latency reported by `gstcheck.Harness` when receiving a latency-query
    extern fn gst_harness_set_upstream_latency(p_h: *Harness, p_latency: gst.ClockTime) void;
    pub const setUpstreamLatency = gst_harness_set_upstream_latency;

    /// Convenience that calls gst_harness_push_to_sink `pushes` number of times.
    /// Will abort the pushing if any one push fails.
    ///
    /// MT safe.
    extern fn gst_harness_sink_push_many(p_h: *Harness, p_pushes: c_int) gst.FlowReturn;
    pub const sinkPushMany = gst_harness_sink_push_many;

    /// Transfer data from the src-`gstcheck.Harness` to the main-`gstcheck.Harness`. Similar to
    /// gst_harness_push_from_src, this variant allows you to specify how many cranks
    /// and how many pushes to perform. This can be useful for both moving a lot
    /// of data at the same time, as well as cases when one crank does not equal one
    /// buffer to push and v.v.
    ///
    /// MT safe.
    extern fn gst_harness_src_crank_and_push_many(p_h: *Harness, p_cranks: c_int, p_pushes: c_int) gst.FlowReturn;
    pub const srcCrankAndPushMany = gst_harness_src_crank_and_push_many;

    /// Similar to what gst_harness_src_push does with `GstBuffers`, this transfers
    /// a `gst.Event` from the src-`gstcheck.Harness` to the main-`gstcheck.Harness`. Note that
    /// some `GstEvents` are being transferred automagically. Look at sink_forward_pad
    /// for details.
    ///
    /// MT safe.
    extern fn gst_harness_src_push_event(p_h: *Harness) c_int;
    pub const srcPushEvent = gst_harness_src_push_event;

    /// Start a custom stress-thread that will call your `callback` for every
    /// iteration allowing you to do something nasty.
    ///
    /// MT safe.
    extern fn gst_harness_stress_custom_start(p_h: *Harness, p_init: ?glib.Func, p_callback: glib.Func, p_data: ?*anyopaque, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressCustomStart = gst_harness_stress_custom_start;

    /// Call g_object_set with `name` and `value` in intervals of `sleep` microseconds
    ///
    /// MT safe.
    extern fn gst_harness_stress_property_start_full(p_h: *Harness, p_name: [*:0]const u8, p_value: *const gobject.Value, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressPropertyStartFull = gst_harness_stress_property_start_full;

    /// Push a `gst.Buffer` in intervals of `sleep` microseconds.
    ///
    /// MT safe.
    extern fn gst_harness_stress_push_buffer_start_full(p_h: *Harness, p_caps: *gst.Caps, p_segment: *const gst.Segment, p_buf: *gst.Buffer, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressPushBufferStartFull = gst_harness_stress_push_buffer_start_full;

    /// Push a `gst.Buffer` returned by `func` in intervals of `sleep` microseconds.
    ///
    /// MT safe.
    extern fn gst_harness_stress_push_buffer_with_cb_start_full(p_h: *Harness, p_caps: *gst.Caps, p_segment: *const gst.Segment, p_func: gstcheck.HarnessPrepareBufferFunc, p_data: ?*anyopaque, p_notify: ?glib.DestroyNotify, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressPushBufferWithCbStartFull = gst_harness_stress_push_buffer_with_cb_start_full;

    /// Push the `event` onto the harnessed `gst.Element` sinkpad in intervals of
    /// `sleep` microseconds
    ///
    /// MT safe.
    extern fn gst_harness_stress_push_event_start_full(p_h: *Harness, p_event: *gst.Event, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressPushEventStartFull = gst_harness_stress_push_event_start_full;

    /// Push a `gst.Event` returned by `func` onto the harnessed `gst.Element` sinkpad
    /// in intervals of `sleep` microseconds.
    ///
    /// MT safe.
    extern fn gst_harness_stress_push_event_with_cb_start_full(p_h: *Harness, p_func: gstcheck.HarnessPrepareEventFunc, p_data: ?*anyopaque, p_notify: ?glib.DestroyNotify, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressPushEventWithCbStartFull = gst_harness_stress_push_event_with_cb_start_full;

    /// Push the `event` onto the harnessed `gst.Element` srcpad in intervals of
    /// `sleep` microseconds.
    ///
    /// MT safe.
    extern fn gst_harness_stress_push_upstream_event_start_full(p_h: *Harness, p_event: *gst.Event, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressPushUpstreamEventStartFull = gst_harness_stress_push_upstream_event_start_full;

    /// Push a `gst.Event` returned by `func` onto the harnessed `gst.Element` srcpad
    /// in intervals of `sleep` microseconds.
    ///
    /// MT safe.
    extern fn gst_harness_stress_push_upstream_event_with_cb_start_full(p_h: *Harness, p_func: gstcheck.HarnessPrepareEventFunc, p_data: ?*anyopaque, p_notify: ?glib.DestroyNotify, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressPushUpstreamEventWithCbStartFull = gst_harness_stress_push_upstream_event_with_cb_start_full;

    /// Call gst_element_request_pad in intervals of `sleep` microseconds
    ///
    /// MT safe.
    extern fn gst_harness_stress_requestpad_start_full(p_h: *Harness, p_templ: *gst.PadTemplate, p_name: [*:0]const u8, p_caps: *gst.Caps, p_release: c_int, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressRequestpadStartFull = gst_harness_stress_requestpad_start_full;

    /// Change the state of your harnessed `gst.Element` from NULL to PLAYING and
    /// back again, only pausing for `sleep` microseconds every time.
    ///
    /// MT safe.
    extern fn gst_harness_stress_statechange_start_full(p_h: *Harness, p_sleep: c_ulong) *gstcheck.HarnessThread;
    pub const stressStatechangeStartFull = gst_harness_stress_statechange_start_full;

    /// Pulls all pending data from the harness and returns it as a single
    /// data slice.
    extern fn gst_harness_take_all_data(p_h: *Harness, p_size: *usize) *u8;
    pub const takeAllData = gst_harness_take_all_data;

    /// Pulls all pending data from the harness and returns it as a single buffer.
    extern fn gst_harness_take_all_data_as_buffer(p_h: *Harness) *gst.Buffer;
    pub const takeAllDataAsBuffer = gst_harness_take_all_data_as_buffer;

    /// Pulls all pending data from the harness and returns it as a single `glib.Bytes`.
    extern fn gst_harness_take_all_data_as_bytes(p_h: *Harness) *glib.Bytes;
    pub const takeAllDataAsBytes = gst_harness_take_all_data_as_bytes;

    /// Tears down a `GstHarness`, freeing all resources allocated using it.
    ///
    /// MT safe.
    extern fn gst_harness_teardown(p_h: *Harness) void;
    pub const teardown = gst_harness_teardown;

    /// Pulls a `gst.Buffer` from the `glib.AsyncQueue` on the `gstcheck.Harness` sinkpad. Unlike
    /// gst_harness_pull this will not wait for any buffers if not any are present,
    /// and return `NULL` straight away.
    ///
    /// MT safe.
    extern fn gst_harness_try_pull(p_h: *Harness) ?*gst.Buffer;
    pub const tryPull = gst_harness_try_pull;

    /// Pulls an `gst.Event` from the `glib.AsyncQueue` on the `gstcheck.Harness` sinkpad.
    /// See gst_harness_try_pull for details.
    ///
    /// MT safe.
    extern fn gst_harness_try_pull_event(p_h: *Harness) ?*gst.Event;
    pub const tryPullEvent = gst_harness_try_pull_event;

    /// Pulls an `gst.Event` from the `glib.AsyncQueue` on the `gstcheck.Harness` srcpad.
    /// See gst_harness_try_pull for details.
    ///
    /// MT safe.
    extern fn gst_harness_try_pull_upstream_event(p_h: *Harness) ?*gst.Event;
    pub const tryPullUpstreamEvent = gst_harness_try_pull_upstream_event;

    /// The number of `GstEvents` currently in the `gstcheck.Harness` srcpad `glib.AsyncQueue`
    ///
    /// MT safe.
    extern fn gst_harness_upstream_events_in_queue(p_h: *Harness) c_uint;
    pub const upstreamEventsInQueue = gst_harness_upstream_events_in_queue;

    /// The total number of `GstEvents` that has arrived on the `gstcheck.Harness` srcpad
    /// This number includes events handled by the harness as well as events
    /// that have already been pulled out.
    ///
    /// MT safe.
    extern fn gst_harness_upstream_events_received(p_h: *Harness) c_uint;
    pub const upstreamEventsReceived = gst_harness_upstream_events_received;

    /// Sets the system `gst.Clock` on the `GstHarness` `gst.Element`
    ///
    /// MT safe.
    extern fn gst_harness_use_systemclock(p_h: *Harness) void;
    pub const useSystemclock = gst_harness_use_systemclock;

    /// Sets the `gstcheck.TestClock` on the `gstcheck.Harness` `gst.Element`
    ///
    /// MT safe.
    extern fn gst_harness_use_testclock(p_h: *Harness) void;
    pub const useTestclock = gst_harness_use_testclock;

    /// Waits for `timeout` seconds until `waits` number of `gst.ClockID` waits is
    /// registered with the `gstcheck.TestClock`. Useful for writing deterministic tests,
    /// where you want to make sure that an expected number of waits have been
    /// reached.
    ///
    /// MT safe.
    extern fn gst_harness_wait_for_clock_id_waits(p_h: *Harness, p_waits: c_uint, p_timeout: c_uint) c_int;
    pub const waitForClockIdWaits = gst_harness_wait_for_clock_id_waits;

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const HarnessPrivate = opaque {
    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Opaque handle representing a GstHarness stress testing thread.
pub const HarnessThread = opaque {
    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Opaque consistency checker handle.
pub const StreamConsistency = opaque {
    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// The class of a `gstcheck.TestClock`, which has no virtual methods to override.
pub const TestClockClass = extern struct {
    pub const Instance = gstcheck.TestClock;

    /// the parent class structure
    f_parent_class: gst.ClockClass,

    pub fn as(p_instance: *TestClockClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const TestClockPrivate = opaque {
    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Get one buffer from `pad`. Implemented via buffer probes. This function will
/// block until the pipeline passes a buffer over `pad`, so for robust behavior
/// in unit tests, you need to use check's timeout to fail out in the case that a
/// buffer never arrives.
///
/// You must have previously called `gstcheck.bufferStrawStartPipeline` on
/// `pipeline` and `pad`.
extern fn gst_buffer_straw_get_buffer(p_bin: *gst.Element, p_pad: *gst.Pad) *gst.Buffer;
pub const bufferStrawGetBuffer = gst_buffer_straw_get_buffer;

/// Sets up a pipeline for buffer sucking. This will allow you to call
/// `gstcheck.bufferStrawGetBuffer` to access buffers as they pass over `pad`.
///
/// This function is normally used in unit tests that want to verify that a
/// particular element is outputting correct buffers. For example, you would make
/// a pipeline via `gst.parseLaunch`, pull out the pad you want to monitor, then
/// call `gstcheck.bufferStrawGetBuffer` to get the buffers that pass through `pad`.
/// The pipeline will block until you have sucked off the buffers.
///
/// This function will set the state of `bin` to PLAYING; to clean up, be sure to
/// call `gstcheck.bufferStrawStopPipeline`.
///
/// Note that you may not start two buffer straws at the same time. This function
/// is intended for unit tests, not general API use. In fact it calls fail_if
/// from libcheck, so you cannot use it outside unit tests.
extern fn gst_buffer_straw_start_pipeline(p_bin: *gst.Element, p_pad: *gst.Pad) void;
pub const bufferStrawStartPipeline = gst_buffer_straw_start_pipeline;

/// Set `bin` to `GST_STATE_NULL` and release resource allocated in
/// `gstcheck.bufferStrawStartPipeline`.
///
/// You must have previously called `gstcheck.bufferStrawStartPipeline` on
/// `pipeline` and `pad`.
extern fn gst_buffer_straw_stop_pipeline(p_bin: *gst.Element, p_pad: *gst.Pad) void;
pub const bufferStrawStopPipeline = gst_buffer_straw_stop_pipeline;

/// Verifies that reference values and current values are equals in `list`.
extern fn gst_check_abi_list(p_list: *gstcheck.CheckABIStruct, p_have_abi_sizes: c_int) void;
pub const checkAbiList = gst_check_abi_list;

/// Add a callback `func` to be called for all log messages that matches
/// `log_domain`, `log_level` and `regex`. If `func` is NULL the
/// matching logs will be silently discarded by GstCheck.
///
/// MT safe.
extern fn gst_check_add_log_filter(p_log_domain: [*:0]const u8, p_log_level: glib.LogLevelFlags, p_regex: *glib.Regex, p_func: gstcheck.CheckLogFilterFunc, p_user_data: ?*anyopaque, p_destroy_data: ?glib.DestroyNotify) *gstcheck.CheckLogFilter;
pub const checkAddLogFilter = gst_check_add_log_filter;

/// Compare the buffer contents with `data` and `size`.
extern fn gst_check_buffer_data(p_buffer: *gst.Buffer, p_data: ?*const anyopaque, p_size: usize) void;
pub const checkBufferData = gst_check_buffer_data;

/// Compare two caps with gst_caps_is_equal and fail unless they are
/// equal.
extern fn gst_check_caps_equal(p_caps1: *gst.Caps, p_caps2: *gst.Caps) void;
pub const checkCapsEqual = gst_check_caps_equal;

/// A fake chain function that appends the buffer to the internal list of
/// buffers.
extern fn gst_check_chain_func(p_pad: *gst.Pad, p_parent: *gst.Object, p_buffer: *gst.Buffer) gst.FlowReturn;
pub const checkChainFunc = gst_check_chain_func;

/// Clear all filters added by `gst_check_add_log_filter`.
///
/// MT safe.
extern fn gst_check_clear_log_filter() void;
pub const checkClearLogFilter = gst_check_clear_log_filter;

/// Unref and remove all buffers that are in the global `buffers` GList,
/// emptying the list.
extern fn gst_check_drop_buffers() void;
pub const checkDropBuffers = gst_check_drop_buffers;

/// Create an element using the factory providing the `element_name` and
/// push the `buffer_in` to this element. The element should create one buffer
/// and this will be compared with `buffer_out`. We only check the caps
/// and the data of the buffers. This function unrefs the buffers.
extern fn gst_check_element_push_buffer(p_element_name: [*:0]const u8, p_buffer_in: *gst.Buffer, p_caps_in: *gst.Caps, p_buffer_out: *gst.Buffer, p_caps_out: *gst.Caps) void;
pub const checkElementPushBuffer = gst_check_element_push_buffer;

/// Create an element using the factory providing the `element_name` and push the
/// buffers in `buffer_in` to this element. The element should create the buffers
/// equal to the buffers in `buffer_out`. We only check the size and the data of
/// the buffers. This function unrefs the buffers in the two lists.
/// The last_flow_return parameter indicates the expected flow return value from
/// pushing the final buffer in the list.
/// This can be used to set up a test which pushes some buffers and then an
/// invalid buffer, when the final buffer is expected to fail, for example.
extern fn gst_check_element_push_buffer_list(p_element_name: [*:0]const u8, p_buffer_in: *glib.List, p_caps_in: *gst.Caps, p_buffer_out: *glib.List, p_caps_out: *gst.Caps, p_last_flow_return: gst.FlowReturn) void;
pub const checkElementPushBufferList = gst_check_element_push_buffer_list;

extern fn gst_check_init(p_argc: *c_int, p_argv: **[*:0]u8) void;
pub const checkInit = gst_check_init;

extern fn gst_check_message_error(p_message: *gst.Message, p_type: gst.MessageType, p_domain: glib.Quark, p_code: c_int) void;
pub const checkMessageError = gst_check_message_error;

/// Unrefs `object_to_unref` and checks that is has properly been
/// destroyed.
extern fn gst_check_object_destroyed_on_unref(p_object_to_unref: ?*anyopaque) void;
pub const checkObjectDestroyedOnUnref = gst_check_object_destroyed_on_unref;

/// Unrefs `object_to_unref` and checks that is has properly been
/// destroyed, also checks that the other objects passed in
/// parameter have been destroyed as a concequence of
/// unrefing `object_to_unref`. Last variable argument should be NULL.
extern fn gst_check_objects_destroyed_on_unref(p_object_to_unref: ?*anyopaque, p_first_object: ?*anyopaque, ...) void;
pub const checkObjectsDestroyedOnUnref = gst_check_objects_destroyed_on_unref;

/// Remove a filter that has been added by `gst_check_add_log_filter`.
///
/// MT safe.
extern fn gst_check_remove_log_filter(p_filter: *gstcheck.CheckLogFilter) void;
pub const checkRemoveLogFilter = gst_check_remove_log_filter;

extern fn gst_check_run_suite(p_suite: *anyopaque, p_name: [*:0]const u8, p_fname: [*:0]const u8) c_int;
pub const checkRunSuite = gst_check_run_suite;

/// setup an element for a filter test with mysrcpad and mysinkpad
extern fn gst_check_setup_element(p_factory: [*:0]const u8) *gst.Element;
pub const checkSetupElement = gst_check_setup_element;

/// Push stream-start, caps and segment event, which consist of the minimum
/// required events to allow streaming. Caps is optional to allow raw src
/// testing. If `element` has more than one src or sink pad, use
/// `gstcheck.checkSetupEventsWithStreamId` instead.
extern fn gst_check_setup_events(p_srcpad: *gst.Pad, p_element: *gst.Element, p_caps: ?*gst.Caps, p_format: gst.Format) void;
pub const checkSetupEvents = gst_check_setup_events;

/// Push stream-start, caps and segment event, which consist of the minimum
/// required events to allow streaming. Caps is optional to allow raw src
/// testing.
extern fn gst_check_setup_events_with_stream_id(p_srcpad: *gst.Pad, p_element: *gst.Element, p_caps: ?*gst.Caps, p_format: gst.Format, p_stream_id: [*:0]const u8) void;
pub const checkSetupEventsWithStreamId = gst_check_setup_events_with_stream_id;

/// Does the same as `gstcheck.checkSetupSinkPadByName` with the <emphasis> name </emphasis> parameter equal to "src".
extern fn gst_check_setup_sink_pad(p_element: *gst.Element, p_tmpl: *gst.StaticPadTemplate) *gst.Pad;
pub const checkSetupSinkPad = gst_check_setup_sink_pad;

/// Creates a new sink pad (based on the given `tmpl`) and links it to the given `element` src pad
/// (the pad that matches the given `name`).
/// You can set event/chain/query functions on this pad to check the output of the `element`.
extern fn gst_check_setup_sink_pad_by_name(p_element: *gst.Element, p_tmpl: *gst.StaticPadTemplate, p_name: [*:0]const u8) *gst.Pad;
pub const checkSetupSinkPadByName = gst_check_setup_sink_pad_by_name;

extern fn gst_check_setup_sink_pad_by_name_from_template(p_element: *gst.Element, p_tmpl: *gst.PadTemplate, p_name: [*:0]const u8) *gst.Pad;
pub const checkSetupSinkPadByNameFromTemplate = gst_check_setup_sink_pad_by_name_from_template;

extern fn gst_check_setup_sink_pad_from_template(p_element: *gst.Element, p_tmpl: *gst.PadTemplate) *gst.Pad;
pub const checkSetupSinkPadFromTemplate = gst_check_setup_sink_pad_from_template;

/// Does the same as `gstcheck.checkSetupSrcPadByName` with the <emphasis> name </emphasis> parameter equal to "sink".
extern fn gst_check_setup_src_pad(p_element: *gst.Element, p_tmpl: *gst.StaticPadTemplate) *gst.Pad;
pub const checkSetupSrcPad = gst_check_setup_src_pad;

/// Creates a new src pad (based on the given `tmpl`) and links it to the given `element` sink pad (the pad that matches the given `name`).
/// Before using the src pad to push data on `element` you need to call `gstcheck.checkSetupEvents` on the created src pad.
///
/// Example of how to push a buffer on `element`:
///
/// ```
/// static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
/// GST_PAD_SINK,
/// GST_PAD_ALWAYS,
/// GST_STATIC_CAPS (YOUR_CAPS_TEMPLATE_STRING)
/// );
/// static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
/// GST_PAD_SRC,
/// GST_PAD_ALWAYS,
/// GST_STATIC_CAPS (YOUR_CAPS_TEMPLATE_STRING)
/// );
///
/// GstElement * element = gst_check_setup_element ("element");
/// GstPad * mysrcpad = gst_check_setup_src_pad (element, &srctemplate);
/// GstPad * mysinkpad = gst_check_setup_sink_pad (element, &sinktemplate);
///
/// gst_pad_set_active (mysrcpad, TRUE);
/// gst_pad_set_active (mysinkpad, TRUE);
/// fail_unless (gst_element_set_state (element, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, "could not set to playing");
///
/// GstCaps * caps = gst_caps_from_string (YOUR_DESIRED_SINK_CAPS);
/// gst_check_setup_events (mysrcpad, element, caps, GST_FORMAT_TIME);
/// gst_caps_unref (caps);
///
/// fail_unless (gst_pad_push (mysrcpad, gst_buffer_new_and_alloc(2)) == GST_FLOW_OK);
/// ```
///
/// For very simple input/output test scenarios checkout `gstcheck.checkElementPushBufferList` and `gstcheck.checkElementPushBuffer`.
extern fn gst_check_setup_src_pad_by_name(p_element: *gst.Element, p_tmpl: *gst.StaticPadTemplate, p_name: [*:0]const u8) *gst.Pad;
pub const checkSetupSrcPadByName = gst_check_setup_src_pad_by_name;

extern fn gst_check_setup_src_pad_by_name_from_template(p_element: *gst.Element, p_tmpl: *gst.PadTemplate, p_name: [*:0]const u8) *gst.Pad;
pub const checkSetupSrcPadByNameFromTemplate = gst_check_setup_src_pad_by_name_from_template;

extern fn gst_check_setup_src_pad_from_template(p_element: *gst.Element, p_tmpl: *gst.PadTemplate) *gst.Pad;
pub const checkSetupSrcPadFromTemplate = gst_check_setup_src_pad_from_template;

extern fn gst_check_teardown_element(p_element: *gst.Element) void;
pub const checkTeardownElement = gst_check_teardown_element;

extern fn gst_check_teardown_pad_by_name(p_element: *gst.Element, p_name: [*:0]const u8) void;
pub const checkTeardownPadByName = gst_check_teardown_pad_by_name;

extern fn gst_check_teardown_sink_pad(p_element: *gst.Element) void;
pub const checkTeardownSinkPad = gst_check_teardown_sink_pad;

extern fn gst_check_teardown_src_pad(p_element: *gst.Element) void;
pub const checkTeardownSrcPad = gst_check_teardown_src_pad;

/// Sets up a data probe on the given pad which will raise assertions if the
/// data flow is inconsistent.
extern fn gst_consistency_checker_add_pad(p_consist: *gstcheck.StreamConsistency, p_pad: *gst.Pad) c_int;
pub const consistencyCheckerAddPad = gst_consistency_checker_add_pad;

/// Frees the allocated data and probes associated with `consist`.
extern fn gst_consistency_checker_free(p_consist: *gstcheck.StreamConsistency) void;
pub const consistencyCheckerFree = gst_consistency_checker_free;

/// Sets up a data probe on the given pad which will raise assertions if the
/// data flow is inconsistent.
extern fn gst_consistency_checker_new(p_pad: *gst.Pad) *gstcheck.StreamConsistency;
pub const consistencyCheckerNew = gst_consistency_checker_new;

/// Reset the stream checker's internal variables.
extern fn gst_consistency_checker_reset(p_consist: *gstcheck.StreamConsistency) void;
pub const consistencyCheckerReset = gst_consistency_checker_reset;

/// A function that is called for messages matching the filter added by
/// `gst_check_add_log_filter`.
pub const CheckLogFilterFunc = *const fn (p_log_domain: [*:0]const u8, p_log_level: glib.LogLevelFlags, p_message: [*:0]const u8, p_user_data: ?*anyopaque) callconv(.c) c_int;

pub const HarnessPrepareBufferFunc = *const fn (p_h: *gstcheck.Harness, p_data: ?*anyopaque) callconv(.c) *gst.Buffer;

pub const HarnessPrepareEventFunc = *const fn (p_h: *gstcheck.Harness, p_data: ?*anyopaque) callconv(.c) *gst.Event;

test {
    @setEvalBranchQuota(100_000);
    std.testing.refAllDecls(@This());
    std.testing.refAllDecls(ext);
}
