From b29c59e4705a9de5c7be1de43cd726c3fc1d5a66 Mon Sep 17 00:00:00 2001 From: Ben Bleything Date: Mon, 15 Aug 2005 19:17:32 +0000 Subject: [PATCH] Line ending cleanup. Most of these are svn propsets which should make the files check out appropriately in the future. The three files in app/models had inconsitent line endings, so they had to be fixed by hand. --- CHANGELOG | 372 ++++++++++----------- README | 140 ++++---- app/models/page.rb | 272 ++++++++-------- app/models/revision.rb | 208 ++++++------ app/models/web.rb | 344 +++++++++---------- instiki.gemspec | 88 ++--- lib/db_structure.rb | 92 +++--- test/fixtures/pages.yml | 108 +++--- test/fixtures/revisions.yml | 166 +++++----- test/fixtures/webs.yml | 28 +- test/test_helper.rb | 212 ++++++------ test/unit/page_test.rb | 176 +++++----- test/unit/revision_test.rb | 634 ++++++++++++++++++------------------ test/unit/web_test.rb | 316 +++++++++--------- 14 files changed, 1578 insertions(+), 1578 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 96ba1c4f..519da063 100755 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,186 +1,186 @@ - * 0.10.2: - Upgraded to Rails 0.13.1 - Fixed HTML export - Added layout=no option to the export_html action (it exports page contents processed - by the markup engine, but without the default layout - so that they can be wrapped in - some other layout) - tag can span several lines (before it was applied when both opening and closing - tags were on the same line only) - Resolved the "endless redirection loop" condition and otherwise improved handling of - errors in the rendering engines - Fixed rendering of Markdown hyperlinks such as [Text](http://something.com/foo) - - * 0.10.1: - Upgraded Rails to 0.12.0 - Upgraded rubyzip to version 0.5.8 - BlueCloth is back (RedCloth didn't do pure Markdown well enough) - Handling of line breaks in Textile is as in 0.9 (inserts
tag) - Fixed HTML export (to enclose the output in tags, include the stylesheet etc) - Corrected some compatibility issues with storages from earlier Instiki versions - Some other bug fixes - - * 0.10.0: - Ported to ActionPack - RedCloth 3.0.3 - BlueCloth is phased out, Markdown is rendered by RedCloth - Mix markup option understands both Textile and Markdown on the same page - Instiki can serve static content (such as HTML or plain-text files) from ./public - directory - Much friendlier admin interface - Wiki link syntax doesn't conflict with Textile hyperlink syntax. Therefore - "textile link":LinkToSomePlace will not look insane. - RSS feeds accept query parameters, sush as - http://localhost:2500/wiki/rss_with_headlines?start=2005-02-18&end=2005-02-19&limit=10 - RSS feed with page contents for a password-protected web behaves as follows: - if the web is published, RSS feed links to the published version of the web - otherwise, the feed is not available - Madeleine will check every hour if there are new commands in the log or 24 hours have - passed since last snapshot, and take snapshot if either of these conditions is true - Madeleine will also not log read-only operations, resulting in a better performance - Wiki extracts (to HTML and plain text) will leave only the last extract file in ./storage - Wiki search handles multibyte (UTF-8) characters correctly - Local hyperlinks in published pages point to published pages [Michael DeHaan] - Fixed a bug that sometimes caused all past revisions of a page to be "forgotten" on - restart - Fixed parsing of URIs with a port number (http://someplace.org:8080) - Instiki will not fork itself on a *nix, unless explicitly asked to - Instiki can bind to IPs other than 127.0.0.1 (command-line option) - Revisions that do not change anything on the page are rejected - Automated tests for all controller actions - category: lines are presented as links to "All Pages" for relevant categories - Search looks at page titles, as well as content - Multiple other usability enhancements and bug fixes - - * 0.9.2: - Rollback takes the user to an edit form. The form has to be submitted for the change to - take place. - Changed to use inline style on published pages - Fixed "forward in time" on the last revision before current page - Instiki won't log bogus error messages when creating a new Wiki - Fixed deprecation warning for Object.id (introduced in Ruby 1.8.2) - Madeleine upgraded to 0.7.1 - Madeleine snapshots are compressed - Packaged as a gem - - * 0.9.1: - Added performance improvements for updating existing pages - Fixed IP logging and RSS feeds behind proxies [With help from Guan Yang] - Fixed default storage directory (borked running on Windows) [Spotted by Curt Hibbs] - - * 0.9.0: - Added aliased links such as [[HomePage|that nice home page]] [Mark Reid] - Added include other page content with [[!include TableOfContents]] [Mark Reid] - Added delete orphan pages from the Edit Web screen [by inspiration from Simon Arnaud] - Added logging of IP address for authors (who's behind the rollback wars) - Added Categories pages through backlinks (use "categories: news, instiki" on start of line) [Mark Reid] - Added option to use bracket-style wiki links only (and hence ban WikiWords) - Added command-line option to specify different storage path - Added print view without navigation - Added character and page (2275 characters including spaces) counter (important for student papers) - Off by default, activate it on the Edit Web screen - Added LaTeX/PDF integration on Textile installations with pdflatex installed on system (EXPERIMENTAL) - Use the home page as a table of contents with a unordered list to control sections - Added limit of 15 to the number of pages included in RSS feed - Moved static parts of stylesheet to separate file [Lau TŒrnskov] - Fixed better semantics for revision movement [Ryan Singer] - Fixed color diffs to work much better [Xen/Mertz/Atkins] - Fixed performance problems for All Pages list [Dennis Mertz] - Fixed lots of rendering bugs [Mark Reid] - Upgraded to RedCloth 2.0.11 [integrating the fine work of Dennis Mertz] - - * 0.8.9: - Added color diffs to see changes between revisions [Bill Atkins] - They're aren't quite perfect yet as new paragraphs split the tags (hence 0.8.9, not 0.9.0) - Added redirect to edit if content of page generates an error - (so the page doesn't become unusable on bugs in the markup engines) - Fixed update Web with different address bug [Denis Metz] - Fixed a bunch of wiki word rendering issues by doing wiki word detection and replacment at once - Upgraded to BlueCloth 0.0.3b (should fix loads of problems on Markdown wikis) - - * 0.8.5: - Instiki can now serve as a CMS by running a password-protected web with a published front - Added version check at startup (Instiki needs Ruby 1.8.1) - - * 0.8.1: - Actually included RedCloth 2.0.7 in the release - - * 0.8.0: - NOTE: Single-web wikis created in versions prior to 0.8.0 have "instiki" as their system password - Accepts wiki words in bracket style. Ex: [[wiki word]], [[c]], [[We could'nt have done it!]] - Accepts camel-case wiki words in all latin, greek, cyrillian, and armenian unicode characters - Many thanks to Guan Yang for building the higher- and lower-case lookup tables - And thanks to Simon Arnaud for the initial patch that got the work started - Changed charset to UTF-8 - Cut down on command-line options and replaced them with an per-web config screen - Added option to extend the stylesheet on a per-web basis to tweak the look in details - Added simple color options for variety - Added option to add/remove password protection on each web - Added the wiki name of the author locking a given page (instead of just "someone") - Removed single/multi-web distinction -- all Instikis are now multi-web - Load libraries from an unshifted load path, so that old installed libraries doesn't clash [Emiel van de Laar] - Keeps the author cookie forever, so you don't have to enter your name again and again - Fixed XHTML so it validates [Bruce D'Arcus] - Authors are no longer listed under orphan pages - Added export to markup (great for backups, potentially for switching wiki engine) - Don't link wiki words that proceeds from either /, = or ? - (http://c2.com/cgi/wiki?WikiWikiClones, /show/HomePage, cgi.pl?show=WikiWord without escaping) - Accessing an unexisting page redirects to a different url (/new/PageName) - Increased snapshot time to just once a day (cuts down on disk storage requirements) - Made RDoc support work better with 1.8.1 [Mauricio Fern‡ndez] - Added convinient redirect from /wiki/ to /wiki/show/HomePage - Fixed BlueCloth bug with backticks at start of line - Updated to RedCloth 2.0.7 (and linked to the new Textile reference) - - * 0.7.0: - Added Markdown (BlueCloth) and RDoc [Mauricio Fern‡ndez] as command-line markup choices - Added wanted and orphan page lists to All pages (only show up if there's actually orphan or wanted pages) - Added ISO-8859-1 as XML encoding in RSS feeds (makes FeedReader among others happy for special entities) - Added proper links in the RSS feed (but the body links are still relative, which NNW and others doesn't grok) - Added access keys: E => Edit, H => HomePage, A => All Pages, U => Recently Revised, X => Export - Added password-login through URL (so you can subscribe to feed on a protected web) - Added web passwords to the feed links for protected webs, so they work without manual login - Added the web name in small letters above all pages within a web - Polished authors and recently revised - Updated to RedCloth 2.0.6 - Changed content type for RSS feeds to text/xml (makes Mozilla Aggreg8 happy) - Changed searching to be case insensitive - Changed HomePage to display the name of the web instead - Changed exported HTML pages to be valid XHTML (which can be preprocessed by XSLT) - Fixed broken recently revised - - * 0.6.0: - Fixed Windows compatibility [Florian] - Fixed bug that would prevent Madeleine from taking snapshots in Daemon mode - Added export entire web as HTML in a zip file - Added RSS feeds - Added proper getops support for the growing number of options [Florian] - Added safe mode that forbids style options in RedCloth [Florian] - Updated RedCloth to 2.0.5 - - * 0.5.0: - NOTE: 0.5.0 is NOT compatible with databases from earlier versions - Added revisions - Added multiple webs - Added password protection for webs on multi-web setups - Added the notion of authors (that are saved in a cookie) - Added command-line option for not running as a Daemon on Unix - - * 0.3.1: - Added option to escape wiki words with \ - - * 0.3.0: - Brought all files into common style (including Textile help on the edit page) - Added page locking (if someone already is editing a page there's a warning) - Added daemon abilities on Unix (keep Instiki running after you close the terminal) - Made port 2500 the default port, so Instiki can be launched by dobbelt-click - Added Textile cache to speed-up rendering of large pages - Made WikiWords look like "Wiki Words" - Updated RedCloth to 2.0.4 - - * 0.2.5: - Upgraded to RedCloth 2.0.2 and Madeleine 0.6.1, which means the - Windows problems are gone. Also fixed a problem with wikiwords - that used part of other wikiwords. - - * 0.2.0: - First public release + * 0.10.2: + Upgraded to Rails 0.13.1 + Fixed HTML export + Added layout=no option to the export_html action (it exports page contents processed + by the markup engine, but without the default layout - so that they can be wrapped in + some other layout) + tag can span several lines (before it was applied when both opening and closing + tags were on the same line only) + Resolved the "endless redirection loop" condition and otherwise improved handling of + errors in the rendering engines + Fixed rendering of Markdown hyperlinks such as [Text](http://something.com/foo) + + * 0.10.1: + Upgraded Rails to 0.12.0 + Upgraded rubyzip to version 0.5.8 + BlueCloth is back (RedCloth didn't do pure Markdown well enough) + Handling of line breaks in Textile is as in 0.9 (inserts
tag) + Fixed HTML export (to enclose the output in tags, include the stylesheet etc) + Corrected some compatibility issues with storages from earlier Instiki versions + Some other bug fixes + + * 0.10.0: + Ported to ActionPack + RedCloth 3.0.3 + BlueCloth is phased out, Markdown is rendered by RedCloth + Mix markup option understands both Textile and Markdown on the same page + Instiki can serve static content (such as HTML or plain-text files) from ./public + directory + Much friendlier admin interface + Wiki link syntax doesn't conflict with Textile hyperlink syntax. Therefore + "textile link":LinkToSomePlace will not look insane. + RSS feeds accept query parameters, sush as + http://localhost:2500/wiki/rss_with_headlines?start=2005-02-18&end=2005-02-19&limit=10 + RSS feed with page contents for a password-protected web behaves as follows: + if the web is published, RSS feed links to the published version of the web + otherwise, the feed is not available + Madeleine will check every hour if there are new commands in the log or 24 hours have + passed since last snapshot, and take snapshot if either of these conditions is true + Madeleine will also not log read-only operations, resulting in a better performance + Wiki extracts (to HTML and plain text) will leave only the last extract file in ./storage + Wiki search handles multibyte (UTF-8) characters correctly + Local hyperlinks in published pages point to published pages [Michael DeHaan] + Fixed a bug that sometimes caused all past revisions of a page to be "forgotten" on + restart + Fixed parsing of URIs with a port number (http://someplace.org:8080) + Instiki will not fork itself on a *nix, unless explicitly asked to + Instiki can bind to IPs other than 127.0.0.1 (command-line option) + Revisions that do not change anything on the page are rejected + Automated tests for all controller actions + category: lines are presented as links to "All Pages" for relevant categories + Search looks at page titles, as well as content + Multiple other usability enhancements and bug fixes + + * 0.9.2: + Rollback takes the user to an edit form. The form has to be submitted for the change to + take place. + Changed to use inline style on published pages + Fixed "forward in time" on the last revision before current page + Instiki won't log bogus error messages when creating a new Wiki + Fixed deprecation warning for Object.id (introduced in Ruby 1.8.2) + Madeleine upgraded to 0.7.1 + Madeleine snapshots are compressed + Packaged as a gem + + * 0.9.1: + Added performance improvements for updating existing pages + Fixed IP logging and RSS feeds behind proxies [With help from Guan Yang] + Fixed default storage directory (borked running on Windows) [Spotted by Curt Hibbs] + + * 0.9.0: + Added aliased links such as [[HomePage|that nice home page]] [Mark Reid] + Added include other page content with [[!include TableOfContents]] [Mark Reid] + Added delete orphan pages from the Edit Web screen [by inspiration from Simon Arnaud] + Added logging of IP address for authors (who's behind the rollback wars) + Added Categories pages through backlinks (use "categories: news, instiki" on start of line) [Mark Reid] + Added option to use bracket-style wiki links only (and hence ban WikiWords) + Added command-line option to specify different storage path + Added print view without navigation + Added character and page (2275 characters including spaces) counter (important for student papers) + Off by default, activate it on the Edit Web screen + Added LaTeX/PDF integration on Textile installations with pdflatex installed on system (EXPERIMENTAL) + Use the home page as a table of contents with a unordered list to control sections + Added limit of 15 to the number of pages included in RSS feed + Moved static parts of stylesheet to separate file [Lau TŒrnskov] + Fixed better semantics for revision movement [Ryan Singer] + Fixed color diffs to work much better [Xen/Mertz/Atkins] + Fixed performance problems for All Pages list [Dennis Mertz] + Fixed lots of rendering bugs [Mark Reid] + Upgraded to RedCloth 2.0.11 [integrating the fine work of Dennis Mertz] + + * 0.8.9: + Added color diffs to see changes between revisions [Bill Atkins] + They're aren't quite perfect yet as new paragraphs split the tags (hence 0.8.9, not 0.9.0) + Added redirect to edit if content of page generates an error + (so the page doesn't become unusable on bugs in the markup engines) + Fixed update Web with different address bug [Denis Metz] + Fixed a bunch of wiki word rendering issues by doing wiki word detection and replacment at once + Upgraded to BlueCloth 0.0.3b (should fix loads of problems on Markdown wikis) + + * 0.8.5: + Instiki can now serve as a CMS by running a password-protected web with a published front + Added version check at startup (Instiki needs Ruby 1.8.1) + + * 0.8.1: + Actually included RedCloth 2.0.7 in the release + + * 0.8.0: + NOTE: Single-web wikis created in versions prior to 0.8.0 have "instiki" as their system password + Accepts wiki words in bracket style. Ex: [[wiki word]], [[c]], [[We could'nt have done it!]] + Accepts camel-case wiki words in all latin, greek, cyrillian, and armenian unicode characters + Many thanks to Guan Yang for building the higher- and lower-case lookup tables + And thanks to Simon Arnaud for the initial patch that got the work started + Changed charset to UTF-8 + Cut down on command-line options and replaced them with an per-web config screen + Added option to extend the stylesheet on a per-web basis to tweak the look in details + Added simple color options for variety + Added option to add/remove password protection on each web + Added the wiki name of the author locking a given page (instead of just "someone") + Removed single/multi-web distinction -- all Instikis are now multi-web + Load libraries from an unshifted load path, so that old installed libraries doesn't clash [Emiel van de Laar] + Keeps the author cookie forever, so you don't have to enter your name again and again + Fixed XHTML so it validates [Bruce D'Arcus] + Authors are no longer listed under orphan pages + Added export to markup (great for backups, potentially for switching wiki engine) + Don't link wiki words that proceeds from either /, = or ? + (http://c2.com/cgi/wiki?WikiWikiClones, /show/HomePage, cgi.pl?show=WikiWord without escaping) + Accessing an unexisting page redirects to a different url (/new/PageName) + Increased snapshot time to just once a day (cuts down on disk storage requirements) + Made RDoc support work better with 1.8.1 [Mauricio Fern‡ndez] + Added convinient redirect from /wiki/ to /wiki/show/HomePage + Fixed BlueCloth bug with backticks at start of line + Updated to RedCloth 2.0.7 (and linked to the new Textile reference) + + * 0.7.0: + Added Markdown (BlueCloth) and RDoc [Mauricio Fern‡ndez] as command-line markup choices + Added wanted and orphan page lists to All pages (only show up if there's actually orphan or wanted pages) + Added ISO-8859-1 as XML encoding in RSS feeds (makes FeedReader among others happy for special entities) + Added proper links in the RSS feed (but the body links are still relative, which NNW and others doesn't grok) + Added access keys: E => Edit, H => HomePage, A => All Pages, U => Recently Revised, X => Export + Added password-login through URL (so you can subscribe to feed on a protected web) + Added web passwords to the feed links for protected webs, so they work without manual login + Added the web name in small letters above all pages within a web + Polished authors and recently revised + Updated to RedCloth 2.0.6 + Changed content type for RSS feeds to text/xml (makes Mozilla Aggreg8 happy) + Changed searching to be case insensitive + Changed HomePage to display the name of the web instead + Changed exported HTML pages to be valid XHTML (which can be preprocessed by XSLT) + Fixed broken recently revised + + * 0.6.0: + Fixed Windows compatibility [Florian] + Fixed bug that would prevent Madeleine from taking snapshots in Daemon mode + Added export entire web as HTML in a zip file + Added RSS feeds + Added proper getops support for the growing number of options [Florian] + Added safe mode that forbids style options in RedCloth [Florian] + Updated RedCloth to 2.0.5 + + * 0.5.0: + NOTE: 0.5.0 is NOT compatible with databases from earlier versions + Added revisions + Added multiple webs + Added password protection for webs on multi-web setups + Added the notion of authors (that are saved in a cookie) + Added command-line option for not running as a Daemon on Unix + + * 0.3.1: + Added option to escape wiki words with \ + + * 0.3.0: + Brought all files into common style (including Textile help on the edit page) + Added page locking (if someone already is editing a page there's a warning) + Added daemon abilities on Unix (keep Instiki running after you close the terminal) + Made port 2500 the default port, so Instiki can be launched by dobbelt-click + Added Textile cache to speed-up rendering of large pages + Made WikiWords look like "Wiki Words" + Updated RedCloth to 2.0.4 + + * 0.2.5: + Upgraded to RedCloth 2.0.2 and Madeleine 0.6.1, which means the + Windows problems are gone. Also fixed a problem with wikiwords + that used part of other wikiwords. + + * 0.2.0: + First public release diff --git a/README b/README index b5df8534..09d29a9f 100755 --- a/README +++ b/README @@ -1,70 +1,70 @@ -===What is Instiki? - -Admitted, it's YetAnotherWikiClone[http://c2.com/cgi/wiki?WikiWikiClones], but with a strong focus -on simplicity of installation and running: - -Step 1. Download - -Step 2. Run "instiki" - -Step 3. Chuckle... "There's no step three!" (TM) - -You're now running a perfectly suitable wiki on port 2500 -that'll present you with one-step setup, followed by a textarea for the home page -on http://localhost:2500. - -Instiki lowers the barriers of interest for when you might consider -using a wiki. It's so simple to get running that you'll find yourself -using it for anything -- taking notes, brainstorming, organizing a -gathering. - -===Features: -* Regular expression search: Find deep stuff really fast -* Revisions: Follow the changes on every page from birth. Rollback to an earlier rev -* Export to HTML or markup in a zip: Take the entire wiki with you home or for reference -* RSS feeds to track recently revised pages -* Multiple webs: Create separate wikis with their own namespace -* Password-protected webs: Keep it private -* Authors: Each revision is associated with an author, so you can see who changed what -* Reference tracker: Which other pages are pointing to the current? -* Speed: Using Madelein[http://madeleine.sourceforge.net] for persistence (all pages are in memory) -* Three markup choices: Textile[http://www.textism.com/tools/textile] - (default / RedCloth[http://www.whytheluckystiff.net/ruby/redcloth]), - Markdown (BlueCloth[http://bluecloth.rubyforge.org]), and RDoc[http://rdoc.sourceforge.net/doc] -* Embedded webserver: Through WEBrick[http://www.webrick.org] -* Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters -* Color diffs: Track changes through revisions - -===Missing: -* File attachments - -===Install from gem: -* Install rubygems -* Run "gem install instiki" -* Change to a directory where you want Instiki to keep its data files (for example, ~/instiki/) -* Run "instiki" - this will create a "storage" directory (for example, ~/instiki/storage), and start a new Wiki service - -Make sure that you always launch Instiki from the same working directory, or specify the storage directory in runtime parameters, such as: - instiki --storage ~/instiki/storage - -===Command-line options: -* Run "instiki --help" - -===History: - * See CHANGELOG - -===Download latest from: -* http://rubyforge.org/project/showfiles.php?group_id=186 - -===Visit the official Instiki wiki: -* http://www.instiki.org - -===License: -* same as Ruby's - ---- -Author:: David Heinemeier Hansson -Email:: david@loudthinking.com -Weblog:: http://www.loudthinking.com - - +===What is Instiki? + +Admitted, it's YetAnotherWikiClone[http://c2.com/cgi/wiki?WikiWikiClones], but with a strong focus +on simplicity of installation and running: + +Step 1. Download + +Step 2. Run "instiki" + +Step 3. Chuckle... "There's no step three!" (TM) + +You're now running a perfectly suitable wiki on port 2500 +that'll present you with one-step setup, followed by a textarea for the home page +on http://localhost:2500. + +Instiki lowers the barriers of interest for when you might consider +using a wiki. It's so simple to get running that you'll find yourself +using it for anything -- taking notes, brainstorming, organizing a +gathering. + +===Features: +* Regular expression search: Find deep stuff really fast +* Revisions: Follow the changes on every page from birth. Rollback to an earlier rev +* Export to HTML or markup in a zip: Take the entire wiki with you home or for reference +* RSS feeds to track recently revised pages +* Multiple webs: Create separate wikis with their own namespace +* Password-protected webs: Keep it private +* Authors: Each revision is associated with an author, so you can see who changed what +* Reference tracker: Which other pages are pointing to the current? +* Speed: Using Madelein[http://madeleine.sourceforge.net] for persistence (all pages are in memory) +* Three markup choices: Textile[http://www.textism.com/tools/textile] + (default / RedCloth[http://www.whytheluckystiff.net/ruby/redcloth]), + Markdown (BlueCloth[http://bluecloth.rubyforge.org]), and RDoc[http://rdoc.sourceforge.net/doc] +* Embedded webserver: Through WEBrick[http://www.webrick.org] +* Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters +* Color diffs: Track changes through revisions + +===Missing: +* File attachments + +===Install from gem: +* Install rubygems +* Run "gem install instiki" +* Change to a directory where you want Instiki to keep its data files (for example, ~/instiki/) +* Run "instiki" - this will create a "storage" directory (for example, ~/instiki/storage), and start a new Wiki service + +Make sure that you always launch Instiki from the same working directory, or specify the storage directory in runtime parameters, such as: + instiki --storage ~/instiki/storage + +===Command-line options: +* Run "instiki --help" + +===History: + * See CHANGELOG + +===Download latest from: +* http://rubyforge.org/project/showfiles.php?group_id=186 + +===Visit the official Instiki wiki: +* http://www.instiki.org + +===License: +* same as Ruby's + +--- +Author:: David Heinemeier Hansson +Email:: david@loudthinking.com +Weblog:: http://www.loudthinking.com + + diff --git a/app/models/page.rb b/app/models/page.rb index 8f2ef436..dfd5b87c 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -1,137 +1,137 @@ -class Page < ActiveRecord::Base - belongs_to :web - has_many :revisions, :order => 'id' - has_one :current_revision, :class_name => 'Revision', :order => 'id DESC' - - def revise(content, time, author) - revisions_size = new_record? ? 0 : revisions.size - if (revisions_size > 0) and content == current_revision.content - raise Instiki::ValidationError.new( - "You have tried to save page '#{name}' without changing its content") - end - - author = Author.new(author.to_s) unless author.is_a?(Author) - - # Try to render content to make sure that markup engine can take it, - Revision.new(:page => self, :content => content, :author => author, :revised_at => time).force_rendering - - # A user may change a page, look at it and make some more changes - several times. - # Not to record every such iteration as a new revision, if the previous revision was done - # by the same author, not more than 30 minutes ago, then update the last revision instead of - # creating a new one - if (revisions_size > 0) && continous_revision?(time, author) - current_revision.update_attributes(:content => content, :revised_at => time) - else - Revision.create(:page => self, :content => content, :author => author, :revised_at => time) - end - - save - web.refresh_pages_with_references(name) if revisions_size == 0 - - self - end - - def rollback(revision_number, time, author_ip = nil) - roll_back_revision = self.revisions[revision_number] - if roll_back_revision.nil? - raise Instiki::ValidationError.new("Revision #{revision_number} not found") - end - revise(roll_back_revision.content, time, Author.new(roll_back_revision.author, author_ip)) - end - - def revisions? - revisions.size > 1 - end - - def previous_revision(revision) - revision_index = revisions.each_with_index do |rev, index| - if rev.id == revision.id - break index - else - nil - end - end - if revision_index.nil? or revision_index == 0 - nil - else - revisions[revision_index - 1] - end - end - - def in_category?(cat) - cat.nil? || cat.empty? || categories.include?(cat) - end - - def categories - display_content.find_chunks(Category).map { |cat| cat.list }.flatten - end - - def authors - revisions.collect { |rev| rev.author } - end - - def references - web.select.pages_that_reference(name) - end - - def linked_from - web.select.pages_that_link_to(name) - end - - def included_from - web.select.pages_that_include(name) - end - - # Returns the original wiki-word name as separate words, so "MyPage" becomes "My Page". - def plain_name - web.brackets_only? ? name : WikiWords.separate(name) - end - - # used to build chunk ids. - #def id - # @id ||= name.unpack('H*').first - #end - - def link(options = {}) - web.make_link(name, nil, options) - end - - def author_link(options = {}) - web.make_link(author, nil, options) - end - - LOCKING_PERIOD = 30.minutes - - def lock(time, locked_by) - update_attributes(:locked_at => time, :locked_by => locked_by) - end - - def lock_duration(time) - ((time - locked_at) / 60).to_i unless locked_at.nil? - end - - def unlock - update_attribute(:locked_at, nil) - end - - def locked?(comparison_time) - locked_at + LOCKING_PERIOD > comparison_time unless locked_at.nil? - end - - private - - def continous_revision?(time, author) - (current_revision.author == author) && (revised_at + 30.minutes > time) - end - - # Forward method calls to the current revision, so the page responds to all revision calls - def method_missing(method_id, *args, &block) - method_name = method_id.to_s - # Perform a hand-off to AR::Base#method_missing - if @attributes.include?(method_name) or md = /(=|\?|_before_type_cast)$/.match(method_name) - super(method_id, *args, &block) - else - current_revision.send(method_id) - end - end +class Page < ActiveRecord::Base + belongs_to :web + has_many :revisions, :order => 'id' + has_one :current_revision, :class_name => 'Revision', :order => 'id DESC' + + def revise(content, time, author) + revisions_size = new_record? ? 0 : revisions.size + if (revisions_size > 0) and content == current_revision.content + raise Instiki::ValidationError.new( + "You have tried to save page '#{name}' without changing its content") + end + + author = Author.new(author.to_s) unless author.is_a?(Author) + + # Try to render content to make sure that markup engine can take it, + Revision.new(:page => self, :content => content, :author => author, :revised_at => time).force_rendering + + # A user may change a page, look at it and make some more changes - several times. + # Not to record every such iteration as a new revision, if the previous revision was done + # by the same author, not more than 30 minutes ago, then update the last revision instead of + # creating a new one + if (revisions_size > 0) && continous_revision?(time, author) + current_revision.update_attributes(:content => content, :revised_at => time) + else + Revision.create(:page => self, :content => content, :author => author, :revised_at => time) + end + + save + web.refresh_pages_with_references(name) if revisions_size == 0 + + self + end + + def rollback(revision_number, time, author_ip = nil) + roll_back_revision = self.revisions[revision_number] + if roll_back_revision.nil? + raise Instiki::ValidationError.new("Revision #{revision_number} not found") + end + revise(roll_back_revision.content, time, Author.new(roll_back_revision.author, author_ip)) + end + + def revisions? + revisions.size > 1 + end + + def previous_revision(revision) + revision_index = revisions.each_with_index do |rev, index| + if rev.id == revision.id + break index + else + nil + end + end + if revision_index.nil? or revision_index == 0 + nil + else + revisions[revision_index - 1] + end + end + + def in_category?(cat) + cat.nil? || cat.empty? || categories.include?(cat) + end + + def categories + display_content.find_chunks(Category).map { |cat| cat.list }.flatten + end + + def authors + revisions.collect { |rev| rev.author } + end + + def references + web.select.pages_that_reference(name) + end + + def linked_from + web.select.pages_that_link_to(name) + end + + def included_from + web.select.pages_that_include(name) + end + + # Returns the original wiki-word name as separate words, so "MyPage" becomes "My Page". + def plain_name + web.brackets_only? ? name : WikiWords.separate(name) + end + + # used to build chunk ids. + #def id + # @id ||= name.unpack('H*').first + #end + + def link(options = {}) + web.make_link(name, nil, options) + end + + def author_link(options = {}) + web.make_link(author, nil, options) + end + + LOCKING_PERIOD = 30.minutes + + def lock(time, locked_by) + update_attributes(:locked_at => time, :locked_by => locked_by) + end + + def lock_duration(time) + ((time - locked_at) / 60).to_i unless locked_at.nil? + end + + def unlock + update_attribute(:locked_at, nil) + end + + def locked?(comparison_time) + locked_at + LOCKING_PERIOD > comparison_time unless locked_at.nil? + end + + private + + def continous_revision?(time, author) + (current_revision.author == author) && (revised_at + 30.minutes > time) + end + + # Forward method calls to the current revision, so the page responds to all revision calls + def method_missing(method_id, *args, &block) + method_name = method_id.to_s + # Perform a hand-off to AR::Base#method_missing + if @attributes.include?(method_name) or md = /(=|\?|_before_type_cast)$/.match(method_name) + super(method_id, *args, &block) + else + current_revision.send(method_id) + end + end end diff --git a/app/models/revision.rb b/app/models/revision.rb index 9aab6370..56d818ce 100644 --- a/app/models/revision.rb +++ b/app/models/revision.rb @@ -1,105 +1,105 @@ -require 'diff' -class Revision < ActiveRecord::Base - belongs_to :page - composed_of :author, :mapping => [ %w(author name), %w(ip ip) ] - - # Returns an array of all the WikiIncludes present in the content of this revision. - def wiki_includes - unless @wiki_includes_cache - chunks = display_content.find_chunks(Include) - @wiki_includes_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq - end - @wiki_includes_cache - end - - # Returns an array of all the WikiReferences present in the content of this revision. - def wiki_references - unless @wiki_references_cache - chunks = display_content.find_chunks(WikiChunk::WikiReference) - @wiki_references_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq - end - @wiki_references_cache - end - - # Returns an array of all the WikiWords present in the content of this revision. - def wiki_words - unless @wiki_words_cache - wiki_chunks = display_content.find_chunks(WikiChunk::WikiLink) - @wiki_words_cache = wiki_chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq - end - @wiki_words_cache - end - - # Returns an array of all the WikiWords present in the content of this revision. - # that already exists as a page in the web. - def existing_pages - wiki_words.select { |wiki_word| page.web.page(wiki_word) } - end - - # Returns an array of all the WikiWords present in the content of this revision - # that *doesn't* already exists as a page in the web. - def unexisting_pages - wiki_words - existing_pages - end - - # Explicit check for new type of display cache with chunks_by_type method. - # Ensures new version works with older snapshots. - def display_content - unless @display_cache && @display_cache.respond_to?(:chunks_by_type) - @display_cache = WikiContent.new(self) - @display_cache.render! - end - @display_cache - end - - # TODO this probably doesn't belong in revision (because it has to call back the page) - def display_diff - previous_revision = page.previous_revision(self) - if previous_revision - HTMLDiff.diff(previous_revision.display_content, display_content) - else - display_content - end - end - - def clear_display_cache - @wiki_words_cache = @published_cache = @display_cache = @wiki_includes_cache = - @wiki_references_cache = nil - end - - def display_published - unless @published_cache && @published_cache.respond_to?(:chunks_by_type) - @published_cache = WikiContent.new(self, {:mode => :publish}) - @published_cache.render! - end - @published_cache - end - - def display_content_for_export - WikiContent.new(self, {:mode => :export} ).render! - end - - def force_rendering - begin - display_content.render! - rescue => e - logger.error "Failed rendering page #{@name}" - logger.error e - message = e.message - # substitute content with an error message - self.content = <<-EOL -

