Project

General

Profile

Patch #4250 » 0001-Converted-Menus-to-a-Tree-structure-to-allow-submenu.patch

Eric Davis, 2009-11-20 00:02

View differences:

config/environment.rb
50 50
  # It will automatically turn deliveries on
51 51
  config.action_mailer.perform_deliveries = false
52 52

  
53
  config.gem 'rubytree', :lib => 'tree'
54
  
53 55
  # Load any local configuration that is kept out of source control
54 56
  # (e.g. gems, patches).
55 57
  if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
lib/redmine/menu_manager.rb
15 15
# along with this program; if not, write to the Free Software
16 16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 17

  
18
require 'tree' # gem install rubytree
19

  
20
# Monkey patch the TreeNode to add on a few more methods :nodoc:
21
module TreeNodePatch
22
  def self.included(base)
23
    base.class_eval do
24
      attr_reader :last_items_count
25
      
26
      alias :old_initilize :initialize
27
      def initialize(name, content = nil)
28
        old_initilize(name, content)
29
        @last_items_count = 0
30
        extend(InstanceMethods)
31
      end
32
    end
33
  end
34
  
35
  module InstanceMethods
36
    # Adds the specified child node to the receiver node.  The child node's
37
    # parent is set to be the receiver.  The child is added as the first child in
38
    # the current list of children for the receiver node.
39
    def prepend(child)
40
      raise "Child already added" if @childrenHash.has_key?(child.name)
41

  
42
      @childrenHash[child.name]  = child
43
      @children = [child] + @children
44
      child.parent = self
45
      return child
46

  
47
    end
48

  
49
    # Adds the specified child node to the receiver node.  The child node's
50
    # parent is set to be the receiver.  The child is added at the position
51
    # into the current list of children for the receiver node.
52
    def add_at(child, position)
53
      raise "Child already added" if @childrenHash.has_key?(child.name)
54

  
55
      @childrenHash[child.name]  = child
56
      @children = @children.insert(position, child)
57
      child.parent = self
58
      return child
59

  
60
    end
61

  
62
    def add_last(child)
63
      raise "Child already added" if @childrenHash.has_key?(child.name)
64

  
65
      @childrenHash[child.name]  = child
66
      @children <<  child
67
      @last_items_count += 1
68
      child.parent = self
69
      return child
70

  
71
    end
72

  
73
    # Adds the specified child node to the receiver node.  The child node's
74
    # parent is set to be the receiver.  The child is added as the last child in
75
    # the current list of children for the receiver node.
76
    def add(child)
77
      raise "Child already added" if @childrenHash.has_key?(child.name)
78

  
79
      @childrenHash[child.name]  = child
80
      position = @children.size - @last_items_count
81
      @children.insert(position, child)
82
      child.parent = self
83
      return child
84

  
85
    end
86

  
87
    # Will return the position (zero-based) of the current child in
88
    # it's parent
89
    def position
90
      self.parent.children.index(self)
91
    end
92
  end
93
end
94
Tree::TreeNode.send(:include, TreeNodePatch)
95

  
18 96
module Redmine
19 97
  module MenuManager
20 98
    module MenuController
......
79 157
      
80 158
      def render_menu(menu, project=nil)
81 159
        links = []
82
        menu_items_for(menu, project) do |item, caption, url, selected|
83
          links << content_tag('li', 
84
            link_to(h(caption), url, item.html_options(:selected => selected)))
160
        menu_items_for(menu, project) do |node|
161
          links << render_menu_node(node, project)
85 162
        end
86 163
        links.empty? ? nil : content_tag('ul', links.join("\n"))
87 164
      end
88 165

  
166
      def render_menu_node(node, project=nil)
167
        caption, url, selected = extract_node_details(node, project)
168
        if node.hasChildren?
169
          html = []
170
          html << '<li>'
171
          html << render_single_menu_node(node, caption, url, selected) # parent
172
          html << '  <ul>'
173
          node.children.each do |child|
174
            html << render_menu_node(child, project)
175
          end
176
          html << '  </ul>'
177
          html << '</li>'
178
          return html.join("\n")
179
        else
180
          return content_tag('li',
181
                               render_single_menu_node(node, caption, url, selected))
182
        end
183
      end
184

  
185
      def render_single_menu_node(item, caption, url, selected)
186
        link_to(h(caption), url, item.html_options(:selected => selected))
187
      end
188
      
