Skip to content

Commit

Permalink
Add Test Tags to test suites settings (#2651)
Browse files Browse the repository at this point in the history
  • Loading branch information
HelioGuilherme66 authored Oct 7, 2023
1 parent b455031 commit 0353501
Show file tree
Hide file tree
Showing 17 changed files with 122 additions and 33 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to http://semver.org/spec/v2.0.0.html[Semantic Versioni

=== Added

- Added Test Tags field (new, since Robot Framework 6.0) to Test Suites settings. This field will replace Default and
Force Tags settings, after Robot Framework 7.0
- Added content help pop-up on Text Editor by pressing ``Ctrl`` for text at cursor position or selected autocomplete list item
- Added Exclude option in context nenu for Test files, previously was only possible for Test Suites folders
- Added exclusion of monitoring filesystem changes for files and directories excluded in Preferences
Expand Down
4 changes: 3 additions & 1 deletion src/robotide/application/CHANGELOG.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Changelog</title><link rel="stylesheet" type="text/css" href="docbook-xsl.css" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /></head><body><div xml:lang="en" class="article" lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="id1337"></a>Changelog</h2></div></div><hr /></div><p>All notable changes to this project will be documented in this file.</p><p>The format is based on <a class="ulink" href="http://keepachangelog.com/en/1.0.0/" target="_top">Keep a Changelog</a>
and this project adheres to <a class="ulink" href="http://semver.org/spec/v2.0.0.html" target="_top">Semantic Versioning</a>.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ulink_url_https_github_com_robotframework_ride_unreleased_ulink"></a>1. <a class="ulink" href="https://github.com/robotframework/RIDE" target="_top">Unreleased</a></h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_added"></a>1.1. Added</h3></div></div></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
and this project adheres to <a class="ulink" href="http://semver.org/spec/v2.0.0.html" target="_top">Semantic Versioning</a>.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_ulink_url_https_github_com_robotframework_ride_unreleased_ulink"></a>1. <a class="ulink" href="https://github.com/robotframework/RIDE" target="_top">Unreleased</a></h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_added"></a>1.1. Added</h3></div></div></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">Added Test Tags field (new, since Robot Framework 6.0) to Test Suites settings. This field will replace Default and Force Tags settings, after Robot Framework 7.0</li>
<li class="listitem">
Added content help pop-up on Text Editor by pressing ``Ctrl`` for text at cursor position or selected autocomplete list item
</li><li class="listitem">
Added Exclude option in context nenu for Test files, previously was only possible for Test Suites folders
Expand Down
1 change: 1 addition & 0 deletions src/robotide/application/releasenotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ def set_content(self, html_win, content):
</ul>
<p><strong>New Features and Fixes Highlights</strong></p>
<ul class="simple">
<li>Added <b>Test Tags</b> field (new, since Robot Framework 6.0) to Test Suites settings. This field will replace <b>Default</b> and <b>Force Tags</b> settings, after Robot Framework 7.0</li>
<li>Improved <b>RIDE Log</b> and <b>Parser Log</b> windows to allow Zoom In/Out with <b>Ctrl-Mouse Wheel</b></li>
<li>Hide continuation markers in Project Tree</li>
<li>Improved content assistance in Text Editor by allowing to filter list as we type</li>
Expand Down
20 changes: 16 additions & 4 deletions src/robotide/controller/filecontrollers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from .basecontroller import WithUndoRedoStacks, _BaseController, WithNamespace, ControllerWithParent
from .robotdata import new_test_case_file, new_test_data_directory
from .settingcontrollers import (DocumentationController, FixtureController, TimeoutController, TemplateController,
DefaultTagsController, ForceTagsController)
DefaultTagsController, ForceTagsController, TestTagsController)
from .tablecontrollers import (VariableTableController, TestCaseTableController, KeywordTableController,
ImportSettingsController, MetadataListController)
from .macrocontrollers import TestCaseController, UserKeywordController
Expand Down Expand Up @@ -161,7 +161,7 @@ def internal_settings(self):
FixtureController(self, ss.suite_teardown),
FixtureController(self, ss.test_setup),
FixtureController(self, ss.test_teardown),
self.force_tags]
self.force_tags, self.test_tags]

@property
def setting_table(self):
Expand All @@ -171,6 +171,10 @@ def setting_table(self):
def force_tags(self):
return ForceTagsController(self, self.setting_table.force_tags)

@property
def test_tags(self):
return TestTagsController(self, self.setting_table.test_tags)

