From f7f3179a89a622c9c7e64a7bfcd4675ae8bbc115 Mon Sep 17 00:00:00 2001 From: WMOkiishi Date: Wed, 2 Aug 2023 08:24:44 +0200 Subject: [PATCH] Move test code from across `direct` to proper test modules Closes #1480 --- .github/workflows/ci.yml | 20 +- direct/src/distributed/CRDataCache.py | 38 -- direct/src/fsm/StatePush.py | 155 +----- direct/src/physics/__init__.py | 0 direct/src/showbase/CountedResource.py | 144 ----- direct/src/showbase/DistancePhasedNode.py | 28 - direct/src/showbase/PythonUtil.py | 47 -- direct/src/stdpy/threading.py | 105 ---- direct/src/stdpy/threading2.py | 89 --- direct/src/task/Task.py | 526 ------------------ direct/src/tkpanels/ParticlePanel.py | 18 - direct/src/tkpanels/Placer.py | 8 - direct/src/tkwidgets/AppShell.py | 4 - direct/src/tkwidgets/Dial.py | 15 - direct/src/tkwidgets/EntryScale.py | 42 -- direct/src/tkwidgets/Floater.py | 39 -- direct/src/tkwidgets/VectorWidgets.py | 14 - requirements-test.txt | 4 + tests/{display => }/conftest.py | 23 + tests/distributed/test_CRDataCache.py | 42 ++ tests/fsm/test_StatePush.py | 144 +++++ .../gui/test_DirectGui.py | 22 +- .../particles/test_particle.py | 20 +- .../particles/test_particle_floor.py | 8 +- .../FallTest.py => tests/physics/test_fall.py | 15 +- .../physics/test_rotation.py | 15 +- tests/showbase/test_CountedResource.py | 145 +++++ tests/showbase/test_DistancePhasedNode.py | 30 + tests/showbase/test_PythonUtil.py | 43 ++ tests/stdpy/test_threading.py | 103 ++++ tests/stdpy/test_threading2.py | 84 +++ tests/task/test_Task.py | 518 +++++++++++++++++ tests/task/test_task_arg.py | 4 +- .../TaskTester.py => tests/task/test_tasks.py | 10 +- tests/test_imports.py | 7 - tests/tkpanels/test_ParticlePanel.py | 11 + tests/tkpanels/test_Placer.py | 12 + tests/tkwidgets/test_AppShell.py | 7 + tests/tkwidgets/test_Dial.py | 19 + tests/tkwidgets/test_EntryScale.py | 44 ++ tests/tkwidgets/test_Floater.py | 41 ++ tests/tkwidgets/test_VectorWidgets.py | 17 + 42 files changed, 1336 insertions(+), 1344 deletions(-) delete mode 100644 direct/src/physics/__init__.py create mode 100644 requirements-test.txt rename tests/{display => }/conftest.py (77%) create mode 100644 tests/distributed/test_CRDataCache.py create mode 100644 tests/fsm/test_StatePush.py rename direct/src/gui/DirectGuiTest.py => tests/gui/test_DirectGui.py (92%) rename direct/src/particles/ParticleTest.py => tests/particles/test_particle.py (54%) rename direct/src/particles/ParticleFloorTest.py => tests/particles/test_particle_floor.py (93%) mode change 100755 => 100644 rename direct/src/physics/FallTest.py => tests/physics/test_fall.py (92%) rename direct/src/physics/RotationTest.py => tests/physics/test_rotation.py (92%) create mode 100644 tests/showbase/test_CountedResource.py create mode 100644 tests/showbase/test_DistancePhasedNode.py create mode 100644 tests/stdpy/test_threading2.py create mode 100644 tests/task/test_Task.py rename direct/src/task/TaskTester.py => tests/task/test_tasks.py (82%) mode change 100755 => 100644 create mode 100644 tests/tkpanels/test_ParticlePanel.py create mode 100644 tests/tkpanels/test_Placer.py create mode 100644 tests/tkwidgets/test_AppShell.py create mode 100644 tests/tkwidgets/test_Dial.py create mode 100644 tests/tkwidgets/test_EntryScale.py create mode 100644 tests/tkwidgets/test_Floater.py create mode 100644 tests/tkwidgets/test_VectorWidgets.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fc6e969ff..bfddcd515e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -207,7 +207,7 @@ jobs: PYTHONPATH: ${{ matrix.config }} run: | PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') - $PYTHON_EXECUTABLE -m pip install pytest pytest-cov + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw $PYTHON_EXECUTABLE -m pytest ../tests --cov=. # END B @@ -239,7 +239,7 @@ jobs: PYTHONPATH: ${{ matrix.config }} run: | PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') - $PYTHON_EXECUTABLE -m pip install pytest pytest-cov + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw $PYTHON_EXECUTABLE -m pytest ../tests --cov=. # END B @@ -271,7 +271,7 @@ jobs: PYTHONPATH: ${{ matrix.config }} run: | PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') - $PYTHON_EXECUTABLE -m pip install pytest pytest-cov + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw $PYTHON_EXECUTABLE -m pytest ../tests --cov=. # END B @@ -303,7 +303,7 @@ jobs: PYTHONPATH: ${{ matrix.config }} run: | PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') - $PYTHON_EXECUTABLE -m pip install pytest pytest-cov + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw $PYTHON_EXECUTABLE -m pytest ../tests --cov=. # END B @@ -335,7 +335,7 @@ jobs: PYTHONPATH: ${{ matrix.config }} run: | PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') - $PYTHON_EXECUTABLE -m pip install pytest pytest-cov + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw $PYTHON_EXECUTABLE -m pytest ../tests --cov=. # END B @@ -398,7 +398,7 @@ jobs: - name: Test Python 3.11 shell: bash run: | - python -m pip install pytest + python -m pip install -r requirements-test.txt PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Set up Python 3.10 @@ -412,7 +412,7 @@ jobs: - name: Test Python 3.10 shell: bash run: | - python -m pip install pytest + python -m pip install -r requirements-test.txt PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Set up Python 3.9 @@ -426,7 +426,7 @@ jobs: - name: Test Python 3.9 shell: bash run: | - python -m pip install pytest + python -m pip install -r requirements-test.txt PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Set up Python 3.8 @@ -440,7 +440,7 @@ jobs: - name: Test Python 3.8 shell: bash run: | - python -m pip install pytest + python -m pip install -r requirements-test.txt PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Set up Python 3.7 @@ -454,7 +454,7 @@ jobs: - name: Test Python 3.7 shell: bash run: | - python -m pip install pytest + python -m pip install -r requirements-test.txt PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest - name: Make installer diff --git a/direct/src/distributed/CRDataCache.py b/direct/src/distributed/CRDataCache.py index 43c87a015b..e6806cf9c3 100755 --- a/direct/src/distributed/CRDataCache.py +++ b/direct/src/distributed/CRDataCache.py @@ -76,41 +76,3 @@ if __debug__: def flush(self): CachedDOData.flush(self) self._flushed = True - - dc = CRDataCache() - dc._startMemLeakCheck() - - cd = CachedDOData() - cd.foo = 34 - dc.setCachedData(1, 'testCachedData', cd) - del cd - cd = CachedDOData() - cd.bar = 45 - dc.setCachedData(1, 'testCachedData2', cd) - del cd - assert dc.hasCachedData(1) - assert dc.hasCachedData(1) - assert not dc.hasCachedData(2) - # data is dict of dataName->data - data = dc.popCachedData(1) - assert len(data) == 2 - assert 'testCachedData' in data - assert 'testCachedData2' in data - assert data['testCachedData'].foo == 34 - assert data['testCachedData2'].bar == 45 - for cd in data.values(): - cd.flush() - del data - dc._checkMemLeaks() - - cd = CachedDOData() - cd.bar = 1234 - dc.setCachedData(43, 'testCachedData2', cd) - del cd - assert dc.hasCachedData(43) - dc.flush() - dc._checkMemLeaks() - - dc._stopMemLeakCheck() - dc.destroy() - del dc diff --git a/direct/src/fsm/StatePush.py b/direct/src/fsm/StatePush.py index 5c93aebd8e..21bed7e299 100755 --- a/direct/src/fsm/StatePush.py +++ b/direct/src/fsm/StatePush.py @@ -46,11 +46,6 @@ class PushesStateChanges: for subscriber in self._subscribers: subscriber._recvStatePush(self) -if __debug__: - psc = PushesStateChanges(0) - assert psc.getState() == 0 - psc.destroy() - del psc class ReceivesStateChanges: # base class for objects that subscribe to state changes from PushesStateChanges objects @@ -83,10 +78,6 @@ class ReceivesStateChanges: def _recvStatePush(self, source): pass -if __debug__: - rsc = ReceivesStateChanges(None) - rsc.destroy() - del rsc class StateVar(PushesStateChanges): # coder-friendly object that allows values to be set on it and pushes those values @@ -97,13 +88,6 @@ class StateVar(PushesStateChanges): def get(self): return PushesStateChanges.getState(self) -if __debug__: - sv = StateVar(0) - assert sv.get() == 0 - sv.set(1) - assert sv.get() == 1 - sv.destroy() - del sv class StateChangeNode(PushesStateChanges, ReceivesStateChanges): # base class that can be used to create a state-change notification chain @@ -120,31 +104,6 @@ class StateChangeNode(PushesStateChanges, ReceivesStateChanges): # got a state push, apply new state to self self._handlePotentialStateChange(source._value) -if __debug__: - sv = StateVar(0) - assert sv.get() == 0 - scn = StateChangeNode(sv) - assert scn.getState() == 0 - sv.set(1) - assert sv.get() == 1 - assert scn.getState() == 1 - scn2 = StateChangeNode(scn) - assert scn2.getState() == 1 - sv.set(2) - assert scn2.getState() == 2 - scn3 = StateChangeNode(scn) - assert scn3.getState() == 2 - sv.set(3) - assert scn2.getState() == 3 - assert scn3.getState() == 3 - scn3.destroy() - scn2.destroy() - scn.destroy() - sv.destroy() - del scn3 - del scn2 - del scn - del sv class ReceivesMultipleStateChanges: # base class for objects that subscribe to state changes from multiple PushesStateChanges @@ -179,15 +138,6 @@ class ReceivesMultipleStateChanges: def _recvMultiStatePush(self, key, source): pass -if __debug__: - rsc = ReceivesMultipleStateChanges() - sv = StateVar(0) - sv2 = StateVar('b') - rsc._subscribeTo(sv, 'a') - rsc._subscribeTo(sv2, 2) - rsc._unsubscribe('a') - rsc.destroy() - del rsc class FunctionCall(ReceivesMultipleStateChanges, PushesStateChanges): # calls func with provided args whenever arguments' state changes @@ -249,47 +199,6 @@ class FunctionCall(ReceivesMultipleStateChanges, PushesStateChanges): self._func(*self._bakedArgs, **self._bakedKargs) PushesStateChanges._handleStateChange(self) -if __debug__: - l = [] - def handler1(value, l=l): - l.append(value) - assert not l - sv = StateVar(0) - fc = FunctionCall(handler1, sv) - assert not l - fc.pushCurrentState() - assert l == [0,] - sv.set(1) - assert l == [0,1,] - sv.set(2) - assert l == [0,1,2,] - fc.destroy() - sv.destroy() - del fc - del sv - del handler1 - del l - - l = [] - def handler2(value, kDummy=None, kValue=None, l=l): - l.append((value, kValue)) - assert not l - sv = StateVar(0) - ksv = StateVar('a') - fc = FunctionCall(handler2, sv, kValue=ksv) - assert not l - fc.pushCurrentState() - assert l == [(0,'a',),] - sv.set(1) - assert l == [(0,'a'),(1,'a'),] - ksv.set('b') - assert l == [(0,'a'),(1,'a'),(1,'b'),] - fc.destroy() - sv.destroy() - del fc - del sv - del handler2 - del l class EnterExit(StateChangeNode): # call enterFunc when our state becomes true, exitFunc when it becomes false @@ -314,33 +223,6 @@ class EnterExit(StateChangeNode): self._exitFunc() StateChangeNode._handleStateChange(self) -if __debug__: - l = [] - def enter(l=l): - l.append(1) - def exit(l=l): - l.append(0) - sv = StateVar(0) - ee = EnterExit(sv, enter, exit) - sv.set(0) - assert not l - sv.set(1) - assert l == [1,] - sv.set(2) - assert l == [1,] - sv.set(0) - assert l == [1,0,] - sv.set(True) - assert l == [1,0,1,] - sv.set(False) - assert l == [1,0,1,0,] - ee.destroy() - sv.destroy() - del ee - del sv - del enter - del exit - del l class Pulse(PushesStateChanges): # changes state to True then immediately to False whenever sendPulse is called @@ -351,25 +233,6 @@ class Pulse(PushesStateChanges): self._handlePotentialStateChange(True) self._handlePotentialStateChange(False) -if __debug__: - l = [] - def handler(value, l=l): - l.append(value) - p = Pulse() - fc = FunctionCall(handler, p) - assert not l - fc.pushCurrentState() - assert l == [False, ] - p.sendPulse() - assert l == [False, True, False, ] - p.sendPulse() - assert l == [False, True, False, True, False, ] - fc.destroy() - p.destroy() - del fc - del p - del l - del handler class EventPulse(Pulse, DirectObject): # sends a True-False "pulse" whenever a specific messenger message is sent @@ -381,6 +244,7 @@ class EventPulse(Pulse, DirectObject): self.ignoreAll() Pulse.destroy(self) + class EventArgument(PushesStateChanges, DirectObject): # tracks a particular argument to a particular messenger event def __init__(self, event, index=0): @@ -396,6 +260,7 @@ class EventArgument(PushesStateChanges, DirectObject): def _handleEvent(self, *args): self._handlePotentialStateChange(args[self._index]) + class AttrSetter(StateChangeNode): def __init__(self, source, object, attrName): self._object = object @@ -406,19 +271,3 @@ class AttrSetter(StateChangeNode): def _handleStateChange(self): setattr(self._object, self._attrName, self._value) StateChangeNode._handleStateChange(self) - -if __debug__: - from direct.showbase.PythonUtil import ScratchPad - o = ScratchPad() - svar = StateVar(0) - aset = AttrSetter(svar, o, 'testAttr') - assert hasattr(o, 'testAttr') - assert o.testAttr == 0 - svar.set('red') - assert o.testAttr == 'red' - aset.destroy() - svar.destroy() - o.destroy() - del aset - del svar - del o diff --git a/direct/src/physics/__init__.py b/direct/src/physics/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/direct/src/showbase/CountedResource.py b/direct/src/showbase/CountedResource.py index a1463470e8..45b76ad31c 100755 --- a/direct/src/showbase/CountedResource.py +++ b/direct/src/showbase/CountedResource.py @@ -81,147 +81,3 @@ class CountedResource(object): def __del__(self): self.decrementCounter() - - -if __debug__ and __name__ == '__main__': - class MouseResource(CountedResource): - """ - A simple class to demonstrate the acquisition of a resource. - """ - @classmethod - def acquire(cls): - # The call to the super-class's acquire() is - # not necessary at the moment, but may be in - # the future, so do it now for good measure. - super(MouseResource, cls).acquire() - - # Now acquire the resource this class is - # managing. - print('-- Acquire Mouse') - - @classmethod - def release(cls): - # First, release the resource this class is - # managing. - print('-- Release Mouse') - - # The call to the super-class's release() is - # not necessary at the moment, but may be in - # the future, so do it now for good measure. - super(MouseResource, cls).release() - - - def __init__(self): - super(MouseResource, self).__init__() - - def __del__(self): - super(MouseResource, self).__del__() - - class CursorResource(CountedResource): - """ - A class to demonstrate how to implement a dependent - resource. Notice how this class also inherits from - CountedResource. Instead of subclassing MouseCounter, - we will just acquire it in our __init__() and release - it in our __del__(). - """ - @classmethod - def acquire(cls): - super(CursorResource, cls).acquire() - print('-- Acquire Cursor') - - @classmethod - def release(cls): - print('-- Release Cursor') - - super(CursorResource, cls).release() - - def __init__(self): - # The required resource references should - # be stored on 'self' since we want to - # release it when the object is deleted. - self.__mouseResource = MouseResource() - - # Call the super-classes __init__() - # after all required resources are - # referenced. - super(CursorResource, self).__init__() - - def __del__(self): - # Free up the most dependent resource - # first, the one this class is managing. - super(CursorResource, self).__del__() - - # Now unlink any required resources. - del self.__mouseResource - - class InvalidResource(MouseResource): - @classmethod - def acquire(cls): - super(InvalidResource, cls).acquire() - print('-- Acquire Invalid') - - @classmethod - def release(cls): - print('-- Release Invalid') - super(InvalidResource, cls).release() - - print('\nAllocate Mouse') - m = MouseResource() - print('Free up Mouse') - del m - - print('\nAllocate Cursor') - c = CursorResource() - print('Free up Cursor') - del c - - print('\nAllocate Mouse then Cursor') - m = MouseResource() - c = CursorResource() - print('Free up Cursor') - del c - print('Free up Mouse') - del m - - print('\nAllocate Mouse then Cursor') - m = MouseResource() - c = CursorResource() - print('Free up Mouse') - del m - print('Free up Cursor') - del c - - print('\nAllocate Cursor then Mouse') - c = CursorResource() - m = MouseResource() - print('Free up Mouse') - del m - print('Free up Cursor') - del c - - print('\nAllocate Cursor then Mouse') - c = CursorResource() - m = MouseResource() - print('Free up Cursor') - del c - - # example of an invalid subclass - try: - print('\nAllocate Invalid') - i = InvalidResource() - print('Free up Invalid') - except AssertionError as e: - print(e) - print('') - - print('Free up Mouse') - del m - - def demoFunc(): - print('\nAllocate Cursor within function') - c = CursorResource() - - print('Cursor will be freed on function exit') - - demoFunc() diff --git a/direct/src/showbase/DistancePhasedNode.py b/direct/src/showbase/DistancePhasedNode.py index 8ca2b3c12c..0f0a426e99 100755 --- a/direct/src/showbase/DistancePhasedNode.py +++ b/direct/src/showbase/DistancePhasedNode.py @@ -327,31 +327,3 @@ class BufferedDistancePhasedNode(DistancePhasedNode): for x,sphere in enumerate(self._colSpheres[phase+1:]): sphere.node().modifySolid(0).setRadius(self.bufferParamList[x+phase+1][1][0]) sphere.node().markInternalBoundsStale() - - -if __debug__ and 0: - cSphere = CollisionSphere(0, 0, 0, 0.1) - cNode = CollisionNode('camCol') - cNode.addSolid(cSphere) - cNodePath = NodePath(cNode) - cNodePath.reparentTo(base.cam) - # cNodePath.show() - # cNodePath.setPos(25,0,0) - - base.cTrav = CollisionTraverser() - - eventHandler = CollisionHandlerEvent() - eventHandler.addInPattern('enter%in') - eventHandler.addOutPattern('exit%in') - - # messenger.toggleVerbose() - base.cTrav.addCollider(cNodePath, eventHandler) - - p = BufferedDistancePhasedNode('p', {'At': (10, 20), 'Near': (100, 200), 'Far': (1000, 1020)}, - autoCleanup=False, - fromCollideNode=cNodePath, - ) - - p.reparentTo(render) - p._DistancePhasedNode__oneTimeCollide() - base.eventMgr.doEvents() diff --git a/direct/src/showbase/PythonUtil.py b/direct/src/showbase/PythonUtil.py index 370a67d408..7ca1b36fe1 100644 --- a/direct/src/showbase/PythonUtil.py +++ b/direct/src/showbase/PythonUtil.py @@ -2458,18 +2458,6 @@ def formatTimeCompact(seconds): return result -if __debug__ and __name__ == '__main__': - ftc = formatTimeCompact - assert ftc(0) == '0s' - assert ftc(1) == '1s' - assert ftc(60) == '1m0s' - assert ftc(64) == '1m4s' - assert ftc(60*60) == '1h0m0s' - assert ftc(24*60*60) == '1d0h0m0s' - assert ftc(24*60*60 + 2*60*60 + 34*60 + 12) == '1d2h34m12s' - del ftc - - def formatTimeExact(seconds): # like formatTimeCompact but leaves off '0 seconds', '0 minutes' etc. for # times that are e.g. 1 hour, 3 days etc. @@ -2496,19 +2484,6 @@ def formatTimeExact(seconds): return result -if __debug__ and __name__ == '__main__': - fte = formatTimeExact - assert fte(0) == '0s' - assert fte(1) == '1s' - assert fte(2) == '2s' - assert fte(61) == '1m1s' - assert fte(60) == '1m' - assert fte(60*60) == '1h' - assert fte(24*60*60) == '1d' - assert fte((24*60*60) + (2 * 60)) == '1d0h2m' - del fte - - class AlphabetCounter: # object that produces 'A', 'B', 'C', ... 'AA', 'AB', etc. def __init__(self): @@ -2540,28 +2515,6 @@ class AlphabetCounter: __next__ = next -if __debug__ and __name__ == '__main__': - def testAlphabetCounter(): - tempList = [] - ac = AlphabetCounter() - for i in range(26*3): - tempList.append(ac.next()) - assert tempList == [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ', - 'BA','BB','BC','BD','BE','BF','BG','BH','BI','BJ','BK','BL','BM','BN','BO','BP','BQ','BR','BS','BT','BU','BV','BW','BX','BY','BZ',] - ac = AlphabetCounter() - num = 26 # A-Z - num += (26*26) # AA-ZZ - num += 26 # AAZ - num += 1 # ABA - num += 2 # ABC - for i in range(num): - x = ac.next() - assert x == 'ABC' - testAlphabetCounter() - del testAlphabetCounter - - class Default: # represents 'use the default value' # useful for keyword arguments to virtual methods diff --git a/direct/src/stdpy/threading.py b/direct/src/stdpy/threading.py index 97cdf387f0..96effd86b5 100644 --- a/direct/src/stdpy/threading.py +++ b/direct/src/stdpy/threading.py @@ -435,108 +435,3 @@ def setprofile(func): def stack_size(size = None): raise ThreadError - - -if __debug__: - def _test(): - from collections import deque - - _sleep = core.Thread.sleep - - _VERBOSE = False - - class _Verbose(object): - - def __init__(self, verbose=None): - if verbose is None: - verbose = _VERBOSE - self.__verbose = verbose - - def _note(self, format, *args): - if self.__verbose: - format = format % args - format = "%s: %s\n" % ( - currentThread().getName(), format) - _sys.stderr.write(format) - - class BoundedQueue(_Verbose): - - def __init__(self, limit): - _Verbose.__init__(self) - self.mon = Lock(name = "BoundedQueue.mon") - self.rc = Condition(self.mon) - self.wc = Condition(self.mon) - self.limit = limit - self.queue = deque() - - def put(self, item): - self.mon.acquire() - while len(self.queue) >= self.limit: - self._note("put(%s): queue full", item) - self.wc.wait() - self.queue.append(item) - self._note("put(%s): appended, length now %d", - item, len(self.queue)) - self.rc.notify() - self.mon.release() - - def get(self): - self.mon.acquire() - while not self.queue: - self._note("get(): queue empty") - self.rc.wait() - item = self.queue.popleft() - self._note("get(): got %s, %d left", item, len(self.queue)) - self.wc.notify() - self.mon.release() - return item - - class ProducerThread(Thread): - - def __init__(self, queue, quota): - Thread.__init__(self, name="Producer") - self.queue = queue - self.quota = quota - - def run(self): - from random import random - counter = 0 - while counter < self.quota: - counter = counter + 1 - self.queue.put("%s.%d" % (self.getName(), counter)) - _sleep(random() * 0.00001) - - class ConsumerThread(Thread): - - def __init__(self, queue, count): - Thread.__init__(self, name="Consumer") - self.queue = queue - self.count = count - - def run(self): - while self.count > 0: - item = self.queue.get() - print(item) - self.count = self.count - 1 - - NP = 3 - QL = 4 - NI = 5 - - Q = BoundedQueue(QL) - P = [] - for i in range(NP): - t = ProducerThread(Q, NI) - t.setName("Producer-%d" % (i+1)) - P.append(t) - C = ConsumerThread(Q, NI*NP) - for t in P: - t.start() - _sleep(0.000001) - C.start() - for t in P: - t.join() - C.join() - - if __name__ == '__main__': - _test() diff --git a/direct/src/stdpy/threading2.py b/direct/src/stdpy/threading2.py index 3bc3f22b1e..8bdde3a27c 100644 --- a/direct/src/stdpy/threading2.py +++ b/direct/src/stdpy/threading2.py @@ -762,92 +762,3 @@ def main_thread(): ## from thread import _local as local ## except ImportError: ## from _threading_local import local - - -# Self-test code -if __debug__: - def _test(): - from collections import deque - - class BoundedQueue(_Verbose): - - def __init__(self, limit): - _Verbose.__init__(self) - self.mon = RLock() - self.rc = Condition(self.mon) - self.wc = Condition(self.mon) - self.limit = limit - self.queue = deque() - - def put(self, item): - self.mon.acquire() - while len(self.queue) >= self.limit: - self._note("put(%s): queue full", item) - self.wc.wait() - self.queue.append(item) - self._note("put(%s): appended, length now %d", - item, len(self.queue)) - self.rc.notify() - self.mon.release() - - def get(self): - self.mon.acquire() - while not self.queue: - self._note("get(): queue empty") - self.rc.wait() - item = self.queue.popleft() - self._note("get(): got %s, %d left", item, len(self.queue)) - self.wc.notify() - self.mon.release() - return item - - class ProducerThread(Thread): - - def __init__(self, queue, quota): - Thread.__init__(self, name="Producer") - self.queue = queue - self.quota = quota - - def run(self): - from random import random - counter = 0 - while counter < self.quota: - counter = counter + 1 - self.queue.put("%s.%d" % (self.getName(), counter)) - _sleep(random() * 0.00001) - - - class ConsumerThread(Thread): - - def __init__(self, queue, count): - Thread.__init__(self, name="Consumer") - self.queue = queue - self.count = count - - def run(self): - while self.count > 0: - item = self.queue.get() - print(item) - self.count = self.count - 1 - - NP = 3 - QL = 4 - NI = 5 - - Q = BoundedQueue(QL) - P = [] - for i in range(NP): - t = ProducerThread(Q, NI) - t.setName("Producer-%d" % (i+1)) - P.append(t) - C = ConsumerThread(Q, NI*NP) - for t in P: - t.start() - _sleep(0.000001) - C.start() - for t in P: - t.join() - C.join() - - if __name__ == '__main__': - _test() diff --git a/direct/src/task/Task.py b/direct/src/task/Task.py index 24358b3573..470eb73cdf 100644 --- a/direct/src/task/Task.py +++ b/direct/src/task/Task.py @@ -801,532 +801,6 @@ class TaskManager: # time.sleep(delta) # delta = minFinTime - self.globalClock.getRealTime() - if __debug__: - # to catch memory leaks during the tests at the bottom of the file - def _startTrackingMemLeaks(self): - pass - - def _stopTrackingMemLeaks(self): - pass - - def _checkMemLeaks(self): - pass - - def _runTests(self): - if __debug__: - tm = TaskManager() - tm.setClock(ClockObject()) - tm.setupTaskChain("default", tickClock = True) - - # check for memory leaks after every test - tm._startTrackingMemLeaks() - tm._checkMemLeaks() - - # run-once task - l = [] - - def _testDone(task, l=l): - l.append(None) - return task.done - tm.add(_testDone, 'testDone') - tm.step() - assert len(l) == 1 - tm.step() - assert len(l) == 1 - _testDone = None - tm._checkMemLeaks() - - # remove by name - def _testRemoveByName(task): - return task.done - tm.add(_testRemoveByName, 'testRemoveByName') - assert tm.remove('testRemoveByName') == 1 - assert tm.remove('testRemoveByName') == 0 - _testRemoveByName = None - tm._checkMemLeaks() - - # duplicate named tasks - def _testDupNamedTasks(task): - return task.done - tm.add(_testDupNamedTasks, 'testDupNamedTasks') - tm.add(_testDupNamedTasks, 'testDupNamedTasks') - assert tm.remove('testRemoveByName') == 0 - _testDupNamedTasks = None - tm._checkMemLeaks() - - # continued task - l = [] - - def _testCont(task, l = l): - l.append(None) - return task.cont - tm.add(_testCont, 'testCont') - tm.step() - assert len(l) == 1 - tm.step() - assert len(l) == 2 - tm.remove('testCont') - _testCont = None - tm._checkMemLeaks() - - # continue until done task - l = [] - - def _testContDone(task, l = l): - l.append(None) - if len(l) >= 2: - return task.done - else: - return task.cont - tm.add(_testContDone, 'testContDone') - tm.step() - assert len(l) == 1 - tm.step() - assert len(l) == 2 - tm.step() - assert len(l) == 2 - assert not tm.hasTaskNamed('testContDone') - _testContDone = None - tm._checkMemLeaks() - - # hasTaskNamed - def _testHasTaskNamed(task): - return task.done - tm.add(_testHasTaskNamed, 'testHasTaskNamed') - assert tm.hasTaskNamed('testHasTaskNamed') - tm.step() - assert not tm.hasTaskNamed('testHasTaskNamed') - _testHasTaskNamed = None - tm._checkMemLeaks() - - # task sort - l = [] - - def _testPri1(task, l = l): - l.append(1) - return task.cont - - def _testPri2(task, l = l): - l.append(2) - return task.cont - tm.add(_testPri1, 'testPri1', sort = 1) - tm.add(_testPri2, 'testPri2', sort = 2) - tm.step() - assert len(l) == 2 - assert l == [1, 2,] - tm.step() - assert len(l) == 4 - assert l == [1, 2, 1, 2,] - tm.remove('testPri1') - tm.remove('testPri2') - _testPri1 = None - _testPri2 = None - tm._checkMemLeaks() - - # task extraArgs - l = [] - - def _testExtraArgs(arg1, arg2, l=l): - l.extend([arg1, arg2,]) - return done - tm.add(_testExtraArgs, 'testExtraArgs', extraArgs=[4,5]) - tm.step() - assert len(l) == 2 - assert l == [4, 5,] - _testExtraArgs = None - tm._checkMemLeaks() - - # task appendTask - l = [] - - def _testAppendTask(arg1, arg2, task, l=l): - l.extend([arg1, arg2,]) - return task.done - tm.add(_testAppendTask, '_testAppendTask', extraArgs=[4,5], appendTask=True) - tm.step() - assert len(l) == 2 - assert l == [4, 5,] - _testAppendTask = None - tm._checkMemLeaks() - - # task uponDeath - l = [] - - def _uponDeathFunc(task, l=l): - l.append(task.name) - - def _testUponDeath(task): - return done - tm.add(_testUponDeath, 'testUponDeath', uponDeath=_uponDeathFunc) - tm.step() - assert len(l) == 1 - assert l == ['testUponDeath'] - _testUponDeath = None - _uponDeathFunc = None - tm._checkMemLeaks() - - # task owner - class _TaskOwner: - def _addTask(self, task): - self.addedTaskName = task.name - - def _clearTask(self, task): - self.clearedTaskName = task.name - to = _TaskOwner() - l = [] - - def _testOwner(task): - return done - tm.add(_testOwner, 'testOwner', owner=to) - tm.step() - assert getattr(to, 'addedTaskName', None) == 'testOwner' - assert getattr(to, 'clearedTaskName', None) == 'testOwner' - _testOwner = None - del to - _TaskOwner = None - tm._checkMemLeaks() - - doLaterTests = [0,] - - # doLater - l = [] - - def _testDoLater1(task, l=l): - l.append(1) - - def _testDoLater2(task, l=l): - l.append(2) - - def _monitorDoLater(task, tm=tm, l=l, doLaterTests=doLaterTests): - if task.time > .03: - assert l == [1, 2,] - doLaterTests[0] -= 1 - return task.done - return task.cont - tm.doMethodLater(.01, _testDoLater1, 'testDoLater1') - tm.doMethodLater(.02, _testDoLater2, 'testDoLater2') - doLaterTests[0] += 1 - # make sure we run this task after the doLaters if they all occur on the same frame - tm.add(_monitorDoLater, 'monitorDoLater', sort=10) - _testDoLater1 = None - _testDoLater2 = None - _monitorDoLater = None - # don't check until all the doLaters are finished - #tm._checkMemLeaks() - - # doLater sort - l = [] - - def _testDoLaterPri1(task, l=l): - l.append(1) - - def _testDoLaterPri2(task, l=l): - l.append(2) - - def _monitorDoLaterPri(task, tm=tm, l=l, doLaterTests=doLaterTests): - if task.time > .02: - assert l == [1, 2,] - doLaterTests[0] -= 1 - return task.done - return task.cont - tm.doMethodLater(.01, _testDoLaterPri1, 'testDoLaterPri1', sort=1) - tm.doMethodLater(.01, _testDoLaterPri2, 'testDoLaterPri2', sort=2) - doLaterTests[0] += 1 - # make sure we run this task after the doLaters if they all occur on the same frame - tm.add(_monitorDoLaterPri, 'monitorDoLaterPri', sort=10) - _testDoLaterPri1 = None - _testDoLaterPri2 = None - _monitorDoLaterPri = None - # don't check until all the doLaters are finished - #tm._checkMemLeaks() - - # doLater extraArgs - l = [] - - def _testDoLaterExtraArgs(arg1, l=l): - l.append(arg1) - - def _monitorDoLaterExtraArgs(task, tm=tm, l=l, doLaterTests=doLaterTests): - if task.time > .02: - assert l == [3,] - doLaterTests[0] -= 1 - return task.done - return task.cont - tm.doMethodLater(.01, _testDoLaterExtraArgs, 'testDoLaterExtraArgs', extraArgs=[3,]) - doLaterTests[0] += 1 - # make sure we run this task after the doLaters if they all occur on the same frame - tm.add(_monitorDoLaterExtraArgs, 'monitorDoLaterExtraArgs', sort=10) - _testDoLaterExtraArgs = None - _monitorDoLaterExtraArgs = None - # don't check until all the doLaters are finished - #tm._checkMemLeaks() - - # doLater appendTask - l = [] - - def _testDoLaterAppendTask(arg1, task, l=l): - assert task.name == 'testDoLaterAppendTask' - l.append(arg1) - - def _monitorDoLaterAppendTask(task, tm=tm, l=l, doLaterTests=doLaterTests): - if task.time > .02: - assert l == [4,] - doLaterTests[0] -= 1 - return task.done - return task.cont - tm.doMethodLater(.01, _testDoLaterAppendTask, 'testDoLaterAppendTask', - extraArgs=[4,], appendTask=True) - doLaterTests[0] += 1 - # make sure we run this task after the doLaters if they all occur on the same frame - tm.add(_monitorDoLaterAppendTask, 'monitorDoLaterAppendTask', sort=10) - _testDoLaterAppendTask = None - _monitorDoLaterAppendTask = None - # don't check until all the doLaters are finished - #tm._checkMemLeaks() - - # doLater uponDeath - l = [] - - def _testUponDeathFunc(task, l=l): - assert task.name == 'testDoLaterUponDeath' - l.append(10) - - def _testDoLaterUponDeath(arg1, l=l): - return done - - def _monitorDoLaterUponDeath(task, tm=tm, l=l, doLaterTests=doLaterTests): - if task.time > .02: - assert l == [10,] - doLaterTests[0] -= 1 - return task.done - return task.cont - tm.doMethodLater(.01, _testDoLaterUponDeath, 'testDoLaterUponDeath', - uponDeath=_testUponDeathFunc) - doLaterTests[0] += 1 - # make sure we run this task after the doLaters if they all occur on the same frame - tm.add(_monitorDoLaterUponDeath, 'monitorDoLaterUponDeath', sort=10) - _testUponDeathFunc = None - _testDoLaterUponDeath = None - _monitorDoLaterUponDeath = None - # don't check until all the doLaters are finished - #tm._checkMemLeaks() - - # doLater owner - class _DoLaterOwner: - def _addTask(self, task): - self.addedTaskName = task.name - - def _clearTask(self, task): - self.clearedTaskName = task.name - doLaterOwner = _DoLaterOwner() - l = [] - - def _testDoLaterOwner(l=l): - pass - - def _monitorDoLaterOwner(task, tm=tm, l=l, doLaterOwner=doLaterOwner, - doLaterTests=doLaterTests): - if task.time > .02: - assert getattr(doLaterOwner, 'addedTaskName', None) == 'testDoLaterOwner' - assert getattr(doLaterOwner, 'clearedTaskName', None) == 'testDoLaterOwner' - doLaterTests[0] -= 1 - return task.done - return task.cont - tm.doMethodLater(.01, _testDoLaterOwner, 'testDoLaterOwner', - owner=doLaterOwner) - doLaterTests[0] += 1 - # make sure we run this task after the doLaters if they all occur on the same frame - tm.add(_monitorDoLaterOwner, 'monitorDoLaterOwner', sort=10) - _testDoLaterOwner = None - _monitorDoLaterOwner = None - del doLaterOwner - _DoLaterOwner = None - # don't check until all the doLaters are finished - #tm._checkMemLeaks() - - # run the doLater tests - while doLaterTests[0] > 0: - tm.step() - del doLaterTests - tm._checkMemLeaks() - - # getTasks - def _testGetTasks(task): - return task.cont - # No doLaterProcessor in the new world. - assert len(tm.getTasks()) == 0 - tm.add(_testGetTasks, 'testGetTasks1') - assert len(tm.getTasks()) == 1 - assert (tm.getTasks()[0].name == 'testGetTasks1' or - tm.getTasks()[1].name == 'testGetTasks1') - tm.add(_testGetTasks, 'testGetTasks2') - tm.add(_testGetTasks, 'testGetTasks3') - assert len(tm.getTasks()) == 3 - tm.remove('testGetTasks2') - assert len(tm.getTasks()) == 2 - tm.remove('testGetTasks1') - tm.remove('testGetTasks3') - assert len(tm.getTasks()) == 0 - _testGetTasks = None - tm._checkMemLeaks() - - # getDoLaters - def _testGetDoLaters(): - pass - assert len(tm.getDoLaters()) == 0 - tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater1') - assert len(tm.getDoLaters()) == 1 - assert tm.getDoLaters()[0].name == 'testDoLater1' - tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater2') - tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater3') - assert len(tm.getDoLaters()) == 3 - tm.remove('testDoLater2') - assert len(tm.getDoLaters()) == 2 - tm.remove('testDoLater1') - tm.remove('testDoLater3') - assert len(tm.getDoLaters()) == 0 - _testGetDoLaters = None - tm._checkMemLeaks() - - # duplicate named doLaters removed via taskMgr.remove - def _testDupNameDoLaters(): - pass - # the doLaterProcessor is always running - tm.doMethodLater(.1, _testDupNameDoLaters, 'testDupNameDoLater') - tm.doMethodLater(.1, _testDupNameDoLaters, 'testDupNameDoLater') - assert len(tm.getDoLaters()) == 2 - tm.remove('testDupNameDoLater') - assert len(tm.getDoLaters()) == 0 - _testDupNameDoLaters = None - tm._checkMemLeaks() - - # duplicate named doLaters removed via remove() - def _testDupNameDoLatersRemove(): - pass - # the doLaterProcessor is always running - dl1 = tm.doMethodLater(.1, _testDupNameDoLatersRemove, 'testDupNameDoLaterRemove') - dl2 = tm.doMethodLater(.1, _testDupNameDoLatersRemove, 'testDupNameDoLaterRemove') - assert len(tm.getDoLaters()) == 2 - dl2.remove() - assert len(tm.getDoLaters()) == 1 - dl1.remove() - assert len(tm.getDoLaters()) == 0 - _testDupNameDoLatersRemove = None - # nameDict etc. isn't cleared out right away with task.remove() - tm._checkMemLeaks() - - # getTasksNamed - def _testGetTasksNamed(task): - return task.cont - assert len(tm.getTasksNamed('testGetTasksNamed')) == 0 - tm.add(_testGetTasksNamed, 'testGetTasksNamed') - assert len(tm.getTasksNamed('testGetTasksNamed')) == 1 - assert tm.getTasksNamed('testGetTasksNamed')[0].name == 'testGetTasksNamed' - tm.add(_testGetTasksNamed, 'testGetTasksNamed') - tm.add(_testGetTasksNamed, 'testGetTasksNamed') - assert len(tm.getTasksNamed('testGetTasksNamed')) == 3 - tm.remove('testGetTasksNamed') - assert len(tm.getTasksNamed('testGetTasksNamed')) == 0 - _testGetTasksNamed = None - tm._checkMemLeaks() - - # removeTasksMatching - def _testRemoveTasksMatching(task): - return task.cont - tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching') - assert len(tm.getTasksNamed('testRemoveTasksMatching')) == 1 - tm.removeTasksMatching('testRemoveTasksMatching') - assert len(tm.getTasksNamed('testRemoveTasksMatching')) == 0 - tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching1') - tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching2') - assert len(tm.getTasksNamed('testRemoveTasksMatching1')) == 1 - assert len(tm.getTasksNamed('testRemoveTasksMatching2')) == 1 - tm.removeTasksMatching('testRemoveTasksMatching*') - assert len(tm.getTasksNamed('testRemoveTasksMatching1')) == 0 - assert len(tm.getTasksNamed('testRemoveTasksMatching2')) == 0 - tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching1a') - tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching2a') - assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 1 - assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 1 - tm.removeTasksMatching('testRemoveTasksMatching?a') - assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 0 - assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 0 - _testRemoveTasksMatching = None - tm._checkMemLeaks() - - # create Task object and add to mgr - l = [] - - def _testTaskObj(task, l=l): - l.append(None) - return task.cont - t = Task(_testTaskObj) - tm.add(t, 'testTaskObj') - tm.step() - assert len(l) == 1 - tm.step() - assert len(l) == 2 - tm.remove('testTaskObj') - tm.step() - assert len(l) == 2 - _testTaskObj = None - tm._checkMemLeaks() - - # remove Task via task.remove() - l = [] - - def _testTaskObjRemove(task, l=l): - l.append(None) - return task.cont - t = Task(_testTaskObjRemove) - tm.add(t, 'testTaskObjRemove') - tm.step() - assert len(l) == 1 - tm.step() - assert len(l) == 2 - t.remove() - tm.step() - assert len(l) == 2 - del t - _testTaskObjRemove = None - tm._checkMemLeaks() - - # this test fails, and it's not clear what the correct behavior should be. - # sort passed to Task.__init__ is always overridden by taskMgr.add() - # even if no sort is specified, and calling Task.setSort() has no - # effect on the taskMgr's behavior. - # set/get Task sort - #l = [] - #def _testTaskObjSort(arg, task, l=l): - # l.append(arg) - # return task.cont - #t1 = Task(_testTaskObjSort, sort=1) - #t2 = Task(_testTaskObjSort, sort=2) - #tm.add(t1, 'testTaskObjSort1', extraArgs=['a',], appendTask=True) - #tm.add(t2, 'testTaskObjSort2', extraArgs=['b',], appendTask=True) - #tm.step() - #assert len(l) == 2 - #assert l == ['a', 'b'] - #assert t1.getSort() == 1 - #assert t2.getSort() == 2 - #t1.setSort(3) - #assert t1.getSort() == 3 - #tm.step() - #assert len(l) == 4 - #assert l == ['a', 'b', 'b', 'a',] - #t1.remove() - #t2.remove() - #tm.step() - #assert len(l) == 4 - #del t1 - #del t2 - #_testTaskObjSort = None - #tm._checkMemLeaks() - - del l - tm.destroy() - del tm - if __debug__: def checkLeak(): diff --git a/direct/src/tkpanels/ParticlePanel.py b/direct/src/tkpanels/ParticlePanel.py index 7408497ac2..6d41ba808f 100644 --- a/direct/src/tkpanels/ParticlePanel.py +++ b/direct/src/tkpanels/ParticlePanel.py @@ -2909,21 +2909,3 @@ class ParticlePanel(AppShell): min = 0.01, value = force.getRadius()) self.createForceActiveWidget(frame, pageName, forceName, force) - -###################################################################### - - -# Create demo in root window for testing. -if __name__ == '__main__': - try: - base - except NameError: - from direct.showbase.ShowBase import ShowBase - base = ShowBase() - - root = Pmw.initialise() - pp = ParticlePanel() - base.pp=pp - #ve = VectorEntry(Toplevel(), relief = GROOVE) - #ve.pack() - base.run() diff --git a/direct/src/tkpanels/Placer.py b/direct/src/tkpanels/Placer.py index addbe1f414..6fdf0767f1 100644 --- a/direct/src/tkpanels/Placer.py +++ b/direct/src/tkpanels/Placer.py @@ -786,11 +786,3 @@ class Placer(AppShell): def place(nodePath): return Placer(nodePath = nodePath) - -###################################################################### - - -# Create demo in root window for testing. -if __name__ == '__main__': - root = Pmw.initialise() - widget = Placer() diff --git a/direct/src/tkwidgets/AppShell.py b/direct/src/tkwidgets/AppShell.py index ad76a7ccae..b5913e958e 100644 --- a/direct/src/tkwidgets/AppShell.py +++ b/direct/src/tkwidgets/AppShell.py @@ -550,7 +550,3 @@ class TestAppShell(AppShell): def createInterface(self): self.createButtons() self.createMain() - - -if __name__ == '__main__': - test = TestAppShell(balloon_state='none') diff --git a/direct/src/tkwidgets/Dial.py b/direct/src/tkwidgets/Dial.py index 2b1c062439..ca2211ea77 100644 --- a/direct/src/tkwidgets/Dial.py +++ b/direct/src/tkwidgets/Dial.py @@ -422,18 +422,3 @@ class DialWidget(Pmw.MegaWidget): """ User redefinable callback executed on button release """ if self['postCallback']: self['postCallback'](*self['callbackData']) - - -if __name__ == '__main__': - tl = tk.Toplevel() - d = Dial(tl) - d2 = Dial(tl, dial_numSegments = 12, max = 360, - dial_fRollover = 0, value = 180) - d3 = Dial(tl, dial_numSegments = 12, max = 90, min = -90, - dial_fRollover = 0) - d4 = Dial(tl, dial_numSegments = 16, max = 256, - dial_fRollover = 0) - d.pack(expand = 1, fill = tk.X) - d2.pack(expand = 1, fill = tk.X) - d3.pack(expand = 1, fill = tk.X) - d4.pack(expand = 1, fill = tk.X) diff --git a/direct/src/tkwidgets/EntryScale.py b/direct/src/tkwidgets/EntryScale.py index cb6516275c..5ae9bf335e 100644 --- a/direct/src/tkwidgets/EntryScale.py +++ b/direct/src/tkwidgets/EntryScale.py @@ -517,45 +517,3 @@ def rgbPanel(nodePath, callback = None): messenger.send('RGBPanel_setColor', [nodePath, r, g, b, a]) esg['postCallback'] = onRelease return esg - - -## SAMPLE CODE -if __name__ == '__main__': - # Initialise Tkinter and Pmw. - root = tk.Toplevel() - root.title('Pmw EntryScale demonstration') - - # Dummy command - def printVal(val): - print(val) - - # Create and pack a EntryScale megawidget. - mega1 = EntryScale(root, command = printVal) - mega1.pack(side = 'left', expand = 1, fill = 'x') - - # These are things you can set/configure - # Starting value for entryScale - #mega1['value'] = 123.456 - #mega1['text'] = 'Drive delta X' - #mega1['min'] = 0.0 - #mega1['max'] = 1000.0 - #mega1['resolution'] = 1.0 - # To change the color of the label: - #mega1.label['foreground'] = 'Red' - # Max change/update, default is 100 - # To have really fine control, for example - # mega1['maxVelocity'] = 0.1 - # Number of digits to the right of the decimal point, default = 2 - # mega1['numDigits'] = 5 - - # To create a entryScale group to set an RGBA value: - group1 = EntryScaleGroup(root, dim = 4, - title = 'Simple RGBA Panel', - labels = ('R', 'G', 'B', 'A'), - Valuator_min = 0.0, - Valuator_max = 255.0, - Valuator_resolution = 1.0, - command = printVal) - - # Uncomment this if you aren't running in IDLE - #root.mainloop() diff --git a/direct/src/tkwidgets/Floater.py b/direct/src/tkwidgets/Floater.py index 6544eb3890..432070f6ec 100644 --- a/direct/src/tkwidgets/Floater.py +++ b/direct/src/tkwidgets/Floater.py @@ -329,42 +329,3 @@ class FloaterGroup(Pmw.MegaToplevel): def reset(self): self.set(self['value']) - - -## SAMPLE CODE -if __name__ == '__main__': - # Initialise Tkinter and Pmw. - root = tk.Toplevel() - root.title('Pmw Floater demonstration') - - # Dummy command - def printVal(val): - print(val) - - # Create and pack a Floater megawidget. - mega1 = Floater(root, command = printVal) - mega1.pack(side = 'left', expand = 1, fill = 'x') - - # These are things you can set/configure - # Starting value for floater - #mega1['value'] = 123.456 - #mega1['text'] = 'Drive delta X' - # To change the color of the label: - #mega1.label['foreground'] = 'Red' - # Max change/update, default is 100 - # To have really fine control, for example - #mega1['maxVelocity'] = 0.1 - # Number of digits to the right of the decimal point, default = 2 - #mega1['numDigits'] = 5 - - # To create a floater group to set an RGBA value: - group1 = FloaterGroup(root, dim = 4, - title = 'Simple RGBA Panel', - labels = ('R', 'G', 'B', 'A'), - Valuator_min = 0.0, - Valuator_max = 255.0, - Valuator_resolution = 1.0, - command = printVal) - - # Uncomment this if you aren't running in IDLE - #root.mainloop() diff --git a/direct/src/tkwidgets/VectorWidgets.py b/direct/src/tkwidgets/VectorWidgets.py index 6797782f71..e9abf8f63d 100644 --- a/direct/src/tkwidgets/VectorWidgets.py +++ b/direct/src/tkwidgets/VectorWidgets.py @@ -329,17 +329,3 @@ class ColorEntry(VectorEntry): initialcolor = tuple(self.get()[:3]))[0] if color: self.set((color[0], color[1], color[2], self.getAt(3))) - - -if __name__ == '__main__': - root = tk.Toplevel() - root.title('Vector Widget demo') - - ve = VectorEntry(root) - ve.pack() - v3e = Vector3Entry(root) - v3e.pack() - v4e = Vector4Entry(root) - v4e.pack() - ce = ColorEntry(root) - ce.pack() diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 0000000000..bf6a71e61c --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,4 @@ +pytest +pytest-cov + +Pmw-py3==2.1 diff --git a/tests/display/conftest.py b/tests/conftest.py similarity index 77% rename from tests/display/conftest.py rename to tests/conftest.py index 36d498b9a3..9c2a01c6ca 100644 --- a/tests/display/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,27 @@ +import sys +import tkinter as tk import pytest +from panda3d import core +from direct.showbase.ShowBase import ShowBase + + +@pytest.fixture +def base(): + base = ShowBase(windowType='none') + yield base + base.destroy() + + +@pytest.fixture +def tk_toplevel(): + if sys.platform == 'darwin' and not core.ConfigVariableBool('want-tk', False): + pytest.skip('"want-tk" must be true to use tkinter with Panda3D on macOS') + try: + root = tk.Toplevel() + except tk.TclError as e: + pytest.skip(str(e)) + yield root + root.destroy() @pytest.fixture(scope='session') diff --git a/tests/distributed/test_CRDataCache.py b/tests/distributed/test_CRDataCache.py new file mode 100644 index 0000000000..1ba4928487 --- /dev/null +++ b/tests/distributed/test_CRDataCache.py @@ -0,0 +1,42 @@ +from direct.distributed.CachedDOData import CachedDOData +from direct.distributed.CRDataCache import CRDataCache + + +def test_CRDataCache(): + dc = CRDataCache() + dc._startMemLeakCheck() + + cd = CachedDOData() + cd.foo = 34 + dc.setCachedData(1, 'testCachedData', cd) + del cd + cd = CachedDOData() + cd.bar = 45 + dc.setCachedData(1, 'testCachedData2', cd) + del cd + assert dc.hasCachedData(1) + assert dc.hasCachedData(1) + assert not dc.hasCachedData(2) + # data is dict of dataName->data + data = dc.popCachedData(1) + assert len(data) == 2 + assert 'testCachedData' in data + assert 'testCachedData2' in data + assert data['testCachedData'].foo == 34 + assert data['testCachedData2'].bar == 45 + for cd in data.values(): + cd.flush() + del data + dc._checkMemLeaks() + + cd = CachedDOData() + cd.bar = 1234 + dc.setCachedData(43, 'testCachedData2', cd) + del cd + assert dc.hasCachedData(43) + dc.flush() + dc._checkMemLeaks() + + dc._stopMemLeakCheck() + dc.destroy() + del dc diff --git a/tests/fsm/test_StatePush.py b/tests/fsm/test_StatePush.py new file mode 100644 index 0000000000..a5a7093ae5 --- /dev/null +++ b/tests/fsm/test_StatePush.py @@ -0,0 +1,144 @@ +from direct.fsm import StatePush + + +def test_PushesStateChanges(): + psc = StatePush.PushesStateChanges(0) + assert psc.getState() == 0 + psc.destroy() + + +def test_ReceivesStateChanges(): + rsc = StatePush.ReceivesStateChanges(None) + rsc.destroy() + + +def test_StateVar(): + sv = StatePush.StateVar(0) + assert sv.get() == 0 + sv.set(1) + assert sv.get() == 1 + sv.destroy() + + +def test_StateChangeNode(): + sv = StatePush.StateVar(0) + assert sv.get() == 0 + scn = StatePush.StateChangeNode(sv) + assert scn.getState() == 0 + sv.set(1) + assert sv.get() == 1 + assert scn.getState() == 1 + scn2 = StatePush.StateChangeNode(scn) + assert scn2.getState() == 1 + sv.set(2) + assert scn2.getState() == 2 + scn3 = StatePush.StateChangeNode(scn) + assert scn3.getState() == 2 + sv.set(3) + assert scn2.getState() == 3 + assert scn3.getState() == 3 + scn3.destroy() + scn2.destroy() + scn.destroy() + sv.destroy() + + +def test_ReceivesMultipleStateChanges(): + rsc = StatePush.ReceivesMultipleStateChanges() + sv = StatePush.StateVar(0) + sv2 = StatePush.StateVar('b') + rsc._subscribeTo(sv, 'a') + rsc._subscribeTo(sv2, 2) + rsc._unsubscribe('a') + rsc.destroy() + + +def test_FunctionCall_1(): + l = [] + def handler1(value, l=l): + l.append(value) + assert not l + sv = StatePush.StateVar(0) + fc = StatePush.FunctionCall(handler1, sv) + assert not l + fc.pushCurrentState() + assert l == [0,] + sv.set(1) + assert l == [0,1,] + sv.set(2) + assert l == [0,1,2,] + fc.destroy() + sv.destroy() + + +def test_FunctionCall_2(): + l = [] + def handler2(value, kDummy=None, kValue=None, l=l): + l.append((value, kValue)) + assert not l + sv = StatePush.StateVar(0) + ksv = StatePush.StateVar('a') + fc = StatePush.FunctionCall(handler2, sv, kValue=ksv) + assert not l + fc.pushCurrentState() + assert l == [(0,'a',),] + sv.set(1) + assert l == [(0,'a'),(1,'a'),] + ksv.set('b') + assert l == [(0,'a'),(1,'a'),(1,'b'),] + fc.destroy() + sv.destroy() + + +def test_EnterExit(): + l = [] + def enter(l=l): + l.append(1) + def exit(l=l): + l.append(0) + sv = StatePush.StateVar(0) + ee = StatePush.EnterExit(sv, enter, exit) + sv.set(0) + assert not l + sv.set(1) + assert l == [1,] + sv.set(2) + assert l == [1,] + sv.set(0) + assert l == [1,0,] + sv.set(True) + assert l == [1,0,1,] + sv.set(False) + assert l == [1,0,1,0,] + ee.destroy() + sv.destroy() + + +def test_Pulse(): + l = [] + def handler(value, l=l): + l.append(value) + p = StatePush.Pulse() + fc = StatePush.FunctionCall(handler, p) + assert not l + fc.pushCurrentState() + assert l == [False, ] + p.sendPulse() + assert l == [False, True, False, ] + p.sendPulse() + assert l == [False, True, False, True, False, ] + fc.destroy() + p.destroy() + + +def test_AttrSetter(): + from types import SimpleNamespace + o = SimpleNamespace() + svar = StatePush.StateVar(0) + aset = StatePush.AttrSetter(svar, o, 'testAttr') + assert hasattr(o, 'testAttr') + assert o.testAttr == 0 + svar.set('red') + assert o.testAttr == 'red' + aset.destroy() + svar.destroy() diff --git a/direct/src/gui/DirectGuiTest.py b/tests/gui/test_DirectGui.py similarity index 92% rename from direct/src/gui/DirectGuiTest.py rename to tests/gui/test_DirectGui.py index 622bd17d77..f72419a5c3 100644 --- a/direct/src/gui/DirectGuiTest.py +++ b/tests/gui/test_DirectGui.py @@ -1,19 +1,11 @@ -"""Undocumented Module""" - -__all__ = [] +from random import random +from panda3d.core import Point3 +from direct.task.TaskManagerGlobal import taskMgr +from direct.gui import DirectGuiGlobals +from direct.gui.DirectGui import DirectButton, DirectDialog, DirectEntry, DirectFrame, YesNoDialog -if __name__ == "__main__": - from panda3d.core import Point3 - from direct.showbase.ShowBase import ShowBase - from direct.task.TaskManagerGlobal import taskMgr - from . import DirectGuiGlobals - from .DirectGui import DirectButton, DirectDialog, DirectEntry, DirectFrame, YesNoDialog - #from whrandom import * - from random import random - - base = ShowBase() - +def test_DirectGui(base): # EXAMPLE CODE # Load a model smiley = base.loader.loadModel('models/misc/smiley') @@ -142,5 +134,3 @@ if __name__ == "__main__": print('WIDTH: %s' % de1.getWidth()) print('HEIGHT: %s' % de1.getHeight()) print('CENTER: %s' % (de1.getCenter(),)) - - base.run() diff --git a/direct/src/particles/ParticleTest.py b/tests/particles/test_particle.py similarity index 54% rename from direct/src/particles/ParticleTest.py rename to tests/particles/test_particle.py index f385b69c57..e41aa35ec2 100644 --- a/direct/src/particles/ParticleTest.py +++ b/tests/particles/test_particle.py @@ -1,15 +1,11 @@ +from panda3d.core import Vec3 +from panda3d.physics import LinearVectorForce +from direct.particles import ParticleEffect +from direct.particles import Particles +from direct.particles import ForceGroup -if __name__ == "__main__": - from panda3d.core import Vec3 - from panda3d.physics import LinearVectorForce - - from direct.directbase.TestStart import base - from direct.tkpanels import ParticlePanel - - from . import ParticleEffect - from . import Particles - from . import ForceGroup +def test_particle(base): # Showbase base.enableParticles() @@ -29,6 +25,4 @@ if __name__ == "__main__": pe.addParticles(p) # Particle Panel - pp = ParticlePanel.ParticlePanel(pe) - - base.run() + # pp = ParticlePanel.ParticlePanel(pe) diff --git a/direct/src/particles/ParticleFloorTest.py b/tests/particles/test_particle_floor.py old mode 100755 new mode 100644 similarity index 93% rename from direct/src/particles/ParticleFloorTest.py rename to tests/particles/test_particle_floor.py index fc79a600e4..acf60d4d81 --- a/direct/src/particles/ParticleFloorTest.py +++ b/tests/particles/test_particle_floor.py @@ -1,4 +1,3 @@ - from panda3d.core import NodePath, Vec3 from panda3d.physics import LinearVectorForce from direct.particles import ParticleEffect @@ -49,10 +48,9 @@ class ParticleFloorTest(NodePath): self.f.enable() -if __name__ == "__main__": - from direct.directbase.TestStart import base +def test_ParticleFloorTest(base): + base.enableParticles() pt = ParticleFloorTest() pt.reparentTo(base.render) pt.start() - base.camera.setY(-10.0) - base.run() + # base.camera.setY(-10.0) diff --git a/direct/src/physics/FallTest.py b/tests/physics/test_fall.py similarity index 92% rename from direct/src/physics/FallTest.py rename to tests/physics/test_fall.py index cec8b69129..99397072a8 100644 --- a/direct/src/physics/FallTest.py +++ b/tests/physics/test_fall.py @@ -26,9 +26,9 @@ class FallTest(NodePath): avatarNodePath = base.loader.loadModel("models/misc/smiley") assert not avatarNodePath.isEmpty() - camLL = base.render.find("**/camLL") - camLL.reparentTo(avatarNodePath) - camLL.setPosHpr(0, -10, 0, 0, 0, 0) + # camLL = base.render.find("**/camLL") + # camLL.reparentTo(avatarNodePath) + # camLL.setPosHpr(0, -10, 0, 0, 0, 0) avatarNodePath.reparentTo(actorNodePath) #avatarNodePath.setPos(Vec3(0)) #avatarNodePath.setHpr(Vec3(0)) @@ -86,10 +86,11 @@ class FallTest(NodePath): #self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos()) #self.actorNode.updateTransform() -if __name__ == "__main__": - from direct.directbase.ThreeUpStart import base + +def test_FallTest(base): + base.enableParticles() + base.addAngularIntegrator() test = FallTest() test.reparentTo(base.render) test.setup() - base.camera.setY(-10.0) - base.run() + # base.camera.setY(-10.0) diff --git a/direct/src/physics/RotationTest.py b/tests/physics/test_rotation.py similarity index 92% rename from direct/src/physics/RotationTest.py rename to tests/physics/test_rotation.py index d9f3ba9b62..ec24cf433b 100644 --- a/direct/src/physics/RotationTest.py +++ b/tests/physics/test_rotation.py @@ -27,9 +27,9 @@ class RotationTest(NodePath): avatarNodePath = base.loader.loadModel("models/misc/smiley") assert not avatarNodePath.isEmpty() - camLL = base.render.find("**/camLL") - camLL.reparentTo(avatarNodePath) - camLL.setPosHpr(0, -10, 0, 0, 0, 0) + # camLL = base.render.find("**/camLL") + # camLL.reparentTo(avatarNodePath) + # camLL.setPosHpr(0, -10, 0, 0, 0, 0) avatarNodePath.reparentTo(actorNodePath) #avatarNodePath.setPos(Vec3(0)) #avatarNodePath.setHpr(Vec3(0)) @@ -97,10 +97,11 @@ class RotationTest(NodePath): #self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos()) #self.actorNode.updateTransform() -if __name__ == "__main__": - from direct.directbase.ThreeUpStart import base + +def test_RotationTest(base): + base.enableParticles() + base.addAngularIntegrator() test = RotationTest() test.reparentTo(base.render) test.setup() - base.camera.setY(-10.0) - base.run() + # base.camera.setY(-10.0) diff --git a/tests/showbase/test_CountedResource.py b/tests/showbase/test_CountedResource.py new file mode 100644 index 0000000000..1d5f6807c9 --- /dev/null +++ b/tests/showbase/test_CountedResource.py @@ -0,0 +1,145 @@ +from direct.showbase.CountedResource import CountedResource + + +def test_CountedResource(): + class MouseResource(CountedResource): + """ + A simple class to demonstrate the acquisition of a resource. + """ + @classmethod + def acquire(cls): + # The call to the super-class's acquire() is + # not necessary at the moment, but may be in + # the future, so do it now for good measure. + super(MouseResource, cls).acquire() + + # Now acquire the resource this class is + # managing. + print('-- Acquire Mouse') + + @classmethod + def release(cls): + # First, release the resource this class is + # managing. + print('-- Release Mouse') + + # The call to the super-class's release() is + # not necessary at the moment, but may be in + # the future, so do it now for good measure. + super(MouseResource, cls).release() + + + def __init__(self): + super(MouseResource, self).__init__() + + def __del__(self): + super(MouseResource, self).__del__() + + class CursorResource(CountedResource): + """ + A class to demonstrate how to implement a dependent + resource. Notice how this class also inherits from + CountedResource. Instead of subclassing MouseCounter, + we will just acquire it in our __init__() and release + it in our __del__(). + """ + @classmethod + def acquire(cls): + super(CursorResource, cls).acquire() + print('-- Acquire Cursor') + + @classmethod + def release(cls): + print('-- Release Cursor') + + super(CursorResource, cls).release() + + def __init__(self): + # The required resource references should + # be stored on 'self' since we want to + # release it when the object is deleted. + self.__mouseResource = MouseResource() + + # Call the super-classes __init__() + # after all required resources are + # referenced. + super(CursorResource, self).__init__() + + def __del__(self): + # Free up the most dependent resource + # first, the one this class is managing. + super(CursorResource, self).__del__() + + # Now unlink any required resources. + del self.__mouseResource + + class InvalidResource(MouseResource): + @classmethod + def acquire(cls): + super(InvalidResource, cls).acquire() + print('-- Acquire Invalid') + + @classmethod + def release(cls): + print('-- Release Invalid') + super(InvalidResource, cls).release() + + print('\nAllocate Mouse') + m = MouseResource() + print('Free up Mouse') + del m + + print('\nAllocate Cursor') + c = CursorResource() + print('Free up Cursor') + del c + + print('\nAllocate Mouse then Cursor') + m = MouseResource() + c = CursorResource() + print('Free up Cursor') + del c + print('Free up Mouse') + del m + + print('\nAllocate Mouse then Cursor') + m = MouseResource() + c = CursorResource() + print('Free up Mouse') + del m + print('Free up Cursor') + del c + + print('\nAllocate Cursor then Mouse') + c = CursorResource() + m = MouseResource() + print('Free up Mouse') + del m + print('Free up Cursor') + del c + + print('\nAllocate Cursor then Mouse') + c = CursorResource() + m = MouseResource() + print('Free up Cursor') + del c + + # example of an invalid subclass + try: + print('\nAllocate Invalid') + i = InvalidResource() + print('Free up Invalid') + except AssertionError as e: + print(e) + print('') + + print('Free up Mouse') + del m + + def demoFunc(): + print('\nAllocate Cursor within function') + c = CursorResource() + + print('Cursor will be freed on function exit') + + demoFunc() diff --git a/tests/showbase/test_DistancePhasedNode.py b/tests/showbase/test_DistancePhasedNode.py new file mode 100644 index 0000000000..60d7f289b3 --- /dev/null +++ b/tests/showbase/test_DistancePhasedNode.py @@ -0,0 +1,30 @@ +from panda3d import core +from direct.showbase.DistancePhasedNode import BufferedDistancePhasedNode + + +def test_BufferedDistancePhasedNode(base): + cSphere = core.CollisionSphere(0, 0, 0, 0.1) + cNode = core.CollisionNode('camCol') + cNode.addSolid(cSphere) + cNodePath = core.NodePath(cNode) + # cNodePath.reparentTo(base.cam) + # cNodePath.show() + # cNodePath.setPos(25,0,0) + + base.cTrav = core.CollisionTraverser() + + eventHandler = core.CollisionHandlerEvent() + eventHandler.addInPattern('enter%in') + eventHandler.addOutPattern('exit%in') + + # messenger.toggleVerbose() + base.cTrav.addCollider(cNodePath, eventHandler) + + p = BufferedDistancePhasedNode('p', {'At': (10, 20), 'Near': (100, 200), 'Far': (1000, 1020)}, + autoCleanup=False, + fromCollideNode=cNodePath, + ) + + p.reparentTo(base.render) + p._DistancePhasedNode__oneTimeCollide() + base.eventMgr.doEvents() diff --git a/tests/showbase/test_PythonUtil.py b/tests/showbase/test_PythonUtil.py index df174ef76b..06e82bfa0a 100644 --- a/tests/showbase/test_PythonUtil.py +++ b/tests/showbase/test_PythonUtil.py @@ -56,6 +56,49 @@ def test_flywheel(): assert obj2count[4] == 4 * 3 +def test_formatTimeCompact(): + ftc = PythonUtil.formatTimeCompact + assert ftc(0) == '0s' + assert ftc(1) == '1s' + assert ftc(60) == '1m0s' + assert ftc(64) == '1m4s' + assert ftc(60*60) == '1h0m0s' + assert ftc(24*60*60) == '1d0h0m0s' + assert ftc(24*60*60 + 2*60*60 + 34*60 + 12) == '1d2h34m12s' + + +def test_formatTimeExact(): + fte = PythonUtil.formatTimeExact + assert fte(0) == '0s' + assert fte(1) == '1s' + assert fte(2) == '2s' + assert fte(61) == '1m1s' + assert fte(60) == '1m' + assert fte(60*60) == '1h' + assert fte(24*60*60) == '1d' + assert fte((24*60*60) + (2 * 60)) == '1d0h2m' + del fte + + +def test_AlphabetCounter(): + tempList = [] + ac = PythonUtil.AlphabetCounter() + for i in range(26*3): + tempList.append(ac.next()) + assert tempList == [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ', + 'BA','BB','BC','BD','BE','BF','BG','BH','BI','BJ','BK','BL','BM','BN','BO','BP','BQ','BR','BS','BT','BU','BV','BW','BX','BY','BZ',] + ac = PythonUtil.AlphabetCounter() + num = 26 # A-Z + num += (26*26) # AA-ZZ + num += 26 # AAZ + num += 1 # ABA + num += 2 # ABC + for i in range(num): + x = ac.next() + assert x == 'ABC' + + def test_unescape_html_string(): assert PythonUtil.unescapeHtmlString('asdf') == 'asdf' assert PythonUtil.unescapeHtmlString('as+df') == 'as df' diff --git a/tests/stdpy/test_threading.py b/tests/stdpy/test_threading.py index 557a9e428e..a105ad20e1 100644 --- a/tests/stdpy/test_threading.py +++ b/tests/stdpy/test_threading.py @@ -1,3 +1,5 @@ +import sys +from panda3d import core from direct.stdpy import threading import pytest @@ -5,3 +7,104 @@ import pytest def test_threading_error(): with pytest.raises(threading.ThreadError): threading.stack_size() + + +def test_threading(): + from collections import deque + + _sleep = core.Thread.sleep + + _VERBOSE = False + + class _Verbose(object): + + def __init__(self, verbose=None): + if verbose is None: + verbose = _VERBOSE + self.__verbose = verbose + + def _note(self, format, *args): + if self.__verbose: + format = format % args + format = "%s: %s\n" % ( + threading.currentThread().getName(), format) + sys.stderr.write(format) + + class BoundedQueue(_Verbose): + + def __init__(self, limit): + _Verbose.__init__(self) + self.mon = threading.Lock(name = "BoundedQueue.mon") + self.rc = threading.Condition(self.mon) + self.wc = threading.Condition(self.mon) + self.limit = limit + self.queue = deque() + + def put(self, item): + self.mon.acquire() + while len(self.queue) >= self.limit: + self._note("put(%s): queue full", item) + self.wc.wait() + self.queue.append(item) + self._note("put(%s): appended, length now %d", + item, len(self.queue)) + self.rc.notify() + self.mon.release() + + def get(self): + self.mon.acquire() + while not self.queue: + self._note("get(): queue empty") + self.rc.wait() + item = self.queue.popleft() + self._note("get(): got %s, %d left", item, len(self.queue)) + self.wc.notify() + self.mon.release() + return item + + class ProducerThread(threading.Thread): + + def __init__(self, queue, quota): + threading.Thread.__init__(self, name="Producer") + self.queue = queue + self.quota = quota + + def run(self): + from random import random + counter = 0 + while counter < self.quota: + counter = counter + 1 + self.queue.put("%s.%d" % (self.getName(), counter)) + _sleep(random() * 0.00001) + + class ConsumerThread(threading.Thread): + + def __init__(self, queue, count): + threading.Thread.__init__(self, name="Consumer") + self.queue = queue + self.count = count + + def run(self): + while self.count > 0: + item = self.queue.get() + print(item) + self.count = self.count - 1 + + NP = 3 + QL = 4 + NI = 5 + + Q = BoundedQueue(QL) + P = [] + for i in range(NP): + t = ProducerThread(Q, NI) + t.setName("Producer-%d" % (i+1)) + P.append(t) + C = ConsumerThread(Q, NI*NP) + for t in P: + t.start() + _sleep(0.000001) + C.start() + for t in P: + t.join() + C.join() diff --git a/tests/stdpy/test_threading2.py b/tests/stdpy/test_threading2.py new file mode 100644 index 0000000000..f2a31dc172 --- /dev/null +++ b/tests/stdpy/test_threading2.py @@ -0,0 +1,84 @@ +from collections import deque +from panda3d import core +from direct.stdpy import threading2 + + +def test_threading2(): + class BoundedQueue(threading2._Verbose): + + def __init__(self, limit): + threading2._Verbose.__init__(self) + self.mon = threading2.RLock() + self.rc = threading2.Condition(self.mon) + self.wc = threading2.Condition(self.mon) + self.limit = limit + self.queue = deque() + + def put(self, item): + self.mon.acquire() + while len(self.queue) >= self.limit: + self._note("put(%s): queue full", item) + self.wc.wait() + self.queue.append(item) + self._note("put(%s): appended, length now %d", + item, len(self.queue)) + self.rc.notify() + self.mon.release() + + def get(self): + self.mon.acquire() + while not self.queue: + self._note("get(): queue empty") + self.rc.wait() + item = self.queue.popleft() + self._note("get(): got %s, %d left", item, len(self.queue)) + self.wc.notify() + self.mon.release() + return item + + class ProducerThread(threading2.Thread): + + def __init__(self, queue, quota): + threading2.Thread.__init__(self, name="Producer") + self.queue = queue + self.quota = quota + + def run(self): + from random import random + counter = 0 + while counter < self.quota: + counter = counter + 1 + self.queue.put("%s.%d" % (self.getName(), counter)) + core.Thread.sleep(random() * 0.00001) + + class ConsumerThread(threading2.Thread): + + def __init__(self, queue, count): + threading2.Thread.__init__(self, name="Consumer") + self.queue = queue + self.count = count + + def run(self): + while self.count > 0: + item = self.queue.get() + print(item) + self.count = self.count - 1 + + NP = 3 + QL = 4 + NI = 5 + + Q = BoundedQueue(QL) + P = [] + for i in range(NP): + t = ProducerThread(Q, NI) + t.setName("Producer-%d" % (i+1)) + P.append(t) + C = ConsumerThread(Q, NI*NP) + for t in P: + t.start() + core.Thread.sleep(0.000001) + C.start() + for t in P: + t.join() + C.join() diff --git a/tests/task/test_Task.py b/tests/task/test_Task.py new file mode 100644 index 0000000000..46710362b1 --- /dev/null +++ b/tests/task/test_Task.py @@ -0,0 +1,518 @@ +from panda3d import core +from direct.task import Task + + +def test_TaskManager(): + tm = Task.TaskManager() + tm.mgr = core.AsyncTaskManager("Test manager") + tm.setClock(core.ClockObject()) + tm.setupTaskChain("default", tickClock = True) + + tm._startTrackingMemLeaks = lambda: None + tm._stopTrackingMemLeaks = lambda: None + tm._checkMemLeaks = lambda: None + + # check for memory leaks after every test + tm._startTrackingMemLeaks() + tm._checkMemLeaks() + + # run-once task + l = [] + + def _testDone(task, l=l): + l.append(None) + return task.done + tm.add(_testDone, 'testDone') + tm.step() + assert len(l) == 1 + tm.step() + assert len(l) == 1 + _testDone = None + tm._checkMemLeaks() + + # remove by name + def _testRemoveByName(task): + return task.done + tm.add(_testRemoveByName, 'testRemoveByName') + assert tm.remove('testRemoveByName') == 1 + assert tm.remove('testRemoveByName') == 0 + _testRemoveByName = None + tm._checkMemLeaks() + + # duplicate named tasks + def _testDupNamedTasks(task): + return task.done + tm.add(_testDupNamedTasks, 'testDupNamedTasks') + tm.add(_testDupNamedTasks, 'testDupNamedTasks') + assert tm.remove('testRemoveByName') == 0 + _testDupNamedTasks = None + tm._checkMemLeaks() + + # continued task + l = [] + + def _testCont(task, l = l): + l.append(None) + return task.cont + tm.add(_testCont, 'testCont') + tm.step() + assert len(l) == 1 + tm.step() + assert len(l) == 2 + tm.remove('testCont') + _testCont = None + tm._checkMemLeaks() + + # continue until done task + l = [] + + def _testContDone(task, l = l): + l.append(None) + if len(l) >= 2: + return task.done + else: + return task.cont + tm.add(_testContDone, 'testContDone') + tm.step() + assert len(l) == 1 + tm.step() + assert len(l) == 2 + tm.step() + assert len(l) == 2 + assert not tm.hasTaskNamed('testContDone') + _testContDone = None + tm._checkMemLeaks() + + # hasTaskNamed + def _testHasTaskNamed(task): + return task.done + tm.add(_testHasTaskNamed, 'testHasTaskNamed') + assert tm.hasTaskNamed('testHasTaskNamed') + tm.step() + assert not tm.hasTaskNamed('testHasTaskNamed') + _testHasTaskNamed = None + tm._checkMemLeaks() + + # task sort + l = [] + + def _testPri1(task, l = l): + l.append(1) + return task.cont + + def _testPri2(task, l = l): + l.append(2) + return task.cont + tm.add(_testPri1, 'testPri1', sort = 1) + tm.add(_testPri2, 'testPri2', sort = 2) + tm.step() + assert len(l) == 2 + assert l == [1, 2,] + tm.step() + assert len(l) == 4 + assert l == [1, 2, 1, 2,] + tm.remove('testPri1') + tm.remove('testPri2') + _testPri1 = None + _testPri2 = None + tm._checkMemLeaks() + + # task extraArgs + l = [] + + def _testExtraArgs(arg1, arg2, l=l): + l.extend([arg1, arg2,]) + return Task.done + tm.add(_testExtraArgs, 'testExtraArgs', extraArgs=[4,5]) + tm.step() + assert len(l) == 2 + assert l == [4, 5,] + _testExtraArgs = None + tm._checkMemLeaks() + + # task appendTask + l = [] + + def _testAppendTask(arg1, arg2, task, l=l): + l.extend([arg1, arg2,]) + return task.done + tm.add(_testAppendTask, '_testAppendTask', extraArgs=[4,5], appendTask=True) + tm.step() + assert len(l) == 2 + assert l == [4, 5,] + _testAppendTask = None + tm._checkMemLeaks() + + # task uponDeath + l = [] + + def _uponDeathFunc(task, l=l): + l.append(task.name) + + def _testUponDeath(task): + return Task.done + tm.add(_testUponDeath, 'testUponDeath', uponDeath=_uponDeathFunc) + tm.step() + assert len(l) == 1 + assert l == ['testUponDeath'] + _testUponDeath = None + _uponDeathFunc = None + tm._checkMemLeaks() + + # task owner + class _TaskOwner: + def _addTask(self, task): + self.addedTaskName = task.name + + def _clearTask(self, task): + self.clearedTaskName = task.name + to = _TaskOwner() + l = [] + + def _testOwner(task): + return Task.done + tm.add(_testOwner, 'testOwner', owner=to) + tm.step() + assert getattr(to, 'addedTaskName', None) == 'testOwner' + assert getattr(to, 'clearedTaskName', None) == 'testOwner' + _testOwner = None + del to + _TaskOwner = None + tm._checkMemLeaks() + + doLaterTests = [0,] + + # doLater + l = [] + + def _testDoLater1(task, l=l): + l.append(1) + + def _testDoLater2(task, l=l): + l.append(2) + + def _monitorDoLater(task, tm=tm, l=l, doLaterTests=doLaterTests): + if task.time > .03: + assert l == [1, 2,] + doLaterTests[0] -= 1 + return task.done + return task.cont + tm.doMethodLater(.01, _testDoLater1, 'testDoLater1') + tm.doMethodLater(.02, _testDoLater2, 'testDoLater2') + doLaterTests[0] += 1 + # make sure we run this task after the doLaters if they all occur on the same frame + tm.add(_monitorDoLater, 'monitorDoLater', sort=10) + _testDoLater1 = None + _testDoLater2 = None + _monitorDoLater = None + # don't check until all the doLaters are finished + #tm._checkMemLeaks() + + # doLater sort + l = [] + + def _testDoLaterPri1(task, l=l): + l.append(1) + + def _testDoLaterPri2(task, l=l): + l.append(2) + + def _monitorDoLaterPri(task, tm=tm, l=l, doLaterTests=doLaterTests): + if task.time > .02: + assert l == [1, 2,] + doLaterTests[0] -= 1 + return task.done + return task.cont + tm.doMethodLater(.01, _testDoLaterPri1, 'testDoLaterPri1', sort=1) + tm.doMethodLater(.01, _testDoLaterPri2, 'testDoLaterPri2', sort=2) + doLaterTests[0] += 1 + # make sure we run this task after the doLaters if they all occur on the same frame + tm.add(_monitorDoLaterPri, 'monitorDoLaterPri', sort=10) + _testDoLaterPri1 = None + _testDoLaterPri2 = None + _monitorDoLaterPri = None + # don't check until all the doLaters are finished + #tm._checkMemLeaks() + + # doLater extraArgs + l = [] + + def _testDoLaterExtraArgs(arg1, l=l): + l.append(arg1) + + def _monitorDoLaterExtraArgs(task, tm=tm, l=l, doLaterTests=doLaterTests): + if task.time > .02: + assert l == [3,] + doLaterTests[0] -= 1 + return task.done + return task.cont + tm.doMethodLater(.01, _testDoLaterExtraArgs, 'testDoLaterExtraArgs', extraArgs=[3,]) + doLaterTests[0] += 1 + # make sure we run this task after the doLaters if they all occur on the same frame + tm.add(_monitorDoLaterExtraArgs, 'monitorDoLaterExtraArgs', sort=10) + _testDoLaterExtraArgs = None + _monitorDoLaterExtraArgs = None + # don't check until all the doLaters are finished + #tm._checkMemLeaks() + + # doLater appendTask + l = [] + + def _testDoLaterAppendTask(arg1, task, l=l): + assert task.name == 'testDoLaterAppendTask' + l.append(arg1) + + def _monitorDoLaterAppendTask(task, tm=tm, l=l, doLaterTests=doLaterTests): + if task.time > .02: + assert l == [4,] + doLaterTests[0] -= 1 + return task.done + return task.cont + tm.doMethodLater(.01, _testDoLaterAppendTask, 'testDoLaterAppendTask', + extraArgs=[4,], appendTask=True) + doLaterTests[0] += 1 + # make sure we run this task after the doLaters if they all occur on the same frame + tm.add(_monitorDoLaterAppendTask, 'monitorDoLaterAppendTask', sort=10) + _testDoLaterAppendTask = None + _monitorDoLaterAppendTask = None + # don't check until all the doLaters are finished + #tm._checkMemLeaks() + + # doLater uponDeath + l = [] + + def _testUponDeathFunc(task, l=l): + assert task.name == 'testDoLaterUponDeath' + l.append(10) + + def _testDoLaterUponDeath(arg1, l=l): + return Task.done + + def _monitorDoLaterUponDeath(task, tm=tm, l=l, doLaterTests=doLaterTests): + if task.time > .02: + assert l == [10,] + doLaterTests[0] -= 1 + return task.done + return task.cont + tm.doMethodLater(.01, _testDoLaterUponDeath, 'testDoLaterUponDeath', + uponDeath=_testUponDeathFunc) + doLaterTests[0] += 1 + # make sure we run this task after the doLaters if they all occur on the same frame + tm.add(_monitorDoLaterUponDeath, 'monitorDoLaterUponDeath', sort=10) + _testUponDeathFunc = None + _testDoLaterUponDeath = None + _monitorDoLaterUponDeath = None + # don't check until all the doLaters are finished + #tm._checkMemLeaks() + + # doLater owner + class _DoLaterOwner: + def _addTask(self, task): + self.addedTaskName = task.name + + def _clearTask(self, task): + self.clearedTaskName = task.name + doLaterOwner = _DoLaterOwner() + l = [] + + def _testDoLaterOwner(l=l): + pass + + def _monitorDoLaterOwner(task, tm=tm, l=l, doLaterOwner=doLaterOwner, + doLaterTests=doLaterTests): + if task.time > .02: + assert getattr(doLaterOwner, 'addedTaskName', None) == 'testDoLaterOwner' + assert getattr(doLaterOwner, 'clearedTaskName', None) == 'testDoLaterOwner' + doLaterTests[0] -= 1 + return task.done + return task.cont + tm.doMethodLater(.01, _testDoLaterOwner, 'testDoLaterOwner', + owner=doLaterOwner) + doLaterTests[0] += 1 + # make sure we run this task after the doLaters if they all occur on the same frame + tm.add(_monitorDoLaterOwner, 'monitorDoLaterOwner', sort=10) + _testDoLaterOwner = None + _monitorDoLaterOwner = None + del doLaterOwner + _DoLaterOwner = None + # don't check until all the doLaters are finished + #tm._checkMemLeaks() + + # run the doLater tests + while doLaterTests[0] > 0: + tm.step() + del doLaterTests + tm._checkMemLeaks() + + # getTasks + def _testGetTasks(task): + return task.cont + # No doLaterProcessor in the new world. + assert len(tm.getTasks()) == 0 + tm.add(_testGetTasks, 'testGetTasks1') + assert len(tm.getTasks()) == 1 + assert (tm.getTasks()[0].name == 'testGetTasks1' or + tm.getTasks()[1].name == 'testGetTasks1') + tm.add(_testGetTasks, 'testGetTasks2') + tm.add(_testGetTasks, 'testGetTasks3') + assert len(tm.getTasks()) == 3 + tm.remove('testGetTasks2') + assert len(tm.getTasks()) == 2 + tm.remove('testGetTasks1') + tm.remove('testGetTasks3') + assert len(tm.getTasks()) == 0 + _testGetTasks = None + tm._checkMemLeaks() + + # getDoLaters + def _testGetDoLaters(): + pass + assert len(tm.getDoLaters()) == 0 + tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater1') + assert len(tm.getDoLaters()) == 1 + assert tm.getDoLaters()[0].name == 'testDoLater1' + tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater2') + tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater3') + assert len(tm.getDoLaters()) == 3 + tm.remove('testDoLater2') + assert len(tm.getDoLaters()) == 2 + tm.remove('testDoLater1') + tm.remove('testDoLater3') + assert len(tm.getDoLaters()) == 0 + _testGetDoLaters = None + tm._checkMemLeaks() + + # duplicate named doLaters removed via taskMgr.remove + def _testDupNameDoLaters(): + pass + # the doLaterProcessor is always running + tm.doMethodLater(.1, _testDupNameDoLaters, 'testDupNameDoLater') + tm.doMethodLater(.1, _testDupNameDoLaters, 'testDupNameDoLater') + assert len(tm.getDoLaters()) == 2 + tm.remove('testDupNameDoLater') + assert len(tm.getDoLaters()) == 0 + _testDupNameDoLaters = None + tm._checkMemLeaks() + + # duplicate named doLaters removed via remove() + def _testDupNameDoLatersRemove(): + pass + # the doLaterProcessor is always running + dl1 = tm.doMethodLater(.1, _testDupNameDoLatersRemove, 'testDupNameDoLaterRemove') + dl2 = tm.doMethodLater(.1, _testDupNameDoLatersRemove, 'testDupNameDoLaterRemove') + assert len(tm.getDoLaters()) == 2 + dl2.remove() + assert len(tm.getDoLaters()) == 1 + dl1.remove() + assert len(tm.getDoLaters()) == 0 + _testDupNameDoLatersRemove = None + # nameDict etc. isn't cleared out right away with task.remove() + tm._checkMemLeaks() + + # getTasksNamed + def _testGetTasksNamed(task): + return task.cont + assert len(tm.getTasksNamed('testGetTasksNamed')) == 0 + tm.add(_testGetTasksNamed, 'testGetTasksNamed') + assert len(tm.getTasksNamed('testGetTasksNamed')) == 1 + assert tm.getTasksNamed('testGetTasksNamed')[0].name == 'testGetTasksNamed' + tm.add(_testGetTasksNamed, 'testGetTasksNamed') + tm.add(_testGetTasksNamed, 'testGetTasksNamed') + assert len(tm.getTasksNamed('testGetTasksNamed')) == 3 + tm.remove('testGetTasksNamed') + assert len(tm.getTasksNamed('testGetTasksNamed')) == 0 + _testGetTasksNamed = None + tm._checkMemLeaks() + + # removeTasksMatching + def _testRemoveTasksMatching(task): + return task.cont + tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching') + assert len(tm.getTasksNamed('testRemoveTasksMatching')) == 1 + tm.removeTasksMatching('testRemoveTasksMatching') + assert len(tm.getTasksNamed('testRemoveTasksMatching')) == 0 + tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching1') + tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching2') + assert len(tm.getTasksNamed('testRemoveTasksMatching1')) == 1 + assert len(tm.getTasksNamed('testRemoveTasksMatching2')) == 1 + tm.removeTasksMatching('testRemoveTasksMatching*') + assert len(tm.getTasksNamed('testRemoveTasksMatching1')) == 0 + assert len(tm.getTasksNamed('testRemoveTasksMatching2')) == 0 + tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching1a') + tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching2a') + assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 1 + assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 1 + tm.removeTasksMatching('testRemoveTasksMatching?a') + assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 0 + assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 0 + _testRemoveTasksMatching = None + tm._checkMemLeaks() + + # create Task object and add to mgr + l = [] + + def _testTaskObj(task, l=l): + l.append(None) + return task.cont + t = Task.Task(_testTaskObj) + tm.add(t, 'testTaskObj') + tm.step() + assert len(l) == 1 + tm.step() + assert len(l) == 2 + tm.remove('testTaskObj') + tm.step() + assert len(l) == 2 + _testTaskObj = None + tm._checkMemLeaks() + + # remove Task via task.remove() + l = [] + + def _testTaskObjRemove(task, l=l): + l.append(None) + return task.cont + t = Task.Task(_testTaskObjRemove) + tm.add(t, 'testTaskObjRemove') + tm.step() + assert len(l) == 1 + tm.step() + assert len(l) == 2 + t.remove() + tm.step() + assert len(l) == 2 + del t + _testTaskObjRemove = None + tm._checkMemLeaks() + + # set/get Task sort + l = [] + def _testTaskObjSort(arg, task, l=l): + l.append(arg) + return task.cont + t1 = Task.Task(_testTaskObjSort) + t2 = Task.Task(_testTaskObjSort) + tm.add(t1, 'testTaskObjSort1', extraArgs=['a',], appendTask=True, sort=1) + tm.add(t2, 'testTaskObjSort2', extraArgs=['b',], appendTask=True, sort=2) + tm.step() + assert len(l) == 2 + assert l == ['a', 'b'] + assert t1.getSort() == 1 + assert t2.getSort() == 2 + t1.setSort(3) + assert t1.getSort() == 3 + tm.step() + assert len(l) == 4 + assert l == ['a', 'b', 'b', 'a',] + t1.remove() + t2.remove() + tm.step() + assert len(l) == 4 + del t1 + del t2 + _testTaskObjSort = None + tm._checkMemLeaks() + + del l + tm.destroy() + del tm diff --git a/tests/task/test_task_arg.py b/tests/task/test_task_arg.py index 4243c44f2b..26b3552053 100644 --- a/tests/task/test_task_arg.py +++ b/tests/task/test_task_arg.py @@ -2,7 +2,7 @@ from direct.showbase.ShowBase import ShowBase from direct.task import Task from panda3d.core import Vec2 -def test_task_arg(): +def test_task_arg(base): def test(ship, flood, task): ship.y += flood return task.done @@ -10,7 +10,6 @@ def test_task_arg(): ship = Vec2(2.2, 2) flood = 1 - base = ShowBase(windowType='none') task = base.addTask(test, 'test_task', extraArgs=[ship, flood], appendTask=True) base.taskMgr.step() assert ship.y == 3 @@ -25,4 +24,3 @@ def test_task_arg(): task = base.taskMgr.add(task) base.taskMgr.step() assert ship.y == 6 - \ No newline at end of file diff --git a/direct/src/task/TaskTester.py b/tests/task/test_tasks.py old mode 100755 new mode 100644 similarity index 82% rename from direct/src/task/TaskTester.py rename to tests/task/test_tasks.py index 582b7486da..b5e4ff9d8b --- a/direct/src/task/TaskTester.py +++ b/tests/task/test_tasks.py @@ -1,11 +1,7 @@ -"""Undocumented Module""" - -__all__ = [] - -from direct.task.TaskManagerGlobal import taskMgr from direct.task import Task import random +taskMgr = Task.TaskManager() numTasks = 10000 maxDelay = 20 counter = 0 @@ -24,8 +20,10 @@ def taskCallback(task): spawnNewTask() return Task.done -if __name__ == '__main__': +def test_tasks(): taskMgr.removeTasksMatching("taskTester*") for i in range(numTasks): spawnNewTask() + + taskMgr.destroy() diff --git a/tests/test_imports.py b/tests/test_imports.py index b7df8d8239..58b146e589 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -93,7 +93,6 @@ def test_imports_direct(): import direct.gui.DirectGui import direct.gui.DirectGuiBase import direct.gui.DirectGuiGlobals - import direct.gui.DirectGuiTest import direct.gui.DirectLabel import direct.gui.DirectOptionMenu import direct.gui.DirectRadioButton @@ -112,7 +111,6 @@ def test_imports_direct(): import direct.interval.Interval import direct.interval.IntervalGlobal import direct.interval.IntervalManager - import direct.interval.IntervalTest import direct.interval.LerpBlendHelpers import direct.interval.LerpInterval import direct.interval.MetaInterval @@ -185,7 +183,6 @@ def test_imports_direct(): import direct.task.Task import direct.task.TaskManagerGlobal import direct.task.TaskProfiler - import direct.task.TaskTester import direct.task.Timer @@ -196,13 +193,9 @@ def test_imports_direct_physics(): import direct.particles.ForceGroup import direct.particles.GlobalForceGroup import direct.particles.ParticleEffect - import direct.particles.ParticleFloorTest import direct.particles.ParticleManagerGlobal - import direct.particles.ParticleTest import direct.particles.Particles import direct.particles.SpriteParticleRendererExt - import direct.physics.FallTest - import direct.physics.RotationTest import direct.showbase.PhysicsManagerGlobal diff --git a/tests/tkpanels/test_ParticlePanel.py b/tests/tkpanels/test_ParticlePanel.py new file mode 100644 index 0000000000..e1498a4868 --- /dev/null +++ b/tests/tkpanels/test_ParticlePanel.py @@ -0,0 +1,11 @@ +import pytest +Pmw = pytest.importorskip('Pmw') +from direct.tkpanels.ParticlePanel import ParticlePanel + + +def test_ParticlePanel(base, tk_toplevel): + root = Pmw.initialise() + pp = ParticlePanel() + base.pp=pp + #ve = VectorEntry(Toplevel(), relief = GROOVE) + #ve.pack() diff --git a/tests/tkpanels/test_Placer.py b/tests/tkpanels/test_Placer.py new file mode 100644 index 0000000000..1a5072bf82 --- /dev/null +++ b/tests/tkpanels/test_Placer.py @@ -0,0 +1,12 @@ +import pytest +Pmw = pytest.importorskip('Pmw') +from direct.showbase.ShowBase import ShowBase +from direct.tkpanels.Placer import Placer + + +def test_Placer(window): + base = ShowBase() + base.start_direct() + root = Pmw.initialise() + widget = Placer() + base.destroy() diff --git a/tests/tkwidgets/test_AppShell.py b/tests/tkwidgets/test_AppShell.py new file mode 100644 index 0000000000..e87889d34b --- /dev/null +++ b/tests/tkwidgets/test_AppShell.py @@ -0,0 +1,7 @@ +import pytest +pytest.importorskip('Pmw') +from direct.tkwidgets import AppShell + + +def test_TestAppShell(tk_toplevel): + test = AppShell.TestAppShell(balloon_state='none') diff --git a/tests/tkwidgets/test_Dial.py b/tests/tkwidgets/test_Dial.py new file mode 100644 index 0000000000..eda8d0591b --- /dev/null +++ b/tests/tkwidgets/test_Dial.py @@ -0,0 +1,19 @@ +import tkinter as tk +import pytest +pytest.importorskip('Pmw') +from direct.tkwidgets.Dial import Dial + + +def test_Dial(tk_toplevel): + tl = tk_toplevel + d = Dial(tl) + d2 = Dial(tl, dial_numSegments = 12, max = 360, + dial_fRollover = 0, value = 180) + d3 = Dial(tl, dial_numSegments = 12, max = 90, min = -90, + dial_fRollover = 0) + d4 = Dial(tl, dial_numSegments = 16, max = 256, + dial_fRollover = 0) + d.pack(expand = 1, fill = tk.X) + d2.pack(expand = 1, fill = tk.X) + d3.pack(expand = 1, fill = tk.X) + d4.pack(expand = 1, fill = tk.X) diff --git a/tests/tkwidgets/test_EntryScale.py b/tests/tkwidgets/test_EntryScale.py new file mode 100644 index 0000000000..f06fb036ed --- /dev/null +++ b/tests/tkwidgets/test_EntryScale.py @@ -0,0 +1,44 @@ +import pytest +pytest.importorskip('Pmw') +from direct.tkwidgets.EntryScale import EntryScale, EntryScaleGroup + + +def test_EntryScale(tk_toplevel): + # Initialise Tkinter and Pmw. + root = tk_toplevel + root.title('Pmw EntryScale demonstration') + + # Dummy command + def printVal(val): + print(val) + + # Create and pack a EntryScale megawidget. + mega1 = EntryScale(root, command = printVal) + mega1.pack(side = 'left', expand = 1, fill = 'x') + + # These are things you can set/configure + # Starting value for entryScale + #mega1['value'] = 123.456 + #mega1['text'] = 'Drive delta X' + #mega1['min'] = 0.0 + #mega1['max'] = 1000.0 + #mega1['resolution'] = 1.0 + # To change the color of the label: + #mega1.label['foreground'] = 'Red' + # Max change/update, default is 100 + # To have really fine control, for example + # mega1['maxVelocity'] = 0.1 + # Number of digits to the right of the decimal point, default = 2 + # mega1['numDigits'] = 5 + + # To create a entryScale group to set an RGBA value: + group1 = EntryScaleGroup(root, dim = 4, + title = 'Simple RGBA Panel', + labels = ('R', 'G', 'B', 'A'), + Valuator_min = 0.0, + Valuator_max = 255.0, + Valuator_resolution = 1.0, + command = printVal) + + # Uncomment this if you aren't running in IDLE + #root.mainloop() diff --git a/tests/tkwidgets/test_Floater.py b/tests/tkwidgets/test_Floater.py new file mode 100644 index 0000000000..dfd470763f --- /dev/null +++ b/tests/tkwidgets/test_Floater.py @@ -0,0 +1,41 @@ +import pytest +pytest.importorskip('Pmw') +from direct.tkwidgets.Floater import Floater, FloaterGroup + + +def test_Floater(tk_toplevel): + # Initialise Tkinter and Pmw. + root = tk_toplevel + root.title('Pmw Floater demonstration') + + # Dummy command + def printVal(val): + print(val) + + # Create and pack a Floater megawidget. + mega1 = Floater(root, command = printVal) + mega1.pack(side = 'left', expand = 1, fill = 'x') + + # These are things you can set/configure + # Starting value for floater + #mega1['value'] = 123.456 + #mega1['text'] = 'Drive delta X' + # To change the color of the label: + #mega1.label['foreground'] = 'Red' + # Max change/update, default is 100 + # To have really fine control, for example + #mega1['maxVelocity'] = 0.1 + # Number of digits to the right of the decimal point, default = 2 + #mega1['numDigits'] = 5 + + # To create a floater group to set an RGBA value: + group1 = FloaterGroup(root, dim = 4, + title = 'Simple RGBA Panel', + labels = ('R', 'G', 'B', 'A'), + Valuator_min = 0.0, + Valuator_max = 255.0, + Valuator_resolution = 1.0, + command = printVal) + + # Uncomment this if you aren't running in IDLE + #root.mainloop() diff --git a/tests/tkwidgets/test_VectorWidgets.py b/tests/tkwidgets/test_VectorWidgets.py new file mode 100644 index 0000000000..fecad4cfa7 --- /dev/null +++ b/tests/tkwidgets/test_VectorWidgets.py @@ -0,0 +1,17 @@ +import pytest +pytest.importorskip('Pmw') +from direct.tkwidgets import VectorWidgets + + +def test_VectorEntry(tk_toplevel): + root = tk_toplevel + root.title('Vector Widget demo') + + ve = VectorWidgets.VectorEntry(root) + ve.pack() + v3e = VectorWidgets.Vector3Entry(root) + v3e.pack() + v4e = VectorWidgets.Vector4Entry(root) + v4e.pack() + ce = VectorWidgets.ColorEntry(root) + ce.pack()