aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatěj Cepl <mcepl@redhat.com>2014-06-23 14:56:22 +0200
committerMatěj Cepl <mcepl@redhat.com>2014-06-23 15:19:41 +0200
commit5cde8f20dc328706651db6be8502dcb0f910e221 (patch)
tree32982101571b4e9e231c30008c9999571a8b52e1
parentc7a0434ba4ce0e83bc179221cd2d5fd583f4bd8b (diff)
downloadcucutags-5cde8f20dc328706651db6be8502dcb0f910e221.tar.gz
The string in the step decoration doesn’t have to be Unicode.0.7.0
Fixes #1 on gitorious.
-rw-r--r--MANIFEST.in2
-rw-r--r--README11
-rwxr-xr-xcucutags.py9
m---------test/data/common_steps0
-rw-r--r--test/data/common_steps/.gitignore2
-rw-r--r--test/data/common_steps/__init__.py0
-rw-r--r--test/data/common_steps/app.py87
-rw-r--r--test/data/common_steps/dialogs.py57
-rw-r--r--test/data/common_steps/gmenu.py48
-rw-r--r--test/data/common_steps/helpers.py591
-rw-r--r--test/data/features/steps/tutorial.py13
-rw-r--r--test/data/features/tutorial.feature6
-rw-r--r--test/test_cucutags.py5
13 files changed, 822 insertions, 9 deletions
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 <mcepl_at_redhat_dot_com>"
@@ -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
-Subproject d56c6197dfe923afc39e8795bf8e1b1d5a98403
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
--- /dev/null
+++ b/test/data/common_steps/__init__.py
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("<Enter>")
+ 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('<Enter>')
+
+
+@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 <msimon@redhat.com>
+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='<Control><Q>',
+ 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 &amp; 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('<Enter>')
+
+ 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('<Enter>')
+
+ 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),