@property
def variables(self):
if self._variables_table_controller is None:
Expand Down Expand Up @@ -1015,7 +1019,7 @@ def internal_settings(self):
FixtureController(self, ss.suite_teardown),
FixtureController(self, ss.test_setup),
FixtureController(self, ss.test_teardown),
self.force_tags]
self.force_tags, self.test_tags]

@property
def setting_table(self):
Expand All @@ -1025,6 +1029,10 @@ def setting_table(self):
def force_tags(self):
return ForceTagsController(self, self.setting_table.force_tags)

@property
def test_tags(self):
return TestTagsController(self, self.setting_table.test_tags)

@property
def dirty(self):
return False
Expand Down Expand Up @@ -1089,7 +1097,7 @@ def internal_settings(self):
sett = _DataController.internal_settings(self)
sett.insert(-1, TemplateController(self, ss.test_template))
sett.insert(-1, TimeoutController(self, ss.test_timeout))
return sett + [self.default_tags, self.force_tags] # OK doing some cheating here ;)
return sett + [self.default_tags, self.force_tags, self.test_tags] # OK doing some cheating here ;)

@property
def longname(self):
Expand Down Expand Up @@ -1173,6 +1181,10 @@ def setting_table(self):
def force_tags(self): # Yes, I know this is impossible, but is Exclude file, right?
return None # ForceTagsController(self, self.setting_table.force_tags)

@property
def test_tags(self): # Yes, I know this is impossible, but is Exclude file, right?
return None

@property
def dirty(self):
return False
Expand Down
5 changes: 5 additions & 0 deletions src/robotide/controller/macrocontrollers.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ def tags(self):
def force_tags(self):
return self.datafile_controller.force_tags

@property
def test_tags(self):
return self.datafile_controller.test_tags

@property
def default_tags(self):
return self.datafile_controller.default_tags
Expand Down Expand Up @@ -416,6 +420,7 @@ def _init(self, kw):
# Needed for API compatibility in tag search
self.force_tags = []
self.default_tags = []
self.test_tags = []

def __eq__(self, other):
if self is other:
Expand Down
47 changes: 42 additions & 5 deletions src/robotide/controller/settingcontrollers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
RideItemSettingsChanged, RideImportSettingAdded)
from ..utils import variablematcher, unescape_newlines_and_whitespaces
from .basecontroller import ControllerWithParent
from .tags import Tag, ForcedTag, DefaultTag
from .tags import Tag, ForcedTag, DefaultTag, TestTag


class _SettingController(ControllerWithParent):
Expand Down Expand Up @@ -222,13 +222,14 @@ def remove(self, tag):

def __iter__(self):
forced = self._parent.force_tags
test_tags = self._parent.test_tags
if self.tags.value is None:
return chain(forced, self._parent.default_tags).__iter__()
return chain(forced, self._parent.default_tags, test_tags).__iter__()
if len(self.tags.value) == 0:
return chain(forced, [Tag('', controller=self)])
return chain(forced, test_tags, [Tag('', controller=self)])
own_tags = (Tag(t, index, self)
for index, t in enumerate(self.tags.value))
return chain(forced, own_tags).__iter__()
return chain(forced, test_tags, own_tags).__iter__()

@property
def is_set(self):
Expand Down Expand Up @@ -284,11 +285,47 @@ def _recursive_gather_from(self, obj, result):
def _gather_from_data(tags, parent):
if tags.value is None:
return []
print(f"DEBUG: SettingsController _gather_from_data entry tags={tags.value}")
return [ForcedTag(t, index, parent)
for index, t in enumerate(tags.value)]


class TestTagsController(TagsController):

def empty_tag(self):
return TestTag(None, controller=self)

def __iter__(self):
return self._recursive_gather_from(self.parent, []).__iter__()

def __eq__(self, other):
if self is other:
return True
if other is None:
return False
if not isinstance(other, self.__class__):
return False
return self.tags == other.tags

def _recursive_gather_from(self, obj, result):
if obj is None:
return result
try:
test_tags = obj.setting_table.test_tags
except AttributeError: # In the case of a .resource file, there is no Test Tags fields
return result
# print(f"DEBUG: SettingsController _recursive_gather_from force_tags={force_tags}, obj.parent={obj.parent}")
return self._recursive_gather_from(
obj.parent,
self._gather_from_data(test_tags, obj.test_tags) + result)

@staticmethod
def _gather_from_data(tags, parent):
if tags.value is None:
return []
return [TestTag(t, index, parent)
for index, t in enumerate(tags.value)]


class TimeoutController(_SettingController):

