--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/ide_tests/sikuliberemiz.py Sun Feb 13 20:59:42 2022 +0100
@@ -0,0 +1,218 @@
+"Commons definitions for sikuli based beremiz IDE GUI tests"
+
+import os
+import sys
+import subprocess
+from threading import Thread, Event
+from sikuli import *
+
+home = os.environ["HOME"]
+beremiz_path = os.environ["BEREMIZPATH"]
+
+opj = os.path.join
+
+
+def StartBeremizApp(projectpath=None, exemple=None):
+ """
+ Starts Beremiz IDE, waits for main window to appear, maximize it.
+
+ Parameters:
+ projectpath (str): path to project to open
+ exemple (str): path relative to exemples directory
+
+ Returns:
+ Sikuli App class instance
+ """
+
+ command = ["%s/beremizenv/bin/python"%home, opj(beremiz_path,"Beremiz.py"), "--log=/dev/stdout"]
+
+ if exemple is not None:
+ command.append(opj(beremiz_path,"exemples",exemple))
+ elif projectpath is not None:
+ command.append(projectpath)
+
+ # App class is broken in Sikuli 2.0.5: can't start process with arguments.
+ #
+ # Workaround : - use subprocess module to spawn IDE process,
+ # - use wmctrl to find IDE window details and maximize it
+ # - pass exact window title to App class constructor
+
+ proc = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=0)
+
+ # Window are macthed against process' PID
+ ppid = proc.pid
+
+ # Timeout 5s
+ c = 50
+ while c > 0:
+ # equiv to "wmctrl -l -p | grep $pid"
+ try:
+ wlist = filter(lambda l:(len(l)>2 and l[2]==str(ppid)), map(lambda s:s.split(None,4), subprocess.check_output(["wmctrl", "-l", "-p"]).splitlines()))
+ except subprocess.CalledProcessError:
+ wlist = []
+
+ # window with no title only has 4 fields do describe it
+ # beremiz splashcreen has no title
+ # we wity until main window is visible
+ if len(wlist) == 1 and len(wlist[0]) == 5:
+ windowID,_zero,wpid,_XID,wtitle = wlist[0]
+ break
+
+ wait(0.1)
+ c = c - 1
+
+ if c == 0:
+ raise Exception("Couldn't find Beremiz window")
+
+ # Maximize window x and y
+ subprocess.check_call(["wmctrl", "-i", "-r", windowID, "-b", "add,maximized_vert,maximized_horz"])
+
+ # switchApp creates an App object by finding window by title, is not supposed to spawn a process
+ return proc, switchApp(wtitle)
+
+class KBDShortcut:
+ """Send shortut to app by calling corresponding methods:
+ Stop
+ Run
+ Transfer
+ Connect
+ Clean
+ Build
+
+ example:
+ k = KBDShortcut(app)
+ k.Clean()
+ """
+
+ fkeys = {"Stop": Key.F4,
+ "Run": Key.F5,
+ "Transfer": Key.F6,
+ "Connect": Key.F7,
+ "Clean": Key.F9,
+ "Build": Key.F11}
+
+ def __init__(self, app):
+ self.app = app
+
+ def __getattr__(self, name):
+ fkey = self.fkeys[name]
+ app = self.app
+
+ def PressShortCut():
+ app.focus()
+ type(fkey)
+
+ return PressShortCut
+
+
+class IDEIdleObserver:
+ "Detects when IDE is idle. This is particularly handy when staring an operation and witing for the en of it."
+
+ def __init__(self, app):
+ """
+ Parameters:
+ app (class App): Sikuli app given by StartBeremizApp
+ """
+ self.r = Region(app.window())
+
+ self.idechanged = False
+
+ # 200 was selected because default 50 was still catching cursor blinking in console
+ # FIXME : remove blinking cursor in console
+ self.r.onChange(200,self._OnIDEWindowChange)
+ self.r.observeInBackground()
+
+ def __del__(self):
+ self.r.stopObserver()
+
+ def _OnIDEWindowChange(self, event):
+ print event
+ self.idechanged = True
+
+ def Wait(self, period, timeout):
+ """
+ Wait for IDE to stop changing
+ Parameters:
+ period (int): how many seconds with no change to consider idle
+ timeout (int): how long to wait for idle, in seconds
+ """
+ c = timeout/period
+ while c > 0:
+ self.idechanged = False
+ wait(period)
+ if not self.idechanged:
+ break
+ c = c - 1
+
+ if c == 0:
+ raise Exception("Window did not idle before timeout")
+
+
+class stdoutIdleObserver:
+ "Detects when IDE's stdout is idle. Can be more reliable than pixel based version (false changes ?)"
+
+ def __init__(self, proc):
+ """
+ Parameters:
+ proc (subprocess.Popen): Beremiz process, given by StartBeremizApp
+ """
+ self.proc = proc
+ self.stdoutchanged = False
+
+ self.thread = Thread(target = self._waitStdoutProc).start()
+
+ def _waitStdoutProc():
+ while True:
+ a = self.proc.stdout.read(1)
+ if len(a) == 0 or a is None:
+ break
+ sys.stdout.write(a)
+ self.idechanged = True
+
+ def Wait(self, period, timeout):
+ """
+ Wait for IDE'stdout to stop changing
+ Parameters:
+ period (int): how many seconds with no change to consider idle
+ timeout (int): how long to wait for idle, in seconds
+ """
+ c = timeout/period
+ while c > 0:
+ self.idechanged = False
+ wait(period)
+ if not self.idechanged:
+ break
+ c = c - 1
+
+ if c == 0:
+ raise Exception("Stdout did not idle before timeout")
+
+
+def waitPatternInStdout(proc, pattern, timeout, count=1):
+
+ success_event = Event()
+
+ def waitPatternInStdoutProc():
+ found = 0
+ while True:
+ a = proc.stdout.readline()
+ if len(a) == 0 or a is None:
+ raise Exception("App finished before producing expected stdout pattern")
+ sys.stdout.write(a)
+ if a.find(pattern) >= 0:
+ found = found + 1
+ if found >= count:
+ success_event.set()
+ break
+
+
+ Thread(target = waitPatternInStdoutProc).start()
+
+ if not success_event.wait(timeout):
+ # test timed out
+ return False
+ else:
+ return True
+
+
+