# HG changeset patch # User Edouard Tisserant # Date 1647006217 -3600 # Node ID 24fbd4d1fe80099559bcf50368a57510000b157f # Parent ce366d67a5b7807eb27eca2283209c972459f8c9 Tests: Re-introduced pytest based tests. Fixed them a bit, commented-out otherwise. Application tests only runs with logging test, and PLCOpenEditor tests seem broken. diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/Makefile --- a/tests/Makefile Sat Mar 05 11:14:00 2022 +0100 +++ b/tests/Makefile Fri Mar 11 14:43:37 2022 +0100 @@ -47,6 +47,7 @@ # Any change in Matiec and Beremiz directory triggers copy of source code # to $(test_dir)/build. # +# BEREMIZPYTHONPATH is expected to be absolute path to python interpreter # # Please note: # In order to run asside a freshly build Matiec, tested beremiz instance @@ -99,12 +100,22 @@ own_apps: $(build_dir)/matiec/iec2c $(build_dir)/beremiz/$(beremiz_checksum).sha1 touch $@ -ide_tests = $(subst $(src)/ide_tests/,,$(wildcard $(src)/ide_tests/*.sikuli)) +ide_test_dir = $(src)/ide_tests +sikuli_ide_tests = $(subst $(ide_test_dir)/,,$(wildcard $(ide_test_dir)/*.sikuli)) +pytest_ide_tests = $(subst $(ide_test_dir)/,,$(wildcard $(ide_test_dir)/*.pytest)) -define idetest_command +define sikuli_idetest_command (fluxbox >/dev/null 2>&1 &); BEREMIZPATH=$(build_dir)/beremiz sikulix -r $(src)/ide_tests/$(1) | tee test_stdout.txt; exit $$$${PIPESTATUS[0]} endef + +DELAY=400 +KILL_DELAY=430 +PYTEST=$(dir $(BEREMIZPYTHONPATH))/pytest +define pytest_idetest_command + (fluxbox >/dev/null 2>&1 &); PYTHONPATH=$(ide_test_dir) timeout -k $(KILL_DELAY) $(DELAY) $(PYTEST) --maxfail=1 --timeout=100 $(src)/ide_tests/$(1) | tee test_stdout.txt; exit $$$${PIPESTATUS[0]} +endef + # Xnest based interactive sessions for tests edit and debug. # Would be nice with something equivalent to xvfb-run, waiting for USR1. # Arbitrary "sleep 1" is probably enough for interactive use @@ -122,7 +133,7 @@ define make_idetest_rule $(test_dir)/$(1)_idetest/.passed: own_apps - $(call prep_test,$(1)); $(xserver_command) bash -c '$(call idetest_command,$(1))' + $(call prep_test,$(1)); $(xserver_command) bash -c '$(call $(2),$(1))' touch $$@ # Manually invoked rule {testname}.sikuli @@ -131,11 +142,12 @@ # Manually invoked rule xnest_{testname}.sikuli # runs test in xnest so that one can see what happens xnest_$(1): own_apps - $(call prep_test,$(1)); $$(call xnest_run, bash -c '$(call idetest_command,$(1))') + $(call prep_test,$(1)); $$(call xnest_run, bash -c '$(call $(2),$(1))') ide_tests_targets += $(test_dir)/$(1)_idetest/.passed endef -$(foreach idetest,$(ide_tests),$(eval $(call make_idetest_rule,$(idetest)))) +$(foreach idetest,$(sikuli_ide_tests),$(eval $(call make_idetest_rule,$(idetest),sikuli_idetest_command))) +$(foreach idetest,$(pytest_ide_tests),$(eval $(call make_idetest_rule,$(idetest),pytest_idetest_command))) ide_tests : $(ide_tests_targets) echo "$(ide_tests_targets) : Passed" diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/ide_tests/conftest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/conftest.py Fri Mar 11 14:43:37 2022 +0100 @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of Beremiz, a Integrated Development Environment for +# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +# +# Copyright (C) 2017: Andrey Skvortsov +# +# See COPYING file for copyrights details. +# +# 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 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from __future__ import absolute_import +import os +import sys + +# import pytest +# import xvfbwrapper + + +def init_environment(): + """Append module root directory to sys.path""" + try: + import Beremiz as _Beremiz + except ImportError: + sys.path.append( + os.path.abspath( + os.path.join( + os.path.dirname(__file__), '..', '..') + ) + ) + + +init_environment() + +# +# Something seems to be broken in Beremiz application, +# because after tests in test_application.py during Xvfb shutdown +# pytest returns error message: +# pytest: Fatal IO error 11 (Die Ressource ist zur Zeit nicht verfügbar) on X server :2821. +# +# As a result of that pytest returns code 1 as some tests were failed, +# but they aren't. +# +# To avoid this Xvfb is launched and killed not by pytest. +# $ Xvfb :42 -screen 0 1280x1024x24 & +# $ export DISPLAY=:42 +# $ pytest --timeout=10 ./tests/tools +# $ pkill -9 Xvfb +# +# TODO: find root of this problem. + + +# vdisplay = None +# +# @pytest.fixture(scope="session", autouse=True) +# def start_xvfb_server(request): +# global vdisplay +# vdisplay = xvfbwrapper.Xvfb(width=1280, height=720) +# vdisplay.start() +# request.addfinalizer(stop_xvfb_server) +# +# def stop_xvfb_server(): +# if vdisplay is not None: +# vdisplay.stop() diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/ide_tests/load_and_build_tests.pytest/test_application.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/load_and_build_tests.pytest/test_application.py Fri Mar 11 14:43:37 2022 +0100 @@ -0,0 +1,232 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of Beremiz, a Integrated Development Environment for +# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +# +# Copyright (C) 2017: Andrey Skvortsov +# +# See COPYING file for copyrights details. +# +# 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 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from __future__ import absolute_import +from __future__ import print_function +import os +import sys +import unittest +import time + +import six +import pytest +import wx +import ddt + +import conftest +import Beremiz +import PLCOpenEditor + + +class UserApplicationTest(unittest.TestCase): + def InstallExceptionHandler(self): + def handle_exception(e_type, e_value, e_traceback, exit=False): + # traceback.print_exception(e_type, e_value, e_traceback) + self.exc_info = [e_type, e_value, e_traceback] + self.exc_info = None + self.old_excepthook = sys.excepthook + sys.excepthook = handle_exception + + def StartApp(self): + self.app = None + + def FinishApp(self): + wx.CallAfter(self.app.frame.Close) + self.app.MainLoop() + self.app = None + + def setUp(self): + self.app = None + + def tearDown(self): + if self.app is not None and self.app.frame is not None: + self.FinishApp() + + def RunUIActions(self, actions): + for act in actions: + wx.CallAfter(*act) + self.ProcessEvents() + + def CheckForErrors(self): + if self.exc_info is not None: + # reraise catched previously exception + exc_type = self.exc_info[0] + exc_value = self.exc_info[1] + exc_traceback = self.exc_info[2] + six.reraise(exc_type, exc_value, exc_traceback) + + def ProcessEvents(self): + for dummy in range(0, 30): + self.CheckForErrors() + wx.Yield() + time.sleep(0.01) + + +@ddt.ddt +class BeremizApplicationTest(UserApplicationTest): + """Test Beremiz as whole application""" + + def StartApp(self): + self.app = Beremiz.BeremizIDELauncher() + # disable default exception handler in Beremiz + self.app.InstallExceptionHandler = lambda: None + self.InstallExceptionHandler() + self.app.handle_exception = sys.excepthook + self.app.PreStart() + self.ProcessEvents() + self.app.frame.Show() + self.ProcessEvents() + self.app.frame.ShowFullScreen(True) + self.ProcessEvents() + + def FinishApp(self): + wx.CallAfter(self.app.frame.Close) + self.app.MainLoop() + time.sleep(1) + self.app = None + + def GetSkippedProjectTreeItems(self): + """ + Returns the list of skipped items in the project tree. + + Beremiz test don't need to skip any elemnts in the project tree. + """ + return [] + + def OpenAllProjectElements(self): + """Open editor for every object in the project tree""" + self.app.frame.ProjectTree.ExpandAll() + self.ProcessEvents() + item = self.app.frame.ProjectTree.GetRootItem() + skip = self.GetSkippedProjectTreeItems() + tree_id = self.app.frame.ProjectTree.GetId() + while item is not None: + self.app.frame.ProjectTree.SelectItem(item, True) + self.ProcessEvents() + if item not in skip: + event = wx.lib.agw.customtreectrl.TreeEvent( + wx.lib.agw.customtreectrl.wxEVT_TREE_ITEM_ACTIVATED, + tree_id, item) + self.app.frame.OnProjectTreeItemActivated(event) + self.ProcessEvents() + item = self.app.frame.ProjectTree.GetNextVisible(item) + + def CheckTestProject(self, project): + sys.argv = ["", project] + self.StartApp() + self.OpenAllProjectElements() + user_actions = self.GetUserActions() + self.RunUIActions(user_actions) + self.FinishApp() + + def GetProjectPath(self, project): + return os.path.abspath(os.path.join(os.path.dirname(__file__), "..","..","projects", project)) + + def GetUserActions(self): + """ + Returns list of user actions that will be executed + on every test project by testCheckProject test. + """ + user_actions = [ + [self.app.frame.SwitchFullScrMode, None], + [self.app.frame.SwitchFullScrMode, None], + [self.app.frame.CTR._Clean], + [self.app.frame.CTR._Build], + [self.app.frame.CTR._Connect], + [self.app.frame.CTR._Transfer], + [self.app.frame.CTR._Run], + [self.app.frame.CTR._Stop], + [self.app.frame.CTR._Disconnect], + [self.app.frame.CTR._Clean], + ] + return user_actions + + def testStartUp(self): + """Checks whether the app starts and finishes correctly""" + sys.argv = [""] + self.StartApp() + self.FinishApp() + + # TODO: also use "exemples/*" projects + @ddt.data( + #"first_steps", + "logging", + #"traffic_lights", + #"wxGlade", + #"python", + #"wiimote", + # "wxHMI", + ) + @pytest.mark.timeout(300) + def testCheckProject(self, name): + """ + Checks that test PLC project can be open, + compiled and run on SoftPLC. + """ + project = self.GetProjectPath(name) + print("Testing example " + name) + self.CheckTestProject(project) + + +# class PLCOpenEditorApplicationTest(BeremizApplicationTest): +# """Test PLCOpenEditor as whole application""" +# +# def StartApp(self): +# self.app = PLCOpenEditor.PLCOpenEditorApp() +# # disable default exception handler in application +# self.app.InstallExceptionHandler = lambda: None +# self.InstallExceptionHandler() +# self.app.Show() +# self.ProcessEvents() +# self.app.frame.ShowFullScreen(True) +# self.ProcessEvents() +# +# def FinishApp(self): +# wx.CallAfter(self.app.frame.Close) +# self.app.MainLoop() +# time.sleep(1) +# self.app = None +# +# def GetSkippedProjectTreeItems(self): +# """ +# Returns the list of skipped items in the project tree. +# +# Root item opens dialog window for project settings. +# To avoid code that handles closing dialog windows just skip this item. +# """ +# return [self.app.frame.ProjectTree.GetRootItem()] +# +# def GetUserActions(self): +# return [] +# +# def GetProjectPath(self, project): +# """Open PLC program in every Beremiz test project""" +# project_dir = BeremizApplicationTest.GetProjectPath(self, project) +# return os.path.join(project_dir, "plc.xml") +# + +if __name__ == '__main__': + conftest.init_environment() + unittest.main() diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/ide_tests/wx_widgets.pytest/test_CustomIntCtrl.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/wx_widgets.pytest/test_CustomIntCtrl.py Fri Mar 11 14:43:37 2022 +0100 @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of Beremiz, a Integrated Development Environment for +# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +# +# Copyright (C) 2017: Andrey Skvortsov +# +# See COPYING file for copyrights details. +# +# 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 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from __future__ import absolute_import +from __future__ import division +import unittest +import time + +import wx +import conftest +import controls.CustomIntCtrl + + +class TestCustomIntCtrl(unittest.TestCase): + def setUp(self): + self.app = wx.App() + self.frame = wx.Frame(None) + + def tearDown(self): + self.frame.Destroy() + wx.CallAfter(wx.Exit) + self.app.MainLoop() + + def testMaxLimit(self): + """Test working upper bound""" + self.AddControls() + self.int_ctrl.SetValue(self.max_val + 100) + self.ProcessEvents() + + self.txt_ctrl.SetFocus() + self.ProcessEvents() + self.assertEqual(self.int_ctrl.GetValue(), self.max_val) + + def testMinLimit(self): + """Test working lower bound""" + self.AddControls() + self.int_ctrl.SetValue(self.min_val - 100) + self.ProcessEvents() + + self.txt_ctrl.SetFocus() + self.ProcessEvents() + + self.assertEqual(self.int_ctrl.GetValue(), self.min_val) + + def testCorrectValue(self): + """Test case if no limiting is necessary""" + self.AddControls() + val = (self.max_val + self.min_val) // 2 + self.int_ctrl.SetValue(val) + self.ProcessEvents() + + self.txt_ctrl.SetFocus() + self.ProcessEvents() + + self.assertEqual(self.int_ctrl.GetValue(), val) + + def testEventBinding(self): + """Test event sending after edit and bound checks are done""" + self.AddControls() + self.event_happend = False + + def EventHandler(event): + self.event_happend = True + event.Skip() + + self.int_ctrl.Bind(controls.CustomIntCtrl.EVT_CUSTOM_INT, EventHandler) + + val = (self.max_val + self.min_val) // 2 + + self.int_ctrl.SetValue(val) + self.ProcessEvents() + self.txt_ctrl.SetFocus() + + self.ProcessEvents() + self.txt_ctrl.SetFocus() + self.ProcessEvents() + + self.assertEqual(self.int_ctrl.GetValue(), val) + self.assertTrue(self.event_happend) + + def testLongNumbers(self): + """Test support of long integer""" + self.AddControls() + val = 40000000000 + self.int_ctrl.SetMax(val) + self.int_ctrl.SetValue(val) + self.ProcessEvents() + + self.txt_ctrl.SetFocus() + self.ProcessEvents() + + self.assertEqual(val, val) + + def ProcessEvents(self): + for dummy in range(0, 10): + wx.Yield() + time.sleep(0.01) + + def AddControls(self): + vs = wx.BoxSizer(wx.VERTICAL) + self.int_ctrl = controls.CustomIntCtrl(self.frame) + self.txt_ctrl = wx.TextCtrl(self.frame) + vs.Add(self.int_ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5) + vs.Add(self.txt_ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5) + self.frame.SetSizer(vs) + vs.Fit(self.frame) + self.frame.Show() + self.frame.Raise() + + self.min_val = 50 + self.max_val = 100 + self.int_ctrl.SetBounds(self.min_val, self.max_val) + self.ProcessEvents() + + +if __name__ == '__main__': + conftest.init_environment() + unittest.main() diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/tools/Docker/beremiz-sikuli/Dockerfile --- a/tests/tools/Docker/beremiz-sikuli/Dockerfile Sat Mar 05 11:14:00 2022 +0100 +++ b/tests/tools/Docker/beremiz-sikuli/Dockerfile Fri Mar 11 14:43:37 2022 +0100 @@ -54,6 +54,7 @@ RUN virtualenv --python=$(which python2) ~/beremizenv RUN ~/beremizenv/bin/pip install \ + pytest pytest-timeout ddt \ lxml future matplotlib zeroconf2 enum34 pyro sslpsk posix_spawn \ twisted nevow autobahn \ wxPython==4.1.1 diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/tools/conftest.py --- a/tests/tools/conftest.py Sat Mar 05 11:14:00 2022 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This file is part of Beremiz, a Integrated Development Environment for -# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. -# -# Copyright (C) 2017: Andrey Skvortsov -# -# See COPYING file for copyrights details. -# -# 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 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -from __future__ import absolute_import -import os -import sys - -# import pytest -# import xvfbwrapper - - -def init_environment(): - """Append module root directory to sys.path""" - try: - import Beremiz as _Beremiz - except ImportError: - sys.path.append( - os.path.abspath( - os.path.join( - os.path.dirname(__file__), '..', '..') - ) - ) - - -init_environment() - -# -# Something seems to be broken in Beremiz application, -# because after tests in test_application.py during Xvfb shutdown -# pytest returns error message: -# pytest: Fatal IO error 11 (Die Ressource ist zur Zeit nicht verfügbar) on X server :2821. -# -# As a result of that pytest returns code 1 as some tests were failed, -# but they aren't. -# -# To avoid this Xvfb is launched and killed not by pytest. -# $ Xvfb :42 -screen 0 1280x1024x24 & -# $ export DISPLAY=:42 -# $ pytest --timeout=10 ./tests/tools -# $ pkill -9 Xvfb -# -# TODO: find root of this problem. - - -# vdisplay = None -# -# @pytest.fixture(scope="session", autouse=True) -# def start_xvfb_server(request): -# global vdisplay -# vdisplay = xvfbwrapper.Xvfb(width=1280, height=720) -# vdisplay.start() -# request.addfinalizer(stop_xvfb_server) -# -# def stop_xvfb_server(): -# if vdisplay is not None: -# vdisplay.stop() diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/tools/run_python_tests.sh --- a/tests/tools/run_python_tests.sh Sat Mar 05 11:14:00 2022 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -#!/bin/sh - - - -cleanup() -{ - find $PYTEST_DIR -name '*.pyc' -delete -} - - - -print_help() -{ - echo "Usage: run_python_tests.sh [--on-local-xserver]" - echo "" - echo "--on-local-xserver" - echo " all tests are run on local X-server. " - echo " User can see test in action." - echo " Any interaction (mouse, keyboard) should be avoided" - echo " By default without arguments script runs pytest on virtual X serverf." - echo "" - - exit 1 -} - -main() -{ - LC_ALL=ru_RU.utf-8 - PYTEST_DIR=./tests/tools - - if [ ! -d $PYTEST_DIR ]; then - echo "Script should be run from top directory in repository" - exit 1; - fi - - use_xvfb=0 - if [ "$1" != "--on-local-xserver" ]; then - export DISPLAY=:42 - use_xvfb=1 - Xvfb $DISPLAY -screen 0 1280x1024x24 & - sleep 1 - fi - - - cleanup - - ret=0 - DELAY=400 - KILL_DELAY=$(($DELAY + 30)) - timeout -k $KILL_DELAY $DELAY pytest --timeout=10 ./tests/tools - ret=$? - - cleanup - - [ $use_xvfb = 1 ] && pkill -9 Xvfb - exit $ret -} - - -[ "$1" = "--help" -o "$1" = "-h" ] && print_help -main $@ diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/tools/test_CustomIntCtrl.py --- a/tests/tools/test_CustomIntCtrl.py Sat Mar 05 11:14:00 2022 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This file is part of Beremiz, a Integrated Development Environment for -# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. -# -# Copyright (C) 2017: Andrey Skvortsov -# -# See COPYING file for copyrights details. -# -# 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 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -from __future__ import absolute_import -from __future__ import division -import unittest -import time - -import wx -import conftest -import controls.CustomIntCtrl - - -class TestCustomIntCtrl(unittest.TestCase): - def setUp(self): - self.app = wx.App() - self.frame = wx.Frame(None) - - def tearDown(self): - self.frame.Destroy() - wx.CallAfter(self.app.Exit) - self.app.MainLoop() - - def testMaxLimit(self): - """Test working upper bound""" - self.AddControls() - self.int_ctrl.SetValue(self.max_val + 100) - self.ProcessEvents() - - self.txt_ctrl.SetFocus() - self.ProcessEvents() - self.assertEqual(self.int_ctrl.GetValue(), self.max_val) - - def testMinLimit(self): - """Test working lower bound""" - self.AddControls() - self.int_ctrl.SetValue(self.min_val - 100) - self.ProcessEvents() - - self.txt_ctrl.SetFocus() - self.ProcessEvents() - - self.assertEqual(self.int_ctrl.GetValue(), self.min_val) - - def testCorrectValue(self): - """Test case if no limiting is necessary""" - self.AddControls() - val = (self.max_val + self.min_val) // 2 - self.int_ctrl.SetValue(val) - self.ProcessEvents() - - self.txt_ctrl.SetFocus() - self.ProcessEvents() - - self.assertEqual(self.int_ctrl.GetValue(), val) - - def testEventBinding(self): - """Test event sending after edit and bound checks are done""" - self.AddControls() - self.event_happend = False - - def EventHandler(event): - self.event_happend = True - event.Skip() - - self.int_ctrl.Bind(controls.CustomIntCtrl.EVT_CUSTOM_INT, EventHandler) - - val = (self.max_val + self.min_val) // 2 - - self.int_ctrl.SetValue(val) - self.ProcessEvents() - self.txt_ctrl.SetFocus() - - self.ProcessEvents() - self.txt_ctrl.SetFocus() - self.ProcessEvents() - - self.assertEqual(self.int_ctrl.GetValue(), val) - self.assertTrue(self.event_happend) - - def testLongNumbers(self): - """Test support of long integer""" - self.AddControls() - val = 40000000000 - self.int_ctrl.SetMax(val) - self.int_ctrl.SetValue(val) - self.ProcessEvents() - - self.txt_ctrl.SetFocus() - self.ProcessEvents() - - self.assertEqual(val, val) - - def ProcessEvents(self): - for dummy in range(0, 10): - wx.Yield() - time.sleep(0.01) - - def AddControls(self): - vs = wx.BoxSizer(wx.VERTICAL) - self.int_ctrl = controls.CustomIntCtrl(self.frame) - self.txt_ctrl = wx.TextCtrl(self.frame) - vs.Add(self.int_ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5) - vs.Add(self.txt_ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5) - self.frame.SetSizer(vs) - vs.Fit(self.frame) - self.frame.Show() - self.frame.Raise() - - self.min_val = 50 - self.max_val = 100 - self.int_ctrl.SetBounds(self.min_val, self.max_val) - self.ProcessEvents() - - -if __name__ == '__main__': - conftest.init_environment() - unittest.main() diff -r ce366d67a5b7 -r 24fbd4d1fe80 tests/tools/test_application.py --- a/tests/tools/test_application.py Sat Mar 05 11:14:00 2022 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This file is part of Beremiz, a Integrated Development Environment for -# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. -# -# Copyright (C) 2017: Andrey Skvortsov -# -# See COPYING file for copyrights details. -# -# 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 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -from __future__ import absolute_import -from __future__ import print_function -import os -import sys -import unittest -import time - -import six -import pytest -import wx -import ddt - -import conftest -import Beremiz -import PLCOpenEditor - - -class UserApplicationTest(unittest.TestCase): - def InstallExceptionHandler(self): - def handle_exception(e_type, e_value, e_traceback, exit=False): - # traceback.print_exception(e_type, e_value, e_traceback) - self.exc_info = [e_type, e_value, e_traceback] - self.exc_info = None - self.old_excepthook = sys.excepthook - sys.excepthook = handle_exception - - def StartApp(self): - self.app = None - - def FinishApp(self): - wx.CallAfter(self.app.frame.Close) - self.app.MainLoop() - self.app = None - - def setUp(self): - self.app = None - - def tearDown(self): - if self.app is not None and self.app.frame is not None: - self.FinishApp() - - def RunUIActions(self, actions): - for act in actions: - wx.CallAfter(*act) - self.ProcessEvents() - - def CheckForErrors(self): - if self.exc_info is not None: - # reraise catched previously exception - exc_type = self.exc_info[0] - exc_value = self.exc_info[1] - exc_traceback = self.exc_info[2] - six.reraise(exc_type, exc_value, exc_traceback) - - def ProcessEvents(self): - for dummy in range(0, 30): - self.CheckForErrors() - wx.Yield() - time.sleep(0.01) - - -@ddt.ddt -class BeremizApplicationTest(UserApplicationTest): - """Test Beremiz as whole application""" - - def StartApp(self): - self.app = Beremiz.BeremizIDELauncher() - # disable default exception handler in Beremiz - self.app.InstallExceptionHandler = lambda: None - self.InstallExceptionHandler() - self.app.handle_exception = sys.excepthook - self.app.PreStart() - self.ProcessEvents() - self.app.frame.Show() - self.ProcessEvents() - self.app.frame.ShowFullScreen(True) - self.ProcessEvents() - - def FinishApp(self): - wx.CallAfter(self.app.frame.Close) - self.app.MainLoop() - time.sleep(1) - self.app = None - - def GetSkippedProjectTreeItems(self): - """ - Returns the list of skipped items in the project tree. - - Beremiz test don't need to skip any elemnts in the project tree. - """ - return [] - - def OpenAllProjectElements(self): - """Open editor for every object in the project tree""" - self.app.frame.ProjectTree.ExpandAll() - self.ProcessEvents() - item = self.app.frame.ProjectTree.GetRootItem() - skip = self.GetSkippedProjectTreeItems() - tree_id = self.app.frame.ProjectTree.GetId() - while item is not None: - self.app.frame.ProjectTree.SelectItem(item, True) - self.ProcessEvents() - if item not in skip: - event = wx.lib.agw.customtreectrl.TreeEvent( - wx.lib.agw.customtreectrl.wxEVT_TREE_ITEM_ACTIVATED, - tree_id, item) - self.app.frame.OnProjectTreeItemActivated(event) - self.ProcessEvents() - item = self.app.frame.ProjectTree.GetNextVisible(item) - - def CheckTestProject(self, project): - sys.argv = ["", project] - self.StartApp() - self.OpenAllProjectElements() - user_actions = self.GetUserActions() - self.RunUIActions(user_actions) - self.FinishApp() - - def GetProjectPath(self, project): - return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", project)) - - def GetUserActions(self): - """ - Returns list of user actions that will be executed - on every test project by testCheckProject test. - """ - user_actions = [ - [self.app.frame.SwitchFullScrMode, None], - [self.app.frame.SwitchFullScrMode, None], - [self.app.frame.CTR._Clean], - [self.app.frame.CTR._Build], - [self.app.frame.CTR._Connect], - [self.app.frame.CTR._Transfer], - [self.app.frame.CTR._Run], - [self.app.frame.CTR._Stop], - [self.app.frame.CTR._Disconnect], - [self.app.frame.CTR._Clean], - ] - return user_actions - - def testStartUp(self): - """Checks whether the app starts and finishes correctly""" - sys.argv = [""] - self.StartApp() - self.FinishApp() - - @ddt.data( - "first_steps", - "logging", - "traffic_lights", - "wxGlade", - "python", - "wiimote", - "wxHMI", - ) - @pytest.mark.timeout(30) - def testCheckProject(self, name): - """ - Checks that test PLC project can be open, - compiled and run on SoftPLC. - """ - project = self.GetProjectPath(name) - print("Testing example " + name) - self.CheckTestProject(project) - - -class PLCOpenEditorApplicationTest(BeremizApplicationTest): - """Test PLCOpenEditor as whole application""" - - def StartApp(self): - self.app = PLCOpenEditor.PLCOpenEditorApp() - # disable default exception handler in application - self.app.InstallExceptionHandler = lambda: None - self.InstallExceptionHandler() - self.app.Show() - self.ProcessEvents() - self.app.frame.ShowFullScreen(True) - self.ProcessEvents() - - def FinishApp(self): - wx.CallAfter(self.app.frame.Close) - self.app.MainLoop() - time.sleep(1) - self.app = None - - def GetSkippedProjectTreeItems(self): - """ - Returns the list of skipped items in the project tree. - - Root item opens dialog window for project settings. - To avoid code that handles closing dialog windows just skip this item. - """ - return [self.app.frame.ProjectTree.GetRootItem()] - - def GetUserActions(self): - return [] - - def GetProjectPath(self, project): - """Open PLC program in every Beremiz test project""" - project_dir = BeremizApplicationTest.GetProjectPath(self, project) - return os.path.join(project_dir, "plc.xml") - - -if __name__ == '__main__': - conftest.init_environment() - unittest.main()