89 189
      def menu_items_for(menu, project=nil)
90 190
        items = []
91
        Redmine::MenuManager.allowed_items(menu, User.current, project).each do |item|
92
          unless item.condition && !item.condition.call(project)
93
            url = case item.url
94
            when Hash
95
              project.nil? ? item.url : {item.param => project}.merge(item.url)
96
            when Symbol
97
              send(item.url)
98
            else
99
              item.url
100
            end
101
            caption = item.caption(project)
191
        Redmine::MenuManager.items(menu).root.children.each do |node|
192
          if allowed_node?(node, User.current, project)
102 193
            if block_given?
103
              yield item, caption, url, (current_menu_item == item.name)
194
              yield node
104 195
            else
105
              items << [item, caption, url, (current_menu_item == item.name)]
196
              items << node  # TODO: not used?
106 197
            end
107 198
          end
108 199
        end
109 200
        return block_given? ? nil : items
110 201
      end
202

  
203
      def extract_node_details(node, project=nil)
204
        item = node
205
        url = case item.url
206
        when Hash
207
          project.nil? ? item.url : {item.param => project}.merge(item.url)
208
        when Symbol
209
          send(item.url)
210
        else
211
          item.url
212
        end
213
        caption = item.caption(project)
214
        return [caption, url, (current_menu_item == item.name)]
215
      end
216

  
217
      # Checks if a user is allowed to access the menu item by:
218
      #
219
      # * Checking the conditions of the item
220
      # * Checking the url target (project only)
221
      def allowed_node?(node, user, project)
222
        if node.condition && !node.condition.call(project)
223
          # Condition that doesn't pass
224
          return false
225
        end
226

  
227
        if project
228
          return user && user.allowed_to?(node.url, project)
229
        else
230
          # outside a project, all menu items allowed
231
          return true
232
        end
233
      end
111 234
    end
112 235
    
113 236
    class << self
......
122 245
      end
123 246
      
124 247
      def items(menu_name)
125
        @items[menu_name.to_sym] || []
126
      end
127
      
128
      def allowed_items(menu_name, user, project)
129
        project ? items(menu_name).select {|item| user && user.allowed_to?(item.url, project)} : items(menu_name)
248
        @items[menu_name.to_sym] || Tree::TreeNode.new(:root, {})
130 249
      end
131 250
    end
132 251
    
133 252
    class Mapper
134 253
      def initialize(menu, items)
135
        items[menu] ||= []
254
        items[menu] ||= Tree::TreeNode.new(:root, {})
136 255
        @menu = menu
137 256
        @menu_items = items[menu]
138 257
      end
......
151 270
      # * html_options: a hash of html options that are passed to link_to
152 271
      def push(name, url, options={})
153 272
        options = options.dup
154
        
273

  
274
        if options[:parent_menu]
275
          subtree = self.find(options[:parent_menu])
276
          if subtree
277
            target_root = subtree
278
          else
279
            target_root = @menu_items.root
280
          end
281

  
282
        else
283
          target_root = @menu_items.root
284
        end
285

  
155 286
        # menu item position
156
        if before = options.delete(:before)
157
          position = @menu_items.collect(&:name).index(before)
287
        if first = options.delete(:first)
288
          target_root.prepend(MenuItem.new(name, url, options))
289
        elsif before = options.delete(:before)
290

  
291
          if exists?(before)
292
            target_root.add_at(MenuItem.new(name, url, options), position_of(before))
293
          else
294
            target_root.add(MenuItem.new(name, url, options))
295
          end
296

  
158 297
        elsif after = options.delete(:after)
159
          position = @menu_items.collect(&:name).index(after)
160
          position += 1 unless position.nil?
298

  
299
          if exists?(after)
300
            target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1)
301
          else
302
            target_root.add(MenuItem.new(name, url, options))
303
          end
304
          
161 305
        elsif options.delete(:last)
162
          position = @menu_items.size
163
          @@last_items_count[@menu] += 1
306
          target_root.add_last(MenuItem.new(name, url, options))
307
        else
308
          target_root.add(MenuItem.new(name, url, options))
164 309
        end
165
        # default position
166
        position ||= @menu_items.size - @@last_items_count[@menu]
167
        
168
        @menu_items.insert(position, MenuItem.new(name, url, options))
169 310
      end
170 311
      
171 312
      # Removes a menu item
172 313
      def delete(name)
173
        @menu_items.delete_if {|i| i.name == name}
