andrej@1808: #!/usr/bin/env python
andrej@1808: # -*- coding: utf-8 -*-
andrej@1808: 
andrej@1808: # This file is part of Beremiz, a Integrated Development Environment for
andrej@1808: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
andrej@1808: #
andrej@1808: # Copyright (C) 2017: Andrey Skvortsov
andrej@1808: #
andrej@1808: # See COPYING file for copyrights details.
andrej@1808: #
andrej@1808: # This program is free software; you can redistribute it and/or
andrej@1808: # modify it under the terms of the GNU General Public License
andrej@1808: # as published by the Free Software Foundation; either version 2
andrej@1808: # of the License, or (at your option) any later version.
andrej@1808: #
andrej@1808: # This program is distributed in the hope that it will be useful,
andrej@1808: # but WITHOUT ANY WARRANTY; without even the implied warranty of
andrej@1808: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
andrej@1808: # GNU General Public License for more details.
andrej@1808: #
andrej@1808: # You should have received a copy of the GNU General Public License
andrej@1808: # along with this program; if not, write to the Free Software
andrej@1808: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
andrej@1808: 
andrej@1826: 
andrej@1881: from __future__ import absolute_import
andrej@1826: from __future__ import print_function
andrej@1796: import os
andrej@1796: import sys
andrej@1796: import unittest
andrej@1832: import time
andrej@1832: 
andrej@2419: import six
andrej@1809: import pytest
andrej@1796: import wx
andrej@1809: import ddt
andrej@1796: 
andrej@1808: import conftest
andrej@1808: import Beremiz
andrej@1819: import PLCOpenEditor
andrej@1796: 
andrej@1796: 
andrej@1796: class UserApplicationTest(unittest.TestCase):
andrej@1796:     def InstallExceptionHandler(self):
edouard@1961:         def handle_exception(e_type, e_value, e_traceback, exit=False):
andrej@1796:             # traceback.print_exception(e_type, e_value, e_traceback)
andrej@1796:             self.exc_info = [e_type, e_value, e_traceback]
andrej@1796:         self.exc_info = None
andrej@1796:         self.old_excepthook = sys.excepthook
andrej@1796:         sys.excepthook = handle_exception
andrej@1796: 
andrej@1796:     def StartApp(self):
andrej@1796:         self.app = None
andrej@1796: 
andrej@1796:     def FinishApp(self):
andrej@1796:         wx.CallAfter(self.app.frame.Close)
andrej@1796:         self.app.MainLoop()
andrej@1796:         self.app = None
andrej@1796: 
andrej@1809:     def setUp(self):
andrej@1809:         self.app = None
andrej@1809: 
andrej@1796:     def tearDown(self):
andrej@1796:         if self.app is not None and self.app.frame is not None:
andrej@1796:             self.FinishApp()
andrej@1796: 
andrej@1796:     def RunUIActions(self, actions):
andrej@1796:         for act in actions:
andrej@1796:             wx.CallAfter(*act)
andrej@1796:             self.ProcessEvents()
andrej@1796: 
andrej@1796:     def CheckForErrors(self):
andrej@1796:         if self.exc_info is not None:
andrej@1796:             # reraise catched previously exception
andrej@2419:             exc_type = self.exc_info[0]
andrej@2419:             exc_value = self.exc_info[1]
andrej@2419:             exc_traceback = self.exc_info[2]
andrej@2419:             six.reraise(exc_type, exc_value, exc_traceback)
andrej@1796: 
andrej@1796:     def ProcessEvents(self):
andrej@1847:         for dummy in range(0, 30):
andrej@1796:             self.CheckForErrors()
andrej@1796:             wx.Yield()
andrej@1796:             time.sleep(0.01)
andrej@1796: 
andrej@1796: 
andrej@1809: @ddt.ddt
andrej@1796: class BeremizApplicationTest(UserApplicationTest):
andrej@1796:     """Test Beremiz as whole application"""
andrej@1816: 
andrej@1796:     def StartApp(self):
andrej@1796:         self.app = Beremiz.BeremizIDELauncher()
andrej@1796:         # disable default exception handler in Beremiz
andrej@1796:         self.app.InstallExceptionHandler = lambda: None
andrej@1796:         self.InstallExceptionHandler()
edouard@1961:         self.app.handle_exception = sys.excepthook
andrej@1796:         self.app.PreStart()
edouard@1961:         self.ProcessEvents()
andrej@1818:         self.app.frame.Show()
andrej@1818:         self.ProcessEvents()
andrej@1818:         self.app.frame.ShowFullScreen(True)
andrej@1818:         self.ProcessEvents()
andrej@1796: 
andrej@1796:     def FinishApp(self):
andrej@1796:         wx.CallAfter(self.app.frame.Close)
andrej@1796:         self.app.MainLoop()
andrej@1796:         time.sleep(1)
andrej@1796:         self.app = None
andrej@1796: 
andrej@1816:     def GetSkippedProjectTreeItems(self):
andrej@1816:         """
andrej@1816:         Returns the list of skipped items in the project tree.
andrej@1816: 
andrej@1816:         Beremiz test don't need to skip any elemnts in the project tree.
andrej@1816:         """
andrej@1816:         return []
andrej@1816: 
andrej@1796:     def OpenAllProjectElements(self):
andrej@1808:         """Open editor for every object in the project tree"""
andrej@1796:         self.app.frame.ProjectTree.ExpandAll()
andrej@1796:         self.ProcessEvents()
andrej@1796:         item = self.app.frame.ProjectTree.GetRootItem()
andrej@1819:         skip = self.GetSkippedProjectTreeItems()
andrej@1819:         tree_id = self.app.frame.ProjectTree.GetId()
andrej@1796:         while item is not None:
andrej@1796:             self.app.frame.ProjectTree.SelectItem(item, True)
andrej@1796:             self.ProcessEvents()
andrej@1819:             if item not in skip:
andrej@1819:                 event = wx.lib.agw.customtreectrl.TreeEvent(
andrej@1819:                     wx.lib.agw.customtreectrl.wxEVT_TREE_ITEM_ACTIVATED,
andrej@1819:                     tree_id, item)
andrej@1819:                 self.app.frame.OnProjectTreeItemActivated(event)
andrej@1796:             self.ProcessEvents()
andrej@1796:             item = self.app.frame.ProjectTree.GetNextVisible(item)
andrej@1796: 
andrej@1816:     def CheckTestProject(self, project):
andrej@1796:         sys.argv = ["", project]
andrej@1796:         self.StartApp()
andrej@1796:         self.OpenAllProjectElements()
andrej@1816:         user_actions = self.GetUserActions()
andrej@1816:         self.RunUIActions(user_actions)
andrej@1816:         self.FinishApp()
andrej@1796: 
andrej@1816:     def GetProjectPath(self, project):
andrej@1816:         return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", project))
andrej@1816: 
andrej@1816:     def GetUserActions(self):
andrej@1816:         """
andrej@1816:         Returns list of user actions that will be executed
andrej@1816:         on every test project by testCheckProject test.
andrej@1816:         """
andrej@1796:         user_actions = [
andrej@1796:             [self.app.frame.SwitchFullScrMode, None],
andrej@1796:             [self.app.frame.SwitchFullScrMode, None],
andrej@1796:             [self.app.frame.CTR._Clean],
andrej@1796:             [self.app.frame.CTR._Build],
andrej@1796:             [self.app.frame.CTR._Connect],
andrej@1796:             [self.app.frame.CTR._Transfer],
andrej@1796:             [self.app.frame.CTR._Run],
andrej@1796:             [self.app.frame.CTR._Stop],
andrej@1796:             [self.app.frame.CTR._Disconnect],
andrej@1822:             [self.app.frame.CTR._Clean],
andrej@1796:         ]
andrej@1816:         return user_actions
andrej@1796: 
andrej@1796:     def testStartUp(self):
andrej@1796:         """Checks whether the app starts and finishes correctly"""
andrej@1817:         sys.argv = [""]
andrej@1796:         self.StartApp()
andrej@1796:         self.FinishApp()
andrej@1796: 
andrej@1809:     @ddt.data(
andrej@1809:         "first_steps",
andrej@1809:         "logging",
andrej@1809:         "svgui",
andrej@1809:         "traffic_lights",
andrej@1809:         "wxGlade",
andrej@1809:         "python",
andrej@1809:         "wiimote",
andrej@1809:         "wxHMI",
andrej@1809:     )
andrej@1809:     @pytest.mark.timeout(30)
andrej@1809:     def testCheckProject(self, name):
andrej@1816:         """
andrej@1816:         Checks that test PLC project can be open,
andrej@1816:         compiled and run on SoftPLC.
andrej@1816:         """
andrej@1816:         project = self.GetProjectPath(name)
andrej@1826:         print("Testing example " + name)
andrej@1816:         self.CheckTestProject(project)
andrej@1796: 
andrej@1796: 
andrej@1819: class PLCOpenEditorApplicationTest(BeremizApplicationTest):
andrej@1819:     """Test PLCOpenEditor as whole application"""
andrej@1819: 
andrej@1819:     def StartApp(self):
andrej@1819:         self.app = PLCOpenEditor.PLCOpenEditorApp()
andrej@1819:         # disable default exception handler in application
andrej@1819:         self.app.InstallExceptionHandler = lambda: None
andrej@1819:         self.InstallExceptionHandler()
andrej@1819:         self.app.Show()
andrej@1819:         self.ProcessEvents()
andrej@1819:         self.app.frame.ShowFullScreen(True)
andrej@1819:         self.ProcessEvents()
andrej@1819: 
andrej@1819:     def FinishApp(self):
andrej@1819:         wx.CallAfter(self.app.frame.Close)
andrej@1819:         self.app.MainLoop()
andrej@1819:         time.sleep(1)
andrej@1819:         self.app = None
andrej@1819: 
andrej@1819:     def GetSkippedProjectTreeItems(self):
andrej@1819:         """
andrej@1819:         Returns the list of skipped items in the project tree.
andrej@1819: 
andrej@1819:         Root item opens dialog window for project settings.
andrej@1819:         To avoid code that handles closing dialog windows just skip this item.
andrej@1819:         """
andrej@1819:         return [self.app.frame.ProjectTree.GetRootItem()]
andrej@1819: 
andrej@1819:     def GetUserActions(self):
andrej@1819:         return []
andrej@1819: 
andrej@1819:     def GetProjectPath(self, project):
andrej@1819:         """Open PLC program in every Beremiz test project"""
andrej@1819:         project_dir = BeremizApplicationTest.GetProjectPath(self, project)
andrej@1819:         return os.path.join(project_dir, "plc.xml")
andrej@1819: 
andrej@1819: 
andrej@1796: if __name__ == '__main__':
andrej@1850:     conftest.init_environment()
andrej@1796:     unittest.main()