diff --git a/.gitignore b/.gitignore index 1e5cd33..08b92b7 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ evolution-2.31.5.tar.bz2 /evolution-3.12.3.tar.xz /evolution-3.12.4.tar.xz /evolution-3.13.4.tar.xz +/evolution-3.13.5.tar.xz diff --git a/evolution-3.13.4-missing-tests.patch b/evolution-3.13.4-missing-tests.patch deleted file mode 100644 index cab4f03..0000000 --- a/evolution-3.13.4-missing-tests.patch +++ /dev/null @@ -1,1282 +0,0 @@ -diff -up evolution-3.13.4/tests/addressbook.feature.missing-tests evolution-3.13.4/tests/addressbook.feature ---- evolution-3.13.4/tests/addressbook.feature.missing-tests 2014-07-30 11:21:47.031172903 +0200 -+++ evolution-3.13.4/tests/addressbook.feature 2014-07-30 11:21:47.031172903 +0200 -@@ -0,0 +1,101 @@ -+Feature: Addressbook: File: Create contacts -+ -+ Background: -+ * Open Evolution and setup fake account -+ * Open "Contacts" section -+ * Select "Personal" addressbook -+ * Change categories view to "Any Category" -+ * Delete all contacts containing "Doe" -+ -+ @addressbook_contacts -+ Scenario: Create a simple contact -+ * Create a new contact -+ * Set "Full Name..." in contact editor to "John Doe" -+ * Save the contact -+ * Refresh addressbook -+ * Select "Doe, John" contact -+ * Open contact editor for selected contact -+ Then "Full Name..." property is set to "John Doe" -+ -+ @addressbook_contacts -+ Scenario: Create a new contact with data -+ * Create a new contact -+ * Set "Full Name..." in contact editor to "Jimmy Doe" -+ * Set "Nickname:" in contact editor to "Unknown" -+ * Set emails in contact editor to -+ | Field | Value | -+ | Work Email | jimmy.doe@company.com | -+ | Home Email | jimmy_doe_72@gmail.com | -+ | Other Email | jimmydoe72@yahoo.com | -+ | Other Email | xxjimmyxx@free_email.com | -+ * Tick "Wants to receive HTML mail" checkbox -+ * Set phones in contact editor to -+ | Field | Value | -+ | Assistant Phone | 123 | -+ | Business Phone | 234 | -+ | Business Fax | 345 | -+ | Callback Phone | 456 | -+ | Car Phone | 567 | -+ | Company Phone | 678 | -+ | Home Phone | 789 | -+ | Home Fax | 890 | -+ | ISDN | 123 | -+ | Mobile Phone | 234 | -+ | Other Phone | 345 | -+ | Other Fax | 456 | -+ | Pager | 567 | -+ | Primary Phone | 678 | -+ | Radio | 789 | -+ | Telex | 890 | -+ * Set IMs in contact editor to -+ | Field | Value | -+ | AIM | 123 | -+ | Jabber | 234 | -+ | Yahoo | 345 | -+ | Gadu-Gadu | 456 | -+ | MSN | 123 | -+ | ICQ | 234 | -+ | GroupWise | 345 | -+ | Skype | jimmy.doe | -+ | Twitter | @jimmydoe | -+ * Save the contact -+ * Refresh addressbook -+ * Select "Doe, Jimmy" contact -+ * Open contact editor for selected contact -+ Then "Nickname:" property is set to "Unknown" -+ And Emails are set to -+ | Field | Value | -+ | Work Email | jimmy.doe@company.com | -+ | Home Email | jimmy_doe_72@gmail.com | -+ | Other Email | jimmydoe72@yahoo.com | -+ | Other Email | xxjimmyxx@free_email.com | -+ And "Wants to receive HTML mail" checkbox is ticked -+ And Phones are set to -+ | Field | Value | -+ | Assistant Phone | 123 | -+ | Business Phone | 234 | -+ | Business Fax | 345 | -+ | Callback Phone | 456 | -+ | Car Phone | 567 | -+ | Company Phone | 678 | -+ | Home Phone | 789 | -+ | Home Fax | 890 | -+ | ISDN | 123 | -+ | Mobile Phone | 234 | -+ | Other Phone | 345 | -+ | Other Fax | 456 | -+ | Pager | 567 | -+ | Primary Phone | 678 | -+ | Radio | 789 | -+ | Telex | 890 | -+ And IMs are set to -+ | Field | Value | -+ | AIM | 123 | -+ | Jabber | 234 | -+ | Yahoo | 345 | -+ | Gadu-Gadu | 456 | -+ | MSN | 123 | -+ | ICQ | 234 | -+ | GroupWise | 345 | -+ | Skype | jimmy.doe | -+ | Twitter | @jimmydoe | -diff -up evolution-3.13.4/tests/common_steps.py.missing-tests evolution-3.13.4/tests/common_steps.py ---- evolution-3.13.4/tests/common_steps.py.missing-tests 2014-07-30 11:21:47.031172903 +0200 -+++ evolution-3.13.4/tests/common_steps.py 2014-07-30 11:21:47.031172903 +0200 -@@ -0,0 +1,238 @@ -+# -*- coding: UTF-8 -*- -+from dogtail.utils import isA11yEnabled, enableA11y -+if isA11yEnabled() is False: -+ enableA11y(True) -+ -+from time import time, sleep -+from functools import wraps -+from os import strerror, errno, system -+from signal import signal, alarm, SIGALRM -+from subprocess import Popen, PIPE -+from behave import step -+from gi.repository import GLib, Gio -+import fcntl, os -+ -+from dogtail.rawinput import keyCombo, absoluteMotion, pressKey -+from dogtail.tree import root -+from unittest import TestCase -+ -+ -+# Create a dummy unittest class to have nice assertions -+class dummy(TestCase): -+ def runTest(self): # pylint: disable=R0201 -+ assert True -+ -+ -+def wait_until(my_lambda, element, timeout=30, period=0.25): -+ """ -+ This function keeps running lambda with specified params until the result is True -+ or timeout is reached -+ Sample usages: -+ * wait_until(lambda x: x.name != 'Loading...', context.app) -+ Pause until window title is not 'Loading...'. -+ Return False if window title is still 'Loading...' -+ Throw an exception if window doesn't exist after default timeout -+ -+ * wait_until(lambda element, expected: x.text == expected, element, ('Expected text')) -+ Wait until element text becomes the expected (passed to the lambda) -+ -+ """ -+ exception_thrown = None -+ mustend = int(time()) + timeout -+ while int(time()) < mustend: -+ try: -+ if my_lambda(element): -+ return True -+ except Exception as e: -+ # If lambda has thrown the exception we'll re-raise it later -+ # and forget about if lambda passes -+ exception_thrown = e -+ sleep(period) -+ if exception_thrown: -+ raise exception_thrown -+ else: -+ return False -+ -+ -+class TimeoutError(Exception): -+ """ -+ Timeout exception class for limit_execution_time_to function -+ """ -+ pass -+ -+ -+def limit_execution_time_to( -+ seconds=10, error_message=strerror(errno.ETIME)): -+ """ -+ Decorator to limit function execution to specified limit -+ """ -+ def decorator(func): -+ def _handle_timeout(signum, frame): -+ raise TimeoutError(error_message) -+ -+ def wrapper(*args, **kwargs): -+ signal(SIGALRM, _handle_timeout) -+ alarm(seconds) -+ try: -+ result = func(*args, **kwargs) -+ finally: -+ alarm(0) -+ return result -+ -+ return wraps(func)(wrapper) -+ -+ return decorator -+ -+ -+class App(object): -+ """ -+ This class does all basic events with the app -+ """ -+ def __init__( -+ self, appName, shortcut='', a11yAppName=None, -+ forceKill=True, parameters='', recordVideo=False): -+ """ -+ Initialize object App -+ appName command to run the app -+ shortcut default quit shortcut -+ a11yAppName app's a11y name is different than binary -+ forceKill is the app supposed to be kill before/after test? -+ parameters has the app any params needed to start? (only for startViaCommand) -+ recordVideo start gnome-shell recording while running the app -+ """ -+ self.appCommand = appName -+ self.shortcut = shortcut -+ self.forceKill = forceKill -+ self.parameters = parameters -+ self.internCommand = self.appCommand.lower() -+ self.a11yAppName = a11yAppName -+ self.recordVideo = recordVideo -+ self.pid = None -+ -+ # a way of overcoming overview autospawn when mouse in 1,1 from start -+ pressKey('Esc') -+ absoluteMotion(100, 100, 2) -+ -+ # attempt to make a recording of the test -+ if self.recordVideo: -+ keyCombo('R') -+ -+ def isRunning(self): -+ """ -+ Is the app running? -+ """ -+ if self.a11yAppName is None: -+ self.a11yAppName = self.internCommand -+ -+ # Trap weird bus errors -+ for attempt in xrange(0, 30): -+ sleep(1) -+ try: -+ return self.a11yAppName in [x.name for x in root.applications()] -+ except GLib.GError: -+ continue -+ raise Exception("10 at-spi errors, seems that bus is blocked") -+ -+ def kill(self): -+ """ -+ Kill the app via 'killall' -+ """ -+ if self.recordVideo: -+ keyCombo('R') -+ -+ try: -+ self.process.kill() -+ except: -+ # Fall back to killall -+ Popen("killall " + self.appCommand, shell=True).wait() -+ -+ def startViaCommand(self): -+ """ -+ Start the app via command -+ """ -+ if self.forceKill and self.isRunning(): -+ self.kill() -+ assert not self.isRunning(), "Application cannot be stopped" -+ -+ #command = "%s %s" % (self.appCommand, self.parameters) -+ #self.pid = run(command, timeout=5) -+ self.process = Popen(self.appCommand.split() + self.parameters.split(), -+ stdout=PIPE, stderr=PIPE, bufsize=0) -+ self.pid = self.process.pid -+ -+ assert self.isRunning(), "Application failed to start" -+ return root.application(self.a11yAppName) -+ -+ def closeViaShortcut(self): -+ """ -+ Close the app via shortcut -+ """ -+ if not self.isRunning(): -+ raise Exception("App is not running") -+ -+ keyCombo(self.shortcut) -+ assert not self.isRunning(), "Application cannot be stopped" -+ -+ -+@step(u'Start a new Evolution instance') -+def start_new_evolution_instance(context): -+ context.app = context.app_class.startViaCommand() -+ -+ -+def cleanup(): -+ # Remove cached data and settings -+ folders = ['~/.local/share/evolution', '~/.cache/evolution', '~/.config/evolution'] -+ for folder in folders: -+ system("rm -rf %s > /dev/null" % folder) -+ -+ # Clean up goa data -+ system("rm -rf ~/.config/goa-1.0/accounts.conf") -+ system("killall goa-daemon 2&> /dev/null") -+ -+ # Reset GSettings -+ schemas = [x for x in Gio.Settings.list_schemas() if 'evolution' in x.lower()] -+ for schema in schemas: -+ system("gsettings reset-recursively %s" % schema) -+ -+ # Skip warning dialog -+ system("gsettings set org.gnome.evolution.shell skip-warning-dialog true") -+ # Show switcher buttons as icons (to minimize tree scrolling) -+ system("gsettings set org.gnome.evolution.shell buttons-style icons") -+ # Skip default mailer handler dialog -+ system("gsettings set org.gnome.evolution.mail prompt-check-if-default-mailer 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 or context.app.dead: -+ return -+ alerts = context.app.findChildren(lambda x: x.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(lambda x: x.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 -+ system("evolution --force-shutdown &> /dev/null") -+ -+ # Remove previous data -+ folders = ['~/.local/share/evolution', '~/.cache/evolution', '~/.config/evolution'] -+ for folder in folders: -+ system("rm -rf %s > /dev/null" % folder) -+ -+ raise RuntimeError("Error occurred: %s" % messages) -+ -+ -+def non_block_read(output): -+ fd = output.fileno() -+ fl = fcntl.fcntl(fd, fcntl.F_GETFL) -+ fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) -+ try: -+ return output.read() -+ except: -+ return "" -diff -up evolution-3.13.4/tests/environment.py.missing-tests evolution-3.13.4/tests/environment.py ---- evolution-3.13.4/tests/environment.py.missing-tests 2014-07-30 11:21:47.031172903 +0200 -+++ evolution-3.13.4/tests/environment.py 2014-07-30 11:21:47.031172903 +0200 -@@ -0,0 +1,82 @@ -+# -*- coding: UTF-8 -*- -+ -+from time import sleep, localtime, strftime -+from dogtail.utils import isA11yEnabled, enableA11y -+if not isA11yEnabled(): -+ enableA11y(True) -+ -+from common_steps import App, dummy, cleanup, non_block_read -+from dogtail.config import config -+import os -+ -+ -+def before_all(context): -+ """Setup evolution stuff -+ Being executed once before any test -+ """ -+ -+ try: -+ # Close running evo instances -+ os.system("evolution --force-shutdown > /dev/null") -+ -+ # Skip dogtail actions to print to stdout -+ config.logDebugToStdOut = False -+ config.typingDelay = 0.2 -+ -+ # Include assertion object -+ context.assertion = dummy() -+ -+ # Cleanup existing data before any test -+ cleanup() -+ -+ # Store scenario start time for session logs -+ context.log_start_time = strftime("%Y-%m-%d %H:%M:%S", localtime()) -+ -+ context.app_class = App('evolution') -+ -+ except Exception as e: -+ print("Error in before_all: %s" % e.message) -+ -+ -+def after_step(context, step): -+ try: -+ if step.status == 'failed' and hasattr(context, "embed"): -+ # Embed screenshot if HTML report is used -+ os.system("dbus-send --print-reply --session --type=method_call " + -+ "--dest='org.gnome.Shell.Screenshot' " + -+ "'/org/gnome/Shell/Screenshot' " + -+ "org.gnome.Shell.Screenshot.Screenshot " + -+ "boolean:true boolean:false string:/tmp/screenshot.png") -+ context.embed('image/png', open("/tmp/screenshot.png", 'r').read()) -+ except Exception as e: -+ print("Error in after_step: %s" % str(e)) -+ -+ -+def after_scenario(context, scenario): -+ """Teardown for each scenario -+ Kill evolution (in order to make this reliable we send sigkill) -+ """ -+ try: -+ # Attach journalctl logs -+ if hasattr(context, "embed"): -+ os.system("journalctl /usr/bin/gnome-session --no-pager -o cat --since='%s'> /tmp/journal-session.log" % context.log_start_time) -+ data = open("/tmp/journal-session.log", 'r').read() -+ if data: -+ context.embed('text/plain', data) -+ -+ context.app_class.kill() -+ -+ stdout = non_block_read(context.app_class.process.stdout) -+ stderr = non_block_read(context.app_class.process.stderr) -+ -+ if stdout: -+ context.embed('text/plain', stdout) -+ -+ if stderr: -+ context.embed('text/plain', stderr) -+ -+ # Make some pause after scenario -+ sleep(1) -+ except Exception as e: -+ # Stupid behave simply crashes in case exception has occurred -+ print("Error in after_scenario: %s" % e.message) -diff -up evolution-3.13.4/tests/shortcuts.feature.missing-tests evolution-3.13.4/tests/shortcuts.feature ---- evolution-3.13.4/tests/shortcuts.feature.missing-tests 2014-07-30 11:21:47.032172902 +0200 -+++ evolution-3.13.4/tests/shortcuts.feature 2014-07-30 11:21:47.031172903 +0200 -@@ -0,0 +1,135 @@ -+Feature: Shortcuts -+ -+ Background: -+ * Open Evolution and setup fake account -+ -+ @general_shortcuts -+ Scenario: Ctrl-Q to quit application - two instances -+ * Start a new Evolution instance -+ * Press "Q" -+ Then Evolution is closed -+ -+ @general_shortcuts -+ Scenario: F1 to launch help -+ * Press "" -+ Then Help section "Evolution Mail and Calendar" is displayed -+ -+ @general_shortcuts -+ Scenario: Shift-Ctrl-W to open a new window -+ * Press "W" -+ Then Evolution has 2 windows opened -+ -+ @general_shortcuts -+ Scenario: Ctrl-W to close a window -+ * Press "W" -+ * Press "W" -+ Then Evolution has 1 window opened -+ -+ @general_shortcuts -+ Scenario: Ctrl-Shift-S to open Preferences -+ * Press "S" -+ Then Preferences dialog is opened -+ -+ @mail_shortcuts -+ Scenario: Mail: Ctrl-Shift-M to compose new message -+ * Open "Mail" section -+ * Press "M" -+ Then Message composer with title "Compose Message" is opened -+ -+ @contacts_shortcuts -+ Scenario: Contacts: Ctrl-Shift-C to create new contact -+ * Open "Contacts" section -+ * Press "C" -+ Then Contact editor window is opened -+ -+ @contacts_shortcuts -+ Scenario: Contacts: Ctrl-Shift-L to create new contact list -+ * Open "Contacts" section -+ * Press "L" -+ Then Contact List editor window is opened -+ -+ @calendar_shortcuts -+ Scenario: Calendar: Ctrl-Shift-A to create new appointment -+ * Open "Calendar" section -+ * Press "A" -+ Then Event editor with title "Appointment - No Summary" is displayed -+ -+ @calendar_shortcuts -+ Scenario: Calendar: Ctrl-Shift-E to create new meeting -+ * Open "Calendar" section -+ * Press "E" -+ Then Event editor with title "Meeting - No Summary" is displayed -+ -+ @calendar_shortcuts -+ Scenario: Tasks: Ctrl-Shift-T to create new task -+ * Open "Tasks" section -+ * Press "T" -+ Then Task editor with title "Task - No Summary" is opened -+ -+ @memos_shortcuts -+ Scenario: Memos: Ctrl-Shift-O to create new memo -+ * Open "Memos" section -+ * Press "O" -+ Then Memo editor with title "Memo - No Summary" is opened -+ -+ @memos_shortcuts -+ Scenario: Memos: Ctrl-Shift-O to create new task -+ * Open "Memos" section -+ * Press "O" -+ Then Shared memo editor with title "Memo - No Summary" is opened -+ -+ @view_shortcuts -+ Scenario Outline: Ctrl+<1-5> to switch views -+ * Press "" -+ Then "
" view is opened -+ -+ Examples: -+ | shortcut | section | -+ | 1 | Mail | -+ | 2 | Contacts | -+ | 3 | Calendar | -+ | 4 | Tasks | -+ | 5 | Memos | -+ -+ @menu_shortcuts -+ Scenario Outline: Menu shortcuts on all views -+ * Open "
" section -+ * Press "" -+ Then "" menu is opened -+ -+ Examples: -+ | section | shortcut | menu | -+ | Mail | F | File | -+ | Mail | E | Edit | -+ | Mail | V | View | -+ | Mail | O | Folder | -+ | Mail | M | Message | -+ | Mail | S | Search | -+ | Mail | H | Help | -+ -+ | Contacts | F | File | -+ | Contacts | E | Edit | -+ | Contacts | V | View | -+ | Contacts | A | Actions | -+ | Contacts | S | Search | -+ | Contacts | H | Help | -+ -+ | Calendar | F | File | -+ | Calendar | E | Edit | -+ | Calendar | V | View | -+ | Calendar | A | Actions | -+ | Calendar | S | Search | -+ | Calendar | H | Help | -+ -+ | Tasks | F | File | -+ | Tasks | E | Edit | -+ | Tasks | V | View | -+ | Tasks | A | Actions | -+ | Tasks | S | Search | -+ | Tasks | H | Help | -+ -+ | Memos | F | File | -+ | Memos | E | Edit | -+ | Memos | V | View | -+ | Memos | S | Search | -+ | Memos | H | Help | -diff -up evolution-3.13.4/tests/steps/addressbook_steps.py.missing-tests evolution-3.13.4/tests/steps/addressbook_steps.py ---- evolution-3.13.4/tests/steps/addressbook_steps.py.missing-tests 2014-07-30 11:21:47.032172902 +0200 -+++ evolution-3.13.4/tests/steps/addressbook_steps.py 2014-07-30 11:21:47.032172902 +0200 -@@ -0,0 +1,391 @@ -+# -*- coding: UTF-8 -*- -+from behave import step, then -+from common_steps import wait_until -+from dogtail.predicate import GenericPredicate -+from dogtail.rawinput import keyCombo -+from time import time, sleep -+from gi.repository import GLib -+import pyatspi -+ -+ -+@step(u'Select "{name}" addressbook') -+def select_addressbook(context, name, password=None): -+ cells = context.app.findChildren( -+ GenericPredicate(name=name, roleName='table cell')) -+ visible_cells = filter(lambda x: x.showing, cells) -+ if visible_cells == []: -+ raise RuntimeError("Cannot find addressbook '%s'" % name) -+ visible_cells[0].click() -+ # Wait for addressbook to load -+ try: -+ spinner = context.app.findChild( -+ GenericPredicate(name='Spinner'), retry=False, requireResult=False) -+ if spinner: -+ start_time = time() -+ while spinner.showing: -+ sleep(1) -+ if (time() - start_time) > 180: -+ raise RuntimeError("Contacts take too long to synchronize") -+ except (GLib.GError, TypeError): -+ pass -+ -+ -+@step(u'Change categories view to "{category}"') -+def change_categories_view(context, category): -+ labels = context.app.findChildren( -+ lambda x: x.labeller.name == 'Show:' and x.showing) -+ if labels == []: -+ raise RuntimeError("Cannot find category switcher") -+ labels[0].combovalue = category -+ -+ -+@step(u'Delete selected contact') -+def delete_selected_contact(context): -+ context.app.menu('Edit').click() -+ mnu = context.app.menu('Edit').menuItem("Delete Contact") -+ if pyatspi.STATE_ENABLED in mnu.getState().getStates(): -+ context.app.menu('Edit').menuItem("Delete Contact").click() -+ -+ alert = context.app.child(roleName='alert', name='Question') -+ alert.button('Delete').click() -+ context.execute_steps(u"* Wait for email to synchronize") -+ -+ -+@step(u'Delete all contacts containing "{part}"') -+def delete_all_contacts_containing(context, part): -+ context.app.search_bar.grab_focus() -+ for attempts in range(0, 10): -+ try: -+ context.app.search_bar.text = part -+ break -+ except (GLib.GError, AttributeError): -+ sleep(0.1) -+ continue -+ keyCombo("") -+ context.execute_steps(u"* Wait for email to synchronize") -+ context.app.search_bar.grab_focus() -+ keyCombo("") -+ sleep(3) -+ heading = context.app.findChild( -+ GenericPredicate(roleName='heading'), -+ retry=False, requireResult=False) -+ if heading: -+ keyCombo("a") -+ context.execute_steps(u"* Delete selected contact") -+ sleep(3) -+ -+ -+@step(u'Create a new contact') -+def create_a_new_contact(context): -+ context.app.menu('File').click() -+ context.app.menu('File').menu('New').point() -+ context.app.menu('File').menu('New').menuItem("Contact").click() -+ context.execute_steps(u"Then Contact editor window is opened") -+ -+ -+def get_element_by_name(contact_editor, name, section=None): -+ """Get a field object by name in section (if specified)""" -+ element = None -+ if section: -+ panel = contact_editor.findChild( -+ GenericPredicate(roleName='panel', name=section), retry=False, requireResult=False) -+ if not panel: -+ # Other section is not a panel, but a toggle button -+ panel = contact_editor.child(roleName='toggle button', name=section) -+ element = panel.childLabelled(name) -+ else: -+ label = contact_editor.findChild( -+ GenericPredicate(label=name), retry=False, requireResult=False) -+ if not label: -+ # In case childLabelled is missing -+ # Find a filler with this name and get its text child -+ element = contact_editor.child( -+ roleName='filler', name=name).child(roleName='text') -+ else: -+ element = contact_editor.childLabelled(name) -+ if element: -+ return element -+ else: -+ raise RuntimeError("Cannot find element named '%s' in section '%s'" % ( -+ name, section)) -+ -+ -+@step(u'Set "{field_name}" in contact editor to "{field_value}"') -+def set_field_to_value(context, field_name, field_value): -+ element = get_element_by_name(context.app.contact_editor, field_name) -+ if element.roleName == "text": -+ element.text = field_value -+ elif element.roleName == "combo box": -+ if element.combovalue != field_value: -+ element.combovalue = field_value -+ -+ -+@step(u'Save the contact') -+def save_contact(context): -+ context.app.contact_editor.button('Save').click() -+ assert wait_until(lambda x: not x.showing, context.app.contact_editor),\ -+ "Contact Editor was not hidden" -+ assert wait_until(lambda x: x.dead, context.app.contact_editor),\ -+ "Contact Editor was not closed" -+ context.app.contact_editor = None -+ -+ -+@step(u'Refresh addressbook') -+def refresh_addressbook(context): -+ #Clear the search -+ icons = context.app.search_bar.findChildren(lambda x: x.roleName == 'icon') -+ if icons != []: -+ icons[-1].click() -+ else: -+ for attempts in range(0, 10): -+ try: -+ context.app.search_bar.text = '' -+ break -+ except (GLib.GError, AttributeError): -+ sleep(0.1) -+ continue -+ context.app.search_bar.grab_focus() -+ keyCombo('') -+ context.execute_steps(u"* Wait for email to synchronize") -+ -+ -+@step(u'Select "{contact_name}" contact list') -+@step(u'Select "{contact_name}" contact') -+def select_contact_with_name(context, contact_name): -+ # heading shows the name of currently selected contact -+ # We have to keep on pressing Tab to select the next contact -+ # Until we meet the first contact -+ # WARNING - what if we will have two identical contacts? -+ fail = False -+ selected_contact = None -+ -+ # HACK -+ # To make the contact table appear -+ # we need to focus on search window -+ # and send Tabs to have the first contact focused -+ context.app.search_bar.grab_focus() -+ sleep(0.1) -+ # Switch to 'Any field contains' (not reachable in 3.6) -+ icons = context.app.search_bar.findChildren(GenericPredicate(roleName='icon')) -+ -+ if icons != []: -+ icons[0].click() -+ wait_until(lambda x: x.findChildren( -+ GenericPredicate(roleName='check menu item', name='Any field contains')) != [], -+ context.app) -+ context.app.menuItem('Any field contains').click() -+ for attempts in range(0, 10): -+ try: -+ context.app.search_bar.text = contact_name -+ break -+ except (GLib.GError, AttributeError): -+ sleep(0.1) -+ continue -+ keyCombo("") -+ context.app.search_bar.grab_focus() -+ -+ keyCombo("") -+ first_contact_name = context.app.child(roleName='heading').text -+ -+ while True: -+ selected_contact = context.app.child(roleName='heading') -+ if selected_contact.text == contact_name: -+ fail = False -+ break -+ keyCombo("") -+ # Wait until contact data is being rendered -+ sleep(1) -+ if first_contact_name == selected_contact.text: -+ fail = True -+ break -+ -+ context.assertion.assertFalse( -+ fail, "Can't find contact named '%s'" % contact_name) -+ context.selected_contact_text = selected_contact.text -+ -+ -+@step(u'Open contact editor for selected contact') -+def open_contact_editor_for_selected_contact(context): -+ context.app.menu('File').click() -+ context.app.menu('File').menuItem('Open Contact').click() -+ context.execute_steps(u""" -+ Then Contact editor window with title "Contact Editor - %s" is opened -+ """ % context.selected_contact_text) -+ -+ -+@then(u'"{field}" property is set to "{expected}"') -+def property_in_contact_window_is_set_to(context, field, expected): -+ element = get_element_by_name(context.app.contact_editor, field) -+ actual = None -+ if element.roleName == "text": -+ actual = element.text -+ elif element.roleName == "combo box": -+ actual = element.combovalue -+ if actual == '': -+ actual = element.textentry('').text -+ assert unicode(actual) == expected, "Incorrect value" -+ -+ -+def get_combobox_textbox_object(contact_editor, section, scroll_to_bottom=True): -+ """Get a list of paired 'combobox-textbox' objects in contact editor""" -+ section_names = { -+ 'Ims': 'Instant Messaging', -+ 'Phones': 'Telephone', -+ 'Emails': 'Email'} -+ section = section_names[section.capitalize()] -+ lbl = contact_editor.child(roleName='label', name=section) -+ panel = lbl.findAncestor(GenericPredicate(roleName='panel')) -+ textboxes = panel.findChildren(GenericPredicate(roleName='text')) -+ -+ # Scroll to the bottom of the page if needed -+ pagetab = panel.findAncestor(GenericPredicate(roleName='page tab')) -+ for scroll in pagetab.findChildren(lambda x: x.roleName == 'scroll bar'): -+ if scroll_to_bottom: -+ scroll.value = scroll.maxValue -+ else: -+ scroll.value = 0 -+ -+ # Expand section if button exists -+ button = panel.findChild( -+ GenericPredicate(roleName='push button', name=section), -+ retry=False, requireResult=False) -+ # Expand button if any of textboxes is not visible -+ if button and (False in [x.showing for x in textboxes]): -+ button.click() -+ -+ comboboxes = panel.findChildren(GenericPredicate(roleName='combo box')) -+ -+ # Rearrange comboboxes and textboxes according to their position -+ result = [] -+ for combo in comboboxes: -+ combo_row = combo.position[1] -+ matching_textboxes = [ -+ x for x in textboxes -+ if ((x.position[1] - combo_row) == 0) and (x.position[0] > combo.position[0])] -+ if (matching_textboxes != []): -+ correct_textbox = min(matching_textboxes, key=lambda x: x.position[0]) -+ result.append((combo, correct_textbox)) -+ -+ comboboxes = [x[0] for x in result][::-1] -+ textboxes = [x[1] for x in result][::-1] -+ -+ return (textboxes, comboboxes, button) -+ -+ -+@step(u'Set {section} in contact editor to') -+def set_contact_emails_to_value(context, section): -+ (textboxes, comboboxes, collapse_button) = get_combobox_textbox_object( -+ context.app.contact_editor, section) -+ -+ # clear existing data -+ for textbox in textboxes: -+ textbox.text = "" -+ -+ for index, row in enumerate(context.table.rows): -+ # Check that we have sufficient amount of textboxes -+ # If not - click plus buttons until we have enough -+ if index == len(textboxes): -+ textboxes[0].parent.child(roleName="push button").click() -+ (textboxes, comboboxes, collapse_button) = get_combobox_textbox_object( -+ context.app.contact_editor, section) -+ textboxes[index].text = row['Value'] -+ if comboboxes[index].combovalue != row['Field']: -+ comboboxes[index].combovalue = row['Field'] -+ -+ -+@then(u'{section} are set to') -+def emails_are_set_to(context, section): -+ (textboxes, comboboxes, collapse_button) = get_combobox_textbox_object( -+ context.app.contact_editor, section, section == 'IMs') -+ -+ actual = [] -+ for index, textbox in enumerate(textboxes): -+ combo_value = textbox.text -+ if combo_value.strip() != '': -+ type_value = comboboxes[index].combovalue -+ actual.append({'Field': unicode(type_value), 'Value': unicode(combo_value)}) -+ actual = sorted(actual) -+ -+ expected = [] -+ for row in context.table: -+ expected.append({'Field': row['Field'], 'Value': row['Value']}) -+ expected = sorted(expected) -+ -+ assert actual == expected, "Incorrect %s value:\nexpected:%s\n but was:%s" % ( -+ row['Field'], expected, actual) -+ -+ # Collapse the section after check -+ collapse_button.click() -+ -+ -+@step(u'Tick "Wants to receive HTML mail" checkbox') -+def tick_checkbox(context): -+ context.app.contact_editor.childNamed("Wants to receive HTML mail").click() -+ -+ -+@step(u'"Wants to receive HTML mail" checkbox is ticked') -+def checkbox_is_ticked(context): -+ check_state = context.app.childNamed("Wants to receive HTML mail").checked -+ assert check_state, "Incorrect checkbox state" -+ -+ -+@step(u'Switch to "{name}" tab in contact editor') -+def switch_to_tab(context, name): -+ context.app.contact_editor.tab(name).click() -+ -+ -+@step(u'Set the following properties in contact editor') -+def set_properties(context): -+ for row in context.table.rows: -+ context.execute_steps(u""" -+ * Set "%s" in contact editor to "%s" -+ """ % (row['Field'], row['Value'])) -+ -+ -+@step(u'The following properties in contact editor are set') -+def verify_properties(context): -+ for row in context.table.rows: -+ context.execute_steps(u""" -+ Then "%s" property is set to "%s" -+ """ % (row['Field'], row['Value'])) -+ -+ -+@step(u'Set the following properties in "{section}" section of contact editor') -+def set_properties_in_section(context, section): -+ for row in context.table.rows: -+ context.execute_steps(u""" -+ * Set "%s" in "%s" section of contact editor to "%s" -+ """ % (row['Field'], section, row['Value'])) -+ -+ -+@step(u'The following properties in "{section}" section of contact editor are set') -+def verify_properties_in_section(context, section): -+ for row in context.table.rows: -+ context.execute_steps(u""" -+ Then "%s" property in "%s" section is set to "%s" -+ """ % (row['Field'], section, row['Value'])) -+ -+ -+@step(u'Set the following note for the contact') -+def set_note_for_contact(context): -+ context.app.contact_editor.child( -+ roleName='page tab', name='Notes').textentry('').text = context.text -+ -+ -+@then(u'The following note is set for the contact') -+def verify_note_set_for_contact(context): -+ actual = context.app.contact_editor.child( -+ roleName='page tab', name='Notes').textentry('').text -+ expected = context.text -+ assert actual == expected,\ -+ "Incorrect note value:\nexpected:%s\n but was:%s" % (expected, actual) -+ -+ -+@step(u'Set "{field_name}" in "{section}" section of contact editor to "{field_value}"') -+def set_field_in_section_to_value(context, field_name, section, field_value): -+ element = get_element_by_name( -+ context.app.contact_editor, field_name, section=section) -+ if element.roleName == "text": -+ element.text = field_value -+ elif element.roleName == "combo box": -+ element.combovalue = field_value -diff -up evolution-3.13.4/tests/steps/initial_setup_steps.py.missing-tests evolution-3.13.4/tests/steps/initial_setup_steps.py ---- evolution-3.13.4/tests/steps/initial_setup_steps.py.missing-tests 2014-07-30 11:21:47.032172902 +0200 -+++ evolution-3.13.4/tests/steps/initial_setup_steps.py 2014-07-30 11:21:47.032172902 +0200 -@@ -0,0 +1,130 @@ -+# -*- coding: UTF-8 -*- -+from behave import step -+ -+from common_steps import check_for_errors -+from dogtail.tree import root -+from os import system -+from pyatspi import STATE_SENSITIVE -+from time import sleep -+ -+ -+@step(u'Open Evolution and setup fake account') -+def open_evolution_and_setup_fake_account(context): -+ system("evolution --force-shutdown 2&> /dev/null") -+ context.execute_steps(u'* Start a new Evolution instance') -+ window = context.app.child(roleName='frame') -+ if window.name == 'Welcome': -+ context.execute_steps(u""" -+ * Complete Welcome dialog in Evolution Account Assistant -+ * Complete Restore from Backup dialog in Evolution Account Assistant -+ * Complete Identity dialog setting name to "GNOME QE User" and email address to "test@test" -+ * Wait for account is being looked up dialog in Evolution Account Assistant -+ * Complete Receiving Email dialog of Evolution Account Assistant setting -+ | Field | Value | -+ | Server Type: | None | -+ * Complete Sending Email dialog of Evolution Account Assistant setting -+ | Field | Value | -+ | Server Type: | Sendmail | -+ * Complete Account Summary in Evolution Account Assistant -+ * Complete Done dialog in Evolution Account Assistant -+ """) -+ -+ -+@step(u'Complete Receiving Options in Evolution Account Assistant') -+@step(u'Complete Account Summary in Evolution Account Assistant') -+@step(u'Complete Restore from Backup dialog in Evolution Account Assistant') -+@step(u'Complete Welcome dialog in Evolution Account Assistant') -+def evo_account_assistant_dummy_dialogs(context): -+ # nothing to do here, skip it -+ window = context.app.child(roleName='frame') -+ click_next(window) -+ -+ -+@step(u'Complete Identity dialog setting name to "{name}" and email address to "{email}"') -+def evo_account_assistant_identity_dialog(context, name, email): -+ # nothing to do here, skip it -+ window = context.app.child(roleName='frame') -+ window.childLabelled("Full Name:").text = name -+ window.childLabelled("Email Address:").text = email -+ click_next(window) -+ -+ -+@step(u"Wait for account is being looked up dialog in Evolution Account Assistant") -+def wait_for_account_to_be_looked_up(context): -+ window = context.app.child(roleName='frame') -+ skip_lookup = window.findChildren(lambda x: x.name == 'Skip Lookup') -+ visible_skip_lookup = [x for x in skip_lookup if x.showing] -+ if len(visible_skip_lookup) > 0: -+ visible_skip_lookup = visible_skip_lookup[0] -+ # bug https://bugzilla.gnome.org/show_bug.cgi?id=726539: Skip Lookup is not being removed -+ #assert wait_until(lambda x: not x.showing, visible_skip_lookup),\ -+ # "Skip Lookup button didn't dissappear" -+ -+ -+def click_next(window): -+ # As initial wizard dialog creates a bunch of 'Next' buttons -+ # We have to click to the visible and enabled one -+ buttons = window.findChildren(lambda x: x.name == 'Next' and x.showing and -+ STATE_SENSITIVE in x.getState().getStates()) -+ if buttons == []: -+ raise Exception("Enabled Next button was not found") -+ else: -+ buttons[0].click() -+ -+ -+@step(u'Complete {sending_or_receiving} Email dialog of Evolution Account Assistant setting') -+def evo_account_assistant_receiving_email_dialog_from_table(context, sending_or_receiving): -+ window = context.app.child(roleName='frame') -+ for row in context.table: -+ label = str(row['Field']) -+ value = str(row['Value']) -+ filler = window.child(roleName='filler', name='%s Email' % sending_or_receiving) -+ widgets = filler.findChildren(lambda x: x.showing) -+ visible_widgets = [x for x in widgets if x.labeller and x.labeller.name == label] -+ if len(visible_widgets) == 0: -+ raise RuntimeError("Cannot find visible widget labelled '%s'" % label) -+ widget = visible_widgets[0] -+ if widget.roleName == 'combo box': -+ if label != 'Port:': -+ widget.click() -+ widget.menuItem(value).click() -+ else: -+ # Port is a combobox, but you can type your port there -+ widget.textentry('').text = value -+ widget.textentry('').grab_focus() -+ widget.textentry('').keyCombo("") -+ if widget.roleName == 'text': -+ widget.text = value -+ -+ # Check for password here and accept self-generated certificate (if appears) -+ btns = window.findChildren(lambda x: x.name == 'Check for Supported Types') -+ visible_btns = [w for w in btns if w.showing] -+ if visible_btns == []: -+ click_next(window) -+ return -+ visible_btns[0].click() -+ -+ # Confirm all certificates by clicking 'Accept Permanently' until dialog is visible -+ apps = [x.name for x in root.applications()] -+ if 'evolution-user-prompter' in apps: -+ prompter = root.application('evolution-user-prompter') -+ dialog = prompter.child(roleName='dialog') -+ while dialog.showing: -+ if prompter.findChild(lambda x: x.name == 'Accept Permanently', retry=False, requireResult=False): -+ prompter.button('Accept Permanently').click() -+ else: -+ sleep(0.1) -+ -+ # Wait until Cancel button disappears -+ cancel = filler.findChildren(lambda x: x.name == 'Cancel')[0] -+ while cancel.showing: -+ sleep(0.1) -+ check_for_errors(context) -+ click_next(window) -+ -+ -+@step(u'Complete Done dialog in Evolution Account Assistant') -+def evo_account_assistant_done_dialog(context): -+ # nothing to do here, skip it -+ window = context.app.child(roleName='frame') -+ window.button('Apply').click() -diff -up evolution-3.13.4/tests/steps/steps.py.missing-tests evolution-3.13.4/tests/steps/steps.py ---- evolution-3.13.4/tests/steps/steps.py.missing-tests 2014-07-30 11:21:47.032172902 +0200 -+++ evolution-3.13.4/tests/steps/steps.py 2014-07-30 11:21:47.032172902 +0200 -@@ -0,0 +1,177 @@ -+# -*- coding: UTF-8 -*- -+from behave import step, then -+from common_steps import wait_until -+from dogtail.tree import root -+from dogtail.rawinput import keyCombo -+from time import sleep, time -+from os import system -+from gi.repository import Gio, GLib -+ -+ -+@step(u'Help section "{name}" is displayed') -+def help_is_displayed(context, name): -+ try: -+ context.yelp = root.application('yelp') -+ frame = context.yelp.child(roleName='frame') -+ wait_until(lambda x: x.showing, frame) -+ sleep(1) -+ context.assertion.assertEquals(name, frame.name) -+ finally: -+ system("killall yelp") -+ -+ -+@step(u'Evolution has {num:d} window opened') -+@step(u'Evolution has {num:d} windows opened') -+def evolution_has_num_windows_opened(context, num): -+ windows = context.app.findChildren(lambda x: x.roleName == 'frame') -+ context.assertion.assertEqual(len(windows), num) -+ -+ -+@step(u'Preferences dialog is opened') -+def preferences_dialog_opened(context): -+ context.app.window('Evolution Preferences') -+ -+ -+@step(u'"{name}" view is opened') -+def view_is_opened(context, name): -+ if name != 'Mail': -+ window_name = context.app.children[0].name -+ context.assertion.assertEquals(window_name, "%s - Evolution" % name) -+ else: -+ # A special case for Mail -+ context.assertion.assertTrue(context.app.menu('Message').showing) -+ -+ -+def get_visible_searchbar(context): -+ """Wait for searchbar to become visible""" -+ def get_searchbars(): -+ return context.app.findChildren(lambda x: x.labeller.name == 'Search:' and x.showing) -+ assert wait_until(lambda x: len(x()) > 0, get_searchbars), "No visible searchbars found" -+ return get_searchbars()[0] -+ -+ -+@step(u'Open "{section_name}" section') -+def open_section_by_name(context, section_name): -+ wait_until(lambda x: x.showing, context.app.menu('View')) -+ sleep(0.2) -+ context.app.menu('View').click() -+ context.app.menu('View').menu('Window').point() -+ context.app.menu('View').menu('Window').menuItem(section_name).click() -+ -+ # Find a search bar -+ context.app.search_bar = get_visible_searchbar(context) -+ -+ # Check that service required for this sections is running -+ required_services = { -+ 'Mail': 'org.gnome.evolution.dataserver.Sources', -+ 'Calendar': 'org.gnome.evolution.dataserver.Calendar', -+ 'Tasks': 'org.gnome.evolution.dataserver.Calendar', -+ 'Memos': 'org.gnome.evolution.dataserver.Calendar', -+ 'Contacts': 'org.gnome.evolution.dataserver.AddressBook', -+ } -+ required_service = required_services[section_name] -+ bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) -+ dbus_proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE, None, -+ 'org.freedesktop.DBus', -+ '/org/freedesktop/DBus', -+ 'org.freedesktop.DBus', None) -+ for attempt in xrange(0, 10): -+ result = dbus_proxy.call_sync( -+ 'ListNames', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None) -+ sleep(1) -+ if True in [required_service in x for x in result[0]]: -+ return -+ raise RuntimeError("%s service was not found" % required_service) -+ -+ -+@step(u'"{name}" menu is opened') -+def menu_is_opened(context, name): -+ sleep(0.5) -+ menu = context.app.menu(name) -+ children_displayed = [x.showing for x in menu.children] -+ context.assertion.assertTrue(True in children_displayed, "Menu '%s' is not opened" % name) -+ -+ -+@step(u'Press "{sequence}"') -+def press_button_sequence(context, sequence): -+ keyCombo(sequence) -+ sleep(0.5) -+ -+ -+@then(u'Evolution is closed') -+def evolution_is_closed(context): -+ assert wait_until(lambda x: x.dead, context.app),\ -+ "Evolution window is opened" -+ context.assertion.assertFalse(context.app_class.isRunning(), "Evolution is in the process list") -+ -+ -+@step(u'Message composer with title "{name}" is opened') -+def message_composer_is_opened(context, name): -+ context.app.composer = context.app.window(name) -+ -+ -+@then(u'Contact editor window with title "{title}" is opened') -+def contact_editor_with_label_is_opened(context, title): -+ context.app.contact_editor = context.app.dialog(title) -+ context.assertion.assertIsNotNone( -+ context.app.contact_editor, "Contact Editor was not found") -+ context.assertion.assertTrue( -+ context.app.contact_editor.showing, "Contact Editor didn't appear") -+ -+ -+@then(u'Contact editor window is opened') -+def contact_editor_is_opened(context): -+ context.execute_steps(u'Then Contact editor window with title "Contact Editor" is opened') -+ -+ -+@then(u'Contact List editor window is opened') -+def contact_list_editor_is_opened(context): -+ context.execute_steps( -+ u'Then Contact List editor window with title "Contact List Editor" is opened') -+ -+ -+@then(u'Contact List editor window with title "{name}" is opened') -+def contact_list_editor__with_name_is_opened(context, name): -+ context.app.contact_list_editor = context.app.dialog(name) -+ -+ -+@step(u'Memo editor with title "{name}" is opened') -+def memo_editor_is_opened(context, name): -+ context.execute_steps(u'* Task editor with title "%s" is opened' % name) -+ -+ -+@step(u'Shared Memo editor with title "{name}" is opened') -+def shared_memo_editor_is_opened(context, name): -+ context.execute_steps(u'* Task editor with title "%s" is opened' % name) -+ -+ -+@step(u'Task editor with title "{title}" is opened') -+def task_editor_with_title_is_opened(context, title): -+ context.app.task_editor = context.app.window(title) -+ # Spoof event_editor for assigned tasks -+ if 'Assigned' in title: -+ context.app.event_editor = context.app.task_editor -+ -+ -+@step(u'Event editor with title "{name}" is displayed') -+def event_editor_with_name_displayed(context, name): -+ context.app.event_editor = context.app.window(name) -+ -+ -+@step(u'Wait for email to synchronize') -+def wait_for_mail_folder_to_synchronize(context): -+ # Wait until Google calendar is loaded -+ for attempt in range(0, 10): -+ start_time = time() -+ try: -+ spinners = context.app.findChildren(lambda x: x.name == 'Spinner') -+ for spinner in spinners: -+ try: -+ while spinner.showing: -+ sleep(0.1) -+ if (time() - start_time) > 180: -+ raise RuntimeError("Mail takes too long to synchronize") -+ except GLib.GError: -+ continue -+ except (GLib.GError, TypeError): -+ continue diff --git a/evolution.spec b/evolution.spec index 3dd7189..4648ce5 100644 --- a/evolution.spec +++ b/evolution.spec @@ -29,8 +29,8 @@ ### Abstract ### Name: evolution -Version: 3.13.4 -Release: 2%{?dist} +Version: 3.13.5 +Release: 1%{?dist} Group: Applications/Productivity Summary: Mail and calendar client for GNOME License: GPLv2+ and GFDL @@ -50,8 +50,6 @@ Patch01: evolution-1.4.4-ldap-x86_64-hack.patch # RH bug #589555 Patch02: evolution-2.30.1-help-contents.patch -Patch03: evolution-3.13.4-missing-tests.patch - ## Dependencies ### Requires: gvfs @@ -218,7 +216,6 @@ the functionality of the installed %{name} package. %setup -q -n evolution-%{version} %patch01 -p1 -b .ldaphack %patch02 -p1 -b .help-contents -%patch03 -p1 -b .missing-tests # Remove the welcome email from Novell for inbox in mail/default/*/Inbox; do @@ -545,6 +542,10 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/installed-tests %changelog +* Mon Aug 25 2014 Milan Crha - 3.13.5-1 +- Update to 3.13.5 +- Remove patch to add missing tests files in the distribution tarball (fixed upstream) + * Sat Aug 16 2014 Fedora Release Engineering - 3.13.4-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild diff --git a/sources b/sources index a7db44e..32e445a 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -0e866a0572c99bef9a560758891ba5e7 evolution-3.13.4.tar.xz +3d984360b837a176e56db08a137ba799 evolution-3.13.5.tar.xz