314
        if found = self.find(name)
315
          @menu_items.remove!(found)
316
        end
317
      end
318

  
319
      # Checks if a menu item exists
320
      def exists?(name)
321
        @menu_items.any? {|node| node.name == name}
322
      end
323

  
324
      def find(name)
325
        @menu_items.find {|node| node.name == name}
326
      end
327

  
328
      def position_of(name)
329
        @menu_items.each do |node|
330
          if node.name == name
331
            return node.position
332
          end
333
        end
174 334
      end
175 335
    end
176 336
    
177
    class MenuItem
337
    class MenuItem < Tree::TreeNode
178 338
      include Redmine::I18n
179
      attr_reader :name, :url, :param, :condition
339
      attr_reader :name, :url, :param, :condition, :parent_menu
180 340
      
181 341
      def initialize(name, url, options)
182
        raise "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
183
        raise "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
342
        raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
343
        raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
344
        raise ArgumentError, "Cannot set the :parent_menu to be the same as this item" if options[:parent_menu] == name.to_sym
184 345
        @name = name
185 346
        @url = url
186 347
        @condition = options[:if]
......
189 350
        @html_options = options[:html] || {}
190 351
        # Adds a unique class to each menu item based on its name
191 352
        @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
353
        @parent_menu = options[:parent_menu]
354
        super @name.to_sym
192 355
      end
193 356
      
194 357
      def caption(project=nil)
test/unit/lib/redmine/menu_manager/mapper_test.rb
1
# Redmine - project management software
2
# Copyright (C) 2006-2009  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
# 
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
# 
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.dirname(__FILE__) + '/../../../../test_helper'
19

  
20
class Redmine::MenuManager::MapperTest < Test::Unit::TestCase
21
  context "Mapper#initialize" do
22
    should "be tested"
23
  end
24

  
25
  def test_push_onto_root
26
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
27
    menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
28

  
29
    menu_mapper.exists?(:test_overview)
30
  end
31

  
32
  def test_push_onto_parent
33
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
34
    menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
35
    menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent_menu => :test_overview}
36

  
37
    assert menu_mapper.exists?(:test_child)
38
    assert_equal :test_child, menu_mapper.find(:test_child).name
39
  end
40

  
41
  def test_push_onto_grandparent
42
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
43
    menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
44
    menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent_menu => :test_overview}
45
    menu_mapper.push :test_grandchild, { :controller => 'projects', :action => 'show'}, {:parent_menu => :test_child}
46

  
47
    assert menu_mapper.exists?(:test_grandchild)
48
    grandchild = menu_mapper.find(:test_grandchild)
49
    assert_equal :test_grandchild, grandchild.name
50
    assert_equal :test_child, grandchild.parent_menu
51
  end
52

  
53
  def test_push_first
54
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
55
    menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
56
    menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
57
    menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
58
    menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
59
    menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {:first => true}
60

  
61
    root = menu_mapper.find(:root)
62
    assert_equal 5, root.children.size
