2015-04-15 17:57:43 +00:00
|
|
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
|
|
|
# vim: tabstop=4 shiftwidth=4 expandtab
|
2005-09-01 10:36:07 +00:00
|
|
|
#
|
2015-04-15 17:57:43 +00:00
|
|
|
# Copyright (C) 2015 Thibault Saunier <thibault.saunier@collabora.com>
|
2005-09-01 10:36:07 +00:00
|
|
|
#
|
2015-04-15 17:57:43 +00:00
|
|
|
# This program is free software; you can redistribute it and/or
|
2005-09-01 10:36:07 +00:00
|
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
|
|
# License as published by the Free Software Foundation; either
|
|
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
|
|
#
|
2015-04-15 17:57:43 +00:00
|
|
|
# This program is distributed in the hope that it will be useful,
|
2005-09-01 10:36:07 +00:00
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
# Lesser General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
2015-04-15 17:57:43 +00:00
|
|
|
# License along with this program; if not, write to the
|
|
|
|
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
# Boston, MA 02110-1301, USA.
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 3, or (at your option)
|
|
|
|
# any later version.
|
|
|
|
"""
|
|
|
|
A collection of objects to use for testing
|
|
|
|
|
|
|
|
Copyied from pitivi
|
|
|
|
"""
|
|
|
|
|
2004-03-08 19:22:15 +00:00
|
|
|
import os
|
2005-09-28 13:29:52 +00:00
|
|
|
import gc
|
2004-03-08 19:22:15 +00:00
|
|
|
import unittest
|
2015-04-15 17:57:43 +00:00
|
|
|
import gi.overrides
|
2016-02-15 22:26:06 +00:00
|
|
|
|
overrides: Add more GstValue overrides
This patch adds overrides to support IntRange, Int64Range, DoubleRange,
FractionRange, Array and List. For integer ranges, it maps this
to python 'range'. Gst.IntRange() and Gst.Int64Range() are simple cast
to let the underlying code know which GType to use. To set such range in
python you will do:
structure["range"] = Gst.IntRange(range(0,10,2)))
Same for the 64 bit variant. And when you do:
r = structure.get_value("range")
A range will be returned directly, without the wrapper. For DoubleRange
and FractionRange, there is no native support in python. So the usage
will be:
structure["range"] = Gst.DoubleRange(0,10.0)
structure["range"] =
Gst.FractionRange(Gst.Fraction(1/30), Gst.Fraction(1/5)
When getting this value, Gst.DoubleRange and Gst.FractionRange class are
returned. They both have start/stop members. The naming was taken from
range type.
For Array and List, both uses the native list type, though they can be
constructed from any python sequence. So again, the class is just like
a cast, to let it pick the right GType and python list are being
returned.
structure["list"] = Gst.ValueList([1,2,3,4])
structure["array"] = Gst.ValueArray([1,2,3,4)
Using string and tuple could also work. Since Gst.ValueList/Array are
sequence, you can convert one to the other with:
list = Gst.ValueList([1,2,3,4])
array = Gst.ValueArray (list)
https://bugzilla.gnome.org/show_bug.cgi?id=753754
2017-03-23 16:21:32 +00:00
|
|
|
import gi
|
|
|
|
gi.require_version("Gst", "1.0")
|
2015-04-15 17:57:43 +00:00
|
|
|
from gi.repository import Gst
|
|
|
|
|
|
|
|
|
|
|
|
detect_leaks = os.environ.get("TEST_DETECT_LEAKS", "1") not in ("0", "")
|
2004-03-08 19:22:15 +00:00
|
|
|
|
2005-09-28 13:29:52 +00:00
|
|
|
|
|
|
|
class TestCase(unittest.TestCase):
|
2015-04-15 17:57:43 +00:00
|
|
|
_tracked_types = (Gst.MiniObject, Gst.Element, Gst.Pad, Gst.Caps)
|
|
|
|
|
|
|
|
def gctrack(self):
|
|
|
|
self.gccollect()
|
|
|
|
self._tracked = []
|
|
|
|
for obj in gc.get_objects():
|
|
|
|
if not isinstance(obj, self._tracked_types):
|
|
|
|
continue
|
2005-09-28 15:48:10 +00:00
|
|
|
|
2015-04-15 17:57:43 +00:00
|
|
|
self._tracked.append(obj)
|
2005-09-28 15:48:10 +00:00
|
|
|
|
2005-09-28 13:29:52 +00:00
|
|
|
def gccollect(self):
|
2005-09-28 14:20:03 +00:00
|
|
|
ret = 0
|
|
|
|
while True:
|
|
|
|
c = gc.collect()
|
|
|
|
ret += c
|
2015-04-15 17:57:43 +00:00
|
|
|
if c == 0:
|
|
|
|
break
|
2005-09-28 14:20:03 +00:00
|
|
|
return ret
|
2005-09-28 13:29:52 +00:00
|
|
|
|
2015-04-15 17:57:43 +00:00
|
|
|
def gcverify(self):
|
|
|
|
leaked = []
|
|
|
|
for obj in gc.get_objects():
|
|
|
|
if not isinstance(obj, self._tracked_types) or \
|
|
|
|
obj in self._tracked:
|
|
|
|
continue
|
|
|
|
|
|
|
|
leaked.append(obj)
|
|
|
|
|
|
|
|
# we collect again here to get rid of temporary objects created in the
|
|
|
|
# above loop
|
2005-09-28 13:29:52 +00:00
|
|
|
self.gccollect()
|
|
|
|
|
2015-04-15 17:57:43 +00:00
|
|
|
for elt in leaked:
|
|
|
|
print(elt)
|
|
|
|
for i in gc.get_referrers(elt):
|
|
|
|
print(" ", i)
|
|
|
|
|
|
|
|
self.assertFalse(leaked, leaked)
|
2005-09-28 13:29:52 +00:00
|
|
|
del self._tracked
|
2005-09-28 15:48:10 +00:00
|
|
|
|
|
|
|
def setUp(self):
|
2015-04-15 17:57:43 +00:00
|
|
|
self._num_failures = len(getattr(self._result, 'failures', []))
|
|
|
|
self._num_errors = len(getattr(self._result, 'errors', []))
|
|
|
|
if detect_leaks:
|
|
|
|
self.gctrack()
|
2005-09-28 15:48:10 +00:00
|
|
|
|
|
|
|
def tearDown(self):
|
2015-04-15 17:57:43 +00:00
|
|
|
# don't barf gc info all over the console if we have already failed a
|
|
|
|
# test case
|
|
|
|
if (self._num_failures < len(getattr(self._result, 'failures', []))
|
|
|
|
or self._num_errors < len(getattr(self._result, 'failures', []))):
|
|
|
|
return
|
|
|
|
if detect_leaks:
|
|
|
|
self.gccollect()
|
|
|
|
self.gcverify()
|
|
|
|
|
|
|
|
# override run() to save a reference to the test result object
|
|
|
|
def run(self, result=None):
|
|
|
|
if not result:
|
|
|
|
result = self.defaultTestResult()
|
|
|
|
self._result = result
|
|
|
|
unittest.TestCase.run(self, result)
|
|
|
|
|
|
|
|
|
|
|
|
class SignalMonitor(object):
|
|
|
|
|
|
|
|
def __init__(self, obj, *signals):
|
|
|
|
self.signals = signals
|
|
|
|
self.connectToObj(obj)
|
|
|
|
|
|
|
|
def connectToObj(self, obj):
|
|
|
|
self.obj = obj
|
|
|
|
for signal in self.signals:
|
|
|
|
obj.connect(signal, self._signalCb, signal)
|
|
|
|
setattr(self, self._getSignalCounterName(signal), 0)
|
|
|
|
setattr(self, self._getSignalCollectName(signal), [])
|
|
|
|
|
|
|
|
def disconnectFromObj(self, obj):
|
|
|
|
obj.disconnect_by_func(self._signalCb)
|
|
|
|
del self.obj
|
|
|
|
|
|
|
|
def _getSignalCounterName(self, signal):
|
|
|
|
field = '%s_count' % signal.replace('-', '_')
|
|
|
|
return field
|
|
|
|
|
|
|
|
def _getSignalCollectName(self, signal):
|
|
|
|
field = '%s_collect' % signal.replace('-', '_')
|
|
|
|
return field
|
|
|
|
|
|
|
|
def _signalCb(self, obj, *args):
|
|
|
|
name = args[-1]
|
|
|
|
field = self._getSignalCounterName(name)
|
|
|
|
setattr(self, field, getattr(self, field, 0) + 1)
|
|
|
|
field = self._getSignalCollectName(name)
|
|
|
|
setattr(self, field, getattr(self, field, []) + [args[:-1]])
|