Markup engine has failed to render this page, raising the following error:

-

#{message}

-
#{self.content}
- EOL - clear_display_cache - raise e - end - end - - protected - - after_create :force_rendering - after_save :clear_display_cache - +require 'diff' +class Revision < ActiveRecord::Base + belongs_to :page + composed_of :author, :mapping => [ %w(author name), %w(ip ip) ] + + # Returns an array of all the WikiIncludes present in the content of this revision. + def wiki_includes + unless @wiki_includes_cache + chunks = display_content.find_chunks(Include) + @wiki_includes_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq + end + @wiki_includes_cache + end + + # Returns an array of all the WikiReferences present in the content of this revision. + def wiki_references + unless @wiki_references_cache + chunks = display_content.find_chunks(WikiChunk::WikiReference) + @wiki_references_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq + end + @wiki_references_cache + end + + # Returns an array of all the WikiWords present in the content of this revision. + def wiki_words + unless @wiki_words_cache + wiki_chunks = display_content.find_chunks(WikiChunk::WikiLink) + @wiki_words_cache = wiki_chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq + end + @wiki_words_cache + end + + # Returns an array of all the WikiWords present in the content of this revision. + # that already exists as a page in the web. + def existing_pages + wiki_words.select { |wiki_word| page.web.page(wiki_word) } + end + + # Returns an array of all the WikiWords present in the content of this revision + # that *doesn't* already exists as a page in the web. + def unexisting_pages + wiki_words - existing_pages + end + + # Explicit check for new type of display cache with chunks_by_type method. + # Ensures new version works with older snapshots. + def display_content + unless @display_cache && @display_cache.respond_to?(:chunks_by_type) + @display_cache = WikiContent.new(self) + @display_cache.render! + end + @display_cache + end + + # TODO this probably doesn't belong in revision (because it has to call back the page) + def display_diff + previous_revision = page.previous_revision(self) + if previous_revision + HTMLDiff.diff(previous_revision.display_content, display_content) + else + display_content + end + end + + def clear_display_cache + @wiki_words_cache = @published_cache = @display_cache = @wiki_includes_cache = + @wiki_references_cache = nil + end + + def display_published + unless @published_cache && @published_cache.respond_to?(:chunks_by_type) + @published_cache = WikiContent.new(self, {:mode => :publish}) + @published_cache.render! + end + @published_cache + end + + def display_content_for_export + WikiContent.new(self, {:mode => :export} ).render! + end + + def force_rendering + begin + display_content.render! + rescue => e + logger.error "Failed rendering page #{@name}" + logger.error e + message = e.message + # substitute content with an error message + self.content = <<-EOL +