63
    {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
64
      assert_not_nil root.children[position]
65
      assert_equal name, root.children[position].name
66
    end
67
  
68
  end
69
  
70
  def test_push_before
71
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
72
    menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
73
    menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
74
    menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
75
    menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
76
    menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {:before => :test_fourth}
77

  
78
    root = menu_mapper.find(:root)
79
    assert_equal 5, root.children.size
80
    {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
81
      assert_not_nil root.children[position]
82
      assert_equal name, root.children[position].name
83
    end
84
  
85
  end
86

  
87
  def test_push_after
88
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
89
    menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
90
    menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
91
    menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
92
    menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
93
    menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {:after => :test_third}
94

  
95
    
96
    root = menu_mapper.find(:root)
97
    assert_equal 5, root.children.size
98
    {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
99
      assert_not_nil root.children[position]
100
      assert_equal name, root.children[position].name
101
    end
102
  
103
  end
104

  
105
  def test_push_last
106
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
107
    menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
108
    menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
109
    menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
110
    menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {:last => true}
111
    menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
112

  
113
    root = menu_mapper.find(:root)
114
    assert_equal 5, root.children.size
115
    {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
116
      assert_not_nil root.children[position]
117
      assert_equal name, root.children[position].name
118
    end
119
  
120
  end
121
  
122
  def test_exists_for_child_node
123
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
124
    menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
125
    menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent_menu => :test_overview }
126

  
127
    assert menu_mapper.exists?(:test_child)
128
  end
129

  
130
  def test_exists_for_invalid_node
131
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
132
    menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
133

  
134
    assert !menu_mapper.exists?(:nothing)
135
  end
136

  
137
  def test_find
138
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
139
    menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
140

  
141
    item = menu_mapper.find(:test_overview)
142
    assert_equal :test_overview, item.name
143
    assert_equal({:controller => 'projects', :action => 'show'}, item.url)
144
  end
145

  
146
  def test_find_missing
147
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
148
    menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
149

  
150
    item = menu_mapper.find(:nothing)
151
    assert_equal nil, item
152
  end
153

  
154
  def test_delete
155
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
156
    menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
157
    assert_not_nil menu_mapper.delete(:test_overview)
158

  
159
    assert_nil menu_mapper.find(:test_overview)
160
  end
161

  
162
  def test_delete_missing
163
    menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
164
    assert_nil menu_mapper.delete(:test_missing)
165
  end
166
end
test/unit/lib/redmine/menu_manager/menu_helper_test.rb
1
# Redmine - project management software
2
# Copyright (C) 2006-2009  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
# 
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
# 
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.dirname(__FILE__) + '/../../../../test_helper'
19

  
20

  
21

  
22
class Redmine::MenuManager::MenuHelperTest < HelperTestCase
23
  include Redmine::MenuManager::MenuHelper
24
  include ActionController::Assertions::SelectorAssertions
25
  fixtures :users, :members, :projects, :enabled_modules
26

  
27
  # Used by assert_select
28
  def html_document
29
    HTML::Document.new(@response.body)
30
  end
31
  
32
  def setup
33
    super
34
    @response = ActionController::TestResponse.new
35
    # Stub the current menu item in the controller
36
    def @controller.current_menu_item
37
      :index
38
    end
39
  end
40
  
41

  
42
  context "MenuManager#current_menu_item" do
43
    should "be tested"
44
  end
45

  
46
  context "MenuManager#render_main_menu" do
47
    should "be tested"
48
  end
49

  
50
  context "MenuManager#render_menu" do
51
    should "be tested"
52
  end
53

  
54
  context "MenuManager#menu_item_and_children" do
55
    should "be tested"
56
  end
57

  
58
  context "MenuManager#extract_node_details" do
59
    should "be tested"
60
  end
61

  
62
  def test_render_single_menu_node
63
    node = Redmine::MenuManager::MenuItem.new(:testing, '/test', { })
64
    @response.body = render_single_menu_node(node, 'This is a test', node.url, false)
65

  
66
    assert_select("a.testing", "This is a test")
67
  end
68

  
69
  def test_render_menu_node
70
    single_node = Redmine::MenuManager::MenuItem.new(:single_node, '/test', { })
71
    @response.body = render_menu_node(single_node, nil)
72

  
73
    assert_select("li") do
74
      assert_select("a.single-node", "Single node")
75
    end
76
  end
77
  
78
  def test_render_menu_node_with_nested_items
79
    parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { })
80
    parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { })
81
    parent_node << Redmine::MenuManager::MenuItem.new(:child_two_node, '/test', { })
82
    parent_node <<
83
      Redmine::MenuManager::MenuItem.new(:child_three_node, '/test', { }) <<
84
      Redmine::MenuManager::MenuItem.new(:child_three_inner_node, '/test', { })
85

  
86
    @response.body = render_menu_node(parent_node, nil)
87

  
88
    assert_select("li") do
89
      assert_select("a.parent-node", "Parent node")
90
      assert_select("ul") do
91
        assert_select("li a.child-one-node", "Child one node")
92
        assert_select("li a.child-two-node", "Child two node")
93
        assert_select("li") do
94
          assert_select("a.child-three-node", "Child three node")
95
          assert_select("ul") do
96
            assert_select("li a.child-three-inner-node", "Child three inner node")
97
          end
98
        end
99
      end
100
    end
101
    
102
  end
103

  
104
  def test_menu_items_for_should_yield_all_items_if_passed_a_block
105
    menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block
106
    Redmine::MenuManager.map menu_name do |menu|
107
      menu.push(:a_menu, '/', { })
108
      menu.push(:a_menu_2, '/', { })
109
      menu.push(:a_menu_3, '/', { })
110
    end
111

  
112
    items_yielded = []
113
    menu_items_for(menu_name) do |item|
114
      items_yielded << item
115
    end
116
    
117
    assert_equal 3, items_yielded.size
118
  end
119

  
120
  def test_menu_items_for_should_return_all_items
121
    menu_name = :test_menu_items_for_should_return_all_items
122
    Redmine::MenuManager.map menu_name do |menu|
123
      menu.push(:a_menu, '/', { })
124
      menu.push(:a_menu_2, '/', { })
125
      menu.push(:a_menu_3, '/', { })
126
    end
127

  
128
    items = menu_items_for(menu_name)
129
    assert_equal 3, items.size
130
  end
131

  
132
  def test_menu_items_for_should_skip_unallowed_items_on_a_project
133
    menu_name = :test_menu_items_for_should_skip_unallowed_items_on_a_project
134
    Redmine::MenuManager.map menu_name do |menu|
135
      menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
136
      menu.push(:a_menu_2, {:controller => 'issues', :action => 'index' }, { })
137
      menu.push(:unallowed, {:controller => 'issues', :action => 'unallowed' }, { })
138
    end
139

  
140
    User.current = User.find(2)
141
    
142
    items = menu_items_for(menu_name, Project.find(1))
143
    assert_equal 2, items.size
144
  end
145
  
146
  def test_menu_items_for_should_skip_items_that_fail_the_conditions
147
    menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions
148
    Redmine::MenuManager.map menu_name do |menu|
149
      menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
150
      menu.push(:unallowed,
151
                {:controller => 'issues', :action => 'index' },
152
                { :if => Proc.new { false }})
153
    end
154

  
155
    User.current = User.find(2)
156
    
157
    items = menu_items_for(menu_name, Project.find(1))
158
    assert_equal 1, items.size
159
  end
160

  
161
end
test/unit/lib/redmine/menu_manager/menu_item_test.rb
1
# Redmine - project management software
2
# Copyright (C) 2006-2009  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
# 
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
# 
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.dirname(__FILE__) + '/../../../../test_helper'
19

  
20
module RedmineMenuTestHelper
21
  # Helpers
22
  def get_menu_item(menu_name, item_name)
23
    Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
24
  end
25
end
26

  
27
class Redmine::MenuManager::MenuItemTest < Test::Unit::TestCase
28
  include RedmineMenuTestHelper
29

  
30
  Redmine::MenuManager.map :test_menu do |menu|
31
    menu.push(:parent_menu, '/test', { })
32
    menu.push(:child_menu, '/test', { :parent_menu => :parent_menu})
33
    menu.push(:child2_menu, '/test', { :parent_menu => :parent_menu})
34
  end
35
  
36
  context "MenuItem#caption" do
37
    should "be tested"
38
  end
39

  
40
  context "MenuItem#html_options" do
41
    should "be tested"
42
  end
43

  
44
  # context new menu item
45
  def test_new_menu_item_should_require_a_name
46
    assert_raises ArgumentError do
47
      Redmine::MenuManager::MenuItem.new
48
    end
49
  end
50

  
51
  def test_new_menu_item_should_require_an_url
52
    assert_raises ArgumentError do
53
      Redmine::MenuManager::MenuItem.new(:test_missing_url)
54
    end
55
  end
56

  
57
  def test_new_menu_item_should_require_the_options
58
    assert_raises ArgumentError do
59
      Redmine::MenuManager::MenuItem.new(:test_missing_options, '/test')
60
    end
61
  end
62

  
63
  def test_new_menu_item_with_all_required_parameters
64
    assert Redmine::MenuManager::MenuItem.new(:test_good_menu, '/test', {})
65
  end
66

  
67
  def test_new_menu_item_should_require_a_proc_to_use_for_the_if_condition
68
    assert_raises ArgumentError do
69
      Redmine::MenuManager::MenuItem.new(:test_error, '/test',
70
                                         {
71
                                           :if => ['not_a_proc']
72
                                         })
73
    end
74

  
75
    assert Redmine::MenuManager::MenuItem.new(:test_good_if, '/test',
76
                                              {
77
                                                :if => Proc.new{}
78
                                              })
79
  end
80

  
81
  def test_new_menu_item_should_allow_a_hash_for_extra_html_options
82
    assert_raises ArgumentError do
83
      Redmine::MenuManager::MenuItem.new(:test_error, '/test',
84
                                         {
85
                                           :html => ['not_a_hash']
86
                                         })
87
    end
88

  
89
    assert Redmine::MenuManager::MenuItem.new(:test_good_html, '/test',
90
                                              {
91
                                                :html => { :onclick => 'doSomething'}
92
                                              })
93
  end
94

  
95
  def test_new_should_not_allow_setting_the_parent_menu_item_to_the_current_item
96
    assert_raises ArgumentError do
97
      Redmine::MenuManager::MenuItem.new(:test_error, '/test', { :parent_menu => :test_error })
98
    end
99
  end
100

  
101
  def test_has_children
102
    parent_item = get_menu_item(:test_menu, :parent_menu)
103
    assert parent_item.hasChildren?
104
    assert_equal 2, parent_item.children.size
105
    assert_equal get_menu_item(:test_menu, :child_menu), parent_item.children[0]
106
    assert_equal get_menu_item(:test_menu, :child2_menu), parent_item.children[1]
107
  end
108
end
test/unit/lib/redmine/menu_manager_test.rb
1
# Redmine - project management software
2
# Copyright (C) 2006-2009  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
# 
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
# 
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.dirname(__FILE__) + '/../../../test_helper'
19

  
20
class Redmine::MenuManagerTest < Test::Unit::TestCase
21
  context "MenuManager#map" do
22
    should "be tested"
23
  end
24

  
25
  context "MenuManager#items" do
26
    should "be tested"
27
  end
28
end
test/unit/lib/redmine_test.rb
1
# Redmine - project management software
2
# Copyright (C) 2006-2009  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
# 
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
# 
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.dirname(__FILE__) + '/../../test_helper'
19

  
20
module RedmineMenuTestHelper
21
  # Assertions
22
  def assert_number_of_items_in_menu(menu_name, count)
23
    assert Redmine::MenuManager.items(menu_name).size >= count, "Menu has less than #{count} items"
24
  end
25

  
26
  def assert_menu_contains_item_named(menu_name, item_name)
27
    assert Redmine::MenuManager.items(menu_name).collect(&:name).include?(item_name.to_sym), "Menu did not have an item named #{item_name}"
28
  end
29

  
30
  # Helpers
31
  def get_menu_item(menu_name, item_name)
32
    Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
33
  end
34
end
35

  
36
class RedmineTest < Test::Unit::TestCase
37
  include RedmineMenuTestHelper
38

  
39
  def test_top_menu
40
    assert_number_of_items_in_menu :top_menu, 5
41
    assert_menu_contains_item_named :top_menu, :home
42
    assert_menu_contains_item_named :top_menu, :my_page
43
    assert_menu_contains_item_named :top_menu, :projects
44
    assert_menu_contains_item_named :top_menu, :administration
45
    assert_menu_contains_item_named :top_menu, :help
46
  end
47

  
48
  def test_account_menu
49
    assert_number_of_items_in_menu :account_menu, 4
50
    assert_menu_contains_item_named :account_menu, :login
51
    assert_menu_contains_item_named :account_menu, :register
52
    assert_menu_contains_item_named :account_menu, :my_account
53
    assert_menu_contains_item_named :account_menu, :logout
54
  end
55

  
56
  def test_application_menu
57
    assert_number_of_items_in_menu :application_menu, 0
58
  end
59

  
60
  def test_admin_menu
61
    assert_number_of_items_in_menu :admin_menu, 0
62
  end
63

  
64
  def test_project_menu
65
    assert_number_of_items_in_menu :project_menu, 12
66
    assert_menu_contains_item_named :project_menu, :overview
67
    assert_menu_contains_item_named :project_menu, :activity
68
    assert_menu_contains_item_named :project_menu, :roadmap
69
    assert_menu_contains_item_named :project_menu, :issues
70
    assert_menu_contains_item_named :project_menu, :new_issue
71
    assert_menu_contains_item_named :project_menu, :news
72
    assert_menu_contains_item_named :project_menu, :documents
73
    assert_menu_contains_item_named :project_menu, :wiki
74
    assert_menu_contains_item_named :project_menu, :boards
75
    assert_menu_contains_item_named :project_menu, :files
76
    assert_menu_contains_item_named :project_menu, :repository
77
    assert_menu_contains_item_named :project_menu, :settings
78
  end
79

  
80
  def test_new_issue_should_have_root_as_a_parent
81
    new_issue = get_menu_item(:project_menu, :new_issue)
82
    assert_equal :root, new_issue.parent.name
83
  end
84
end
(1-1/3)