Converted Menus to a Tree structure to allow submenus.

* Bundle the rubytree gem
* Patched RubyTree's TreeNode to add some additional methods.
* Converted the menu rendering to walk the Tree of MenuItems to render
  each item
* Added a menu option for :parent_menu to make this menu a child of the parent
* Added a bunch of tests
* Made MenuItem a subclass of Tree::TreeNode in order to use it's methods
  directly
* Changed the exceptions in MenuItem#new to be ArgumentErrors instead of the
  generic RuntimeError

  #4250

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3090 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Eric Davis 2009-11-25 05:36:44 +00:00
parent 5a9528cf3d
commit 1f06cf8899
20 changed files with 4602 additions and 41 deletions

View File

@ -50,6 +50,8 @@ Rails::Initializer.run do |config|
# It will automatically turn deliveries on # It will automatically turn deliveries on
config.action_mailer.perform_deliveries = false config.action_mailer.perform_deliveries = false
config.gem 'rubytree', :lib => 'tree'
# Load any local configuration that is kept out of source control # Load any local configuration that is kept out of source control
# (e.g. gems, patches). # (e.g. gems, patches).
if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb')) if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))

View File

@ -15,6 +15,84 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'tree' # gem install rubytree
# Monkey patch the TreeNode to add on a few more methods :nodoc:
module TreeNodePatch
def self.included(base)
base.class_eval do
attr_reader :last_items_count
alias :old_initilize :initialize
def initialize(name, content = nil)
old_initilize(name, content)
@last_items_count = 0
extend(InstanceMethods)
end
end
end
module InstanceMethods
# Adds the specified child node to the receiver node. The child node's
# parent is set to be the receiver. The child is added as the first child in
# the current list of children for the receiver node.
def prepend(child)
raise "Child already added" if @childrenHash.has_key?(child.name)
@childrenHash[child.name] = child
@children = [child] + @children
child.parent = self
return child
end
# Adds the specified child node to the receiver node. The child node's
# parent is set to be the receiver. The child is added at the position
# into the current list of children for the receiver node.
def add_at(child, position)
raise "Child already added" if @childrenHash.has_key?(child.name)
@childrenHash[child.name] = child
@children = @children.insert(position, child)
child.parent = self
return child
end
def add_last(child)
raise "Child already added" if @childrenHash.has_key?(child.name)
@childrenHash[child.name] = child
@children << child
@last_items_count += 1
child.parent = self
return child
end
# Adds the specified child node to the receiver node. The child node's
# parent is set to be the receiver. The child is added as the last child in
# the current list of children for the receiver node.
def add(child)
raise "Child already added" if @childrenHash.has_key?(child.name)
@childrenHash[child.name] = child
position = @children.size - @last_items_count
@children.insert(position, child)
child.parent = self
return child
end
# Will return the position (zero-based) of the current child in
# it's parent
def position
self.parent.children.index(self)
end
end
end
Tree::TreeNode.send(:include, TreeNodePatch)
module Redmine module Redmine
module MenuManager module MenuManager
module MenuController module MenuController
@ -79,17 +157,51 @@ module Redmine
def render_menu(menu, project=nil) def render_menu(menu, project=nil)
links = [] links = []
menu_items_for(menu, project) do |item, caption, url, selected| menu_items_for(menu, project) do |node|
links << content_tag('li', links << render_menu_node(node, project)
link_to(h(caption), url, item.html_options(:selected => selected)))
end end
links.empty? ? nil : content_tag('ul', links.join("\n")) links.empty? ? nil : content_tag('ul', links.join("\n"))
end end
def render_menu_node(node, project=nil)
caption, url, selected = extract_node_details(node, project)
if node.hasChildren?
html = []
html << '<li>'
html << render_single_menu_node(node, caption, url, selected) # parent
html << ' <ul>'
node.children.each do |child|
html << render_menu_node(child, project)
end
html << ' </ul>'
html << '</li>'
return html.join("\n")
else
return content_tag('li',
render_single_menu_node(node, caption, url, selected))
end
end
def render_single_menu_node(item, caption, url, selected)
link_to(h(caption), url, item.html_options(:selected => selected))
end
def menu_items_for(menu, project=nil) def menu_items_for(menu, project=nil)
items = [] items = []
Redmine::MenuManager.allowed_items(menu, User.current, project).each do |item| Redmine::MenuManager.items(menu).root.children.each do |node|
unless item.condition && !item.condition.call(project) if allowed_node?(node, User.current, project)
if block_given?
yield node
else
items << node # TODO: not used?
end
end
end
return block_given? ? nil : items
end
def extract_node_details(node, project=nil)
item = node
url = case item.url url = case item.url
when Hash when Hash
project.nil? ? item.url : {item.param => project}.merge(item.url) project.nil? ? item.url : {item.param => project}.merge(item.url)
@ -99,16 +211,27 @@ module Redmine
item.url item.url
end end
caption = item.caption(project) caption = item.caption(project)
if block_given? return [caption, url, (current_menu_item == item.name)]
yield item, caption, url, (current_menu_item == item.name) end
# Checks if a user is allowed to access the menu item by:
#
# * Checking the conditions of the item
# * Checking the url target (project only)
def allowed_node?(node, user, project)
if node.condition && !node.condition.call(project)
# Condition that doesn't pass
return false
end
if project
return user && user.allowed_to?(node.url, project)
else else
items << [item, caption, url, (current_menu_item == item.name)] # outside a project, all menu items allowed
return true
end end
end end
end end
return block_given? ? nil : items
end
end
class << self class << self
def map(menu_name) def map(menu_name)
@ -122,17 +245,13 @@ module Redmine
end end
def items(menu_name) def items(menu_name)
@items[menu_name.to_sym] || [] @items[menu_name.to_sym] || Tree::TreeNode.new(:root, {})
end
def allowed_items(menu_name, user, project)
project ? items(menu_name).select {|item| user && user.allowed_to?(item.url, project)} : items(menu_name)
end end
end end
class Mapper class Mapper
def initialize(menu, items) def initialize(menu, items)
items[menu] ||= [] items[menu] ||= Tree::TreeNode.new(:root, {})
@menu = menu @menu = menu
@menu_items = items[menu] @menu_items = items[menu]
end end
@ -152,35 +271,77 @@ module Redmine
def push(name, url, options={}) def push(name, url, options={})
options = options.dup options = options.dup
# menu item position if options[:parent_menu]
if before = options.delete(:before) subtree = self.find(options[:parent_menu])
position = @menu_items.collect(&:name).index(before) if subtree
elsif after = options.delete(:after) target_root = subtree
position = @menu_items.collect(&:name).index(after) else
position += 1 unless position.nil? target_root = @menu_items.root
elsif options.delete(:last)
position = @menu_items.size
@@last_items_count[@menu] += 1
end end
# default position
position ||= @menu_items.size - @@last_items_count[@menu]
@menu_items.insert(position, MenuItem.new(name, url, options)) else
target_root = @menu_items.root
end
# menu item position
if first = options.delete(:first)
target_root.prepend(MenuItem.new(name, url, options))
elsif before = options.delete(:before)
if exists?(before)
target_root.add_at(MenuItem.new(name, url, options), position_of(before))
else
target_root.add(MenuItem.new(name, url, options))
end
elsif after = options.delete(:after)
if exists?(after)
target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1)
else
target_root.add(MenuItem.new(name, url, options))
end
elsif options.delete(:last)
target_root.add_last(MenuItem.new(name, url, options))
else
target_root.add(MenuItem.new(name, url, options))
end
end end
# Removes a menu item # Removes a menu item
def delete(name) def delete(name)
@menu_items.delete_if {|i| i.name == name} if found = self.find(name)
@menu_items.remove!(found)
end end
end end
class MenuItem # Checks if a menu item exists
def exists?(name)
@menu_items.any? {|node| node.name == name}
end
def find(name)
@menu_items.find {|node| node.name == name}
end
def position_of(name)
@menu_items.each do |node|
if node.name == name
return node.position
end
end
end
end
class MenuItem < Tree::TreeNode
include Redmine::I18n include Redmine::I18n
attr_reader :name, :url, :param, :condition attr_reader :name, :url, :param, :condition, :parent_menu
def initialize(name, url, options) def initialize(name, url, options)
raise "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
raise "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash) raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
raise ArgumentError, "Cannot set the :parent_menu to be the same as this item" if options[:parent_menu] == name.to_sym
@name = name @name = name
@url = url @url = url
@condition = options[:if] @condition = options[:if]
@ -189,6 +350,8 @@ module Redmine
@html_options = options[:html] || {} @html_options = options[:html] || {}
# Adds a unique class to each menu item based on its name # Adds a unique class to each menu item based on its name
@html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ') @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
@parent_menu = options[:parent_menu]
super @name.to_sym
end end
def caption(project=nil) def caption(project=nil)

View File