def _init(self, timeout):
Expand Down
8 changes: 8 additions & 0 deletions src/robotide/controller/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,11 @@ class DefaultTag(Tag):
def tooltip(self):
return u'Default tag from suite {0}'.format(
self.controller.datafile_controller.name)


class TestTag(Tag):

@property
def tooltip(self):
return u'Apply Test Tags from suite {0} (since Robot Framework 6.0)'.format(
self.controller.datafile_controller.name)
7 changes: 7 additions & 0 deletions src/robotide/editor/dialoghelps.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ def get_help(title):
%(TAG)s
%(ESCAPE)s
Test Tags
These tags are applied to all test cases in this test suite. This field exists since Robot Framework 6.0 and will
replace Force and Default Tags after version 7.0.
Inherited tags are not shown in this view.
%(TAG)s
%(ESCAPE)s
Tags
These tags are set to this test case in addition to Force Tags and they override possible Default Tags.
Inherited tags are not shown in this view.
Expand Down
6 changes: 6 additions & 0 deletions src/robotide/editor/editordialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,12 @@ def _execute(self):
pass


class TestTagsDialog(_SettingDialog):
def _execute(self):
""" Just ignore it """
pass


class TagsDialog(_SettingDialog):
def _execute(self):
""" Just ignore it """
Expand Down
8 changes: 1 addition & 7 deletions src/robotide/editor/editors.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def __init__(self, plugin, parent, controller, tree):
self.SetSizer(self.sizer)
if self.title:
self.sizer.Add(self._create_header(self.title),
0, wx.EXPAND | wx.ALL, 5)
0, wx.EXPAND | wx.ALL, 6)
self._editors = []
self._last_shown_tooltip = None
self._reset_last_show_tooltip()
Expand Down Expand Up @@ -269,12 +269,6 @@ def _get_editor_class(controller):
def build(self, settings, plugin, tree):
for setting in settings:
editor = self.create_editor_for(setting, plugin, tree)
"""
editor.SetBackgroundColour(Colour(200, 222, 40))
editor.SetOwnBackgroundColour(Colour(200, 222, 40))
editor.SetForegroundColour(Colour(7, 0, 70))
editor.SetOwnForegroundColour(Colour(7, 0, 70))
"""
self._sizer.Add(editor, 0, wx.ALL | wx.EXPAND, self.BORDER)
self._editors.append(editor)
editor.Refresh()
Expand Down
12 changes: 10 additions & 2 deletions src/robotide/editor/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from wx.lib.scrolledpanel import ScrolledPanel
from ..context import IS_WINDOWS
from ..controller import ctrlcommands
from ..controller.tags import ForcedTag, DefaultTag
from ..controller.tags import ForcedTag, DefaultTag, TestTag


class TagsDisplay(ScrolledPanel):
Expand Down Expand Up @@ -225,7 +225,8 @@ def properties(tag, controller):
if tag.controller == controller:
return TagBoxProperties(tag)
return tag.choose({ForcedTag: ForcedTagBoxProperties,
DefaultTag: DefaultTagBoxProperties})(tag)
DefaultTag: DefaultTagBoxProperties,
TestTag: TestTagBoxProperties})(tag)


class _TagBoxProperties(object):
Expand Down Expand Up @@ -292,3 +293,10 @@ class DefaultTagBoxProperties(_TagBoxProperties):
foreground_color = '#666666'
background_color = '#D3D3D3' # Colour(200, 222, 40)
enabled = False