Markup engine has failed to render this page, raising the following error:

+

#{message}

+
#{self.content}
+ EOL + clear_display_cache + raise e + end + end + + protected + + after_create :force_rendering + after_save :clear_display_cache + end diff --git a/app/models/web.rb b/app/models/web.rb index be520aba..13cb6f31 100644 --- a/app/models/web.rb +++ b/app/models/web.rb @@ -1,173 +1,173 @@ -require 'cgi' - -class Web < ActiveRecord::Base - has_many :pages#, :include => [:current_revision, :web] - - def wiki - Wiki.new - end - - def file_yard - @file_yard ||= FileYard.new("#{Wiki.storage_path}/#{address}", max_upload_size) - end - - def settings_changed?(markup, safe_mode, brackets_only) - self.markup != markup || - self.safe_mode != safe_mode || - self.brackets_only != brackets_only - end - - def add_page(name, content, time, author) - page = page(name) || Page.new(:web => self, :name => name) - page.revise(content, time, author) - end - - def authors - select.authors - end - - def categories - select.map { |page| page.categories }.flatten.uniq.sort - end - - def page(name) - pages.find(:first, :conditions => ['name = ?', name]) - end - - def has_page?(name) - Page.count(['web_id = ? AND name = ?', id, name]) > 0 - end - - def has_file?(name) - wiki.file_yard(self).has_file?(name) - end - - def markup - read_attribute('markup').to_sym - end - - def make_file_link(mode, name, text, base_url) - link = CGI.escape(name) - case mode - when :export - if has_file?(name) then "#{text}" - else "#{text}" end - when :publish - if has_file?(name) then "#{text}" - else "#{text}" end - else - if has_file?(name) - "#{text}" - else - "#{text}?" - end - end - end - - # Create a link for the given page name and link text based - # on the render mode in options and whether the page exists - # in the this web. - # The links a relative, and will work only if displayed on another WikiPage. - # It should not be used in menus, templates and such - instead, use link_to_page helper - def make_link(name, text = nil, options = {}) - text = CGI.escapeHTML(text || WikiWords.separate(name)) - mode = options[:mode] || :show - base_url = options[:base_url] || '..' - link_type = options[:link_type] || :show - case link_type.to_sym - when :show - make_page_link(mode, name, text, base_url) - when :file - make_file_link(mode, name, text, base_url) - when :pic - make_pic_link(mode, name, text, base_url) - else - raise "Unknown link type: #{link_type}" - end - end - - def make_page_link(mode, name, text, base_url) - link = CGI.escape(name) - case mode.to_sym - when :export - if has_page?(name) then %{#{text}} - else %{#{text}} end - when :publish - if has_page?(name) then %{#{text}} - else %{#{text}} end - else - if has_page?(name) - %{#{text}} - else - %{#{text}?} - end - end - end - - def make_pic_link(mode, name, text, base_url) - link = CGI.escape(name) - case mode.to_sym - when :export - if has_file?(name) then %{#{text}} - else %{#{text}} end - when :publish - if has_file?(name) then %{#{text}} - else %{#{text}} end - else - if has_file?(name) then %{#{text}} - else %{#{text}?} end - end - end - - # Clears the display cache for all the pages with references to - def refresh_pages_with_references(page_name) - #select.pages_that_reference(page_name).each { |page| - # page.revisions.each { |revision| revision.clear_display_cache } - #} - end - - def refresh_revisions - select.each { |page| page.revisions.each { |revision| revision.clear_display_cache } } - end - - def remove_pages(pages_to_be_removed) - pages_to_be_removed.each { |p| p.destroy } - end - - def revised_at - select.most_recent_revision - end - - def select(&condition) - PageSet.new(self, pages, condition) - end - - private - - # Returns an array of all the wiki words in any current revision - def wiki_words - pages.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq - end - - # Returns an array of all the page names on this web - def page_names - pages.map { |p| p.name } - end - - protected - before_save :sanitize_markup - before_validation :validate_address - validates_uniqueness_of :address - validates_length_of :color, :in => 3..6 - - def sanitize_markup - self.markup = markup.to_s - end - - def validate_address - unless address == CGI.escape(address) - self.errors.add(:address, 'should contain only valid URI characters') - raise Instiki::ValidationError.new("#{self.class.human_attribute_name('address')} #{errors.on(:address)}") - end - end +require 'cgi' + +class Web < ActiveRecord::Base + has_many :pages#, :include => [:current_revision, :web] + + def wiki + Wiki.new + end + + def file_yard + @file_yard ||= FileYard.new("#{Wiki.storage_path}/#{address}", max_upload_size) + end + + def settings_changed?(markup, safe_mode, brackets_only) + self.markup != markup || + self.safe_mode != safe_mode || + self.brackets_only != brackets_only + end + + def add_page(name, content, time, author) + page = page(name) || Page.new(:web => self, :name => name) + page.revise(content, time, author) + end + + def authors + select.authors + end + + def categories + select.map { |page| page.categories }.flatten.uniq.sort + end + + def page(name) + pages.find(:first, :conditions => ['name = ?', name]) + end + + def has_page?(name) + Page.count(['web_id = ? AND name = ?', id, name]) > 0 + end + + def has_file?(name) + wiki.file_yard(self).has_file?(name) + end + + def markup + read_attribute('markup').to_sym + end + + def make_file_link(mode, name, text, base_url) + link = CGI.escape(name) + case mode + when :export + if has_file?(name) then "#{text}" + else "#{text}" end + when :publish + if has_file?(name) then "#{text}" + else "#{text}" end + else + if has_file?(name) + "#{text}" + else + "#{text}?" + end + end + end + + # Create a link for the given page name and link text based + # on the render mode in options and whether the page exists + # in the this web. + # The links a relative, and will work only if displayed on another WikiPage. + # It should not be used in menus, templates and such - instead, use link_to_page helper + def make_link(name, text = nil, options = {}) + text = CGI.escapeHTML(text || WikiWords.separate(name)) + mode = options[:mode] || :show + base_url = options[:base_url] || '..' + link_type = options[:link_type] || :show + case link_type.to_sym + when :show + make_page_link(mode, name, text, base_url) + when :file + make_file_link(mode, name, text, base_url) + when :pic + make_pic_link(mode, name, text, base_url) + else + raise "Unknown link type: #{link_type}" + end + end + + def make_page_link(mode, name, text, base_url) + link = CGI.escape(name) + case mode.to_sym + when :export + if has_page?(name) then %{#{text}} + else %{#{text}} end + when :publish + if has_page?(name) then %{#{text}} + else %{#{text}} end + else + if has_page?(name) + %{#{text}} + else + %{#{text}?} + end + end + end + + def make_pic_link(mode, name, text, base_url) + link = CGI.escape(name) + case mode.to_sym + when :export + if has_file?(name) then %{#{text}} + else %{#{text}} end + when :publish + if has_file?(name) then %{#{text}} + else %{#{text}} end + else + if has_file?(name) then %{#{text}} + else %{#{text}?} end + end + end + + # Clears the display cache for all the pages with references to + def refresh_pages_with_references(page_name) + #select.pages_that_reference(page_name).each { |page| + # page.revisions.each { |revision| revision.clear_display_cache } + #} + end + + def refresh_revisions + select.each { |page| page.revisions.each { |revision| revision.clear_display_cache } } + end + + def remove_pages(pages_to_be_removed) + pages_to_be_removed.each { |p| p.destroy } + end + + def revised_at + select.most_recent_revision + end + + def select(&condition) + PageSet.new(self, pages, condition) + end + + private + + # Returns an array of all the wiki words in any current revision + def wiki_words + pages.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq + end + + # Returns an array of all the page names on this web + def page_names + pages.map { |p| p.name } + end + + protected + before_save :sanitize_markup + before_validation :validate_address + validates_uniqueness_of :address + validates_length_of :color, :in => 3..6 + + def sanitize_markup + self.markup = markup.to_s + end + + def validate_address + unless address == CGI.escape(address) + self.errors.add(:address, 'should contain only valid URI characters') + raise Instiki::ValidationError.new("#{self.class.human_attribute_name('address')} #{errors.on(:address)}") + end + end end diff --git a/instiki.gemspec b/instiki.gemspec index adf1dd74..c65ac414 100755 --- a/instiki.gemspec +++ b/instiki.gemspec @@ -1,44 +1,44 @@ -$__instiki_source_patterns = [ - '[A-Z]*', 'instiki', 'instiki.rb', 'app/**/*', 'lib/**/*', 'vendor/**/*', - 'public/**/*', 'natives/**/*', 'config/**/*', 'script/**/*' -] - -spec = Gem::Specification.new do |s| - s.platform = Gem::Platform::RUBY - s.name = 'instiki' - s.version = "0.10.2" - s.summary = 'Easy to install WikiClone running on WEBrick and SQLite' - s.description = <<-EOF - Instiki is a Wiki Clone written in Ruby that ships with an embedded - webserver. You can setup up an Instiki in just a few steps. - Possibly the simplest wiki setup ever. - EOF - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.rubyforge_project = 'instiki' - s.homepage = 'http://www.instiki.org' - - s.bindir = '.' - s.executables = ['instiki'] - s.default_executable = 'instiki' - - s.has_rdoc = false - - s.add_dependency('RedCloth', '= 3.0.3') - s.add_dependency('rubyzip', '= 0.5.8') - s.add_dependency('rails', '= 0.13.1') - s.add_dependency('sqlite3-ruby', '= 1.1.0') - s.requirements << 'none' - s.require_path = 'lib' - - s.files = $__instiki_source_patterns.inject([]) { |list, glob| - list << Dir[glob].delete_if { |path| - File.directory?(path) or - path.include?('.svn/') or - path.include?('vendor/') or - path.include?('test/') or - path.include?('_test.rb') - } - }.flatten - -end +$__instiki_source_patterns = [ + '[A-Z]*', 'instiki', 'instiki.rb', 'app/**/*', 'lib/**/*', 'vendor/**/*', + 'public/**/*', 'natives/**/*', 'config/**/*', 'script/**/*' +] + +spec = Gem::Specification.new do |s| + s.platform = Gem::Platform::RUBY + s.name = 'instiki' + s.version = "0.10.2" + s.summary = 'Easy to install WikiClone running on WEBrick and SQLite' + s.description = <<-EOF + Instiki is a Wiki Clone written in Ruby that ships with an embedded + webserver. You can setup up an Instiki in just a few steps. + Possibly the simplest wiki setup ever. + EOF + s.author = 'David Heinemeier Hansson' + s.email = 'david@loudthinking.com' + s.rubyforge_project = 'instiki' + s.homepage = 'http://www.instiki.org' + + s.bindir = '.' + s.executables = ['instiki'] + s.default_executable = 'instiki' + + s.has_rdoc = false + + s.add_dependency('RedCloth', '= 3.0.3') + s.add_dependency('rubyzip', '= 0.5.8') + s.add_dependency('rails', '= 0.13.1') + s.add_dependency('sqlite3-ruby', '= 1.1.0') + s.requirements << 'none' + s.require_path = 'lib' + + s.files = $__instiki_source_patterns.inject([]) { |list, glob| + list << Dir[glob].delete_if { |path| + File.directory?(path) or + path.include?('.svn/') or + path.include?('vendor/') or + path.include?('test/') or + path.include?('_test.rb') + } + }.flatten + +end diff --git a/lib/db_structure.rb b/lib/db_structure.rb index 09c212da..d92bb4e4 100644 --- a/lib/db_structure.rb +++ b/lib/db_structure.rb @@ -1,46 +1,46 @@ -require 'erb' - -def create_options - if @db == 'mysql' - 'ENGINE = ' + (mysql_engine rescue @mysql_engine) - end -end - -def db_quote(column) - case @db - when 'postgresql' - return "\"#{column}\"" - when 'sqlite', 'sqlite3' - return "'#{column}'" - when 'mysql' - return "`#{column}`" - end -end - -def db_structure(db) - db.downcase! - @db = db - case db - when 'postgresql' - @pk = 'SERIAL PRIMARY KEY' - @datetime = 'TIMESTAMP' - @boolean = "BOOLEAN" - when 'sqlite', 'sqlite3' - @pk = 'INTEGER PRIMARY KEY' - @datetime = 'DATETIME' - @boolean = "INTEGER" - when 'mysql' - @pk = 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY' - @datetime = 'DATETIME' - @boolean = "TINYINT" - @mysql_engine = 'InnoDB' - else - raise "Unknown db type #{db}" - end - - s = '' - Dir[RAILS_ROOT + '/db/*.erbsql'].each do |filename| - s += ERB.new(File.read(filename)).result - end - s -end +require 'erb' + +def create_options + if @db == 'mysql' + 'ENGINE = ' + (mysql_engine rescue @mysql_engine) + end +end + +def db_quote(column) + case @db + when 'postgresql' + return "\"#{column}\"" + when 'sqlite', 'sqlite3' + return "'#{column}'" + when 'mysql' + return "`#{column}`" + end +end + +def db_structure(db) + db.downcase! + @db = db + case db + when 'postgresql' + @pk = 'SERIAL PRIMARY KEY' + @datetime = 'TIMESTAMP' + @boolean = "BOOLEAN" + when 'sqlite', 'sqlite3' + @pk = 'INTEGER PRIMARY KEY' + @datetime = 'DATETIME' + @boolean = "INTEGER" + when 'mysql' + @pk = 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY' + @datetime = 'DATETIME' + @boolean = "TINYINT" + @mysql_engine = 'InnoDB' + else + raise "Unknown db type #{db}" + end + + s = '' + Dir[RAILS_ROOT + '/db/*.erbsql'].each do |filename| + s += ERB.new(File.read(filename)).result + end + s +end diff --git a/test/fixtures/pages.yml b/test/fixtures/pages.yml index f7add425..65fba487 100644 --- a/test/fixtures/pages.yml +++ b/test/fixtures/pages.yml @@ -1,55 +1,55 @@ -home_page: - id: 1 - created_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> - updated_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> - web_id: 1 - name: HomePage - -my_way: - id: 2 - created_at: <%= 9.days.ago.to_formatted_s(:db) %> - updated_at: <%= 9.days.ago.to_formatted_s(:db) %> - web_id: 1 - name: MyWay - -smart_engine: - id: 3 - created_at: <%= 8.days.ago.to_formatted_s(:db) %> - updated_at: <%= 8.days.ago.to_formatted_s(:db) %> - web_id: 1 - name: SmartEngine - -that_way: - id: 4 - created_at: <%= 7.days.ago.to_formatted_s(:db) %> - updated_at: <%= 7.days.ago.to_formatted_s(:db) %> - web_id: 1 - name: ThatWay - -no_wiki_word: - id: 5 - created_at: <%= 6.days.ago.to_formatted_s(:db) %> - updated_at: <%= 6.days.ago.to_formatted_s(:db) %> - web_id: 1 - name: NoWikiWord - -first_page: - id: 6 - created_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> - updated_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> - web_id: 1 - name: FirstPage - -oak: - id: 7 - created_at: <%= 5.days.ago.to_formatted_s(:db) %> - updated_at: <%= 5.days.ago.to_formatted_s(:db) %> - web_id: 1 - name: Oak - -elephant: - id: 8 - created_at: <%= 10.minutes.ago.to_formatted_s(:db) %> - updated_at: <%= 10.minutes.ago.to_formatted_s(:db) %> - web_id: 1 +home_page: + id: 1 + created_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> + updated_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> + web_id: 1 + name: HomePage + +my_way: + id: 2 + created_at: <%= 9.days.ago.to_formatted_s(:db) %> + updated_at: <%= 9.days.ago.to_formatted_s(:db) %> + web_id: 1 + name: MyWay + +smart_engine: + id: 3 + created_at: <%= 8.days.ago.to_formatted_s(:db) %> + updated_at: <%= 8.days.ago.to_formatted_s(:db) %> + web_id: 1 + name: SmartEngine + +that_way: + id: 4 + created_at: <%= 7.days.ago.to_formatted_s(:db) %> + updated_at: <%= 7.days.ago.to_formatted_s(:db) %> + web_id: 1 + name: ThatWay + +no_wiki_word: + id: 5 + created_at: <%= 6.days.ago.to_formatted_s(:db) %> + updated_at: <%= 6.days.ago.to_formatted_s(:db) %> + web_id: 1 + name: NoWikiWord + +first_page: + id: 6 + created_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> + updated_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> + web_id: 1 + name: FirstPage + +oak: + id: 7 + created_at: <%= 5.days.ago.to_formatted_s(:db) %> + updated_at: <%= 5.days.ago.to_formatted_s(:db) %> + web_id: 1 + name: Oak + +elephant: + id: 8 + created_at: <%= 10.minutes.ago.to_formatted_s(:db) %> + updated_at: <%= 10.minutes.ago.to_formatted_s(:db) %> + web_id: 1 name: Elephant \ No newline at end of file diff --git a/test/fixtures/revisions.yml b/test/fixtures/revisions.yml index 77585e99..d65c2bd2 100644 --- a/test/fixtures/revisions.yml +++ b/test/fixtures/revisions.yml @@ -1,83 +1,83 @@ -home_page_first_revision: - id: 1 - created_at: <%= Time.local(2004, 4, 4, 15, 50).to_formatted_s(:db) %> - updated_at: <%= Time.local(2004, 4, 4, 15, 50).to_formatted_s(:db) %> - revised_at: <%= Time.local(2004, 4, 4, 15, 50).to_formatted_s(:db) %> - page_id: 1 - content: First revision of the HomePage end - author: AnAuthor - ip: 127.0.0.1 - -my_way_first_revision: - id: 2 - created_at: <%= 9.days.ago.to_formatted_s(:db) %> - updated_at: <%= 9.days.ago.to_formatted_s(:db) %> - revised_at: <%= 9.days.ago.to_formatted_s(:db) %> - page_id: 2 - content: MyWay - author: Me - -smart_engine_first_revision: - id: 3 - created_at: <%= 8.days.ago.to_formatted_s(:db) %> - updated_at: <%= 8.days.ago.to_formatted_s(:db) %> - revised_at: <%= 8.days.ago.to_formatted_s(:db) %> - page_id: 3 - content: SmartEngine - author: Me - -that_way_first_revision: - id: 4 - created_at: <%= 7.days.ago.to_formatted_s(:db) %> - updated_at: <%= 7.days.ago.to_formatted_s(:db) %> - revised_at: <%= 7.days.ago.to_formatted_s(:db) %> - page_id: 4 - content: ThatWay - author: Me - -no_wiki_word_first_revision: - id: 5 - created_at: <%= 6.days.ago.to_formatted_s(:db) %> - updated_at: <%= 6.days.ago.to_formatted_s(:db) %> - revised_at: <%= 6.days.ago.to_formatted_s(:db) %> - page_id: 5 - content: hey you - author: Me - -home_page_second_revision: - id: 6 - created_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> - updated_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> - revised_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> - page_id: 1 - content: HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \OverThere -- see SmartEngine in that SmartEngineGUI - author: DavidHeinemeierHansson - -first_page_first_revision: - id: 7 - created_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> - updated_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> - revised_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> - page_id: 6 - content: HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \\OverThere -- see SmartEngine in that SmartEngineGUI - author: DavidHeinemeierHansson - -oak_first_revision: - id: 8 - created_at: <%= 5.days.ago.to_formatted_s(:db) %> - updated_at: <%= 5.days.ago.to_formatted_s(:db) %> - revised_at: <%= 5.days.ago.to_formatted_s(:db) %> - page_id: 7 - content: "All about oak.\ncategory: trees" - author: TreeHugger - ip: 127.0.0.2 - -elephant_first_revision: - id: 9 - created_at: <%= 10.minutes.ago.to_formatted_s(:db) %> - updated_at: <%= 10.minutes.ago.to_formatted_s(:db) %> - revised_at: <%= 10.minutes.ago.to_formatted_s(:db) %> - page_id: 8 - content: "All about elephants.\ncategory: animals" - author: Guest - ip: 127.0.0.2 +home_page_first_revision: + id: 1 + created_at: <%= Time.local(2004, 4, 4, 15, 50).to_formatted_s(:db) %> + updated_at: <%= Time.local(2004, 4, 4, 15, 50).to_formatted_s(:db) %> + revised_at: <%= Time.local(2004, 4, 4, 15, 50).to_formatted_s(:db) %> + page_id: 1 + content: First revision of the HomePage end + author: AnAuthor + ip: 127.0.0.1 + +my_way_first_revision: + id: 2 + created_at: <%= 9.days.ago.to_formatted_s(:db) %> + updated_at: <%= 9.days.ago.to_formatted_s(:db) %> + revised_at: <%= 9.days.ago.to_formatted_s(:db) %> + page_id: 2 + content: MyWay + author: Me + +smart_engine_first_revision: + id: 3 + created_at: <%= 8.days.ago.to_formatted_s(:db) %> + updated_at: <%= 8.days.ago.to_formatted_s(:db) %> + revised_at: <%= 8.days.ago.to_formatted_s(:db) %> + page_id: 3 + content: SmartEngine + author: Me + +that_way_first_revision: + id: 4 + created_at: <%= 7.days.ago.to_formatted_s(:db) %> + updated_at: <%= 7.days.ago.to_formatted_s(:db) %> + revised_at: <%= 7.days.ago.to_formatted_s(:db) %> + page_id: 4 + content: ThatWay + author: Me + +no_wiki_word_first_revision: + id: 5 + created_at: <%= 6.days.ago.to_formatted_s(:db) %> + updated_at: <%= 6.days.ago.to_formatted_s(:db) %> + revised_at: <%= 6.days.ago.to_formatted_s(:db) %> + page_id: 5 + content: hey you + author: Me + +home_page_second_revision: + id: 6 + created_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> + updated_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> + revised_at: <%= Time.local(2004, 4, 4, 16, 50).to_formatted_s(:db) %> + page_id: 1 + content: HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \OverThere -- see SmartEngine in that SmartEngineGUI + author: DavidHeinemeierHansson + +first_page_first_revision: + id: 7 + created_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> + updated_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> + revised_at: <%= Time.local(2004, 4, 4, 16, 55).to_formatted_s(:db) %> + page_id: 6 + content: HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \\OverThere -- see SmartEngine in that SmartEngineGUI + author: DavidHeinemeierHansson + +oak_first_revision: + id: 8 + created_at: <%= 5.days.ago.to_formatted_s(:db) %> + updated_at: <%= 5.days.ago.to_formatted_s(:db) %> + revised_at: <%= 5.days.ago.to_formatted_s(:db) %> + page_id: 7 + content: "All about oak.\ncategory: trees" + author: TreeHugger + ip: 127.0.0.2 + +elephant_first_revision: + id: 9 + created_at: <%= 10.minutes.ago.to_formatted_s(:db) %> + updated_at: <%= 10.minutes.ago.to_formatted_s(:db) %> + revised_at: <%= 10.minutes.ago.to_formatted_s(:db) %> + page_id: 8 + content: "All about elephants.\ncategory: animals" + author: Guest + ip: 127.0.0.2 diff --git a/test/fixtures/webs.yml b/test/fixtures/webs.yml index 29c89566..05437295 100644 --- a/test/fixtures/webs.yml +++ b/test/fixtures/webs.yml @@ -1,15 +1,15 @@ -test_wiki: - id: 1 - created_at: 2004-08-01 - updated_at: 2005-08-01 - name: wiki1 - address: wiki1 - markup: textile - -instiki: - id: 2 - created_at: 2004-08-01 - updated_at: 2005-08-01 - name: Instiki - address: instiki +test_wiki: + id: 1 + created_at: 2004-08-01 + updated_at: 2005-08-01 + name: wiki1 + address: wiki1 + markup: textile + +instiki: + id: 2 + created_at: 2004-08-01 + updated_at: 2005-08-01 + name: Instiki + address: instiki markup: textile \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index 0b29f757..955b059e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,106 +1,106 @@ -ENV["RAILS_ENV"] = "test" - -# Expand the path to environment so that Ruby does not load it multiple times -# File.expand_path can be removed if Ruby 1.9 is in use. -require File.expand_path(File.dirname(__FILE__) + "/../config/environment") -require 'application' - -require 'test/unit' -require 'active_record/fixtures' -require 'action_controller/test_process' -require 'action_web_service/test_invoke' -require 'breakpoint' -require 'wiki_content' - -# Uncomment these and hang on, because the tests will be FAST -#Test::Unit::TestCase.pre_loaded_fixtures = false -#Test::Unit::TestCase.use_transactional_fixtures = true - -Test::Unit::TestCase.use_instantiated_fixtures = false -Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/" - -class Test::Unit::TestCase - def create_fixtures(*table_names) - Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures", table_names) - end - - # Add more helper methods to be used by all tests here... - def set_web_property(property, value) - @web.update_attribute(property, value) - @page = Page.find(@page.id) - @wiki.webs[@web.name] = @web - end - - def setup_wiki_with_30_pages - ActiveRecord::Base.silence do - (1..30).each do |i| - @wiki.write_page('wiki1', "page#{i}", "Test page #{i}\ncategory: test", - Time.local(1976, 10, i, 12, 00, 00), Author.new('Dema', '127.0.0.2')) - end - end - @web = Web.find(@web.id) - end - - def use_blank_wiki - Revision.destroy_all - Page.destroy_all - Web.destroy_all - end -end - -# This module is to be included in unit tests that involve matching chunks. -# It provides a easy way to test whether a chunk matches a particular string -# and any the values of any fields that should be set after a match. -class ContentStub < String - include ChunkManager - def initialize(str) - super - init_chunk_manager - end - def page_link(*); end -end - -module ChunkMatch - - # Asserts a number of tests for the given type and text. - def match(chunk_type, test_text, expected_chunk_state) - if chunk_type.respond_to? :pattern - assert_match(chunk_type.pattern, test_text) - end - - content = ContentStub.new(test_text) - chunk_type.apply_to(content) - - # Test if requested parts are correct. - expected_chunk_state.each_pair do |a_method, expected_value| - assert content.chunks.last.kind_of?(chunk_type) - assert_respond_to(content.chunks.last, a_method) - assert_equal(expected_value, content.chunks.last.send(a_method.to_sym), - "Wrong #{a_method} value") - end - end - - # Asserts that test_text doesn't match the chunk_type - def no_match(chunk_type, test_text) - if chunk_type.respond_to? :pattern - assert_no_match(chunk_type.pattern, test_text) - end - end -end - -if defined? $validate_xml_in_assert_success and $validate_xml_in_assert_success == true - module Test - module Unit - module Assertions - unless method_defined? :__assert_success_before_override_by_instiki - alias :__assert_success_before_override_by_instiki :assert_success - end - def assert_success - __assert_success_before_override_by_instiki - if @response.body.kind_of?(Proc) then # it's a file download, not an HTML content - else assert_nothing_raised(@response.body) { REXML::Document.new(@response.body) } end - end - end - end - end -end +ENV["RAILS_ENV"] = "test" + +# Expand the path to environment so that Ruby does not load it multiple times +# File.expand_path can be removed if Ruby 1.9 is in use. +require File.expand_path(File.dirname(__FILE__) + "/../config/environment") +require 'application' + +require 'test/unit' +require 'active_record/fixtures' +require 'action_controller/test_process' +require 'action_web_service/test_invoke' +require 'breakpoint' +require 'wiki_content' + +# Uncomment these and hang on, because the tests will be FAST +#Test::Unit::TestCase.pre_loaded_fixtures = false +#Test::Unit::TestCase.use_transactional_fixtures = true + +Test::Unit::TestCase.use_instantiated_fixtures = false +Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/" + +class Test::Unit::TestCase + def create_fixtures(*table_names) + Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures", table_names) + end + + # Add more helper methods to be used by all tests here... + def set_web_property(property, value) + @web.update_attribute(property, value) + @page = Page.find(@page.id) + @wiki.webs[@web.name] = @web + end + + def setup_wiki_with_30_pages + ActiveRecord::Base.silence do + (1..30).each do |i| + @wiki.write_page('wiki1', "page#{i}", "Test page #{i}\ncategory: test", + Time.local(1976, 10, i, 12, 00, 00), Author.new('Dema', '127.0.0.2')) + end + end + @web = Web.find(@web.id) + end + + def use_blank_wiki + Revision.destroy_all + Page.destroy_all + Web.destroy_all + end +end + +# This module is to be included in unit tests that involve matching chunks. +# It provides a easy way to test whether a chunk matches a particular string +# and any the values of any fields that should be set after a match. +class ContentStub < String + include ChunkManager + def initialize(str) + super + init_chunk_manager + end + def page_link(*); end +end + +module ChunkMatch + + # Asserts a number of tests for the given type and text. + def match(chunk_type, test_text, expected_chunk_state) + if chunk_type.respond_to? :pattern + assert_match(chunk_type.pattern, test_text) + end + + content = ContentStub.new(test_text) + chunk_type.apply_to(content) + + # Test if requested parts are correct. + expected_chunk_state.each_pair do |a_method, expected_value| + assert content.chunks.last.kind_of?(chunk_type) + assert_respond_to(content.chunks.last, a_method) + assert_equal(expected_value, content.chunks.last.send(a_method.to_sym), + "Wrong #{a_method} value") + end + end + + # Asserts that test_text doesn't match the chunk_type + def no_match(chunk_type, test_text) + if chunk_type.respond_to? :pattern + assert_no_match(chunk_type.pattern, test_text) + end + end +end + +if defined? $validate_xml_in_assert_success and $validate_xml_in_assert_success == true + module Test + module Unit + module Assertions + unless method_defined? :__assert_success_before_override_by_instiki + alias :__assert_success_before_override_by_instiki :assert_success + end + def assert_success + __assert_success_before_override_by_instiki + if @response.body.kind_of?(Proc) then # it's a file download, not an HTML content + else assert_nothing_raised(@response.body) { REXML::Document.new(@response.body) } end + end + end + end + end +end diff --git a/test/unit/page_test.rb b/test/unit/page_test.rb index 4f75d872..b3568271 100644 --- a/test/unit/page_test.rb +++ b/test/unit/page_test.rb @@ -1,88 +1,88 @@ -require File.expand_path(File.dirname(__FILE__) + '/../test_helper') - -class PageTest < Test::Unit::TestCase - fixtures :webs, :pages, :revisions, :system - - def setup - @page = pages(:first_page) - end - - def test_lock - assert !@page.locked?(Time.local(2004, 4, 4, 16, 50)) - - @page.lock(Time.local(2004, 4, 4, 16, 30), "DavidHeinemeierHansson") - - assert @page.locked?(Time.local(2004, 4, 4, 16, 50)) - assert !@page.locked?(Time.local(2004, 4, 4, 17, 1)) - - @page.unlock - - assert !@page.locked?(Time.local(2004, 4, 4, 16, 50)) - end - - def test_lock_duration - @page.lock(Time.local(2004, 4, 4, 16, 30), "DavidHeinemeierHansson") - - assert_equal 15, @page.lock_duration(Time.local(2004, 4, 4, 16, 45)) - end - - def test_plain_name - assert_equal "First Page", @page.plain_name - end - - def test_revise - @page.revise('HisWay would be MyWay in kinda lame', Time.local(2004, 4, 4, 16, 55), 'MarianneSyhler') - @page.reload - - assert_equal 2, @page.revisions.length, 'Should have two revisions' - assert_equal 'MarianneSyhler', @page.current_revision.author.to_s, 'Mary should be the author now' - assert_equal 'DavidHeinemeierHansson', @page.revisions.first.author.to_s, 'David was the first author' - end - - def test_revise_continous_revision - @page.revise('HisWay would be MyWay in kinda lame', Time.local(2004, 4, 4, 16, 55), 'MarianneSyhler') - @page.reload - assert_equal 2, @page.revisions.length - assert_equal 'HisWay would be MyWay in kinda lame', @page.content - - # consecutive revision by the same author within 30 minutes doesn't create a new revision - @page.revise('HisWay would be MyWay in kinda update', Time.local(2004, 4, 4, 16, 57), 'MarianneSyhler') - @page.reload - assert_equal 2, @page.revisions.length - assert_equal 'HisWay would be MyWay in kinda update', @page.content - assert_equal Time.local(2004, 4, 4, 16, 57), @page.revised_at - - # but consecutive revision by another author results in a new revision - @page.revise('HisWay would be MyWay in the house', Time.local(2004, 4, 4, 16, 58), 'DavidHeinemeierHansson') - @page.reload - assert_equal 3, @page.revisions.length - assert_equal 'HisWay would be MyWay in the house', @page.content - - # consecutive update after 30 minutes since the last one also creates a new revision, - # even when it is by the same author - @page.revise('HisWay would be MyWay in my way', Time.local(2004, 4, 4, 17, 30), 'DavidHeinemeierHansson') - @page.reload - assert_equal 4, @page.revisions.length - end - - def test_revise_content_unchanged - last_revision_before = @page.current_revision - revisions_number_before = @page.revisions.size - - assert_raises(Instiki::ValidationError) { - @page.revise(@page.current_revision.content, Time.now, 'AlexeyVerkhovsky') - } - - assert_equal last_revision_before, @page.current_revision(true) - assert_equal revisions_number_before, @page.revisions.size - end - - def test_rollback - @page.revise("spot two", Time.now, "David") - @page.revise("spot three", Time.now + 2000, "David") - assert_equal 3, @page.revisions(true).length, "Should have three revisions" - @page.current_revision(true) - @page.rollback(0, Time.now) - assert_equal "HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \\\\OverThere -- see SmartEngine in that SmartEngineGUI", @page.current_revision(true).content - end -end +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') + +class PageTest < Test::Unit::TestCase + fixtures :webs, :pages, :revisions, :system + + def setup + @page = pages(:first_page) + end + + def test_lock + assert !@page.locked?(Time.local(2004, 4, 4, 16, 50)) + + @page.lock(Time.local(2004, 4, 4, 16, 30), "DavidHeinemeierHansson") + + assert @page.locked?(Time.local(2004, 4, 4, 16, 50)) + assert !@page.locked?(Time.local(2004, 4, 4, 17, 1)) + + @page.unlock + + assert !@page.locked?(Time.local(2004, 4, 4, 16, 50)) + end + + def test_lock_duration + @page.lock(Time.local(2004, 4, 4, 16, 30), "DavidHeinemeierHansson") + + assert_equal 15, @page.lock_duration(Time.local(2004, 4, 4, 16, 45)) + end + + def test_plain_name + assert_equal "First Page", @page.plain_name + end + + def test_revise + @page.revise('HisWay would be MyWay in kinda lame', Time.local(2004, 4, 4, 16, 55), 'MarianneSyhler') + @page.reload + + assert_equal 2, @page.revisions.length, 'Should have two revisions' + assert_equal 'MarianneSyhler', @page.current_revision.author.to_s, 'Mary should be the author now' + assert_equal 'DavidHeinemeierHansson', @page.revisions.first.author.to_s, 'David was the first author' + end + + def test_revise_continous_revision + @page.revise('HisWay would be MyWay in kinda lame', Time.local(2004, 4, 4, 16, 55), 'MarianneSyhler') + @page.reload + assert_equal 2, @page.revisions.length + assert_equal 'HisWay would be MyWay in kinda lame', @page.content + + # consecutive revision by the same author within 30 minutes doesn't create a new revision + @page.revise('HisWay would be MyWay in kinda update', Time.local(2004, 4, 4, 16, 57), 'MarianneSyhler') + @page.reload + assert_equal 2, @page.revisions.length + assert_equal 'HisWay would be MyWay in kinda update', @page.content + assert_equal Time.local(2004, 4, 4, 16, 57), @page.revised_at + + # but consecutive revision by another author results in a new revision + @page.revise('HisWay would be MyWay in the house', Time.local(2004, 4, 4, 16, 58), 'DavidHeinemeierHansson') + @page.reload + assert_equal 3, @page.revisions.length + assert_equal 'HisWay would be MyWay in the house', @page.content + + # consecutive update after 30 minutes since the last one also creates a new revision, + # even when it is by the same author + @page.revise('HisWay would be MyWay in my way', Time.local(2004, 4, 4, 17, 30), 'DavidHeinemeierHansson') + @page.reload + assert_equal 4, @page.revisions.length + end + + def test_revise_content_unchanged + last_revision_before = @page.current_revision + revisions_number_before = @page.revisions.size + + assert_raises(Instiki::ValidationError) { + @page.revise(@page.current_revision.content, Time.now, 'AlexeyVerkhovsky') + } + + assert_equal last_revision_before, @page.current_revision(true) + assert_equal revisions_number_before, @page.revisions.size + end + + def test_rollback + @page.revise("spot two", Time.now, "David") + @page.revise("spot three", Time.now + 2000, "David") + assert_equal 3, @page.revisions(true).length, "Should have three revisions" + @page.current_revision(true) + @page.rollback(0, Time.now) + assert_equal "HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \\\\OverThere -- see SmartEngine in that SmartEngineGUI", @page.current_revision(true).content + end +end diff --git a/test/unit/revision_test.rb b/test/unit/revision_test.rb index d563ccde..f22bfd5d 100644 --- a/test/unit/revision_test.rb +++ b/test/unit/revision_test.rb @@ -1,317 +1,317 @@ -require File.expand_path(File.dirname(__FILE__) + '/../test_helper') - -class RevisionTest < Test::Unit::TestCase - fixtures :webs, :pages, :revisions, :system - - def setup - @wiki = Wiki.new - @web = webs(:test_wiki) - @page = pages(:home_page) - @revision = revisions(:home_page_second_revision) - end - - def test_wiki_words - assert_equal %w( HisWay MyWay SmartEngine SmartEngineGUI ThatWay ), @revision.wiki_words.sort - - @wiki.write_page('wiki1', 'NoWikiWord', 'hey you!', Time.now, 'Me') - assert_equal [], @wiki.read_page('wiki1', 'NoWikiWord').wiki_words - end - - def test_existing_pages - assert_equal %w( MyWay SmartEngine ThatWay ), @revision.existing_pages.sort - end - - def test_unexisting_pages - assert_equal %w( HisWay SmartEngineGUI ), @revision.unexisting_pages.sort - end - - def test_content_with_wiki_links - assert_equal '