@ -0,0 +1,166 @@
# Redmine - project management software
# Copyright (C) 2006-2009 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'
class Redmine::MenuManager::MapperTest < Test::Unit::TestCase
context "Mapper#initialize" do
should "be tested"
end
def test_push_onto_root
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.exists?(:test_overview)
end
def test_push_onto_parent
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent_menu => :test_overview}
assert menu_mapper.exists?(:test_child)
assert_equal :test_child, menu_mapper.find(:test_child).name
end
def test_push_onto_grandparent
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent_menu => :test_overview}
menu_mapper.push :test_grandchild, { :controller => 'projects', :action => 'show'}, {:parent_menu => :test_child}
assert menu_mapper.exists?(:test_grandchild)
grandchild = menu_mapper.find(:test_grandchild)
assert_equal :test_grandchild, grandchild.name
assert_equal :test_child, grandchild.parent_menu
end
def test_push_first
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {:first => true}
root = menu_mapper.find(:root)
assert_equal 5, root.children.size
{0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
assert_not_nil root.children[position]
assert_equal name, root.children[position].name
end
end
def test_push_before
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {:before => :test_fourth}
root = menu_mapper.find(:root)
assert_equal 5, root.children.size
{0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
assert_not_nil root.children[position]
assert_equal name, root.children[position].name
end
end
def test_push_after
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {:after => :test_third}
root = menu_mapper.find(:root)
assert_equal 5, root.children.size
{0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
assert_not_nil root.children[position]
assert_equal name, root.children[position].name
end
end
def test_push_last
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {:last => true}
menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {}
root = menu_mapper.find(:root)
assert_equal 5, root.children.size
{0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name|
assert_not_nil root.children[position]
assert_equal name, root.children[position].name
end
end
def test_exists_for_child_node
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent_menu => :test_overview }
assert menu_mapper.exists?(:test_child)
end
def test_exists_for_invalid_node
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
assert !menu_mapper.exists?(:nothing)
end
def test_find
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
item = menu_mapper.find(:test_overview)
assert_equal :test_overview, item.name
assert_equal({:controller => 'projects', :action => 'show'}, item.url)
end
def test_find_missing
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
item = menu_mapper.find(:nothing)
assert_equal nil, item
end
def test_delete
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {}
assert_not_nil menu_mapper.delete(:test_overview)
assert_nil menu_mapper.find(:test_overview)
end
def test_delete_missing
menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {})
assert_nil menu_mapper.delete(:test_missing)
end
end

View File

@ -0,0 +1,161 @@
# Redmine - project management software
# Copyright (C) 2006-2009 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'
class Redmine::MenuManager::MenuHelperTest < HelperTestCase
include Redmine::MenuManager::MenuHelper
include ActionController::Assertions::SelectorAssertions
fixtures :users, :members, :projects, :enabled_modules
# Used by assert_select
def html_document
HTML::Document.new(@response.body)
end
def setup
super
@response = ActionController::TestResponse.new
# Stub the current menu item in the controller
def @controller.current_menu_item
:index
end
end
context "MenuManager#current_menu_item" do
should "be tested"
end
context "MenuManager#render_main_menu" do
should "be tested"
end
context "MenuManager#render_menu" do
should "be tested"
end
context "MenuManager#menu_item_and_children" do
should "be tested"
end
context "MenuManager#extract_node_details" do
should "be tested"
end
def test_render_single_menu_node
node = Redmine::MenuManager::MenuItem.new(:testing, '/test', { })
@response.body = render_single_menu_node(node, 'This is a test', node.url, false)
assert_select("a.testing", "This is a test")
end
def test_render_menu_node
single_node = Redmine::MenuManager::MenuItem.new(:single_node, '/test', { })
@response.body = render_menu_node(single_node, nil)
assert_select("li") do
assert_select("a.single-node", "Single node")
end
end
def test_render_menu_node_with_nested_items
parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { })
parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { })
parent_node << Redmine::MenuManager::MenuItem.new(:child_two_node, '/test', { })
parent_node <<
Redmine::MenuManager::MenuItem.new(:child_three_node, '/test', { }) <<
Redmine::MenuManager::MenuItem.new(:child_three_inner_node, '/test', { })
@response.body = render_menu_node(parent_node, nil)
assert_select("li") do
assert_select("a.parent-node", "Parent node")
assert_select("ul") do
assert_select("li a.child-one-node", "Child one node")
assert_select("li a.child-two-node", "Child two node")
assert_select("li") do
assert_select("a.child-three-node", "Child three node")
assert_select("ul") do
assert_select("li a.child-three-inner-node", "Child three inner node")
end
end
end
end
end
def test_menu_items_for_should_yield_all_items_if_passed_a_block
menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, '/', { })
menu.push(:a_menu_2, '/', { })
menu.push(:a_menu_3, '/', { })
end
items_yielded = []
menu_items_for(menu_name) do |item|
items_yielded << item
end
assert_equal 3, items_yielded.size
end
def test_menu_items_for_should_return_all_items
menu_name = :test_menu_items_for_should_return_all_items
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, '/', { })
menu.push(:a_menu_2, '/', { })
menu.push(:a_menu_3, '/', { })
end
items = menu_items_for(menu_name)
assert_equal 3, items.size
end
def test_menu_items_for_should_skip_unallowed_items_on_a_project
menu_name = :test_menu_items_for_should_skip_unallowed_items_on_a_project
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
menu.push(:a_menu_2, {:controller => 'issues', :action => 'index' }, { })
menu.push(:unallowed, {:controller => 'issues', :action => 'unallowed' }, { })
end
User.current = User.find(2)
items = menu_items_for(menu_name, Project.find(1))
assert_equal 2, items.size
end
def test_menu_items_for_should_skip_items_that_fail_the_conditions
menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions
Redmine::MenuManager.map menu_name do |menu|
menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
menu.push(:unallowed,
{:controller => 'issues', :action => 'index' },
{ :if => Proc.new { false }})
end
User.current = User.find(2)
items = menu_items_for(menu_name, Project.find(1))
assert_equal 1, items.size
end
end

View File

@ -0,0 +1,108 @@
# Redmine - project management software
# Copyright (C) 2006-2009 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'
module RedmineMenuTestHelper
# Helpers
def get_menu_item(menu_name, item_name)
Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
end
end
class Redmine::MenuManager::MenuItemTest < Test::Unit::TestCase
include RedmineMenuTestHelper
Redmine::MenuManager.map :test_menu do |menu|
menu.push(:parent_menu, '/test', { })
menu.push(:child_menu, '/test', { :parent_menu => :parent_menu})
menu.push(:child2_menu, '/test', { :parent_menu => :parent_menu})
end
context "MenuItem#caption" do
should "be tested"
end
context "MenuItem#html_options" do
should "be tested"
end
# context new menu item
def test_new_menu_item_should_require_a_name
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new
end
end
def test_new_menu_item_should_require_an_url
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_missing_url)
end
end
def test_new_menu_item_should_require_the_options
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_missing_options, '/test')
end
end
def test_new_menu_item_with_all_required_parameters
assert Redmine::MenuManager::MenuItem.new(:test_good_menu, '/test', {})
end
def test_new_menu_item_should_require_a_proc_to_use_for_the_if_condition
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_error, '/test',
{
:if => ['not_a_proc']
})
end
assert Redmine::MenuManager::MenuItem.new(:test_good_if, '/test',
{
:if => Proc.new{}
})
end
def test_new_menu_item_should_allow_a_hash_for_extra_html_options
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_error, '/test',
{
:html => ['not_a_hash']
})
end
assert Redmine::MenuManager::MenuItem.new(:test_good_html, '/test',
{
:html => { :onclick => 'doSomething'}
})
end
def test_new_should_not_allow_setting_the_parent_menu_item_to_the_current_item
assert_raises ArgumentError do
Redmine::MenuManager::MenuItem.new(:test_error, '/test', { :parent_menu => :test_error })
end
end
def test_has_children
parent_item = get_menu_item(:test_menu, :parent_menu)
assert parent_item.hasChildren?
assert_equal 2, parent_item.children.size
assert_equal get_menu_item(:test_menu, :child_menu), parent_item.children[0]
assert_equal get_menu_item(:test_menu, :child2_menu), parent_item.children[1]
end
end

View File

@ -0,0 +1,28 @@
# Redmine - project management software
# Copyright (C) 2006-2009 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'
class Redmine::MenuManagerTest < Test::Unit::TestCase
context "MenuManager#map" do
should "be tested"
end
context "MenuManager#items" do
should "be tested"
end
end

View File

@ -0,0 +1,84 @@
# Redmine - project management software
# Copyright (C) 2006-2009 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'
module RedmineMenuTestHelper
# Assertions
def assert_number_of_items_in_menu(menu_name, count)
assert Redmine::MenuManager.items(menu_name).size >= count, "Menu has less than #{count} items"
end
def assert_menu_contains_item_named(menu_name, item_name)
assert Redmine::MenuManager.items(menu_name).collect(&:name).include?(item_name.to_sym), "Menu did not have an item named #{item_name}"
end
# Helpers
def get_menu_item(menu_name, item_name)
Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
end
end
class RedmineTest < Test::Unit::TestCase
include RedmineMenuTestHelper
def test_top_menu
assert_number_of_items_in_menu :top_menu, 5
assert_menu_contains_item_named :top_menu, :home
assert_menu_contains_item_named :top_menu, :my_page
assert_menu_contains_item_named :top_menu, :projects
assert_menu_contains_item_named :top_menu, :administration
assert_menu_contains_item_named :top_menu, :help
end
def test_account_menu
assert_number_of_items_in_menu :account_menu, 4
assert_menu_contains_item_named :account_menu, :login
assert_menu_contains_item_named :account_menu, :register
assert_menu_contains_item_named :account_menu, :my_account
assert_menu_contains_item_named :account_menu, :logout
end
def test_application_menu
assert_number_of_items_in_menu :application_menu, 0
end
def test_admin_menu
assert_number_of_items_in_menu :admin_menu, 0
end
def test_project_menu
assert_number_of_items_in_menu :project_menu, 12
assert_menu_contains_item_named :project_menu, :overview
assert_menu_contains_item_named :project_menu, :activity
assert_menu_contains_item_named :project_menu, :roadmap
assert_menu_contains_item_named :project_menu, :issues
assert_menu_contains_item_named :project_menu, :new_issue
assert_menu_contains_item_named :project_menu, :news
assert_menu_contains_item_named :project_menu, :documents
assert_menu_contains_item_named :project_menu, :wiki
assert_menu_contains_item_named :project_menu, :boards
assert_menu_contains_item_named :project_menu, :files
assert_menu_contains_item_named :project_menu, :repository
assert_menu_contains_item_named :project_menu, :settings
end
def test_new_issue_should_have_root_as_a_parent
new_issue = get_menu_item(:project_menu, :new_issue)
assert_equal :root, new_issue.parent.name
end
end

View File

@ -0,0 +1,80 @@
--- !ruby/object:Gem::Specification
name: rubytree
version: !ruby/object:Gem::Version
version: 0.5.2
platform: ruby
authors:
- Anupam Sengupta
autorequire: tree
bindir: bin
cert_chain: []
date: 2007-12-20 00:00:00 -08:00
default_executable:
dependencies:
- !ruby/object:Gem::Dependency
name: hoe
type: :runtime
version_requirement:
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: 1.3.0
version:
description: "Provides a generic tree data-structure with ability to store keyed node-elements in the tree. The implementation mixes in the Enumerable module. Website: http://rubytree.rubyforge.org/"
email: anupamsg@gmail.com
executables: []
extensions: []
extra_rdoc_files:
- README
- COPYING
- ChangeLog
- History.txt
files:
- COPYING
- ChangeLog
- History.txt
- Manifest.txt
- README
- Rakefile
- TODO
- lib/tree.rb
- lib/tree/binarytree.rb
- setup.rb
- test/test_binarytree.rb
- test/test_tree.rb
has_rdoc: true
homepage: http://rubytree.rubyforge.org/
licenses: []
post_install_message:
rdoc_options:
- --main
- README
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: "0"
version:
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: "0"
version:
requirements: []
rubyforge_project: rubytree
rubygems_version: 1.3.5
signing_key:
specification_version: 2
summary: Ruby implementation of the Tree data structure.
test_files:
- test/test_binarytree.rb
- test/test_tree.rb

