Zim

Merge lp:~fenryxo/zim/custom-objects into lp:~jaap.karssenberg/zim/custom-objects

Proposed by Jiří Janoušek
Status: Merged
Merged at revision: 363
Proposed branch: lp:~fenryxo/zim/custom-objects
Merge into: lp:~jaap.karssenberg/zim/custom-objects
Diff against target: 69216 lines (+18457/-10579)
152 files modified
.bzrignore (+2/-0)
CHANGELOG.txt (+35/-2)
HACKING/Release_checklist.txt (+27/-13)
HACKING/Start.txt (+6/-0)
HACKING/Test_Suite.txt (+19/-0)
MANIFEST.in (+1/-1)
Makefile (+6/-0)
README.txt (+1/-1)
data/dates.list (+3/-2)
data/manual/Help.txt (+1/-0)
data/manual/Help/Config_Files.txt (+4/-0)
data/manual/Help/Key_Bindings.txt (+82/-81)
data/manual/Help/Pages.txt (+6/-0)
data/manual/Help/Searching.txt (+9/-0)
data/manual/Help/Tags.txt (+13/-0)
data/manual/Help/Templates.txt (+27/-15)
data/manual/Plugins.txt (+3/-0)
data/manual/Plugins/Gnuplot_Editor.txt (+21/-0)
data/manual/Plugins/Gnuplot_Editor/gnuplot.gnu (+1/-0)
data/manual/Plugins/Spell_Checker.txt (+4/-1)
data/manual/Plugins/Tags.txt (+13/-0)
data/manual/Plugins/Task_List.txt (+1/-1)
data/menubar.xml (+5/-1)
data/style.conf (+3/-0)
data/templates/_gnuplot.gnu (+5/-0)
data/urls.list (+1/-1)
debian/changelog (+12/-0)
debian/control (+1/-1)
debian/pyversions (+1/-1)
msgfmt.py (+0/-1)
test.py (+29/-129)
tests/__init__.py (+316/-193)
tests/applications.py (+6/-8)
tests/async.py (+31/-1)
tests/calendar.py (+5/-6)
tests/config.py (+36/-19)
tests/daemon.py (+4/-13)
tests/data/notebook-wiki.xml (+38/-0)
tests/diagrameditor.py (+4/-11)
tests/equationeditor.py (+4/-11)
tests/export.py (+25/-30)
tests/formats.py (+58/-34)
tests/fs.py (+44/-16)
tests/gui.py (+183/-37)
tests/history.py (+5/-3)
tests/index.py (+71/-56)
tests/inlinecalculator.py (+3/-6)
tests/notebook.py (+75/-48)
tests/package.py (+70/-26)
tests/pageview.py (+105/-101)
tests/parsing.py (+1/-1)
tests/plugins.py (+7/-4)
tests/printtobrowser.py (+4/-6)
tests/search.py (+31/-27)
tests/stores.py (+43/-16)
tests/tags.py (+357/-0)
tests/tasklist.py (+19/-10)
tests/templates.py (+20/-16)
tests/versioncontrol.py (+13/-20)
tests/widgets.py (+138/-49)
tests/www.py (+5/-7)
tools/import-launchpad-translations.py (+1/-1)
translations/ca.po (+466/-324)
translations/cs.po (+491/-327)
translations/da.po (+801/-509)
translations/de.po (+496/-324)
translations/el.po (+462/-320)
translations/en_GB.po (+460/-318)
translations/es.po (+505/-332)
translations/et.po (+477/-334)
translations/fr.po (+491/-323)
translations/he.po (+536/-354)
translations/hr.po (+4/-4)
translations/hu.po (+465/-322)
translations/it.po (+514/-347)
translations/ja.po (+462/-320)
translations/ko.po (+4/-4)
translations/nl.po (+493/-321)
translations/pl.po (+465/-323)
translations/ru.po (+809/-626)
translations/sk.po (+464/-327)
translations/sl.po (+515/-331)
translations/sv.po (+486/-341)
translations/tr.po (+469/-326)
translations/uk.po (+465/-323)
translations/zh_CN.po (+564/-376)
translations/zh_TW.po (+464/-322)
translations/zim.pot (+481/-344)
website/files/zim.css (+1/-0)
website/pages/downloads.txt (+1/-1)
zim.py (+1/-1)
zim/__init__.py (+21/-8)
zim/applications.py (+33/-6)
zim/async.py (+104/-17)
zim/config.py (+47/-15)
zim/daemon.py (+9/-9)
zim/errors.py (+7/-1)
zim/exporter.py (+19/-7)
zim/formats/__init__.py (+69/-28)
zim/formats/html.py (+2/-0)
zim/formats/latex.py (+3/-0)
zim/formats/wiki.py (+10/-0)
zim/fs.py (+118/-57)
zim/gui/__init__.py (+165/-61)
zim/gui/applications.py (+3/-3)
zim/gui/cleannotebookdialog.py (+2/-2)
zim/gui/clipboard.py (+38/-30)
zim/gui/customtools.py (+4/-5)
zim/gui/exportdialog.py (+4/-4)
zim/gui/imagegeneratordialog.py (+2/-2)
zim/gui/notebookdialog.py (+59/-60)
zim/gui/pageindex.py (+134/-116)
zim/gui/pageview.py (+364/-72)
zim/gui/pathbar.py (+6/-4)
zim/gui/preferencesdialog.py (+78/-20)
zim/gui/propertiesdialog.py (+1/-2)
zim/gui/searchdialog.py (+1/-1)
zim/gui/server.py (+1/-1)
zim/gui/widgets.py (+369/-135)
zim/history.py (+1/-1)
zim/index.py (+546/-80)
zim/notebook.py (+430/-179)
zim/objectmanager.py (+75/-27)
zim/parsing.py (+6/-7)
zim/plugins/__init__.py (+26/-15)
zim/plugins/attachmentbrowser.py (+13/-13)
zim/plugins/calendar.py (+1/-1)
zim/plugins/diagrameditor.py (+3/-2)
zim/plugins/equationeditor.py (+5/-3)
zim/plugins/gnu_r_ploteditor.py (+2/-1)
zim/plugins/gnuplot_ploteditor.py (+145/-0)
zim/plugins/inlinecalculator.py (+1/-1)
zim/plugins/linesorter.py (+106/-0)
zim/plugins/linkmap/__init__.py (+10/-2)
zim/plugins/linkmap/gui.py (+4/-2)
zim/plugins/quicknote.py (+12/-3)
zim/plugins/screenshot.py (+4/-3)
zim/plugins/sourceview.py (+5/-1)
zim/plugins/spell.py (+16/-3)
zim/plugins/tags.py (+817/-0)
zim/plugins/tasklist.py (+13/-25)
zim/plugins/trayicon.py (+55/-26)
zim/plugins/versioncontrol/__init__.py (+3/-2)
zim/plugins/versioncontrol/bzr.py (+5/-7)
zim/search.py (+18/-10)
zim/stores/__init__.py (+26/-11)
zim/stores/files.py (+25/-5)
zim/stores/gjots.py (+3/-3)
zim/stores/memory.py (+7/-3)
zim/stores/xml.py (+1/-1)
zim/templates.py (+10/-11)
zim/www.py (+14/-14)
To merge this branch: bzr merge lp:~fenryxo/zim/custom-objects
Reviewer Review Type Date Requested Status
Jaap Karssenberg Pending
Review via email: mp+63476@code.launchpad.net

Description of the change

Pushing my changes:
* Resolved conflicts with trunk.
* SourceView plugin ported to the new style dependency check.
* Fixed KeyError when fallback object factory is used.
* Fixed bug when export of Code Block failed in non-GUI mode.
* If there is an inactive plugin for an unknown object a button
  is shown to activate plugin easily.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2010-05-23 23:14:12 +0000
