depgraph 0.11.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.
Files changed (44) hide show
  1. data/History.txt +28 -0
  2. data/License.txt +20 -0
  3. data/README.rdoc +40 -0
  4. data/Rakefile +31 -0
  5. data/VERSION +1 -0
  6. data/bin/depgraph +89 -0
  7. data/config/hoe.rb +71 -0
  8. data/config/requirements.rb +19 -0
  9. data/lib/DepGraph/version.rb +9 -0
  10. data/lib/dependency_types.yaml +11 -0
  11. data/lib/dependency_types_manager.rb +49 -0
  12. data/lib/file_system_node_finder.rb +64 -0
  13. data/lib/graph_creator.rb +122 -0
  14. data/lib/graph_image_creator.rb +125 -0
  15. data/lib/node.rb +44 -0
  16. data/lib/nodefinders/gems_node_finder.rb +58 -0
  17. data/lib/nodefinders/test_node_finder.rb +26 -0
  18. data/script/destroy +14 -0
  19. data/script/destroy.cmd +1 -0
  20. data/script/generate +14 -0
  21. data/script/generate.cmd +1 -0
  22. data/script/txt2html +74 -0
  23. data/script/txt2html.cmd +1 -0
  24. data/setup.rb +1585 -0
  25. data/spec/IntegrationTests/depgraph_spec.rb +90 -0
  26. data/spec/IntegrationTests/file_system_node_finder_spec.rb +54 -0
  27. data/spec/IntegrationTests/gems_node_finder_spec.rb +20 -0
  28. data/spec/IntegrationTests/graph_creator_spec.rb +30 -0
  29. data/spec/IntegrationTests/graph_image_creator_spec.rb +50 -0
  30. data/spec/UnitTests/dependency_types_manager_spec.rb +46 -0
  31. data/spec/UnitTests/file_system_node_finder_spec.rb +62 -0
  32. data/spec/UnitTests/graph_creator_spec.rb +140 -0
  33. data/spec/UnitTests/graph_image_creator_spec.rb +56 -0
  34. data/spec/UnitTests/node_spec.rb +45 -0
  35. data/spec/integration_spec.opts +4 -0
  36. data/spec/spec.opts +6 -0
  37. data/spec/spec_helper.rb +179 -0
  38. data/spec/unit_spec.opts +4 -0
  39. data/tasks/deployment.rake +34 -0
  40. data/tasks/environment.rake +7 -0
  41. data/tasks/rspec.rake +35 -0
  42. data/tasks/website.rake +17 -0
  43. data/todo.txt +4 -0
  44. metadata +128 -0
