| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | # |
|---|
| 3 | # Copyright (C) 2011 Odd Simon Simonsen <oddsimons@gmail.com> |
|---|
| 4 | # Copyright (C) 2012-2015 Steffen Hoffmann <hoff.st@web.de> |
|---|
| 5 | # Copyright (C) 2014 Jun Omae <jun66j5@gmail.com> |
|---|
| 6 | # Copyright (C) 2015 Ryan J Ollos <ryan.j.ollos@gmail.com> |
|---|
| 7 | # |
|---|
| 8 | # This software is licensed as described in the file COPYING, which |
|---|
| 9 | # you should have received as part of this distribution. |
|---|
| 10 | # |
|---|
| 11 | |
|---|
| 12 | import shutil |
|---|
| 13 | import tempfile |
|---|
| 14 | import unittest |
|---|
| 15 | |
|---|
| 16 | from trac.test import EnvironmentStub, Mock, MockRequest |
|---|
| 17 | from trac.util.text import to_unicode |
|---|
| 18 | from trac.web.chrome import Chrome |
|---|
| 19 | from trac.web.href import Href |
|---|
| 20 | from trac.wiki.test import wikisyntax_test_suite |
|---|
| 21 | |
|---|
| 22 | from tractags.db import TagSetup |
|---|
| 23 | from tractags.macros import TagWikiMacros, query_realms |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | def _revert_tractags_schema_init(env): |
|---|
| 27 | with env.db_transaction as db: |
|---|
| 28 | db("DROP TABLE IF EXISTS tags") |
|---|
| 29 | db("DROP TABLE IF EXISTS tags_change") |
|---|
| 30 | db("DELETE FROM system WHERE name='tags_version'") |
|---|
| 31 | db("DELETE FROM permission WHERE action %s" % db.like(), |
|---|
| 32 | ('TAGS_%',)) |
|---|
| 33 | |
|---|
| 34 | |
|---|
| 35 | def _insert_tags(env, tagspace, name, tags): |
|---|
| 36 | args = [(tagspace, name, tag) for tag in tags] |
|---|
| 37 | with env.db_transaction as db: |
|---|
| 38 | db.executemany(""" |
|---|
| 39 | INSERT INTO tags (tagspace,name,tag) VALUES (%s,%s,%s) |
|---|
| 40 | """, args) |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | class _BaseTestCase(unittest.TestCase): |
|---|
| 44 | |
|---|
| 45 | def setUp(self): |
|---|
| 46 | self.env = EnvironmentStub(default_data=True, |
|---|
| 47 | enable=['trac.*', 'tractags.*']) |
|---|
| 48 | self.env.path = tempfile.mkdtemp() |
|---|
| 49 | |
|---|
| 50 | setup = TagSetup(self.env) |
|---|
| 51 | # Current tractags schema is setup with enabled component anyway. |
|---|
| 52 | # Revert these changes for getting default permissions inserted. |
|---|
| 53 | self._revert_tractags_schema_init() |
|---|
| 54 | setup.upgrade_environment() |
|---|
| 55 | |
|---|
| 56 | def tearDown(self): |
|---|
| 57 | self.env.shutdown() |
|---|
| 58 | shutil.rmtree(self.env.path) |
|---|
| 59 | |
|---|
| 60 | def _revert_tractags_schema_init(self): |
|---|
| 61 | _revert_tractags_schema_init(self.env) |
|---|
| 62 | |
|---|
| 63 | def _insert_tags(self, tagspace, name, tags): |
|---|
| 64 | _insert_tags(self.env, tagspace, name, tags) |
|---|
| 65 | |
|---|
| 66 | |
|---|
| 67 | class TagTemplateProviderTestCase(_BaseTestCase): |
|---|
| 68 | |
|---|
| 69 | def setUp(self): |
|---|
| 70 | _BaseTestCase.setUp(self) |
|---|
| 71 | |
|---|
| 72 | # TagTemplateProvider is abstract, test using a subclass |
|---|
| 73 | self.tag_wm = TagWikiMacros(self.env) |
|---|
| 74 | |
|---|
| 75 | def test_template_dirs_added(self): |
|---|
| 76 | self.assertTrue(self.tag_wm in Chrome(self.env).template_providers) |
|---|
| 77 | |
|---|
| 78 | |
|---|
| 79 | class ListTaggedMacroTestCase(_BaseTestCase): |
|---|
| 80 | |
|---|
| 81 | def setUp(self): |
|---|
| 82 | _BaseTestCase.setUp(self) |
|---|
| 83 | self.req = MockRequest(self.env, path_info='/wiki/ListTaggedPage', |
|---|
| 84 | authname='user') |
|---|
| 85 | |
|---|
| 86 | self.tag_twm = TagWikiMacros(self.env) |
|---|
| 87 | |
|---|
| 88 | def test_empty_content(self): |
|---|
| 89 | context = Mock(env=self.env, href=Href('/'), req=self.req) |
|---|
| 90 | formatter = Mock(context=context, req=self.req) |
|---|
| 91 | self.assertTrue('No resources found' in |
|---|
| 92 | str(self.tag_twm.expand_macro(formatter, |
|---|
| 93 | 'ListTagged', ''))) |
|---|
| 94 | |
|---|
| 95 | def test_listtagged_exclude(self): |
|---|
| 96 | self._insert_tags('wiki', 'InterTrac', ('blah',)) |
|---|
| 97 | self._insert_tags('wiki', 'InterWiki', ('blah',)) |
|---|
| 98 | self._insert_tags('wiki', 'WikiStart', ('blah',)) |
|---|
| 99 | context = Mock(env=self.env, href=Href('/'), req=self.req) |
|---|
| 100 | formatter = Mock(context=context, req=self.req) |
|---|
| 101 | result = to_unicode(self.tag_twm.expand_macro(formatter, 'ListTagged', |
|---|
| 102 | 'blah,exclude=Inter*')) |
|---|
| 103 | self.assertFalse('InterTrac' in result) |
|---|
| 104 | self.assertFalse('InterWiki' in result) |
|---|
| 105 | self.assertTrue('WikiStart' in result) |
|---|
| 106 | |
|---|
| 107 | result = to_unicode(self.tag_twm.expand_macro(formatter, 'ListTagged', |
|---|
| 108 | 'blah,exclude=Wi*:*ki')) |
|---|
| 109 | self.assertTrue('InterTrac' in result) |
|---|
| 110 | self.assertFalse('InterWiki' in result) |
|---|
| 111 | self.assertFalse('WikiStart' in result) |
|---|
| 112 | |
|---|
| 113 | def _test_listtagged_paginate(self, page, per_page=2): |
|---|
| 114 | self._insert_tags('wiki', 'InterTrac', ('blah',)) |
|---|
| 115 | self._insert_tags('wiki', 'InterWiki', ('blah',)) |
|---|
| 116 | self._insert_tags('wiki', 'WikiStart', ('blah',)) |
|---|
| 117 | self.req.args['listtagged_per_page'] = per_page |
|---|
| 118 | self.req.args['listtagged_page'] = page |
|---|
| 119 | context = Mock(env=self.env, href=Href('/'), req=self.req) |
|---|
| 120 | formatter = Mock(context=context, req=self.req) |
|---|
| 121 | result = \ |
|---|
| 122 | to_unicode(self.tag_twm.expand_macro(formatter, 'ListTagged', 'blah')) |
|---|
| 123 | return result |
|---|
| 124 | |
|---|
| 125 | def test_listtagged_paginate_page1(self): |
|---|
| 126 | """Paginate results for page 1 has two items.""" |
|---|
| 127 | result = self._test_listtagged_paginate(1) |
|---|
| 128 | self.assertTrue('InterTrac' in result) |
|---|
| 129 | self.assertTrue('InterWiki' in result) |
|---|
| 130 | self.assertFalse('WikiStart' in result) |
|---|
| 131 | |
|---|
| 132 | def test_listtagged_paginate_page2(self): |
|---|
| 133 | """Paginate results for page 2 has one item.""" |
|---|
| 134 | result = self._test_listtagged_paginate(2) |
|---|
| 135 | self.assertFalse('InterTrac' in result) |
|---|
| 136 | self.assertFalse('InterWiki' in result) |
|---|
| 137 | self.assertTrue('WikiStart' in result) |
|---|
| 138 | |
|---|
| 139 | def test_listtagged_paginate_page_out_of_range(self): |
|---|
| 140 | """Out of range page defaults to 1.""" |
|---|
| 141 | result = self._test_listtagged_paginate(3) |
|---|
| 142 | self.assertTrue('InterTrac' in result) |
|---|
| 143 | self.assertTrue('InterWiki' in result) |
|---|
| 144 | self.assertFalse('WikiStart' in result) |
|---|
| 145 | |
|---|
| 146 | def test_listtagged_paginate_page_invalid(self): |
|---|
| 147 | """Invalid page default to 1.""" |
|---|
| 148 | result = self._test_listtagged_paginate(-1) |
|---|
| 149 | self.assertTrue('InterTrac' in result) |
|---|
| 150 | self.assertTrue('InterWiki' in result) |
|---|
| 151 | self.assertFalse('WikiStart' in result) |
|---|
| 152 | |
|---|
| 153 | def test_listtagged_paginate_per_page_invalid(self): |
|---|
| 154 | """Invalid per_page defaults to items_per_page (100).""" |
|---|
| 155 | result = self._test_listtagged_paginate(2, -1) |
|---|
| 156 | self.assertTrue('InterTrac' in result) |
|---|
| 157 | self.assertTrue('InterWiki' in result) |
|---|
| 158 | self.assertTrue('WikiStart' in result) |
|---|
| 159 | |
|---|
| 160 | |
|---|
| 161 | LISTTAGGED_MACRO_TEST_CASES = u""" |
|---|
| 162 | ============================== invalid operator |
|---|
| 163 | [[ListTagged(xyz:wiki xyz)]] |
|---|
| 164 | ------------------------------ |
|---|
| 165 | <p> |
|---|
| 166 | </p><div class="system-message">\ |
|---|
| 167 | <strong>ListTagged macro error</strong>\ |
|---|
| 168 | <pre>Invalid attribute \'xyz\'</pre>\ |
|---|
| 169 | </div><p> |
|---|
| 170 | </p> |
|---|
| 171 | ============================== invalid realm |
|---|
| 172 | [[ListTagged(realm:xyz blah)]] |
|---|
| 173 | ------------------------------ |
|---|
| 174 | <p> |
|---|
| 175 | </p><div class="system-message">\ |
|---|
| 176 | <strong>ListTagged macro error</strong>\ |
|---|
| 177 | <pre>Tags are not supported on the \'xyz\' realm</pre>\ |
|---|
| 178 | </div><p> |
|---|
| 179 | </p> |
|---|
| 180 | """ |
|---|
| 181 | |
|---|
| 182 | |
|---|
| 183 | def listtagged_setup(tc): |
|---|
| 184 | _revert_tractags_schema_init(tc.env) |
|---|
| 185 | TagSetup(tc.env).upgrade_environment() |
|---|
| 186 | _insert_tags(tc.env, 'wiki', 'WikiStart', ('abc', 'xyz')) |
|---|
| 187 | |
|---|
| 188 | |
|---|
| 189 | def listtagged_teardown(tc): |
|---|
| 190 | _revert_tractags_schema_init(tc.env) |
|---|
| 191 | |
|---|
| 192 | |
|---|
| 193 | class TagCloudMacroTestCase(_BaseTestCase): |
|---|
| 194 | |
|---|
| 195 | def setUp(self): |
|---|
| 196 | _BaseTestCase.setUp(self) |
|---|
| 197 | self.req = MockRequest(self.env, path_info='/wiki/TagCloudPage', |
|---|
| 198 | authname='user') |
|---|
| 199 | self.context = Mock(env=self.env, href=self.req.href, req=self.req) |
|---|
| 200 | self.formatter = Mock(context=self.context, req=self.req) |
|---|
| 201 | |
|---|
| 202 | self.tag_twm = TagWikiMacros(self.env) |
|---|
| 203 | |
|---|
| 204 | # Helpers |
|---|
| 205 | |
|---|
| 206 | def _expand_macro(self, content): |
|---|
| 207 | return self.tag_twm.expand_macro(self.formatter, 'TagCloud', content) |
|---|
| 208 | |
|---|
| 209 | # Tests |
|---|
| 210 | |
|---|
| 211 | def test_normal(self): |
|---|
| 212 | self._insert_tags('wiki', 'CamelCase', ('blah', 'foo', 'bar')) |
|---|
| 213 | self._insert_tags('wiki', 'InterMapTxt', ('blah', 'foo', 'bar')) |
|---|
| 214 | self._insert_tags('wiki', 'InterTrac', ('blah',)) |
|---|
| 215 | self._insert_tags('wiki', 'InterWiki', ('blah',)) |
|---|
| 216 | self._insert_tags('wiki', 'PageTemplates', ('blah',)) |
|---|
| 217 | self._insert_tags('wiki', 'RecentChanges', ('blah', 'foo')) |
|---|
| 218 | self._insert_tags('wiki', 'SandBox', ('blah', 'foo')) |
|---|
| 219 | self._insert_tags('ticket', '1', ('blah',)) |
|---|
| 220 | self._insert_tags('ticket', '2', ('blah', 'bar')) |
|---|
| 221 | self._insert_tags('ticket', '3', ('blah', 'bar')) |
|---|
| 222 | self._insert_tags('ticket', '4', ('blah', 'bar')) |
|---|
| 223 | |
|---|
| 224 | result = to_unicode(self._expand_macro('')) |
|---|
| 225 | self.assertTrue('">blah</a>' in result, repr(result)) |
|---|
| 226 | self.assertTrue('">foo</a>' in result, repr(result)) |
|---|
| 227 | self.assertTrue('">bar</a>' in result, repr(result)) |
|---|
| 228 | |
|---|
| 229 | result = to_unicode(self._expand_macro('mincount=5')) |
|---|
| 230 | self.assertTrue('">blah</a>' in result, repr(result)) |
|---|
| 231 | self.assertFalse('">foo</a>' in result, repr(result)) |
|---|
| 232 | self.assertTrue('">bar</a>' in result, repr(result)) |
|---|
| 233 | |
|---|
| 234 | result = to_unicode(self._expand_macro('mincount=6')) |
|---|
| 235 | self.assertTrue('">blah</a>' in result, repr(result)) |
|---|
| 236 | self.assertFalse('">foo</a>' in result, repr(result)) |
|---|
| 237 | self.assertFalse('">bar</a>' in result, repr(result)) |
|---|
| 238 | |
|---|
| 239 | result = to_unicode(self._expand_macro('realm=ticket|wiki')) |
|---|
| 240 | self.assertTrue('">blah</a>' in result, repr(result)) |
|---|
| 241 | self.assertTrue('">foo</a>' in result, repr(result)) |
|---|
| 242 | self.assertTrue('">bar</a>' in result, repr(result)) |
|---|
| 243 | |
|---|
| 244 | result = to_unicode(self._expand_macro('realm=ticket')) |
|---|
| 245 | self.assertTrue('">blah</a>' in result, repr(result)) |
|---|
| 246 | self.assertFalse('">foo</a>' in result, repr(result)) |
|---|
| 247 | self.assertTrue('">bar</a>' in result, repr(result)) |
|---|
| 248 | |
|---|
| 249 | result = to_unicode(self._expand_macro('realm=ticket,mincount=4')) |
|---|
| 250 | self.assertTrue('">blah</a>' in result, repr(result)) |
|---|
| 251 | self.assertFalse('">foo</a>' in result, repr(result)) |
|---|
| 252 | self.assertFalse('">bar</a>' in result, repr(result)) |
|---|
| 253 | |
|---|
| 254 | result = to_unicode(self._expand_macro('realm=unknown')) |
|---|
| 255 | self.assertEquals('No tags found', result) |
|---|
| 256 | |
|---|
| 257 | result = to_unicode(self._expand_macro('mincount=100')) |
|---|
| 258 | self.assertEquals('No tags found', result) |
|---|
| 259 | |
|---|
| 260 | |
|---|
| 261 | class QueryRealmsTestCase(unittest.TestCase): |
|---|
| 262 | def test_query_realms(self): |
|---|
| 263 | all_realms = ['ticket', 'wiki'] |
|---|
| 264 | # No tag providers detected. |
|---|
| 265 | self.assertFalse('ticket' in query_realms('', [])) |
|---|
| 266 | # No tags query statement used. |
|---|
| 267 | self.assertFalse('ticket' in query_realms('', all_realms)) |
|---|
| 268 | self.assertFalse('ticket' in query_realms('ticket', all_realms)) |
|---|
| 269 | self.assertFalse('ticket' in query_realms('realm:ticket', ['wiki'])) |
|---|
| 270 | self.assertTrue('ticket' in query_realms('realm:ticket', all_realms)) |
|---|
| 271 | self.assertFalse('wiki' in query_realms('realm:ticket', all_realms)) |
|---|
| 272 | self.assertTrue('wiki' in |
|---|
| 273 | query_realms('onetag realm:wiki 2ndtag', all_realms)) |
|---|
| 274 | self.assertFalse('wiki' in |
|---|
| 275 | query_realms('onetag realm=wiki 2ndtag', all_realms)) |
|---|
| 276 | |
|---|
| 277 | |
|---|
| 278 | def test_suite(): |
|---|
| 279 | suite = unittest.TestSuite() |
|---|
| 280 | suite.addTest(unittest.makeSuite(TagTemplateProviderTestCase)) |
|---|
| 281 | suite.addTest(unittest.makeSuite(ListTaggedMacroTestCase)) |
|---|
| 282 | suite.addTest( |
|---|
| 283 | wikisyntax_test_suite(LISTTAGGED_MACRO_TEST_CASES, listtagged_setup, |
|---|
| 284 | __file__, listtagged_teardown, |
|---|
| 285 | enable_components=('trac.*', 'tractags.*'))) |
|---|
| 286 | suite.addTest(unittest.makeSuite(TagCloudMacroTestCase)) |
|---|
| 287 | suite.addTest(unittest.makeSuite(QueryRealmsTestCase)) |
|---|
| 288 | return suite |
|---|
| 289 | |
|---|
| 290 | |
|---|
| 291 | if __name__ == '__main__': |
|---|
| 292 | unittest.main(defaultTest='test_suite') |
|---|