class TestTagBoxProperties(_TagBoxProperties):
# DEBUG: Use colours from settings
foreground_color = 'orange'
background_color = '#D3D3D3' # Colour(200, 222, 40)
enabled = False
23 changes: 13 additions & 10 deletions src/robotide/lib/robot/parsing/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def TestData(parent=None, source=None, include_suites=None,
:returns: :class:`~.model.TestDataDirectory` if `source` is a directory,
:class:`~.model.TestCaseFile` otherwise.
"""
# TODO: Remove in RF 3.2.
# DEBUG: Remove in RF 3.2.
if warn_on_skipped != 'DEPRECATED':
warnings.warn("Option 'warn_on_skipped' is deprecated and has no "
"effect.", DeprecationWarning)
Expand Down Expand Up @@ -77,7 +77,7 @@ def _get_tables(self):
(self._keyword_table_names, self.keyword_table),
(self._comment_table_names, None)]:
# remove Comments section, because we want to keep them as they are in files
# , (self._comment_table_names, None)]:
# , (self._comment_table_names, None)
for name in names:
yield name, table

Expand Down Expand Up @@ -117,7 +117,7 @@ def _resolve_deprecated_table(self, used_name):
for name in (self._setting_table_names + self._variable_table_names +
self._testcase_table_names + self._keyword_table_names):
# remove Comments section, because we want to keep them as they are in files
# + self._comment_table_names):
# + self._comment_table_names
if normalize(name) == normalized:
self._report_deprecated_table(used_name, name)
return name
Expand Down Expand Up @@ -414,8 +414,9 @@ def __init__(self, parent):
self.suite_teardown = Fixture('Suite Teardown', self)
self.test_setup = Fixture('Test Setup', self)
self.test_teardown = Fixture('Test Teardown', self)
self.force_tags = Tags('Force Tags', self)
self.default_tags = Tags('Default Tags', self)
self.force_tags = Tags('Force Tags', self) # To deprecate after RF 7.0
self.default_tags = Tags('Default Tags', self) # To deprecate after RF 7.0
self.test_tags = Tags('Test Tags', self) # New since RF 6.0
self.test_template = Template('Test Template', self)
self.test_timeout = Timeout('Test Timeout', self)
self.metadata = MetadataList(self)
Expand Down Expand Up @@ -454,6 +455,7 @@ class TestCaseFileSettingTable(_SettingTable):
'Test Teardown': lambda s: s.test_teardown.populate,
'Force Tags': lambda s: s.force_tags.populate,
'Default Tags': lambda s: s.default_tags.populate,
'Test Tags': lambda s: s.test_tags.populate,
'Test Template': lambda s: s.test_template.populate,
'Test Timeout': lambda s: s.test_timeout.populate,
'Library': lambda s: s.imports.populate_library,
Expand All @@ -468,7 +470,7 @@ class TestCaseFileSettingTable(_SettingTable):
def __iter__(self):
for setting in [self.doc, self.suite_setup, self.suite_teardown,
self.test_setup, self.test_teardown, self.force_tags,
self.default_tags, self.test_template, self.test_timeout] \
self.default_tags, self.test_tags, self.test_template, self.test_timeout] \
+ self.metadata.data + self.imports.data:
yield setting

Expand All @@ -492,14 +494,15 @@ class InitFileSettingTable(_SettingTable):
'Test Teardown': lambda s: s.test_teardown.populate,
'Test Timeout': lambda s: s.test_timeout.populate,
'Force Tags': lambda s: s.force_tags.populate,
'Test Tags': lambda s: s.test_tags.populate,
'Library': lambda s: s.imports.populate_library,
'Resource': lambda s: s.imports.populate_resource,
'Variables': lambda s: s.imports.populate_variables,
'Metadata': lambda s: s.metadata.populate}

def __iter__(self):
for setting in [self.doc, self.suite_setup, self.suite_teardown,
self.test_setup, self.test_teardown, self.force_tags,
self.test_setup, self.test_teardown, self.force_tags, self.test_tags,
self.test_timeout] + self.metadata.data + self.imports.data:
yield setting

Expand Down Expand Up @@ -875,7 +878,7 @@ def __init__(self, content, comment=None):
# print(f"DEBUG: RFLib Model init Step: index={index} inner_kw_pos = {self.inner_kw_pos} indent={self.indent[:]} \ncontent {content}")
self.args = content[index + 1:] if content and index <= len(content) - 1 else []
# print(f"DEBUG: RFLib Model init Step: 1st cell len(content)={len(content)} index {index} indent={self.indent[:]}") # 1st cell: {content[index]}")
# TODO: Create setters for Step.name and Step.args, see stepcontrollers.py replace_keyword
# DEBUG: Create setters for Step.name and Step.args, see stepcontrollers.py replace_keyword
if index < len(content):
self.name = content[index] if content else None
else:
Expand All @@ -899,7 +902,7 @@ def _get_assign(self):
if 0 <= index < len(cells) and self.is_kind_of_comment(cells[index]): # Special case for commented content
return []
# print(f"DEBUG: RFLib Model _get_assign VAR NORMAL (index={index}) inner_kw_pos={self.inner_kw_pos} content={content[:]}")
# first handle non FOR cases
# first handle non-FOR cases
idx = 0
try:
if cells[self.inner_kw_pos] != 'FOR':
Expand Down Expand Up @@ -953,7 +956,7 @@ def is_comment(self):
return self.name.lower() == 'comment' or not (self.assign or self.name or self.args)

def is_for_loop(self):
# TODO: remove steps ForLoop: return self.name == 'FOR'
# DEBUG: remove steps ForLoop: return self.name == 'FOR'
return False

def is_set(self):
Expand Down
Loading

0 comments on commit 0353501

Please sign in to comment.