]> source.dussan.org Git - redmine.git/commitdiff
Added version details view accessible from the roadmap.
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Fri, 7 Dec 2007 10:26:07 +0000 (10:26 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Fri, 7 Dec 2007 10:26:07 +0000 (10:26 +0000)
git-svn-id: http://redmine.rubyforge.org/svn/trunk@955 e93f8b46-1217-0410-a6f0-8f06a7374b81

31 files changed:
app/controllers/versions_controller.rb
app/helpers/versions_helper.rb
app/models/issue_category.rb
app/models/tracker.rb
app/views/projects/roadmap.rhtml
app/views/projects/settings/_versions.rhtml
app/views/versions/_issue_counts.rhtml [new file with mode: 0644]
app/views/versions/_overview.rhtml [new file with mode: 0644]
app/views/versions/show.rhtml [new file with mode: 0644]
lang/bg.yml
lang/cs.yml
lang/de.yml
lang/en.yml
lang/es.yml
lang/fr.yml
lang/he.yml
lang/it.yml
lang/ja.yml
lang/ko.yml
lang/nl.yml
lang/pl.yml
lang/pt-br.yml
lang/pt.yml
lang/ro.yml
lang/ru.yml
lang/sr.yml
lang/sv.yml
lang/zh.yml
lib/redmine.rb
public/stylesheets/application.css
test/functional/versions_controller_test.rb [new file with mode: 0644]

index 4e9016ebf71224867b53394b96223f51ee5b0b0a..1365c97e88faf20160ae7fbce46e5d9206edbeb6 100644 (file)
@@ -21,6 +21,9 @@ class VersionsController < ApplicationController
 
   cache_sweeper :version_sweeper, :only => [ :edit, :destroy ]
   
+  def show
+  end
+  
   def edit
     if request.post? and @version.update_attributes(params[:version])
       flash[:notice] = l(:notice_successful_update)
@@ -49,6 +52,13 @@ class VersionsController < ApplicationController
     flash[:notice] = l(:notice_successful_delete)
     redirect_to :controller => 'projects', :action => 'list_files', :id => @project
   end
+  
+  def status_by
+    respond_to do |format|
+      format.html { render :action => 'show' }
+      format.js { render(:update) {|page| page.replace_html 'status_by', render_issue_status_by(@version, params[:status_by])} }
+    end
+  end
 
 private
   def find_project
index 452f4d7fb668c3dbbad64f672fb9e765294f6b3a..0fcc6407c283fd86e842278386caaf5d3790a269 100644 (file)
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 module VersionsHelper
+
+  STATUS_BY_CRITERIAS = %w(category tracker priority author assigned_to)
+  
+  def render_issue_status_by(version, criteria)
+    criteria ||= 'category'
+    raise 'Unknown criteria' unless STATUS_BY_CRITERIAS.include?(criteria)
+    
+    h = Hash.new {|k,v| k[v] = [0, 0]}
+    begin
+      # Total issue count
+      Issue.count(:group => criteria,
+                  :conditions => ["#{Issue.table_name}.fixed_version_id = ?", version.id]).each {|c,s| h[c][0] = s}
+      # Open issues count
+      Issue.count(:group => criteria,
+                  :include => :status,
+                  :conditions => ["#{Issue.table_name}.fixed_version_id = ? AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s}
+    rescue ActiveRecord::RecordNotFound
+    # When grouping by an association, Rails throws this exception if there's no result (bug)
+    end
+    counts = h.keys.compact.sort.collect {|k| {:group => k, :total => h[k][0], :open => h[k][1], :closed => (h[k][0] - h[k][1])}}
+    max = counts.collect {|c| c[:total]}.max
+    
+    render :partial => 'issue_counts', :locals => {:version => version, :criteria => criteria, :counts => counts, :max => max}
+  end
+  
+  def status_by_options_for_select(value)
+    options_for_select(STATUS_BY_CRITERIAS.collect {|criteria| [l("field_#{criteria}".to_sym), criteria]}, value)
+  end
 end
index 9478504f16780b7f5322c375bc94b29b27518cd0..51baeb4194f48901827dcd23a7e0f94e7d2dd563 100644 (file)
@@ -35,5 +35,9 @@ class IssueCategory < ActiveRecord::Base
     destroy_without_reassign
   end
   
+  def <=>(category)
+    name <=> category.name
+  end
+  
   def to_s; name end
 end
index 6de2a098cb4a6d6753156fd863feb564011859d3..8d864774725f988585ed9f9d3ec1c211d92289f2 100644 (file)
@@ -29,6 +29,10 @@ class Tracker < ActiveRecord::Base
 
   def to_s; name end
   
+  def <=>(tracker)
+    name <=> tracker.name
+  end
+
   def self.all
     find(:all, :order => 'position')
   end
index 7c3544a53bae76fbbe94cea0a8bf4d056c8fe7f5..daf7639fc128f1299d75e0f52024201126540d96 100644 (file)
@@ -5,48 +5,28 @@
 <% end %>
 
 <% @versions.each do |version| %>   
-    <a name="<%= version.name %>"><h3 class="icon22 icon22-package"><%= version.name %></h3></a>
-    <% if version.completed? %>
-      <p><%= format_date(version.effective_date) %></p>
-    <% elsif version.overdue? %>
-      <p><strong><%= l(:label_roadmap_overdue, distance_of_time_in_words(Time.now, version.effective_date)) %> (<%= format_date(version.effective_date) %>)</strong></p>
-    <% elsif version.effective_date %>
-      <p><strong><%=l(:label_roadmap_due_in)%> <%= distance_of_time_in_words Time.now, version.effective_date %> (<%= format_date(version.effective_date) %>)</strong></p>
-    <% end %>
-    <p><%=h version.description %></p>        
-    
-    <% if version.fixed_issues.count > 0 %>
-        <%= progress_bar([version.closed_pourcent, version.completed_pourcent], :width => '40em', :legend => ('%0.0f%' % version.completed_pourcent)) %>
-        <p class="progress-info">
-            <%= link_to(version.closed_issues_count, :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %>
-            <%= lwr(:label_closed_issues, version.closed_issues_count) %>
-            (<%= '%0.0f' % (version.closed_issues_count.to_f / version.fixed_issues.count * 100) %>%)
-            &#160;
-            <%= link_to(version.open_issues_count, :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %>
-            <%= lwr(:label_open_issues, version.open_issues_count)%>
-            (<%= '%0.0f' % (version.open_issues_count.to_f / version.fixed_issues.count * 100) %>%)
-        </p>
-        <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
-        <% issues = version.fixed_issues.find(:all,
-                                     :include => [:status, :tracker],
-                                     :conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
-                                     :order => "#{Tracker.table_name}.position") unless @selected_tracker_ids.empty?
-           issues ||= []
-        %>
-        <ul>
-          <% if issues.size > 0 %>
-            <% issues.each do |issue| %>
-              <li>
-                <%= link = link_to_issue(issue)
-                    issue.status.is_closed? ? content_tag("del", link) : link %>: <%=h issue.subject %>
-                <%= content_tag "em", "(#{l(:label_closed_issues)})" if issue.status.is_closed? %>
-              </li>
-            <% end %>
-          <% end %>
-        </ul>
-    <% else %>
-        <p><em><%= l(:label_roadmap_no_issues) %></em></p>
-    <% end %>
+    <%= tag 'a', :name => version.name %>
+    <h3 class="icon22 icon22-package"><%= link_to h(version.name), :controller => 'versions', :action => 'show', :id => version %></h3>
+    <%= render :partial => 'versions/overview', :locals => {:version => version} %>
+    <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
+
+    <% issues = version.fixed_issues.find(:all,
+                                          :include => [:status, :tracker],
+                                          :conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
+                                          :order => "#{Tracker.table_name}.position") unless @selected_tracker_ids.empty?
+       issues ||= []
+    %>
+    <ul>
+      <% if issues.size > 0 %>
+        <% issues.each do |issue| %>
+          <li>
+            <%= link = link_to_issue(issue)
+                issue.status.is_closed? ? content_tag("del", link) : link %>: <%=h issue.subject %>
+            <%= content_tag "em", "(#{l(:label_closed_issues)})" if issue.status.is_closed? %>
+          </li>
+        <% end %>
+      <% end %>
+    </ul>
 <% end %>
 
 <% content_for :sidebar do %>
@@ -66,3 +46,5 @@
 <%= link_to version.name, :anchor => version.name %><br />
 <% end %>
 <% end %>
+
+<% set_html_title l(:label_roadmap) %>
index 63c408b0dfc1f82c26f9a697ddd4cd1b49dbdeb7..7329c7f3b6e3dcecaddbc9b3c78464bf78bd277d 100644 (file)
@@ -11,7 +11,7 @@
        <tbody>
 <% for version in @project.versions.sort %>
     <tr class="<%= cycle 'odd', 'even' %>">
-    <td><%=h version.name %></td>
+    <td><%= link_to h(version.name), :controller => 'versions', :action => 'show', :id => version %></td>
     <td align="center"><%= format_date(version.effective_date) %></td>
     <td><%=h version.description %></td>
     <td><%= link_to(version.wiki_page_title, :controller => 'wiki', :page => Wiki.titleize(version.wiki_page_title)) unless version.wiki_page_title.blank? || @project.wiki.nil? %></td>
diff --git a/app/views/versions/_issue_counts.rhtml b/app/views/versions/_issue_counts.rhtml
new file mode 100644 (file)
index 0000000..4bab5c6
--- /dev/null
@@ -0,0 +1,35 @@
+<form id="status_by_form">
+<fieldset>
+<legend>
+<%= l(:label_issues_by, 
+       select_tag('status_by',
+                   status_by_options_for_select(criteria),
+                   :id => 'status_by_select',
+                   :onchange => remote_function(:url => { :action => :status_by, :id => version },
+                                                :with => "Form.serialize('status_by_form')"))) %>
+</legend>
+<% if counts.empty? %>
+    <p><em><%= l(:label_no_data) %></em></p>
+<% else %>
+    <table>
+    <% counts.each do |count| %>
+    <tr>
+        <td width="130px" align="right" >
+            <%= link_to count[:group], {:controller => 'issues', 
+                                        :action => 'index',
+                                        :project_id => version.project,
+                                        :set_filter => 1,
+                                        :fixed_version_id => version,
+                                        "#{criteria}_id" => count[:group]} %>
+        </td>
+        <td width="240px">
+            <%= progress_bar((count[:closed].to_f / count[:total])*100, 
+                  :legend => "#{count[:closed]}/#{count[:total]}",
+                  :width => "#{(count[:total].to_f / max * 200).floor}px;") %>
+        </td>
+    </tr>
+    <% end %>
+    </table>
+<% end %>
+</fieldset>
+</form>
diff --git a/app/views/versions/_overview.rhtml b/app/views/versions/_overview.rhtml
new file mode 100644 (file)
index 0000000..d3aa6b1
--- /dev/null
@@ -0,0 +1,24 @@
+<% if version.completed? %>
+  <p><%= format_date(version.effective_date) %></p>
+<% elsif version.overdue? %>
+  <p><strong><%= l(:label_roadmap_overdue, distance_of_time_in_words(Time.now, version.effective_date)) %> (<%= format_date(version.effective_date) %>)</strong></p>
+<% elsif version.effective_date %>
+  <p><strong><%=l(:label_roadmap_due_in)%> <%= distance_of_time_in_words Time.now, version.effective_date %> (<%= format_date(version.effective_date) %>)</strong></p>
+<% end %>
+
+<p><%=h version.description %></p>
+
+<% if version.fixed_issues.count > 0 %>
+    <%= progress_bar([version.closed_pourcent, version.completed_pourcent], :width => '40em', :legend => ('%0.0f%' % version.completed_pourcent)) %>
+    <p class="progress-info">
+        <%= link_to(version.closed_issues_count, :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %>
+        <%= lwr(:label_closed_issues, version.closed_issues_count) %>
+        (<%= '%0.0f' % (version.closed_issues_count.to_f / version.fixed_issues.count * 100) %>%)
+        &#160;
+        <%= link_to(version.open_issues_count, :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %>
+        <%= lwr(:label_open_issues, version.open_issues_count)%>
+        (<%= '%0.0f' % (version.open_issues_count.to_f / version.fixed_issues.count * 100) %>%)
+    </p>
+<% else %>
+    <p><em><%= l(:label_roadmap_no_issues) %></em></p>
+<% end %>
diff --git a/app/views/versions/show.rhtml b/app/views/versions/show.rhtml
new file mode 100644 (file)
index 0000000..d8e2d24
--- /dev/null
@@ -0,0 +1,14 @@
+<div class="contextual">
+<%= link_to_if_authorized l(:button_edit), {:controller => 'versions', :action => 'edit', :id => @version}, :class => 'icon icon-edit' %>
+</div>
+
+<h2><%= h(@version.name) %></h2>
+
+<div id="status_by" style="float:right;">
+<%= render_issue_status_by(@version, params[:status_by]) if @version.fixed_issues.count > 0 %>
+</div>
+
+<%= render :partial => 'versions/overview', :locals => {:version => @version} %>
+<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %>
+
+<% set_html_title h(@version.name) %>
index 5f2dc6a8dd4f57cb32eda447828a0b65ae3e8071..590952681808b7a41dc178084d3f0d2586e774f5 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 49697dda8e5dae951b6e8a5acdd01db273db8614..816f9b92e99138f474c1c861c843b7ea3d6bdf02 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 870f45014803ab0dd34fee38275cd89f854c1ac0..046ed9994bcd97d81a80ae8b305297ff4338d5ec 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Zeitzone
 text_caracters_minimum: Muss mindestens %d Zeichen lang sein.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index cdecb6693a407ba80f0c94bb2724c5439ee618e4..104e7fe6edad06027dcae48af7713e3e687c5cfb 100644 (file)
@@ -210,6 +210,7 @@ label_issue: Issue
 label_issue_new: New issue
 label_issue_plural: Issues
 label_issue_view_all: View all issues
+label_issues_by: Issues by %s
 label_document: Document
 label_document_new: New document
 label_document_plural: Documents
index 5f25de7cfe53c9c20e8d9f7820512d7e3e5ff181..d806d066ec3f8a9385528abfb70fd7a5e29bef80 100644 (file)
@@ -551,3 +551,4 @@ notice_account_pending: "Su cuenta ha sido creada y está pendiende de la aproba
 setting_time_format: Formato de hora
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 63f367f0623f1885dc796c2d05cbb0e5896242ed..36ccc463f8b317c60edd442f4f4f6e5355cb2855 100644 (file)
@@ -210,6 +210,7 @@ label_issue: Demande
 label_issue_new: Nouvelle demande
 label_issue_plural: Demandes
 label_issue_view_all: Voir toutes les demandes
+label_issues_by: Demandes par %s
 label_document: Document
 label_document_new: Nouveau document
 label_document_plural: Documents
index 4ebbecf7afef134e22c3aadcf341938c9abe0402..6be1a4c77806b1dc51cfc841ac59a4f019bb61ae 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index fa13513cb914e15fe62ec542aff46203cf23fd30..8a3e954f4c8bc72d2d0ce140b9ae8e65f378ad52 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index d2f7d579f680900c56622bbaec940f54bf885723..1ecfb1ae9249e2f7a8257898b49b2f4a634c07a0 100644 (file)
@@ -549,3 +549,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index dd50ce2bc4fc972b74ff710b2af6d253cdeb6587..ef081e6229c71e082ceb206ff9abb95225172ac5 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 895feb5ede3f020f84bbdc99c1f07d400a2d0547..24a343eb3a1241021dced80a3d318edf6b15f8c9 100644 (file)
@@ -549,3 +549,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 381dc5e26b3238518141aa624b6cf9df4c8c0f93..ff5f8d82806d9ff2885b5d4af815649fc8b645ec 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Strefa czasowa
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 4c4d862d35e0ef12cfe7dabba6d38440b3cd925c..8c903edd497b3af52d37ac528bb2c576f230f753 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.\r
 setting_bcc_recipients: Blind carbon copy recipients (bcc)\r
 button_annotate: Annotate\r
+label_issues_by: Issues by %s\r
index 1aabc8ac76b39d0f4953aa155cceb457a4e47159..10de07b5fdaa05991a8bab94d2bc10b09cedec09 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 0c10c7727ed54be8664b05760e5fe4dd7a3b8d58..f7d3acd566e64dd69ec7705f4ba1fe9fab6783bd 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index c6e27ca9fbbdd3f31b20107df14b93d10854a33a..cad357c0c8f4ac2d17376942226837510986897e 100644 (file)
@@ -548,3 +548,4 @@ field_time_zone: Часовой пояс
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 42aa3cc3e8f8c138e82a9d869b25e5bd99a7aa1b..f9008d890bdb986b1d181221f4ac7d5c486d9deb 100644 (file)
@@ -549,3 +549,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 7cbcc7a5fcd2c8ec30ddceb08e9319f9c31af712..a4f55a17a1906947819416191d2c4583c8f091e0 100644 (file)
@@ -549,3 +549,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index ad18cecc3ec0f888a57d501e35d55b8f148af4d5..18fe3fda1588696abe5d823913d834e0483bd43b 100644 (file)
@@ -551,3 +551,4 @@ field_time_zone: Time zone
 text_caracters_minimum: Must be at least %d characters long.
 setting_bcc_recipients: Blind carbon copy recipients (bcc)
 button_annotate: Annotate
+label_issues_by: Issues by %s
index 32239ce5966425885d78fe0d7e079ed4df27c515..1f1053438a9ea98ad3aab388dcbdab8fd7e10895 100644 (file)
@@ -27,6 +27,7 @@ Redmine::AccessControl.map do |map|
     # Issues
     map.permission :view_issues, {:projects => [:changelog, :roadmap], 
                                   :issues => [:index, :changes, :show, :context_menu],
+                                  :versions => [:show, :status_by],
                                   :queries => :index,
                                   :reports => :issue_report}, :public => true                    
     map.permission :add_issues, {:projects => :add_issue}
index a10524dbb95f97fd4c0363548da4196c19daa225..f05fb9d91876413dce4efb4a39dd248b083a98b1 100644 (file)
@@ -267,6 +267,8 @@ table.progress td.open { background: #FFF none repeat scroll 0%; }
 p.pourcent {font-size: 80%;}
 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
 
+div#status_by { margin-left: 16px; margin-bottom: 16px; }
+
 /***** Tabs *****/
 #content .tabs{height: 2.6em;}
 #content .tabs ul{margin:0;}
diff --git a/test/functional/versions_controller_test.rb b/test/functional/versions_controller_test.rb
new file mode 100644 (file)
index 0000000..e832793
--- /dev/null
@@ -0,0 +1,42 @@
+# redMine - project management software
+# Copyright (C) 2006-2007  Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+require File.dirname(__FILE__) + '/../test_helper'
+require 'versions_controller'
+
+# Re-raise errors caught by the controller.
+class VersionsController; def rescue_action(e) raise e end; end
+
+class VersionsControllerTest < Test::Unit::TestCase
+  fixtures :projects, :versions, :users, :roles, :members, :enabled_modules
+  
+  def setup
+    @controller = VersionsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+    User.current = nil
+  end
+  
+  def test_show
+    get :show, :id => 2
+    assert_response :success
+    assert_template 'show'
+    assert_not_nil assigns(:version)
+    
+    assert_tag :tag => 'h2', :content => /1.0/
+  end
+end