gexf 0.0.2

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.
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ BOOLEAN_GETTERS = %w(directed? undirected? mutual?)
4
+
5
+ describe GEXF::Edge do
6
+
7
+ let(:id) { 1 }
8
+ let(:type) { nil }
9
+ let(:source_id) { 2 }
10
+ let(:target_id) { 232 }
11
+ let(:graph) { double('graph', :edges => []) }
12
+ let(:weight) { nil }
13
+ let(:label) { 'my-edge' }
14
+ let(:options) { { :graph => graph, :type => type, :weight => weight, :label => label } }
15
+ let(:arguments){ [id, source_id, target_id, options] }
16
+
17
+ subject { GEXF::Edge.new(*arguments) }
18
+
19
+ describe "#new" do
20
+ its(:id) { should == id.to_s }
21
+ its(:source_id) { should == source_id.to_s }
22
+ its(:target_id) { should == target_id.to_s }
23
+ its(:weight) { should == 1.0 }
24
+ its(:label) { should == label }
25
+ its(:type) { should == GEXF::Edge::UNDIRECTED }
26
+
27
+ [:id, :source_id, :target_id, :graph].each do |param|
28
+ context "when :#{param} is missing" do
29
+ let(param) { nil }
30
+
31
+ it "raises an ArgumentError" do
32
+ expect { subject }.to raise_error(ArgumentError)
33
+ end
34
+ end
35
+ end
36
+
37
+ context "non-positive :weight" do
38
+ let(:weight) { -10 }
39
+
40
+ it "raises an ArgumentError" do
41
+ expect { subject }.to raise_error(ArgumentError)
42
+ end
43
+ end
44
+
45
+ context "invalid type" do
46
+ let(:type) { :FOOBAR }
47
+
48
+ it "raises an ArgumentError" do
49
+ expect { subject }.to raise_error(ArgumentError)
50
+ end
51
+ end
52
+ end
53
+
54
+ BOOLEAN_GETTERS.each do |method|
55
+ edge_type = GEXF::Edge.const_get(method[0..-2].upcase.to_sym)
56
+ other_getters = BOOLEAN_GETTERS - [method]
57
+
58
+ describe(method) do
59
+ context "when type is :#{edge_type}" do
60
+ let(:type) { edge_type }
61
+
62
+ its(method) { should be_true }
63
+
64
+ other_getters.each do |other_type|
65
+ its(other_type) { should be_false }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe GEXF::EdgeSet do
4
+
5
+ def make_edge(attr={})
6
+ mock('edge', :source_id => attr[:source_id],
7
+ :target_id => attr[:target_id],
8
+ :directed? => attr[:type] == GEXF::Edge::DIRECTED,
9
+ :undirected? => attr[:type] == GEXF::Edge::UNDIRECTED)
10
+ end
11
+
12
+ let(:source_id) { '1' }
13
+ let(:target_id) { '11' }
14
+ let(:type) { GEXF::Edge::DIRECTED }
15
+ let(:attrs) { { :type => type,
16
+ :source_id => source_id,
17
+ :target_id => target_id }}
18
+
19
+ let(:arguments) { [] }
20
+ let(:edge) { make_edge(attrs) }
21
+
22
+ let(:edge2) { make_edge(:type => GEXF::Edge::UNDIRECTED,
23
+ :source_id => '2',
24
+ :target_id => '22') }
25
+
26
+ let(:edge3) { make_edge(:type => GEXF::Edge::DIRECTED,
27
+ :source_id => '3',
28
+ :target_id => '33') }
29
+
30
+ let(:edge4) { make_edge(:type => GEXF::Edge::DIRECTED,
31
+ :source_id => '3',
32
+ :target_id => '22') }
33
+
34
+
35
+ let(:edgeset) { GEXF::EdgeSet.new(*arguments) }
36
+
37
+ describe "#<<" do
38
+ subject { edgeset << edge }
39
+
40
+ context "when edge is directed" do
41
+ it "adds the edge to the @data hash, using the :source_id as key" do
42
+ subject.to_hash.should have_key(edge.source_id)
43
+ subject.to_hash.should_not have_key(edge.target_id)
44
+ end
45
+ end
46
+
47
+ context "when edge is undirected" do
48
+ let(:type) { GEXF::Edge::UNDIRECTED }
49
+
50
+ it "adds the edge to the data hash, using both :source_id, and the :target_id as keys" do
51
+ subject.to_hash.should have_key(edge.source_id)
52
+ subject.to_hash.should have_key(edge.target_id)
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#count" do
58
+ let(:other_edge) { make_edge(:type => other_edge_type,
59
+ :source_id => '3',
60
+ :target_id => '33') }
61
+
62
+ subject { edgeset << edge << other_edge }
63
+
64
+ context "when adding two directed edges" do
65
+ let(:other_edge_type) { GEXF::Edge::DIRECTED }
66
+
67
+ it "creates 2 keys in the hash, returns 2" do
68
+ subject.should have(2).items
69
+ subject.to_hash.keys.should have(2).items
70
+ end
71
+ end
72
+
73
+ context "when adding a directed and an undirected edge" do
74
+ let(:other_edge_type) { GEXF::Edge::UNDIRECTED }
75
+
76
+ it "creates 3 keys in the hash, returns 2" do
77
+ subject.should have(2).items
78
+ subject.to_hash.keys.should have(3).items
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#map" do
84
+ subject { edgeset << edge << edge2 << edge3 << edge4 }
85
+
86
+ it "returns a list of unique edges" do
87
+ subject.map(&:source_id).should == ['1', '2', '3', '3']
88
+ subject.map(&:target_id).should == ['11', '22', '33', '22']
89
+ end
90
+
91
+ end
92
+
93
+ describe "#select" do
94
+ subject { edgeset << edge << edge2 << edge3 }
95
+
96
+ it "selects two directed edges" do
97
+ subject.select(&:directed?).should include(edge, edge3)
98
+ end
99
+ it "selects an undirected edge" do
100
+ subject.select(&:undirected?).should include(edge2)
101
+ end
102
+ end
103
+
104
+ end
105
+
@@ -0,0 +1,172 @@
1
+ require 'spec_helper'
2
+
3
+ describe GEXF::Graph do
4
+ let(:edgetype) { nil }
5
+ let(:idtype) { nil }
6
+ let(:mode) { nil }
7
+ let(:opts) {{ :defaultedgetype => edgetype,
8
+ :idtype => idtype,
9
+ :mode => mode }}
10
+
11
+ let(:graph) { GEXF::Graph.new(opts) }
12
+
13
+
14
+ describe "default getters" do
15
+ subject { graph }
16
+
17
+ context "when params are valid" do
18
+ its(:defaultedgetype) { should == GEXF::Edge::UNDIRECTED }
19
+ its(:idtype) { should == GEXF::Graph::STRING }
20
+ its(:mode) { should == GEXF::Graph::STATIC }
21
+ its(:nodes) { should be_empty }
22
+ its(:edges) { should be_empty }
23
+ end
24
+
25
+ context "when params are not valid" do
26
+ [:defaultedgetype, :idtype, :mode].each do |param|
27
+
28
+ let(param) { :FOO }
29
+
30
+ describe "when #{param} is invalid" do
31
+ it "raises an argument error" do
32
+ expect { subject }.to raise_error(ArgumentError)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ describe "#define_node_attribute" do
40
+ let(:attr_type) { GEXF::Attribute::STRING }
41
+ let(:attr_id) { nil }
42
+ let(:default) { 'home sweet home' }
43
+ let(:title) { 'page-title' }
44
+ let(:attr_opts) {{ :default => default,
45
+ :attr_id => attr_id }}
46
+
47
+
48
+ subject { graph.define_node_attribute(title, attr_opts) }
49
+
50
+ it "delegates to @nodes" do
51
+
52
+ new_attribute = double('attribute')
53
+
54
+ graph.nodes.should_receive(:define_attribute).
55
+ with('1', title, attr_opts).
56
+ and_return(new_attribute)
57
+
58
+ subject.should == new_attribute
59
+ end
60
+ end
61
+
62
+ describe "#define_edge_attribute" do
63
+ let(:attr_type) { GEXF::Attribute::STRING }
64
+ let(:attr_id) { nil }
65
+ let(:default) { 'home sweet home' }
66
+ let(:title) { 'page-title' }
67
+ let(:attr_opts) {{ :default => default,
68
+ :attr_id => attr_id }}
69
+
70
+
71
+ subject { graph.define_edge_attribute(title, attr_opts) }
72
+
73
+ it "delegates to @nodes" do
74
+
75
+ new_attribute = double('attribute')
76
+
77
+ graph.edges.should_receive(:define_attribute).
78
+ with('1', title, attr_opts).
79
+ and_return(new_attribute)
80
+
81
+ subject.should == new_attribute
82
+ end
83
+ end
84
+
85
+ describe "#create_node" do
86
+ let(:node_id) { 'node_21' }
87
+ let(:node_opts) {{ :label => 'my node' }}
88
+ let(:create_opts) { node_opts }
89
+
90
+ before(:each) do
91
+ @node = mock('node')
92
+ nodeset = mock('nodeset')
93
+
94
+ GEXF::NodeSet.stub(:new).and_return(nodeset)
95
+ nodeset.should_receive(:<<).at_least(:once).with(@node)
96
+ end
97
+
98
+ context "when :id is provided" do
99
+ let(:create_opts) { node_opts.merge(:id => node_id) }
100
+
101
+ it "uses the id provided to create a node" do
102
+ GEXF::Node.should_receive(:new).
103
+ with(node_id, graph, node_opts).
104
+ and_return(@node)
105
+
106
+ graph.create_node(create_opts) == @node
107
+ end
108
+ end
109
+
110
+ context "when :id is not provided" do
111
+ it "auto-assigns the id using the internal counter" do
112
+ 3.times do |n|
113
+ GEXF::Node.should_receive(:new).
114
+ once.ordered.
115
+ with((n+1).to_s, graph, node_opts).
116
+ and_return(@node)
117
+ end
118
+
119
+ 3.times { graph.create_node(create_opts) }
120
+ end
121
+ end
122
+ end
123
+
124
+ describe "#create_edge" do
125
+ let(:edge_label) { 'bar' }
126
+ let(:source_id) { '2' }
127
+ let(:target_id) { '32' }
128
+ let(:source) { mock('source', :id => source_id) }
129
+ let(:target) { mock('target', :id => target_id) }
130
+ let(:edge_opts) {{:label => edge_label }}
131
+
132
+ subject { graph.create_edge(source, target, edge_opts) }
133
+
134
+ before(:each) do
135
+ @edge = mock('edge')
136
+ edgeset = mock('edgeset')
137
+
138
+ GEXF::EdgeSet.stub(:new).and_return(edgeset)
139
+ edgeset.should_receive(:<<).at_least(:once).with(@edge)
140
+ end
141
+
142
+ context "when no :id or :type param is provided" do
143
+ it "auto-assigns the edge :id using the internal counter, and the :type using :edgetype" do
144
+
145
+ GEXF::Edge.should_receive(:new).
146
+ with('1', source.id, target.id, edge_opts.merge(:graph => graph,
147
+ :type => graph.defaultedgetype)).
148
+ and_return(@edge)
149
+
150
+ subject.should == @edge
151
+ end
152
+ end
153
+
154
+ context "when an :id and a :type are provided" do
155
+
156
+ let(:edge_id) { 'myedge-33' }
157
+ let(:edge_opts) {{ :label => edge_label,
158
+ :id => edge_id,
159
+ :type => GEXF::Edge::DIRECTED }}
160
+
161
+ it "passes the params to the Edge constructor" do
162
+ expected_opts = edge_opts.reject {|k,v| k == :id }.merge(:graph => graph)
163
+
164
+ GEXF::Edge.should_receive(:new).
165
+ with(edge_id, source.id, target.id, expected_opts).
166
+ and_return(@edge)
167
+
168
+ subject.should == @edge
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe GEXF::Node do
4
+
5
+ let(:indegree) { GEXF::Attribute.new('1', 'indegree', type: GEXF::Attribute::INTEGER) }
6
+ let(:outdegree) { GEXF::Attribute.new('2', 'outdegree', type: GEXF::Attribute::INTEGER) }
7
+
8
+ let(:attribute_definitions) {{ '1' => indegree,
9
+ '2' => outdegree }}
10
+
11
+ let(:id) { 22 }
12
+ let(:idtype) { GEXF::Graph::STRING }
13
+ let(:collection) { mock('nodeset', :attribute_definitions => attribute_definitions) }
14
+ let(:edges) { mock('edgeset') }
15
+ let(:graph) { double('graph', :nodes => collection, :idtype => idtype, :edges => edges) }
16
+ let(:label) { 'foo' }
17
+ let(:attributes) {{ }}
18
+ let(:options) {{ :label => label, :attributes => attributes }}
19
+ let(:arguments) { [id, graph, options] }
20
+ let(:node) { GEXF::Node.new(*arguments) }
21
+
22
+ subject { node }
23
+
24
+ it "includes the GEXF::Attribute::Assignable module" do
25
+ subject.class.include?(GEXF::Attribute::Assignable)
26
+ end
27
+
28
+ context "when graph :idtype is string" do
29
+ its(:id) { should == id.to_s }
30
+ end
31
+
32
+ context "when graph :idtype is integer" do
33
+ let(:idtype) { GEXF::Graph::INTEGER }
34
+ its(:id) { should == id.to_i }
35
+ end
36
+
37
+ describe "#label" do
38
+ context "option provided" do
39
+ its(:label) { should == label }
40
+ end
41
+ context "option omitted" do
42
+ let(:options) {{}}
43
+ its(:label) { should == id.to_s }
44
+ end
45
+ end
46
+
47
+ describe "attributes" do
48
+ context "when no attributes are defined" do
49
+ let(:attribute_definitions) {{}}
50
+ its(:attributes) { should be_empty }
51
+ end
52
+ context "when no attributes are supplied" do
53
+ its(:attributes) { should == { 'indegree' => nil, 'outdegree' => nil }}
54
+ end
55
+ context "when attributes are supplied" do
56
+ let(:attributes) {{ :outdegree => '24' }}
57
+ its(:attributes) { should == { 'indegree' => nil, 'outdegree' => 24 }}
58
+ end
59
+ end
60
+
61
+ describe "#connect_to" do
62
+
63
+ let(:edge_opts) {{ :type => GEXF::Edge::DIRECTED }}
64
+ let(:other_node) { mock('other_node') }
65
+ let(:new_edge) { mock('new-edge') }
66
+
67
+ subject { node.connect_to(other_node, edge_opts) }
68
+
69
+ it "adds the target to the nodes collection, creates and returns a new edge" do
70
+
71
+ collection.should_receive(:<<).with(other_node)
72
+
73
+ graph.should_receive(:create_edge).
74
+ with(node, other_node, edge_opts).
75
+ and_return(new_edge)
76
+
77
+ subject.should == new_edge
78
+ end
79
+ end
80
+
81
+ describe "#create_and_connect_to" do
82
+ let(:edge_opts) {{ :type => GEXF::Edge::DIRECTED }}
83
+ let(:node_attrs) {{ :label => 'other node'}}
84
+ let(:new_node) { mock('new_node') }
85
+
86
+ subject { node.create_and_connect_to(node_attrs, edge_opts) }
87
+
88
+ it "creates the node, adds it to nodes collection, and returns it" do
89
+ graph.should_receive(:create_node).with(node_attrs).and_return(new_node)
90
+ collection.should_receive(:<<).with(new_node)
91
+ graph.should_receive(:create_edge).with(node, new_node, edge_opts)
92
+
93
+ subject.should == new_node
94
+ end
95
+ end
96
+
97
+ describe "#connections" do
98
+ subject { node.connections }
99
+
100
+ it "delegates to graph.edges[node.id]" do
101
+ edges.should_receive(:[]).with(node.id)
102
+ subject
103
+ end
104
+ end
105
+ end