His Way? ' + - 'would be My Way in kinda ' + - 'That Way in ' + - 'His Way? ' + - 'though My Way OverThere—see ' + - 'Smart Engine in that ' + - 'Smart Engine GUI' + - '?

', - @revision.display_content - end - - def test_markdown - set_web_property :markup, :markdown - - assert_markup_parsed_as( - %{

My Headline

\n\n

that } + - %{Smart Engine GUI?

}, - "My Headline\n===========\n\nthat SmartEngineGUI") - - code_block = [ - 'This is a code block:', - '', - ' def a_method(arg)', - ' return ThatWay', - '', - 'Nice!' - ].join("\n") - - assert_markup_parsed_as( - %{

This is a code block:

\n\n
def a_method(arg)\n} +
-        %{return ThatWay\n
\n\n

Nice!

}, - code_block) - end - - def test_markdown_hyperlink_with_slash - # in response to a bug, see http://dev.instiki.org/attachment/ticket/177 - set_web_property :markup, :markdown - - assert_markup_parsed_as( - '

text

', - '[text](http://example/with/slash)') - end - - def test_mixed_formatting - textile_and_markdown = [ - 'Markdown heading', - '================', - '', - 'h2. Textile heading', - '', - '*some* **text** _with_ -styles-', - '', - '* list 1', - '* list 2' - ].join("\n") - - set_web_property :markup, :markdown - assert_markup_parsed_as( - "

Markdown heading

\n\n" + - "

h2. Textile heading

\n\n" + - "

some text with -styles-

\n\n" + - "
    \n
  • list 1
  • \n
  • list 2
  • \n
", - textile_and_markdown) - - set_web_property :markup, :textile - assert_markup_parsed_as( - "

Markdown heading
================

\n\n\n\t

Textile heading

" + - "\n\n\n\t

some text with styles

" + - "\n\n\n\t
    \n\t
  • list 1
  • \n\t\t
  • list 2
  • \n\t
", - textile_and_markdown) - - set_web_property :markup, :mixed - assert_markup_parsed_as( - "

Markdown heading

\n\n\n\t

Textile heading

\n\n\n\t" + - "

some text with styles

\n\n\n\t" + - "
    \n\t
  • list 1
  • \n\t\t
  • list 2
  • \n\t
", - textile_and_markdown) - end - - def test_rdoc - set_web_property :markup, :rdoc - - @revision = Revision.new(:page => @page, :content => '+hello+ that SmartEngineGUI', - :author => Author.new('DavidHeinemeierHansson')) - - assert_equal "hello that Smart Engine GUI" + - "?\n\n", @revision.display_content - end - - def test_content_with_auto_links - assert_markup_parsed_as( - '

http://www.loudthinking.com/ ' + - 'points to That Way from ' + - 'david@loudthinking.com

', - 'http://www.loudthinking.com/ points to ThatWay from david@loudthinking.com') - - end - - def test_content_with_aliased_links - assert_markup_parsed_as( - '

Would a clever motor' + - ' go by any other name?

', - 'Would a [[SmartEngine|clever motor]] go by any other name?') - end - - def test_content_with_wikiword_in_em - assert_markup_parsed_as( - '

should we go ' + - 'That Way or This Way?' + - '

', - '_should we go ThatWay or ThisWay _') - end - - def test_content_with_wikiword_in_tag - assert_markup_parsed_as( - '

That is some Stylish Emphasis

', - 'That is some Stylish Emphasis') - end - - def test_content_with_escaped_wikiword - # there should be no wiki link - assert_markup_parsed_as('

WikiWord

', '\WikiWord') - end - - def test_content_with_pre_blocks - assert_markup_parsed_as( - '

A class SmartEngine end would not mark up

CodeBlocks

', - 'A class SmartEngine end would not mark up
CodeBlocks
') - end - - def test_content_with_autolink_in_parentheses - assert_markup_parsed_as( - '

The W3C body (' + - 'http://www.w3c.org) sets web standards

', - 'The W3C body (http://www.w3c.org) sets web standards') - end - - def test_content_with_link_in_parentheses - assert_markup_parsed_as( - '

(What is a wiki?)

', - '("What is a wiki?":http://wiki.org/wiki.cgi?WhatIsWiki)') - end - - def test_content_with_image_link - assert_markup_parsed_as( - '

This is a Textile image link.

', - 'This !http://hobix.com/sample.jpg! is a Textile image link.') - end - - def test_content_with_inlined_img_tag - assert_markup_parsed_as( - '

This is an inline image link.

', - 'This is an inline image link.') - - assert_markup_parsed_as( - '

This is an inline image link.

', - 'This is an inline image link.') - end - - def test_nowiki_tag - assert_markup_parsed_as( - '

Do not mark up [[this text]] or http://www.thislink.com.

', - 'Do not mark up [[this text]] ' + - 'or http://www.thislink.com.') - end - - def test_multiline_nowiki_tag - assert_markup_parsed_as( - "

Do not mark \n up [[this text]] \nand http://this.url.com but markup " + - 'this?

', - "Do not mark \n up [[this text]] \n" + - "and http://this.url.com but markup [[this]]") - end - - def test_content_with_bracketted_wiki_word - set_web_property :brackets_only, true - assert_markup_parsed_as( - '

This is a WikiWord and a tricky name ' + - 'Sperberg-McQueen?.

', - 'This is a WikiWord and a tricky name [[Sperberg-McQueen]].') - end - - def test_content_for_export - assert_equal '

His Way would be ' + - 'My Way in kinda ' + - 'That Way in ' + - 'His Way though ' + - 'My Way OverThere—see ' + - 'Smart Engine in that ' + - 'Smart Engine GUI

', - @revision.display_content_for_export - end - - def test_double_replacing - @revision.content = "VersionHistory\r\n\r\ncry VersionHistory" - assert_equal '

Version History' + - "?

\n\n\n\t

cry " + - 'Version History?' + - '

', - @revision.display_content - - @revision.clear_display_cache - - @revision.content = "f\r\nVersionHistory\r\n\r\ncry VersionHistory" - assert_equal "

f
Version History" + - "?

\n\n\n\t

cry " + - "Version History?" + - "

", - @revision.display_content - end - - def test_difficult_wiki_words - @revision.content = "[[It's just awesome GUI!]]" - assert_equal "

It's just awesome GUI!" + - "?

", - @revision.display_content - end - - def test_revisions_diff - Revision.create(:page => @page, :content => 'What a blue and lovely morning', - :author => Author.new('DavidHeinemeierHansson'), :revised_at => Time.now) - Revision.create(:page => @page, :content => 'What a red and lovely morning today', - :author => Author.new('DavidHeinemeierHansson'), :revised_at => Time.now) - - assert_equal "

What a blue red " + - "and lovely morningmorning " + - "today

", @page.revisions.last.display_diff - end - - def test_link_to_file - assert_markup_parsed_as( - '

doc.pdf?

', - '[[doc.pdf:file]]') - end - - def test_link_to_pic - FileUtils.mkdir_p "#{RAILS_ROOT}/storage/test/wiki1" - FileUtils.rm(Dir["#{RAILS_ROOT}/storage/test/wiki1/*"]) - @wiki.file_yard(@web).upload_file('square.jpg', StringIO.new('')) - assert_markup_parsed_as( - '

Square

', - '[[square.jpg|Square:pic]]') - assert_markup_parsed_as( - '

square.jpg

', - '[[square.jpg:pic]]') - end - - def test_link_to_non_existant_pic - assert_markup_parsed_as( - '

NonExistant?' + - '

', - '[[NonExistant.jpg|NonExistant:pic]]') - assert_markup_parsed_as( - '

NonExistant.jpg?' + - '

', - '[[NonExistant.jpg:pic]]') - end - - def test_wiki_link_with_colon - assert_markup_parsed_as( - '

With:Colon?

', - '[[With:Colon]]') - end - - # TODO Remove the leading underscores from this test when upgrading to RedCloth 3.0.1; - # also add a test for the "Unhappy Face" problem (another interesting RedCloth bug) - def test_list_with_tildas - list_with_tildas = <<-EOL - * "a":~b - * c~ d - EOL - - assert_markup_parsed_as( - "
    \n\t
  • a
  • \n\t\t
  • c~ d
  • \n\t
", - list_with_tildas) - end - - def test_textile_image_in_mixed_wiki - set_web_property :markup, :mixed - assert_markup_parsed_as( - "

\"\"\nss

", - "!http://google.com!\r\nss") - end - - def assert_markup_parsed_as(expected_output, input) - revision = Revision.new(:page => @page, :content => input, :author => Author.new('AnAuthor')) - assert_equal expected_output, revision.display_content, 'Textile output not as expected' - end -end +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') + +class RevisionTest < Test::Unit::TestCase + fixtures :webs, :pages, :revisions, :system + + def setup + @wiki = Wiki.new + @web = webs(:test_wiki) + @page = pages(:home_page) + @revision = revisions(:home_page_second_revision) + end + + def test_wiki_words + assert_equal %w( HisWay MyWay SmartEngine SmartEngineGUI ThatWay ), @revision.wiki_words.sort + + @wiki.write_page('wiki1', 'NoWikiWord', 'hey you!', Time.now, 'Me') + assert_equal [], @wiki.read_page('wiki1', 'NoWikiWord').wiki_words + end + + def test_existing_pages + assert_equal %w( MyWay SmartEngine ThatWay ), @revision.existing_pages.sort + end + + def test_unexisting_pages + assert_equal %w( HisWay SmartEngineGUI ), @revision.unexisting_pages.sort + end + + def test_content_with_wiki_links + assert_equal '

His Way? ' + + 'would be My Way in kinda ' + + 'That Way in ' + + 'His Way? ' + + 'though My Way OverThere—see ' + + 'Smart Engine in that ' + + 'Smart Engine GUI' + + '?

', + @revision.display_content + end + + def test_markdown + set_web_property :markup, :markdown + + assert_markup_parsed_as( + %{

My Headline

\n\n

that } + + %{Smart Engine GUI?

}, + "My Headline\n===========\n\nthat SmartEngineGUI") + + code_block = [ + 'This is a code block:', + '', + ' def a_method(arg)', + ' return ThatWay', + '', + 'Nice!' + ].join("\n") + + assert_markup_parsed_as( + %{

This is a code block:

\n\n
def a_method(arg)\n} +
+        %{return ThatWay\n
\n\n

Nice!

}, + code_block) + end + + def test_markdown_hyperlink_with_slash + # in response to a bug, see http://dev.instiki.org/attachment/ticket/177 + set_web_property :markup, :markdown + + assert_markup_parsed_as( + '

text

', + '[text](http://example/with/slash)') + end + + def test_mixed_formatting + textile_and_markdown = [ + 'Markdown heading', + '================', + '', + 'h2. Textile heading', + '', + '*some* **text** _with_ -styles-', + '', + '* list 1', + '* list 2' + ].join("\n") + + set_web_property :markup, :markdown + assert_markup_parsed_as( + "

Markdown heading

\n\n" + + "

h2. Textile heading

\n\n" + + "

some text with -styles-

\n\n" + + "
    \n
  • list 1
  • \n
  • list 2
  • \n
", + textile_and_markdown) + + set_web_property :markup, :textile + assert_markup_parsed_as( + "

Markdown heading
================

\n\n\n\t

Textile heading

" + + "\n\n\n\t

some text with styles

" + + "\n\n\n\t
    \n\t
  • list 1
  • \n\t\t
  • list 2
  • \n\t
", + textile_and_markdown) + + set_web_property :markup, :mixed + assert_markup_parsed_as( + "

Markdown heading

\n\n\n\t

Textile heading

\n\n\n\t" + + "

some text with styles

\n\n\n\t" + + "
    \n\t
  • list 1
  • \n\t\t
  • list 2
  • \n\t
", + textile_and_markdown) + end + + def test_rdoc + set_web_property :markup, :rdoc + + @revision = Revision.new(:page => @page, :content => '+hello+ that SmartEngineGUI', + :author => Author.new('DavidHeinemeierHansson')) + + assert_equal "hello that Smart Engine GUI" + + "?\n\n", @revision.display_content + end + + def test_content_with_auto_links + assert_markup_parsed_as( + '

http://www.loudthinking.com/ ' + + 'points to That Way from ' + + 'david@loudthinking.com

', + 'http://www.loudthinking.com/ points to ThatWay from david@loudthinking.com') + + end + + def test_content_with_aliased_links + assert_markup_parsed_as( + '

Would a clever motor' + + ' go by any other name?

', + 'Would a [[SmartEngine|clever motor]] go by any other name?') + end + + def test_content_with_wikiword_in_em + assert_markup_parsed_as( + '

should we go ' + + 'That Way or This Way?' + + '

', + '_should we go ThatWay or ThisWay _') + end + + def test_content_with_wikiword_in_tag + assert_markup_parsed_as( + '

That is some Stylish Emphasis

', + 'That is some Stylish Emphasis') + end + + def test_content_with_escaped_wikiword + # there should be no wiki link + assert_markup_parsed_as('

WikiWord

', '\WikiWord') + end + + def test_content_with_pre_blocks + assert_markup_parsed_as( + '

A class SmartEngine end would not mark up

CodeBlocks

', + 'A class SmartEngine end would not mark up
CodeBlocks
') + end + + def test_content_with_autolink_in_parentheses + assert_markup_parsed_as( + '

The W3C body (' + + 'http://www.w3c.org) sets web standards

', + 'The W3C body (http://www.w3c.org) sets web standards') + end + + def test_content_with_link_in_parentheses + assert_markup_parsed_as( + '

(What is a wiki?)

', + '("What is a wiki?":http://wiki.org/wiki.cgi?WhatIsWiki)') + end + + def test_content_with_image_link + assert_markup_parsed_as( + '

This is a Textile image link.

', + 'This !http://hobix.com/sample.jpg! is a Textile image link.') + end + + def test_content_with_inlined_img_tag + assert_markup_parsed_as( + '

This is an inline image link.

', + 'This is an inline image link.') + + assert_markup_parsed_as( + '

This is an inline image link.

', + 'This is an inline image link.') + end + + def test_nowiki_tag + assert_markup_parsed_as( + '

Do not mark up [[this text]] or http://www.thislink.com.

', + 'Do not mark up [[this text]] ' + + 'or http://www.thislink.com.') + end + + def test_multiline_nowiki_tag + assert_markup_parsed_as( + "

Do not mark \n up [[this text]] \nand http://this.url.com but markup " + + 'this?

', + "Do not mark \n up [[this text]] \n" + + "and http://this.url.com but markup [[this]]") + end + + def test_content_with_bracketted_wiki_word + set_web_property :brackets_only, true + assert_markup_parsed_as( + '

This is a WikiWord and a tricky name ' + + 'Sperberg-McQueen?.

', + 'This is a WikiWord and a tricky name [[Sperberg-McQueen]].') + end + + def test_content_for_export + assert_equal '

His Way would be ' + + 'My Way in kinda ' + + 'That Way in ' + + 'His Way though ' + + 'My Way OverThere—see ' + + 'Smart Engine in that ' + + 'Smart Engine GUI

', + @revision.display_content_for_export + end + + def test_double_replacing + @revision.content = "VersionHistory\r\n\r\ncry VersionHistory" + assert_equal '

Version History' + + "?

\n\n\n\t

cry " + + 'Version History?' + + '

', + @revision.display_content + + @revision.clear_display_cache + + @revision.content = "f\r\nVersionHistory\r\n\r\ncry VersionHistory" + assert_equal "

f
Version History" + + "?

\n\n\n\t

cry " + + "Version History?" + + "

", + @revision.display_content + end + + def test_difficult_wiki_words + @revision.content = "[[It's just awesome GUI!]]" + assert_equal "

It's just awesome GUI!" + + "?

", + @revision.display_content + end + + def test_revisions_diff + Revision.create(:page => @page, :content => 'What a blue and lovely morning', + :author => Author.new('DavidHeinemeierHansson'), :revised_at => Time.now) + Revision.create(:page => @page, :content => 'What a red and lovely morning today', + :author => Author.new('DavidHeinemeierHansson'), :revised_at => Time.now) + + assert_equal "

What a blue red " + + "and lovely morningmorning " + + "today

", @page.revisions.last.display_diff + end + + def test_link_to_file + assert_markup_parsed_as( + '

doc.pdf?

', + '[[doc.pdf:file]]') + end + + def test_link_to_pic + FileUtils.mkdir_p "#{RAILS_ROOT}/storage/test/wiki1" + FileUtils.rm(Dir["#{RAILS_ROOT}/storage/test/wiki1/*"]) + @wiki.file_yard(@web).upload_file('square.jpg', StringIO.new('')) + assert_markup_parsed_as( + '

Square

', + '[[square.jpg|Square:pic]]') + assert_markup_parsed_as( + '

square.jpg

', + '[[square.jpg:pic]]') + end + + def test_link_to_non_existant_pic + assert_markup_parsed_as( + '

NonExistant?' + + '

', + '[[NonExistant.jpg|NonExistant:pic]]') + assert_markup_parsed_as( + '

NonExistant.jpg?' + + '

', + '[[NonExistant.jpg:pic]]') + end + + def test_wiki_link_with_colon + assert_markup_parsed_as( + '

With:Colon?

', + '[[With:Colon]]') + end + + # TODO Remove the leading underscores from this test when upgrading to RedCloth 3.0.1; + # also add a test for the "Unhappy Face" problem (another interesting RedCloth bug) + def test_list_with_tildas + list_with_tildas = <<-EOL + * "a":~b + * c~ d + EOL + + assert_markup_parsed_as( + "
    \n\t
  • a
  • \n\t\t
  • c~ d
  • \n\t
", + list_with_tildas) + end + + def test_textile_image_in_mixed_wiki + set_web_property :markup, :mixed + assert_markup_parsed_as( + "

\"\"\nss

", + "!http://google.com!\r\nss") + end + + def assert_markup_parsed_as(expected_output, input) + revision = Revision.new(:page => @page, :content => input, :author => Author.new('AnAuthor')) + assert_equal expected_output, revision.display_content, 'Textile output not as expected' + end +end diff --git a/test/unit/web_test.rb b/test/unit/web_test.rb index 433b579f..7e91bbed 100644 --- a/test/unit/web_test.rb +++ b/test/unit/web_test.rb @@ -1,158 +1,158 @@ -require File.expand_path(File.dirname(__FILE__) + '/../test_helper') - -class WebTest < Test::Unit::TestCase - fixtures :webs, :pages, :revisions, :system - - def setup - @web = webs(:instiki) - end - - def test_wiki_word_linking - @web.add_page('SecondPage', 'Yo, yo. Have you EverBeenHated', - Time.now, 'DavidHeinemeierHansson') - - assert_equal('

Yo, yo. Have you Ever Been Hated' + - '?

', - @web.page("SecondPage").display_content) - - @web.add_page('EverBeenHated', 'Yo, yo. Have you EverBeenHated', Time.now, - 'DavidHeinemeierHansson') - assert_equal('

Yo, yo. Have you Ever Been Hated

', - @web.page("SecondPage").display_content) - end - - def test_pages_by_revision - add_sample_pages - assert_equal 'EverBeenHated', @web.select.by_revision.first.name - end - - def test_pages_by_match - add_sample_pages - assert_equal 2, @web.select { |page| page.content =~ /me/i }.length - assert_equal 1, @web.select { |page| page.content =~ /Who/i }.length - assert_equal 0, @web.select { |page| page.content =~ /none/i }.length - end - - def test_references - add_sample_pages - assert_equal 1, @web.select.pages_that_reference('EverBeenHated').length - assert_equal 0, @web.select.pages_that_reference('EverBeenInLove').length - end - - def test_delete - add_sample_pages - assert_equal 2, @web.pages.length - @web.remove_pages([ @web.page('EverBeenInLove') ]) - assert_equal 1, @web.pages(true).length - end - - def test_make_link - add_sample_pages - - existing_page_wiki_url = - 'Ever Been In Love' - existing_page_published_url = - 'Ever Been In Love' - existing_page_static_url = - 'Ever Been In Love' - new_page_wiki_url = - 'Unknown Word?' - new_page_published_url = - new_page_static_url = - 'Unknown Word' - - # no options - assert_equal existing_page_wiki_url, @web.make_link('EverBeenInLove') - - # :mode => :export - assert_equal existing_page_static_url, @web.make_link('EverBeenInLove', nil, :mode => :export) - - # :mode => :publish - assert_equal existing_page_published_url, - @web.make_link('EverBeenInLove', nil, :mode => :publish) - - # new page, no options - assert_equal new_page_wiki_url, @web.make_link('UnknownWord') - - # new page, :mode => :export - assert_equal new_page_static_url, @web.make_link('UnknownWord', nil, :mode => :export) - - # new page, :mode => :publish - assert_equal new_page_published_url, @web.make_link('UnknownWord', nil, :mode => :publish) - - # Escaping special characters in the name - assert_equal( - 'Smith & Wesson?', - @web.make_link('Smith & Wesson')) - - # optionally using text as the link text - assert_equal( - existing_page_published_url.sub(/>Ever Been In LoveHaven't you ever been in love?<"), - @web.make_link('EverBeenInLove', "Haven't you ever been in love?", :mode => :publish)) - - end - - def test_initialize - web = Web.new(:name => 'Wiki2', :address => 'wiki2', :password => '123') - - assert_equal 'Wiki2', web.name - assert_equal 'wiki2', web.address - assert_equal '123', web.password - - # new web should be set for maximum features enabled - assert_equal :textile, web.markup - assert_equal '008B26', web.color - assert !web.safe_mode? - assert_equal([], web.pages) - assert web.allow_uploads? - assert_nil web.additional_style - assert !web.published? - assert !web.brackets_only? - assert !web.count_pages? - assert_equal 100, web.max_upload_size - end - - def test_initialize_invalid_name - assert_raises(Instiki::ValidationError) { - Web.create(:name => 'Wiki2', :address => "wiki\234", :password => '123') - } - end - - def test_new_page_linked_from_mother_page - # this was a bug in revision 204 - home = @web.add_page('HomePage', 'This page refers to AnotherPage', - Time.local(2004, 4, 4, 16, 50), 'Alexey Verkhovsky') - @web.add_page('AnotherPage', 'This is \AnotherPage', - Time.local(2004, 4, 4, 16, 51), 'Alexey Verkhovsky') - - @web.pages(true) - assert_equal [home], @web.select.pages_that_link_to('AnotherPage') - end - - def test_orphaned_pages - add_sample_pages - home = @web.add_page('HomePage', - 'This is a home page, it should not be an orphan', - Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky') - author = @web.add_page('AlexeyVerkhovsky', - 'This is an author page, it should not be an orphan', - Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky') - self_linked = @web.add_page('SelfLinked', - 'I am me SelfLinked and link to EverBeenInLove', - Time.local(2004, 4, 4, 16, 50), 'AnonymousCoward') - - # page that links to itself, and nobody else links to it must be an orphan - assert_equal ['EverBeenHated', 'SelfLinked'], - @web.select.orphaned_pages.collect{ |page| page.name }.sort - end - - private - - def add_sample_pages - @in_love = @web.add_page('EverBeenInLove', 'Who am I me', - Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson') - @hated = @web.add_page('EverBeenHated', 'I am me EverBeenHated', - Time.local(2004, 4, 4, 16, 51), 'DavidHeinemeierHansson') - end -end +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') + +class WebTest < Test::Unit::TestCase + fixtures :webs, :pages, :revisions, :system + + def setup + @web = webs(:instiki) + end + + def test_wiki_word_linking + @web.add_page('SecondPage', 'Yo, yo. Have you EverBeenHated', + Time.now, 'DavidHeinemeierHansson') + + assert_equal('

Yo, yo. Have you Ever Been Hated' + + '?

', + @web.page("SecondPage").display_content) + + @web.add_page('EverBeenHated', 'Yo, yo. Have you EverBeenHated', Time.now, + 'DavidHeinemeierHansson') + assert_equal('

Yo, yo. Have you Ever Been Hated

', + @web.page("SecondPage").display_content) + end + + def test_pages_by_revision + add_sample_pages + assert_equal 'EverBeenHated', @web.select.by_revision.first.name + end + + def test_pages_by_match + add_sample_pages + assert_equal 2, @web.select { |page| page.content =~ /me/i }.length + assert_equal 1, @web.select { |page| page.content =~ /Who/i }.length + assert_equal 0, @web.select { |page| page.content =~ /none/i }.length + end + + def test_references + add_sample_pages + assert_equal 1, @web.select.pages_that_reference('EverBeenHated').length + assert_equal 0, @web.select.pages_that_reference('EverBeenInLove').length + end + + def test_delete + add_sample_pages + assert_equal 2, @web.pages.length + @web.remove_pages([ @web.page('EverBeenInLove') ]) + assert_equal 1, @web.pages(true).length + end + + def test_make_link + add_sample_pages + + existing_page_wiki_url = + 'Ever Been In Love' + existing_page_published_url = + 'Ever Been In Love' + existing_page_static_url = + 'Ever Been In Love' + new_page_wiki_url = + 'Unknown Word?' + new_page_published_url = + new_page_static_url = + 'Unknown Word' + + # no options + assert_equal existing_page_wiki_url, @web.make_link('EverBeenInLove') + + # :mode => :export + assert_equal existing_page_static_url, @web.make_link('EverBeenInLove', nil, :mode => :export) + + # :mode => :publish + assert_equal existing_page_published_url, + @web.make_link('EverBeenInLove', nil, :mode => :publish) + + # new page, no options + assert_equal new_page_wiki_url, @web.make_link('UnknownWord') + + # new page, :mode => :export + assert_equal new_page_static_url, @web.make_link('UnknownWord', nil, :mode => :export) + + # new page, :mode => :publish + assert_equal new_page_published_url, @web.make_link('UnknownWord', nil, :mode => :publish) + + # Escaping special characters in the name + assert_equal( + 'Smith & Wesson?', + @web.make_link('Smith & Wesson')) + + # optionally using text as the link text + assert_equal( + existing_page_published_url.sub(/>Ever Been In LoveHaven't you ever been in love?<"), + @web.make_link('EverBeenInLove', "Haven't you ever been in love?", :mode => :publish)) + + end + + def test_initialize + web = Web.new(:name => 'Wiki2', :address => 'wiki2', :password => '123') + + assert_equal 'Wiki2', web.name + assert_equal 'wiki2', web.address + assert_equal '123', web.password + + # new web should be set for maximum features enabled + assert_equal :textile, web.markup + assert_equal '008B26', web.color + assert !web.safe_mode? + assert_equal([], web.pages) + assert web.allow_uploads? + assert_nil web.additional_style + assert !web.published? + assert !web.brackets_only? + assert !web.count_pages? + assert_equal 100, web.max_upload_size + end + + def test_initialize_invalid_name + assert_raises(Instiki::ValidationError) { + Web.create(:name => 'Wiki2', :address => "wiki\234", :password => '123') + } + end + + def test_new_page_linked_from_mother_page + # this was a bug in revision 204 + home = @web.add_page('HomePage', 'This page refers to AnotherPage', + Time.local(2004, 4, 4, 16, 50), 'Alexey Verkhovsky') + @web.add_page('AnotherPage', 'This is \AnotherPage', + Time.local(2004, 4, 4, 16, 51), 'Alexey Verkhovsky') + + @web.pages(true) + assert_equal [home], @web.select.pages_that_link_to('AnotherPage') + end + + def test_orphaned_pages + add_sample_pages + home = @web.add_page('HomePage', + 'This is a home page, it should not be an orphan', + Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky') + author = @web.add_page('AlexeyVerkhovsky', + 'This is an author page, it should not be an orphan', + Time.local(2004, 4, 4, 16, 50), 'AlexeyVerkhovsky') + self_linked = @web.add_page('SelfLinked', + 'I am me SelfLinked and link to EverBeenInLove', + Time.local(2004, 4, 4, 16, 50), 'AnonymousCoward') + + # page that links to itself, and nobody else links to it must be an orphan + assert_equal ['EverBeenHated', 'SelfLinked'], + @web.select.orphaned_pages.collect{ |page| page.name }.sort + end + + private + + def add_sample_pages + @in_love = @web.add_page('EverBeenInLove', 'Who am I me', + Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson') + @hated = @web.add_page('EverBeenHated', 'I am me EverBeenHated', + Time.local(2004, 4, 4, 16, 51), 'DavidHeinemeierHansson') + end +end