31
vendor/gems/rubytree-0.5.2/COPYING vendored Normal file
View File

@ -0,0 +1,31 @@
RUBYTREE - http://rubytree.rubyforge.org
========================================
Copyright (c) 2006, 2007 Anupam Sengupta
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
- Neither the name of the organization nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

163
vendor/gems/rubytree-0.5.2/ChangeLog vendored Normal file
View File

@ -0,0 +1,163 @@
2007-12-21 Anupam Sengupta <anupamsg@gmail.com>
* Rakefile: Added the rcov option to exclude rcov itself from
coverage reports.
* lib/tree.rb: Minor comment changes.
* test/test_tree.rb: Added the TestTree enclosing module, and
renamed tests to meet ZenTest requirements. Also added a few
missing test cases.
* test/test_binarytree.rb: Added the TestTree enclosing Module,
and renamed the tests to meet ZenTest requirements.
2007-12-19 Anupam Sengupta <anupamsg@gmail.com>
* README (Module): Modified the install instructions from source.
* lib/tree.rb (Tree::TreeNode::initialize): Removed the
unnecessary self_initialize method.
(Tree::TreeNode): Removed the spurious self_initialize from the
protected list.
(Module): Updated the minor version number.
* Rakefile: Fixed a problem with reading the Tree::VERSION for the
gem packaging, if any prior version of the gem is already installed.
2007-12-18 Anupam Sengupta <anupamsg@gmail.com>
* lib/tree.rb: Updated the marshalling logic to correctly handle
non-string content.
(Tree::TreeNode::createDumpRep): Minor code change to use symbols
instead of string key names.
(Tree): Version number change to 0.5.0
(Tree::TreeNode::hasContent): Minor fix to the comments.
* test/test_tree.rb (TC_TreeTest::test_breadth_each): Updated test
cases for the marshalling logic.
2007-11-12 Anupam Sengupta <anupamsg@gmail.com>
* test/test_binarytree.rb: Minor documentation correction.
* lib/tree/binarytree.rb (Tree::BinaryTreeNode::isRightChild):
Minor documentation change.
2007-10-10 Anupam Sengupta <anupamsg@gmail.com>
* README: Restructured the format.
* Rakefile: Added Hoe related logic. If not present, the Rakefile
will default to old behavior.
2007-10-09 Anupam Sengupta <anupamsg@gmail.com>
* Rakefile: Added setup.rb related tasks. Also added the setup.rb in the PKG_FILES list.
2007-10-01 Anupam Sengupta <anupamsg@gmail.com>
* Rakefile: Added an optional task for rcov code coverage.
Added a dependency for rake in the Gem Specification.
* test/test_binarytree.rb: Removed the unnecessary dependency on "Person" class.
* test/test_tree.rb: Removed dependency on the redundant "Person" class.
(TC_TreeTest::test_comparator): Added a new test for the spaceship operator.
(TC_TreeTest::test_hasContent): Added tests for hasContent? and length methods.
2007-08-30 Anupam Sengupta <anupamsg@gmail.com>
* test/test_tree.rb (TC_TreeTest::test_preordered_each, TC_TreeTest::test_breadth_each, TC_TreeTest::test_detached_copy):
Added new tests for the new functions added to tree.rb.
* lib/tree.rb (Tree::TreeNode::detached_copy, Tree::TreeNode::preordered_each, Tree::TreeNode::breadth_each):
Added new functions for returning a detached copy of the node and
for performing breadth first traversal. Also added the pre-ordered
traversal function which is an alias of the existing 'each' method.
* test/test_binarytree.rb (TC_BinaryTreeTest::test_swap_children):
Added a test case for the children swap function.
* lib/tree/binarytree.rb (Tree::BinaryTreeNode::swap_children):
Added new function to swap the children. Other minor changes in
comments and code.
2007-07-18 Anupam Sengupta <anupamsg@gmail.com>
* lib/tree/binarytree.rb (Tree::BinaryTreeNode::leftChild /
rightChild): Minor cosmetic change on the parameter name.
* test/testbinarytree.rb (TC_BinaryTreeTest::test_isLeftChild):
Minor syntax correction.
* lib/tree.rb (Tree::TreeNode::depth): Added a tree depth
computation method.
(Tree::TreeNode::breadth): Added a tree breadth method.
* test/testtree.rb (TC_TreeTest::test_depth/test_breadth): Added a
test for the depth and breadth method.
* lib/tree/binarytree.rb (Tree::BinaryTreeNode::is*Child):
Added tests for determining whether a node is a left or right
child.
* test/testbinarytree.rb: Added the test cases for the binary tree
implementation.
(TC_BinaryTreeTest::test_is*Child): Added tests for right or left
childs.
* lib/tree/binarytree.rb: Added the binary tree implementation.
2007-07-17 Anupam Sengupta <anupamsg@gmail.com>
* lib/tree.rb (Tree::TreeNode::parentage): Renamed 'ancestors'
method to 'parentage' to avoid clobbering Module.ancestors
2007-07-16 Anupam Sengupta <anupamsg@gmail.com>
* Rakefile: Added an optional rtags task to generate TAGS file for
Emacs.
* lib/tree.rb (Tree::TreeNode): Added navigation methods for
siblings and children. Also added some convenience methods.
2007-07-08 Anupam Sengupta <anupamsg@gmail.com>
* Rakefile: Added a developer target for generating rdoc for the
website.
2007-06-24 Anupam Sengupta <anupamsg@gmail.com>
* test/testtree.rb, lib/tree.rb: Added the each_leaf traversal method.
* README: Replaced all occurrances of LICENSE with COPYING
and lowercased all instances of the word 'RubyTree'.
* Rakefile: Replaced all occurrances of LICENSE with COPYING
2007-06-23 Anupam Sengupta <anupamsg@gmail.com>
* lib/tree.rb (Tree::TreeNode::isLeaf): Added a isLeaf? method.
* test/testtree.rb (TC_TreeTest::test_removeFromParent): Added
test for isLeaf? method
* Rakefile: Added the LICENSE and ChangeLog to the extra RDoc files.
* lib/tree.rb: Minor updates to the comments.
* test/testtree.rb: Added the Copyright and License header.
* test/person.rb: Added the Copyright and License header.
* lib/tree.rb: Added the Copyright and License header.
* Rakefile: Added the LICENSE and Changelog to be part of the RDoc task.
* README: Added documentation in the README, including install
instructions and an example.
* LICENSE: Added the BSD LICENSE file.
* Changelog: Added the Changelog file.

20
vendor/gems/rubytree-0.5.2/History.txt vendored Normal file
View File

@ -0,0 +1,20 @@
= 0.5.2 / 2007-12-21
* Added more test cases and enabled ZenTest compatibility for the test case
names.
= 0.5.1 / 2007-12-20
* Minor code refactoring.
= 0.5.0 / 2007-12-18
* Fixed the marshalling code to correctly handle non-string content.
= 0.4.3 / 2007-10-09
* Changes to the build mechanism (now uses Hoe).
= 0.4.2 / 2007-10-01
* Minor code refactoring. Changes in the Rakefile.

12
vendor/gems/rubytree-0.5.2/Manifest.txt vendored Normal file
View File

@ -0,0 +1,12 @@
COPYING
ChangeLog
History.txt
Manifest.txt
README
Rakefile
TODO
lib/tree.rb
lib/tree/binarytree.rb
setup.rb
test/test_binarytree.rb
test/test_tree.rb

147
vendor/gems/rubytree-0.5.2/README vendored Normal file
View File

@ -0,0 +1,147 @@
__ _ _
/__\_ _| |__ _ _| |_ _ __ ___ ___
/ \// | | | '_ \| | | | __| '__/ _ \/ _ \
/ _ \ |_| | |_) | |_| | |_| | | __/ __/
\/ \_/\__,_|_.__/ \__, |\__|_| \___|\___|
|___/
(c) 2006, 2007 Anupam Sengupta
http://rubytree.rubyforge.org
Rubytree is a simple implementation of the generic Tree data structure. This
implementation is node-centric, where the individual nodes on the tree are the
primary objects and drive the structure.
== INSTALL:
Rubytree is an open source project and is hosted at:
http://rubytree.rubyforge.org
Rubytree can be downloaded as a Rubygem or as a tar/zip file from:
http://rubyforge.org/frs/?group_id=1215&release_id=8817
The file-name is one of:
rubytree-<VERSION>.gem - The Rubygem
rubytree-<VERSION>.tgz - GZipped source files
rubytree-<VERSION>.zip - Zipped source files
Download the appropriate file-type for your system.
It is recommended to install Rubytree as a Ruby Gem, as this is an easy way to
keep the version updated, and keep multiple versions of the library available on
your system.
=== Installing the Gem
To Install the Gem, from a Terminal/CLI command prompt, issue the command:
gem install rubytree
This should install the gem file for Rubytree. Note that you may need to be a
super-user (root) to successfully install the gem.
=== Installing from the tgz/zip file
Extract the archive file (tgz or zip) and run the following command from the
top-level source directory:
ruby ./setup.rb
You may need administrator/super-user privileges to complete the setup using
this method.
== DOCUMENTATION:
The primary class for this implementation is Tree::TreeNode. See the
class documentation for an usage example.
From a command line/terminal prompt, you can issue the following command to view
the text mode ri documentation:
ri Tree::TreeNode
Documentation on the web is available at:
http://rubytree.rubyforge.org/rdoc
== EXAMPLE:
The following code-snippet implements this tree structure:
+------------+
| ROOT |
+-----+------+
+-------------+------------+
| |
+-------+-------+ +-------+-------+
| CHILD 1 | | CHILD 2 |
+-------+-------+ +---------------+
|
|
+-------+-------+
| GRANDCHILD 1 |
+---------------+
require 'tree'
myTreeRoot = Tree::TreeNode.new("ROOT", "Root Content")
myTreeRoot << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content")
myTreeRoot << Tree::TreeNode.new("CHILD2", "Child2 Content")
myTreeRoot.printTree
child1 = myTreeRoot["CHILD1"]
grandChild1 = myTreeRoot["CHILD1"]["GRANDCHILD1"]
siblingsOfChild1Array = child1.siblings
immediateChildrenArray = myTreeRoot.children
# Process all nodes
myTreeRoot.each { |node| node.content.reverse }
myTreeRoot.remove!(child1) # Remove the child
== LICENSE:
Rubytree is licensed under BSD license.
Copyright (c) 2006, 2007 Anupam Sengupta
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
- Neither the name of the organization nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
(Document Revision: $Revision: 1.16 $ by $Author: anupamsg $)

