From 5cde8f20dc328706651db6be8502dcb0f910e221 Mon Sep 17 00:00:00 2001 From: Matěj Cepl Date: Mon, 23 Jun 2014 14:56:22 +0200 Subject: The string in the step decoration doesn’t have to be Unicode. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1 on gitorious. --- MANIFEST.in | 2 + README | 11 +- cucutags.py | 9 +- test/data/common_steps | 1 - test/data/common_steps/.gitignore | 2 + test/data/common_steps/__init__.py | 0 test/data/common_steps/app.py | 87 ++++++ test/data/common_steps/dialogs.py | 57 ++++ test/data/common_steps/gmenu.py | 48 +++ test/data/common_steps/helpers.py | 591 +++++++++++++++++++++++++++++++++++ test/data/features/steps/tutorial.py | 13 + test/data/features/tutorial.feature | 6 + test/test_cucutags.py | 5 +- 13 files changed, 822 insertions(+), 10 deletions(-) create mode 100644 MANIFEST.in delete mode 160000 test/data/common_steps create mode 100644 test/data/common_steps/.gitignore create mode 100644 test/data/common_steps/__init__.py create mode 100644 test/data/common_steps/app.py create mode 100644 test/data/common_steps/dialogs.py create mode 100644 test/data/common_steps/gmenu.py create mode 100644 test/data/common_steps/helpers.py create mode 100644 test/data/features/steps/tutorial.py create mode 100644 test/data/features/tutorial.feature diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..9e2c619 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include README +recursive-include test *.feature *.py diff --git a/README b/README index e3cfc7f..73bd5f4 100644 --- a/README +++ b/README @@ -1,11 +1,12 @@ cucutags provides a simple generator of ctags-like tags file for the combination of [Gherkin language features](https://github.com/cucumber/cucumber/wiki/Gherkin) and Python [steps](https://github.com/behave/behave). -Unfortunately, no text editor known to me is able to use so -generated tags file. However, this script can be also used by any -other Python script as a library, and thus for example -[vim](http://www.vim.org) can use it via -[vim-behave](https://gitorious.org/cucutags/vim-behave) plugin. +Unfortunately, no text editor known to me is able to use so generated +tags file. However, this script can be also used by any other Python +script as a library, and thus for example [vim](http://www.vim.org) can +use it via [vim-behave](https://gitorious.org/cucutags/vim-behave) +plugin or [gedit](https://wiki.gnome.org/Apps/Gedit) via the +[gedit_behave](https://gitorious.org/cucutags/gedit_behave) one. All bug reports and enhancement requests, please, send to the email listed in the script file. diff --git a/cucutags.py b/cucutags.py index d57d310..a463258 100755 --- a/cucutags.py +++ b/cucutags.py @@ -31,7 +31,7 @@ logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', import parse __docformat__ = 'reStructuredText' -__version__ = "0.6.1" +__version__ = "0.7.0" __author__ = u"Matěj Cepl " @@ -39,7 +39,7 @@ class Target(object): """ Represents one line from the Python modules. """ - pattern = re.compile(r"^\s*@(step|when|given|then)\(u'(.*)'\)") + pattern = re.compile(r"^\s*@(step|when|given|then)\(u?'(.*)'\)") result = 'targets' def __init__(self, text, filename, lineno): @@ -123,11 +123,14 @@ class CodeFile(io.TextIOWrapper): if file_ext in PATTERNS.keys(): ftype = PATTERNS[file_ext] - logging.debug("cdir = %s, file = %s", cdir, self.name) + logging.debug("cdir = %s, file = %s, ftype = %s", + cdir, self.name, ftype) with io.open(self.name) as f: lineno = 0 for line in f.readlines(): lineno += 1 + logging.debug('line = %s', line) + logging.debug('pattern = %s', ftype.pattern.pattern) matches = ftype.pattern.search(line) if matches: logging.debug("key = %s", ftype.result) diff --git a/test/data/common_steps b/test/data/common_steps deleted file mode 160000 index d56c619..0000000 --- a/test/data/common_steps +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d56c6197dfe923afc39e8795bf8e1b1d5a984032 diff --git a/test/data/common_steps/.gitignore b/test/data/common_steps/.gitignore new file mode 100644 index 0000000..2f836aa --- /dev/null +++ b/test/data/common_steps/.gitignore @@ -0,0 +1,2 @@ +*~ +*.pyc diff --git a/test/data/common_steps/__init__.py b/test/data/common_steps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/data/common_steps/app.py b/test/data/common_steps/app.py new file mode 100644 index 0000000..9615398 --- /dev/null +++ b/test/data/common_steps/app.py @@ -0,0 +1,87 @@ +# -- FILE: features/steps/example_steps.py +import os +import logging +logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', + level=logging.INFO) +from gi.repository import GLib +from behave import then, step +from time import sleep +#from subprocess import Popen, PIPE +from dogtail.tree import root, SearchError +from dogtail.rawinput import keyCombo +from dogtail.utils import doDelay +#from ConfigParser import ConfigParser +#, step + + +@step(u'Press "{sequence}"') +def press_button_sequence(context, sequence): + keyCombo(sequence) + sleep(0.5) + + +def wait_for_app_to_appear(context, app): + # Waiting for a window to appear + for attempt in xrange(0, 10): + try: + context.app.instance = root.application(app.lower()) + context.app.instance.child(roleName='frame') + break + except (GLib.GError, SearchError): + sleep(1) + if attempt == 6: + # Cleanup and restart app processes if we reached 30 + # seconds wait + keyCombo("") + os.system("python cleanup.py") + os.system("pkill -f %s 2&> /dev/null" % app.lower()) + context.execute_steps(u"* Start %s via command" % app) + continue + + +@step(u'Start {app:w} via {type:w}') +def start_app_via_command(context, app, type): + for attempt in xrange(0, 10): + try: + if type == 'command': + context.app.startViaCommand() + if type == 'menu': + context.app.startViaMenu() + break + except GLib.GError: + sleep(1) + if attempt == 6: + # Killall the app processes if we reached 30 seconds wait + os.system("pkill -f %s 2&> /dev/null" % app.lower()) + continue + + +@step(u'Make sure that {app:w} is running') +def ensure_app_running(context, app): + start_app_via_command(context, app, 'menu') + wait_for_app_to_appear(context, app) + logging.debug("app = %s", root.application(app.lower())) + + +@then(u'{app:w} should start') +def test_app_started(context, app): + wait_for_app_to_appear(context, app) + + +@then(u"{app:w} shouldn't be running anymore") +def test_app_dead(context, app): + app = app.lower() + doDelay(3) + logging.debug("app = %s", app) + try: + context.app.instance = root.application(app) + logging.debug("root instance = %s", app) + context.app.instance.child(roleName='frame') + except (GLib.GError, SearchError): + # We SHOULD fail here, because app shouldn't be found + logging.debug("Exception fired!") + return True + else: + # Bad, app is still running + logging.debug("No exception!") + return False diff --git a/test/data/common_steps/dialogs.py b/test/data/common_steps/dialogs.py new file mode 100644 index 0000000..2679cf0 --- /dev/null +++ b/test/data/common_steps/dialogs.py @@ -0,0 +1,57 @@ +# -*- coding: UTF-8 -*- +from behave import step +from dogtail.rawinput import keyCombo +from dogtail.predicate import GenericPredicate +import pyatspi + + +@step(u'folder select dialog with name "{name}" is displayed') +def has_folder_select_dialog_with_name(context, name): + has_files_select_dialog_with_name(context, name) + + +@step(u'folder select dialog is displayed') +def has_folder_select_dialog(context): + context.execute_steps( + u'Then folder select dialog with name "Select Folder" is displayed') + + +@step(u'in folder select dialog I choose "{name}"') +def select_folder_in_dialog(context, name): + select_file_in_dialog(context, name) + + +@step(u'file select dialog with name "{name}" is displayed') +def has_files_select_dialog_with_name(context, name): + context.app.dialog = context.app.instance.child(name=name, roleName='file chooser') + + +@step(u'file select dialog is displayed') +def has_files_select_dialog(context): + context.execute_steps( + u'Then file select dialog with name "Select Files" is displayed') + + +@step(u'in file select dialog I select "{name}"') +def select_file_in_dialog(context, name): + # Find an appropriate button to click + # It will be either 'Home' or 'File System' + + home_folder = context.app.dialog.findChild(GenericPredicate(name='Home'), retry=False, requireResult=False) + if home_folder: + home_folder.click() + else: + context.app.dialog.childNamed('File System').click() + location_button = context.app.dialog.child('Type a file name') + if not pyatspi.STATE_ARMED in location_button.getState().getStates(): + location_button.click() + + context.app.dialog.childLabelled('Location:').set_text_contents(name) + context.app.dialog.childLabelled('Location:').grab_focus() + keyCombo('') + + +@step(u'in file save dialog I save file to "{path}" clicking "{button}"') +def file_save_to_path(context, path, button): + context.app.dialog.childLabelled('Name:').set_text_contents(path) + context.app.dialog.childNamed(button).click() diff --git a/test/data/common_steps/gmenu.py b/test/data/common_steps/gmenu.py new file mode 100644 index 0000000..250ea5f --- /dev/null +++ b/test/data/common_steps/gmenu.py @@ -0,0 +1,48 @@ +# -*- coding: UTF-8 -*- +import logging +logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', + level=logging.INFO) +from behave import step +from dogtail import tree +from dogtail.utils import doDelay +from dogtail.predicate import GenericPredicate + + +# GApplication menu steps +@step(u'I open GApplication menu') +def get_gmenu(context): + gs = tree.root.application('gnome-shell') + logging.debug("gs = %s", gs) + quit_element = gs.child(roleName='menu', label='Quit') + logging.debug("quit_element = %s", quit_element) + if not quit_element.showing: + gnome_menu = gs.child(roleName='menu') + logging.debug("gnome_menu = %s", gnome_menu) + gnome_menu.click() + doDelay(2) + return gs.child(roleName='menu', label='Quit').parent.parent.parent.\ + parent.parent + + +@step(u'I close GApplication menu') +def close_gmenu(context): + gs = tree.root.application('gnome-shell') + gs.child(roleName='menu').click() + doDelay(2) + + +@step(u'I click menu "{name}" in GApplication menu') +def click_gmenu(context, name): + logging.debug("context = %s", context) + gmenu = get_gmenu(context) + logging.debug("gmenu = %s", gmenu) + menu_item = gmenu.childLabelled(name) + logging.debug("menu_item = %s", menu_item) + menu_item.click() + doDelay(2) + + +@step(u'I get submenus from GApplication') +def get_submenus_from_gmenu(context, name): + return get_gmenu(context).childLabelled(name).parent.findChildren( + GenericPredicate(roleName='menu item')) diff --git a/test/data/common_steps/helpers.py b/test/data/common_steps/helpers.py new file mode 100644 index 0000000..e1cfd4b --- /dev/null +++ b/test/data/common_steps/helpers.py @@ -0,0 +1,591 @@ +#!/usr/bin/python +""" +Library for basic acceptance tests +Author: Martin Simon +Version: 2 (2012-04-13) +""" +import sys +import re +import os +import logging +from dogtail.tree import root, SearchError +from dogtail.rawinput import keyCombo, click, typeText, absoluteMotion +from dogtail.predicate import GenericPredicate +from subprocess import Popen, PIPE +from iniparse import ConfigParser +from time import sleep, time + +# Create a dummy unittest class to have nice assertions +import unittest + + +class dummy(unittest.TestCase): + def runTest(self): + assert True + + +def timeout(func, args=(), expected=True, equals=True, + timeout=30, period=0.25): + """This function waits until specified function returns required result""" + mustend = int(time()) + timeout + while int(time()) < mustend: + res = func.__call__(args) + if equals: + if res == expected: + return True + else: + if res != expected: + return True + sleep(period) + return False + + +def check_for_errors(context): + """Check that no error is displayed on Evolution UI""" + # Don't try to check for errors on dead app + if not context.app.instance or context.app.instance.dead: + return + alerts = context.app.instance.findChildren( + GenericPredicate(roleName='alert')) + if not alerts: + # alerts can also return None + return + alerts = filter(lambda x: x.showing, alerts) + if len(alerts) > 0: + labels = alerts[0].findChildren(GenericPredicate(roleName='label')) + messages = [x.name for x in labels] + + if alerts[0].name != 'Error' and alerts[0].showing: + # Erase the configuration and start all over again + #return Popen("pkill -u `whoami` -9 " + self.appCommand, + os.system("pkill -u `whoami` /*%s* &> /dev/null" % + context.app.appCommand) + sleep(3) + os.system("pkill -u `whoami` -9 /*%s* &> /dev/null" % + context.app.appCommand) + + # Remove previous data + for folder in context.app.clean_dirs: + os.system("rm -rf %s > /dev/null" % folder) + + raise RuntimeError("Error occurred: %s" % messages) + else: + print("Error occurred: %s" % messages) + + +def getMiniaturesPosition(name): + """Get a position of miniature on Overview""" + miniatures = [] + + over = root.application('gnome-shell').child(name='Overview') + mini = over.parent.children[-1] + if mini == over: + #print "Overview is not active" + return miniatures + widgets = mini.findChildren(GenericPredicate(name=name, roleName='label')) + + for widget in widgets: + (x, y) = widget.position + (a, b) = widget.size + miniatures.append((x + a / 2, y + b / 2 - 100)) + return miniatures + + +def getDashIconPosition(name): + """Get a position of icon on Overview dash""" + over = root.application('gnome-shell').child(name='Overview') + button = over[2].child(name=name) + (x, y) = button.position + (a, b) = button.size + return (x + a / 2, y + b / 2) + + +class App(): + """ + Does all basic events with app + """ + def __init__(self, appName, critical=None, shortcut='', + quitButton=None, timeout=10, forceKill=True, + parameters='', clean_dirs=None, polkit=False): + """ + Initialize object App + appName command to run the app + critical what's the function we check? {start,quit} + shortcut default quit shortcut + timeout timeout for starting and shuting down the app + forceKill is the app supposed to be kill before/after test? + parameters has the app any params needed to start? + (only for startViaCommand) + """ + self.appCommand = appName.lower() + self.shortcut = shortcut + self.timeout = timeout + self.forceKill = forceKill + self.critical = critical + self.quitButton = quitButton + # the result remains false until the correct result is verified + self.result = False + self.updateCorePattern() + self.parameters = parameters + self.internCommand = self.appCommand.lower() + self.polkit = polkit + self.polkitPass = 'redhat' + self.clean_dirs = clean_dirs or [] + + """ + Getting all necessary data from *.desktop file of the app + """ + cmd = "rpm -qlf $(which %s)" % appName + #cmd2 = "grep %s.desktop" % self.appCommand + #is it enough to search for .desktop?; vhumpa: no + cmd += '|grep "^/usr/share/applications/.*\%s.desktop$"' % appName + logging.debug("cmd = %s", cmd) + proc = Popen(cmd, shell=True, stdout=PIPE) + #have to check if the command and its desktop file exist + #raise Exception, "*.desktop file of the app not found" + #print("*.desktop file of the app not found") + output = proc.communicate()[0].rstrip() + logging.debug("output = %s", output) + self.desktopConfig = ConfigParser() + self.desktopConfig.read(output) + + def end(self): + """ + Ends the test with correct return value + """ + if self.result: + #print "PASS" + sys.exit(0) + else: + sys.exit("FAIL") + + def updateResult(self, result): + self.result = result + + def getName(self): + return self.desktopConfig.get('Desktop Entry', 'name') + + def getCategories(self): + return self.desktopConfig.get('Desktop Entry', 'categories') + + def getMenuGroups(self): + """ + Convert group list to the one correct menu group + """ + groupsList = self.getCategories().split(';') + groupsList.reverse() + groupConversionDict = { + 'Accessibility': 'Universal Access', + 'System': 'System Tools', + 'Development': 'Programming', + 'Network': 'Internet', + 'Office': 'Office', + 'Graphics': 'Graphics', + 'Game': 'Games', + 'Education': 'Education', + 'Utility': 'Accessories', + 'AudioVideo': 'Sound & Video' + } + + for i in groupsList: + if i in groupConversionDict: + return groupConversionDict[i] + + def isRunning(self): + """ + Is the app running? + """ + #print "*** Checking if '%s' is running" % self.internCommand + app = root + + apps = root.applications() + for i in apps: + if i.name.lower() == self.internCommand: + app = i + break + + if app.isChild(roleName='frame', recursive=False): + #print "*** The app '%s' is running" % self.internCommand + return True + else: + #print "*** The app '%s' is not running" % self.internCommand + return False + + def kill(self): + """ + Kill the app via 'killall' + """ + #print "*** Killing all '%s' instances" % self.appCommand + #return Popen("killall " + self.appCommand, shell = True).wait() + return Popen("pkill -u `whoami` -9 " + self.appCommand, + shell=True).wait() + + def updateCorePattern(self): + """ + Update string in /proc/sys/kernel/core_pattern to catch + possible return code + """ + #Popen("sudo rm -rf /tmp/cores", shell = True).wait() + #Popen("mkdir /tmp/cores", shell = True).wait() + #Popen("chmod a+rwx /tmp/cores", shell = True).wait() + #Popen("echo \"/tmp/cores/core.%e.%s.%p\" \ + # | sudo tee /proc/sys/kernel/core_pattern", shell = True).wait() + pass + + def existsCoreDump(self): + """ + Check if there is core dump created + """ + #dirPath = "/tmp/cores/" + #files = os.listdir(dirPath) + #regexp = "core\.%s\.[0-9]{1,3}\.[0-9]*" % self.appCommand + #for f in files: + # if re.match(regexp, f): + # return int(f.split(".")[2]) + return 0 + + def startViaMenu(self): + """ + Start the app via Gnome Shell menu + """ + internCritical = (self.critical == 'start') + + #check if the app is running + if self.forceKill and self.isRunning(): + self.kill() + sleep(2) + if self.isRunning(): + if internCritical: + self.updateResult(False) + #print "!!! The app is running but it shouldn't be" + return False + else: + #print "*** The app has been killed succesfully" + pass + + try: + #panel button Activities + gnomeShell = root.application('gnome-shell') + activities = gnomeShell.child(name='Activities', roleName='label') + activities.click() + sleep(6) # time for overview to appear + + #menu Applications + x, y = getDashIconPosition('Show Applications') + absoluteMotion(x, y) + sleep(1) + click(x, y) + sleep(4) # time for all the oversized app icons to appear + + #submenu that contains the app + submenu = gnomeShell.child(name=self.getMenuGroups(), + roleName='list item') + submenu.click() + sleep(4) + + #the app itself + app = gnomeShell.child(name=self.getName(), roleName='label') + app.click() + + #if there is a polkit + if self.polkit: + sleep(3) + typeText(self.polkitPass) + keyCombo('') + + sleep(self.timeout) + + if self.isRunning(): + #print "*** The app started successfully" + if internCritical: + self.updateResult(True) + return True + else: + #print "!!! The app is not running but it should be" + if internCritical: + self.updateResult(False) + return False + except SearchError: + #print "!!! Lookup error while passing the path" + if internCritical: + self.updateResult(False) + return False + + def startViaCommand(self): + """ + Start the app via command + """ + internCritical = (self.critical == 'start') + if self.forceKill and self.isRunning(): + self.kill() + sleep(2) + if self.isRunning(): + if internCritical: + self.updateResult(False) + #print "!!! The app is running but it shouldn't be" + return False + else: + pass + #print "*** The app has been killed succesfully" + + returnValue = 0 + command = "%s %s &" % (self.appCommand, self.parameters) + import os + os.system(command) + returnValue = 1 + #returnValue = utilsRun(command, timeout = 1, dumb = True) + + #if there is a polkit + if self.polkit: + sleep(3) + typeText(self.polkitPass) + keyCombo('') + + start_time = 0 + while start_time < self.timeout: + if self.isRunning(): + break + sleep(0.5) + start_time += 0.5 + + #check the returned values + if returnValue is None: + if internCritical: + self.updateResult(False) + #print "!!! The app command could not be found" + return False + else: + if self.isRunning(): + if internCritical: + self.updateResult(True) + #print "*** The app started successfully" + return True + else: + if internCritical: + self.updateResult(False) + #print "!!! The app did not started despite " \ + # + "the fact that the command was found" + return False + + def closeViaShortcut(self): + """ + Close the app via shortcut + """ + internCritical = (self.critical == 'quit') + + if not self.isRunning(): + if internCritical: + self.updateResult(False) + #print "!!! The app does not seem to be running" + return False + + keyCombo(self.shortcut) + sleep(self.timeout) + + if self.isRunning(): + if self.forceKill: + self.kill() + if internCritical: + self.updateResult(False) + #print "!!! The app is running but it shouldn't be" + return False + else: + if self.existsCoreDump() != 0: + if internCritical: + self.updateResult(False) + # print "!!! The app closed with core dump created. Signal %d"\ + # % self.existsCoreDump() + return False + if internCritical: + self.updateResult(True) + #print "*** The app was successfully closed" + return True + + def closeViaMenu(self): + """ + Close app via menu button + """ + internCritical = (self.critical == 'quit') + + if not self.isRunning(): + if internCritical: + self.updateResult(False) + #print "!!! The app does not seem to be running" + return False + + #bind to the right app + app = root + apps = root.applications() + for i in apps: + if i.name.lower() == self.internCommand: + app = i + break + app = app # variable app is not used FIXME + + #try to bind the menu and the button + try: + firstSubmenu = self.getMenuNth(0) + firstSubmenu.click() + length = len(firstSubmenu.children) + closeButton = firstSubmenu.children[length - 1] + if self.quitButton is None: + while re.search('(Close|Quit|Exit)', closeButton.name) is None: + length = length - 1 + closeButton = firstSubmenu.children[length] + if length < 0: + if internCritical: + self.update(False) + #print "!!! The app quit button coldn't be found" + return False + else: + closeButton = firstSubmenu.child(self.quitButton) + except SearchError: + if internCritical: + self.updateResult(False) + #print "!!! The app menu bar or the quit button could'n be found" + if self.forceKill: + self.kill() + return False + + sleep(2) # timeout until menu appear + #print "*** Trying to click to '%s'" % closeButton + closeButton.click() + sleep(self.timeout) + + if self.isRunning(): + if self.forceKill: + self.kill() + if internCritical: + self.updateResult(False) + #print "!!! The app is running but it shouldn't be" + return False + else: + if self.existsCoreDump() != 0: + if internCritical: + self.updateResult(False) + # print "!! The app closed with core dump created. Signal %d" \ + # % self.existsCoreDump() + return False + if internCritical: + self.updateResult(True) + #print "*** The app was successfully closed" + return True + + def getMenuNamed(self, menuName): + """ + Return submenu with name specified with 'menuName' + """ + #bind to the right app + app = root + apps = root.applications() + for i in apps: + if i.name.lower() == self.internCommand: + app = i + break + + #try to bind the menu and the button + try: + appMenu = app.child(roleName='menu bar') + return appMenu.child(name=menuName) + except: + return None + + def getMenuNth(self, nth): + """ + Return nth submenu + """ + #bind to the right app + app = root + apps = root.applications() + for i in apps: + if i.name.lower() == self.internCommand: + app = i + break + + #try to bind the menu and the button + try: + appMenu = app.child(roleName='menu bar') + return appMenu.children[nth] + except: + return None + + def getGnomePanelMenu(self): + """ + Return object of gnome-panel menu of the app + """ + try: + app = root.application('gnome-shell') + menu = app.child(roleName='menu') + return menu.child(self.getName(), roleName='label') + except: + raise Exception("Gnome-panel menu of the app could not be found!") + + def openGnomePanelMenu(self): + """ + Click to the gnome-panel menu + """ + menu = self.getGnomePanelMenu() + if menu is not None: + menu.click() + else: + raise Exception("Gnome-panel menu of the app could not be found!") + + def getGnomePanelMenuItems(self): + """ + Return a list of objects in gnome-panel app menu + """ + quitButton = self.getGnomePanelQuit() + if quitButton is None: + return [] + else: + return quitButton.get_parent().children + + def getGnomePanelQuit(self): + """ + Return object of Quit button in gnome-panel menu + It's the only way how to find out the gnome-panel menu... + """ + try: + return root.application('gnome-shell').child('Quit') + except: + raise Exception("Quit menu item at gnome-panel menu" + + " could not be found!") + + def closeViaGnomePanel(self): + """ + Close the app via menu at gnome-panel + """ + internCritical = (self.critical == 'quit') + + if not self.isRunning(): + if internCritical: + self.updateResult(False) + #print "!!! The app does not seem to be running" + return False + + self.openGnomePanelMenu() + closeButton = self.getGnomePanelQuit() + + sleep(2) # timeout until menu appear + #print "*** Trying to click to '%s'" % closeButton + closeButton.click() + sleep(self.timeout) + + if self.isRunning(): + if self.forceKill: + self.kill() + if internCritical: + self.updateResult(False) + #print "!!! The app is running but it shouldn't be" + return False + else: + if self.existsCoreDump() != 0: + if internCritical: + self.updateResult(False) + # print "!!! The app closed with core dumps. Signal %d" % \ + # self.existsCoreDump() + return False + if internCritical: + self.updateResult(True) + #print "*** The app was successfully closed" + return True diff --git a/test/data/features/steps/tutorial.py b/test/data/features/steps/tutorial.py new file mode 100644 index 0000000..94cb6d8 --- /dev/null +++ b/test/data/features/steps/tutorial.py @@ -0,0 +1,13 @@ +from behave import * + +@given('we have behave installed') +def step_impl(context): + pass + +@when('we implement a test') +def step_impl(context): + assert True is not False + +@then('behave will test it for us!') +def step_impl(context): + assert context.failed is False diff --git a/test/data/features/tutorial.feature b/test/data/features/tutorial.feature new file mode 100644 index 0000000..cd8c621 --- /dev/null +++ b/test/data/features/tutorial.feature @@ -0,0 +1,6 @@ +Feature: showing off behave + + Scenario: run a simple test + Given we have behave installed + when we implement a test + then behave will test it for us! diff --git a/test/test_cucutags.py b/test/test_cucutags.py index 7ae82ec..aad673f 100644 --- a/test/test_cucutags.py +++ b/test/test_cucutags.py @@ -22,7 +22,10 @@ class TestCucutags(unittest.TestCase): """Generate tags and compare with expected result.""" tags = [tuple(x[1:]) for x in self.session.generate_tags(self.datadir)] - expected = [(u'common_steps/app.py', 59), + expected = [(u'features/steps/tutorial.py', 3), + (u'features/steps/tutorial.py', 7), + (u'features/steps/tutorial.py', 11), + (u'common_steps/app.py', 59), (u'common_steps/gmenu.py', 12), (u'common_steps/gmenu.py', 34), (u'common_steps/app.py', 59), -- cgit