--- a/BeremizIDE.py Sun Feb 13 20:53:00 2022 +0100
+++ b/BeremizIDE.py Sun Feb 13 20:59:42 2022 +0100
@@ -398,6 +398,7 @@
self.LogConsole.MarkerDefine(0, wx.stc.STC_MARK_CIRCLE, "BLACK", "RED")
self.LogConsole.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT)
+ self.LogConsole.SetCaretPeriod(0) self.LogConsole.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnLogConsoleMarginClick)
self.LogConsole.Bind(wx.stc.EVT_STC_MODIFIED, self.OnLogConsoleModified)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/ide_tests/run_python_exemple.sikuli/run_python_exemple.py Sun Feb 13 20:59:42 2022 +0100
@@ -0,0 +1,57 @@
+""" This test opens, builds and runs exemple project named "python". +Test succeeds if runtime's stdout behaves as expected +# allow module import from current test directory's parent +addImportPath(os.path.dirname(getBundlePath())) +# common test definitions module +from sikuliberemiz import * +proc,app = StartBeremizApp(exemple="python") +# To detect when actions did finish because IDE content isn't changing +# idle = IDEIdleObserver(app) +# screencap based idle detection was making many false positive. Test is more stable with stdout based idle detection +stdoutIdle = stdoutIdleObserver(proc) +# To send keyboard shortuts +# wait 10 seconds for 10 Grumpfs +found = waitPatternInStdout(proc, "Grumpf", 10, 10) --- /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" +from threading import Thread, Event +home = os.environ["HOME"] +beremiz_path = os.environ["BEREMIZPATH"] +def StartBeremizApp(projectpath=None, exemple=None): + Starts Beremiz IDE, waits for main window to appear, maximize it. + projectpath (str): path to project to open + exemple (str): path relative to exemples directory + 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 + # equiv to "wmctrl -l -p | grep $pid" + 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: + # 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] + 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) + """Send shortut to app by calling corresponding methods: + fkeys = {"Stop": Key.F4, + def __init__(self, app): + def __getattr__(self, name): + fkey = self.fkeys[name] + "Detects when IDE is idle. This is particularly handy when staring an operation and witing for the en of it." + def __init__(self, app): + 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 _OnIDEWindowChange(self, event): + def Wait(self, period, timeout): + Wait for IDE to stop changing + period (int): how many seconds with no change to consider idle + timeout (int): how long to wait for idle, in seconds + self.idechanged = False + if not self.idechanged: + 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): + proc (subprocess.Popen): Beremiz process, given by StartBeremizApp + self.stdoutchanged = False + self.thread = Thread(target = self._waitStdoutProc).start() + a = self.proc.stdout.read(1) + if len(a) == 0 or a is None: + def Wait(self, period, timeout): + Wait for IDE'stdout to stop changing + period (int): how many seconds with no change to consider idle + timeout (int): how long to wait for idle, in seconds + self.idechanged = False + if not self.idechanged: + raise Exception("Stdout did not idle before timeout") +def waitPatternInStdout(proc, pattern, timeout, count=1): + success_event = Event() + def waitPatternInStdoutProc(): + a = proc.stdout.readline() + if len(a) == 0 or a is None: + raise Exception("App finished before producing expected stdout pattern") + if a.find(pattern) >= 0: + Thread(target = waitPatternInStdoutProc).start() + if not success_event.wait(timeout):