212
vendor/gems/rubytree-0.5.2/Rakefile vendored Normal file
View File

@ -0,0 +1,212 @@
# Rakefile
#
# $Revision: 1.27 $ by $Author: anupamsg $
# $Name: $
#
# Copyright (c) 2006, 2007 Anupam Sengupta
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# - Neither the name of the organization nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
require 'rubygems'
require 'rake/gempackagetask'
require 'rake/clean'
require 'rake/packagetask'
require 'rake/testtask'
require 'rake/rdoctask'
require 'fileutils'
# General Stuff ####################################################
$:.insert 0, File.expand_path( File.join( File.dirname(__FILE__), 'lib' ) )
require 'tree' # To read the version information.
PKG_NAME = "rubytree"
PKG_VERSION = Tree::VERSION
PKG_FULLNAME = PKG_NAME + "-" + PKG_VERSION
PKG_SUMMARY = "Ruby implementation of the Tree data structure."
PKG_DESCRIPTION = <<-END
Provides a generic tree data-structure with ability to
store keyed node-elements in the tree. The implementation
mixes in the Enumerable module.
Website: http://rubytree.rubyforge.org/
END
PKG_FILES = FileList[
'[A-Z]*',
'*.rb',
'lib/**/*.rb',
'test/**/*.rb'
]
# Default is to create a rubygem.
desc "Default Task"
task :default => :gem
begin # Try loading hoe
require 'hoe'
# If Hoe is found, use it to define tasks
# =======================================
Hoe.new(PKG_NAME, PKG_VERSION) do |p|
p.rubyforge_name = PKG_NAME
p.author = "Anupam Sengupta"
p.email = "anupamsg@gmail.com"
p.summary = PKG_SUMMARY
p.description = PKG_DESCRIPTION
p.url = "http://rubytree.rubyforge.org/"
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
p.remote_rdoc_dir = 'rdoc'
p.need_tar = true
p.need_zip = true
p.test_globs = ['test/test_*.rb']
p.spec_extras = {
:has_rdoc => true,
:platform => Gem::Platform::RUBY,
:has_rdoc => true,
:extra_rdoc_files => ['README', 'COPYING', 'ChangeLog', 'History.txt'],
:rdoc_options => ['--main', 'README'],
:autorequire => 'tree'
}
end
rescue LoadError # If Hoe is not found
# If Hoe is not found, then use the usual Gemspec based Rake tasks
# ================================================================
spec = Gem::Specification.new do |s|
s.name = PKG_NAME
s.version = PKG_VERSION
s.platform = Gem::Platform::RUBY
s.author = "Anupam Sengupta"
s.email = "anupamsg@gmail.com"
s.homepage = "http://rubytree.rubyforge.org/"
s.rubyforge_project = 'rubytree'
s.summary = PKG_SUMMARY
s.add_dependency('rake', '>= 0.7.2')
s.description = PKG_DESCRIPTION
s.has_rdoc = true
s.extra_rdoc_files = ['README', 'COPYING', 'ChangeLog']
s.autorequire = "tree"
s.files = PKG_FILES.to_a
s.test_files = Dir.glob('test/test*.rb')
end
desc "Prepares for installation"
task :prepare do
ruby "setup.rb config"
ruby "setup.rb setup"
end
desc "Installs the package #{PKG_NAME}"
task :install => [:prepare] do
ruby "setup.rb install"
end
Rake::GemPackageTask.new(spec) do |pkg|
pkg.need_zip = true
pkg.need_tar = true
end
Rake::TestTask.new do |t|
t.libs << "test"
t.test_files = FileList['test/test*.rb']
t.verbose = true
end
end # End loading Hoerc
# ================================================================
# The following tasks are loaded independently of Hoe
# Hoe's rdoc task is ugly.
Rake::RDocTask.new(:docs) do |rd|
rd.rdoc_files.include("README", "COPYING", "ChangeLog", "lib/**/*.rb")
rd.rdoc_dir = 'doc'
rd.title = "#{PKG_FULLNAME} Documentation"
# Use the template only if it is present, otherwise, the standard template is
# used.
template = "../allison/allison.rb"
rd.template = template if File.file?(template)
rd.options << '--line-numbers' << '--inline-source'
end
# Optional TAGS Task.
# Needs https://rubyforge.org/projects/rtagstask/
begin
require 'rtagstask'
RTagsTask.new do |rd|
rd.vi = false
end
rescue LoadError
end
# Optional RCOV Task
# Needs http://eigenclass.org/hiki/rcov
begin
require 'rcov/rcovtask'
Rcov::RcovTask.new do |t|
t.test_files = FileList['test/test*.rb']
t.rcov_opts << "--exclude 'rcov.rb'" # rcov itself should not be profiled
# t.verbose = true # uncomment to see the executed commands
end
rescue LoadError
end
#Rakefile,v $
# Revision 1.21 2007/07/21 05:14:43 anupamsg
# Added a VERSION constant to the Tree module,
# and using the same in the Rakefile.
#
# Revision 1.20 2007/07/21 03:24:25 anupamsg
# Minor edits to parameter names. User visible functionality does not change.
#
# Revision 1.19 2007/07/19 02:16:01 anupamsg
# Release 0.4.0 (and minor fix in Rakefile).
#
# Revision 1.18 2007/07/18 20:15:06 anupamsg
# Added two predicate methods in BinaryTreeNode to determine whether a node
# is a left or a right node.
#
# Revision 1.17 2007/07/18 07:17:34 anupamsg
# Fixed a issue where TreeNode.ancestors was shadowing Module.ancestors. This method
# has been renamed to TreeNode.parentage.
#
# Revision 1.16 2007/07/17 05:34:03 anupamsg
# Added an optional tags Rake-task for generating the TAGS file for Emacs.
#
# Revision 1.15 2007/07/17 04:42:45 anupamsg
# Minor fixes to the Rakefile.
#
# Revision 1.14 2007/07/17 03:39:28 anupamsg
# Moved the CVS Log keyword to end of the files.
#

7
vendor/gems/rubytree-0.5.2/TODO vendored Normal file
View File

@ -0,0 +1,7 @@
# -*- mode: outline; coding: utf-8-unix; -*-
* Add logic in Rakefile to read the file list from Manifest.txt file.
* Add a YAML export method to the TreeNode class.

539
vendor/gems/rubytree-0.5.2/lib/tree.rb vendored Normal file
View File

@ -0,0 +1,539 @@
# tree.rb
#
# $Revision: 1.29 $ by $Author: anupamsg $
# $Name: $
#
# = tree.rb - Generic Multi-way Tree implementation
#
# Provides a generic tree data structure with ability to
# store keyed node elements in the tree. The implementation
# mixes in the Enumerable module.
#
# Author:: Anupam Sengupta (anupamsg@gmail.com)
#
# Copyright (c) 2006, 2007 Anupam Sengupta
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# - Neither the name of the organization nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# This module provides a TreeNode class which is the primary class for all
# nodes represented in the Tree.
# This module mixes in the Enumerable module.
module Tree
# Rubytree Package Version
VERSION = '0.5.2'
# == TreeNode Class Description
#
# The node class for the tree representation. the nodes are named and have a
# place-holder for the node data (i.e., the `content' of the node). The node
# names are expected to be unique. In addition, the node provides navigation
# methods to traverse the tree.
#
# The nodes can have any number of child nodes attached to it. Note that while
# this implementation does not support directed graphs, the class itself makes
# no restrictions on associating a node's CONTENT with multiple parent nodes.
#
#
# == Example
#
# The following code-snippet implements this tree structure:
#
# +------------+
# | ROOT |
# +-----+------+
# +-------------+------------+
# | |
# +-------+-------+ +-------+-------+
# | CHILD 1 | | CHILD 2 |
# +-------+-------+ +---------------+
# |
# |
# +-------+-------+
# | GRANDCHILD 1 |
# +---------------+
#
# require 'tree'
#
# myTreeRoot = Tree::TreeNode.new("ROOT", "Root Content")
#
# myTreeRoot << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content")
#
# myTreeRoot << Tree::TreeNode.new("CHILD2", "Child2 Content")
#
# myTreeRoot.printTree
#
# child1 = myTreeRoot["CHILD1"]
#
# grandChild1 = myTreeRoot["CHILD1"]["GRANDCHILD1"]
#
# siblingsOfChild1Array = child1.siblings
#
# immediateChildrenArray = myTreeRoot.children
#
# # Process all nodes
#
# myTreeRoot.each { |node| node.content.reverse }
#
# myTreeRoot.remove!(child1) # Remove the child
class TreeNode
include Enumerable
attr_reader :content, :name, :parent
attr_writer :content
# Constructor which expects the name of the node
#
# Name of the node is expected to be unique across the
# tree.
#
# The content can be of any type, and is defaulted to _nil_.
def initialize(name, content = nil)
raise "Node name HAS to be provided" if name == nil
@name = name
@content = content
self.setAsRoot!
@childrenHash = Hash.new
@children = []
end
# Returns a copy of this node, with the parent and children links removed.
def detached_copy
Tree::TreeNode.new(@name, @content ? @content.clone : nil)
end
# Print the string representation of this node.
def to_s
"Node Name: #{@name}" +
" Content: " + (@content || "<Empty>") +
" Parent: " + (isRoot?() ? "<None>" : @parent.name) +
" Children: #{@children.length}" +
" Total Nodes: #{size()}"
end
# Returns an array of ancestors in reversed order (the first element is the
# immediate parent). Returns nil if this is a root node.
def parentage
return nil if isRoot?
parentageArray = []
prevParent = self.parent
while (prevParent)
parentageArray << prevParent
prevParent = prevParent.parent
end
parentageArray
end
# Protected method to set the parent node.
# This method should NOT be invoked by client code.
def parent=(parent)
@parent = parent
end
# Convenience synonym for TreeNode#add method. This method allows a convenient
# method to add children hierarchies in the tree.
#
# E.g. root << child << grand_child
def <<(child)
add(child)
end
# Adds the specified child node to the receiver node. The child node's
# parent is set to be the receiver. The child is added as the last child in
# the current list of children for the receiver node.
def add(child)
raise "Child already added" if @childrenHash.has_key?(child.name)
@childrenHash[child.name] = child
@children << child
child.parent = self
return child
end
# Removes the specified child node from the receiver node. The removed
# children nodes are orphaned but available if an alternate reference
# exists.
#
# Returns the child node.
def remove!(child)
@childrenHash.delete(child.name)
@children.delete(child)
child.setAsRoot! unless child == nil
return child
end
# Removes this node from its parent. If this is the root node, then does
# nothing.
def removeFromParent!
@parent.remove!(self) unless isRoot?
end
# Removes all children from the receiver node.
def removeAll!
for child in @children
child.setAsRoot!
end
@childrenHash.clear
@children.clear
self
end
# Indicates whether this node has any associated content.
def hasContent?
@content != nil
end
# Protected method which sets this node as a root node.
def setAsRoot!
@parent = nil
end
# Indicates whether this node is a root node. Note that
# orphaned children will also be reported as root nodes.
def isRoot?
@parent == nil
end
# Indicates whether this node has any immediate child nodes.
def hasChildren?
@children.length != 0
end
# Indicates whether this node is a 'leaf' - i.e., one without
# any children
def isLeaf?
!hasChildren?
end
# Returns an array of all the immediate children. If a block is given,
# yields each child node to the block.
def children
if block_given?
@children.each {|child| yield child}
else
@children
end
end
# Returns the first child of this node. Will return nil if no children are
# present.
def firstChild
children.first
end
# Returns the last child of this node. Will return nil if no children are
# present.
def lastChild
children.last
end
# Returns every node (including the receiver node) from the tree to the
# specified block. The traversal is depth first and from left to right in
# pre-ordered sequence.
def each &block
yield self
children { |child| child.each(&block) }
end
# Traverses the tree in a pre-ordered sequence. This is equivalent to
# TreeNode#each
def preordered_each &block
each(&block)
end
# Performs breadth first traversal of the tree rooted at this node. The
# traversal in a given level is from left to right.
def breadth_each &block
node_queue = [self] # Create a queue with self as the initial entry
# Use a queue to do breadth traversal
until node_queue.empty?
node_to_traverse = node_queue.shift
yield node_to_traverse
# Enqueue the children from left to right.
node_to_traverse.children { |child| node_queue.push child }
end
end
# Yields all leaf nodes from this node to the specified block. May yield
# this node as well if this is a leaf node. Leaf traversal depth first and
# left to right.
def each_leaf &block
self.each { |node| yield(node) if node.isLeaf? }
end
# Returns the requested node from the set of immediate children.
#
# If the parameter is _numeric_, then the in-sequence array of children is
# accessed (see Tree#children). If the parameter is not _numeric_, then it
# is assumed to be the *name* of the child node to be returned.
def [](name_or_index)
raise "Name_or_index needs to be provided" if name_or_index == nil
if name_or_index.kind_of?(Integer)
@children[name_or_index]
else
@childrenHash[name_or_index]
end
end
# Returns the total number of nodes in this tree, rooted at the receiver
# node.
def size
@children.inject(1) {|sum, node| sum + node.size}
end
# Convenience synonym for Tree#size
def length
size()
end
# Pretty prints the tree starting with the receiver node.
def printTree(level = 0)
if isRoot?
print "*"
else
print "|" unless parent.isLastSibling?
print(' ' * (level - 1) * 4)
print(isLastSibling? ? "+" : "|")
print "---"
print(hasChildren? ? "+" : ">")
end
puts " #{name}"
children { |child| child.printTree(level + 1)}
end
# Returns the root for this tree. Root's root is itself.
def root
root = self
root = root.parent while !root.isRoot?
root
end
# Returns the first sibling for this node. If this is the root node, returns
# itself.
def firstSibling
if isRoot?
self
else
parent.children.first
end
end
# Returns true if this node is the first sibling.
def isFirstSibling?
firstSibling == self
end
# Returns the last sibling for this node. If this node is the root, returns
# itself.
def lastSibling
if isRoot?
self
else
parent.children.last
end
end
# Returns true if his node is the last sibling
def isLastSibling?
lastSibling == self
end
# Returns an array of siblings for this node.
# If a block is provided, yields each of the sibling
# nodes to the block. The root always has nil siblings.
def siblings
return nil if isRoot?
if block_given?
for sibling in parent.children
yield sibling if sibling != self
end
else
siblings = []
parent.children {|sibling| siblings << sibling if sibling != self}
siblings
end
end
# Returns true if this node is the only child of its parent
def isOnlyChild?
parent.children.size == 1
end
# Returns the next sibling for this node. Will return nil if no subsequent
# node is present.
def nextSibling
if myidx = parent.children.index(self)
parent.children.at(myidx + 1)
end
end
# Returns the previous sibling for this node. Will return nil if no
# subsequent node is present.
def previousSibling
if myidx = parent.children.index(self)
parent.children.at(myidx - 1) if myidx > 0
end
end
# Provides a comparision operation for the nodes. Comparision
# is based on the natural character-set ordering for the
# node names.
def <=>(other)
return +1 if other == nil
self.name <=> other.name
end
# Freezes all nodes in the tree
def freezeTree!
each {|node| node.freeze}
end
# Creates the marshal-dump represention of the tree rooted at this node.
def marshal_dump
self.collect { |node| node.createDumpRep }
end
# Creates a dump representation and returns the same as a hash.
def createDumpRep
{ :name => @name, :parent => (isRoot? ? nil : @parent.name), :content => Marshal.dump(@content)}
end
# Loads a marshalled dump of the tree and returns the root node of the
# reconstructed tree. See the Marshal class for additional details.
def marshal_load(dumped_tree_array)
nodes = { }
for node_hash in dumped_tree_array do
name = node_hash[:name]
parent_name = node_hash[:parent]
content = Marshal.load(node_hash[:content])
if parent_name then
nodes[name] = current_node = Tree::TreeNode.new(name, content)
nodes[parent_name].add current_node
else
# This is the root node, hence initialize self.
initialize(name, content)
nodes[name] = self # Add self to the list of nodes
end
end
end
# Returns depth of the tree from this node. A single leaf node has a
# depth of 1.
def depth
return 1 if isLeaf?
1 + @children.collect { |child| child.depth }.max
end
# Returns breadth of the tree at this node level. A single node has a
# breadth of 1.
def breadth
return 1 if isRoot?
parent.children.size
end
protected :parent=, :setAsRoot!, :createDumpRep
end
end
# $Log: tree.rb,v $
# Revision 1.29 2007/12/22 00:28:59 anupamsg
# Added more test cases, and enabled ZenTest compatibility.
#
# Revision 1.28 2007/12/20 03:19:33 anupamsg
# * README (Module): Modified the install instructions from source.
# (Module): Updated the minor version number.
#
# Revision 1.27 2007/12/20 03:00:03 anupamsg
# Minor code changes. Removed self_initialize from the protected methods' list.
#
# Revision 1.26 2007/12/20 02:50:04 anupamsg
# (Tree::TreeNode): Removed the spurious self_initialize from the protected list.
#
# Revision 1.25 2007/12/19 20:28:05 anupamsg
# Removed the unnecesary self_initialize method.
#
# Revision 1.24 2007/12/19 06:39:17 anupamsg
# Removed the unnecessary field and record separator constants. Also updated the
# history.txt file.
#
# Revision 1.23 2007/12/19 06:25:00 anupamsg
# (Tree::TreeNode): Minor fix to the comments. Also fixed the private/protected
# scope issue with the createDumpRep method.
#
# Revision 1.22 2007/12/19 06:22:03 anupamsg
# Updated the marshalling logic to correctly handle non-string content. This
# should fix the bug # 15614 ("When dumping with an Object as the content, you get
# a delimiter collision")
#
# Revision 1.21 2007/12/19 02:24:17 anupamsg
# Updated the marshalling logic to handle non-string contents on the nodes.
#
# Revision 1.20 2007/10/10 08:42:57 anupamsg
# Release 0.4.3
#
# Revision 1.19 2007/08/31 01:16:27 anupamsg
# Added breadth and pre-order traversals for the tree. Also added a method
# to return the detached copy of a node from the tree.
#
# Revision 1.18 2007/07/21 05:14:44 anupamsg
# Added a VERSION constant to the Tree module,
# and using the same in the Rakefile.
#
# Revision 1.17 2007/07/21 03:24:25 anupamsg
# Minor edits to parameter names. User visible functionality does not change.
#
# Revision 1.16 2007/07/18 23:38:55 anupamsg
# Minor updates to tree.rb
#
# Revision 1.15 2007/07/18 22:11:50 anupamsg
# Added depth and breadth methods for the TreeNode.
#
# Revision 1.14 2007/07/18 19:33:27 anupamsg
# Added a new binary tree implementation.
#
# Revision 1.13 2007/07/18 07:17:34 anupamsg
# Fixed a issue where TreeNode.ancestors was shadowing Module.ancestors. This method
# has been renamed to TreeNode.parentage.
#
# Revision 1.12 2007/07/17 03:39:28 anupamsg
# Moved the CVS Log keyword to end of the files.
#

View File

@ -0,0 +1,131 @@
# binarytree.rb
#
# $Revision: 1.5 $ by $Author: anupamsg $
# $Name: $
#
# = binarytree.rb - Binary Tree implementation
#
# Provides a generic tree data structure with ability to
# store keyed node elements in the tree. The implementation
# mixes in the Enumerable module.
#
# Author:: Anupam Sengupta (anupamsg@gmail.com)
#
# Copyright (c) 2007 Anupam Sengupta
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# - Neither the name of the organization nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
require 'tree'
module Tree
# Provides a Binary tree implementation. This tree node allows only two child
# nodes (left and right childs). It also provides direct access to the left
# and right children, including assignment to the same.
class BinaryTreeNode < TreeNode
# Adds the specified child node to the receiver node. The child node's
# parent is set to be the receiver. The child nodes are added in the order
# of addition, i.e., the first child added becomes the left node, and the
# second child will be the second node.
# If only one child is present, then this will be the left child.
def add(child)
raise "Already has two child nodes" if @children.size == 2
super(child)
end
# Returns the left child node. Note that
# left Child == first Child
def leftChild
children.first
end
# Returns the right child node. Note that
# right child == last child unless there is only one child.
# Returns nil if the right child does not exist.
def rightChild
children[1]
end
# Sets the left child. If a previous child existed, it is replaced.
def leftChild=(child)
@children[0] = child
@childrenHash[child.name] = child if child # Assign the name mapping
end
# Sets the right child. If a previous child existed, it is replaced.
def rightChild=(child)
@children[1] = child
@childrenHash[child.name] = child if child # Assign the name mapping
end
# Returns true if this is the left child of its parent. Always returns false
# if this is the root node.
def isLeftChild?
return nil if isRoot?
self == parent.leftChild
end
# Returns true if this is the right child of its parent. Always returns false
# if this is the root node.
def isRightChild?
return nil if isRoot?
self == parent.rightChild
end
# Swaps the left and right children with each other
def swap_children
tempChild = leftChild
self.leftChild= rightChild
self.rightChild= tempChild
end
end
end
# $Log: binarytree.rb,v $
# Revision 1.5 2007/12/18 23:11:29 anupamsg
# Minor documentation changes in the binarytree class.
#
# Revision 1.4 2007/08/30 22:08:58 anupamsg
# Added a new swap_children method for Binary Tree. Also added minor
# documentation and test updates.
#
# Revision 1.3 2007/07/21 03:24:25 anupamsg
# Minor edits to parameter names. User visible functionality does not change.
#
# Revision 1.2 2007/07/18 20:15:06 anupamsg
# Added two predicate methods in BinaryTreeNode to determine whether a node
# is a left or a right node.
#
# Revision 1.1 2007/07/18 19:33:27 anupamsg
# Added a new binary tree implementation.
#

1585
vendor/gems/rubytree-0.5.2/setup.rb vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,204 @@
#!/usr/bin/env ruby
# test_binarytree.rb
#
# $Revision: 1.5 $ by $Author: anupamsg $
# $Name: $
#
# Copyright (c) 2006, 2007 Anupam Sengupta
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# - Neither the name of the organization nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
require 'test/unit'
require 'tree/binarytree'
module TestTree
# Test class for the Tree node.
class TestBinaryTreeNode < Test::Unit::TestCase
def setup
@root = Tree::BinaryTreeNode.new("ROOT", "Root Node")
@left_child1 = Tree::BinaryTreeNode.new("A Child at Left", "Child Node @ left")
@right_child1 = Tree::BinaryTreeNode.new("B Child at Right", "Child Node @ right")
end
def teardown
@root.remove!(@left_child1)
@root.remove!(@right_child1)
@root = nil
end
def test_initialize
assert_not_nil(@root, "Binary tree's Root should have been created")
end
def test_add
@root.add @left_child1
assert_same(@left_child1, @root.leftChild, "The left node should be left_child1")
assert_same(@left_child1, @root.firstChild, "The first node should be left_child1")
@root.add @right_child1
assert_same(@right_child1, @root.rightChild, "The right node should be right_child1")
assert_same(@right_child1, @root.lastChild, "The first node should be right_child1")
assert_raise RuntimeError do
@root.add Tree::BinaryTreeNode.new("The third child!")
end
assert_raise RuntimeError do
@root << Tree::BinaryTreeNode.new("The third child!")
end
end
def test_leftChild
@root << @left_child1
@root << @right_child1
assert_same(@left_child1, @root.leftChild, "The left child should be 'left_child1")
assert_not_same(@right_child1, @root.leftChild, "The right_child1 is not the left child")
end
def test_rightChild
@root << @left_child1
@root << @right_child1
assert_same(@right_child1, @root.rightChild, "The right child should be 'right_child1")
assert_not_same(@left_child1, @root.rightChild, "The left_child1 is not the left child")
end
def test_leftChild_equals
@root << @left_child1
@root << @right_child1
assert_same(@left_child1, @root.leftChild, "The left child should be 'left_child1")
@root.leftChild = Tree::BinaryTreeNode.new("New Left Child")
assert_equal("New Left Child", @root.leftChild.name, "The left child should now be the new child")
assert_equal("B Child at Right", @root.lastChild.name, "The last child should now be the right child")
# Now set the left child as nil, and retest
@root.leftChild = nil
assert_nil(@root.leftChild, "The left child should now be nil")
assert_nil(@root.firstChild, "The first child is now nil")
assert_equal("B Child at Right", @root.lastChild.name, "The last child should now be the right child")
end
def test_rightChild_equals
@root << @left_child1
@root << @right_child1
assert_same(@right_child1, @root.rightChild, "The right child should be 'right_child1")
@root.rightChild = Tree::BinaryTreeNode.new("New Right Child")
assert_equal("New Right Child", @root.rightChild.name, "The right child should now be the new child")
assert_equal("A Child at Left", @root.firstChild.name, "The first child should now be the left child")
assert_equal("New Right Child", @root.lastChild.name, "The last child should now be the right child")
# Now set the right child as nil, and retest
@root.rightChild = nil
assert_nil(@root.rightChild, "The right child should now be nil")
assert_equal("A Child at Left", @root.firstChild.name, "The first child should now be the left child")
assert_nil(@root.lastChild, "The first child is now nil")
end
def test_isLeftChild_eh
@root << @left_child1
@root << @right_child1
assert(@left_child1.isLeftChild?, "left_child1 should be the left child")
assert(!@right_child1.isLeftChild?, "left_child1 should be the left child")
# Now set the right child as nil, and retest
@root.rightChild = nil
assert(@left_child1.isLeftChild?, "left_child1 should be the left child")
assert(!@root.isLeftChild?, "Root is neither left child nor right")
end
def test_isRightChild_eh
@root << @left_child1
@root << @right_child1
assert(@right_child1.isRightChild?, "right_child1 should be the right child")
assert(!@left_child1.isRightChild?, "right_child1 should be the right child")
# Now set the left child as nil, and retest
@root.leftChild = nil
assert(@right_child1.isRightChild?, "right_child1 should be the right child")
assert(!@root.isRightChild?, "Root is neither left child nor right")
end
def test_swap_children
@root << @left_child1
@root << @right_child1
assert(@right_child1.isRightChild?, "right_child1 should be the right child")
assert(!@left_child1.isRightChild?, "right_child1 should be the right child")
@root.swap_children
assert(@right_child1.isLeftChild?, "right_child1 should now be the left child")
assert(@left_child1.isRightChild?, "left_child1 should now be the right child")
assert_equal(@right_child1, @root.firstChild, "right_child1 should now be the first child")
assert_equal(@left_child1, @root.lastChild, "left_child1 should now be the last child")
assert_equal(@right_child1, @root[0], "right_child1 should now be the first child")
assert_equal(@left_child1, @root[1], "left_child1 should now be the last child")
end
end
end
# $Log: test_binarytree.rb,v $
# Revision 1.5 2007/12/22 00:28:59 anupamsg
# Added more test cases, and enabled ZenTest compatibility.
#
# Revision 1.4 2007/12/18 23:11:29 anupamsg
# Minor documentation changes in the binarytree class.
#
# Revision 1.3 2007/10/02 03:07:30 anupamsg
# * Rakefile: Added an optional task for rcov code coverage.
#
# * test/test_binarytree.rb: Removed the unnecessary dependency on "Person" class.
#
# * test/test_tree.rb: Removed dependency on the redundant "Person" class.
#
# Revision 1.2 2007/08/30 22:06:13 anupamsg
# Added a new swap_children method for the Binary Tree class.
# Also made minor documentation updates and test additions.
#
# Revision 1.1 2007/07/21 04:52:37 anupamsg
# Renamed the test files.
#
# Revision 1.4 2007/07/19 02:03:57 anupamsg
# Minor syntax correction.
#
# Revision 1.3 2007/07/19 02:02:12 anupamsg
# Removed useless files (including rdoc, which should be generated for each release.
#
# Revision 1.2 2007/07/18 20:15:06 anupamsg
# Added two predicate methods in BinaryTreeNode to determine whether a node
# is a left or a right node.
#

View File

