diff --git a/action.py b/action.py
index 0839873..89fb0dc 100644
--- a/action.py
+++ b/action.py
@@ -1,135 +1,271 @@
import mwparserfromhell # type: ignore
-from typing import Any
+from typing import Any, Union
from siteinfo import CategoryInfo
class Action:
"""A transformation to a piece of wikitext."""
def apply(self, wikitext: str, category_info: CategoryInfo) -> str:
raise NotImplementedError
def summary(self, category_info: CategoryInfo) -> str:
raise NotImplementedError
def is_minor(self) -> bool:
"""Whether this action, on its own, can be considered a minor edit."""
raise NotImplementedError
def cleanup(self) -> None:
"""Partially normalize the action, as a convenience for users.
This should not be used as a replacement for full
normalization via the MediaWiki API.
"""
pass
class CategoryAction(Action):
"""An action to modify a category in the wikitext of a page."""
symbol = ''
def __init__(self, category: str):
assert category, 'category should not be empty'
assert not category.startswith('Category:'), 'category should not include namespace'
assert '[' not in category, 'category should not be a wikilink'
assert ']' not in category, 'category should not be a wikilink'
self.category = category
super().__init__()
def _is_category(self, wikilink: mwparserfromhell.nodes.wikilink.Wikilink, category_info: CategoryInfo) -> bool:
for category_namespace_name in category_info[1]:
if wikilink.startswith('[[' + category_namespace_name + ':'):
return True
return False
def _same_category(self, category1: str, category2: str, category_info: CategoryInfo) -> bool:
if category_info[2] == 'first-letter':
category1 = category1[:1].upper() + category1[1:]
category2 = category2[:1].upper() + category2[1:]
elif category_info[2] == 'case-sensitive':
pass
else:
raise ValueError('Unknown case handling %s' % category_info[2])
return category1.replace(' ', '_') == category2.replace(' ', '_')
def summary(self, category_info: CategoryInfo) -> str:
return type(self).symbol + '[[' + category_info[0] + ':' + self.category + ']]'
def cleanup(self) -> None:
self.category = self.category.replace('_', ' ')
def __eq__(self, value: Any) -> bool:
return type(self) is type(value) and \
self.category == value.category
def __str__(self) -> str:
return type(self).symbol + 'Category:' + self.category
class AddCategoryAction(CategoryAction):
"""An action to add a category to the wikitext of a page."""
symbol = '+'
def apply(self, wikitext: str, category_info: CategoryInfo) -> str:
wikicode = mwparserfromhell.parse(wikitext)
last_category = None
for wikilink in wikicode.ifilter_wikilinks():
if not self._is_category(wikilink, category_info):
continue
- if self._same_category(wikilink.title.split(':', 1)[1], self.category, category_info):
- return wikitext
+ if self._accept_category_link(wikilink, category_info):
+ return str(wikicode)
last_category = wikilink
- wikilink = mwparserfromhell.nodes.wikilink.Wikilink(category_info[0] + ':' + self.category)
+ wikilink = self._make_category_link(category_info)
if last_category:
wikicode.insert_after(last_category, wikilink)
wikicode.insert_before(wikilink, '\n')
else:
if wikicode:
wikicode.append('\n')
wikicode.append(wikilink)
return str(wikicode)
+ def _accept_category_link(self, wikilink, category_info: CategoryInfo) -> bool:
+ return self._same_category(wikilink.title.split(':', 1)[1], self.category, category_info)
+
+ def _make_category_link(self, category_info: CategoryInfo):
+ return mwparserfromhell.nodes.wikilink.Wikilink(category_info[0] + ':' + self.category)
+
def is_minor(self) -> bool:
return True
def __repr__(self) -> str:
return 'AddCategoryAction(' + repr(self.category) + ')'
+class AddCategoryAndSortKeyAction(AddCategoryAction):
+ """An action to add a category to the wikitext of a page, including a sort key."""
+
+ sort_key_symbol = ''
+
+ def __init__(self, category: str, sort_key: Union[str, None]):
+ assert sort_key != '', 'sort key cannot be the empty string'
+ self.sort_key = sort_key
+ super().__init__(category)
+
+ def summary(self, category_info: CategoryInfo) -> str:
+ return '+[[' + category_info[0] + ':' + self.category + '|' + \
+ category_info[0] + ':' + self.category + '|' + (self.sort_key or '') + ']]'
+
+ def __eq__(self, value: Any) -> bool:
+ return type(self) is type(value) and \
+ self.category == value.category and \
+ self.sort_key == value.sort_key
+
+ def __str__(self) -> str:
+ return super().__str__() + type(self).sort_key_symbol + (self.sort_key or '')
+
+
+class AddCategoryWithSortKeyAction(AddCategoryAndSortKeyAction):
+ """An action to add a category with a certain sort key to the wikitext of a page.
+
+ If no category link for that category exists yet, it is added with that sort key.
+ If such a category link exists, with or without any sort key, no change is made."""
+
+ sort_key_symbol = '#'
+
+ def _make_category_link(self, category_info: CategoryInfo):
+ if not self.sort_key:
+ return super()._make_category_link(category_info)
+ return mwparserfromhell.nodes.wikilink.Wikilink(category_info[0] + ':' + self.category,
+ self.sort_key)
+
+ def __repr__(self) -> str:
+ return 'AddCategoryWithSortKeyAction(' + \
+ repr(self.category) + ', ' + \
+ repr(self.sort_key) + ')'
+
+
+class AddCategoryProvideSortKeyAction(AddCategoryAndSortKeyAction):
+ """An action to provide a category with a certain sort key in the wikitext of a page.
+
+ If no category link for that category exists yet, it is added with that sort key.
+ If such a category link exists, but without a sort key, the sort key is added.
+ If the existing category specifies a different sort key, no change is made."""
+
+ sort_key_symbol = '##'
+
+ def _accept_category_link(self, wikilink, category_info: CategoryInfo) -> bool:
+ if super()._accept_category_link(wikilink, category_info):
+ if wikilink.text is None:
+ wikilink.text = self.sort_key
+ return True
+ else:
+ return False
+
+ def _make_category_link(self, category_info: CategoryInfo):
+ if not self.sort_key:
+ return super()._make_category_link(category_info)
+ return mwparserfromhell.nodes.wikilink.Wikilink(category_info[0] + ':' + self.category,
+ self.sort_key)
+
+ def __repr__(self) -> str:
+ return 'AddCategoryProvideSortKeyAction(' + \
+ repr(self.category) + ', ' + \
+ repr(self.sort_key) + ')'
+
+
+class AddCategoryReplaceSortKeyAction(AddCategoryAndSortKeyAction):
+ """An action to replace a category’s sort key in the wikitext of a page.
+
+ If no category link for that category exists yet, it is added with that sort key.
+ If such a category link exists, with or without any sort key, its sort key is replaced with the given one."""
+
+ sort_key_symbol = '###'
+
+ def _accept_category_link(self, wikilink, category_info: CategoryInfo) -> bool:
+ if super()._accept_category_link(wikilink, category_info):
+ wikilink.text = self.sort_key
+ return True
+ else:
+ return False
+
+ def _make_category_link(self, category_info: CategoryInfo):
+ return mwparserfromhell.nodes.wikilink.Wikilink(category_info[0] + ':' + self.category,
+ self.sort_key)
+
+ def __repr__(self) -> str:
+ return 'AddCategoryReplaceSortKeyAction(' + \
+ repr(self.category) + ', ' + \
+ repr(self.sort_key) + ')'
+
+
class RemoveCategoryAction(CategoryAction):
"""An action to remove a category from the wikitext of a page."""
symbol = '-'
def apply(self, wikitext: str, category_info: CategoryInfo) -> str:
wikicode = mwparserfromhell.parse(wikitext)
for index, wikilink in enumerate(wikicode.nodes):
if not isinstance(wikilink, mwparserfromhell.nodes.wikilink.Wikilink):
continue
if not self._is_category(wikilink, category_info):
continue
- if self._same_category(wikilink.title.split(':', 1)[1], self.category, category_info):
+ if self._reject_category_link(wikilink, category_info):
# also remove preceding line break
if index-1 >= 0 and \
isinstance(wikicode.nodes[index-1], mwparserfromhell.nodes.text.Text) and \
wikicode.nodes[index-1].value.endswith('\n'):
wikicode.nodes[index-1].value = wikicode.nodes[index-1].value[:-1]
# or following line break
elif index+1 < len(wikicode.nodes) and \
isinstance(wikicode.nodes[index+1], mwparserfromhell.nodes.text.Text) and \
wikicode.nodes[index+1].value.startswith('\n'):
wikicode.nodes[index+1].value = wikicode.nodes[index+1].value[1:]
del wikicode.nodes[index] # this should happen *after* the above blocks, otherwise the indices get confusing
break
return str(wikicode)
+ def _reject_category_link(self, wikilink, category_info: CategoryInfo) -> bool:
+ return self._same_category(wikilink.title.split(':', 1)[1], self.category, category_info)
+
def is_minor(self) -> bool:
return False
def __repr__(self) -> str:
return 'RemoveCategoryAction(' + repr(self.category) + ')'
+
+
+class RemoveCategoryWithSortKeyAction(RemoveCategoryAction):
+ """An action to remove a category from the wikitext of a page if it matches a certain sort key."""
+
+ def __init__(self, category: str, sort_key: Union[str, None]):
+ assert sort_key != '', 'sort key cannot be the empty string'
+ self.sort_key = sort_key
+ super().__init__(category)
+
+ def _reject_category_link(self, wikilink, category_info: CategoryInfo) -> bool:
+ return super()._reject_category_link(wikilink, category_info) and \
+ wikilink.text == self.sort_key
+
+ def summary(self, category_info: CategoryInfo) -> str:
+ return '-[[' + category_info[0] + ':' + self.category + '|' + \
+ category_info[0] + ':' + self.category + '|' + (self.sort_key or '') + ']]'
+
+ def __eq__(self, value: Any) -> bool:
+ return type(self) is type(value) and \
+ self.category == value.category and \
+ self.sort_key == value.sort_key
+
+ def __str__(self) -> str:
+ return super().__str__() + '#' + (self.sort_key or '')
+
+ def __repr__(self) -> str:
+ return 'RemoveCategoryWithSortKeyAction(' + \
+ repr(self.category) + ', ' + \
+ repr(self.sort_key) + ')'
diff --git a/test_action.py b/test_action.py
index 27aa0d6..655b951 100644
--- a/test_action.py
+++ b/test_action.py
@@ -1,163 +1,319 @@
import pytest # type: ignore
-from action import AddCategoryAction, RemoveCategoryAction
+from action import AddCategoryAction, AddCategoryWithSortKeyAction, AddCategoryProvideSortKeyAction, AddCategoryReplaceSortKeyAction, RemoveCategoryAction, RemoveCategoryWithSortKeyAction
addCategory1 = AddCategoryAction('Cat 1')
addCategory2 = AddCategoryAction('Cat 2')
+addCategoryWithSortKey1 = AddCategoryWithSortKeyAction('Cat 1', 'sort key')
+addCategoryProvideSortKey1 = AddCategoryProvideSortKeyAction('Cat 1', 'sort key')
+addCategoryReplaceSortKey1 = AddCategoryReplaceSortKeyAction('Cat 1', 'sort key')
removeCategory1 = RemoveCategoryAction('Cat 1')
+removeCategoryWithSortKey1 = RemoveCategoryWithSortKeyAction('Cat 1', 'sort key')
@pytest.mark.parametrize('clazz', [AddCategoryAction, RemoveCategoryAction])
def test_CategoryAction_init_empty(clazz):
with pytest.raises(AssertionError):
clazz('')
@pytest.mark.parametrize('clazz', [AddCategoryAction, RemoveCategoryAction])
def test_CategoryAction_init_wikilink(clazz):
with pytest.raises(AssertionError):
clazz('[[Category:Cat 1]]')
with pytest.raises(AssertionError):
clazz('[[other link]]')
@pytest.mark.parametrize('clazz', [AddCategoryAction, RemoveCategoryAction])
def test_CategoryAction_init_category_namespace(clazz):
with pytest.raises(AssertionError):
clazz('Category:Cat 1')
@pytest.mark.parametrize('wikitext, expected', [
('', '[[Category:Test]]'),
('end of article', 'end of article\n[[Category:Test]]'),
('end of article\n[[Category:A]]\n[[Category:B]]', 'end of article\n[[Category:A]]\n[[Category:B]]\n[[Category:Test]]'),
('some wikitext\n[[Category:Here]]\nmore wikitext', 'some wikitext\n[[Category:Here]]\n[[Category:Test]]\nmore wikitext'),
('it is [[Category:Test]] already present', 'it is [[Category:Test]] already present'),
('it is [[Category:test]] already present in lowercase', 'it is [[Category:test]] already present in lowercase'),
('it is [[Category:TEST]] present in different capitalization', 'it is [[Category:TEST]]\n[[Category:Test]] present in different capitalization'),
('[[Kategorie:Test]]', '[[Kategorie:Test]]'),
('[[K:Test]]', '[[K:Test]]'),
('[[Category:Test|sort key]]', '[[Category:Test|sort key]]'),
('[[:Category:Test]]', '[[:Category:Test]]\n[[Category:Test]]'),
('[[:Category:Test|link text]]', '[[:Category:Test|link text]]\n[[Category:Test]]'),
('[[Category:Test]]', '[[Category:Test]]\n[[Category:Test]]'),
('[[Test]]', '[[Test]]\n[[Category:Test]]'),
('[[Special:Test]]', '[[Special:Test]]\n[[Category:Test]]'),
])
def test_AddCategoryAction_apply(wikitext, expected):
action = AddCategoryAction('Test')
actual = action.apply(wikitext, ('Category', ['Category', 'Kategorie', 'K'], 'first-letter'))
assert expected == actual
def test_AddCategoryAction_apply_detects_underscores():
action = AddCategoryAction('My Test Category')
wikitext = '[[Category:My_Test_Category]]'
assert wikitext == action.apply(wikitext, ('Category', ['Category'], 'first-letter'))
# note: the following test is no longer as relevant since we clean up all new batches to never contain underscores
def test_AddCategoryAction_apply_preserves_underscores():
action1 = AddCategoryAction('Test Category 1')
action2 = AddCategoryAction('Test_Category_2')
action3 = AddCategoryAction('Test_Category 3')
expected = '[[Category:Test Category 1]]\n[[Category:Test_Category_2]]\n[[Category:Test_Category 3]]'
actual = ''
for action in [action1, action2, action3]:
actual = action.apply(actual, ('Category', ['Category'], 'first-letter'))
assert expected == actual
def test_AddCategoryAction_apply_case_sensitive():
action = AddCategoryAction('Test')
wikitext = '[[Category:test]]'
expected = '[[Category:test]]\n[[Category:Test]]'
assert expected == action.apply(wikitext, ('Category', ['Category'], 'case-sensitive'))
def test_AddCategoryAction_summary():
assert AddCategoryAction('Test').summary(('Kategorie', ['Kategorie', 'Category'])) == '+[[Kategorie:Test]]'
def test_AddCategoryAction_is_minor():
assert AddCategoryAction('Test').is_minor()
def test_AddCategoryAction_cleanup():
action = AddCategoryAction('User_input_from_URL')
action.cleanup()
assert action == AddCategoryAction('User input from URL')
def test_AddCategoryAction_eq_same():
assert addCategory1 == addCategory1
def test_AddCategoryAction_eq_equal():
assert addCategory1 == AddCategoryAction(addCategory1.category)
def test_AddCategoryAction_eq_different_type():
assert addCategory1 != RemoveCategoryAction(addCategory1.category)
def test_AddCategoryAction_eq_different_category():
assert addCategory1 != addCategory2
def test_AddCategoryAction_eq_different_category_normalization():
assert AddCategoryAction('Foo Bar') != AddCategoryAction('Foo_Bar')
def test_AddCategoryAction_str():
assert str(addCategory1) == '+Category:Cat 1'
def test_AddCategoryAction_repr():
assert eval(repr(addCategory1)) == addCategory1
+@pytest.mark.parametrize('clazz', [AddCategoryWithSortKeyAction, AddCategoryProvideSortKeyAction, AddCategoryReplaceSortKeyAction])
+def test_AddCategoryAndSortKeyAction_init_empty_sort_key(clazz):
+ with pytest.raises(AssertionError):
+ clazz('Category', '')
+
+@pytest.mark.parametrize('clazz', [AddCategoryWithSortKeyAction, AddCategoryProvideSortKeyAction, AddCategoryReplaceSortKeyAction])
+def test_AddCategoryAndSortKeyAction_summary(clazz):
+ assert clazz('Test', 'Sortierschlüssel').summary(('Kategorie', ['Kategorie', 'Category'])) == '+[[Kategorie:Test|Kategorie:Test|Sortierschlüssel]]'
+
+
+@pytest.mark.parametrize('wikitext, expected', [
+ ('', '[[Category:Test|sort key]]'),
+ ('[[Category:Test]]', '[[Category:Test]]'),
+ ('[[Category:Test|other sort key]]', '[[Category:Test|other sort key]]'),
+])
+def test_AddCategoryWithSortKeyAction_apply(wikitext, expected):
+ action = AddCategoryWithSortKeyAction('Test', 'sort key')
+ actual = action.apply(wikitext, ('Category', ['Category', 'Kategorie', 'K'], 'first-letter'))
+ assert expected == actual
+
+def test_AddCategoryWithSortKeyAction_eq_same():
+ assert addCategoryWithSortKey1 == addCategoryWithSortKey1
+
+def test_AddCategoryWithSortKeyAction_eq_equal():
+ assert addCategoryWithSortKey1 == AddCategoryWithSortKeyAction(addCategoryWithSortKey1.category, addCategoryWithSortKey1.sort_key)
+
+def test_AddCategoryWithSortKeyAction_eq_different_type():
+ assert addCategoryWithSortKey1 != AddCategoryProvideSortKeyAction(addCategoryWithSortKey1.category, addCategoryWithSortKey1.sort_key)
+
+def test_AddCategoryWithSortKeyAction_eq_different_category():
+ assert addCategoryWithSortKey1 != AddCategoryWithSortKeyAction('Cat 2', addCategoryWithSortKey1.sort_key)
+
+def test_AddCategoryWithSortKeyAction_eq_different_sort_key():
+ assert addCategoryWithSortKey1 != AddCategoryWithSortKeyAction(addCategoryWithSortKey1.category, 'other sort key')
+
+def test_AddCategoryWithSortKeyAction_str():
+ assert str(addCategoryWithSortKey1) == '+Category:Cat 1#sort key'
+
+def test_AddCategoryWithSortKeyAction_repr():
+ assert eval(repr(addCategoryWithSortKey1)) == addCategoryWithSortKey1
+
+
+@pytest.mark.parametrize('wikitext, expected', [
+ ('', '[[Category:Test|sort key]]'),
+ ('[[Category:Test]]', '[[Category:Test|sort key]]'),
+ ('[[Category:Test|other sort key]]', '[[Category:Test|other sort key]]'),
+])
+def test_AddCategoryProvideSortKeyAction_apply(wikitext, expected):
+ action = AddCategoryProvideSortKeyAction('Test', 'sort key')
+ actual = action.apply(wikitext, ('Category', ['Category', 'Kategorie', 'K'], 'first-letter'))
+ assert expected == actual
+
+def test_AddCategoryProvideSortKeyAction_eq_same():
+ assert addCategoryProvideSortKey1 == addCategoryProvideSortKey1
+
+def test_AddCategoryProvideSortKeyAction_eq_equal():
+ assert addCategoryProvideSortKey1 == AddCategoryProvideSortKeyAction(addCategoryProvideSortKey1.category, addCategoryProvideSortKey1.sort_key)
+
+def test_AddCategoryProvideSortKeyAction_eq_different_type():
+ assert addCategoryProvideSortKey1 != AddCategoryWithSortKeyAction(addCategoryProvideSortKey1.category, addCategoryProvideSortKey1.sort_key)
+
+def test_AddCategoryProvideSortKeyAction_eq_different_category():
+ assert addCategoryProvideSortKey1 != AddCategoryProvideSortKeyAction('Cat 2', addCategoryProvideSortKey1.sort_key)
+
+def test_AddCategoryProvideSortKeyAction_eq_different_sort_key():
+ assert addCategoryProvideSortKey1 != AddCategoryProvideSortKeyAction(addCategoryProvideSortKey1.category, 'other sort key')
+
+def test_AddCategoryProvideSortKeyAction_str():
+ assert str(addCategoryProvideSortKey1) == '+Category:Cat 1##sort key'
+
+def test_AddCategoryProvideSortKeyAction_repr():
+ assert eval(repr(addCategoryProvideSortKey1)) == addCategoryProvideSortKey1
+
+
+@pytest.mark.parametrize('wikitext, expected', [
+ ('', '[[Category:Test|sort key]]'),
+ ('[[Category:Test]]', '[[Category:Test|sort key]]'),
+ ('[[Category:Test|other sort key]]', '[[Category:Test|sort key]]'),
+])
+def test_AddCategoryReplaceSortKeyAction_apply(wikitext, expected):
+ action = AddCategoryReplaceSortKeyAction('Test', 'sort key')
+ actual = action.apply(wikitext, ('Category', ['Category', 'Kategorie', 'K'], 'first-letter'))
+ assert expected == actual
+
+def test_AddCategoryReplaceSortKeyAction_apply_remove_sort_key():
+ action = AddCategoryReplaceSortKeyAction('Test', None)
+ wikitext = '[[Category:Test|sort key]]'
+ expected = '[[Category:Test]]'
+ actual = action.apply(wikitext, ('Category', ['Category', 'Kategorie', 'K'], 'first-letter'))
+ assert expected == actual
+
+def test_AddCategoryReplaceSortKeyAction_eq_same():
+ assert addCategoryReplaceSortKey1 == addCategoryReplaceSortKey1
+
+def test_AddCategoryReplaceSortKeyAction_eq_equal():
+ assert addCategoryReplaceSortKey1 == AddCategoryReplaceSortKeyAction(addCategoryReplaceSortKey1.category, addCategoryReplaceSortKey1.sort_key)
+
+def test_AddCategoryReplaceSortKeyAction_eq_different_type():
+ assert addCategoryReplaceSortKey1 != AddCategoryProvideSortKeyAction(addCategoryReplaceSortKey1.category, addCategoryReplaceSortKey1.sort_key)
+
+def test_AddCategoryReplaceSortKeyAction_eq_different_category():
+ assert addCategoryReplaceSortKey1 != AddCategoryReplaceSortKeyAction('Cat 2', addCategoryReplaceSortKey1.sort_key)
+
+def test_AddCategoryReplaceSortKeyAction_eq_different_sort_key():
+ assert addCategoryReplaceSortKey1 != AddCategoryReplaceSortKeyAction(addCategoryReplaceSortKey1.category, 'other sort key')
+
+def test_AddCategoryReplaceSortKeyAction_str():
+ assert str(addCategoryReplaceSortKey1) == '+Category:Cat 1###sort key'
+
+def test_AddCategoryReplaceSortKeyAction_repr():
+ assert eval(repr(addCategoryReplaceSortKey1)) == addCategoryReplaceSortKey1
+
+
@pytest.mark.parametrize('wikitext, expected', [
('', ''),
('[[Category:Test]]', ''),
('end of article\n[[Category:Test]]', 'end of article'),
('[[Category:Test]]\nbeginning of article', 'beginning of article'),
('[[Category:Start]][[Category:Test]][[Category:End]]', '[[Category:Start]][[Category:End]]'),
('[[Category:Start]]\n[[Category:Test]]\n[[Category:End]]', '[[Category:Start]]\n[[Category:End]]'),
('[[Category:test]]', ''),
('[[Kategorie:Test]]', ''),
('[[K:Test]]', ''),
('[[Category:Test|sort key]]', ''),
('[[:Category:Test]]', '[[:Category:Test]]'),
('[[:Category:Test|link text]]', '[[:Category:Test|link text]]'),
('[[Category:Test]]', '[[Category:Test]]'),
('[[Test]]', '[[Test]]'),
('[[Special:Test]]', '[[Special:Test]]'),
])
def test_RemoveCategoryAction_apply(wikitext, expected):
action = RemoveCategoryAction('Test')
actual = action.apply(wikitext, ('Category', ['Category', 'Kategorie', 'K'], 'first-letter'))
assert expected == actual
def test_RemoveCategoryAction_apply_case_sensitive():
action = RemoveCategoryAction('Test')
wikitext = '[[category:test]]'
assert wikitext == action.apply(wikitext, ('Category', ['Category'], 'case-sensitive'))
def test_RemoveCategoryAction_summary():
assert RemoveCategoryAction('Test').summary(('Kategorie', ['Kategorie', 'Category'])) == '-[[Kategorie:Test]]'
def test_RemoveCategoryAction_is_minor():
assert not RemoveCategoryAction('Test').is_minor()
def test_RemoveCategoryAction_cleanup():
action = RemoveCategoryAction('User_input_from_URL')
action.cleanup()
assert action == RemoveCategoryAction('User input from URL')
def test_RemoveCategoryAction_eq_same():
assert removeCategory1 == removeCategory1
def test_RemoveCategoryAction_eq_equal():
assert removeCategory1 == RemoveCategoryAction(removeCategory1.category)
def test_RemoveCategoryAction_eq_different_type():
assert removeCategory1 != AddCategoryAction(removeCategory1.category)
def test_RemoveCategoryAction_eq_different_category():
assert removeCategory1 != RemoveCategoryAction('Cat 2')
def test_RemoveCategoryAction_eq_different_category_normalization():
assert RemoveCategoryAction('Foo Bar') != RemoveCategoryAction('Foo_Bar')
def test_RemoveCategoryAction_str():
assert str(removeCategory1) == '-Category:Cat 1'
def test_RemoveCategoryAction_repr():
assert eval(repr(removeCategory1)) == removeCategory1
+
+
+def test_RemoveCategoryWithSortKeyAction_init_empty_sort_key():
+ with pytest.raises(AssertionError):
+ RemoveCategoryWithSortKeyAction('Category', '')
+
+def test_RemoveCategoryWithSortKeyAction_summary():
+ assert RemoveCategoryWithSortKeyAction('Test', 'Sortierschlüssel').summary(('Kategorie', ['Kategorie', 'Category'])) == '-[[Kategorie:Test|Kategorie:Test|Sortierschlüssel]]'
+
+@pytest.mark.parametrize('wikitext, expected', [
+ ('', ''),
+ ('[[Category:Test]]', '[[Category:Test]]'),
+ ('[[Category:Test|sort key]]', ''),
+])
+def test_RemoveCategoryWithSortKeyAction_apply(wikitext, expected):
+ action = RemoveCategoryWithSortKeyAction('Test', 'sort key')
+ actual = action.apply(wikitext, ('Category', ['Category', 'Kategorie', 'K'], 'first-letter'))
+ assert expected == actual
+
+def test_RemoveCategoryWithSortKeyAction_eq_same():
+ assert removeCategoryWithSortKey1 == removeCategoryWithSortKey1
+
+def test_RemoveCategoryWithSortKeyAction_eq_equal():
+ assert removeCategoryWithSortKey1 == RemoveCategoryWithSortKeyAction(removeCategoryWithSortKey1.category, removeCategoryWithSortKey1.sort_key)
+
+def test_RemoveCategoryWithSortKeyAction_eq_different_type():
+ assert removeCategoryWithSortKey1 != AddCategoryWithSortKeyAction(removeCategoryWithSortKey1.category, removeCategoryWithSortKey1.sort_key)
+
+def test_RemoveCategoryWithSortKeyAction_eq_different_category():
+ assert removeCategoryWithSortKey1 != RemoveCategoryWithSortKeyAction('Cat 2', removeCategoryWithSortKey1.sort_key)
+
+def test_RemoveCategoryWithSortKeyAction_eq_different_sort_key():
+ assert removeCategoryWithSortKey1 != RemoveCategoryWithSortKeyAction(removeCategoryWithSortKey1.category, 'other sort key')
+
+def test_RemoveCategoryWithSortKeyAction_str():
+ assert str(removeCategoryWithSortKey1) == '-Category:Cat 1#sort key'
+
+def test_RemoveCategoryWithSortKeyAction_repr():
+ assert eval(repr(removeCategoryWithSortKey1)) == removeCategoryWithSortKey1