forester 4.3.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +16 -1
- data/.travis.yml +4 -5
- data/CHANGELOG.md +14 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +1 -1
- data/{LICENSE → LICENSE.txt} +5 -5
- data/README.md +60 -24
- data/Rakefile +4 -4
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/forester.gemspec +28 -20
- data/lib/forester.rb +13 -11
- data/lib/forester/tree_factory.rb +18 -49
- data/lib/forester/tree_node.rb +68 -80
- data/lib/forester/tree_node_ext/iterators.rb +57 -0
- data/lib/forester/tree_node_ext/mutators.rb +36 -43
- data/lib/forester/tree_node_ext/serializers.rb +48 -0
- data/lib/forester/tree_node_ext/validators.rb +21 -24
- data/lib/forester/version.rb +1 -15
- metadata +78 -50
- data/lib/forester/node_content/base.rb +0 -9
- data/lib/forester/node_content/dictionary.rb +0 -91
- data/lib/forester/node_content/factory.rb +0 -25
- data/lib/forester/node_content/list.rb +0 -31
- data/lib/forester/tree_node_ext/aggregators.rb +0 -101
- data/lib/forester/tree_node_ext/views.rb +0 -34
- data/test/minitest_helper.rb +0 -41
- data/test/test_ad_hoc_tree.rb +0 -48
- data/test/test_aggregators.rb +0 -105
- data/test/test_mutators.rb +0 -97
- data/test/test_tree_factory.rb +0 -30
- data/test/test_tree_node.rb +0 -44
- data/test/test_validators.rb +0 -240
- data/test/test_views.rb +0 -22
- data/test/trees/simple_tree.yml +0 -61
@@ -1,34 +0,0 @@
|
|
1
|
-
module Forester
|
2
|
-
module Views
|
3
|
-
|
4
|
-
def as_root_hash(options = {})
|
5
|
-
default_options = {
|
6
|
-
fields_to_include: :all,
|
7
|
-
max_level: :last,
|
8
|
-
children_key: :children,
|
9
|
-
stringify_keys: false,
|
10
|
-
symbolize_keys: false
|
11
|
-
}
|
12
|
-
options = default_options.merge(options)
|
13
|
-
|
14
|
-
hash = content.to_hash(options)
|
15
|
-
|
16
|
-
children_key = options[:children_key]
|
17
|
-
children_key = children_key.to_s if options[:stringify_keys]
|
18
|
-
|
19
|
-
max_level = options[:max_level]
|
20
|
-
max_level = -1 if max_level == :last
|
21
|
-
|
22
|
-
next_children =
|
23
|
-
if max_level == 0
|
24
|
-
[]
|
25
|
-
else
|
26
|
-
next_options = options.merge(max_level: max_level - 1)
|
27
|
-
children.map { |node| node.as_root_hash(next_options) }
|
28
|
-
end
|
29
|
-
|
30
|
-
hash.merge(children_key => next_children)
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
data/test/minitest_helper.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'simplecov'
|
2
|
-
SimpleCov.start do
|
3
|
-
add_filter 'test/'
|
4
|
-
end
|
5
|
-
|
6
|
-
require 'minitest/autorun'
|
7
|
-
|
8
|
-
require 'pry-byebug'
|
9
|
-
|
10
|
-
require 'forester'
|
11
|
-
|
12
|
-
class Forester::Test < Minitest::Test
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
PATH_TO_TREES = "#{File.dirname(__FILE__)}/trees"
|
17
|
-
PATH_TO_SIMPLE_TREE = "#{PATH_TO_TREES}/simple_tree.yml"
|
18
|
-
TREE = Forester::TreeFactory.from_yaml_file(PATH_TO_SIMPLE_TREE)
|
19
|
-
|
20
|
-
BINARY_TREE = Forester::TreeFactory.node_from_hash(name: :top) do |parent|
|
21
|
-
parent.add_child_content!(name: :left) do |left|
|
22
|
-
left.add_child_content!(name: :left_left) do |left_left|
|
23
|
-
left_left.add_child_content!(name: :left_left_left)
|
24
|
-
end
|
25
|
-
left.add_child_content!(name: :left_right)
|
26
|
-
end
|
27
|
-
parent.add_child_content!(name: :right) do |right|
|
28
|
-
right.add_child_content!(name: :right_left)
|
29
|
-
right.add_child_content!(name: :right_right)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def tree
|
34
|
-
TREE
|
35
|
-
end
|
36
|
-
|
37
|
-
def binary_tree
|
38
|
-
BINARY_TREE
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
data/test/test_ad_hoc_tree.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'minitest_helper'
|
2
|
-
|
3
|
-
class TestAdHocTree < Forester::Test
|
4
|
-
|
5
|
-
def test_content
|
6
|
-
assert_equal({ number: 1 }, Forester::TreeFactory.node_from_hash(number: 1).content)
|
7
|
-
end
|
8
|
-
|
9
|
-
def test_each_node_type
|
10
|
-
assert_instance_of Enumerator, binary_tree.each_node
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_each_content_type
|
14
|
-
assert_instance_of Enumerator, binary_tree.each_content
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_each_content_depth_first
|
18
|
-
expected = %i(top left left_left left_left_left left_right right right_left right_right)
|
19
|
-
assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :depth_first)
|
20
|
-
assert_equal expected, binary_tree.each_node(traversal: :depth_first).map { |n| n.get(:name) }
|
21
|
-
assert_equal expected, binary_tree.each_content(traversal: :depth_first).map { |c| c[:name] }
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_each_content_breadth_first
|
25
|
-
expected = %i(top left right left_left left_right right_left right_right left_left_left)
|
26
|
-
|
27
|
-
assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :breadth_first)
|
28
|
-
assert_equal expected, binary_tree.each_node(traversal: :breadth_first).map { |n| n.get(:name) }
|
29
|
-
assert_equal expected, binary_tree.each_node.map { |n| n.get(:name) }
|
30
|
-
assert_equal expected, binary_tree.each_content(traversal: :breadth_first).map { |c| c[:name] }
|
31
|
-
assert_equal expected, binary_tree.each_content.map { |c| c[:name] }
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_each_content_postorder
|
35
|
-
expected = %i(left_left_left left_left left_right left right_left right_right right top)
|
36
|
-
assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :postorder)
|
37
|
-
assert_equal expected, binary_tree.each_node(traversal: :postorder).map { |n| n.get(:name) }
|
38
|
-
assert_equal expected, binary_tree.each_content(traversal: :postorder).map { |c| c[:name] }
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_each_content_preorder
|
42
|
-
expected = %i(top left left_left left_left_left left_right right right_left right_right)
|
43
|
-
assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :preorder)
|
44
|
-
assert_equal expected, binary_tree.each_node(traversal: :preorder).map { |n| n.get(:name) }
|
45
|
-
assert_equal expected, binary_tree.each_content(traversal: :preorder).map { |c| c[:name] }
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
data/test/test_aggregators.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
require 'minitest_helper'
|
2
|
-
|
3
|
-
class TestAggregators < Forester::Test
|
4
|
-
|
5
|
-
def test_group_by_sibling_subtrees
|
6
|
-
expected = {
|
7
|
-
"First node of level 2" => [
|
8
|
-
"Already in level 2",
|
9
|
-
"I want to be the very best",
|
10
|
-
"like no one ever was"
|
11
|
-
],
|
12
|
-
"Second node of level 2" => [
|
13
|
-
"I have a sibling to my left",
|
14
|
-
"She wants to catch them all"
|
15
|
-
],
|
16
|
-
"Third node of level 2" => [
|
17
|
-
"Reached level 3",
|
18
|
-
"It's dark",
|
19
|
-
"A hidden secret lies in the deepest leaves...",
|
20
|
-
"Just kidding.",
|
21
|
-
"Could forester handle trees with hundreds of levels?",
|
22
|
-
"Maybe."
|
23
|
-
]
|
24
|
-
}
|
25
|
-
|
26
|
-
actual = tree.group_by_sibling_subtrees(
|
27
|
-
level: 2,
|
28
|
-
aggregation_field: 'strings'
|
29
|
-
)
|
30
|
-
|
31
|
-
assert_equal expected, actual
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_group_by_sibling_subtrees_with_ancestry
|
35
|
-
expected = {
|
36
|
-
["First node of level 1", "First node of level 2"] => ["Already in level 2", "I want to be the very best", "like no one ever was"],
|
37
|
-
["First node of level 1", "Second node of level 2"] => ["I have a sibling to my left", "She wants to catch them all"],
|
38
|
-
["Second node of level 1", "Third node of level 2"] => ["Reached level 3", "It's dark", "A hidden secret lies in the deepest leaves...", "Just kidding.", "Could forester handle trees with hundreds of levels?", "Maybe."]
|
39
|
-
}
|
40
|
-
|
41
|
-
actual = tree.group_by_sibling_subtrees(
|
42
|
-
level: 2,
|
43
|
-
aggregation_field: 'strings',
|
44
|
-
ancestry_in_keys: true
|
45
|
-
)
|
46
|
-
|
47
|
-
assert_equal expected, actual
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_nodes_with
|
51
|
-
expected_names = [
|
52
|
-
"A hidden secret lies in the deepest leaves...",
|
53
|
-
"Just kidding.",
|
54
|
-
"Could forester handle trees with hundreds of levels?",
|
55
|
-
"Maybe."
|
56
|
-
]
|
57
|
-
|
58
|
-
found_nodes = tree.nodes_with('name', 'Second node of level 3')
|
59
|
-
assert_equal 1, found_nodes.length
|
60
|
-
|
61
|
-
actual_names = found_nodes.flat_map do |node|
|
62
|
-
node.own_and_descendants('strings')
|
63
|
-
end
|
64
|
-
|
65
|
-
assert_equal expected_names, actual_names
|
66
|
-
end
|
67
|
-
|
68
|
-
def test_search
|
69
|
-
expected = [7]
|
70
|
-
|
71
|
-
actual_1 = tree.search({
|
72
|
-
by_field: 'name',
|
73
|
-
keywords: 'Second node of level 3',
|
74
|
-
then_get: 'value',
|
75
|
-
subtree: false
|
76
|
-
})
|
77
|
-
|
78
|
-
actual_2 = tree.search({
|
79
|
-
by_field: 'name',
|
80
|
-
keywords: ['Second node of level 3', 'Not present name'],
|
81
|
-
then_get: 'value',
|
82
|
-
subtree: false
|
83
|
-
})
|
84
|
-
|
85
|
-
actual_3 = tree.search({
|
86
|
-
by_field: 'strings',
|
87
|
-
keywords: 'A hidden secret lies in the deepest leaves...',
|
88
|
-
then_get: 'value',
|
89
|
-
subtree: false
|
90
|
-
})
|
91
|
-
assert_equal expected, actual_1
|
92
|
-
assert_equal expected, actual_2
|
93
|
-
assert_equal expected, actual_3
|
94
|
-
|
95
|
-
expected_values = [7, 8, 9]
|
96
|
-
actual_values = tree.search({
|
97
|
-
by_field: 'name',
|
98
|
-
keywords: 'Second node of level 3',
|
99
|
-
then_get: 'value',
|
100
|
-
subtree: true
|
101
|
-
})
|
102
|
-
assert_equal expected_values, actual_values
|
103
|
-
end
|
104
|
-
|
105
|
-
end
|
data/test/test_mutators.rb
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
require 'minitest_helper'
|
2
|
-
|
3
|
-
class TestMutators < Forester::Test
|
4
|
-
|
5
|
-
def test_add_field
|
6
|
-
tree.add_field!('number_four', 4)
|
7
|
-
|
8
|
-
assert_equal 4, tree.get(:number_four)
|
9
|
-
assert_equal 4, tree.get('number_four')
|
10
|
-
|
11
|
-
tree.add_field!(:number_five, 5)
|
12
|
-
|
13
|
-
assert_equal 5, tree.get(:number_five)
|
14
|
-
assert_equal 5, tree.get('number_five')
|
15
|
-
|
16
|
-
number_one = 1
|
17
|
-
|
18
|
-
tree.add_field!(:number_six, -> (node) { node.get(:number_five) + number_one })
|
19
|
-
|
20
|
-
assert_equal 6, tree.get(:number_six)
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_delete_values
|
24
|
-
node_1, node_2, node_3 = nodes_with_tags
|
25
|
-
|
26
|
-
tree.delete_values!(:tags, [])
|
27
|
-
assert_equal ['First tag', 'Second tag', 'Third tag'], node_1.get(:tags)
|
28
|
-
assert_equal ['Second tag', 'Third tag'], node_2.get(:tags)
|
29
|
-
assert_equal ['Third tag'], node_3.get(:tags)
|
30
|
-
|
31
|
-
tree.delete_values!(:tags, ['First tag'])
|
32
|
-
assert_equal ['Second tag', 'Third tag'], node_1.get(:tags)
|
33
|
-
assert_equal ['Second tag', 'Third tag'], node_2.get(:tags)
|
34
|
-
assert_equal ['Third tag'], node_3.get(:tags)
|
35
|
-
|
36
|
-
tree.delete_values!(:tags, ['First tag', 'Second tag', 'Third tag'])
|
37
|
-
assert_equal [], node_1.get(:tags)
|
38
|
-
assert_equal [], node_2.get(:tags)
|
39
|
-
assert_equal [], node_3.get(:tags)
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_percolate_values
|
43
|
-
node_1, node_2, node_3 = nodes_with_tags
|
44
|
-
|
45
|
-
tree.percolate_values!(:tags, ['First tag', 'Second tag', 'Third tag'])
|
46
|
-
assert_equal ['First tag', 'Second tag', 'Third tag'], node_1.get(:tags)
|
47
|
-
assert_equal ['Second tag', 'Third tag'], node_2.get(:tags)
|
48
|
-
assert_equal ['Third tag'], node_3.get(:tags)
|
49
|
-
|
50
|
-
tree.percolate_values!(:tags, ['First tag'])
|
51
|
-
assert_equal ['First tag'], node_1.get(:tags)
|
52
|
-
assert_equal [], node_2.get(:tags)
|
53
|
-
assert_equal [], node_3.get(:tags)
|
54
|
-
|
55
|
-
tree.percolate_values!(:tags, [])
|
56
|
-
assert_equal [], node_1.get(:tags)
|
57
|
-
assert_equal [], node_2.get(:tags)
|
58
|
-
assert_equal [], node_3.get(:tags)
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_change_parent_to
|
62
|
-
node_to_move = binary_tree.search(single_node: true, by_field: :name, keywords: [:left_left]).first
|
63
|
-
old_parent = binary_tree.search(single_node: true, by_field: :name, keywords: [:left]).first
|
64
|
-
new_parent = binary_tree.search(single_node: true, by_field: :name, keywords: [:right]).first
|
65
|
-
|
66
|
-
node_to_move.change_parent_to!(new_parent)
|
67
|
-
|
68
|
-
expected = %i(top left left_right right right_left right_right left_left left_left_left)
|
69
|
-
assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :depth_first)
|
70
|
-
|
71
|
-
node_to_move.change_parent_to!(old_parent, subtree: false)
|
72
|
-
|
73
|
-
expected = %i(top left left_right left_left right right_left right_right left_left_left)
|
74
|
-
assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :depth_first)
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
def tree
|
80
|
-
@mutable_tree ||= super.detached_subtree_copy
|
81
|
-
end
|
82
|
-
|
83
|
-
def binary_tree
|
84
|
-
@mutable_binary_tree ||= super.detached_subtree_copy
|
85
|
-
end
|
86
|
-
|
87
|
-
def nodes_with_tags
|
88
|
-
[1, 6, 9].map do |n|
|
89
|
-
tree.search({
|
90
|
-
single_node: true,
|
91
|
-
by_field: :value,
|
92
|
-
keywords: n
|
93
|
-
}).first
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
data/test/test_tree_factory.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'minitest_helper'
|
2
|
-
|
3
|
-
class TestTreeFactory < Forester::Test
|
4
|
-
|
5
|
-
def test_from_root_hash
|
6
|
-
hash = YAML.load_file(PATH_TO_SIMPLE_TREE)
|
7
|
-
|
8
|
-
whole_tree = from_root_hash(hash)
|
9
|
-
|
10
|
-
whole_trees = [whole_tree] + [29, 4].map { |ml| from_root_hash(hash, max_level: ml) }
|
11
|
-
|
12
|
-
assert(whole_trees.product(whole_trees).all? { |t1, t2| t1.same_as?(t2) })
|
13
|
-
|
14
|
-
pruned_trees = (0..2).map { |ml| from_root_hash(hash, max_level: ml) }
|
15
|
-
|
16
|
-
pruned_trees.each_with_index do |t, i|
|
17
|
-
assert_equal(i, t.max_level)
|
18
|
-
|
19
|
-
pruned = whole_trees[i].remove_levels_past!(i)
|
20
|
-
assert(t.same_as?(pruned))
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def from_root_hash(hash, options = {})
|
27
|
-
Forester::TreeFactory.from_root_hash(hash['root'], options)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
data/test/test_tree_node.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'minitest_helper'
|
2
|
-
|
3
|
-
class TestTreeNode < Forester::Test
|
4
|
-
|
5
|
-
def test_size
|
6
|
-
assert_equal 10, tree.size
|
7
|
-
end
|
8
|
-
|
9
|
-
def test_values
|
10
|
-
values = (0..9).to_a
|
11
|
-
|
12
|
-
expected = values.reduce(:+)
|
13
|
-
actual = tree.reduce(0) { |acum, node| acum + node.get('value') }
|
14
|
-
|
15
|
-
assert_equal expected, actual
|
16
|
-
|
17
|
-
assert_equal values, tree.get('value', subtree: true)
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_missing_values
|
21
|
-
assert_equal 0, tree.get('value')
|
22
|
-
assert_equal 'no', tree.get('whatever', default: 'no')
|
23
|
-
assert_equal 'no', tree.get('whatever', default: 'missing') { 'no' }
|
24
|
-
assert_equal 'no', tree.get('whatever') { 'no' }
|
25
|
-
assert_equal 'no', tree.get('whatever') { |n| 'no' }
|
26
|
-
assert_equal 1, tree.get('whatever') { |n| n.get('value') + 1 }
|
27
|
-
|
28
|
-
assert_raises(ArgumentError) { tree.get('whatever') }
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_levels
|
32
|
-
expected = [
|
33
|
-
["root"],
|
34
|
-
["First node of level 1", "Second node of level 1"],
|
35
|
-
["First node of level 2", "Second node of level 2", "Third node of level 2"],
|
36
|
-
["First node of level 3", "Second node of level 3"],
|
37
|
-
["First node of level 4", "Second node of level 4"]
|
38
|
-
]
|
39
|
-
actual = tree.each_level.map { |l| l.map { |n| n.get('name') } }.to_a
|
40
|
-
|
41
|
-
assert_equal expected, actual
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
data/test/test_validators.rb
DELETED
@@ -1,240 +0,0 @@
|
|
1
|
-
require 'minitest_helper'
|
2
|
-
|
3
|
-
class TestValidators < Forester::Test
|
4
|
-
|
5
|
-
def test_validate_uniqueness_of_field_uniques
|
6
|
-
expected = {
|
7
|
-
is_valid: true,
|
8
|
-
repeated: {},
|
9
|
-
failures: {}
|
10
|
-
}
|
11
|
-
|
12
|
-
['name', :name, 'special', 'ghost'].each do |field|
|
13
|
-
actual = tree.validate_uniqueness_of_field(field)
|
14
|
-
assert_equal expected, actual
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_validate_uniqueness_of_field_color
|
20
|
-
expected = {
|
21
|
-
is_valid: false,
|
22
|
-
repeated: {
|
23
|
-
:color => ['Green', 'Yellow']
|
24
|
-
},
|
25
|
-
failures: {
|
26
|
-
:color => {
|
27
|
-
'Green' => ['First node of level 1', 'Second node of level 1'],
|
28
|
-
'Yellow' => ['First node of level 4', 'Second node of level 4']
|
29
|
-
}
|
30
|
-
}
|
31
|
-
}
|
32
|
-
|
33
|
-
actual = tree.validate_uniqueness_of_field(:color)
|
34
|
-
assert_equal expected, actual
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_validate_uniqueness_of_field_color_first_failure_only
|
38
|
-
expected = {
|
39
|
-
is_valid: false,
|
40
|
-
repeated: {
|
41
|
-
:color => ['Green']
|
42
|
-
},
|
43
|
-
failures: {
|
44
|
-
:color => {
|
45
|
-
'Green' => ['First node of level 1', 'Second node of level 1']
|
46
|
-
}
|
47
|
-
}
|
48
|
-
}
|
49
|
-
|
50
|
-
actual = tree.validate_uniqueness_of_field(:color, {
|
51
|
-
first_failure_only: true
|
52
|
-
})
|
53
|
-
assert_equal expected, actual
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_validate_uniqueness_of_field_color_among_siblings_of_level_1
|
57
|
-
expected = {
|
58
|
-
is_valid: false,
|
59
|
-
repeated: {
|
60
|
-
:color => ['Green']
|
61
|
-
},
|
62
|
-
failures: {
|
63
|
-
:color => {
|
64
|
-
'Green' => ['First node of level 1', 'Second node of level 1']
|
65
|
-
}
|
66
|
-
}
|
67
|
-
}
|
68
|
-
|
69
|
-
actual = tree.validate_uniqueness_of_field(:color, {
|
70
|
-
among_siblings_of_level: 1
|
71
|
-
})
|
72
|
-
|
73
|
-
assert_equal expected, actual
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_validate_uniqueness_of_field_color_among_siblings_of_level_2
|
77
|
-
expected = {
|
78
|
-
is_valid: true,
|
79
|
-
repeated: {},
|
80
|
-
failures: {}
|
81
|
-
}
|
82
|
-
|
83
|
-
actual = tree.validate_uniqueness_of_field(:color, {
|
84
|
-
among_siblings_of_level: 2
|
85
|
-
})
|
86
|
-
|
87
|
-
assert_equal expected, actual
|
88
|
-
end
|
89
|
-
|
90
|
-
def test_validate_uniqueness_of_field_color_within_subtrees_of_level_1
|
91
|
-
expected = {
|
92
|
-
is_valid: false,
|
93
|
-
repeated: {
|
94
|
-
:color => ['Yellow']
|
95
|
-
},
|
96
|
-
failures: {
|
97
|
-
:color => {
|
98
|
-
'Yellow' => ['First node of level 4', 'Second node of level 4']
|
99
|
-
}
|
100
|
-
}
|
101
|
-
}
|
102
|
-
|
103
|
-
actual = tree.validate_uniqueness_of_field(:color, {
|
104
|
-
within_subtrees_of_level: 1,
|
105
|
-
})
|
106
|
-
|
107
|
-
assert_equal expected, actual
|
108
|
-
end
|
109
|
-
|
110
|
-
def test_validate_uniqueness_of_field_color_within_subtrees_of_level_3
|
111
|
-
expected = {
|
112
|
-
is_valid: false,
|
113
|
-
repeated: {
|
114
|
-
:color => ['Yellow']
|
115
|
-
},
|
116
|
-
failures: {
|
117
|
-
:color => {
|
118
|
-
'Yellow' => ['First node of level 4', 'Second node of level 4']
|
119
|
-
}
|
120
|
-
}
|
121
|
-
}
|
122
|
-
|
123
|
-
actual = tree.validate_uniqueness_of_field(:color, {
|
124
|
-
within_subtrees_of_level: 3,
|
125
|
-
})
|
126
|
-
|
127
|
-
assert_equal expected, actual
|
128
|
-
end
|
129
|
-
|
130
|
-
def test_validate_uniqueness_of_field_color_within_subtrees_of_level_4
|
131
|
-
expected = {
|
132
|
-
is_valid: true,
|
133
|
-
repeated: {},
|
134
|
-
failures: {}
|
135
|
-
}
|
136
|
-
|
137
|
-
actual = tree.validate_uniqueness_of_field(:color, {
|
138
|
-
within_subtrees_of_level: 4,
|
139
|
-
})
|
140
|
-
|
141
|
-
assert_equal expected, actual
|
142
|
-
end
|
143
|
-
|
144
|
-
def test_validate_uniqueness_of_fields_name_color
|
145
|
-
expected = {
|
146
|
-
is_valid: false,
|
147
|
-
repeated: {
|
148
|
-
'color' => ['Green', 'Yellow']
|
149
|
-
},
|
150
|
-
failures: {
|
151
|
-
'color' => {
|
152
|
-
'Green' => ['First node of level 1', 'Second node of level 1'],
|
153
|
-
'Yellow' => ['First node of level 4', 'Second node of level 4']
|
154
|
-
}
|
155
|
-
}
|
156
|
-
}
|
157
|
-
|
158
|
-
actual = tree.validate_uniqueness_of_fields(['name', 'color'])
|
159
|
-
|
160
|
-
assert_equal expected, actual
|
161
|
-
end
|
162
|
-
|
163
|
-
def test_validate_uniqueness_of_combination_of_fields_name_color
|
164
|
-
expected = {
|
165
|
-
is_valid: true,
|
166
|
-
repeated: {},
|
167
|
-
failures: {}
|
168
|
-
}
|
169
|
-
|
170
|
-
actual = tree.validate_uniqueness_of_fields(['name', 'color'], {
|
171
|
-
combination: true
|
172
|
-
})
|
173
|
-
|
174
|
-
assert_equal expected, actual
|
175
|
-
end
|
176
|
-
|
177
|
-
def test_validate_uniqueness_of_fields_color_tone_first_failure_only
|
178
|
-
expected = {
|
179
|
-
is_valid: false,
|
180
|
-
repeated: {
|
181
|
-
'color' => ['Green']
|
182
|
-
},
|
183
|
-
failures: {
|
184
|
-
'color' => {
|
185
|
-
'Green' => ['First node of level 1', 'Second node of level 1']
|
186
|
-
}
|
187
|
-
}
|
188
|
-
}
|
189
|
-
|
190
|
-
actual = tree.validate_uniqueness_of_fields(['color', 'tone'], {
|
191
|
-
first_failure_only: true
|
192
|
-
})
|
193
|
-
|
194
|
-
assert_equal expected, actual
|
195
|
-
end
|
196
|
-
|
197
|
-
def test_validate_uniqueness_of_fields_color_tone
|
198
|
-
expected = {
|
199
|
-
is_valid: false,
|
200
|
-
repeated: {
|
201
|
-
'color' => ['Green', 'Yellow'],
|
202
|
-
'tone' => ['Dark']
|
203
|
-
},
|
204
|
-
failures: {
|
205
|
-
'color' => {
|
206
|
-
'Green' => ['First node of level 1', 'Second node of level 1'],
|
207
|
-
'Yellow' => ['First node of level 4', 'Second node of level 4']
|
208
|
-
},
|
209
|
-
'tone' => {
|
210
|
-
'Dark' => ['First node of level 1', 'Second node of level 1']
|
211
|
-
}
|
212
|
-
}
|
213
|
-
}
|
214
|
-
|
215
|
-
actual = tree.validate_uniqueness_of_fields(['color', 'tone'])
|
216
|
-
|
217
|
-
assert_equal expected, actual
|
218
|
-
end
|
219
|
-
|
220
|
-
def test_validate_uniqueness_of_combination_of_fields_color_tone
|
221
|
-
expected = {
|
222
|
-
is_valid: false,
|
223
|
-
repeated: {
|
224
|
-
['color', 'tone'] => [['Green', 'Dark']]
|
225
|
-
},
|
226
|
-
failures: {
|
227
|
-
['color', 'tone'] => {
|
228
|
-
['Green', 'Dark'] => ['First node of level 1', 'Second node of level 1']
|
229
|
-
}
|
230
|
-
}
|
231
|
-
}
|
232
|
-
|
233
|
-
actual = tree.validate_uniqueness_of_fields(['color', 'tone'], {
|
234
|
-
combination: true
|
235
|
-
})
|
236
|
-
|
237
|
-
assert_equal expected, actual
|
238
|
-
end
|
239
|
-
|
240
|
-
end
|