@@ -0,0 +1,90 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'rubygems'
3
+ require 'graph_creator'
4
+
5
+ include FileTestHelper
6
+
7
+ default_graph_file = 'dependency_graph.png'
8
+ tool_name = 'depgraph'
9
+ tool_path = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'bin', tool_name))
10
+
11
+ describe "#{tool_name} (integration tests)" do
12
+
13
+ test_data = {
14
+ :csproj => {'proj1.csproj' => '"proj2.csproj"', 'proj2.csproj' => '"proj1.csproj"'},
15
+ :ruby_requires => {'rubyfile1.rb' => 'require "rubyfile2"', 'rubyfile2.rb' => 'require "rubyfile3"'},
16
+ :gems => {}
17
+ }
18
+
19
+ DepGraph::GraphCreator.types.each do |filter_type|
20
+ it "should create an image from the #{filter_type} dependency type" do
21
+ test_files = test_data[filter_type]
22
+ with_files(test_files) do
23
+ system "ruby \"#{tool_path}\" -type #{filter_type}"
24
+
25
+ non_empty_file_created(default_graph_file).should be_true
26
+ end
27
+ end
28
+ end
29
+
30
+ three_files_with_chained_dependencies_from_file1_to_file2_to_file3 = {'file1.csproj' => '"file2.csproj"', 'file2.csproj' => '"file3.csproj"', 'file3.csproj' => ''}
31
+ two_files_with_one_dependency_from_file1_to_file2 = {'file1.csproj' => '"file2.csproj"', 'file2.csproj' => ''}
32
+ it 'should not create a file when the "-from" filter does not find matches' do
33
+ with_files(two_files_with_one_dependency_from_file1_to_file2) do
34
+ system "ruby \"#{tool_path}\" -type csproj -from file2"
35
+
36
+ File.exist?(default_graph_file).should be_false
37
+ end
38
+ end
39
+
40
+ it 'should create a file when the "-from" filter finds matches' do
41
+ with_files(two_files_with_one_dependency_from_file1_to_file2) do
42
+ system "ruby \"#{tool_path}\" -type csproj -from file1"
43
+
44
+ File.exist?(default_graph_file).should be_true
45
+ end
46
+ end
47
+
48
+ it 'should not create a file when the "-to" filter does not find matches' do
49
+ with_files(two_files_with_one_dependency_from_file1_to_file2) do
50
+ system "ruby \"#{tool_path}\" -type csproj -to file1"
51
+
52
+ File.exist?(default_graph_file).should be_false
53
+ end
54
+ end
55
+
56
+ it 'should create a file when the "-to" filter finds matches' do
57
+ with_files(two_files_with_one_dependency_from_file1_to_file2) do
58
+ system "ruby \"#{tool_path}\" -type csproj -to file2"
59
+
60
+ File.exist?(default_graph_file).should be_true
61
+ end
62
+ end
63
+
64
+ it 'should exclude nodes when the "-exc" filter is used' do
65
+ with_files(three_files_with_chained_dependencies_from_file1_to_file2_to_file3) do
66
+ system "ruby \"#{tool_path}\" -type csproj -exc \"file2, ile3\""
67
+
68
+ File.exist?(default_graph_file).should be_false #because only file1 exists
69
+ end
70
+ end
71
+
72
+ it 'should be possible to load the test node finder found in the nodefinders directory' do
73
+ with_files() do
74
+ system "ruby \"#{tool_path}\" -type test"
75
+
76
+ File.exist?(default_graph_file).should be_true
77
+ end
78
+ end
79
+
80
+ it 'should be possible apply a transitive reduction to the output graph' do
81
+ with_files() do
82
+ system "ruby \"#{tool_path}\" -type test -trans"
83
+
84
+ File.exist?(default_graph_file).should be_true
85
+ File.exist?('temp.dot').should be_false
86
+ end
87
+ end
88
+ end
89
+
90
+
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'file_system_node_finder'
3
+ require 'rubygems'
4
+
5
+ include FileTestHelper
6
+ include DepGraph
7
+
8
+ describe FileSystemNodeFinder, '(integration tests)' do
9
+ it 'should remove extensions from node names' do
10
+ with_files('directory1/directory2/file.name.ext' => '') do
11
+ node_finder = FileSystemNodeFinder.new(non_existent_filter_type)
12
+ node_finder.file_name_pattern = '*ext'
13
+ nodes = node_finder.get_nodes
14
+ nodes.should == ['file.name']
15
+ end
16
+ end
17
+
18
+ it 'should search only in the specified directories' do
19
+ with_files('good1/file1' => '', 'good2/file2' => '', 'bad/file3' => '') do
20
+ node_finder = FileSystemNodeFinder.new(non_existent_filter_type)
21
+ node_finder.location = ['good1', 'good2']
22
+
23
+ nodes = node_finder.get_nodes
24
+ nodes.should == ['file1', 'file2']
25
+ end
26
+ end
27
+ end
28
+
29
+ #To setup the test files for each filter type, include three sample node files
30
+ #and make the first file, named 'a' depend on the next two, named 'b' and 'c'
31
+ test_set = {
32
+ :ruby_requires => {'a.rb' => 'require "b"\nrequire "c"', 'dir/b.rb' => '', 'dir/c.rb' => '', 'not_a_ruby_file' => ''},
33
+ :csproj => {'a.csproj' => '"b.csproj"\n"c.csproj"', 'dir/b.csproj' => '', 'dir/c.csproj' => '', 'not_a_csproj_file' => ''}
34
+ }
35
+
36
+ dependency_types.each do |filter_type|
37
+ test_files = test_set[filter_type]
38
+
39
+ describe FileSystemNodeFinder, "for #{filter_type.to_s} (integration tests)" do
40
+ it "should find the correct number of nodes" do
41
+ with_files(test_files) do
42
+ nodes = FileSystemNodeFinder.new(filter_type).get_nodes
43
+ nodes.sort.should == ['a', 'b', 'c']
44
+ end
45
+ end
46
+ it "should correctly find the dependencies from each file" do
47
+ with_files(test_files) do
48
+ node = FileSystemNodeFinder.new(filter_type).get_nodes.detect {|n| n.name == 'a'}
49
+ node.should_not be_nil
50
+ node.dependencies.should == ['b', 'c']
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'rubygems'
3
+ require 'nodefinders/gems_node_finder'
4
+
5
+ include FileTestHelper
6
+ include DepGraph::NodeFinders
7
+
8
+ describe GemsNodeFinder do
9
+ it "should list all gems and its dependencies" do
10
+ with_files('fakegem-0.9.1.gemspec' => 's.add_dependency(%q<fakedependencygem>, [">= 1.5.0"])') do
11
+ gems_node_finder = GemsNodeFinder.new
12
+ gems_node_finder.location = ['./']
13
+ nodes = gems_node_finder.get_nodes
14
+
15
+ nodes.should == ['fakedependencygem', 'fakegem']
16
+ nodes[1].dependencies.size.should == 1
17
+ nodes[1].dependencies[0].name.should == 'fakedependencygem'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'graph_creator'
3
+ require 'rubygems'
4
+ include DepGraph
5
+ include FileTestHelper
6
+
7
+ test_data = {
8
+ :csproj => {'file1.csproj'=>'"file2.csproj"', 'dir/file2.csproj'=>'"file1.csproj"' },
9
+ :ruby_requires => {'file1.rb'=>'require "file2"', 'dir/file2.rb'=>'require "file1"' },
10
+ :gems => {}
11
+ }
12
+
13
+ describe GraphCreator, '(integration tests)' do
14
+ GraphCreator.types.each do |filter_type|
15
+ it "should create a png image from the #{filter_type} dependencies found" do
16
+ with_files(test_data[filter_type]) do
17
+ GraphCreator.new(filter_type).create_image('test.png')
18
+
19
+ non_empty_file_created('test.png').should be_true
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+
26
+
27
+
28
+
29
+
30
+
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'graph_image_creator'
3
+ require 'rubygems'
4
+ include FileTestHelper
5
+ include DepGraph
6
+
7
+ describe GraphImageCreator, '(integration tests)' do
8
+ it "should create a file with the graph image" do
9
+ with_files do
10
+ graph = create_graph_with_2_nodes_and_1_edge
11
+ graph.create_image('graph.png')
12
+
13
+ non_empty_file_created('graph.png').should be_true
14
+ end
15
+ end
16
+
17
+ it "should not create an image file from an empty graph" do
18
+ with_files do
19
+ create_empty_graph.create_image('graph.png')
20
+ non_empty_file_created('graph.png').should be_false
21
+ end
22
+ end
23
+
24
+ it "should not create an image file from a graph with no edges" do
25
+ with_files do
26
+ create_graph_with_2_nodes_and_0_edges.create_image('graph.png')
27
+
28
+ non_empty_file_created('graph.png').should be_false
29
+ end
30
+ end
31
+
32
+ it 'can change output generation behaviour'do
33
+ graph = create_graph_with_2_nodes_and_1_edge
34
+ graph.output_generation = no_output_generation
35
+ with_files do
36
+ graph.create_image('test.png')
37
+ File.exist?('test.png').should be_false
38
+ end
39
+ end
40
+
41
+ it 'can generate dot script'do
42
+ graph = create_graph_with_2_nodes_and_1_edge
43
+ with_files do
44
+ graph.create_image('test.dot')
45
+ File.exist?('test.dot').should be_true
46
+ File.read('test.dot').match('digraph G').should_not be_nil
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'dependency_types_manager'
3
+ include DepGraph
4
+
5
+ describe DependencyTypesManager do
6
+
7
+ it "should return the available filter types" do
8
+ dependency_types_in_file = YAML.load_file(DependencyTypesManager.dependency_types_file).map do |filter_type_in_file, _|
9
+ filter_type_in_file
10
+ end
11
+
12
+ dependency_types_in_file.should == dependency_types.map {|filter_type| filter_type.to_s}
13
+ end
14
+
15
+ it "should use default values if the specified filter type is not found" do
16
+ dependable_filter_manager = DependencyTypesManager.new non_existent_filter_type
17
+
18
+ dependable_filter_manager.dependable_regexp.should == /.+/
19
+ dependable_filter_manager.dependable_regexp_capture_group_index.should == 0
20
+ dependable_filter_manager.file_name_pattern.should == '*'
21
+ end
22
+
23
+
24
+ sample_contents = {
25
+ :ruby_requires => {:content => ['require "something/dependency"',
26
+ " require 'something/dependency.rb'"],
27
+ :file_pattern => '*.rb'},
28
+
29
+ :csproj => {:content => ['sdff "directory\\dependency.csproj"hyhyhy',
30
+ 'asdfffd"directory\\anotherdir\\dependency.dll" gfgfgg'],
31
+ :file_pattern => '*.csproj'}
32
+ }
33
+
34
+ dependency_types.each do |filter_type|
35
+ it "should have a #{filter_type} filter type" do
36
+ dependable_filter_manager = DependencyTypesManager.new filter_type
37
+
38
+ capture_index = dependable_filter_manager.dependable_regexp_capture_group_index
39
+ sample_contents[filter_type][:content].each do |sample_dependency|
40
+ dependable_filter_manager.dependable_regexp.match(sample_dependency).captures[capture_index].should == 'dependency'
41
+ end
42
+ dependable_filter_manager.file_name_pattern.should == sample_contents[filter_type][:file_pattern]
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,62 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'file_system_node_finder'
3
+
4
+ include DepGraph
5
+
6
+ describe FileSystemNodeFinder do
7
+ it 'should be able to get the dependencies to csproj and dll files from a string' do
8
+ node_finder = FileSystemNodeFinder.new(:csproj)
9
+ node = Node.new('a')
10
+ dependencies_string = 'from this string the dependable to "\\a.dir\\node1.csproj", \n"\\tgg.hyhy\\node2.dll" and "node3.csproj" should be found'
11
+
12
+ node_finder.load_dependencies_from_string(node, dependencies_string)
13
+
14
+ node.dependencies.should == ["node1", "node2", "node3"]
15
+ end
16
+
17
+ it 'should be able to use a custom regexp filter to get the node dependencies from a string' do
18
+ node_finder = FileSystemNodeFinder.new(non_existent_filter_type)
19
+ dependencies_string = 'from this string the dependable to node.csproj \n and node1.dll should be found'
20
+ node_finder.dependable_filter = /\s([^\s]+)\.(csproj|dll)[^\w]/
21
+ node_finder.dependable_filter_capture_group_index = 0
22
+ node = Node.new('a')
23
+
24
+ node_finder.load_dependencies_from_string(node, dependencies_string)
25
+
26
+ node.dependencies.should == ["node", "node1"]
27
+ end
28
+
29
+ it 'should be able to use a capture group in the dependable regexp filter' do
30
+ node_finder = FileSystemNodeFinder.new(non_existent_filter_type)
31
+ dependencies_string = 'from this string the dependable to prefix.node.csproj \n and prefix.node1.dll should be found'
32
+ node_finder.dependable_filter = /\s(prefix\.)([^\s]+)\.(csproj|dll)[^\w]/
33
+ node_finder.dependable_filter_capture_group_index = 1
34
+ node = Node.new('a')
35
+
36
+ node_finder.load_dependencies_from_string(node, dependencies_string)
37
+
38
+ node.dependencies.should == ["node", "node1"]
39
+ end
40
+
41
+ it 'should ignore repeated dependencies in the string' do
42
+ node_finder = FileSystemNodeFinder.new(:csproj)
43
+ node = Node.new('a')
44
+ dependencies_string = 'this string has only one dependable that is repeated 3 times: "\\a.dir\\node.csproj", \n"\\tgg.hyhy\\node.dll" and "node.csproj"'
45
+
46
+ node_finder.load_dependencies_from_string(node, dependencies_string)
47
+
48
+ node.dependencies.should == ["node"]
49
+ end
50
+
51
+ it 'should ignore the capture group index if the dependable filter regexp has no capture groups' do
52
+ node_finder = FileSystemNodeFinder.new(non_existent_filter_type)
53
+ node_finder.dependable_filter = /dep[0-9]/
54
+ node_finder.dependable_filter_capture_group_index = 1
55
+ node = Node.new('a')
56
+
57
+ node_finder.load_dependencies_from_string(node, 'dep1 is in the first line \n in the second dep2')
58
+
59
+ node.dependencies.size.should == 2
60
+ end
61
+ end
62
+
@@ -0,0 +1,140 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'graph_creator'
3
+ require 'rubygems'
4
+ include DepGraph
5
+
6
+ describe GraphCreator do
7
+ it 'should not create a file if the graph is empty' do
8
+ create_graph_creator_with_no_nodes.create_image.should be_false
9
+ end
10
+
11
+ it 'should return an empty graph if an empty set of nodes is specified' do
12
+ graph = create_graph_creator_with_two_nodes_and_no_dependencies.create_graph
13
+
14
+ graph.node_count.should == 0
15
+ graph.edge_count.should == 0
16
+
17
+ end
18
+
19
+ it 'should return an empty graph if only one node is specified' do
20
+ graph = create_graph_creator_with_two_nodes_and_no_dependencies.create_graph
21
+
22
+ graph.node_count.should == 0
23
+ graph.edge_count.should == 0
24
+
25
+ end
26
+
27
+ it 'should return an empty graph if all nodes specified are equal' do
28
+ graph = create_graph_creator_with_two_nodes_and_no_dependencies.create_graph
29
+
30
+ graph.node_count.should == 0
31
+ graph.edge_count.should == 0
32
+
33
+ end
34
+
35
+ it 'should ignore disconnected nodes' do
36
+ graph = create_2_connected_and_1_disconnected_node_with_an_orphan_dependency_graph_creator.create_graph
37
+
38
+ graph.node_count.should == 2
39
+ graph.edge_count.should == 1
40
+ end
41
+
42
+ it 'should ignore dependencies to non existent nodes' do
43
+ graph = create_2_node_graph_creator_with_1_normal_and_1_orphan_dependency.create_graph
44
+
45
+ graph.node_count.should == 2
46
+ graph.edge_count.should == 1
47
+ end
48
+
49
+ it 'should return a graph with one edge if two nodes with one dependable are specified' do
50
+ graph = create_graph_creator_with_two_nodes_and_one_dependency.create_graph
51
+
52
+ graph.node_count.should == 2
53
+ graph.edge_count.should == 1
54
+ end
55
+
56
+ it 'should be possible to filter dependent nodes with a regular expression' do
57
+ graph_creator = create_dependency_chain_graph_creator('node1', 'node2', 'node3', 'node4')
58
+ graph_creator.from = 'e2$'
59
+ graph = graph_creator.create_graph
60
+
61
+ graph.node_count.should == 2
62
+ graph.edge_count.should == 1
63
+ dependency_exists?(graph, 'node2', 'node3').should be_true
64
+ end
65
+
66
+ it 'should be possible to filter dependable nodes with a regular expression' do
67
+ graph_creator = create_dependency_chain_graph_creator('node1', 'node2', 'node3', 'node4')
68
+ graph_creator.to = 'e4$'
69
+ graph = graph_creator.create_graph
70
+
71
+ graph.node_count.should == 2
72
+ graph.edge_count.should == 1
73
+ dependency_exists?(graph, 'node3', 'node4').should be_true
74
+ end
75
+
76
+ it 'should exclude user selected nodes' do
77
+ graph_creator = create_dependency_chain_graph_creator('node1', 'node2', 'anode3', 'node4isthisone')
78
+ graph_creator.excluded_nodes = ['node3', 'node4', 'node6']
79
+ graph = graph_creator.create_graph
80
+
81
+ graph.node_count.should == 2
82
+ graph.edge_count.should == 1
83
+ dependency_exists?(graph, 'node1', 'node2').should be_true
84
+ end
85
+
86
+ it 'should not show disconnected nodes' do
87
+ graph = create_2_connected_plus_2_disconnected_nodes_graph_creator.create_graph
88
+ graph.node_count.should == 2
89
+ graph.edge_count.should == 1
90
+ end
91
+
92
+ it 'should not show nodes that are only connected to excluded nodes' do
93
+ graph_creator = create_dependency_chain_graph_creator('node1', 'node2', 'node3', 'node4')
94
+ graph_creator.excluded_nodes = ['node3']
95
+ graph = graph_creator.create_graph
96
+
97
+ graph.node_count.should == 2
98
+ graph.edge_count.should == 1
99
+ dependency_exists?(graph, 'node1', 'node2').should be_true
100
+ end
101
+
102
+ it 'should notify sucessful image creation' do
103
+ graph_creator = create_graph_creator_with_two_nodes_and_one_dependency
104
+ graph_creator.graph_image_creator_class = NoOutputGraph
105
+ graph_creator.create_image('graph.png').should be_true
106
+ end
107
+
108
+ it 'should notify failed image creation' do
109
+ graph_creator = create_graph_creator_with_no_nodes
110
+ graph_creator.graph_image_creator_class = NoOutputGraph
111
+ graph_creator.create_image('graph.png').should be_false
112
+ end
113
+
114
+ it 'should dynamically load node finders based on the dependency type' do
115
+ module DepGraph::NodeFinders
116
+ class FakeNodeFinder
117
+ def location=(d) end
118
+ def get_nodes
119
+ d1 = Node.new('node1')
120
+ d2 = Node.new('node2')
121
+ d1.depends_on(d2)
122
+ [d1, d2]
123
+ end
124
+ end
125
+ end
126
+
127
+ graph = GraphCreator.new(:fake).create_graph
128
+
129
+ graph.node_count.should == 2
130
+ graph.edge_count.should == 1
131
+ dependency_exists?(graph, 'node1', 'node2').should be_true
132
+ end
133
+
134
+ invalid_graph_creators.each do |invalid_graph_creator_description, invalid_graph_creator|
135
+ it "should return false when trying to create an image from a #{invalid_graph_creator_description}" do
136
+ invalid_graph_creator.graph_image_creator_class = NoOutputGraph
137
+ invalid_graph_creator.create_image('graph.png').should be_false
138
+ end
139
+ end
140
+ end