@ -0,0 +1,718 @@
#!/usr/bin/env ruby
# testtree.rb
#
# $Revision: 1.6 $ by $Author: anupamsg $
# $Name: $
#
# Copyright (c) 2006, 2007 Anupam Sengupta
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# - Neither the name of the organization nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
require 'test/unit'
require 'tree'
module TestTree
# Test class for the Tree node.
class TestTreeNode < Test::Unit::TestCase
Person = Struct::new(:First, :last)
def setup
@root = Tree::TreeNode.new("ROOT", "Root Node")
@child1 = Tree::TreeNode.new("Child1", "Child Node 1")
@child2 = Tree::TreeNode.new("Child2", "Child Node 2")
@child3 = Tree::TreeNode.new("Child3", "Child Node 3")
@child4 = Tree::TreeNode.new("Child31", "Grand Child 1")
end
# Create this structure for the tests
#
# +----------+
# | ROOT |
# +-+--------+
# |
# | +---------------+
# +----+ CHILD1 |
# | +---------------+
# |
# | +---------------+
# +----+ CHILD2 |
# | +---------------+
# |
# | +---------------+ +------------------+
# +----+ CHILD3 +---+ CHILD4 |
# +---------------+ +------------------+
#
def loadChildren
@root << @child1
@root << @child2
@root << @child3 << @child4
end
def teardown
@root = nil
end
def test_root_setup
assert_not_nil(@root, "Root cannot be nil")
assert_nil(@root.parent, "Parent of root node should be nil")
assert_not_nil(@root.name, "Name should not be nil")
assert_equal("ROOT", @root.name, "Name should be 'ROOT'")
assert_equal("Root Node", @root.content, "Content should be 'Root Node'")
assert(@root.isRoot?, "Should identify as root")
assert(!@root.hasChildren?, "Cannot have any children")
assert(@root.hasContent?, "This root should have content")
assert_equal(1, @root.size, "Number of nodes should be one")
assert_nil(@root.siblings, "Root cannot have any children")
assert_raise(RuntimeError) { Tree::TreeNode.new(nil) }
end
def test_root
loadChildren
assert_same(@root, @root.root, "Root's root is self")
assert_same(@root, @child1.root, "Root should be ROOT")
assert_same(@root, @child4.root, "Root should be ROOT")
end
def test_hasContent_eh
aNode = Tree::TreeNode.new("A Node")
assert_nil(aNode.content, "The node should not have content")
assert(!aNode.hasContent?, "The node should not have content")
aNode.content = "Something"
assert_not_nil(aNode.content, "The node should now have content")
assert(aNode.hasContent?, "The node should now have content")
end
def test_length
loadChildren
assert_equal(@root.size, @root.length, "Length and size methods should return the same result")
end
def test_spaceship # Test the <=> operator.
firstNode = Tree::TreeNode.new(1)
secondNode = Tree::TreeNode.new(2)
assert_equal(firstNode <=> nil, +1)
assert_equal(firstNode <=> secondNode, -1)
secondNode = Tree::TreeNode.new(1)
assert_equal(firstNode <=> secondNode, 0)
firstNode = Tree::TreeNode.new("ABC")
secondNode = Tree::TreeNode.new("XYZ")
assert_equal(firstNode <=> nil, +1)
assert_equal(firstNode <=> secondNode, -1)
secondNode = Tree::TreeNode.new("ABC")
assert_equal(firstNode <=> secondNode, 0)
end
def test_to_s
aNode = Tree::TreeNode.new("A Node", "Some Content")
expectedString = "Node Name: A Node Content: Some Content Parent: <None> Children: 0 Total Nodes: 1"
assert_equal(expectedString, aNode.to_s, "The string representation should be same")
end
def test_firstSibling
loadChildren
assert_same(@root, @root.firstSibling, "Root's first sibling is itself")
assert_same(@child1, @child1.firstSibling, "Child1's first sibling is itself")
assert_same(@child1, @child2.firstSibling, "Child2's first sibling should be child1")
assert_same(@child1, @child3.firstSibling, "Child3's first sibling should be child1")
assert_not_same(@child1, @child4.firstSibling, "Child4's first sibling is itself")
end
def test_isFirstSibling_eh
loadChildren
assert(@root.isFirstSibling?, "Root's first sibling is itself")
assert( @child1.isFirstSibling?, "Child1's first sibling is itself")
assert(!@child2.isFirstSibling?, "Child2 is not the first sibling")
assert(!@child3.isFirstSibling?, "Child3 is not the first sibling")
assert( @child4.isFirstSibling?, "Child4's first sibling is itself")
end
def test_isLastSibling_eh
loadChildren
assert(@root.isLastSibling?, "Root's last sibling is itself")
assert(!@child1.isLastSibling?, "Child1 is not the last sibling")
assert(!@child2.isLastSibling?, "Child2 is not the last sibling")
assert( @child3.isLastSibling?, "Child3's last sibling is itself")
assert( @child4.isLastSibling?, "Child4's last sibling is itself")
end
def test_lastSibling
loadChildren
assert_same(@root, @root.lastSibling, "Root's last sibling is itself")
assert_same(@child3, @child1.lastSibling, "Child1's last sibling should be child3")
assert_same(@child3, @child2.lastSibling, "Child2's last sibling should be child3")
assert_same(@child3, @child3.lastSibling, "Child3's last sibling should be itself")
assert_not_same(@child3, @child4.lastSibling, "Child4's last sibling is itself")
end
def test_siblings
loadChildren
siblings = []
@child1.siblings { |sibling| siblings << sibling}
assert_equal(2, siblings.length, "Should have two siblings")
assert(siblings.include?(@child2), "Should have 2nd child as sibling")
assert(siblings.include?(@child3), "Should have 3rd child as sibling")
siblings.clear
siblings = @child1.siblings
assert_equal(2, siblings.length, "Should have two siblings")
siblings.clear
@child4.siblings {|sibling| siblings << sibling}
assert(siblings.empty?, "Should not have any children")
end
def test_isOnlyChild_eh
loadChildren
assert(!@child1.isOnlyChild?, "Child1 is not the only child")
assert(!@child2.isOnlyChild?, "Child2 is not the only child")
assert(!@child3.isOnlyChild?, "Child3 is not the only child")
assert( @child4.isOnlyChild?, "Child4 is not the only child")
end
def test_nextSibling
loadChildren
assert_equal(@child2, @child1.nextSibling, "Child1's next sibling is Child2")
assert_equal(@child3, @child2.nextSibling, "Child2's next sibling is Child3")
assert_nil(@child3.nextSibling, "Child3 does not have a next sibling")
assert_nil(@child4.nextSibling, "Child4 does not have a next sibling")
end
def test_previousSibling
loadChildren
assert_nil(@child1.previousSibling, "Child1 does not have previous sibling")
assert_equal(@child1, @child2.previousSibling, "Child2's previous sibling is Child1")
assert_equal(@child2, @child3.previousSibling, "Child3's previous sibling is Child2")
assert_nil(@child4.previousSibling, "Child4 does not have a previous sibling")
end
def test_add
assert(!@root.hasChildren?, "Should not have any children")
@root.add(@child1)
@root << @child2
assert(@root.hasChildren?, "Should have children")
assert_equal(3, @root.size, "Should have three nodes")
@root << @child3 << @child4
assert_equal(5, @root.size, "Should have five nodes")
assert_equal(2, @child3.size, "Should have two nodes")
assert_raise(RuntimeError) { @root.add(Tree::TreeNode.new(@child1.name)) }
end
def test_remove_bang
@root << @child1
@root << @child2
assert(@root.hasChildren?, "Should have children")
assert_equal(3, @root.size, "Should have three nodes")
@root.remove!(@child1)
assert_equal(2, @root.size, "Should have two nodes")
@root.remove!(@child2)
assert(!@root.hasChildren?, "Should have no children")
assert_equal(1, @root.size, "Should have one node")
@root << @child1
@root << @child2
assert(@root.hasChildren?, "Should have children")
assert_equal(3, @root.size, "Should have three nodes")
@root.removeAll!
assert(!@root.hasChildren?, "Should have no children")
assert_equal(1, @root.size, "Should have one node")
end
def test_removeAll_bang
loadChildren
assert(@root.hasChildren?, "Should have children")
@root.removeAll!
assert(!@root.hasChildren?, "Should have no children")
assert_equal(1, @root.size, "Should have one node")
end
def test_removeFromParent_bang
loadChildren
assert(@root.hasChildren?, "Should have children")
assert(!@root.isLeaf?, "Root is not a leaf here")
child1 = @root[0]
assert_not_nil(child1, "Child 1 should exist")
assert_same(@root, child1.root, "Child 1's root should be ROOT")
assert(@root.include?(child1), "root should have child1")
child1.removeFromParent!
assert_same(child1, child1.root, "Child 1's root should be self")
assert(!@root.include?(child1), "root should not have child1")
child1.removeFromParent!
assert_same(child1, child1.root, "Child 1's root should still be self")
end
def test_children
loadChildren
assert(@root.hasChildren?, "Should have children")
assert_equal(5, @root.size, "Should have four nodes")
assert(@child3.hasChildren?, "Should have children")
assert(!@child3.isLeaf?, "Should not be a leaf")
children = []
for child in @root.children
children << child
end
assert_equal(3, children.length, "Should have three direct children")
assert(!children.include?(@root), "Should not have root")
assert(children.include?(@child1), "Should have child 1")
assert(children.include?(@child2), "Should have child 2")
assert(children.include?(@child3), "Should have child 3")
assert(!children.include?(@child4), "Should not have child 4")
children.clear
children = @root.children
assert_equal(3, children.length, "Should have three children")
end
def test_firstChild
loadChildren
assert_equal(@child1, @root.firstChild, "Root's first child is Child1")
assert_nil(@child1.firstChild, "Child1 does not have any children")
assert_equal(@child4, @child3.firstChild, "Child3's first child is Child4")
end
def test_lastChild
loadChildren
assert_equal(@child3, @root.lastChild, "Root's last child is Child3")
assert_nil(@child1.lastChild, "Child1 does not have any children")
assert_equal(@child4, @child3.lastChild, "Child3's last child is Child4")
end
def test_find
loadChildren
foundNode = @root.find { |node| node == @child2}
assert_same(@child2, foundNode, "The node should be Child 2")
foundNode = @root.find { |node| node == @child4}
assert_same(@child4, foundNode, "The node should be Child 4")
foundNode = @root.find { |node| node.name == "Child31" }
assert_same(@child4, foundNode, "The node should be Child 4")
foundNode = @root.find { |node| node.name == "NOT PRESENT" }
assert_nil(foundNode, "The node should not be found")
end
def test_parentage
loadChildren
assert_nil(@root.parentage, "Root does not have any parentage")
assert_equal([@root], @child1.parentage, "Child1 has Root as its parent")
assert_equal([@child3, @root], @child4.parentage, "Child4 has Child3 and Root as ancestors")
end
def test_each
loadChildren
assert(@root.hasChildren?, "Should have children")
assert_equal(5, @root.size, "Should have five nodes")
assert(@child3.hasChildren?, "Should have children")
nodes = []
@root.each { |node| nodes << node }
assert_equal(5, nodes.length, "Should have FIVE NODES")
assert(nodes.include?(@root), "Should have root")
assert(nodes.include?(@child1), "Should have child 1")
assert(nodes.include?(@child2), "Should have child 2")
assert(nodes.include?(@child3), "Should have child 3")
assert(nodes.include?(@child4), "Should have child 4")
end
def test_each_leaf
loadChildren
nodes = []
@root.each_leaf { |node| nodes << node }
assert_equal(3, nodes.length, "Should have THREE LEAF NODES")
assert(!nodes.include?(@root), "Should not have root")
assert(nodes.include?(@child1), "Should have child 1")
assert(nodes.include?(@child2), "Should have child 2")
assert(!nodes.include?(@child3), "Should not have child 3")
assert(nodes.include?(@child4), "Should have child 4")
end
def test_parent
loadChildren
assert_nil(@root.parent, "Root's parent should be nil")
assert_equal(@root, @child1.parent, "Parent should be root")
assert_equal(@root, @child3.parent, "Parent should be root")
assert_equal(@child3, @child4.parent, "Parent should be child3")
assert_equal(@root, @child4.parent.parent, "Parent should be root")
end
def test_indexed_access
loadChildren
assert_equal(@child1, @root[0], "Should be the first child")
assert_equal(@child4, @root[2][0], "Should be the grandchild")
assert_nil(@root["TEST"], "Should be nil")
assert_raise(RuntimeError) { @root[nil] }
end
def test_printTree
loadChildren
#puts
#@root.printTree
end
# Tests the binary dumping mechanism with an Object content node
def test_marshal_dump
# Setup Test Data
test_root = Tree::TreeNode.new("ROOT", "Root Node")
test_content = {"KEY1" => "Value1", "KEY2" => "Value2" }
test_child = Tree::TreeNode.new("Child", test_content)
test_content2 = ["AValue1", "AValue2", "AValue3"]
test_grand_child = Tree::TreeNode.new("Grand Child 1", test_content2)
test_root << test_child << test_grand_child
# Perform the test operation
data = Marshal.dump(test_root) # Marshal
new_root = Marshal.load(data) # And unmarshal
# Test the root node
assert_equal(test_root.name, new_root.name, "Must identify as ROOT")
assert_equal(test_root.content, new_root.content, "Must have root's content")
assert(new_root.isRoot?, "Must be the ROOT node")
assert(new_root.hasChildren?, "Must have a child node")
# Test the child node
new_child = new_root[test_child.name]
assert_equal(test_child.name, new_child.name, "Must have child 1")
assert(new_child.hasContent?, "Child must have content")
assert(new_child.isOnlyChild?, "Child must be the only child")
new_child_content = new_child.content
assert_equal(Hash, new_child_content.class, "Class of child's content should be a hash")
assert_equal(test_child.content.size, new_child_content.size, "The content should have same size")
# Test the grand-child node
new_grand_child = new_child[test_grand_child.name]
assert_equal(test_grand_child.name, new_grand_child.name, "Must have grand child")
assert(new_grand_child.hasContent?, "Grand-child must have content")
assert(new_grand_child.isOnlyChild?, "Grand-child must be the only child")
new_grand_child_content = new_grand_child.content
assert_equal(Array, new_grand_child_content.class, "Class of grand-child's content should be an Array")
assert_equal(test_grand_child.content.size, new_grand_child_content.size, "The content should have same size")
end
# marshal_load and marshal_dump are symmetric methods
# This alias is for satisfying ZenTest
alias test_marshal_load test_marshal_dump
# Test the collect method from the mixed-in Enumerable functionality.
def test_collect
loadChildren
collectArray = @root.collect do |node|
node.content = "abc"
node
end
collectArray.each {|node| assert_equal("abc", node.content, "Should be 'abc'")}
end
# Test freezing the tree
def test_freezeTree_bang
loadChildren
@root.content = "ABC"
assert_equal("ABC", @root.content, "Content should be 'ABC'")
@root.freezeTree!
assert_raise(TypeError) {@root.content = "123"}
assert_raise(TypeError) {@root[0].content = "123"}
end
# Test whether the content is accesible
def test_content
pers = Person::new("John", "Doe")
@root.content = pers
assert_same(pers, @root.content, "Content should be the same")
end
# Test the depth computation algorithm
def test_depth
assert_equal(1, @root.depth, "A single node's depth is 1")
@root << @child1
assert_equal(2, @root.depth, "This should be of depth 2")
@root << @child2
assert_equal(2, @root.depth, "This should be of depth 2")
@child2 << @child3
assert_equal(3, @root.depth, "This should be of depth 3")
assert_equal(2, @child2.depth, "This should be of depth 2")
@child3 << @child4
assert_equal(4, @root.depth, "This should be of depth 4")
end
# Test the breadth computation algorithm
def test_breadth
assert_equal(1, @root.breadth, "A single node's breadth is 1")
@root << @child1
assert_equal(1, @root.breadth, "This should be of breadth 1")
@root << @child2
assert_equal(2, @child1.breadth, "This should be of breadth 2")
assert_equal(2, @child2.breadth, "This should be of breadth 2")
@root << @child3
assert_equal(3, @child1.breadth, "This should be of breadth 3")
assert_equal(3, @child2.breadth, "This should be of breadth 3")
@child3 << @child4
assert_equal(1, @child4.breadth, "This should be of breadth 1")
end
# Test the breadth for each
def test_breadth_each
j = Tree::TreeNode.new("j")
f = Tree::TreeNode.new("f")
k = Tree::TreeNode.new("k")
a = Tree::TreeNode.new("a")
d = Tree::TreeNode.new("d")
h = Tree::TreeNode.new("h")
z = Tree::TreeNode.new("z")
# The expected order of response
expected_array = [j,
f, k,
a, h, z,
d]
# Create the following Tree
# j <-- level 0 (Root)
# / \
# f k <-- level 1
# / \ \
# a h z <-- level 2
# \
# d <-- level 3
j << f << a << d
f << h
j << k << z
# Create the response
result_array = Array.new
j.breadth_each { |node| result_array << node.detached_copy }
expected_array.each_index do |i|
assert_equal(expected_array[i].name, result_array[i].name) # Match only the names.
end
end
def test_preordered_each
j = Tree::TreeNode.new("j")
f = Tree::TreeNode.new("f")
k = Tree::TreeNode.new("k")
a = Tree::TreeNode.new("a")
d = Tree::TreeNode.new("d")
h = Tree::TreeNode.new("h")
z = Tree::TreeNode.new("z")
# The expected order of response
expected_array = [j, f, a, d, h, k, z]
# Create the following Tree
# j <-- level 0 (Root)
# / \
# f k <-- level 1
# / \ \
# a h z <-- level 2
# \
# d <-- level 3
j << f << a << d
f << h
j << k << z
result_array = []
j.preordered_each { |node| result_array << node.detached_copy}
expected_array.each_index do |i|
# Match only the names.
assert_equal(expected_array[i].name, result_array[i].name)
end
end
def test_detached_copy
loadChildren
assert(@root.hasChildren?, "The root should have children")
copy_of_root = @root.detached_copy
assert(!copy_of_root.hasChildren?, "The copy should not have children")
assert_equal(@root.name, copy_of_root.name, "The names should be equal")
# Try the same test with a child node
assert(!@child3.isRoot?, "Child 3 is not a root")
assert(@child3.hasChildren?, "Child 3 has children")
copy_of_child3 = @child3.detached_copy
assert(copy_of_child3.isRoot?, "Child 3's copy is a root")
assert(!copy_of_child3.hasChildren?, "Child 3's copy does not have children")
end
def test_hasChildren_eh
loadChildren
assert(@root.hasChildren?, "The Root node MUST have children")
end
def test_isLeaf_eh
loadChildren
assert(!@child3.isLeaf?, "Child 3 is not a leaf node")
assert(@child4.isLeaf?, "Child 4 is a leaf node")
end
def test_isRoot_eh
loadChildren
assert(@root.isRoot?, "The ROOT node must respond as the root node")
end
def test_content_equals
@root.content = nil
assert_nil(@root.content, "Root's content should be nil")
@root.content = "ABCD"
assert_equal("ABCD", @root.content, "Root's content should now be 'ABCD'")
end
def test_size
assert_equal(1, @root.size, "Root's size should be 1")
loadChildren
assert_equal(5, @root.size, "Root's size should be 5")
assert_equal(2, @child3.size, "Child 3's size should be 2")
end
def test_lt2 # Test the << method
@root << @child1
@root << @child2
@root << @child3 << @child4
assert_not_nil(@root['Child1'], "Child 1 should have been added to Root")
assert_not_nil(@root['Child2'], "Child 2 should have been added to Root")
assert_not_nil(@root['Child3'], "Child 3 should have been added to Root")
assert_not_nil(@child3['Child31'], "Child 31 should have been added to Child3")
end
def test_index # Test the [] method
assert_raise(RuntimeError) {@root[nil]}
@root << @child1
@root << @child2
assert_equal(@child1.name, @root['Child1'].name, "Child 1 should be returned")
assert_equal(@child1.name, @root[0].name, "Child 1 should be returned")
assert_equal(@child2.name, @root['Child2'].name, "Child 2 should be returned")
assert_equal(@child2.name, @root[1].name, "Child 2 should be returned")
assert_nil(@root['Some Random Name'], "Should return nil")
assert_nil(@root[99], "Should return nil")
end
end
end
__END__
# $Log: test_tree.rb,v $
# Revision 1.6 2007/12/22 00:28:59 anupamsg
# Added more test cases, and enabled ZenTest compatibility.
#
# Revision 1.5 2007/12/19 02:24:18 anupamsg
# Updated the marshalling logic to handle non-string contents on the nodes.
#
# Revision 1.4 2007/10/02 03:38:11 anupamsg
# Removed dependency on the redundant "Person" class.
# (TC_TreeTest::test_comparator): Added a new test for the spaceship operator.
# (TC_TreeTest::test_hasContent): Added tests for hasContent? and length methods.
#
# Revision 1.3 2007/10/02 03:07:30 anupamsg
# * Rakefile: Added an optional task for rcov code coverage.
#
# * test/test_binarytree.rb: Removed the unnecessary dependency on "Person" class.
#
# * test/test_tree.rb: Removed dependency on the redundant "Person" class.
#
# Revision 1.2 2007/08/31 01:16:28 anupamsg
# Added breadth and pre-order traversals for the tree. Also added a method
# to return the detached copy of a node from the tree.
#
# Revision 1.1 2007/07/21 04:52:38 anupamsg
# Renamed the test files.
#
# Revision 1.13 2007/07/18 22:11:50 anupamsg
# Added depth and breadth methods for the TreeNode.
#
# Revision 1.12 2007/07/18 07:17:34 anupamsg
# Fixed a issue where TreeNode.ancestors was shadowing Module.ancestors. This method
# has been renamed to TreeNode.parentage.
#
# Revision 1.11 2007/07/17 03:39:29 anupamsg
# Moved the CVS Log keyword to end of the files.
#