3+++ .bzrignore 2011-06-04 21:27:03 +0000
4@@ -15,6 +15,8 @@
5 ./debian/pycompat
6 ./man
7 ./html
8+./apidoc
9 ./windows/build
10 ./windows/version-and-date.nsi
11 ./xdg/hicolor
12+
13
14=== modified file 'CHANGELOG.txt'
15--- CHANGELOG.txt 2011-02-19 16:27:44 +0000
16+++ CHANGELOG.txt 2011-06-04 21:27:03 +0000
17@@ -5,6 +5,37 @@
18 Earlier version numbers for zim correspond to the Perl branch.
19
20
21+=== 0.51 - Thu 28 Apr 2011 ===
22+Bug fix release
23+* Fixed a critical bug in the "Add Notebook" prompt for the first notebook on
24+ a fresh install and two minor bugs with the ntoebook list - Jiří Janoušek
25+
26+
27+=== 0.51 - Tue 19 Apr 2011 ===
28+* Fixed critical bug with resizing images - Stefan Muthers
29+* Fixed bug preventing resizing of text entries in dialogs
30+* Fixed bug disabling auto-completion for page names in dialogs
31+* Fix so cancelling the preferences dialog will also reset plugins
32+ - Lisa Vitolo
33+* Fix to switch sensitivity of items in the Edit menu on cursor position
34+ - Konstantin Baierer
35+* Fix to handle case where document_root is inside notebook folder
36+ - Jiří Janoušek
37+* Fixed support for interwiki links in export
38+* Fixed "Link Map" plugin to actually support clicking on page names in the map
39+* Fixed copy pasting to use plain text by default for external applications
40+ added preference to revert to old behavior
41+* Disable <Alt><Space> keybinding due to conflicts with internationalization
42+ added hidden preference to get it back if desired
43+* Added support for organizing pages by tags - Fabian Moser
44+* Added feature to zoom font size of the page view on <Ctrl>+ / <Ctrl>-
45+ - Konstantin Baierer
46+* Added support for system Trash (using gio if available)
47+* Added Calendar widget to the "Insert Date" dialog
48+* Added plugin to sort selected lines - NorfCran
49+* Added plugin for GNUplot plots - Alessandro Magni
50+
51+
52 === 0.50 - Mon 14 Feb 2011 ===
53 Maintenance release with many bug fixes. Biggest change is the refactoring
54 of input forms and dialogs, but this is not very visible to the user.
55@@ -191,9 +222,11 @@
56 * Added a web-based interface to read zim notebooks
57 * Task List now supports tags
58 * Distinguishing between "move page" and "rename page"
59-* Menu actions like "Rename Page (F2)" now follow the focus and work in the side pane as well
60+* Menu actions like "Rename Page (F2)" now follow the focus and work in the
61+ side pane as well
62 * Page title can be updated automatically when moving a page
63-* "Link" action behaves more like inserting an object instead of applying formatting
64+* "Link" action behaves more like inserting an object instead of applying
65+ formatting
66 * File links are now inserted showing only the basename of the file
67 * Dialogs spawned from another dialog will pop over it
68 * Dialogs remember their window size
69
70=== modified file 'HACKING/Release_checklist.txt'
71--- HACKING/Release_checklist.txt 2011-02-19 16:27:44 +0000
72+++ HACKING/Release_checklist.txt 2011-06-04 21:27:03 +0000
73@@ -13,34 +13,34 @@
74
75 Merge translations:
76 * Request download from launchpad
77-* Merge it with tools/import-launchpad-translations.py
78+* Merge it with ''tools/import-launchpad-translations.py''
79
80 Prepare the package:
81 * Set version in ''zim/__init__.py''
82-* Update CHANGELOG.txt -- see `bzr visualize` for changes
83-* Update debian changes -- run e.g. `debchange -v 0.46`
84+* Update CHANGELOG.txt -- see `''bzr visualize''` for changes
85+* Update debian changes -- run e.g. `''debchange -v 0.46''`
86 * Optionally merge branch with website updates since previous release
87 * Update version number in website downloads page
88
89 Check the package:
90-* `./setup.py sdist` (updates meta data etc.)
91-* `make builddeb` and check `lintian -Ivi ../zim_0.46_i386.changes`
92+* `''./setup.py sdist''` (updates meta data etc.)
93+* `make builddeb` and check `''lintian -Ivi ../zim_0.46_i386.changes''`
94 * Test website with ./tools/test_website.py
95-* Run `make clean` and check `bzr st` for any remaining build files
96+* Run `''make clean''` and check `''bzr st''` for any remaining build files
97
98 Finalize the revision:
99-* run ./test.py for the last time
100+* run ''./test.py'' for the last time
101
102 * commit + tag + push
103
104 Build release packages:
105-* `./setup.py sdist` (updates meta data etc.)
106-* `make builddeb` + `make clean`
107-* ./tools/build_website.sh
108+* `''./setup.py sdist''` (updates meta data etc.)
109+* `''make builddeb''` + `''make clean''`
110+* ''./tools/build_website.sh''
111
112 Publish to launchpad PPA:
113-* debuild -S -kB3223C82
114-* dput ppa:jaap.karssenberg/zim zim_XX_sources.changes
115+* ''debuild -S -kB3223C82''
116+* ''dput ppa:jaap.karssenberg/zim ../zim_XX_sources.changes''
117
118 Publish the release:
119 * Upload website
120@@ -48,5 +48,19 @@
121 * Write release notes
122 * Announce on freshmeat
123 * Announce on launchpad
124-* Announce on gnome files
125+* ~~Announce on gnome files~~
126 * Announce on mailing list
127+
128+
129+**For snapshots**
130+* `''./setup.py sdist`'' to update build meta data
131+* ''debchange -v 0.50-SNASPSHOT-r359''
132+* ''debuild -S -kB3223C82''
133+* ''lintian -Ivi ../zim_0.46_i386.changes''
134+* ''dput ppa:jaap.karssenberg/zim-snapshots ../zim_XX_sources.changes''
135+
136+To check version numbering is OK use:
137+
138+'''
139+dpkg --compare-versions "0.51" gt "0.50-SNAPSHOT-r345" && echo OK
140+'''
141
142=== modified file 'HACKING/Start.txt'
143--- HACKING/Start.txt 2010-01-31 11:22:31 +0000
144+++ HACKING/Start.txt 2011-06-04 21:27:03 +0000
145@@ -24,6 +24,12 @@
146
147 ===== Classes =====
148
149+**NOTE: the overview below is limitted and partially out of date. To generate a full set of API docs install "epydoc" [1] and run "make epydoc" in the zim source dir**
150+
151+[1] http://epydoc.sourceforge.net/
152+
153+-----
154+
155 Each class has inline documentation, use pydoc to view it.
156 The tree below is only a summary, run "dev/class_tree.py" to see
157 the full tree.
158
159=== added file 'HACKING/Test_Suite.txt'
160--- HACKING/Test_Suite.txt 1970-01-01 00:00:00 +0000
161+++ HACKING/Test_Suite.txt 2011-06-04 21:27:03 +0000
162@@ -0,0 +1,19 @@
163+Content-Type: text/x-zim-wiki
164+Wiki-Format: zim 0.4
165+Creation-Date: 2011-05-13T23:18:07+02:00
166+
167+====== Test Suite ======
168+
169+Zim comes with a full test suite, it can be executed using the "''test.py''" script. See "''test.py --help''" for it's commandline options.
170+
171+It is good practice to run the full suite before committing to a development branch and especially before generating a merge request. This should ensures the new patch doesn't break any existing code.
172+
173+For any but the most trivial fixes test cases should be written to ensure the functionality works as designed and to avoid breaking it again at a later time. You'll surprise how often the same bug comes back after some time if there is now test case is in place to detect it. Some bugs are just waiting to happen again and again.
174+
175+For writing tests have a look at the existing test code or check the documentation for the "unittest" module in the python library. (For python versions < 2.7 we use the "unittest2" module, which backports some new features for older python versions.)
176+
177+A most useful tool for developing tests is looking at test **coverage**. When you run "''test.py''" with the "''--coverage''" option the "coverage" module will be loaded and a set of html pages will be generated in "''./coverage''". In these pages you can see line by line what code is called during the test run and what lines of code go untested. It is hard to really get to 100% coverage, but the target should be to get the coverage above at least 80% for each module.
178+
179+If you added e.g. a new class and wrote a test case for it have a look at the coverage to see what additional tests are needed to cover all code.
180+
181+Of course having full coverage is no guarantee we cover all possible inputs, but looking at coverage combined with writing tests for reported bugs makes a strong test suite. Even if the test suite only catches the most simple bugs that users would see when first using the application it is worth the effort.
182
183=== modified file 'MANIFEST.in'
184--- MANIFEST.in 2010-07-22 21:33:10 +0000
185+++ MANIFEST.in 2011-06-04 21:27:03 +0000
186@@ -10,7 +10,7 @@
187 recursive-include tools/ *
188 recursive-include xdg/ *
189 prune xdg/hicolor/
190-recursive-include po/ *
191+recursive-include translations/ *
192 recursive-include cgi-bin/ *
193 recursive-include contrib/ *
194 recursive-include HACKING/ *
195
196=== modified file 'Makefile'
197--- Makefile 2010-06-24 20:27:50 +0000
198+++ Makefile 2011-06-04 21:27:03 +0000
199@@ -13,6 +13,7 @@
200 @echo "make source - Create source package"
201 @echo "make buildrpm - Generate a rpm package"
202 @echo "make builddeb - Generate a deb package"
203+ @echo "make epydoc - Generate API docs using 'epydoc'"
204 @echo "make clean - Get rid of scratch and byte files"
205
206 source:
207@@ -31,6 +32,11 @@
208 dpkg-buildpackage -i -I -rfakeroot
209 $(MAKE) -f $(CURDIR)/debian/rules clean
210
211+epydoc:
212+ rm -fr ./apidoc
213+ epydoc --html zim --graph umlclasstree -o ./apidoc --parse-only --no-private
214+ @echo -e '\nAPI docs are available in ./apidoc'
215+
216 clean:
217 $(PYTHON) setup.py clean
218 rm -rf build/ MANIFEST tests/tmp/ locale/ man/ xdg/hicolor
219
220=== modified file 'README.txt'
221--- README.txt 2011-02-19 16:27:44 +0000
222+++ README.txt 2011-06-04 21:27:03 +0000
223@@ -20,7 +20,7 @@
224
225 ====== COPYRIGHT ======
226
227-Copyright 2008, 2009 Jaap Karssenberg <jaap.karssenberg@gmail.com>
228+Copyright 2008, 2011 Jaap Karssenberg <jaap.karssenberg@gmail.com>
229
230 This program is free software; you can redistribute it and/or modify
231 it under the terms of the GNU General Public License as published by
232
233=== modified file 'data/dates.list'
234--- data/dates.list 2009-08-15 15:02:30 +0000
235+++ data/dates.list 2011-06-04 21:27:03 +0000
236@@ -1,9 +1,10 @@
237 # List with date-time formats used for the
238 # "Insert Date eand Time" dialog.
239 # See man strftime a description of the format.
240+%x
241 %c
242 %A %d/%m/%Y
243 %A %d/%m/%Y %H:%M
244 %A %d %B %Y
245-%x
246-%F
247+[d: %Y-%m-%d]
248+%Y-%m-%d
249
250=== modified file 'data/manual/Help.txt'
251--- data/manual/Help.txt 2010-07-08 20:29:24 +0000
252+++ data/manual/Help.txt 2011-06-04 21:27:03 +0000
253@@ -13,6 +13,7 @@
254 * [[+Notebooks|Notebooks]]
255 * [[+Pages|Pages]]
256 * [[+Links|Links]]
257+* [[+Tags|Tags]]
258
259 Editing
260 * [[+Key Bindings|Key Bindings]]
261
262=== modified file 'data/manual/Help/Config_Files.txt'
263--- data/manual/Help/Config_Files.txt 2011-02-14 20:22:50 +0000
264+++ data/manual/Help/Config_Files.txt 2011-06-04 21:27:03 +0000
265@@ -30,6 +30,8 @@
266
267 The config file is written automatically when you close zim. So if you want to change it manually you need to close all instances of zim first.
268
269+There is a hidden option here called "''autosave_timeout''" which gives the interval for autosaving in seconds, default is 10.
270+
271 ==== Interwiki URL list ====
272 The file ''XDG_DATA/zim/urls.list'' gives a list of urls which are used for the [[Links|interwiki]] function. All files in the XDG_DATA path are read when looking for an url, so you can use XDG_DATA_HOME to overload the installation defaults.
273
274@@ -118,3 +120,5 @@
275 There is a notebook specific config files called "''notebook.zim''" which should be in the notebook folder. This file contains a section "''[Notebook]''" which contains the properties that can be set in the [[properties|properties dialog]].
276
277 There is one hidden property, called "''end_of_line''" which determines the end-of-line convention for files written by zim within the scope of this notebook. The value can be either "''dos''" or "''unix''". For newly created notebooks this value is set depending on the platform on which zim is running. Main purpose of this property is to ensure that a notebook which is shared between e.g. linux and windows machines does not change the full file on every write. When desired the property can be changed manually, which will affect all pages edited after the change.
278+
279+A second hidden option is "''disable_trash''" which defaults to ''False''. If enabled this will cause zim to avoid using the system trash for this notebook, see the section about deleting in [[Pages]].
280
281=== modified file 'data/manual/Help/Key_Bindings.txt'
282--- data/manual/Help/Key_Bindings.txt 2010-01-19 18:41:47 +0000
283+++ data/manual/Help/Key_Bindings.txt 2011-06-04 21:27:03 +0000
284@@ -10,103 +10,104 @@
285
286 '''
287 F9 Toggle index visibility
288-alt-space Toggle focus between index and buffer
289+<Ctrl><Space> Toggle focus between index and buffer
290 opens side pane if index is invisible
291-ctrl-space Same as ctrl-space - optional see preferences
292-ctrl-tab Focus next inteface element (gtk default)
293-'''
294-
295-
296-'''
297-alt-home Go to the home page
298-alt-left Go one page back in history
299-alt-right Go one page forward in history
300-alt-up Go one page up in the namespace
301-alt-down Go one page down in the namespace
302+ (optional see preferences)
303+<Ctrl><Tab> Focus next inteface element (gtk default)
304+'''
305+
306+
307+'''
308+<Alt><Home> Go to the home page
309+<Alt><Left> Go one page back in history
310+<Alt><Right> Go one page forward in history
311+<Alt><Up> Go one page up in the namespace
312+<Alt><Down> Go one page down in the namespace
313 (The actual page is choosen by the history)
314-alt-pgup Go to the previous page in the index
315-alt-pgdown Go to the next page in the index
316-alt-D Go to todays page
317-'''
318-
319-
320-'''
321-^Q Quit the application
322-^w Close window
323-'''
324-
325-
326-'''
327-^F Find in the current page
328-^G Find next
329-shift-^G Find previous
330-shift-^F Search in all pages
331-^H Find and Replace
332-'''
333-
334-
335-'''
336-^S Save page (forced)
337-shift-^S Save version...
338-^R Reload page (saves first)
339-^J Jump to page... (either an existing or a new page)
340-'''
341-
342-
343-'''
344-^L Link selected text
345+<Alt><PgUp> Go to the previous page in the index
346+<Alt><PgDown> Go to the next page in the index
347+<Alt>D Go to todays page
348+'''
349+
350+
351+'''
352+<Ctrl>Q Quit the application
353+<Ctrl>w Close window
354+'''
355+
356+
357+'''
358+<Ctrl>F Find in the current page
359+<Ctrl>G Find next
360+<Shift><Ctrl>G Find previous
361+<Shift><Ctrl>F Search in all pages
362+<Ctrl>H Find and Replace
363+'''
364+
365+
366+'''
367+<Ctrl>S Save page (forced)
368+<Shift><Ctrl>S Save version...
369+<Ctrl>R Reload page (saves first)
370+<Ctrl>J Jump to page... (either an existing or a new page)
371+'''
372+
373+
374+'''
375+<Ctrl>L Link selected text
376 Follow selected text as link when read-only
377-shift-^L Copy a link to the current page to the clipboard
378+<Shift><Ctrl>L Copy a link to the current page to the clipboard
379 In the side pane copies a link to the selected page
380- (Paste this link in a page with ^V)
381-^E Show the "edit link" dialog
382-^D Inserts timestamp
383-'''
384-
385-
386-'''
387-^1..^5 Make selected text a heading
388-^6 Make selected text normal
389-^B Make selected text strong
390-^I Make selected text italic
391-^U Make selected text underline (renders highlighted)
392-^K Make selected text strike-trough
393-^T Make selected text verbatim text (monospace font)
394-'''
395-
396-
397-'''
398-^Z Undo
399-Shift-^Z Redo
400-^Y Redo
401-'''
402-
403-
404-'''
405-shift-^D Show the calendar dialog
406+ (Paste this link in a page with <Ctrl>V)
407+<Ctrl>E Show the "edit link" dialog
408+<Ctrl>D Inserts timestamp
409+'''
410+
411+
412+'''
413+<Ctrl>1..<Ctrl>5 Make selected text a heading
414+<Ctrl>9 Make selected text normal
415+<Ctrl>B Make selected text strong
416+<Ctrl>I Make selected text italic
417+<Ctrl>U Make selected text underline (renders highlighted)
418+<Ctrl>K Make selected text strike-trough
419+<Ctrl>T Make selected text verbatim text (monospace font)
420+'''
421+
422+
423+'''
424+<Ctrl>Z Undo
425+<Shift><Ctrl>Z Redo
426+<Ctrl>Y Redo
427+'''
428+
429+
430+'''
431+<Shift><Ctrl>D Show the calendar dialog
432 '''
433
434
435 '''
436 F1 Show the manual
437 F2 Rename current page
438-F3 Find next (same as ^G)
439-F5 Reload page (same as ^R)
440+F3 Find next (same as <Ctrl>G)
441+<Shift>F3 Find previous (same as <Ctrl>G)
442+F5 Reload page (same as <Ctrl>R)
443 F12 Toggle checkbox item to 'OK'
444-Shift-F12 Toggle checkbox item to 'NOK'
445+<Shift>F12 Toggle checkbox item to 'NOK'
446 '''
447
448 Also all the usual keybindings apply for the gtk text edit widget, thus bindings like
449-''^C'', ''^X'', ''^V'', ''^A'' etc. work as expected.
450+''<Ctrl>C'', ''<Ctrl>X'', ''<Ctrl>V'', ''<Ctrl>A'' etc. work as expected.
451
452 ==== Side pane tree ====
453 The following key bindings works when the tree in the side pane is focussed:
454
455 '''
456-^L Insert a link to the selected page
457-shift-^L Copy the selected page to clipboard
458-^C Copy the selected page to clipboard
459-^F Search in the page list as shown
460+<Ctrl>L Insert a link to the selected page
461+<Shift><Ctrl>L Copy the selected page to clipboard
462+<Ctrl>C Copy the selected page to clipboard
463+<Ctrl>F Search in the page list as shown
464 * Expand all
465 \ Collapse all
466 '''
467@@ -118,9 +119,9 @@
468 '''
469 * Toggle bullets for selected text
470 > Toggle email-style quoting for selected text
471-TAB Indent selected text
472-shift-TAB Un-indents selected text
473-BACKSPACE Un-indents selected text
474+<Tab> Indent selected text
475+<Shift><Tab> Un-indents selected text
476+<Backspace> Un-indents selected text
477 '''
478
479
480
481=== modified file 'data/manual/Help/Pages.txt'
482--- data/manual/Help/Pages.txt 2010-01-19 18:41:47 +0000
483+++ data/manual/Help/Pages.txt 2011-06-04 21:27:03 +0000
484@@ -32,3 +32,9 @@
485 ===== Jump To Dialog =====
486 This dialog is intended to jump to a specified page. It is actually hardly different from the New Page dialog except that it resolves page names relative to the current page and does not immediately create a new page. However you can always create new pages by jumping to a page that does not yet exist and start editing.
487
488+===== Deleting pages =====
489+When you select "Delete Page" by default zim will try to trash the page and all it's sub pages and attachments - **that means all files that are in the folder below the text file for the page**. If you deleted something on accident you should be able to recover the data from your system's trash can. After recovering data you probable need to run "Re-build Index" from the "Tools" menu to make sure zim indexes the data again.
490+
491+If zim is not able to move data to the trash can it will offer to delete the data permanently. In this case a dialog is shown to ask for confirmation which includes a detailed list of files to be deleted.
492+
493+If you don't like to use the trash by default (e.g. for notebooks that contain sensitive data) there is an option in the notebook [[Config Files|config file]] to disable the trash. In this case the confirmation dialog will always be shown on "delete page".
494
495=== modified file 'data/manual/Help/Searching.txt'
496--- data/manual/Help/Searching.txt 2010-07-20 20:37:06 +0000
497+++ data/manual/Help/Searching.txt 2011-06-04 21:27:03 +0000
498@@ -54,6 +54,7 @@
499 Links:
500 LinksFrom:
501 LinksTo:
502+Tag:
503
504
505 === Details ===
506@@ -125,6 +126,7 @@
507 **Links:**
508 **LinksFrom:**
509 **LinksTo:**
510+ **Tag:**
511
512 For example to only search the page names you can use:
513
514@@ -160,3 +162,10 @@
515 namespace: Date and linksto: Planning
516 '''
517
518+The keyword "Tag" can be used to search for specifc tags like:
519+'''
520+
521+Tag: home
522+'''
523+
524+Note that a simple search for a single word like "''@home''" will automatically be converted to "''Tag: home''"
525
526=== added file 'data/manual/Help/Tags.txt'
527--- data/manual/Help/Tags.txt 1970-01-01 00:00:00 +0000
528+++ data/manual/Help/Tags.txt 2011-06-04 21:27:03 +0000
529@@ -0,0 +1,13 @@
530+Content-Type: text/x-zim-wiki
531+Wiki-Format: zim 0.4
532+Creation-Date: 2011-04-04T21:14:35+02:00
533+
534+====== Tags ======
535+
536+Zim supports the use of tags to organize pages. Tags are keywords or labels that are used to categorize pages.
537+
538+Tags can be used anywhere in a page using the "@" prefix. Like this: @example @tags
539+
540+To find context based on tags you can use the [[Searching|Search]] dialog. For example to find all pages tagged with "@example" you can search for "''Tag: example''" or just for "''@example''". Since tags are cached in the index, this search is much quicker than a full text search for random words.
541+
542+There is also a plugin that will add a tag cloud and a page index organized by tag in the side page, see also [[Plugins:Tags]]
543
544=== modified file 'data/manual/Help/Templates.txt'
545--- data/manual/Help/Templates.txt 2010-03-03 19:43:13 +0000
546+++ data/manual/Help/Templates.txt 2011-06-04 21:27:03 +0000
547@@ -55,20 +55,32 @@
548 Available variables:
549
550 '''
551+zim.version # version of zim
552+
553 page.name # complete page name
554 page.namespace # namespace
555-page.title # last part of the name of the page
556-page.heading # title or first heading in the page
557-page.body # content of the page
558-page.links # list of vars with a .file and a .name subvar
559-page.backlinks # "" idem ""
560-page.is_index # true for the automatic generated index page
561-prev.name # name of previous page
562-prev.file # file name of previous page
563-next.name # name of next page
564-next.file # file name of next page
565-notebook.root # root dir relative to page file
566-zim.version # version of zim
567-'''
568-
569-The "Title" field contains either the first heading in the page or the page name. If the first header is used, this header is removed from the "Body" field.
570+page.basename # last part of the page name
571+page.title #
572+'''
573+''first heading in the page or the basename''
574+''page.heading # first heading in the page''
575+''page.body # content of the page (without the leading heading)''
576+''page.links # list of page objects for pages linked in this page''
577+''page.backlinks # ''''list of page objects for pages linking to this page''
578+''page.properties # dict with page properties''
579+
580+''# These special pages have the same properties as the 'page' object''
581+''pages.index # the index page generated when exporting''
582+''pages.home # the home page''
583+''pages.next # the next page in the index (if any)''
584+''pages.previous # the previous page in the index (if any)''
585+
586+''options # dict where format specific options can be set''
587+
588+Functions available:
589+
590+'''
591+url(link) # turns a zim link into an URL
592+strftime(template, date) # format a date
593+'''
594+
595
596=== modified file 'data/manual/Plugins.txt'
597--- data/manual/Plugins.txt 2010-07-06 20:36:53 +0000
598+++ data/manual/Plugins.txt 2011-06-04 21:27:03 +0000
599@@ -6,11 +6,14 @@
600 The following plugins are standard included with zim:
601
602 * [[+Calendar|Calendar]]
603+* [[+Tags|Tags]]
604 * [[+Diagram Editor|Diagram Editor]]
605 * [[+Equation Editor|Equation Editor]]
606 * [[+GNU R Plot Editor|GNU R Plot Editor]]
607+* [[+Gnuplot Editor|Gnuplot Editor]]
608 * [[+Insert Screenshot|Insert Screenshot]]
609 * [[+Insert Symbol|Insert Symbol]]
610+* [[+Inline Calculator|Inline Calculator]]
611 * [[+Link Map|Link Map]]
612 * [[+Quick Note|Quick Note]]
613 * [[+Spell Checker|Spell Checker]]
614
615=== added directory 'data/manual/Plugins/Gnuplot_Editor'
616=== added file 'data/manual/Plugins/Gnuplot_Editor.txt'
617--- data/manual/Plugins/Gnuplot_Editor.txt 1970-01-01 00:00:00 +0000
618+++ data/manual/Plugins/Gnuplot_Editor.txt 2011-06-04 21:27:03 +0000
619@@ -0,0 +1,21 @@
620+Content-Type: text/x-zim-wiki
621+Wiki-Format: zim 0.4
622+Creation-Date: 2011-03-28T21:59:01+02:00
623+
624+====== Gnuplot Editor ======
625+
626+
627+The Gnuplot editor is, as its name suggests, a simple dialog that allows you to insert plots rendered with gnuplot.
628+
629+**Dependencies:** The plugin requires gnuplot to be installed.
630+
631+===== Syntax =====
632+
633+{{./gnuplot.png?type=gnuplot}}
634+'''
635+
636+plot sin(x), cos(x)
637+'''
638+
639+
640+See http://www.gnuplot.info/ for more information about gnuplot
641
642=== added file 'data/manual/Plugins/Gnuplot_Editor/gnuplot.gnu'
643--- data/manual/Plugins/Gnuplot_Editor/gnuplot.gnu 1970-01-01 00:00:00 +0000
644+++ data/manual/Plugins/Gnuplot_Editor/gnuplot.gnu 2011-06-04 21:27:03 +0000
645@@ -0,0 +1,1 @@
646+plot sin(x), cos(x)
647\ No newline at end of file
648
649=== added file 'data/manual/Plugins/Gnuplot_Editor/gnuplot.png'
650Binary files data/manual/Plugins/Gnuplot_Editor/gnuplot.png 1970-01-01 00:00:00 +0000 and data/manual/Plugins/Gnuplot_Editor/gnuplot.png 2011-06-04 21:27:03 +0000 differ
651=== modified file 'data/manual/Plugins/Spell_Checker.txt'
652--- data/manual/Plugins/Spell_Checker.txt 2010-05-02 12:46:50 +0000
653+++ data/manual/Plugins/Spell_Checker.txt 2011-06-04 21:27:03 +0000
654@@ -5,4 +5,7 @@
655
656 This plugin adds inline spell checking for zim. It has a preference setting to determine the language used for spell checking. If this is not set, the system default is used.
657
658-**Dependencies:** This plugin requires the "gtkspell" library to be installed as well as the Python language bindings for this library. On Ubuntu or Debian systems installing the package "python-gtkspell" (or "python-gnome2-extras" on older releases) will meet these dependencies.
659+**Dependencies:** This plugin requires the "gtkspell" library to be installed as well as the Python language bindings for this library.
660+
661+* On Ubuntu or Debian systems installing the package "python-gtkspell" (or "python-gnome2-extras" on older releases) will meet these dependencies.
662+* On Fedora systems, installing the package "gnome-python2-gtkspell" will meet these dependencies.
663
664=== added file 'data/manual/Plugins/Tags.txt'
665--- data/manual/Plugins/Tags.txt 1970-01-01 00:00:00 +0000
666+++ data/manual/Plugins/Tags.txt 2011-06-04 21:27:03 +0000
667@@ -0,0 +1,13 @@
668+Content-Type: text/x-zim-wiki
669+Wiki-Format: zim 0.4
670+Creation-Date: 2011-04-04T21:14:50+02:00
671+
672+====== Tags ======
673+
674+This plugin adds a tag cloud and a page index organized by tags in the side pane.
675+
676+The tag cloud allows toggling the selection of tags that is shown in the page index. The page index can be switched between a flat view, showing all pages that match the filtering criteria, and an ordered view that shows known tags as the top level nodes with pages beneath them.
677+
678+**Dependencies:** This plugin has no additional dependencies.
679+
680+**See also: **[[Help:Tags]]
681
682=== modified file 'data/manual/Plugins/Task_List.txt'
683--- data/manual/Plugins/Task_List.txt 2010-05-25 19:47:41 +0000
684+++ data/manual/Plugins/Task_List.txt 2011-06-04 21:27:03 +0000
685@@ -35,7 +35,7 @@
686 yyyy/mm/dd yyyy-mm-dd
687 '''
688
689-So you can use e.g. "[d: 5/1]", "[d: 2010-1-5]" or "[d: 5/1/10]".
690+So you can use e.g. "[d: 5/1]", "[d: 2010-1-5]" or "[d: 5/1/10]". (Any other separator character to separate year, month, and day will also work, as long as it is not a number or a letter.)
691
692 **Note: **dates are parse in European notation, so "dd/mm", not as "mm/dd" as is customary in the US. Unfortunately there is no way to resolve these unambiguously.
693
694
695=== modified file 'data/menubar.xml'
696--- data/menubar.xml 2011-02-14 20:22:50 +0000
697+++ data/menubar.xml 2011-06-04 21:27:03 +0000
698@@ -42,7 +42,7 @@
699 <menuitem action='edit_object'/>
700 <menuitem action='remove_link'/>
701 <separator/>
702- <placeholder name='edit_page'/>
703+ <placeholder name='plugin_items'/>
704 <separator/>
705 <menuitem action='copy_location'/>
706 <separator/>
707@@ -72,6 +72,10 @@
708 <separator/>
709 <placeholder name='plugin_items'/>
710 <separator/>
711+ <menuitem action='zoom_in'/>
712+ <menuitem action='zoom_out'/>
713+ <menuitem action='zoom_reset'/>
714+ <separator/>
715 <menuitem action='reload_page'/>
716 </menu>
717 <menu action='insert_menu'>
718
719=== modified file 'data/style.conf'
720--- data/style.conf 2011-01-16 21:57:51 +0000
721+++ data/style.conf 2011-06-04 21:27:03 +0000
722@@ -38,6 +38,9 @@
723 foreground = blue
724 #underline = single
725
726+[Tag tag]
727+foreground = #ce5c00
728+
729
730 # For the various headings we scale the size relative to the font size.
731 # The color choosen is the dark green -or "Chameleon"- as defined in the
732
733=== added file 'data/templates/_gnuplot.gnu'
734--- data/templates/_gnuplot.gnu 1970-01-01 00:00:00 +0000
735+++ data/templates/_gnuplot.gnu 2011-06-04 21:27:03 +0000
736@@ -0,0 +1,5 @@
737+set term png
738+set output '[% png_fname %]'
739+
740+[% gnuplot_script %]
741+
742
743=== modified file 'data/urls.list'
744--- data/urls.list 2010-01-08 18:02:36 +0000
745+++ data/urls.list 2011-06-04 21:27:03 +0000
746@@ -21,7 +21,7 @@
747 google http://www.google.com/search?q=
748 google.de http://www.google.de/search?q=
749 phpfn http://www.php.net/{NAME}
750-go http://www.google.com/search?q={URL}&amp;btnI=lucky
751+go http://www.google.com/search?q={URL}&btnI=lucky
752 cpan http://search.cpan.org/search?query={URL}&mode=all
753 perldoc http://perldoc.perl.org/search.html?q=
754
755
756=== modified file 'debian/changelog'
757--- debian/changelog 2011-02-19 16:27:44 +0000
758+++ debian/changelog 2011-06-04 21:27:03 +0000
759@@ -1,3 +1,15 @@
760+zim (0.52) maverick; urgency=low
761+
762+ * Updated to release 0.52
763+
764+ -- Jaap Karssenberg <jaap.karssenberg@gmail.com> Thu, 28 Apr 2011 19:56:04 +0200
765+
766+zim (0.51) maverick; urgency=low
767+
768+ * Updated to release 0.51
769+
770+ -- Jaap Karssenberg <jaap.karssenberg@gmail.com> Tue, 19 Apr 2011 20:51:32 +0200
771+
772 zim (0.50) maverick; urgency=low
773
774 * Updated to release 0.50
775
776=== modified file 'debian/control'
777--- debian/control 2011-02-19 16:27:44 +0000
778+++ debian/control 2011-06-04 21:27:03 +0000
779@@ -3,7 +3,7 @@
780 Priority: optional
781 Maintainer: Jaap Karssenberg <jaap.karssenberg@gmail.com>
782 Standards-Version: 3.9.1
783-Build-Depends: debhelper (>= 7.4.12), cdbs, python-support (>= 0.8), xdg-utils, python (>= 2.5), libgtk2.0-0 (>= 2.6), python-gtk2, python-xdg, python-simplejson | python (>= 2.6)
784+Build-Depends: debhelper (>= 7.4.12), cdbs, python-support (>= 0.8), python-unittest2 | python (>= 2.7), xdg-utils, python (>= 2.5), libgtk2.0-0 (>= 2.6), python-gtk2, python-xdg, python-simplejson | python (>= 2.6)
785
786 Package: zim
787 Architecture: all
788
789=== modified file 'debian/pyversions'
790--- debian/pyversions 2009-10-21 18:34:17 +0000
791+++ debian/pyversions 2011-06-04 21:27:03 +0000
792@@ -1,1 +1,1 @@
793-2.5,2.6
794+2.5,2.6,2.7
795
796=== modified file 'msgfmt.py'
797--- msgfmt.py 2009-07-18 13:57:52 +0000
798+++ msgfmt.py 2011-06-04 21:27:03 +0000
799@@ -71,7 +71,6 @@
800 offsets.append((len(ids), len(_id), len(strs), len(MESSAGES[_id])))
801 ids += _id + '\0'
802 strs += MESSAGES[_id] + '\0'
803- output = ''
804 # The header is 7 32-bit unsigned integers. We don't use hash tables, so
805 # the keys start right after the index tables.
806 # translated string.
807
808=== modified file 'test.py'
809--- test.py 2011-02-19 16:27:44 +0000
810+++ test.py 2011-06-04 21:27:03 +0000
811@@ -2,6 +2,10 @@
812
813 # -*- coding: utf-8 -*-
814
815+# This is a wrapper script to run tests using the unittest
816+# framework. It setups the environment properly and defines some
817+# commandline options for running tests.
818+#
819 # Copyright 2008 Jaap Karssenberg <jaap.karssenberg@gmail.com>
820
821 import os
822@@ -10,92 +14,8 @@
823 import getopt
824 import logging
825
826-import unittest
827-import time
828-import types
829-
830 import tests
831-
832-# TODO overload one of the unittest classes to test add file names
833-
834-pyfiles = []
835-for d, dirs, files in os.walk('zim'):
836- pyfiles.extend([d+'/'+f for f in files if f.endswith('.py')])
837-pyfiles.sort()
838-
839-class FastTestLoader(unittest.TestLoader):
840- '''Extension of TestLoader which ignores all classes which have an
841- attribute 'slowTest' set to True.
842- '''
843-
844- def __init__(self, alltests=True):
845- unittest.TestLoader.__init__(self)
846- self.ignored = 0
847- self.skipped = 0
848- self.alltests = alltests
849-
850- def loadTestsFromModule(self, module):
851- """Return a suite of all tests cases contained in the given module"""
852- tests = []
853- for name in dir(module):
854- obj = getattr(module, name)
855- if (isinstance(obj, (type, types.ClassType)) and
856- issubclass(obj, unittest.TestCase)):
857- if not self.alltests and hasattr(obj, 'slowTest') and obj.slowTest:
858- print 'Ignoring slow test:', obj.__name__
859- self.ignored += 1
860- elif hasattr(obj, 'skipTest') and obj.skipTest():
861- print 'Skipping test:', obj.__name__, '-', obj.skipTest()
862- self.skipped += 1
863- else:
864- tests.append(self.loadTestsFromTestCase(obj))
865- return self.suiteClass(tests)
866-
867-
868-class MyTextTestRunner(unittest.TextTestRunner):
869- '''Extionsion of TextTestRunner to report number of ignored tests in the
870- proper place.
871- '''
872-
873- def __init__(self, verbosity, ignored, skipped):
874- unittest.TextTestRunner.__init__(self, verbosity=verbosity)
875- self.ignored = ignored
876- self.skipped = skipped
877-
878- def run(self, test):
879- "Run the given test case or test suite."
880- result = self._makeResult()
881- startTime = time.time()
882- test(result)
883- stopTime = time.time()
884- timeTaken = stopTime - startTime
885- result.printErrors()
886- self.stream.writeln(result.separator2)
887- run = result.testsRun
888- self.stream.writeln("Ran %d test%s in %.3fs" %
889- (run, run != 1 and "s" or "", timeTaken))
890- ignored = self.ignored
891- if ignored > 0:
892- self.stream.writeln("Ignored %d slow test%s" %
893- (ignored, ignored != 1 and "s" or ""))
894- skipped = self.skipped
895- if skipped > 0:
896- self.stream.writeln("Skipped %d test%s" %
897- (skipped, skipped != 1 and "s" or ""))
898- self.stream.writeln()
899- if not result.wasSuccessful():
900- self.stream.write("FAILED (")
901- failed, errored = map(len, (result.failures, result.errors))
902- if failed:
903- self.stream.write("failures=%d" % failed)
904- if errored:
905- if failed: self.stream.write(", ")
906- self.stream.write("errors=%d" % errored)
907- self.stream.writeln(")")
908- else:
909- self.stream.writeln("OK")
910- return result
911-
912+from tests import unittest
913
914
915 def main(argv=None):
916@@ -105,9 +25,10 @@
917
918 # parse options
919 coverage = None
920- alltests = True
921+ failfast = False
922 loglevel = logging.WARNING
923- opts, args = getopt.gnu_getopt(argv[1:], 'hVD', ['help', 'coverage', 'fast', 'debug', 'verbose'])
924+ opts, args = getopt.gnu_getopt(argv[1:],
925+ 'hVD', ['help', 'coverage', 'fast', 'failfast', 'debug', 'verbose'])
926 for o, a in opts:
927 if o in ('-h', '--help'):
928 print '''\
929@@ -118,7 +39,8 @@
930
931 Options:
932 -h, --help print this text
933- --fast skip a number of slower tests
934+ --fast skip a number of slower tests (assumes --failfast)
935+ --failfast stop after the first test that fails
936 --coverage report test coverage statistics
937 -V, --verbose run with verbose output from logging
938 -D, --debug run with debug output from logging
939@@ -129,7 +51,7 @@
940 import coverage as coverage_module
941 except ImportError:
942 print >>sys.stderr, '''\
943-Can not run test coverage without module coverage.
944+Can not run test coverage without module 'coverage'.
945 On Ubuntu or Debian install package 'python-coverage'.
946 '''
947 sys.exit(1)
948@@ -139,7 +61,11 @@
949 coverage.exclude('raise NotImplementedError')
950 coverage.start()
951 elif o == '--fast':
952- alltests = False
953+ failfast = True
954+ tests.FAST_TEST = True
955+ # set before any test classes are loaded !
956+ elif o == '--failfast':
957+ failfast = True
958 elif o in ('-V', '--verbose'):
959 loglevel = logging.INFO
960 elif o in ('-D', '--debug'):
961@@ -150,28 +76,19 @@
962 # Set logging handler
963 logging.basicConfig(level=loglevel, format='%(levelname)s: %(message)s')
964
965- # Set environment - so we can be sure we don't see
966- # any data from a previous installed version
967- tests.set_environ()
968-
969- # Collect the test cases
970- suite = unittest.TestSuite()
971- loader = FastTestLoader(alltests=alltests)
972-
973+ # Build the test suite
974+ loader = unittest.TestLoader()
975 if args:
976- modules = [ 'tests.'+name for name in args ]
977+ suite = unittest.TestSuite()
978+ for module in [ 'tests.'+name for name in args ]:
979+ test = loader.loadTestsFromName(module)
980+ suite.addTest(test)
981 else:
982- suite.addTest(TestCompileAll())
983- suite.addTest(TestNotebookUpgrade())
984- modules = [ 'tests.'+name for name in tests.__all__ ]
985-
986- for name in modules:
987- test = loader.loadTestsFromName(name)
988- suite.addTest(test)
989-
990- # And run them
991- MyTextTestRunner(verbosity=3,
992- ignored=loader.ignored, skipped=loader.skipped).run(suite)
993+ suite = tests.load_tests(loader, None, None)
994+
995+ # And run it
996+ unittest.installHandler() # Fancy handling for ^C during test
997+ unittest.TextTestRunner(verbosity=2, failfast=failfast).run(suite)
998
999 # Check the modules were loaded from the right location
1000 # (so no testing based on modules from a previous installed version...)
1001@@ -184,6 +101,7 @@
1002 assert file.startswith(mylib), \
1003 'Module %s was loaded from %s' % (module, file)
1004
1005+ # Create coverage output if asked to do so
1006 if coverage:
1007 coverage.stop()
1008 report_coverage(coverage)
1009@@ -192,6 +110,7 @@
1010 def report_coverage(coverage):
1011 print ''
1012 print 'Writing detailed coverage reports...'
1013+ pyfiles = list(tests.zim_pyfiles())
1014 coverage.report(pyfiles, show_missing=False)
1015
1016 # Detailed report in html
1017@@ -307,25 +226,6 @@
1018 print '\nDetailed coverage reports can be found in ./coverage/'
1019
1020
1021-class TestCompileAll(unittest.TestCase):
1022-
1023- def runTest(self):
1024- '''Test if all modules compile'''
1025- for file in pyfiles:
1026- module = file[:-3].replace('/', '.')
1027- assert __import__(module)
1028-
1029-
1030-class TestNotebookUpgrade(unittest.TestCase):
1031-
1032- def runTest(self):
1033- '''Test if included notebooks are up to date'''
1034- from zim.fs import Dir
1035- from zim.notebook import get_notebook
1036- for path in ('data/manual', 'HACKING'):
1037- notebook = get_notebook(Dir(path))
1038- self.assertTrue(not notebook.needs_upgrade)
1039-
1040
1041 if __name__ == '__main__':
1042 main()
1043
1044=== modified file 'tests/__init__.py'
1045--- tests/__init__.py 2011-02-27 20:51:16 +0000
1046+++ tests/__init__.py 2011-06-04 21:27:03 +0000
1047@@ -7,14 +7,36 @@
1048 import os
1049 import sys
1050 import shutil
1051-import unittest
1052 import logging
1053 import gettext
1054 import xml.etree.cElementTree as etree
1055-
1056-
1057+import types
1058+import glob
1059+
1060+if sys.version_info < (2, 7, 0):
1061+ try:
1062+ import unittest2 as unittest
1063+ except ImportError:
1064+ print >>sys.stderr, '''\
1065+For python versions < 2.7 the 'unittest2' module is needed to run
1066+the test suite. On Ubuntu or Debian install package 'python-unittest2'.
1067+'''
1068+ sys.exit(1)
1069+else:
1070+ import unittest
1071+
1072+from unittest import skip, skipIf, skipUnless
1073+
1074+__unittest = 1 # needed to get stack trace OK for class TestCase
1075+
1076+gettext.install('zim', unicode=True, names=('_', 'gettext', 'ngettext'))
1077+
1078+FAST_TEST = False #: determines whether we skip slow tests or not
1079+
1080+
1081+# This list also determines the order in which tests will executed
1082 __all__ = [
1083- 'coding', 'translations',
1084+ 'package', 'translations',
1085 'errors', 'parsing', 'fs', 'config', 'applications', 'async',
1086 'formats', 'templates', 'inlineobjects',
1087 'stores', 'index', 'notebook',
1088@@ -22,17 +44,33 @@
1089 'export', 'www', 'search',
1090 'widgets', 'gui', 'pageview',
1091 'calendar', 'printtobrowser', 'versioncontrol', 'inlinecalculator',
1092- 'tasklist',
1093+ 'tasklist', 'tags',
1094 'equationeditor', 'diagrameditor',
1095+ 'daemon' # Note that running this test in another position can skrew up e.g. clipboard test
1096 ]
1097
1098-__unittest = 1 # needed to get stack trace OK for class TestCase
1099-
1100-
1101-gettext.install('zim', unicode=True, names=('_', 'gettext', 'ngettext'))
1102-
1103-
1104-def set_environ():
1105+# when a test is missing from the list that should be detected
1106+for file in glob.glob(os.path.dirname(__file__) + '/*.py'):
1107+ name = os.path.basename(file)[:-3]
1108+ if name != '__init__' and not name in __all__:
1109+ raise AssertionError, 'Test missing in __all__: %s' % name
1110+
1111+
1112+def load_tests(loader, tests, pattern):
1113+ '''Load all test cases and return a unittest.TestSuite object.
1114+ The parameters 'tests' and 'pattern' are ignored.
1115+ '''
1116+ suite = unittest.TestSuite()
1117+ for name in ['tests.'+name for name in __all__ ]:
1118+ test = loader.loadTestsFromName(name)
1119+ suite.addTest(test)
1120+ return suite
1121+
1122+
1123+def _setUpEnvironment():
1124+ '''Method to be run once before test suite starts'''
1125+ # In fact to be loaded before loading some of the zim modules
1126+ # like zim.config and any that export constants from it
1127 tmpdir = './tests/tmp/'
1128 os.environ.update({
1129 'ZIM_TEST_RUNNING': 'True',
1130@@ -55,75 +93,218 @@
1131 os.makedirs(hicolor)
1132
1133
1134-def create_tmp_dir(name):
1135- '''Returns a path to a tmp dir for tests to store dump data.
1136- The dir is removed and recreated empty every time this function
1137- is called.
1138+_setUpEnvironment() # just do this whenever we are loaded
1139+
1140+
1141+_zim_pyfiles = []
1142+
1143+def zim_pyfiles():
1144+ '''Returns a list with file paths for all the zim python files'''
1145+ if not _zim_pyfiles:
1146+ for d, dirs, files in os.walk('zim'):
1147+ _zim_pyfiles.extend([d+'/'+f for f in files if f.endswith('.py')])
1148+ _zim_pyfiles.sort()
1149+ for file in _zim_pyfiles:
1150+ yield file # shallow copy
1151+
1152+
1153+
1154+def gtk_process_events(*a):
1155+ '''Method to simulate a few iterations of the gtk main loop'''
1156+ import gtk
1157+ while gtk.events_pending():
1158+ gtk.main_iteration(block=False)
1159+ return True # continue
1160+
1161+
1162+def slowTest(obj):
1163+ '''Decorator for slow tests
1164+
1165+ Tests wrapped with this decorator are ignored when you run
1166+ C{test.py --fast}. You can either wrap whole test classes::
1167+
1168+ @tests.slowTest
1169+ class MyTest(tests.TestCase):
1170+ ...
1171+
1172+ or individual test functions::
1173+
1174+ class MyTest(tests.TestCase):
1175+
1176+ @tests.slowTest
1177+ def testFoo(self):
1178+ ...
1179+
1180+ def testBar(self):
1181+ ...
1182 '''
1183- dir = os.path.join('tests', 'tmp', name)
1184- if os.name == 'nt':
1185- dir = unicode(dir)
1186+ if FAST_TEST:
1187+ wrapper = skip('Slow test')
1188+ return wrapper(obj)
1189 else:
1190- dir = dir.encode(sys.getfilesystemencoding())
1191- if os.path.exists(dir):
1192- shutil.rmtree(dir)
1193- assert not os.path.exists(dir) # make real sure
1194- os.makedirs(dir)
1195- assert os.path.exists(dir) # make real sure
1196- return dir
1197-
1198-
1199-_test_data_wiki = None
1200-
1201-def get_test_data(format):
1202- global _test_data_wiki
1203- assert format == 'wiki' # No other formats available for now
1204- if _test_data_wiki is None:
1205- _test_data_wiki = _get_test_data_wiki()
1206-
1207- for name, text in _test_data_wiki:
1208- #~ print '>', name
1209- yield name, text
1210-
1211-
1212-def get_test_data_page(format, name):
1213- global _test_data_wiki
1214- assert format == 'wiki' # No other formats available for now
1215- if not _test_data_wiki:
1216- _test_data_wiki = _get_test_data_wiki()
1217-
1218- for n, text in _test_data_wiki:
1219- if n == name:
1220- return text
1221- assert False, 'Could not find data for page: %s' % name
1222-
1223-
1224-def _get_test_data_wiki():
1225- test_data = []
1226- tree = etree.ElementTree(file='tests/data/notebook-wiki.xml')
1227- for node in tree.getiterator(tag='page'):
1228- name = node.attrib['name']
1229- text = unicode(node.text.lstrip('\n'))
1230- test_data.append((name, text))
1231- return tuple(test_data)
1232-
1233-
1234-def get_test_notebook(format='wiki'):
1235- '''Returns a notebook with a memory store and some test data'''
1236- from zim.notebook import Notebook, Path
1237- from zim.index import Index
1238- notebook = Notebook(index=Index(dbfile=':memory:'))
1239- store = notebook.add_store(Path(':'), 'memory')
1240- manifest = []
1241- for name, text in get_test_data(format):
1242- manifest.append(name)
1243- store.set_node(Path(name), text)
1244- notebook.testdata_manifest = expand_manifest(manifest)
1245- notebook.index.update()
1246- return notebook
1247-
1248-
1249-def expand_manifest(names):
1250+ return obj
1251+
1252+
1253+class TestCase(unittest.TestCase):
1254+ '''Base class for test cases'''
1255+
1256+ def create_tmp_dir(self, name=None):
1257+ '''Returns a path to a tmp dir where tests can write data.
1258+ The dir is removed and recreated empty every time this function
1259+ is called with the same name from the same class.
1260+ '''
1261+ path = self._get_tmp_name(name)
1262+ if os.path.exists(path):
1263+ shutil.rmtree(path)
1264+ assert not os.path.exists(path) # make real sure
1265+ os.makedirs(path)
1266+ assert os.path.exists(path) # make real sure
1267+ return path
1268+
1269+ def get_tmp_name(self, name=None):
1270+ '''Returns the same path as L{create_tmp_dir()} but without
1271+ touching it. This method will raise an exception when a file
1272+ or dir exists of the same name.
1273+ '''
1274+ path = self._get_tmp_name(name)
1275+ assert not os.path.exists(path), 'This path should not exist: %s' % path
1276+ return path
1277+
1278+ def _get_tmp_name(self, name):
1279+ if name:
1280+ assert not os.path.sep in name, 'Don\'t use this method to get sub folders or files'
1281+ name = self.__class__.__name__ + '_' + name
1282+ else:
1283+ name = self.__class__.__name__
1284+
1285+ dir = os.path.dirname(__file__)
1286+ path = os.path.join(dir, 'tmp', name)
1287+ if os.name == 'nt':
1288+ path = unicode(path)
1289+ else:
1290+ path = path.encode(sys.getfilesystemencoding())
1291+
1292+ return path
1293+
1294+
1295+class LoggingFilter(object):
1296+ '''Base class for logging filters that can be used as a context
1297+ using the "with" keyword. To subclass it you only need to set the
1298+ logger to be used and (the begin of) the message to filter.
1299+ '''
1300+
1301+ logger = None
1302+ message = None
1303+
1304+ def __init__(self, logger=None, message=None):
1305+ if logger: self.logger = logger
1306+ if message: self.message = message
1307+
1308+ self.loggerobj = logging.getLogger(self.logger)
1309+
1310+ def __enter__(self):
1311+ self.loggerobj.addFilter(self)
1312+
1313+ def __exit__(self, *a):
1314+ self.loggerobj.removeFilter(self)
1315+
1316+ def filter(self, record):
1317+ return not record.getMessage().startswith(self.message)
1318+
1319+
1320+class DialogContext(object):
1321+ '''Context manager to catch dialogs being opened
1322+
1323+ Inteded to be used like this::
1324+
1325+ def myCustomTest(dialog):
1326+ self.assertTrue(isinstance(dialog, CustomDialogClass))
1327+ # ...
1328+ dialog.assert_response_ok()
1329+
1330+ with DialogContext(
1331+ myCustomTest,
1332+ SomeOtherDialogClass
1333+ ):
1334+ gui.show_dialogs()
1335+
1336+ In this example the first dialog that is run by C{gui.show_dialogs()}
1337+ is checked by the function C{myCustomTest()} while the second dialog
1338+ just needs to be of class C{SomeOtherDialogClass} and will then
1339+ be closed with C{assert_response_ok()} by the context manager.
1340+
1341+ This context only works for dialogs derived from zim's Dialog class
1342+ as it uses a special hook in L{zim.gui.widgets}.
1343+ '''
1344+
1345+ def __init__(self, *definitions):
1346+ '''Constructor
1347+ @param definitions: list of either classes or methods
1348+ '''
1349+ self.stack = list(definitions)
1350+ self.old_test_mode = None
1351+
1352+ def __enter__(self):
1353+ import zim.gui.widgets
1354+ self.old_test_mode = zim.gui.widgets.TEST_MODE
1355+ self.old_callback = zim.gui.widgets.TEST_MODE_RUN_CB
1356+ zim.gui.widgets.TEST_MODE = True
1357+ zim.gui.widgets.TEST_MODE_RUN_CB = self._callback
1358+
1359+ def _callback(self, dialog):
1360+ #~ print '>>>', dialog
1361+ if not self.stack:
1362+ raise AssertionError, 'Unexpected dialog run: %s' % dialog
1363+
1364+ handler = self.stack.pop(0)
1365+
1366+ if isinstance(handler, (type, types.ClassType)): # is a class
1367+ if not isinstance(dialog, handler):
1368+ raise AssertionError, 'Expected dialog of class %s, but got %s instead' % (handler, dialog.__class__)
1369+ dialog.assert_response_ok()
1370+ else: # assume a function
1371+ handler(dialog)
1372+
1373+ def __exit__(self, *error):
1374+ #~ print 'ERROR', error
1375+ import zim.gui.widgets
1376+ zim.gui.widgets.TEST_MODE = self.old_test_mode
1377+ zim.gui.widgets.TEST_MODE_RUN_CB = self.old_callback
1378+ return False # Raise any errors again outside context
1379+
1380+
1381+class TestData(object):
1382+ '''Wrapper for a set of test data in tests/data'''
1383+
1384+ def __init__(self, format):
1385+ assert format == 'wiki', 'TODO: add other formats'
1386+ tree = etree.ElementTree(file='tests/data/notebook-wiki.xml')
1387+
1388+ test_data = []
1389+ for node in tree.getiterator(tag='page'):
1390+ name = node.attrib['name']
1391+ text = unicode(node.text.lstrip('\n'))
1392+ test_data.append((name, text))
1393+
1394+ self._test_data = tuple(test_data)
1395+
1396+ def __iter__(self):
1397+ '''Yield the test data as 2 tuple (pagename, text)'''
1398+ for name, text in self._test_data:
1399+ yield name, text # shallow copy
1400+
1401+ def get(self, pagename):
1402+ '''Return text for a specific pagename'''
1403+ for n, text in self._test_data:
1404+ if n == pagename:
1405+ return text
1406+ assert False, 'Could not find data for page: %s' % pagename
1407+
1408+
1409+WikiTestData = TestData('wiki') #: singleton to be used by various tests
1410+
1411+
1412+def _expand_manifest(names):
1413 '''Build a set of all pages names and all namespaces that need to
1414 exist to host those page names.
1415 '''
1416@@ -137,96 +318,63 @@
1417 return manifest
1418
1419
1420-def get_test_page(name='Foo'):
1421- '''FIXME'''
1422+def new_notebook(fakedir=None):
1423+ '''Returns a new Notebook object with all data in memory
1424+
1425+ Uses data from L{WikiTestData}
1426+
1427+ @param fakedir: optional parameter to set the 'dir' attribute for
1428+ the notebook and the main store which allows you to resolve file
1429+ paths etc. It will not automatically touch the dir
1430+ (hence it being 'fake').
1431+ '''
1432+ from zim.fs import Dir
1433 from zim.notebook import Notebook, Path
1434- notebook = Notebook()
1435- notebook.add_store(Path(':'), 'memory')
1436- return notebook, notebook.get_page(Path(name))
1437-
1438-
1439-def print_index(index):
1440- print '==== INDEX ===='
1441- for page in index.walk():
1442- print page.name, page.hascontent, page.haschildren
1443- for link in index.list_links(page):
1444- print '\t->', link.href.name
1445- print '==============='
1446-
1447-
1448-
1449-class TestCase(unittest.TestCase):
1450- '''Base class for test cases'''
1451-
1452- def run(self, *args):
1453- unittest.TestCase.run(self, *args)
1454-
1455- def assertEqualDiff(self, first, second, msg=None):
1456- '''Fail if the two strings are unequal as determined by
1457- the '==' operator. On failure shows a diff of both strings.
1458- Alternatively the arguments can be lists of lines.
1459- '''
1460- if msg is None:
1461- msg = u'Strings differ:'
1462- else:
1463- msg = unicode(msg)
1464-
1465- if not type(first) == type(second):
1466- types = type(first), type(second)
1467- msg += ' types differ, %s and %s' % types
1468- elif not first:
1469- msg += ' first text is empty'
1470- elif not second:
1471- msg += ' second text is empty'
1472- elif not first == second:
1473- from difflib import Differ
1474- if isinstance(first, basestring):
1475- first = first.splitlines(True)
1476- if isinstance(second, basestring):
1477- second = second.splitlines(True)
1478- diff = Differ().compare(second, first)
1479- # switching first and second, because usually second
1480- # is the reference we are testing against
1481- msg += '\n' + ''.join(diff)
1482- else:
1483- return
1484-
1485- raise self.failureException, msg.encode('utf-8')
1486-
1487- def assertEqualDiffData(self, first, second, msg=None):
1488- '''Like assertEqualDiff(), but handles sets and other
1489- data types that can be cast to lists.
1490- '''
1491- if msg is None:
1492- msg = u'Values differ:'
1493- else:
1494- msg = unicode(msg)
1495-
1496- if not type(first) == type(second):
1497- types = type(first), type(second)
1498- msg += ' types differ, %s and %s' % types
1499- elif first is None:
1500- msg += ' first item is "None"'
1501- elif second is None:
1502- msg += ' second item is "None"'
1503- elif not first == second:
1504- from difflib import Differ
1505- if isinstance(first, set):
1506- first = list(first)
1507- second = list(second)
1508- first.sort()
1509- second.sort()
1510- else:
1511- first = list(first)
1512- second = list(second)
1513- diff = Differ().compare(second, first)
1514- # switching first and second, because usually second
1515- # is the reference we are testing against
1516- msg += '\n' + '\n'.join(diff)
1517- else:
1518- return
1519-
1520- raise self.failureException, msg.encode('utf-8')
1521+ from zim.index import Index
1522+
1523+ notebook = Notebook(index=Index(dbfile=':memory:'))
1524+ store = notebook.add_store(Path(':'), 'memory')
1525+ manifest = []
1526+ for name, text in WikiTestData:
1527+ manifest.append(name)
1528+ store.set_node(Path(name), text)
1529+ notebook.testdata_manifest = _expand_manifest(manifest)
1530+ notebook.index.update()
1531+
1532+ if fakedir:
1533+ dir = Dir(fakedir)
1534+ notebook.dir = dir
1535+ store.dir = dir
1536+
1537+ return notebook
1538+
1539+
1540+def new_files_notebook(dir):
1541+ '''Returns a new Notebook object with a file store
1542+
1543+ Uses data from L{WikiTestData}
1544+
1545+ @param path: a folder path, e.g. created by L{TestCase.create_tmp_dir()}
1546+ '''
1547+ from zim.fs import Dir
1548+ from zim.notebook import init_notebook, Notebook, Path
1549+ from zim.index import Index
1550+
1551+ dir = Dir(dir)
1552+ init_notebook(dir)
1553+ notebook = Notebook(dir=dir)
1554+ store = notebook.get_store(':')
1555+ manifest = []
1556+ for name, text in WikiTestData:
1557+ manifest.append(name)
1558+ page = store.get_page(Path(name))
1559+ page.parse('wiki', text)
1560+ store.store_page(page)
1561+ notebook.testdata_manifest = _expand_manifest(manifest)
1562+ notebook.index.update()
1563+
1564+ return notebook
1565+
1566
1567
1568 class MockObject(object):
1569@@ -260,28 +408,3 @@
1570
1571 setattr(self, name, my_mock_method)
1572 return my_mock_method
1573-
1574-
1575-class LoggingFilter(object):
1576- '''Base class for logging filters that can be used as a context
1577- using the "with" keyword. To subclass it you only need to set the
1578- logger to be used and (the begin of) the message to filter.
1579- '''
1580-
1581- logger = None
1582- message = None
1583-
1584- def __init__(self, logger=None, message=None):
1585- if logger: self.logger = logger
1586- if message: self.message = message
1587-
1588- self.loggerobj = logging.getLogger(self.logger)
1589-
1590- def __enter__(self):
1591- self.loggerobj.addFilter(self)
1592-
1593- def __exit__(self, *a):
1594- self.loggerobj.removeFilter(self)
1595-
1596- def filter(self, record):
1597- return not record.getMessage().startswith(self.message)
1598
1599=== modified file 'tests/applications.py'
1600--- tests/applications.py 2011-02-19 16:27:44 +0000
1601+++ tests/applications.py 2011-06-04 21:27:03 +0000
1602@@ -1,10 +1,8 @@
1603-
1604 # -*- coding: utf-8 -*-
1605
1606 # Copyright 2009 Jaap Karssenberg <jaap.karssenberg@gmail.com>
1607
1608 import tests
1609-from tests import TestCase, create_tmp_dir
1610
1611 import os
1612 import gtk
1613@@ -22,7 +20,7 @@
1614 return tuple(l)
1615
1616
1617-class TestApplications(TestCase):
1618+class TestApplications(tests.TestCase):
1619
1620 def testParseExec(self):
1621 '''Test parsing of .desktop Exec strings'''
1622@@ -76,7 +74,8 @@
1623 self.assertEqual(result, wanted)
1624
1625
1626-class TestCustomTools(TestCase):
1627+@tests.slowTest
1628+class TestCustomTools(tests.TestCase):
1629
1630 def testManager(self):
1631 '''Test CustomToolManager API'''
1632@@ -166,15 +165,14 @@
1633 # %t for selected text or word under cursor
1634 # %T for selected text or word under cursor with wiki format
1635
1636- notebook = tests.get_test_notebook()
1637+ path = self.get_tmp_name()
1638+ notebook = tests.new_notebook(fakedir=path)
1639 page = notebook.get_page(Path('Test:Foo'))
1640 pageview = StubPageView()
1641 args = (notebook, page, pageview)
1642
1643 tmpfile = TmpFile('tmp-page-source.txt').path
1644- dir = Dir(tests.create_tmp_dir('applications_TestCustomTools'))
1645- notebook.dir = dir # fake file store
1646- notebook._stores[''].dir = dir # fake file store
1647+ dir = notebook.dir
1648
1649 tool = CustomToolDict()
1650 tool.update( {
1651
1652=== modified file 'tests/async.py'
1653--- tests/async.py 2011-02-19 16:27:44 +0000
1654+++ tests/async.py 2011-06-04 21:27:03 +0000
1655@@ -9,6 +9,7 @@
1656
1657 import tests
1658
1659+import time
1660
1661 from zim.async import *
1662 from zim.fs import File
1663@@ -31,10 +32,11 @@
1664
1665 self.assertEqual(value, 'foo bar')
1666
1667+ @tests.slowTest
1668 def testFS(self):
1669 '''Test async FS operations'''
1670
1671- self.path = tests.create_tmp_dir('async_testFS')+'/file.txt'
1672+ self.path = self.create_tmp_dir('testFS')+'/file.txt'
1673
1674 file = File(self.path)
1675
1676@@ -45,3 +47,31 @@
1677 op2.wait()
1678
1679 self.assertEqual(file.read(), 'foo bar 2\n')
1680+
1681+
1682+class Counter(object):
1683+
1684+ def __init__(self):
1685+ self.i = 0
1686+
1687+ def count(self):
1688+ self.i += 1
1689+
1690+
1691+@tests.slowTest
1692+class TestDelayedCallback(tests.TestCase):
1693+
1694+ def runTest(self):
1695+ counter = Counter()
1696+
1697+ callback = DelayedCallback(500, lambda o: counter.count())
1698+ for i in range(3):
1699+ callback('foo')
1700+
1701+ for i in range(10):
1702+ time.sleep(1)
1703+ tests.gtk_process_events()
1704+ if callback.timer_id is None:
1705+ break
1706+
1707+ self.assertEqual(counter.i, 1)
1708
1709=== modified file 'tests/calendar.py'
1710--- tests/calendar.py 2011-02-19 16:27:44 +0000
1711+++ tests/calendar.py 2011-06-04 21:27:03 +0000
1712@@ -1,10 +1,9 @@
1713-
1714 # -*- coding: utf-8 -*-
1715
1716 # Copyright 2008 Jaap Karssenberg <jaap.karssenberg@gmail.com>
1717
1718 import tests
1719-from tests import TestCase
1720+
1721
1722 from datetime import date as dateclass
1723
1724@@ -13,9 +12,9 @@
1725 from zim.config import ConfigDict
1726
1727
1728-class TestCalendarPlugin(TestCase):
1729+@tests.slowTest
1730+class TestCalendarPlugin(tests.TestCase):
1731
1732- slowTest = True
1733
1734 def runTest(self):
1735 'Test Calendar plugin'
1736@@ -38,11 +37,11 @@
1737 ui_type = 'stub'
1738
1739 def __init__(self):
1740- self.notebook = tests.get_test_notebook()
1741+ self.notebook = tests.new_notebook()
1742 self.page = self.notebook.get_page(Path('Test:foo'))
1743 self.preferences = ConfigDict()
1744 self.uistate = ConfigDict()
1745-
1746+
1747 def connect(*a): pass
1748
1749 def connect_after(*a): pass
1750
1751=== modified file 'tests/config.py'
1752--- tests/config.py 2011-02-19 16:27:44 +0000
1753+++ tests/config.py 2011-06-04 21:27:03 +0000
1754@@ -21,6 +21,7 @@
1755 message = 'Invalid config value'
1756
1757
1758+
1759 class TestDirsTestSetup(TestCase):
1760
1761 def runTest(self):
1762@@ -40,16 +41,22 @@
1763 class TestDirsDefault(TestCase):
1764
1765 def setUp(self):
1766+ old_environ = {}
1767 for k in (
1768 'XDG_DATA_HOME', 'XDG_DATA_DIRS',
1769 'XDG_CONFIG_HOME', 'XDG_CONFIG_DIRS', 'XDG_CACHE_HOME'
1770 ):
1771- if k in os.environ: del os.environ[k]
1772-
1773- zim.config._set_basedirs() # refresh
1774-
1775- def tearDown(self):
1776- tests.set_environ() # re-set the environment
1777+ if k in os.environ:
1778+ old_environ[k] = os.environ[k]
1779+ del os.environ[k]
1780+
1781+ def restore_environ():
1782+ for k, v in old_environ.items():
1783+ os.environ[k] = v
1784+ zim.config._set_basedirs() # refresh
1785+
1786+ self.addCleanup(restore_environ)
1787+
1788 zim.config._set_basedirs() # refresh
1789
1790 def testValid(self):
1791@@ -91,14 +98,25 @@
1792 class TestDirsEnvironment(TestDirsDefault):
1793
1794 def setUp(self):
1795- os.environ.update( (
1796- ('XDG_DATA_HOME', '/foo/data/home'),
1797- ('XDG_DATA_DIRS', '/foo/data/dir1:/foo/data/dir2'),
1798- ('XDG_CONFIG_HOME', '/foo/config/home'),
1799- ('XDG_CONFIG_DIRS', '/foo/config/dir1:/foo/config/dir2'),
1800- ('XDG_CACHE_HOME', '/foo/cache')
1801- ) )
1802-
1803+ my_environ = {
1804+ 'XDG_DATA_HOME': '/foo/data/home',
1805+ 'XDG_DATA_DIRS': '/foo/data/dir1:/foo/data/dir2',
1806+ 'XDG_CONFIG_HOME': '/foo/config/home',
1807+ 'XDG_CONFIG_DIRS': '/foo/config/dir1:/foo/config/dir2',
1808+ 'XDG_CACHE_HOME': '/foo/cache',
1809+ }
1810+
1811+ old_environ = dict((name, os.environ.get(name)) for name in my_environ)
1812+
1813+ def restore_environ():
1814+ for k, v in old_environ.items():
1815+ if v:
1816+ os.environ[k] = v
1817+ zim.config._set_basedirs() # refresh
1818+
1819+ self.addCleanup(restore_environ)
1820+
1821+ os.environ.update(my_environ)
1822 zim.config._set_basedirs() # refresh
1823
1824 def testCorrect(self):
1825@@ -147,7 +165,7 @@
1826 none=None
1827
1828 '''
1829- self.assertEqualDiff(file.read(), text)
1830+ self.assertEqual(file.read(), text)
1831
1832 del conf
1833 conf = ConfigDictFile(file)
1834@@ -336,7 +354,7 @@
1835 headers = HeadersDict(text)
1836 self.assertEqual(headers['Foobar'], '123')
1837 self.assertEqual(headers['More-Lines'], 'test\n1234\ntest')
1838- self.assertEqualDiff(headers.dump(), text.splitlines(True))
1839+ self.assertEqual(headers.dump(), text.splitlines(True))
1840
1841 moretext='''\
1842 Foobar: 123
1843@@ -351,8 +369,8 @@
1844 lines = moretext.splitlines(True)
1845 headers = HeadersDict()
1846 headers.read(lines)
1847- self.assertEqualDiff(headers.dump(), text.splitlines(True))
1848- self.assertEqualDiff(lines, ['test 123\n', 'test 456\n'])
1849+ self.assertEqual(headers.dump(), text.splitlines(True))
1850+ self.assertEqual(lines, ['test 123\n', 'test 456\n'])
1851
1852 # error tolerance and case insensitivity
1853 text = '''\
1854@@ -420,4 +438,3 @@
1855 self.assertEqual(dict[Path('foo:bar:baz')]['key1'], 'foo')
1856 dict['']['key2'] = 'FOO'
1857 self.assertEqual(dict[Path('foo:bar:baz')]['key2'], 'FOO')
1858-
1859
1860=== modified file 'tests/daemon.py'
1861--- tests/daemon.py 2011-02-19 16:27:44 +0000
1862+++ tests/daemon.py 2011-06-04 21:27:03 +0000
1863@@ -4,7 +4,6 @@
1864 # Copyright 2009 Jaap Karssenberg <jaap.karssenberg@gmail.com>
1865
1866 import tests
1867-from tests import TestCase
1868
1869 import os
1870 import time
1871@@ -27,21 +26,13 @@
1872 assert file.exists() == exists, 'File did not (dis-)appear'
1873
1874
1875-class TestDaemon(TestCase):
1876-
1877- slowTest = True
1878-
1879- @classmethod
1880- def skipTest(klass):
1881- if os.name == 'nt':
1882- return 'Daemon not supported on Windows'
1883- else:
1884- return False
1885-
1886+@tests.slowTest
1887+@tests.skipIf(os.name == 'nt', 'Daemon not supported on Windows')
1888+class TestDaemon(tests.TestCase):
1889
1890 def runTest(self):
1891 '''Test GUI daemon interaction'''
1892- dir = Dir(tests.create_tmp_dir('daemon'))
1893+ dir = Dir(self.create_tmp_dir())
1894 socket = dir.file('test-socket')
1895 pidfile = dir.file('daemon.pid')
1896
1897
1898=== modified file 'tests/data/notebook-wiki.xml'
1899--- tests/data/notebook-wiki.xml 2010-09-12 21:33:23 +0000
1900+++ tests/data/notebook-wiki.xml 2011-06-04 21:27:03 +0000
1901@@ -1,6 +1,9 @@
1902 <?xml version="1.0" encoding="utf-8"?>
1903 <!-- this file is NOT in store.xml format -->
1904 <pagelist>
1905+<page name="TODOList">
1906+TEst 123
1907+</page>
1908 <page name="TODOList:foo">
1909 TODO: fix 1 !!!
1910
1911@@ -17,6 +20,15 @@
1912
1913 [[Test:Foo:BAR]]
1914 </page>
1915+<page name='TrashMe'>
1916+Trash me!
1917+</page>
1918+<page name='TrashMe:sub page 1'>
1919+Trash me!
1920+</page>
1921+<page name='TrashMe:sub page 2'>
1922+Trash me!
1923+</page>
1924 <page name="Test:wiki">
1925 Content-Type: text/x-zim-wiki
1926 Wiki-Format: zim 0.26
1927@@ -139,6 +151,31 @@
1928
1929 •• Search Me ••
1930 </page>
1931+<page name="Test:tags">
1932+= Tags =
1933+
1934+This page contains @tags in all kind of@places like the
1935+@beginning of a line or its @end
1936+but also after
1937+
1938+ @tabs i.e. within @verbatim blocks
1939+
1940+within [[foo:bar|Link @captions]] as well as
1941+* @enumerations
1942+
1943+Not to forget within
1944+
1945+== @Headings ==
1946+
1947+and
1948+
1949+=== Their last @word ===
1950+
1951+And with a different &#64;encoding
1952+
1953+It also tests which weird @s!gns (sees only "s") and @num6ers @wit#in (aka
1954+"wit") tags and tries hard to @cr@sh ("cr") the parser.
1955+</page>
1956 <page name="Test:Foo Bar:Dus Ja Hmm">
1957 Testing with whitespace in page name
1958 </page>
1959@@ -169,6 +206,7 @@
1960 IMAGE: {{../my-image.png?width=600|Foo Bar}}
1961 LINKS: [[:foo:bar]] [[./file.png]] file:///etc/passwd
1962 LINKS: [[Foo]][[Bar]]
1963+TAGS: @foo @bar
1964
1965 Some indented
1966 paragraphs go here ...
1967
1968=== modified file 'tests/diagrameditor.py'
1969--- tests/diagrameditor.py 2011-02-19 16:27:44 +0000
1970+++ tests/diagrameditor.py 2011-06-04 21:27:03 +0000
1971@@ -3,20 +3,13 @@
1972 # Copyright 2009 Jaap Karssenberg <jaap.karssenberg@gmail.com>
1973
1974 import tests
1975-from tests import TestCase
1976
1977 from zim.plugins.diagrameditor import *
1978
1979-class TestDiagramEditor(TestCase):
1980-
1981- slowTest = True
1982-
1983- @classmethod
1984- def skipTest(klass):
1985- if not InsertDiagramPlugin.check_dependencies_ok():
1986- return 'Missing dependencies'
1987- else:
1988- return False
1989+
1990+@tests.slowTest
1991+@tests.skipUnless(InsertDiagramPlugin.check_dependencies_ok(), 'Missing dependencies')
1992+class TestDiagramEditor(tests.TestCase):
1993
1994 def runTest(self):
1995 'Test Diagram Editor plugin'
1996
1997=== modified file 'tests/equationeditor.py'
1998--- tests/equationeditor.py 2011-02-19 16:27:44 +0000
1999+++ tests/equationeditor.py 2011-06-04 21:27:03 +0000
2000@@ -3,20 +3,13 @@
2001 # Copyright 2009 Jaap Karssenberg <jaap.karssenberg@gmail.com>
2002
2003 import tests
2004-from tests import TestCase
2005
2006 from zim.plugins.equationeditor import *
2007
2008-class TestEquationEditor(TestCase):
2009-
2010- slowTest = True
2011-
2012- @classmethod
2013- def skipTest(klass):
2014- if not InsertEquationPlugin.check_dependencies_ok():
2015- return 'Missing dependencies'
2016- else:
2017- return False
2018+
2019+@tests.slowTest
2020+@tests.skipUnless(InsertEquationPlugin.check_dependencies_ok(), 'Missing dependencies')
2021+class TestEquationEditor(tests.TestCase):
2022
2023 def runTest(self):
2024 'Test Equation Editor plugin'
2025
2026=== modified file 'tests/export.py'
2027--- tests/export.py 2011-02-19 16:27:44 +0000
2028+++ tests/export.py 2011-06-04 21:27:03 +0000
2029@@ -2,7 +2,8 @@
2030
2031 # Copyright 2009 Jaap Karssenberg <jaap.karssenberg@gmail.com>
2032
2033-from tests import TestCase, MockObject, create_tmp_dir, get_test_notebook, get_test_data
2034+import tests
2035+
2036
2037 from subprocess import check_call
2038
2039@@ -12,38 +13,35 @@
2040
2041 # TODO add check that attachments are copied correctly
2042
2043-class TestLinker(TestCase):
2044+class TestLinker(tests.TestCase):
2045
2046 def runTest(self):
2047 '''Test proper linking of files in export'''
2048- notebook = get_test_notebook()
2049- notebook.get_store(Path(':')).dir = Dir('/source/dir/') # fake source dir
2050+ notebook = tests.new_notebook(fakedir='/source/dir/')
2051
2052 linker = StaticLinker('html', notebook)
2053 linker.set_usebase(True) # normally set by html format module
2054 linker.set_path(Path('foo:bar')) # normally set by exporter
2055 linker.set_base(Dir('/source/dir/foo')) # normally set by exporter
2056
2057- self.assertEqual(linker.page('+dus'), './bar/dus.html')
2058- self.assertEqual(linker.page('dus'), './dus.html')
2059- self.assertEqual(linker.file('./dus.pdf'), './bar/dus.pdf')
2060- self.assertEqual(linker.file('../dus.pdf'), './dus.pdf')
2061- self.assertEqual(linker.file('../../dus.pdf'), '../dus.pdf')
2062-
2063-
2064-class TestExport(TestCase):
2065-
2066- slowTest = True
2067+ self.assertEqual(linker.link_page('+dus'), './bar/dus.html')
2068+ self.assertEqual(linker.link_page('dus'), './dus.html')
2069+ self.assertEqual(linker.link_file('./dus.pdf'), './bar/dus.pdf')
2070+ self.assertEqual(linker.link_file('../dus.pdf'), './dus.pdf')
2071+ self.assertEqual(linker.link_file('../../dus.pdf'), '../dus.pdf')
2072+
2073+
2074+@tests.slowTest
2075+class TestExport(tests.TestCase):
2076
2077 options = {'format': 'html', 'template': 'Default'}
2078
2079 def setUp(self):
2080- self.dir = Dir(create_tmp_dir('export_ExportedFiles'))
2081+ self.dir = Dir(self.create_tmp_dir('exported_files'))
2082
2083 def export(self):
2084- notebook = get_test_notebook()
2085- notebook.get_store(Path(':')).dir = Dir('/foo/bar') # fake source dir
2086- notebook.index.update()
2087+ notebook = tests.new_notebook(fakedir='/foo/bar')
2088+
2089 exporter = Exporter(notebook, **self.options)
2090 exporter.export_all(self.dir)
2091
2092@@ -75,10 +73,10 @@
2093 class TestExportCommandLine(TestExportFullOptions):
2094
2095 def export(self):
2096- dir = Dir(create_tmp_dir('export_SourceFiles'))
2097+ dir = Dir(self.create_tmp_dir('source_files'))
2098 init_notebook(dir)
2099 notebook = Notebook(dir=dir)
2100- for name, text in get_test_data('wiki'):
2101+ for name, text in tests.WikiTestData:
2102 page = notebook.get_page(Path(name))
2103 page.parse('wiki', text)
2104 notebook.store_page(page)
2105@@ -94,21 +92,18 @@
2106 # TODO test export single page from command line
2107
2108
2109-class TestExportDialog(TestCase):
2110-
2111- slowTest = True
2112+@tests.slowTest
2113+class TestExportDialog(tests.TestCase):
2114
2115 def runTest(self):
2116 '''Test ExportDialog'''
2117 from zim.gui.exportdialog import ExportDialog
2118
2119- dir = Dir(create_tmp_dir('export_ExportDialog'))
2120-
2121- notebook = get_test_notebook()
2122- notebook.get_store(Path(':')).dir = Dir('/foo/bar') # fake source dir
2123- notebook.index.update()
2124-
2125- ui = MockObject()
2126+ dir = Dir(self.create_tmp_dir())
2127+
2128+ notebook = tests.new_notebook(fakedir='/foo/bar')
2129+
2130+ ui = tests.MockObject()
2131 ui.notebook = notebook
2132 ui.page = Path('foo')
2133 ui.mainwindow = None
2134
2135=== modified file 'tests/formats.py'
2136--- tests/formats.py 2011-02-19 16:27:44 +0000
2137+++ tests/formats.py 2011-06-04 21:27:03 +0000
2138@@ -6,18 +6,20 @@
2139
2140 from __future__ import with_statement
2141
2142-from tests import TestCase, get_test_data_page, get_test_page, LoggingFilter
2143+
2144+import tests
2145
2146 from zim.formats import *
2147-from zim.notebook import Link
2148+from zim.notebook import Path, Link
2149 from zim.parsing import link_type
2150
2151 if not ElementTreeModule.__name__.endswith('cElementTree'):
2152 print 'WARNING: using ElementTree instead of cElementTree'
2153
2154-wikitext = get_test_data_page('wiki', 'roundtrip')
2155-
2156-class TestParseTree(TestCase):
2157+wikitext = tests.WikiTestData.get('roundtrip')
2158+
2159+
2160+class TestParseTree(tests.TestCase):
2161
2162 def setUp(self):
2163 self.xml = '''\
2164@@ -41,7 +43,7 @@
2165 e = tree.getroot()
2166 self.assertEqual(e.tag, 'zim-tree') # check content
2167 text = tree.tostring()
2168- self.assertEqualDiff(text, self.xml)
2169+ self.assertEqual(text, self.xml)
2170
2171 def testcleanup_headings(self):
2172 '''Test ParseTree.cleanup_headings()'''
2173@@ -60,7 +62,7 @@
2174 </zim-tree>'''
2175 tree.cleanup_headings(offset=1, max=4)
2176 text = tree.tostring()
2177- self.assertEqualDiff(text, wanted)
2178+ self.assertEqual(text, wanted)
2179
2180 def testSetHeading(self):
2181 '''Test ParseTree.set_heading()'''
2182@@ -79,7 +81,7 @@
2183 <h level="6">Head 8</h>
2184 </zim-tree>'''
2185 text = tree.tostring()
2186- self.assertEqualDiff(text, wanted)
2187+ self.assertEqual(text, wanted)
2188
2189 def testExtend(self):
2190 tree1 = ParseTree().fromstring(self.xml)
2191@@ -107,13 +109,30 @@
2192 <h level="6">Head 8</h>
2193 </zim-tree>'''
2194 text = tree.tostring()
2195- self.assertEqualDiff(text, wanted)
2196-
2197-class TestTextFormat(TestCase):
2198+ self.assertEqual(text, wanted)
2199+
2200+
2201+ def testGetEndsWithNewline(self):
2202+ for xml, newline in (
2203+ ('<zim-tree partial="True">foo</zim-tree>', False),
2204+ ('<zim-tree partial="True"><strong>foo</strong></zim-tree>', False),
2205+ ('<zim-tree partial="True"><strong>foo</strong>\n</zim-tree>', True),
2206+ ('<zim-tree partial="True"><strong>foo\n</strong></zim-tree>', True),
2207+ ('<zim-tree partial="True"><strong>foo</strong>\n<img src="foo"></img></zim-tree>', False),
2208+ ('<zim-tree partial="True"><li bullet="unchecked-box" indent="0">foo</li></zim-tree>', True),
2209+ ('<zim-tree partial="True"><li bullet="unchecked-box" indent="0"><strong>foo</strong></li></zim-tree>', True),
2210+ ('<zim-tree partial="True"><li bullet="unchecked-box" indent="0"><strong>foo</strong></li></zim-tree>', True),
2211+ ):
2212+ tree = ParseTree().fromstring(xml)
2213+ self.assertEqual(tree.get_ends_with_newline(), newline)
2214+
2215+
2216+class TestTextFormat(tests.TestCase):
2217
2218 def setUp(self):
2219 self.format = get_format('plain')
2220- notebook, self.page = get_test_page()
2221+ notebook = tests.new_notebook()
2222+ self.page = notebook.get_page(Path('Foo'))
2223
2224 def testRoundtrip(self):
2225 '''Test roundtrip for plain text'''
2226@@ -123,8 +142,8 @@
2227 #~ print '>>>\n'+tree.tostring()+'\n<<<\n'
2228 xml = tree.tostring()
2229 output = self.format.Dumper().dump(tree)
2230- self.assertEqualDiff(tree.tostring(), xml) # check tree not modified
2231- self.assertEqualDiff(output, wikitext.splitlines(True))
2232+ self.assertEqual(tree.tostring(), xml) # check tree not modified
2233+ self.assertEqual(output, wikitext.splitlines(True))
2234
2235 def testDumping(self):
2236 '''Test dumping page to plain text'''
2237@@ -153,6 +172,7 @@
2238 IMAGE: Foo Bar
2239 LINKS: :foo:bar ./file.png file:///etc/passwd
2240 LINKS: FooBar
2241+TAGS: @foo @bar
2242
2243 Some indented
2244 paragraphs go here ...
2245@@ -193,7 +213,7 @@
2246
2247 That's all ...
2248 '''
2249- self.assertEqualDiff(text, wanted.splitlines(True))
2250+ self.assertEqual(text, wanted.splitlines(True))
2251
2252
2253 class TestWikiFormat(TestTextFormat):
2254@@ -201,7 +221,9 @@
2255 def setUp(self):
2256 #~ TestTextFormat.setUp(self)
2257 self.format = get_format('wiki')
2258- notebook, self.page = get_test_page()
2259+ notebook = tests.new_notebook()
2260+ self.page = notebook.get_page(Path('Foo'))
2261+
2262
2263 def testRoundtrip(self):
2264 '''Test roundtrip for wiki text'''
2265@@ -224,7 +246,7 @@
2266 #~ print '>>>\n'+tostring(tree)+'\n<<<\n'
2267 #~ self.assertEquals(tree.getroot().attrib['Content-Type'], 'text/x-zim-wiki')
2268 #~ output = self.format.Dumper().dump(tree)
2269- #~ self.assertEqualDiff(output, text.splitlines(True))
2270+ #~ self.assertEqual(output, text.splitlines(True))
2271
2272 def testParsing(self):
2273 '''Test wiki parse tree generation.'''
2274@@ -252,6 +274,7 @@
2275 <p>IMAGE: <img src="../my-image.png" width="600">Foo Bar</img>
2276 LINKS: <link href=":foo:bar">:foo:bar</link> <link href="./file.png">./file.png</link> <link href="file:///etc/passwd">file:///etc/passwd</link>
2277 LINKS: <link href="Foo">Foo</link><link href="Bar">Bar</link>
2278+TAGS: <tag name="foo">@foo</tag> <tag name="bar">@bar</tag>
2279 </p>
2280 <p><div indent="1">Some indented
2281 paragraphs go here ...
2282@@ -279,7 +302,7 @@
2283 <p>That's all ...
2284 </p></zim-tree>'''
2285 t = self.format.Parser().parse(wikitext)
2286- self.assertEqualDiff(t.tostring(), tree)
2287+ self.assertEqual(t.tostring(), tree)
2288
2289 def testUnicodeBullet(self):
2290 '''Test support for unicode bullets in source'''
2291@@ -297,7 +320,7 @@
2292 '''
2293 tree = self.format.Parser().parse(input)
2294 output = self.format.Dumper().dump(tree)
2295- self.assertEqualDiff(output, text.splitlines(True))
2296+ self.assertEqual(output, text.splitlines(True))
2297
2298 def testLink(self):
2299 '''Test iterator function for link'''
2300@@ -340,16 +363,17 @@
2301 <p>test 4 5 6
2302 </p></zim-tree>'''
2303 t = self.format.Parser(version='Unknown').parse(input)
2304- self.assertEqualDiff(t.tostring(), xml)
2305+ self.assertEqual(t.tostring(), xml)
2306 output = self.format.Dumper().dump(t)
2307- self.assertEqualDiff(output, wanted.splitlines(True))
2308-
2309-
2310-class TestHtmlFormat(TestCase):
2311+ self.assertEqual(output, wanted.splitlines(True))
2312+
2313+
2314+class TestHtmlFormat(tests.TestCase):
2315
2316 def setUp(self):
2317 self.format = get_format('html')
2318- notebook, self.page = get_test_page()
2319+ notebook = tests.new_notebook()
2320+ self.page = notebook.get_page(Path('Foo'))
2321
2322 def testEncoding(self):
2323 '''Test HTML encoding'''
2324@@ -399,6 +423,7 @@
2325 IMAGE: <img src="img://../my-image.png" alt="Foo Bar" width="600"><br>
2326 LINKS: <a href="page://:foo:bar" title=":foo:bar">:foo:bar</a> <a href="file://./file.png" title="./file.png">./file.png</a> <a href="file://file:///etc/passwd" title="file:///etc/passwd">file:///etc/passwd</a><br>
2327 LINKS: <a href="page://Foo" title="Foo">Foo</a><a href="page://Bar" title="Bar">Bar</a><br>
2328+TAGS: <span class="zim-tag">@foo</span> <span class="zim-tag">@bar</span><br>
2329 </p>
2330
2331 <p>
2332@@ -478,16 +503,16 @@
2333 That's all ...<br>
2334 </p>
2335 '''
2336- self.assertEqualDiff(output, html.splitlines(True))
2337-
2338-
2339-class LatexLoggingFilter(LoggingFilter):
2340+ self.assertEqual(output, html.splitlines(True))
2341+
2342+
2343+class LatexLoggingFilter(tests.LoggingFilter):
2344
2345 logger = 'zim.formats.latex'
2346 message = 'No document type set in template'
2347
2348
2349-class TestLatexFormat(TestCase):
2350+class TestLatexFormat(tests.TestCase):
2351
2352 def testEncode(self):
2353 '''test the escaping of certain characters'''
2354@@ -501,7 +526,7 @@
2355 '''test the export of a wiki page to latex'''
2356 with LatexLoggingFilter():
2357 format = get_format('LaTeX')
2358- testpage = get_test_data_page('wiki','Test:wiki')
2359+ testpage = tests.WikiTestData.get('Test:wiki')
2360 tree = get_format('wiki').Parser().parse(testpage)
2361 output = format.Dumper(linker=StubLinker()).dump(tree)
2362 self.assertTrue('\chapter{Foo Bar}\n' in output)
2363@@ -520,7 +545,7 @@
2364 def icon(self, name): return 'icon://' + name
2365
2366
2367-class TestParseTreeBuilder(TestCase):
2368+class TestParseTreeBuilder(tests.TestCase):
2369
2370 def runTest(self):
2371 '''Test ParseTreeBuilder class'''
2372@@ -579,5 +604,4 @@
2373 builder.feed(input)
2374 root = builder.close()
2375 tree = ParseTree(root)
2376- self.assertEqualDiff(tree.tostring(), wanted)
2377-
2378+ self.assertEqual(tree.tostring(), wanted)
2379
2380=== modified file 'tests/fs.py'
2381--- tests/fs.py 2011-02-19 16:27:44 +0000
2382+++ tests/fs.py 2011-06-04 21:27:03 +0000
2383@@ -11,6 +11,7 @@
2384 import os
2385 import time
2386
2387+import zim.fs
2388 from zim.fs import *
2389 from zim.fs import Path, FileHandle, FileWriteError, TmpFile, get_tmpdir, normalize_win32_share, PathLookupError, FileNotFoundError, FilteredDir, isabs, joinpath
2390 from zim.errors import Error
2391@@ -118,7 +119,7 @@
2392 def testFileHandle(self):
2393 '''Test FileHandle object'''
2394 self.on_close_called = False
2395- tmpdir = tests.create_tmp_dir('fs_testFile')
2396+ tmpdir = self.create_tmp_dir('testFileHandle')
2397 fh = FileHandle(
2398 tmpdir+'/foo.txt', mode='w', on_close=self.on_close)
2399 fh.write('duss')
2400@@ -130,7 +131,7 @@
2401
2402 def testFile(self):
2403 '''Test File object'''
2404- tmpdir = tests.create_tmp_dir('fs_testFile')
2405+ tmpdir = self.create_tmp_dir('testFile')
2406 file = File(tmpdir+'/foo/bar/baz.txt')
2407 assert not file.exists()
2408 file.touch()
2409@@ -230,7 +231,7 @@
2410
2411 def testDir(self):
2412 '''Test Dir object'''
2413- tmpdir = tests.create_tmp_dir('fs_testDir')
2414+ tmpdir = self.create_tmp_dir('testDir')
2415 dir = Dir(tmpdir+'/foo/bar')
2416 assert not dir.exists()
2417
2418@@ -261,12 +262,22 @@
2419
2420 self.assertEqual(File((dir, 'foo.txt')), dir.file('foo.txt'))
2421 self.assertEqual(dir.file(File((dir, 'foo.txt'))), dir.file('foo.txt'))
2422+ self.assertEqual(dir.file(Path((dir, 'foo.txt'))), dir.file('foo.txt'))
2423+ self.assertEqual(dir.file(('foo.txt',)), dir.file('foo.txt'))
2424 self.assertRaises(PathLookupError, dir.file, File('/foo/bar.txt')) # not below dir
2425
2426+ self.assertEqual(dir.resolve_file('../foo.txt'), dir.dir.file('foo.txt'))
2427+ self.assertEqual(dir.resolve_file(File('/foo/bar.txt')), File('/foo/bar.txt'))
2428+
2429 self.assertEqual(Dir((dir, 'bar')), dir.subdir('bar'))
2430 self.assertEqual(dir.subdir(Dir((dir, 'bar'))), dir.subdir('bar'))
2431+ self.assertEqual(dir.subdir(Path((dir, 'bar'))), dir.subdir('bar'))
2432+ self.assertEqual(dir.subdir(('bar',)), dir.subdir('bar'))
2433 self.assertRaises(PathLookupError, dir.subdir, Dir('/foo/bar')) # not below dir
2434
2435+ self.assertEqual(dir.resolve_dir('../bar'), dir.dir.subdir('bar'))
2436+ self.assertEqual(dir.resolve_dir(Dir('/foo/bar')), Dir('/foo/bar'))
2437+
2438 self.assertRaises(OSError, dir.remove) # dir not empty
2439 self.assertTrue(dir.exists())
2440 dir.cleanup()
2441@@ -279,12 +290,11 @@
2442 self.assertEqual(dir.list(), []) # list non-existing dir
2443
2444
2445+@tests.slowTest
2446 class TestFileOverwrite(tests.TestCase):
2447
2448- slowTest = True
2449-
2450 def setUp(self):
2451- self.path = tests.create_tmp_dir('fs_testOverwrite')+'/file.txt'
2452+ self.path = self.create_tmp_dir()+'/file.txt'
2453
2454 def modify(self, func):
2455 mtime = os.stat(self.path).st_mtime
2456@@ -329,22 +339,15 @@
2457 self.assertEquals(file.read(), 'foo')
2458
2459
2460+@tests.slowTest
2461+@tests.skipUnless(hasattr(os, 'symlink'), 'OS does not supprot symlinks')
2462 class TestSymlinks(tests.TestCase):
2463
2464- slowTest = True
2465-
2466- @staticmethod
2467- def skipTest():
2468- if not hasattr(os, 'symlink'):
2469- return 'OS does not supprot symlinks'
2470- else:
2471- return False
2472-
2473 def runTest(self):
2474 '''Test file operations are safe for symlinks'''
2475
2476 # Set up a file structue with a symlink
2477- tmpdir = tests.create_tmp_dir('fs_TestSymLinks')
2478+ tmpdir = self.create_tmp_dir()
2479 targetdir = Dir(tmpdir + '/target')
2480 targetdir.file('foo.txt').touch()
2481 targetfile = File(tmpdir + '/target.txt')
2482@@ -383,3 +386,28 @@
2483 self.assertEqual(dir.list(), [])
2484 self.assertTrue(targetdir.exists())
2485 self.assertEqual(targetdir.list(), ['foo.txt'])
2486+
2487+
2488+@tests.slowTest
2489+@tests.skipUnless(zim.fs.gio, 'Trashing not supported, \'gio\' is missing')
2490+class TestTrash(tests.TestCase):
2491+
2492+ def runTest(self):
2493+ '''Test trashing files and folders'''
2494+ root = Dir(self.create_tmp_dir())
2495+ file = root.file('test.txt')
2496+ file.touch()
2497+ self.assertTrue(file.exists())
2498+ self.assertTrue(file.trash())
2499+ self.assertFalse(file.exists())
2500+ dir = root.subdir('test')
2501+ dir.touch()
2502+ self.assertTrue(dir.exists())
2503+ self.assertTrue(dir.trash())
2504+ self.assertFalse(dir.exists())
2505+
2506+ # fails silent if file does not exist
2507+ self.assertFalse(file.trash())
2508+ self.assertFalse(dir.trash())
2509+
2510+ # How can we cause gio to give an error and test that case ??
2511
2512=== modified file 'tests/gui.py'
2513--- tests/gui.py 2011-02-14 20:22:50 +0000
2514+++ tests/gui.py 2011-06-04 21:27:03 +0000
2515@@ -1,23 +1,31 @@
2516-
2517-from tests import TestCase, get_test_notebook, create_tmp_dir, MockObject
2518+# -*- coding: utf-8 -*-
2519+
2520+# Copyright 2009 Jaap Karssenberg <jaap.karssenberg@gmail.com>
2521+
2522+from __future__ import with_statement
2523+
2524+import tests
2525+
2526
2527 from zim.errors import Error
2528-from zim.notebook import Path
2529+from zim.notebook import get_notebook_list, Path, NotebookInfo
2530 from zim.fs import File, Dir
2531+from zim.config import config_file
2532
2533 import zim.gui
2534
2535 from zim.gui.clipboard import *
2536
2537
2538-class TestClipboard(TestCase):
2539+@tests.slowTest
2540+class TestClipboard(tests.TestCase):
2541
2542 def runTest(self):
2543 '''Test clipboard interaction'''
2544+ path = self.get_tmp_name()
2545+ notebook = tests.new_notebook(fakedir=path)
2546+
2547 clipboard = Clipboard()
2548- notebook = get_test_notebook()
2549- tmp_dir = create_tmp_dir('gui_Clipboard')
2550- notebook.get_store(Path(':')).dir = Dir(tmp_dir) # fake source dir
2551
2552 # tree roundtrip
2553 for pagename in ('Test:wiki', 'roundtrip'):
2554@@ -36,7 +44,7 @@
2555
2556 wanted = 'some **bold** text\n'
2557 text = clipboard.wait_for_text()
2558- self.assertEqualDiff(text, wanted)
2559+ self.assertEqual(text, wanted)
2560
2561 wanted = '''\
2562 <html>
2563@@ -54,7 +62,7 @@
2564 </html>
2565 '''
2566 selection = clipboard.wait_for_contents('text/html')
2567- self.assertEqualDiff(selection.data, wanted)
2568+ self.assertEqual(selection.data, wanted)
2569
2570 wanted = '''\
2571 Version:1.0\r
2572@@ -72,7 +80,7 @@
2573 </p>
2574 <!--EndFragment--></BODY></HTML>'''
2575 selection = clipboard.wait_for_contents('HTML Format')
2576- self.assertEqualDiff(selection.data, wanted)
2577+ self.assertEqual(selection.data, wanted)
2578
2579
2580 # pagelink -> ..
2581@@ -153,12 +161,12 @@
2582 self.assertEqual(notebook.resolve_file(rel_path, page), file_obj)
2583
2584
2585-class TestDialogs(TestCase):
2586-
2587- slowTest = True
2588+@tests.slowTest
2589+class TestDialogs(tests.TestCase):
2590
2591 def setUp(self):
2592- self.ui = MockUI('Test:foo:bar')
2593+ path = self.create_tmp_dir()
2594+ self.ui = MockUI('Test:foo:bar', fakedir=path)
2595
2596 def testOpenPageDialog(self):
2597 '''Test OpenPageDialog dialog (Jump To...)'''
2598@@ -213,7 +221,7 @@
2599
2600 def testSaveCopyDialog(self):
2601 '''Test SaveCopyDialog'''
2602- tmp_dir = create_tmp_dir('gui_SaveCopyDialog')
2603+ tmp_dir = self.create_tmp_dir('testSaveCopyDialog')
2604 file = File((tmp_dir, 'save_copy.txt'))
2605 self.assertFalse(file.exists())
2606 dialog = zim.gui.SaveCopyDialog(self.ui)
2607@@ -223,11 +231,10 @@
2608
2609 def testImportPageDialog(self):
2610 '''Test ImportPageDialog'''
2611- tmp_dir = create_tmp_dir('gui_ImportPageDialog')
2612+ tmp_dir = self.create_tmp_dir('testImportPageDialog')
2613 file = File((tmp_dir, 'import_page.txt'))
2614 file.write('test 123\n')
2615 self.assertTrue(file.exists())
2616- self.ui = MockUI()
2617 dialog = zim.gui.ImportPageDialog(self.ui)
2618 dialog.set_file(file)
2619 #~ dialog.assert_response_ok()
2620@@ -295,15 +302,13 @@
2621
2622 def testAttachFileDialog(self):
2623 '''Test AttachFileDialog'''
2624- tmp_dir = create_tmp_dir('gui_AttachFileDialog')
2625+ tmp_dir = self.create_tmp_dir('testAttachFileDialog')
2626 file = File((tmp_dir, 'file_to_be_attached'))
2627 file.write('Test 1 2 3\n')
2628 newfile = File((tmp_dir, 'attachments', 'Test', 'foo', 'file_to_be_attached'))
2629 self.assertTrue(file.exists())
2630 self.assertFalse(newfile.exists())
2631
2632- store = self.ui.notebook.get_store(Path(':'))
2633- store.dir = Dir((tmp_dir, 'attachments')) # Fake dir based notebook
2634 dialog = zim.gui.AttachFileDialog(self.ui, path=Path('Test:foo'))
2635 dialog.set_file(file)
2636 #~ dialog.assert_response_ok()
2637@@ -311,20 +316,19 @@
2638 #~ self.assertTrue(file.exists()) # No move or delete happened
2639 #~ self.assertTrue(newfile.exists())
2640 #~ self.assertTrue(newfile.compare(file))
2641- #~ del store.dir
2642
2643 def testSearchDialog(self):
2644 '''Test SearchDialog'''
2645 from zim.gui.searchdialog import SearchDialog
2646- self.ui.notebook = get_test_notebook()
2647+ self.ui.notebook = tests.new_notebook()
2648 dialog = SearchDialog(self.ui)
2649 dialog.query_entry.set_text('Foo')
2650 dialog.query_entry.activate()
2651 model = dialog.results_treeview.get_model()
2652 self.assertTrue(len(model) > 3)
2653
2654- self.ui.mainwindow = MockObject()
2655- self.ui.mainwindow.pageview = MockObject()
2656+ self.ui.mainwindow = tests.MockObject()
2657+ self.ui.mainwindow.pageview = tests.MockObject()
2658 col = dialog.results_treeview.get_column(0)
2659 dialog.results_treeview.row_activated((0,), col)
2660
2661@@ -380,8 +384,52 @@
2662 def testPropertiesDialog(self):
2663 '''Test PropertiesDialog'''
2664 from zim.gui.propertiesdialog import PropertiesDialog
2665- dialog = PropertiesDialog(self.ui)
2666- dialog.assert_response_ok()
2667+ self.ui.readonly = True
2668+ dialog = PropertiesDialog(self.ui)
2669+ dialog.assert_response_ok()
2670+
2671+ from zim.config import ConfigDictFile
2672+ notebook = self.ui.notebook
2673+ file = notebook.dir.file('notebook.zim')
2674+ notebook.config = ConfigDictFile(file)
2675+ self.ui.readonly = False
2676+
2677+ config1 = {
2678+ 'name': 'Notebook Foo',
2679+ 'home': 'Home',
2680+ 'icon': './icon.png',
2681+ 'document_root': '/foo',
2682+ 'shared': False,
2683+ }
2684+ config2 = {
2685+ 'name': 'Notebook Bar',
2686+ 'home': 'HomeSweetHome',
2687+ 'icon': './picture.png',
2688+ 'document_root': '/bar',
2689+ 'shared': True,
2690+ }
2691+ notebook.save_properties(**config1)
2692+ self.assertEqual(notebook.config['Notebook'], config1)
2693+
2694+ dialog = PropertiesDialog(self.ui)
2695+ dialog.assert_response_ok()
2696+
2697+ self.assertEqual(notebook.config['Notebook'], config1)
2698+ self.assertEqual(notebook.name, config1['name'])
2699+ self.assertEqual(notebook.get_home_page(), Path(config1['home']))
2700+ self.assertEqual(notebook.icon, notebook.dir.file(config1['icon']).path)
2701+ self.assertEqual(notebook.document_root, Dir(config1['document_root']))
2702+
2703+ dialog = PropertiesDialog(self.ui)
2704+ dialog.form.update(config2)
2705+ dialog.assert_response_ok()
2706+
2707+ self.assertEqual(notebook.config['Notebook'], config2)
2708+ self.assertEqual(notebook.name, config2['name'])
2709+ self.assertEqual(notebook.get_home_page(), Path(config2['home']))
2710+ self.assertEqual(notebook.icon, notebook.dir.file(config2['icon']).path)
2711+ self.assertEqual(notebook.document_root, Dir(config2['document_root']))
2712+
2713
2714 def testPreferencesDialog(self):
2715 '''Test PreferencesDialog'''
2716@@ -432,14 +480,114 @@
2717
2718
2719 # Test for ExportDialog can be found in test/export.py
2720-
2721-
2722-class MockUI(MockObject):
2723-
2724- tmp_dir = create_tmp_dir('gui_MockUI')
2725-
2726- def __init__(self, page=None):
2727- MockObject.__init__(self)
2728+ # Test for NotebookDialog is in separate class below
2729+
2730+
2731+@tests.slowTest
2732+class TestGtkInterface(tests.TestCase):
2733+
2734+ def runTest(self):
2735+ ui = zim.gui.GtkInterface()
2736+
2737+ # test populating menus
2738+ menu = gtk.Menu()
2739+ ui.populate_popup('page_popup', menu)
2740+ items = menu.get_children()
2741+ self.assertTrue(len(items) > 3)
2742+
2743+
2744+@tests.slowTest
2745+class TestNotebookDialog(tests.TestCase):
2746+
2747+ def setUp(self):
2748+ list = config_file('notebooks.list')
2749+ file = list.file
2750+ if file.exists():
2751+ file.remove()
2752+
2753+ def runTest(self):
2754+ from zim.gui.notebookdialog import prompt_notebook, \
2755+ AddNotebookDialog, NotebookDialog
2756+
2757+ tmpdir = self.create_tmp_dir()
2758+ dir1 = Dir(tmpdir + '/mynotebook1')
2759+ dir2 = Dir(tmpdir + '/mynotebook2')
2760+
2761+ # First time we get directly the AddNotebookDialog
2762+ def doAddNotebook(dialog):
2763+ self.assertTrue(isinstance(dialog, AddNotebookDialog))
2764+ dialog.form['name'] = 'Foo'
2765+ dialog.form['folder'] = dir1.path
2766+ dialog.assert_response_ok()
2767+
2768+ with tests.DialogContext(doAddNotebook):
2769+ self.assertEqual(prompt_notebook(), dir1.uri)
2770+
2771+ # Second time we get the list
2772+ def testNotebookDialog(dialog):
2773+ self.assertTrue(isinstance(dialog, NotebookDialog))
2774+ selection = dialog.treeview.get_selection()
2775+ selection.select_path((0,)) # select first and only notebook
2776+ dialog.assert_response_ok()
2777+
2778+ with tests.DialogContext(testNotebookDialog):
2779+ self.assertEqual(prompt_notebook(), dir1.uri)
2780+
2781+ # Third time we add a notebook and set the default
2782+ def doAddNotebook(dialog):
2783+ self.assertTrue(isinstance(dialog, AddNotebookDialog))
2784+ dialog.form['name'] = 'Bar'
2785+ dialog.form['folder'] = dir2.path
2786+ dialog.assert_response_ok()
2787+
2788+ def testAddNotebook(dialog):
2789+ self.assertTrue(isinstance(dialog, NotebookDialog))
2790+
2791+ with tests.DialogContext(doAddNotebook):
2792+ dialog.do_add_notebook()
2793+
2794+ dialog.combobox.set_active(0)
2795+
2796+ selection = dialog.treeview.get_selection()
2797+ selection.select_path((1,)) # select newly added notebook
2798+ dialog.assert_response_ok()
2799+
2800+ with tests.DialogContext(testAddNotebook):
2801+ self.assertEqual(prompt_notebook(), dir2.uri)
2802+
2803+ # Check the notebook exists and the notebook list looks like it should
2804+ for dir in (dir1, dir2):
2805+ self.assertTrue(dir.exists())
2806+ self.assertTrue(dir.file('notebook.zim').exists())
2807+
2808+ list = get_notebook_list()
2809+ self.assertTrue(len(list) == 2)
2810+ self.assertEqual(list[0], NotebookInfo(dir1.uri, name='Foo'))
2811+ self.assertEqual(list[1], NotebookInfo(dir2.uri, name='Bar'))
2812+ self.assertEqual(list.default, NotebookInfo(dir1.uri, name='Foo'))
2813+
2814+ # Now unset the default and again check the notebook list
2815+ def unsetDefault(dialog):
2816+ self.assertTrue(isinstance(dialog, NotebookDialog))
2817+ dialog.combobox.set_active(-1)
2818+ selection = dialog.treeview.get_selection()
2819+ selection.select_path((1,)) # select newly added notebook
2820+ dialog.assert_response_ok()
2821+
2822+ with tests.DialogContext(unsetDefault):
2823+ self.assertEqual(prompt_notebook(), dir2.uri)
2824+
2825+ list = get_notebook_list()
2826+ self.assertTrue(len(list) == 2)
2827+ self.assertTrue(list.default is None)
2828+
2829+
2830+class MockUI(tests.MockObject):
2831+
2832+ def __init__(self, page=None, fakedir=None):
2833+ tests.MockObject.__init__(self)
2834+
2835+ self.tmp_dir = self.create_tmp_dir()
2836
2837 if page and not isinstance(page, Path):
2838 self.page = Path(page)
2839@@ -447,6 +595,4 @@
2840 self.page = page
2841
2842 self.mainwindow = None
2843- self.notebook = get_test_notebook()
2844- self.notebook.get_store(Path(':')).dir = Dir(self.tmp_dir) # fake source dir
2845-
2846+ self.notebook = tests.new_notebook(fakedir=fakedir)
2847
2848=== modified file 'tests/history.py'
2849--- tests/history.py 2011-02-19 16:27:44 +0000
2850+++ tests/history.py 2011-06-04 21:27:03 +0000
2851@@ -2,18 +2,20 @@
2852
2853 # Copyright 2008 Jaap Karssenberg <jaap.karssenberg@gmail.com>
2854
2855-from tests import TestCase, get_test_notebook
2856+import tests
2857+
2858
2859 import zim.history
2860 from zim.history import History, HistoryPath
2861 from zim.notebook import Path
2862 from zim.config import ConfigDict
2863
2864-class TestHistory(TestCase):
2865+
2866+class TestHistory(tests.TestCase):
2867
2868 def setUp(self):
2869 zim.history.MAX_HISTORY = 100
2870- self.notebook = get_test_notebook()
2871+ self.notebook = tests.new_notebook()
2872 self.pages = [self.notebook.get_page(Path(name))
2873 for name in self.notebook.testdata_manifest]
2874
2875
2876=== modified file 'tests/index.py'
2877--- tests/index.py 2011-02-19 16:27:44 +0000
2878+++ tests/index.py 2011-06-04 21:27:03 +0000
2879@@ -8,31 +8,13 @@
2880 import pango
2881
2882 from zim.fs import Dir
2883-from zim.notebook import Notebook, Path, Link, init_notebook
2884+from zim.notebook import Notebook, Path, Link
2885 from zim.index import *
2886 from zim.gui.pageindex import *
2887 from zim.formats import ParseTree
2888
2889-# TODO test n_list_* functions
2890-
2891-
2892-def get_files_notebook(key):
2893- # We fill the notebook using the store interface, as this test comes before
2894- # the notebook test, but after the store test.
2895- dir = Dir(tests.create_tmp_dir('index_'+key))
2896- init_notebook(dir)
2897- notebook = Notebook(dir=dir)
2898- store = notebook.get_store(':')
2899- manifest = []
2900- for name, text in tests.get_test_data('wiki'):
2901- manifest.append(name)
2902- page = store.get_page(Path(name))
2903- page.parse('wiki', text)
2904- store.store_page(page)
2905- notebook.testdata_manifest = tests.expand_manifest(manifest)
2906- return notebook
2907-
2908-
2909+
2910+@tests.slowTest
2911 class TestIndex(tests.TestCase):
2912
2913 def setUp(self):
2914@@ -40,7 +22,7 @@
2915 # for the notebook. So any assumption from the notebook about
2916 # the index will be wrong.
2917 self.index = Index(dbfile=':memory:')
2918- self.notebook = tests.get_test_notebook()
2919+ self.notebook = tests.new_notebook()
2920 self.index.set_notebook(self.notebook)
2921
2922 def runTest(self):
2923@@ -96,6 +78,19 @@
2924 n = self.index.n_list_links(Path('Test:foo:bar'), LINK_DIR_BACKWARD)
2925 self.assertEqual(n, len(backlist))
2926
2927+ # tags
2928+ taglist = list(self.index.list_tags(Path('Test:tags')))
2929+ self.assertTrue(len(taglist) == 11)
2930+ for tag in taglist:
2931+ self.assertTrue(isinstance(tag, IndexTag))
2932+ tagnames = [t.name for t in taglist]
2933+ aretags = ['tags', 'beginning', 'end', 'tabs', 'verbatim',
2934+ 'enumerations', 'encoding', 's', 'num6ers', 'wit', 'cr']
2935+ nottags = ['places', 'links', 'captions', 'Headings', 'word']
2936+ for t in aretags:
2937+ self.assertTrue(t in tagnames)
2938+ for t in nottags:
2939+ self.assertTrue(not t in tagnames)
2940
2941 # cursor.row_count is not reliable - see docs
2942 def count_pages(db):
2943@@ -121,7 +116,7 @@
2944 self.assertTrue(count_pages(self.index.db) >= manifest)
2945 origdb = dump_db(self.index.db)
2946 self.index.update(checkcontents=False)
2947- self.assertEqualDiff(dump_db(self.index.db), origdb)
2948+ self.assertEqual(dump_db(self.index.db), origdb)
2949
2950 # indexkey
2951 for path in (Path('Test'), Path('Test:foo')):
2952@@ -154,7 +149,7 @@
2953 self.index.flush()
2954 self.assertEqual(count_pages(self.index.db), 1)
2955 self.index.update()
2956- self.assertEqualDiff(dump_db(self.index.db), origdb)
2957+ self.assertEqual(dump_db(self.index.db), origdb)
2958
2959 # now index only part of the tree - and repeat
2960 self.index.flush()
2961@@ -163,7 +158,7 @@
2962 self.assertTrue(count_pages(self.index.db) > 2)
2963 partdb = dump_db(self.index.db)
2964 self.index.update(Path('Test'))
2965- self.assertEqualDiff(dump_db(self.index.db), partdb)
2966+ self.assertEqual(dump_db(self.index.db), partdb)
2967
2968 # Index whole tree again
2969 self.index.update()
2970@@ -184,6 +179,13 @@
2971 path = self.index.lookup_path(Path('foo:bar'))
2972 self.assertTrue(path)
2973
2974+ # Check for tag indexing
2975+ tags = [tag.name for tag in self.index.list_tags(Path('roundtrip'))]
2976+ for t in ('foo', 'bar'):
2977+ self.assertTrue(t in tags)
2978+ tagged = list(self.index.list_tagged_pages(t))
2979+ self.assertTrue(Path('roundtrip') in tagged)
2980+
2981 tree = ParseTree().fromstring('<zim-tree><link href=":foo:bar">:foo:bar</link></zim-tree>')
2982 page = self.notebook.get_page(Path('roundtrip'))
2983 page.set_parsetree(tree)
2984@@ -198,13 +200,13 @@
2985 self.assertTrue(path is None)
2986
2987
2988+@tests.slowTest
2989 class TestIndexFiles(TestIndex):
2990 # Like the test above, but now using a files backend
2991
2992- slowTest = True
2993-
2994 def setUp(self):
2995- self.notebook = get_files_notebook('TestIndexFiles')
2996+ path = self.create_tmp_dir()
2997+ self.notebook = tests.new_files_notebook(path)
2998 self.index = self.notebook.index
2999
3000 def runTest(self):
3001@@ -221,7 +223,7 @@
3002
3003 def setUp(self):
3004 self.index = Index(dbfile=':memory:')
3005- self.notebook = tests.get_test_notebook()
3006+ self.notebook = tests.new_notebook()
3007 self.index.set_notebook(self.notebook)
3008 self.notebook.index.update()
3009
3010@@ -233,22 +235,21 @@
3011 # Hooking up the treeview as well just to see if we get any errors
3012 # From the order the signals are generated.
3013
3014- ui = StubUI()
3015+ ui = MockUI()
3016+ ui.notebook = self.notebook
3017+ ui.page = Path('Test:foo')
3018+ self.assertTrue(self.notebook.get_page(ui.page).exists())
3019+
3020 treeview = PageTreeView(ui)
3021 treestore = PageTreeStore(self.index)
3022 self.assertEqual(treestore.get_flags(), 0)
3023 self.assertEqual(treestore.get_n_columns(), 5)
3024 treeview.set_model(treestore)
3025
3026- def process_events(*a):
3027- while gtk.events_pending():
3028- gtk.main_iteration(block=False)
3029- return True # continue
3030-
3031- self.index.update(callback=process_events)
3032- process_events()
3033-
3034- treeview = PageTreeView(None) # just run hidden to check errors
3035+ self.index.update(callback=tests.gtk_process_events)
3036+ tests.gtk_process_events()
3037+
3038+ treeview = PageTreeView(ui) # just run hidden to check errors
3039 treeview.set_model(treestore)
3040
3041 n = treestore.on_iter_n_children(None)
3042@@ -279,10 +280,11 @@
3043
3044 # Now walk through the whole notebook testing the API
3045 # with nested pages and stuff
3046- n = 0
3047+ npages = 0
3048 path = []
3049 for page in self.notebook.walk():
3050- n += 1
3051+ #~ print '>>', page
3052+ npages += 1
3053 names = page.name.split(':')
3054 if len(names) > len(path):
3055 path.append(0) # always increment by one
3056@@ -340,22 +342,41 @@
3057 child = treestore.iter_nth_child(iter, 0)
3058 self.assertTrue(child is None)
3059
3060- self.assertTrue(n > 0) # double check sanity of walk() method
3061+ self.assertTrue(npages > 10) # double check sanity of walk() method
3062
3063 # Check if all the signals go OK
3064- treestore.disconnect()
3065+ treestore.disconnect_index()
3066 del treestore
3067 self.index.flush()
3068 treestore = PageTreeStore(self.index)
3069- self.index.update(callback=process_events)
3070-
3071-
3072+ treeview = PageTreeView(ui, treestore)
3073+ self.index.update(callback=tests.gtk_process_events)
3074+
3075+ # Try some TreeView methods
3076+ path = Path('Test:foo')
3077+ self.assertTrue(treeview.select_page(path))
3078+ self.assertEqual(treeview.get_selected_path(), path)
3079+ treepath = treeview.get_model().get_treepath(path)
3080+ self.assertTrue(not treepath is None)
3081+ col = treeview.get_column(0)
3082+ treeview.row_activated(treepath, col)
3083+
3084+ #~ treeview.emit('popup-menu')
3085+ treeview.emit('insert-link', path)
3086+ treeview.emit('copy')
3087+
3088+ # Check if all the signals go OK in delete
3089+ for page in reversed(list(self.notebook.walk())): # delete bottom up
3090+ self.notebook.delete_page(page)
3091+ tests.gtk_process_events()
3092+
3093+
3094+@tests.slowTest
3095 class TestPageTreeStoreFiles(TestPageTreeStore):
3096
3097- slowTest = True
3098-
3099 def setUp(self):
3100- self.notebook = get_files_notebook('TestPageTreeStoreFiles')
3101+ path = self.create_tmp_dir()
3102+ self.notebook = tests.new_files_notebook(path)
3103 self.index = self.notebook.index
3104
3105 def runTest(self):
3106@@ -363,13 +384,7 @@
3107 TestPageTreeStore.runTest(self)
3108
3109
3110-class StubUI(object):
3111+class MockUI(tests.MockObject):
3112
3113 page = None
3114 notebook = None
3115-
3116- def connect(*a):
3117- pass
3118-
3119- def connect_after(*a):
3120- pass
3121
3122=== modified file 'tests/inlinecalculator.py'
3123--- tests/inlinecalculator.py 2011-02-19 16:27:44 +0000
3124+++ tests/inlinecalculator.py 2011-06-04 21:27:03 +0000
3125@@ -1,18 +1,15 @@
3126-
3127 # -*- coding: utf-8 -*-
3128
3129 # Copyright 2008 Jaap Karssenberg <jaap.karssenberg@gmail.com>
3130
3131 import tests
3132-from tests import TestCase
3133
3134 import zim.plugins
3135 from zim.config import ConfigDict
3136
3137
3138-class TestPrintToBrowser(TestCase):
3139-
3140- slowTest = True
3141+@tests.slowTest
3142+class TestPrintToBrowser(tests.TestCase):
3143
3144 def runTest(self):
3145 'Test InlineCalculator plugin'
3146@@ -90,7 +87,7 @@
3147 ui_type = 'stub'
3148
3149 def __init__(self):
3150- self.notebook = tests.get_test_notebook()
3151+ self.notebook = tests.new_notebook()
3152 self.preferences = ConfigDict()
3153 self.uistate = ConfigDict()
3154
3155
3156=== modified file 'tests/notebook.py'
3157--- tests/notebook.py 2011-02-19 16:27:44 +0000
3158+++ tests/notebook.py 2011-06-04 21:27:03 +0000
3159@@ -13,11 +13,13 @@
3160 import zim.errors
3161 from zim.formats import ParseTree
3162
3163-
3164+from zim import _get_default_or_only_notebook
3165+ # private, but want to check it anyway
3166+
3167+
3168+@tests.slowTest
3169 class TestGetNotebook(tests.TestCase):
3170
3171- slowTest = True
3172-
3173 def setUp(self):
3174 list = config_file('notebooks.list')
3175 file = list.file
3176@@ -25,16 +27,16 @@
3177 file.remove()
3178
3179 def runTest(self):
3180- root = Dir(tests.create_tmp_dir(u'notebook_TestGetNotebook_\u0421\u0430\u0439'))
3181+ root = Dir(self.create_tmp_dir(u'some_utf8_here_\u0421\u0430\u0439'))
3182
3183 # Start empty - see this is no issue
3184 list = get_notebook_list()
3185- self.assertTrue(isinstance(list, NotebookList))
3186- self.assertFalse(list)
3187+ self.assertTrue(isinstance(list, NotebookInfoList))
3188+ self.assertTrue(len(list) == 0)
3189
3190 nb, page = resolve_notebook('foo')
3191 self.assertTrue(nb is None)
3192- nb = resolve_default_notebook()
3193+ nb = _get_default_or_only_notebook()
3194 self.assertTrue(nb is None)
3195
3196 # Non-existing dir
3197@@ -56,36 +58,45 @@
3198 self.assertEqual(page, Path('foo:bar:baz'))
3199
3200 # And put it in the list and resolve it by name
3201- list.append(dir.uri)
3202+ list = get_notebook_list()
3203+ list.append(NotebookInfo(dir.uri, name='foo'))
3204 list.write()
3205- list = get_notebook_list()
3206 self.assertTrue(len(list) == 1)
3207+ self.assertTrue(isinstance(list[0], NotebookInfo))
3208+
3209+ info = list.get_by_name('foo')
3210+ self.assertEqual(info.uri, dir.uri)
3211+ self.assertEqual(info.name, 'foo')
3212+
3213 nb, page = resolve_notebook('foo')
3214 self.assertEqual(nb, dir)
3215
3216 # Single notebook is automatically the default
3217- nb = resolve_default_notebook()
3218- self.assertEqual(nb, dir)
3219+ nb = _get_default_or_only_notebook()
3220+ self.assertEqual(nb, dir.uri)
3221
3222 # But not anymore after adding second notebook
3223- list.append('file:///foo/bar')
3224+ list = get_notebook_list()
3225+ list.append(NotebookInfo('file:///foo/bar'))
3226 list.write()
3227- list = get_notebook_list()
3228 self.assertTrue(len(list) == 2)
3229- self.assertEqual(list[:], [dir.uri, 'file:///foo/bar'])
3230+ self.assertEqual(list[:],
3231+ [NotebookInfo(dir.uri), NotebookInfo('file:///foo/bar')])
3232
3233 nb, page = resolve_notebook('foo')
3234 self.assertEqual(nb, dir)
3235 self.assertTrue(isinstance(get_notebook(nb), Notebook))
3236
3237- nb = resolve_default_notebook()
3238+ nb = _get_default_or_only_notebook()
3239 self.assertTrue(nb is None)
3240
3241- list.default = 'file:///default/foo'
3242+ list = get_notebook_list()
3243+ list.set_default('file:///foo/bar')
3244 list.write()
3245- list = get_notebook_list()
3246- nb = resolve_default_notebook()
3247- self.assertEqual(nb, Dir('/default/foo'))
3248+ nb = _get_default_or_only_notebook()
3249+ self.assertEqual(nb, Dir('/foo/bar').uri)
3250+ nb, p = resolve_notebook(nb)
3251+ self.assertEqual(nb, Dir('/foo/bar'))
3252 self.assertEqual(get_notebook(nb), None)
3253
3254 # Check interwiki parsing
3255@@ -97,22 +108,20 @@
3256
3257 # Check backward compatibility
3258 file = File('tests/data/notebook-list-old-format.list')
3259- wanted = [Dir('~/Notes').uri, Dir('/home/user/code/zim.debug').uri, Dir('/home/user/Foo Bar').uri]
3260- list = NotebookList(file)
3261- self.assertEqual(list[:], wanted)
3262- self.assertEqual(list.default, Dir('/home/user/code/zim.debug').uri)
3263+ list = NotebookInfoList(file)
3264+ self.assertEqual(list[:], [
3265+ NotebookInfo(Dir(path).uri) for path in
3266+ ('~/Notes', '/home/user/code/zim.debug', '/home/user/Foo Bar')
3267+ ])
3268+ self.assertEqual(list.default,
3269+ NotebookInfo(Dir('/home/user/code/zim.debug').uri) )
3270
3271
3272 class TestNotebook(tests.TestCase):
3273
3274 def setUp(self):
3275- zim.errors.silence_signal_exception_context = True
3276- if not hasattr(self, 'notebook'):
3277- self.notebook = tests.get_test_notebook()
3278- self.notebook.index.update()
3279-
3280- def tearDown(self):
3281- zim.errors.silence_signal_exception_context = False
3282+ path = self.get_tmp_name()
3283+ self.notebook = tests.new_notebook(fakedir=path)
3284
3285 def testAPI(self):
3286 '''Test various notebook methods'''
3287@@ -246,6 +255,13 @@
3288 ':AnotherNewPage:Foo:bar\n'
3289 '**bold** :AnotherNewPage\n' )
3290
3291+
3292+ # Try trashing
3293+ try:
3294+ self.notebook.trash_page(Path('TrashMe'))
3295+ except TrashNotSupportedError:
3296+ print 'trashing not supported'
3297+
3298 #~ print '\n==== DB ===='
3299 #~ self.notebook.index.ensure_update()
3300 #~ cursor = self.notebook.index.db.cursor()
3301@@ -324,15 +340,15 @@
3302 [[Dus:Ja|Grrr]] # relative link that needs updating on move, but not on rename - with name
3303 [[:Foo:Bar:Dus]] # Link that could be made relative, but isn't
3304 '''
3305- notebook, page = tests.get_test_page('Foo:Bar:Baz')
3306+ page = self.notebook.get_page(Path('Foo:Bar:Baz'))
3307 page.parse('wiki', text)
3308- notebook._update_links_from(page, Path('Dus:Baz'), page, Path('Dus:Baz'))
3309- self.assertEqualDiff(u''.join(page.dump('wiki')), wanted1)
3310+ self.notebook._update_links_from(page, Path('Dus:Baz'), page, Path('Dus:Baz'))
3311+ self.assertEqual(u''.join(page.dump('wiki')), wanted1)
3312
3313- notebook, page = tests.get_test_page('Dus:Bar')
3314+ page = self.notebook.get_page(Path('Dus:Bar'))
3315 page.parse('wiki', text)
3316- notebook._update_links_from(page, Path('Dus:Baz'), page, Path('Dus:Baz'))
3317- self.assertEqualDiff(u''.join(page.dump('wiki')), wanted2)
3318+ self.notebook._update_links_from(page, Path('Dus:Baz'), page, Path('Dus:Baz'))
3319+ self.assertEqual(u''.join(page.dump('wiki')), wanted2)
3320
3321 # updating links to the page that was moved
3322 # moving from Dus:Baz to Foo:Bar:Baz or renaming to Dus:Bar - updating links in Dus:Ja
3323@@ -366,15 +382,15 @@
3324 [[Bar:Hmm]] # absolute link that needs updating
3325 [[Bar:Hmm:Ja]] # absolute link that needs updating
3326 '''
3327- notebook, page = tests.get_test_page('Dus:Ja')
3328+ page = self.notebook.get_page(Path('Dus:Ja'))
3329 page.parse('wiki', text)
3330- notebook._update_links_in_page(page, Path('Dus:Baz'), Path('Foo:Bar:Baz'))
3331- self.assertEqualDiff(u''.join(page.dump('wiki')), wanted1)
3332+ self.notebook._update_links_in_page(page, Path('Dus:Baz'), Path('Foo:Bar:Baz'))
3333+ self.assertEqual(u''.join(page.dump('wiki')), wanted1)
3334
3335- notebook, page = tests.get_test_page('Dus:Ja')
3336+ page = self.notebook.get_page(Path('Dus:Ja'))
3337 page.parse('wiki', text)
3338- notebook._update_links_in_page(page, Path('Dus:Baz'), Path('Dus:Bar'))
3339- self.assertEqualDiff(u''.join(page.dump('wiki')), wanted2)
3340+ self.notebook._update_links_in_page(page, Path('Dus:Baz'), Path('Dus:Bar'))
3341+ self.assertEqual(u''.join(page.dump('wiki')), wanted2)
3342
3343 # now test actual move on full notebook
3344 def links(source, href):
3345@@ -438,12 +454,12 @@
3346
3347 def testResolveFile(self):
3348 '''Test notebook.resolve_file()'''
3349- dir = Dir(tests.create_tmp_dir('notebook_testResolveFile'))
3350 path = Path('Foo:Bar')
3351- self.notebook.dir = dir
3352- self.notebook.get_store(path).dir = dir
3353+ dir = self.notebook.dir
3354 self.notebook.config['Notebook']['document_root'] = './notebook_document_root'
3355- doc_root = self.notebook.get_document_root()
3356+ self.notebook.do_properties_changed() # parse config
3357+ doc_root = self.notebook.document_root
3358+ self.assertEqual(doc_root, dir.subdir('notebook_document_root'))
3359 for link, wanted, cleaned in (
3360 ('~/test.txt', File('~/test.txt'), '~/test.txt'),
3361 (r'~\test.txt', File('~/test.txt'), '~/test.txt'),
3362@@ -451,6 +467,7 @@
3363 ('file:/test.txt', File('file:///test.txt'), None),
3364 ('file://localhost/test.txt', File('file:///test.txt'), None),
3365 ('/test.txt', doc_root.file('test.txt'), '/test.txt'),
3366+ ('../../notebook_document_root/test.txt', doc_root.file('test.txt'), '/test.txt'),
3367 ('./test.txt', dir.file('Foo/Bar/test.txt'), './test.txt'),
3368 (r'.\test.txt', dir.file('Foo/Bar/test.txt'), './test.txt'),
3369 ('../test.txt', dir.file('Foo/test.txt'), '../test.txt'),
3370@@ -468,6 +485,10 @@
3371 # check relative path without Path
3372 self.assertEqual(
3373 self.notebook.relative_filepath(doc_root.file('foo.txt')), '/foo.txt')
3374+ self.assertEqual(
3375+ self.notebook.relative_filepath(dir.file('foo.txt')), './foo.txt')
3376+
3377+
3378
3379 # def testResolveLink(self):
3380 # '''Test page.resolve_link()'''
3381@@ -542,7 +563,7 @@
3382 '''Test page object'''
3383
3384 def setUp(self):
3385- self.notebook = tests.get_test_notebook()
3386+ self.notebook = tests.new_notebook()
3387
3388 def generator(self, name):
3389 return self.notebook.get_page(Path(name))
3390@@ -555,6 +576,7 @@
3391 <zim-tree>
3392 <link href='foo:bar'>foo:bar</link>
3393 <link href='bar'>bar</link>
3394+<tag name='baz'>@baz</tag>
3395 </zim-tree>
3396 ''' )
3397 page = Page(Path('Foo'))
3398@@ -567,6 +589,11 @@
3399 ('page', 'bar', {}),
3400 ] )
3401
3402+ tags = list(page.get_tags())
3403+ self.assertEqual(tags, [
3404+ ('@baz', {'name': 'baz'}),
3405+ ])
3406+
3407 self.assertEqual(page.get_parsetree().tostring(), tree.tostring())
3408 # ensure we didn't change the tree
3409
3410@@ -581,7 +608,7 @@
3411 class TestIndexPage(tests.TestCase):
3412
3413 def setUp(self):
3414- self.notebook = tests.get_test_notebook()
3415+ self.notebook = tests.new_notebook()
3416 self.notebook.index.update()
3417
3418 def runTest(self):
3419
3420=== renamed file 'tests/coding.py' => 'tests/package.py'
3421--- tests/coding.py 2011-02-14 20:22:50 +0000
3422+++ tests/package.py 2011-06-04 21:27:03 +0000
3423@@ -1,16 +1,44 @@
3424-
3425-from tests import TestCase
3426+# -*- coding: utf-8 -*-
3427+
3428+# Copyright 2011 Jaap Karssenberg <jaap.karssenberg@gmail.com>
3429+
3430+# This module contains a number of meta test to check coding style
3431+# and packaging
3432+
3433+import tests
3434
3435 import os
3436 import copy
3437-
3438-
3439-class TestCoding(TestCase):
3440+import re
3441+
3442+
3443+class TestCompileAll(tests.TestCase):
3444+
3445+ def runTest(self):
3446+ '''Test if all modules compile'''
3447+ for file in tests.zim_pyfiles():
3448+ module = file[:-3].replace('/', '.')
3449+ assert __import__(module)
3450+
3451+
3452+@tests.slowTest
3453+class TestNotebookUpgrade(tests.TestCase):
3454+
3455+ def runTest(self):
3456+ '''Test if included notebooks are up to date'''
3457+ from zim.fs import Dir
3458+ from zim.notebook import get_notebook
3459+ for path in ('data/manual', 'HACKING'):
3460+ notebook = get_notebook(Dir(path))
3461+ self.assertTrue(not notebook.needs_upgrade)
3462+
3463+
3464+class TestCoding(tests.TestCase):
3465 '''This test case enforces some coding style items'''
3466
3467 def __init__(self, *a):
3468 self._code_files = []
3469- TestCase.__init__(self, *a)
3470+ tests.TestCase.__init__(self, *a)
3471
3472 def list_code(self):
3473 '''Return all python files as text'''
3474@@ -23,16 +51,32 @@
3475 self._code_files = []
3476 for root in ('zim', 'tests'):
3477 for dir, dirs, files in os.walk(root):
3478- if 'coding.py' in files:
3479- files.remove('coding.py') # Skip this file itself
3480 for basename in files:
3481 if basename.endswith('.py'):
3482 file = dir + '/' + basename
3483- #print 'READING', file
3484+ if file == 'tests/package.py': # skip ourselve
3485+ continue
3486+ #~ print 'READING', file
3487 fh = open(file)
3488 self._code_files.append((file, fh.read()))
3489 fh.close()
3490
3491+ def testWrongDependencies(self):
3492+ '''Check clean dependencies'''
3493+ #~ for klass in ('gobject', 'gtk', 'gio'): # TODO get rid of gobject as well
3494+ for klass in ('gtk', 'gio'):
3495+ import_re = re.compile(r'^(import|from)\s+%s' % klass, re.M)
3496+ # only match global imports - allow import in limitted scope
3497+ for file, code in self.list_code():
3498+ if file.startswith('zim/gui') \
3499+ or file.startswith('zim/_lib/') \
3500+ or file.startswith('zim/plugins/') \
3501+ or file.startswith('tests/'):
3502+ continue # skip
3503+ match = import_re.search(code)
3504+ if match: print '>>>', match.group(0)
3505+ self.assertFalse(match, '%s imports %s, this is not allowed' % (file, klass))
3506+
3507 def testWrongMethog(self):
3508 '''Check for a couple of constructs to be avoided'''
3509 for file, code in self.list_code():
3510@@ -45,24 +89,24 @@
3511 '''Check python 2.5 compatibility'''
3512 for file, code in self.list_code():
3513 import_seen = False
3514- in_comment = False
3515- n = 0
3516+ suspect = False
3517 for line in code.splitlines():
3518- n += 1
3519- line = line.lstrip()
3520+ line = line.strip()
3521 if line.startswith('from __future__ ') \
3522 and 'with_statement' in line.split():
3523 import_seen = True
3524- elif in_comment:
3525- if line.endswith("'''"):
3526- in_comment = False
3527- else:
3528- pass
3529- elif line.startswith("'''"):
3530- if not line.endswith("'''"):
3531- in_comment = True
3532- else:
3533- pass
3534- elif line.startswith('with '):
3535- self.assertTrue(import_seen, '%s missing with_statement import from __future__ ("with" seen on line %i)' % (file, n))
3536-
3537+ elif line.startswith('with') and line.endswith(':'):
3538+ suspect = True
3539+
3540+ #~ if suspect: print file, 'uses "with" statement'
3541+
3542+ if suspect and not import_seen:
3543+ # Need real parsing to avoid false positives
3544+ import tokenize
3545+ import StringIO
3546+
3547+ for token in tokenize.generate_tokens(StringIO.StringIO(code).readline):
3548+ if token[0] == tokenize.NAME and token[1] == 'with':
3549+ lineno = token[2][0]
3550+ line = token[-1]
3551+ self.assertTrue(import_seen, '%s missing with_statement import from __future__ ("with" seen on line %i):\n%s' % (file, lineno, line))
3552
3553=== modified file 'tests/pageview.py'
3554--- tests/pageview.py 2011-02-19 16:27:44 +0000
3555+++ tests/pageview.py 2011-06-04 21:27:03 +0000
3556@@ -4,8 +4,8 @@
3557
3558 from __future__ import with_statement
3559
3560-from tests import TestCase, LoggingFilter, MockObject, \
3561- get_test_data_page, get_test_page
3562+import tests
3563+
3564
3565 from zim.fs import *
3566 from zim.formats import wiki, ParseTree
3567@@ -14,7 +14,7 @@
3568 from zim.config import ConfigDict
3569
3570
3571-class FilterNoSuchImageWarning(LoggingFilter):
3572+class FilterNoSuchImageWarning(tests.LoggingFilter):
3573
3574 logger = 'zim.gui.pageview'
3575 message = 'No such image:'
3576@@ -22,8 +22,8 @@
3577
3578 def get_tree(wikitext):
3579 tree = wiki.Parser().parse(wikitext)
3580- notebook, page = get_test_page()
3581- notebook.get_store(page).dir = Dir('/foo') # HACK
3582+ notebook = tests.new_notebook(fakedir='/foo')
3583+ page = notebook.get_page(Path('Foo'))
3584 tree.resolve_images(notebook, page)
3585 return tree
3586
3587@@ -37,11 +37,11 @@
3588 return ParseTree(root)
3589
3590
3591-class TestTextBuffer(TestCase):
3592+class TestTextBuffer(tests.TestCase):
3593
3594 def runTest(self):
3595 '''Test serialization and interaction of the page view textbuffer'''
3596- wikitext = get_test_data_page('wiki', 'roundtrip')
3597+ wikitext = tests.WikiTestData.get('roundtrip')
3598 tree = get_tree(wikitext)
3599 buffer = TextBuffer()
3600 with FilterNoSuchImageWarning():
3601@@ -51,30 +51,30 @@
3602 result1 = buffer.get_parsetree()
3603 #~ print tree.tostring()
3604 #~ print result1.tostring()
3605- #~ self.assertEqualDiff(result1.tostring(), tree.tostring())
3606+ #~ self.assertEqual(result1.tostring(), tree.tostring())
3607
3608 # Compare cooked tree after dumping back
3609 resulttext = u''.join(wiki.Dumper().dump(result1))
3610- self.assertEqualDiff(resulttext, wikitext)
3611+ self.assertEqual(resulttext, wikitext)
3612
3613 # Compare we are stable when loading raw tree again
3614 raw = raw1.tostring()
3615 with FilterNoSuchImageWarning():
3616 buffer.set_parsetree(raw1)
3617- self.assertEqualDiff(raw1.tostring(), raw)
3618+ self.assertEqual(raw1.tostring(), raw)
3619 # If this fails, set_parsetree is modifying the tree
3620 raw2 = buffer.get_parsetree(raw=True)
3621- self.assertEqualDiff(raw2.tostring(), raw)
3622+ self.assertEqual(raw2.tostring(), raw)
3623 # Actual cooked roundtrip test
3624
3625 # Compare we are stable when loading cooked tree again
3626 cooked = result1.tostring()
3627 with FilterNoSuchImageWarning():
3628 buffer.set_parsetree(result1)
3629- self.assertEqualDiff(result1.tostring(), cooked)
3630+ self.assertEqual(result1.tostring(), cooked)
3631 # If this fails, set_parsetree is modifying the tree
3632 result2 = buffer.get_parsetree()
3633- self.assertEqualDiff(result2.tostring(), cooked)
3634+ self.assertEqual(result2.tostring(), cooked)
3635 # Actual cooked roundtrip test
3636
3637 # Test 'raw' really preserves "errors"
3638@@ -101,7 +101,7 @@
3639
3640 rawtree = buffer.get_parsetree(raw=True)
3641 self.assertFalse(buffer.get_modified())
3642- self.assertEqualDiff(rawtree.tostring(), input)
3643+ self.assertEqual(rawtree.tostring(), input)
3644
3645 # Test errors are cleaned up correctly
3646 wanted = '''\
3647@@ -124,7 +124,7 @@
3648 <li bullet="*" indent="0">Foo</li><li bullet="*" indent="0">Bar</li></zim-tree>'''
3649 tree = buffer.get_parsetree()
3650 self.assertFalse(buffer.get_modified())
3651- self.assertEqualDiff(tree.tostring(), wanted)
3652+ self.assertEqual(tree.tostring(), wanted)
3653
3654 # Test pasting some simple text
3655 buffer.set_parsetree(tree) # reset without errors
3656@@ -157,7 +157,7 @@
3657 buffer.insert_parsetree(iter, pastetree, interactive=True)
3658 tree = buffer.get_parsetree()
3659 self.assertTrue(buffer.get_modified())
3660- self.assertEqualDiff(tree.tostring(), wanted)
3661+ self.assertEqual(tree.tostring(), wanted)
3662
3663 # Now paste list halfway and see result is OK
3664 # because of the bullets pasting should go to a new line
3665@@ -192,7 +192,7 @@
3666 buffer.insert_parsetree(iter, pastetree, interactive=True)
3667 tree = buffer.get_parsetree()
3668 self.assertTrue(buffer.get_modified())
3669- self.assertEqualDiff(tree.tostring(), wanted)
3670+ self.assertEqual(tree.tostring(), wanted)
3671
3672 # Test sanity for editing "errors"
3673 input = '''\
3674@@ -213,7 +213,7 @@
3675 #print buffer.get_parsetree(raw=True).tostring()
3676 #print buffer.get_parsetree().tostring()
3677 tree = buffer.get_parsetree()
3678- self.assertEqualDiff(tree.tostring(), wanted)
3679+ self.assertEqual(tree.tostring(), wanted)
3680
3681 # Strange bug let to second bullet disappearing in this case
3682 input = '''\
3683@@ -231,7 +231,7 @@
3684 #~ print buffer.get_parsetree(raw=True).tostring()
3685 #~ print buffer.get_parsetree().tostring()
3686 tree = buffer.get_parsetree()
3687- self.assertEqualDiff(tree.tostring(), input)
3688+ self.assertEqual(tree.tostring(), input)
3689
3690 # Check how robust we are for placeholder utf8 character
3691 buffer = TextBuffer()
3692@@ -240,7 +240,7 @@
3693 <?xml version='1.0' encoding='utf-8'?>
3694 <zim-tree>foo bar</zim-tree>'''
3695 tree = buffer.get_parsetree()
3696- self.assertEqualDiff(tree.tostring(), wanted)
3697+ self.assertEqual(tree.tostring(), wanted)
3698
3699 # Test merge lines logic on delete
3700 input = '''\
3701@@ -263,7 +263,7 @@
3702 tree = get_tree_from_xml(input)
3703 buffer.set_parsetree(tree)
3704 tree = buffer.get_parsetree()
3705- self.assertEqualDiff(tree.tostring(), input)
3706+ self.assertEqual(tree.tostring(), input)
3707
3708 iter = buffer.get_iter_at_line(2) # before h2
3709 bound = iter.copy()
3710@@ -283,7 +283,7 @@
3711 #~ print buffer.get_parsetree(raw=True).tostring()
3712 #~ print buffer.get_parsetree().tostring()
3713 tree = buffer.get_parsetree()
3714- self.assertEqualDiff(tree.tostring(), wanted)
3715+ self.assertEqual(tree.tostring(), wanted)
3716
3717
3718
3719@@ -303,7 +303,7 @@
3720 tree = get_tree_from_xml(input)
3721 buffer.set_parsetree(tree)
3722 tree = buffer.get_parsetree(raw=True)
3723- self.assertEqualDiff(tree.tostring(), input) # just a sanity check
3724+ self.assertEqual(tree.tostring(), input) # just a sanity check
3725
3726 wanted = '''\
3727 <?xml version='1.0' encoding='utf-8'?>
3728@@ -325,7 +325,7 @@
3729 buffer.toggle_checkbox_for_cursor_or_selection(XCHECKED_BOX)
3730 # Like <Shift><F12> on first list item line
3731 tree = buffer.get_parsetree(raw=True)
3732- self.assertEqualDiff(tree.tostring(), wanted)
3733+ self.assertEqual(tree.tostring(), wanted)
3734
3735 wanted = '''\
3736 <?xml version='1.0' encoding='utf-8'?>
3737@@ -346,7 +346,7 @@
3738 buffer.toggle_checkbox_for_cursor_or_selection(CHECKED_BOX, recursive=True)
3739 # Like keypress would trigger while selection present
3740 tree = buffer.get_parsetree(raw=True)
3741- self.assertEqualDiff(tree.tostring(), wanted)
3742+ self.assertEqual(tree.tostring(), wanted)
3743
3744
3745 # Test deleting checkbox and undo / redo does not mess up indenting etc
3746@@ -364,24 +364,24 @@
3747 end = buffer.get_iter_at_line(7) # Baz (before checkbox !)
3748 buffer.delete(start, end)
3749 tree = buffer.get_parsetree(raw=True)
3750- self.assertEqualDiff(tree.tostring(), wanted)
3751+ self.assertEqual(tree.tostring(), wanted)
3752
3753 undomanager.undo()
3754 tree = buffer.get_parsetree(raw=True)
3755- self.assertEqualDiff(tree.tostring(), previous)
3756+ self.assertEqual(tree.tostring(), previous)
3757
3758 undomanager.redo()
3759 tree = buffer.get_parsetree(raw=True)
3760- self.assertEqualDiff(tree.tostring(), wanted)
3761-
3762-
3763-class TestUndoStackManager(TestCase):
3764+ self.assertEqual(tree.tostring(), wanted)
3765+
3766+
3767+class TestUndoStackManager(tests.TestCase):
3768
3769 def runTest(self):
3770 '''Test the undo/redo functionality'''
3771 buffer = TextBuffer()
3772 undomanager = UndoStackManager(buffer)
3773- wikitext = get_test_data_page('wiki', 'roundtrip')
3774+ wikitext = tests.WikiTestData.get('roundtrip')
3775 tree = get_tree(wikitext)
3776
3777 with FilterNoSuchImageWarning():
3778@@ -419,7 +419,7 @@
3779 _ = buffer.get_parsetree() # just check for no warnings
3780
3781 emptytree = buffer.get_parsetree(raw=True)
3782- self.assertEqualDiff(emptytree.tostring(),
3783+ self.assertEqual(emptytree.tostring(),
3784 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree raw=\"True\" />")
3785
3786 with FilterNoSuchImageWarning():
3787@@ -427,13 +427,13 @@
3788 _ = buffer.get_parsetree() # just check for no warnings
3789
3790 buffertree2 = buffer.get_parsetree(raw=True)
3791- self.assertEqualDiff(buffertree2.tostring(), buffertree1.tostring())
3792+ self.assertEqual(buffertree2.tostring(), buffertree1.tostring())
3793
3794 while undomanager.undo():
3795 continue
3796
3797 emptytree = buffer.get_parsetree(raw=True)
3798- self.assertEqualDiff(emptytree.tostring(),
3799+ self.assertEqual(emptytree.tostring(),
3800 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree raw=\"True\" />")
3801
3802 buffer.clear()
3803@@ -450,7 +450,7 @@
3804 self.assertTrue(len(undomanager.stack) == 5) # 3 words, 2 spaces
3805 for group in undomanager.stack:
3806 self.assertTrue(len(group) == 1) # merge was sucessfull
3807- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3808+ self.assertEqual(buffer.get_parsetree().tostring(),
3809 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo barr baz</zim-tree>")
3810
3811 for wanted in (
3812@@ -461,11 +461,11 @@
3813 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree />"
3814 ):
3815 undomanager.undo()
3816- self.assertEqualDiff(buffer.get_parsetree().tostring(), wanted)
3817+ self.assertEqual(buffer.get_parsetree().tostring(), wanted)
3818
3819 while undomanager.redo():
3820 continue
3821- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3822+ self.assertEqual(buffer.get_parsetree().tostring(),
3823 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo barr baz</zim-tree>")
3824
3825 # test other actions
3826@@ -473,29 +473,29 @@
3827 buffer.place_cursor(iter)
3828 buffer.select_word()
3829 buffer.toggle_textstyle('strong', interactive=True)
3830- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3831+ self.assertEqual(buffer.get_parsetree().tostring(),
3832 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo <strong>barr</strong> baz</zim-tree>")
3833
3834 undomanager.undo()
3835- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3836+ self.assertEqual(buffer.get_parsetree().tostring(),
3837 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo barr baz</zim-tree>")
3838
3839 undomanager.redo()
3840- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3841+ self.assertEqual(buffer.get_parsetree().tostring(),
3842 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo <strong>barr</strong> baz</zim-tree>")
3843
3844 start, end = map(buffer.get_iter_at_offset, (5, 10))
3845 with buffer.user_action:
3846 buffer.delete(start, end)
3847- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3848+ self.assertEqual(buffer.get_parsetree().tostring(),
3849 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo baz</zim-tree>")
3850
3851 undomanager.undo()
3852- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3853+ self.assertEqual(buffer.get_parsetree().tostring(),
3854 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo <strong>barr</strong> baz</zim-tree>")
3855
3856 undomanager.redo()
3857- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3858+ self.assertEqual(buffer.get_parsetree().tostring(),
3859 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo baz</zim-tree>")
3860
3861 # test folding
3862@@ -504,25 +504,25 @@
3863 undomanager.undo()
3864 undomanager.undo()
3865
3866- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3867+ self.assertEqual(buffer.get_parsetree().tostring(),
3868 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo barr</zim-tree>")
3869
3870 with buffer.user_action:
3871 buffer.insert_at_cursor(' ')
3872
3873 undomanager.undo()
3874- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3875+ self.assertEqual(buffer.get_parsetree().tostring(),
3876 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo barr</zim-tree>")
3877
3878 undomanager.undo() # here we undo fold of 4 undos above
3879- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3880+ self.assertEqual(buffer.get_parsetree().tostring(),
3881 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo baz</zim-tree>")
3882 undomanager.undo()
3883- self.assertEqualDiff(buffer.get_parsetree().tostring(),
3884+ self.assertEqual(buffer.get_parsetree().tostring(),
3885 "<?xml version='1.0' encoding='utf-8'?>\n<zim-tree>fooo <strong>barr</strong> baz</zim-tree>")
3886
3887
3888-class TestFind(TestCase):
3889+class TestFind(tests.TestCase):
3890
3891 def runTest(self):
3892 buffer = TextBuffer()
3893@@ -623,7 +623,7 @@
3894 FooBaz Foo Bar
3895 foo Bar Baz Foo
3896 '''
3897- self.assertEqualDiff(text, wanted)
3898+ self.assertEqual(text, wanted)
3899
3900 finder.replace_all('dus*\\1*')
3901 bounds = buffer.get_bounds()
3902@@ -633,11 +633,11 @@
3903 dus*Baz* dus** Bar
3904 dus** Bar Baz dus**
3905 '''
3906- self.assertEqualDiff(text, wanted)
3907+ self.assertEqual(text, wanted)
3908 self.assertEqual(buffer.get_insert_iter().get_offset(), 6)
3909
3910
3911-class TestLists(TestCase):
3912+class TestLists(tests.TestCase):
3913
3914 def runTest(self):
3915 '''Test interaction for lists'''
3916@@ -658,7 +658,7 @@
3917 tree = get_tree_from_xml(input)
3918 buffer.set_parsetree(tree)
3919 tree = buffer.get_parsetree(raw=True)
3920- self.assertEqualDiff(tree.tostring(), input) # just a sanity check
3921+ self.assertEqual(tree.tostring(), input) # just a sanity check
3922
3923 undomanager = UndoStackManager(buffer)
3924
3925@@ -703,7 +703,7 @@
3926 Tja
3927 </zim-tree>'''
3928 tree = buffer.get_parsetree(raw=True)
3929- self.assertEqualDiff(tree.tostring(), wanted)
3930+ self.assertEqual(tree.tostring(), wanted)
3931
3932 iter = buffer.get_iter_at_line(7) # Baz
3933 row, list = TextBufferList.new_from_iter(buffer, iter)
3934@@ -728,7 +728,7 @@
3935 Tja
3936 </zim-tree>'''
3937 tree = buffer.get_parsetree(raw=True)
3938- self.assertEqualDiff(tree.tostring(), wanted)
3939+ self.assertEqual(tree.tostring(), wanted)
3940
3941 for line in (2, 5, 6): # Bar, Bar 2 & Bar 3
3942 iter = buffer.get_iter_at_line(line)
3943@@ -737,28 +737,28 @@
3944 self.assertTrue(list.unindent(row))
3945
3946 tree = buffer.get_parsetree(raw=True)
3947- self.assertEqualDiff(tree.tostring(), input)
3948+ self.assertEqual(tree.tostring(), input)
3949
3950 # Test undo / redo for indenting and lists
3951 for i in range(3):
3952 self.assertTrue(undomanager.undo())
3953 tree = buffer.get_parsetree(raw=True)
3954- self.assertEqualDiff(tree.tostring(), wanted)
3955+ self.assertEqual(tree.tostring(), wanted)
3956
3957 while undomanager.undo():
3958 pass
3959 tree = buffer.get_parsetree(raw=True)
3960- self.assertEqualDiff(tree.tostring(), input)
3961+ self.assertEqual(tree.tostring(), input)
3962
3963 while undomanager.redo():
3964 pass
3965 tree = buffer.get_parsetree(raw=True)
3966- self.assertEqualDiff(tree.tostring(), input)
3967+ self.assertEqual(tree.tostring(), input)
3968
3969 for i in range(3):
3970 self.assertTrue(undomanager.undo())
3971 tree = buffer.get_parsetree(raw=True)
3972- self.assertEqualDiff(tree.tostring(), wanted)
3973+ self.assertEqual(tree.tostring(), wanted)
3974
3975
3976 # Exercize recursive checkbox lists
3977@@ -777,7 +777,7 @@
3978 tree = get_tree_from_xml(input)
3979 buffer.set_parsetree(tree)
3980 tree = buffer.get_parsetree(raw=True)
3981- self.assertEqualDiff(tree.tostring(), input) # just a sanity check
3982+ self.assertEqual(tree.tostring(), input) # just a sanity check
3983
3984 undomanager = UndoStackManager(buffer)
3985
3986@@ -798,7 +798,7 @@
3987 Tja
3988 </zim-tree>'''
3989 tree = buffer.get_parsetree(raw=True)
3990- self.assertEqualDiff(tree.tostring(), wanted)
3991+ self.assertEqual(tree.tostring(), wanted)
3992
3993 list.set_bullet(row, UNCHECKED_BOX)
3994 row = list.get_row_at_line(3) # Bar 1
3995@@ -818,7 +818,7 @@
3996 Tja
3997 </zim-tree>'''
3998 tree = buffer.get_parsetree(raw=True)
3999- self.assertEqualDiff(tree.tostring(), wanted)
4000+ self.assertEqual(tree.tostring(), wanted)
4001
4002 row = list.get_row_at_line(5) # Bar 2
4003 list.set_bullet(row, CHECKED_BOX)
4004@@ -835,7 +835,7 @@
4005 Tja
4006 </zim-tree>'''
4007 tree = buffer.get_parsetree(raw=True)
4008- self.assertEqualDiff(tree.tostring(), wanted)
4009+ self.assertEqual(tree.tostring(), wanted)
4010
4011 row = list.get_row_at_line(4) # Bar 1.1
4012 list.set_bullet(row, UNCHECKED_BOX)
4013@@ -852,7 +852,7 @@
4014 Tja
4015 </zim-tree>'''
4016 tree = buffer.get_parsetree(raw=True)
4017- self.assertEqualDiff(tree.tostring(), wanted)
4018+ self.assertEqual(tree.tostring(), wanted)
4019
4020 wantedpre1 = wanted
4021 row = list.get_row_at_line(4) # Bar 1.1
4022@@ -870,7 +870,7 @@
4023 Tja
4024 </zim-tree>'''
4025 tree = buffer.get_parsetree(raw=True)
4026- self.assertEqualDiff(tree.tostring(), wanted)
4027+ self.assertEqual(tree.tostring(), wanted)
4028
4029 # Test indenting / unindenting the whole list
4030 wantedpre = wanted
4031@@ -889,32 +889,32 @@
4032 Tja
4033 </zim-tree>'''
4034 tree = buffer.get_parsetree(raw=True)
4035- self.assertEqualDiff(tree.tostring(), wanted)
4036+ self.assertEqual(tree.tostring(), wanted)
4037
4038 list.unindent(row)
4039 tree = buffer.get_parsetree(raw=True)
4040- self.assertEqualDiff(tree.tostring(), wantedpre)
4041+ self.assertEqual(tree.tostring(), wantedpre)
4042
4043 # Test undo / redo for indenting and lists
4044 for xml in (wanted, wantedpre, wantedpre1):
4045 self.assertTrue(undomanager.undo())
4046 tree = buffer.get_parsetree(raw=True)
4047- self.assertEqualDiff(tree.tostring(), xml)
4048+ self.assertEqual(tree.tostring(), xml)
4049
4050 for xml in (wantedpre, wanted, wantedpre):
4051 self.assertTrue(undomanager.redo())
4052 tree = buffer.get_parsetree(raw=True)
4053- self.assertEqualDiff(tree.tostring(), xml)
4054+ self.assertEqual(tree.tostring(), xml)
4055
4056 while undomanager.undo():
4057 pass
4058 tree = buffer.get_parsetree(raw=True)
4059- self.assertEqualDiff(tree.tostring(), input)
4060+ self.assertEqual(tree.tostring(), input)
4061
4062 while undomanager.redo():
4063 pass
4064 tree = buffer.get_parsetree(raw=True)
4065- self.assertEqualDiff(tree.tostring(), wantedpre)
4066+ self.assertEqual(tree.tostring(), wantedpre)
4067
4068
4069 def press(widget, sequence):
4070@@ -940,7 +940,7 @@
4071 widget.emit('key-press-event', event)
4072
4073
4074-class TestTextView(TestCase):
4075+class TestTextView(tests.TestCase):
4076
4077 def setUp(self):
4078 # Initialize default preferences from module
4079@@ -974,7 +974,7 @@
4080 <zim-tree raw="True">aaa
4081 <li bullet="*" indent="0"> foo</li></zim-tree>'''
4082 tree = buffer.get_parsetree(raw=True)
4083- self.assertEqualDiff(tree.tostring(), wanted)
4084+ self.assertEqual(tree.tostring(), wanted)
4085
4086 press(view, '\n')
4087 wanted = '''\
4088@@ -984,7 +984,7 @@
4089 <li bullet="*" indent="0"> </li></zim-tree>'''
4090 tree = buffer.get_parsetree(raw=True)
4091 start, end = buffer.get_bounds()
4092- self.assertEqualDiff(tree.tostring(), wanted)
4093+ self.assertEqual(tree.tostring(), wanted)
4094
4095 press(view, '\tduss')
4096 wanted = '''\
4097@@ -993,7 +993,7 @@
4098 <li bullet="*" indent="0"> foo</li>
4099 <li bullet="*" indent="1"> duss</li></zim-tree>'''
4100 tree = buffer.get_parsetree(raw=True)
4101- self.assertEqualDiff(tree.tostring(), wanted)
4102+ self.assertEqual(tree.tostring(), wanted)
4103
4104 press(view, '\n')
4105 wanted = '''\
4106@@ -1003,7 +1003,7 @@
4107 <li bullet="*" indent="1"> duss</li>
4108 <li bullet="*" indent="1"> </li></zim-tree>'''
4109 tree = buffer.get_parsetree(raw=True)
4110- self.assertEqualDiff(tree.tostring(), wanted)
4111+ self.assertEqual(tree.tostring(), wanted)
4112
4113 press(view, 'CamelCase\n')
4114 wanted = '''\
4115@@ -1014,7 +1014,7 @@
4116 <li bullet="*" indent="1"> <link href="CamelCase">CamelCase</link></li>
4117 <li bullet="*" indent="1"> </li></zim-tree>'''
4118 tree = buffer.get_parsetree(raw=True)
4119- self.assertEqualDiff(tree.tostring(), wanted)
4120+ self.assertEqual(tree.tostring(), wanted)
4121
4122 press(view, '\n')
4123 wanted = '''\
4124@@ -1026,7 +1026,7 @@
4125
4126 </zim-tree>'''
4127 tree = buffer.get_parsetree(raw=True)
4128- self.assertEqualDiff(tree.tostring(), wanted)
4129+ self.assertEqual(tree.tostring(), wanted)
4130
4131 # selection + * to toggle bullets
4132 start = buffer.get_iter_at_line(1) # before foo
4133@@ -1042,7 +1042,7 @@
4134 </div>
4135 </zim-tree>'''
4136 tree = buffer.get_parsetree(raw=True)
4137- self.assertEqualDiff(tree.tostring(), wanted)
4138+ self.assertEqual(tree.tostring(), wanted)
4139
4140 start = buffer.get_iter_at_line(1) # before foo
4141 end = buffer.get_iter_at_line(4) # empty line !
4142@@ -1057,7 +1057,7 @@
4143
4144 </zim-tree>'''
4145 tree = buffer.get_parsetree(raw=True)
4146- self.assertEqualDiff(tree.tostring(), wanted)
4147+ self.assertEqual(tree.tostring(), wanted)
4148
4149 iter = buffer.get_iter_at_line(1)
4150 iter.forward_to_line_end() # behind "foo"
4151@@ -1073,7 +1073,7 @@
4152
4153 </zim-tree>'''
4154 tree = buffer.get_parsetree(raw=True)
4155- self.assertEqualDiff(tree.tostring(), wanted)
4156+ self.assertEqual(tree.tostring(), wanted)
4157
4158
4159
4160@@ -1089,11 +1089,11 @@
4161
4162 </zim-tree>'''
4163 tree = buffer.get_parsetree(raw=True)
4164- self.assertEqualDiff(tree.tostring(), wanted)
4165+ self.assertEqual(tree.tostring(), wanted)
4166
4167 press(view, (KEYVALS_LEFT_TAB[0],)) # Check <Shift><Tab> does not fall through to Tab when indent fails
4168 tree = buffer.get_parsetree(raw=True)
4169- self.assertEqualDiff(tree.tostring(), wanted)
4170+ self.assertEqual(tree.tostring(), wanted)
4171
4172 press(view, (KEYVALS_BACKSPACE[0],)) # delete bullet at once
4173 wanted = '''\
4174@@ -1106,7 +1106,7 @@
4175
4176 </zim-tree>'''
4177 tree = buffer.get_parsetree(raw=True)
4178- self.assertEqualDiff(tree.tostring(), wanted)
4179+ self.assertEqual(tree.tostring(), wanted)
4180
4181 # TODO: this test case fails, even though it works when I try it interactively !?
4182 #~ press(view, (KEYVALS_BACKSPACE[0],)) # remove newline
4183@@ -1119,7 +1119,7 @@
4184 #~
4185 #~ </zim-tree>'''
4186 #~ tree = buffer.get_parsetree(raw=True)
4187- #~ self.assertEqualDiff(tree.tostring(), wanted)
4188+ #~ self.assertEqual(tree.tostring(), wanted)
4189
4190 # TODO more unindenting ?
4191 # TODO checkboxes
4192@@ -1127,15 +1127,15 @@
4193 # TODO enter on link, before link, after link
4194
4195
4196-class TestPageView(TestCase):
4197+class TestPageView(tests.TestCase):
4198
4199 def runTest(self):
4200- PageView.actiongroup = MockObject() # use class attribute to fake ui init
4201- PageView.actiongroup.mock_method('get_action', MockObject())
4202+ PageView.actiongroup = tests.MockObject() # use class attribute to fake ui init
4203+ PageView.actiongroup.mock_method('get_action', tests.MockObject())
4204
4205 ui = MockUI()
4206- ui.uimanager = MockObject()
4207- ui.uimanager.mock_method('get_accel_group', MockObject())
4208+ ui.uimanager = tests.MockObject()
4209+ ui.uimanager.mock_method('get_accel_group', tests.MockObject())
4210
4211 pageview = PageView(ui)
4212 buffer = pageview.view.get_buffer()
4213@@ -1152,7 +1152,7 @@
4214 # TODO much more here
4215
4216
4217-class TestPageviewDialogs(TestCase):
4218+class TestPageviewDialogs(tests.TestCase):
4219
4220 def runTest(self):
4221 '''Test input/output of various pageview dialogs'''
4222@@ -1204,11 +1204,13 @@
4223 self.assertEqual(dialog.form['height'], 24)
4224 dialog.assert_response_ok()
4225 iter = buffer.get_iter_at_offset(0)
4226- self.assertEqual(buffer.get_image_data(iter), {
4227+ imagedata = buffer.get_image_data(iter)
4228+ self.assertEqual(imagedata, {
4229 'src': './data/zim.png', # preserve relative path
4230 '_src_file': file,
4231 'height': 24,
4232 })
4233+ self.assertEqual(type(imagedata['height']).__name__, 'int')
4234
4235 ## Insert text from file dialog
4236 ui = MockUI()
4237@@ -1220,9 +1222,9 @@
4238
4239 ## Insert Link dialog
4240 ui = MockUI()
4241- ui.notebook.index = MockObject()
4242+ ui.notebook.index = tests.MockObject()
4243 ui.notebook.index.mock_method('list_pages', [])
4244- pageview = MockObject()
4245+ pageview = tests.MockObject()
4246 pageview.page = Path('Test:foo:bar')
4247 textview = TextView({})
4248 pageview.view = textview
4249@@ -1252,25 +1254,27 @@
4250 ''')
4251
4252 ## Word Count dialog
4253- pageview = MockObject()
4254+ pageview = tests.MockObject()
4255 pageview.view = textview
4256 pageview.ui = MockUI()
4257 dialog = WordCountDialog(pageview)
4258 dialog.destroy() # nothing to test really
4259
4260
4261-class MockUI(MockObject):
4262+class MockUI(tests.MockObject):
4263
4264 def __init__(self):
4265- MockObject.__init__(self)
4266+ tests.MockObject.__init__(self)
4267 self.mainwindow = None
4268- self.notebook = MockObject()
4269+ self.notebook = tests.MockObject()
4270 self.preferences = ConfigDict()
4271
4272 def register_preferences(self, section, list):
4273- for key, type, category, label, default in list:
4274+ for p in list:
4275+ key = p[0]
4276+ default = p[4]
4277 self.preferences[section][key] = default
4278
4279
4280-class MockBuffer(MockObject):
4281+class MockBuffer(tests.MockObject):
4282 pass
4283
4284=== modified file 'tests/parsing.py'
4285--- tests/parsing.py 2011-02-19 16:27:44 +0000
4286+++ tests/parsing.py 2011-06-04 21:27:03 +0000
4287@@ -88,7 +88,7 @@
4288 def testLinkType(self):
4289 '''Test link_type()'''
4290 for href, type in (
4291- ('zim+file://foo/bar?dus.txt', 'zim-notebook'),
4292+ ('zim+file://foo/bar?dus.txt', 'notebook'),
4293 ('file://foo/bar', 'file'),
4294 ('http://foo/bar', 'http'),
4295 ('http://192.168.168.100', 'http'),
4296
4297=== modified file 'tests/plugins.py'
4298--- tests/plugins.py 2011-02-19 16:27:44 +0000
4299+++ tests/plugins.py 2011-06-04 21:27:03 +0000
4300@@ -2,7 +2,7 @@
4301
4302 # Copyright 2008 Jaap Karssenberg <jaap.karssenberg@gmail.com>
4303
4304-from tests import TestCase, get_test_notebook
4305+import tests
4306
4307 import os
4308
4309@@ -14,7 +14,7 @@
4310 zim.plugins.__path__ = [os.path.abspath('./zim/plugins')] # set back default search path
4311
4312
4313-class testPlugins(TestCase):
4314+class testPlugins(tests.TestCase):
4315 '''FIXME'''
4316
4317 def testListAll(self):
4318@@ -35,20 +35,23 @@
4319
4320 # test dependencies data
4321 dep = plugin.check_dependencies()
4322+ self.assertTrue(isinstance(dep,tuple))
4323+ check, dep = dep
4324+ self.assertTrue(isinstance(check,bool))
4325 self.assertTrue(isinstance(dep,list))
4326 for i in range(len(dep)):
4327 self.assertTrue(isinstance(dep[i],tuple))
4328 self.assertTrue(isinstance(dep[i][0],str))
4329 self.assertTrue(isinstance(dep[i][1],bool))
4330+ self.assertTrue(isinstance(dep[i][2],bool))
4331
4332 def testDefaulPlugins(self):
4333 '''Test loading default plugins'''
4334 # Note that we use parent interface class here, so plugins
4335 # will not really attach - just testing loading and prereq
4336 # checks are OK.
4337- notebook = get_test_notebook()
4338+ notebook = tests.new_notebook()
4339 interface = zim.NotebookInterface(notebook)
4340 interface.uistate = zim.config.ConfigDict()
4341 interface.load_plugins()
4342 self.assertTrue(len(interface.plugins) > 3)
4343-
4344
4345=== modified file 'tests/printtobrowser.py'
4346--- tests/printtobrowser.py 2011-02-19 16:27:44 +0000
4347+++ tests/printtobrowser.py 2011-06-04 21:27:03 +0000
4348@@ -1,18 +1,16 @@
4349-
4350 # -*- coding: utf-8 -*-
4351
4352 # Copyright 2008 Jaap Karssenberg <jaap.karssenberg@gmail.com>
4353
4354 import tests
4355-from tests import TestCase
4356
4357 import zim.plugins
4358 from zim.notebook import Path
4359 from zim.config import ConfigDict
4360
4361-class TestPrintToBrowser(TestCase):
4362
4363- slowTest = True
4364+@tests.slowTest
4365+class TestPrintToBrowser(tests.TestCase):
4366
4367 def runTest(self):
4368 'Test PrintToBrowser plugin'
4369@@ -30,11 +28,11 @@
4370 ui_type = 'stub'
4371
4372 def __init__(self):
4373- self.notebook = tests.get_test_notebook()
4374+ self.notebook = tests.new_notebook()
4375 self.page = self.notebook.get_page(Path('Test:foo'))
4376 self.preferences = ConfigDict()
4377 self.uistate = ConfigDict()
4378-
4379+
4380 def connect(*a): pass
4381
4382 def connect_after(*a): pass
4383
4384=== modified file 'tests/search.py'
4385--- tests/search.py 2010-03-15 17:29:15 +0000
4386+++ tests/search.py 2011-06-04 21:27:03 +0000
4387@@ -1,10 +1,13 @@
4388-
4389-from tests import get_test_notebook, TestCase
4390+# -*- coding: utf-8 -*-
4391+
4392+# Copyright 2011 Jaap Karssenberg <jaap.karssenberg@gmail.com>
4393+
4394+import tests
4395
4396 from zim.search import *
4397 from zim.notebook import Path
4398
4399-class TestSearchRegex(TestCase):
4400+class TestSearchRegex(tests.TestCase):
4401
4402 def runTest(self):
4403 '''Test regex compilation for search terms'''
4404@@ -35,10 +38,10 @@
4405
4406
4407
4408-class TestSearch(TestCase):
4409+class TestSearch(tests.TestCase):
4410
4411 def setUp(self):
4412- self.notebook = get_test_notebook()
4413+ self.notebook = tests.new_notebook()
4414
4415 def runTest(self):
4416 '''Test search API'''
4417@@ -136,32 +139,33 @@
4418 self.assertTrue(set(results.scores.keys()) == results)
4419 self.assertTrue(all(results.scores.values()))
4420
4421+ query = Query('Namespace: "TODOList" fix')
4422+ self.assertTrue(query.root.operator == OPERATOR_AND)
4423+ self.assertEqual(query.root, [QueryTerm('namespace', 'TODOList'), QueryTerm('contentorname', 'fix')])
4424+ results.search(query)
4425+ #~ print results
4426+ self.assertTrue(Path('TODOList:foo') in results)
4427+
4428+ query = Query('Tag: tags')
4429+ self.assertTrue(query.root.operator == OPERATOR_AND)
4430+ self.assertEqual(query.root, [QueryTerm('tag', 'tags')])
4431+ query = Query('@tags')
4432+ self.assertTrue(query.root.operator == OPERATOR_AND)
4433+ self.assertEqual(query.root, [QueryTerm('tag', 'tags')])
4434+ results.search(query)
4435+ #~ print results
4436+ self.assertTrue(Path('Test:tags') in results and len(results) == 1)
4437+
4438 # TODO test ContentOrName versus Content
4439- # TODO test Name and Namespace
4440-
4441-
4442-def get_files_notebook(name):
4443- from tests import create_tmp_dir, get_test_data
4444- from zim.fs import Dir
4445- from zim.notebook import init_notebook, Notebook
4446-
4447- dir = Dir(create_tmp_dir(name))
4448- init_notebook(dir)
4449- notebook = Notebook(dir=dir)
4450- for name, text in get_test_data('wiki'):
4451- page = notebook.get_page(Path(name))
4452- page.parse('wiki', text)
4453- notebook.store_page(page)
4454-
4455- return notebook
4456-
4457-
4458+ # TODO test Name
4459+
4460+
4461+@tests.slowTest
4462 class TestSearchFiles(TestSearch):
4463
4464- slowTest = True
4465-
4466 def setUp(self):
4467- self.notebook = get_files_notebook('search_TestSearchFiles')
4468+ path = self.create_tmp_dir()
4469+ self.notebook = tests.new_files_notebook(path)
4470
4471 def runTest(self):
4472 '''Test search API with file based notebook'''
4473
4474=== modified file 'tests/stores.py'
4475--- tests/stores.py 2011-02-19 16:27:44 +0000
4476+++ tests/stores.py 2011-06-04 21:27:03 +0000
4477@@ -13,6 +13,7 @@
4478
4479 from zim.fs import *
4480 from zim.fs import FileWriteError
4481+from zim.errors import TrashNotSupportedError
4482 from zim.notebook import Notebook, Path, LookupError, PageExistsError
4483 import zim.stores
4484 from zim.formats import ParseTree
4485@@ -120,7 +121,7 @@
4486 #~ pprint.pprint(self.index)
4487 #~ pprint.pprint(names)
4488 self.assertTrue(u'utf8:\u03b1\u03b2\u03b3' in names) # Check usage of unicode
4489- self.assertEqualDiffData(names, self.index)
4490+ self.assertEqual(names, self.index)
4491
4492
4493 class TestStoresMemory(TestReadOnlyStore, tests.TestCase):
4494@@ -130,7 +131,7 @@
4495 store = zim.stores.get_store('memory')
4496 self.store = store.Store(path=Path(':'), notebook=Notebook())
4497 self.index = set()
4498- for name, text in tests.get_test_data('wiki'):
4499+ for name, text in tests.WikiTestData:
4500 self.store.set_node(Path(name), text)
4501 self.index.add(name)
4502 self.normalize_index()
4503@@ -143,14 +144,14 @@
4504 self.assertTrue(page.get_parsetree())
4505 self.assertTrue('Foo' in ''.join(page.dump('plain')))
4506 self.assertFalse(page.modified)
4507- wikitext = tests.get_test_data_page('wiki', 'roundtrip')
4508+ wikitext = tests.WikiTestData.get('roundtrip')
4509 page.parse('wiki', wikitext)
4510 self.assertTrue(page.modified)
4511 self.store.store_page(page)
4512 self.assertFalse(page.modified)
4513- self.assertEqualDiff(''.join(page.dump('wiki')), wikitext)
4514+ self.assertEqual(''.join(page.dump('wiki')), wikitext)
4515 page = self.store.get_page(Path('Test:foo'))
4516- self.assertEqualDiff(''.join(page.dump('wiki')), wikitext)
4517+ self.assertEqual(''.join(page.dump('wiki')), wikitext)
4518
4519 # check test setup OK
4520 for path in (Path('Test:BAR'), Path('NewPage')):
4521@@ -187,7 +188,10 @@
4522 self.assertFalse(page.hascontent)
4523
4524 # let's delete the newpath again
4525- self.assertTrue(self.store.delete_page(newpath))
4526+ page = self.store.get_page(newpath)
4527+ self.assertTrue(self.store.delete_page(page))
4528+ self.assertFalse(page.haschildren)
4529+ self.assertFalse(page.hascontent)
4530 page = self.store.get_page(newpath)
4531 self.assertFalse(page.haschildren)
4532 self.assertFalse(page.hascontent)
4533@@ -223,9 +227,34 @@
4534 page = self.store.get_page(Path('NewPage'))
4535 self.assertFalse(page.hascontent)
4536
4537- # TODO test getting a non-existing page
4538- # TODO test if children uses namespace objects
4539- # TODO test move, delete, read, write
4540+ # check trashing
4541+ trashing = True
4542+ try:
4543+ page = self.store.get_page(Path('TrashMe'))
4544+ self.assertTrue(page.haschildren)
4545+ self.assertTrue(page.hascontent)
4546+ self.store.trash_page(page)
4547+ self.assertFalse(page.haschildren)
4548+ self.assertFalse(page.hascontent)
4549+ page = self.store.get_page(Path('TrashMe'))
4550+ self.assertFalse(page.haschildren)
4551+ self.assertFalse(page.hascontent)
4552+ except TrashNotSupportedError:
4553+ trashing = False
4554+ print '(trashing not supported for this store)'
4555+ self.assertTrue(page.haschildren)
4556+ self.assertTrue(page.hascontent)
4557+ page = self.store.get_page(Path('TrashMe'))
4558+ self.assertTrue(page.haschildren)
4559+ self.assertTrue(page.hascontent)
4560+
4561+ page = self.store.get_page(Path('NonExistingPage'))
4562+ if trashing:
4563+ # fail silently for non-existing page
4564+ self.assertFalse(self.store.trash_page(page))
4565+ else:
4566+ # check error consistent
4567+ self.assertRaises(TrashNotSupportedError, self.store.trash_page, page)
4568
4569
4570 class TextXMLStore(TestReadOnlyStore, tests.TestCase):
4571@@ -265,17 +294,16 @@
4572 page = self.store.get_page(Path('Foo:Bar'))
4573 self.assertEqual(page.dump(format='wiki'), ['Foooo Barrr\n'])
4574 ref = self.xml.replace("'", '"')
4575- self.assertEqualDiff(''.join(self.store.dump()), ref)
4576-
4577-
4578+ self.assertEqual(''.join(self.store.dump()), ref)
4579+
4580+
4581+@tests.slowTest
4582 class TestFiles(TestStoresMemory):
4583 '''Test the store.files module'''
4584
4585- slowTest = True
4586-
4587 def setUp(self):
4588 TestStoresMemory.setUp(self)
4589- tmpdir = tests.create_tmp_dir(u'stores_TestFiles_\u0421\u0430\u0439')
4590+ tmpdir = self.create_tmp_dir(u'_some_utf8_here_\u0421\u0430\u0439')
4591 self.dir = Dir([tmpdir, 'store-files'])
4592 self.mem = self.store
4593 store = zim.stores.get_store('files')
4594@@ -349,4 +377,3 @@
4595
4596 def exists(self):
4597 return len(self.text) > 0
4598-
4599
4600=== added file 'tests/tags.py'
4601--- tests/tags.py 1970-01-01 00:00:00 +0000
4602+++ tests/tags.py 2011-06-04 21:27:03 +0000
4603@@ -0,0 +1,357 @@
4604+# -*- coding: utf-8 -*-
4605+
4606+# Copyright 2011 Jaap Karssenberg <jaap.karssenberg@gmail.com>
4607+
4608+import tests
4609+
4610+import gtk
4611+import pango
4612+
4613+from zim.index import Index, IndexPath, IndexTag
4614+from zim.notebook import Path
4615+from zim.gui.pageindex import FGCOLOR_COL, \
4616+ EMPTY_COL, NAME_COL, PATH_COL, STYLE_COL
4617+ # Explicitly don't import * from pageindex, make clear what we re-use
4618+from zim.config import ListDict
4619+from zim.plugins.tags import *
4620+
4621+
4622+def color_to_string(color):
4623+ # helper method for comparing gtk.gdk.Color objects
4624+ return '%i,%i,%i' % (color.red, color.green, color.blue)
4625+
4626+
4627+@tests.slowTest
4628+class TestTaggedPageTreeStore(tests.TestCase):
4629+
4630+ def setUp(self):
4631+ self.storeclass = TaggedPageTreeStore
4632+ self.viewclass = TagsPageTreeView
4633+ self.notebook = tests.new_notebook()
4634+ self.index = self.notebook.index
4635+
4636+ def runTest(self):
4637+ '''Test TaggedPageTreeStore index interface'''
4638+ # This is one big test instead of seperate sub tests because in the
4639+ # subclass we generate a file based notebook in setUp, and we do not
4640+ # want to do that many times.
4641+ # Hooking up the treeview as well just to see if we get any errors
4642+ # From the order the signals are generated.
4643+
4644+ ui = MockUI()
4645+ ui.notebook = self.notebook
4646+ ui.page = Path('Test:foo')
4647+ self.assertTrue(self.notebook.get_page(ui.page).exists())
4648+
4649+ treestore = self.storeclass(self.index)
4650+ self.assertEqual(treestore.get_flags(), 0)
4651+ self.assertEqual(treestore.get_n_columns(), 5)
4652+ treeview = self.viewclass(ui, treestore)
4653+ model = treeview.get_model()
4654+ if isinstance(model, gtk.TreeModelFilter):
4655+ model = model.get_model() # look inside filtered model
4656+ self.assertEqual(model, treestore)
4657+
4658+ self.assertEqual(treestore.get_flags(), 0)
4659+ self.assertEqual(treestore.get_n_columns(), 5)
4660+
4661+ self.index.update(callback=tests.gtk_process_events)
4662+ tests.gtk_process_events()
4663+
4664+ #~ treeview = PageTreeView(None) # just run hidden to check errors
4665+ #~ treeview.set_model(treestore)
4666+
4667+ n = treestore.on_iter_n_children(None)
4668+ self.assertTrue(n > 0)
4669+ n = treestore.iter_n_children(None)
4670+ self.assertTrue(n > 0)
4671+
4672+ for i in range(treestore.get_n_columns()):
4673+ self.assertTrue(not treestore.get_column_type(i) is None)
4674+
4675+ # Quick check for basic methods
4676+ iter = treestore.on_get_iter((0,))
4677+ self.assertTrue(isinstance(iter, (PageTreeIter, PageTreeTagIter)))
4678+ if self.storeclass is TaggedPageTreeStore:
4679+ self.assertTrue(isinstance(iter, PageTreeIter))
4680+ self.assertTrue(isinstance(iter.indexpath, IndexPath))
4681+ self.assertFalse(iter.indexpath.isroot)
4682+ else:
4683+ self.assertTrue(isinstance(iter, PageTreeTagIter))
4684+ self.assertTrue(isinstance(iter.indextag, IndexTag))
4685+ basename = treestore.on_get_value(iter, 0)
4686+ self.assertTrue(len(basename) > 0)
4687+ self.assertEqual(iter.treepath, (0,))
4688+ self.assertEqual(treestore.on_get_path(iter), (0,))
4689+ if self.storeclass is TaggedPageTreeStore:
4690+ self.assertEqual(treestore.get_treepath(iter.indexpath), (0,))
4691+ self.assertEqual(treestore.get_treepath(Path(iter.indexpath.name)), (0,))
4692+ else:
4693+ self.assertEqual(treestore.get_treepath(iter.indextag), (0,))
4694+
4695+ iter2 = treestore.on_iter_children(None)
4696+ if self.storeclass is TaggedPageTreeStore:
4697+ self.assertEqual(iter2.indexpath, iter.indexpath)
4698+ else:
4699+ self.assertEqual(iter2.indextag, iter.indextag)
4700+
4701+ self.assertTrue(treestore.on_get_iter((20,20,20,20,20)) is None)
4702+ self.assertTrue(treestore.get_treepath(Path('nonexisting')) is None)
4703+ self.assertRaises(ValueError, treestore.get_treepath, Path(':'))
4704+
4705+ # Now walk through the whole tree testing the API
4706+ nitems = 0
4707+ path = (0,)
4708+ prevpath = None
4709+ while path:
4710+ #~ print '>>', path
4711+ assert path != prevpath, 'Prevent infinite loop'
4712+ nitems += 1
4713+ prevpath = path
4714+
4715+ iter = treestore.get_iter(path)
4716+ self.assertEqual(treestore.get_path(iter), tuple(path))
4717+
4718+ if isinstance(treestore.on_get_iter(path), PageTreeIter):
4719+ self._check_indexpath_iter(treestore, iter, path)
4720+ else:
4721+ self._check_indextag_iter(treestore, iter, path)
4722+
4723+ # Determine how to continue
4724+ if treestore.iter_has_child(iter):
4725+ path = path + (0,)
4726+ else:
4727+ path = path[:-1] + (path[-1]+1,) # increase last member
4728+ while path:
4729+ try:
4730+ treestore.get_iter(path)
4731+ except ValueError:
4732+ path = path[:-1]
4733+ if len(path):
4734+ path = path[:-1] + (path[-1]+1,) # increase last member
4735+ else:
4736+ break
4737+
4738+ self.assertTrue(nitems > 10) # double check sanity of loop
4739+
4740+ # Check if all the signals go OK
4741+ treestore.disconnect_index()
4742+ del treestore
4743+ self.index.flush()
4744+ treestore = self.storeclass(self.index)
4745+ treeview = TagsPageTreeView(ui, treestore)
4746+ self.index.update(callback=tests.gtk_process_events)
4747+
4748+ # Try some TreeView methods
4749+ path = Path('Test:foo')
4750+ self.assertTrue(treeview.select_page(path))
4751+ self.assertEqual(treeview.get_selected_path(), path)
4752+ treepath = treeview.get_model().get_treepath(path)
4753+ self.assertTrue(not treepath is None)
4754+ col = treeview.get_column(0)
4755+ treeview.row_activated(treepath, col)
4756+
4757+ #~ treeview.emit('popup-menu')
4758+ treeview.emit('insert-link', path)
4759+ treeview.emit('copy')
4760+
4761+ # Check if all the signals go OK in delete
4762+ for page in reversed(list(self.notebook.walk())): # delete bottom up
4763+ self.notebook.delete_page(page)
4764+ tests.gtk_process_events()
4765+
4766+ def _check_indexpath_iter(self, treestore, iter, path):
4767+ # checks specific for nodes that map to IndexPath object
4768+ indexpath = treestore.get_indexpath(iter)
4769+ self.assertTrue(path in treestore.get_treepaths(indexpath))
4770+
4771+ page = self.notebook.get_page(indexpath)
4772+ self.assertEqual(treestore.get_value(iter, NAME_COL), page.basename)
4773+ self.assertEqual(treestore.get_value(iter, PATH_COL), page)
4774+ if page.hascontent or page.haschildren:
4775+ self.assertEqual(treestore.get_value(iter, EMPTY_COL), False)
4776+ self.assertEqual(treestore.get_value(iter, STYLE_COL), pango.STYLE_NORMAL)
4777+ self.assertEqual(
4778+ color_to_string( treestore.get_value(iter, FGCOLOR_COL) ),
4779+ color_to_string( treestore.NORMAL_COLOR) )
4780+ else:
4781+ self.assertEqual(treestore.get_value(iter, EMPTY_COL), True)
4782+ self.assertEqual(treestore.get_value(iter, STYLE_COL), pango.STYLE_ITALIC)
4783+ self.assertEqual(
4784+ color_to_string( treestore.get_value(iter, FGCOLOR_COL) ),
4785+ color_to_string( treestore.EMPTY_COLOR) )
4786+
4787+ self._check_iter_children(treestore, iter, path, indexpath.haschildren)
4788+
4789+ def _check_indextag_iter(self, treestore, iter, path):
4790+ # checks specific for nodes that map to IndexTag object
4791+ self.assertTrue(treestore.get_indexpath(iter) is None)
4792+
4793+ indextag = treestore.get_indextag(iter)
4794+ self.assertTrue(path in treestore.get_treepaths(indextag))
4795+
4796+ self.assertEqual(treestore.get_value(iter, NAME_COL), indextag.name)
4797+ self.assertEqual(treestore.get_value(iter, PATH_COL), indextag)
4798+ if indextag == treestore.untagged:
4799+ self.assertEqual(treestore.get_value(iter, EMPTY_COL), True)
4800+ self.assertEqual(treestore.get_value(iter, STYLE_COL), pango.STYLE_ITALIC)
4801+ self.assertEqual(
4802+ color_to_string( treestore.get_value(iter, FGCOLOR_COL) ),
4803+ color_to_string( treestore.EMPTY_COLOR) )
4804+ else:
4805+ self.assertEqual(treestore.get_value(iter, EMPTY_COL), False)
4806+ self.assertEqual(treestore.get_value(iter, STYLE_COL), pango.STYLE_NORMAL)
4807+ self.assertEqual(
4808+ color_to_string( treestore.get_value(iter, FGCOLOR_COL) ),
4809+ color_to_string( treestore.NORMAL_COLOR) )
4810+
4811+ if indextag == treestore.untagged:
4812+ haschildren = self.index.n_list_untagged_root_pages() > 0
4813+ else:
4814+ haschildren = self.index.n_list_tagged_pages(indextag) > 0
4815+ self._check_iter_children(treestore, iter, path, haschildren)
4816+
4817+ def _check_iter_children(self, treestore, iter, path, haschildren):
4818+ # Check API for children is consistent
4819+ if haschildren:
4820+ self.assertTrue(treestore.iter_has_child(iter))
4821+ child = treestore.iter_children(iter)
4822+ self.assertTrue(not child is None)
4823+ child = treestore.iter_nth_child(iter, 0)
4824+ self.assertTrue(not child is None)
4825+ parent = treestore.iter_parent(child)
4826+ self.assertEqual(treestore.get_path(parent), path)
4827+ childpath = treestore.get_path(child)
4828+ self.assertEqual(
4829+ childpath, tuple(path) + (0,))
4830+ n = treestore.iter_n_children(iter)
4831+ for i in range(1, n):
4832+ child = treestore.iter_next(child)
4833+ childpath = treestore.get_path(child)
4834+ self.assertEqual(
4835+ childpath, tuple(path) + (i,))
4836+ child = treestore.iter_next(child)
4837+ self.assertTrue(child is None)
4838+ else:
4839+ self.assertTrue(not treestore.iter_has_child(iter))
4840+ child = treestore.iter_children(iter)
4841+ self.assertTrue(child is None)
4842+ child = treestore.iter_nth_child(iter, 0)
4843+ self.assertTrue(child is None)
4844+
4845+
4846+@tests.slowTest
4847+class TestTagsPageTreeStore(TestTaggedPageTreeStore):
4848+
4849+ def setUp(self):
4850+ TestTaggedPageTreeStore.setUp(self)
4851+ self.storeclass = TagsPageTreeStore
4852+ self.viewclass = TagsPageTreeView
4853+
4854+ def runTest(self):
4855+ '''Test TagsPageTreeStore index interface'''
4856+ TestTaggedPageTreeStore.runTest(self)
4857+
4858+
4859+@tests.slowTest
4860+class TestTagPluginWidget(tests.TestCase):
4861+
4862+ def runTest(self):
4863+ ui = MockUI()
4864+ ui.notebook = tests.new_notebook()
4865+
4866+ plugin = tests.MockObject()
4867+ plugin.ui = ui
4868+ plugin.uistate = ListDict()
4869+
4870+ widget = TagsPluginWidget(plugin)
4871+
4872+ # Excersize all model switches and check we still have a sane state
4873+ widget.toggle_treeview()
4874+ widget.toggle_treeview()
4875+
4876+ path = Path('Test:foo')
4877+ treepath = widget.treeview.get_model().get_treepath(path)
4878+ self.assertTrue(not treepath is None)
4879+
4880+ widget.disconnect_model()
4881+ widget.reload_model()
4882+
4883+ path = Path('Test:foo')
4884+ treepath = widget.treeview.get_model().get_treepath(path)
4885+ self.assertTrue(not treepath is None)
4886+
4887+ # Check signals
4888+ #~ widget.treeview.emit('popup-menu')
4889+ widget.treeview.emit('insert-link', path)
4890+
4891+ # Check tag filtering
4892+ cloud = widget.tagcloud
4893+ self.assertEqual(cloud.get_tag_filter(), None)
4894+ tag = None
4895+ for button in cloud.get_children():
4896+ if button.indextag.name == 'tags':
4897+ tag = button.indextag
4898+ button.clicked()
4899+ break
4900+ else:
4901+ raise AssertionError, 'No button for @tags ?'
4902+
4903+ selected, filtered = cloud.get_tag_filter()
4904+ self.assertEqual(selected, [tag])
4905+ self.assertTrue(len(filtered) > 3)
4906+ self.assertTrue(tag in filtered)
4907+
4908+ self.assertTrue(not widget.treeview._tag_filter is None)
4909+
4910+ # check filtering in treestore
4911+ tagfilter = (selected, filtered)
4912+ filtered = frozenset(filtered)
4913+
4914+ def toplevel(model):
4915+ iter = model.get_iter_first()
4916+ assert not iter is None
4917+ while not iter is None:
4918+ yield iter
4919+ iter = model.iter_next(iter)
4920+
4921+ def childiter(model, iter):
4922+ iter = model.iter_children(iter)
4923+ assert not iter is None
4924+ while not iter is None:
4925+ yield iter
4926+ iter = model.iter_next(iter)
4927+
4928+ self.assertEqual(plugin.uistate['treeview'], 'tagged')
4929+ filteredmodel = widget.treeview.get_model()
4930+ for iter in toplevel(filteredmodel):
4931+ path = filteredmodel.get_indexpath(iter)
4932+ self.assertTrue(not path is None)
4933+ tags = list(ui.notebook.index.list_tags(path))
4934+ tags = frozenset(tags)
4935+ self.assertTrue(tags >= filtered)
4936+ treepaths = filteredmodel.get_treepaths(path)
4937+ self.assertTrue(filteredmodel.get_path(iter) in treepaths)
4938+
4939+ widget.toggle_treeview()
4940+ self.assertEqual(plugin.uistate['treeview'], 'tags')
4941+ filteredmodel = widget.treeview.get_model()
4942+ for iter in toplevel(filteredmodel):
4943+ self.assertEqual(filteredmodel.get_indexpath(iter), None)
4944+ # toplevel has tags, not pages
4945+ tag = filteredmodel[iter][PATH_COL]
4946+ self.assertTrue(tag in filtered)
4947+ for iter in childiter(filteredmodel, iter):
4948+ path = filteredmodel.get_indexpath(iter)
4949+ self.assertTrue(not path is None)
4950+ tags = list(ui.notebook.index.list_tags(path))
4951+ tags = frozenset(tags)
4952+ self.assertTrue(tags >= filtered)
4953+ treepaths = filteredmodel.get_treepaths(path)
4954+ self.assertTrue(filteredmodel.get_path(iter) in treepaths)
4955+
4956+
4957+class MockUI(tests.MockObject):
4958+
4959+ page = None
4960+ notebook = None
4961
4962=== modified file 'tests/tasklist.py'
4963--- tests/tasklist.py 2011-02-19 16:27:44 +0000
4964+++ tests/tasklist.py 2011-06-04 21:27:03 +0000
4965@@ -2,16 +2,17 @@
4966
4967 # Copyright 2011 Jaap Karssenberg <jaap.karssenberg@gmail.com>
4968
4969-from tests import TestCase, MockObject, get_test_notebook
4970+import tests
4971+
4972
4973 import zim.plugins
4974 import zim.config
4975 import zim.formats
4976
4977
4978-class TestTaskList(TestCase):
4979+class TestTaskList(tests.TestCase):
4980
4981- def runTest(self):
4982+ def testIndexing(self):
4983 '''Check indexing of tasklist plugin'''
4984 klass = zim.plugins.get_plugin('tasklist')
4985 ui = MockUI()
4986@@ -49,24 +50,32 @@
4987 tasks = plugin.extract_tasks(tree)
4988 labels = [task[-1] for task in tasks]
4989 self.assertEqual(labels, ['A', 'B', 'C', 'D', 'E', 'FIXME: dus'])
4990- self.assertEqualDiff(tree.tostring(), origtree)
4991+ self.assertEqual(tree.tostring(), origtree)
4992 # extract should not modify the tree
4993
4994 plugin.preferences['all_checkboxes'] = False
4995 tasks = plugin.extract_tasks(tree)
4996 labels = [task[-1] for task in tasks]
4997 self.assertEqual(labels, ['A', 'B', 'C', 'FIXME: dus'])
4998- self.assertEqualDiff(tree.tostring(), origtree)
4999+ self.assertEqual(tree.tostring(), origtree)
5000 # extract should not modify the tree
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches