graphs 0.2.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/lib/graph.rb +571 -0
- data/lib/graphs/gdf.rb +225 -0
- data/lib/graphs/json.rb +71 -0
- data/tests/edge_tests.rb +92 -0
- data/tests/gdf_tests.rb +377 -0
- data/tests/graph_tests.rb +703 -0
- data/tests/json_tests.rb +149 -0
- data/tests/node_tests.rb +141 -0
- data/tests/tests.rb +24 -0
- metadata +137 -0
- metadata.gz.sig +0 -0
data/lib/graphs/gdf.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# -*- coding: UTF-8 -*-
|
3
|
+
|
4
|
+
require 'csv'
|
5
|
+
require_relative '../graph'
|
6
|
+
|
7
|
+
class Graph
|
8
|
+
# Returns a GDF version of the current graph
|
9
|
+
# @param opts [Hash] A customizable set of options
|
10
|
+
# @return [String]
|
11
|
+
# @see GDF.unparse
|
12
|
+
def to_gdf(opts=nil)
|
13
|
+
GDF::unparse(self, opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Write the current graph into a GDF file. This method is used internally,
|
17
|
+
# use Graph#write instead.
|
18
|
+
# @param filename [String] a valid filename
|
19
|
+
# @return []
|
20
|
+
# @see GDF.unparse
|
21
|
+
def write_gdf(filename, opts=nil)
|
22
|
+
gdf = GDF::unparse(self, opts)
|
23
|
+
f = File.open(filename, 'w')
|
24
|
+
f.write(gdf)
|
25
|
+
f.close
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# GDF-related functions
|
30
|
+
# see http://guess.wikispot.org/The_GUESS_.gdf_format
|
31
|
+
module GDF
|
32
|
+
|
33
|
+
# Node fields definition
|
34
|
+
NODEDEF = 'nodedef>'
|
35
|
+
|
36
|
+
# Edge fields definition
|
37
|
+
EDGEDEF = 'edgedef>'
|
38
|
+
|
39
|
+
# Non-string predefined node properties
|
40
|
+
PREDEFINED_NODE_PROPS = {
|
41
|
+
'x' => 'float',
|
42
|
+
'y' => 'float',
|
43
|
+
'visible' => 'boolean',
|
44
|
+
'fixed' => 'boolean',
|
45
|
+
'style' => 'int',
|
46
|
+
'width' => 'float',
|
47
|
+
'height' => 'float'
|
48
|
+
}
|
49
|
+
|
50
|
+
# Non-string predefined edge properties
|
51
|
+
PREDEFINED_EDGE_PROPS = {
|
52
|
+
'visible' => 'boolean',
|
53
|
+
'weight' => 'float',
|
54
|
+
'width' => 'float',
|
55
|
+
'directed' => 'boolean',
|
56
|
+
'labelvisible' => 'boolean'
|
57
|
+
}
|
58
|
+
|
59
|
+
# Loads a GDF file and return a new Graph object
|
60
|
+
# @param filename [String] a valid filename
|
61
|
+
# @see GDF.parse
|
62
|
+
def self.load(filename)
|
63
|
+
self.parse(File.read(filename))
|
64
|
+
end
|
65
|
+
|
66
|
+
# Parse some GDF text and return a new Graph object
|
67
|
+
# @param content [String] a valid GDF String
|
68
|
+
# @see GDF.load
|
69
|
+
# @see GDF.unparse
|
70
|
+
def self.parse(content)
|
71
|
+
|
72
|
+
if (content.nil? || content.length == 0)
|
73
|
+
return Graph.new([],[])
|
74
|
+
end
|
75
|
+
|
76
|
+
fields_split = /[\t ]*,[\t ]*/
|
77
|
+
|
78
|
+
nodedef_len, edgedef_len = NODEDEF.length, EDGEDEF.length
|
79
|
+
|
80
|
+
current_def = nil
|
81
|
+
|
82
|
+
nodes, edges = [], []
|
83
|
+
current_set = nil
|
84
|
+
|
85
|
+
content.each_line do |line|
|
86
|
+
line.strip!
|
87
|
+
is_nodedef = line.start_with? NODEDEF
|
88
|
+
is_edgedef = !is_nodedef && line.start_with?(EDGEDEF)
|
89
|
+
|
90
|
+
if is_nodedef || is_edgedef
|
91
|
+
line.slice!(0, is_nodedef ? nodedef_len : edgedef_len)
|
92
|
+
line.strip!
|
93
|
+
defaults = is_nodedef ? PREDEFINED_NODE_PROPS : PREDEFINED_EDGE_PROPS
|
94
|
+
current_def = line.split(fields_split).map do |l|
|
95
|
+
read_def(l, defaults)
|
96
|
+
end
|
97
|
+
|
98
|
+
current_set = is_nodedef ? nodes : edges
|
99
|
+
else
|
100
|
+
el = {}
|
101
|
+
fields = line.parse_csv || [nil]
|
102
|
+
fields.zip(current_def).each do |val,label_type|
|
103
|
+
label, type, default = label_type
|
104
|
+
el[label] = parse_field(val, type, default)
|
105
|
+
end
|
106
|
+
current_set << el
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
Graph.new(nodes, edges)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Return a GDF String which describe the given Graph
|
114
|
+
# @param graph [Graph]
|
115
|
+
# @param opts [Hash] A customizable set of options
|
116
|
+
# @return [String]
|
117
|
+
# @see Graph#write
|
118
|
+
def self.unparse(graph, opts=nil)
|
119
|
+
# nodes
|
120
|
+
gdf_s = NODEDEF
|
121
|
+
|
122
|
+
if (graph.nodes.length == 0)
|
123
|
+
return gdf_s
|
124
|
+
end
|
125
|
+
|
126
|
+
keys = graph.nodes[0].keys
|
127
|
+
nodedef = keys.map { |k| [k, self.get_type(graph.nodes[0][k], opts)] }
|
128
|
+
|
129
|
+
gdf_s += (nodedef.map {|nd| nd.join(' ')}).join(',') + "\n"
|
130
|
+
|
131
|
+
graph.nodes.each do |n|
|
132
|
+
gdf_s += n.values.to_csv
|
133
|
+
end
|
134
|
+
|
135
|
+
# edges
|
136
|
+
gdf_s += EDGEDEF
|
137
|
+
|
138
|
+
return gdf_s if graph.edges.empty?
|
139
|
+
|
140
|
+
keys = graph.edges[0].keys
|
141
|
+
edgedef = keys.map { |k| [k, self.get_type(graph.edges[0][k], opts)] }
|
142
|
+
|
143
|
+
gdf_s += (edgedef.map {|ed| ed.join(' ')}).join(',') + "\n"
|
144
|
+
|
145
|
+
graph.edges.each do |e|
|
146
|
+
gdf_s += e.values.to_csv
|
147
|
+
end
|
148
|
+
|
149
|
+
gdf_s
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
# Read the value of a node/edge field, and return the value's
|
155
|
+
# type (String)
|
156
|
+
# @param v
|
157
|
+
# @param opts [Hash]
|
158
|
+
# @return [String]
|
159
|
+
def self.get_type(v, opts=nil)
|
160
|
+
opts = opts || {}
|
161
|
+
|
162
|
+
if v.is_a?(Fixnum) || v.is_a?(Bignum)
|
163
|
+
if opts[:gephi] || v <= 2147483647
|
164
|
+
return 'INT'
|
165
|
+
else
|
166
|
+
return 'BIGINT'
|
167
|
+
end
|
168
|
+
elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
169
|
+
return 'BOOLEAN'
|
170
|
+
elsif v.is_a?(Float)
|
171
|
+
return 'FLOAT'
|
172
|
+
else
|
173
|
+
return 'VARCHAR'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# read a node/edge def, and return a list where the first element is the
|
178
|
+
# label of the field, the second its type, and the third and last one its
|
179
|
+
# default value
|
180
|
+
# @param s
|
181
|
+
# @param defaults
|
182
|
+
def self.read_def(s, defaults={})
|
183
|
+
label, *params = s.split(/\s+/)
|
184
|
+
default = nil
|
185
|
+
|
186
|
+
if params.empty?
|
187
|
+
value_type = defaults[label.downcase] || 'VARCHAR'
|
188
|
+
else
|
189
|
+
value_type = params.shift
|
190
|
+
|
191
|
+
if params.shift == 'default'
|
192
|
+
default = parse_field(params.shift, value_type.downcase)
|
193
|
+
end
|
194
|
+
|
195
|
+
if /((tiny|small|medium|big)?int|integer)/i.match(value_type)
|
196
|
+
value_type = 'int'
|
197
|
+
elsif /(float|real|double)/i.match(value_type)
|
198
|
+
value_type = 'float'
|
199
|
+
elsif (value_type.downcase === 'boolean')
|
200
|
+
value_type = 'boolean'
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
[label, value_type, default]
|
205
|
+
end
|
206
|
+
|
207
|
+
# read a field and return its value
|
208
|
+
# @param f
|
209
|
+
# @param value_type [String]
|
210
|
+
# @param default
|
211
|
+
def self.parse_field(f, value_type, default=nil)
|
212
|
+
case value_type
|
213
|
+
when 'int' then (f || default).to_i
|
214
|
+
when 'float' then (f || default).to_f
|
215
|
+
when 'boolean' then
|
216
|
+
if f.nil?
|
217
|
+
default.nil? ? false : default
|
218
|
+
else
|
219
|
+
/^(?:null|false|)$/i !~ f
|
220
|
+
end
|
221
|
+
else f || default
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
data/lib/graphs/json.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# -*- coding: UTF-8 -*-
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
require_relative '../graph'
|
6
|
+
|
7
|
+
class Graph
|
8
|
+
# Returns a JSON version of the current graph
|
9
|
+
# @param opts [Hash] A customizable set of options
|
10
|
+
# @return [String]
|
11
|
+
# @see JSONGraph.unparse
|
12
|
+
def to_json(opts=nil)
|
13
|
+
JSONGraph::unparse(self, opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Write the current graph into a JSON file. This method is used internally,
|
17
|
+
# use Graph#write instead.
|
18
|
+
# @param filename [String] a valid filename
|
19
|
+
# @return []
|
20
|
+
# @see JSON.unparse
|
21
|
+
def write_json(filename, opts=nil)
|
22
|
+
json = JSONGraph::unparse(self, opts)
|
23
|
+
f = File.open(filename, 'w')
|
24
|
+
f.write(json)
|
25
|
+
f.close
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# JSON-related functions
|
30
|
+
module JSONGraph
|
31
|
+
|
32
|
+
# Loads a JSON file and return a new Graph object
|
33
|
+
# @param filename [String] a valid filename
|
34
|
+
# @return [Graph]
|
35
|
+
# @see JSONGraph.parse
|
36
|
+
def self.load(filename)
|
37
|
+
self.parse(File.read(filename))
|
38
|
+
end
|
39
|
+
|
40
|
+
# Parse some JSON text and return a new Graph object
|
41
|
+
# @param content [String] a valid GDF String
|
42
|
+
# @return [Graph]
|
43
|
+
# @see JSONGraph.load
|
44
|
+
# @see JSONGraph.unparse
|
45
|
+
def self.parse(content)
|
46
|
+
|
47
|
+
if (content.nil? || content.length == 0)
|
48
|
+
return Graph.new([],[])
|
49
|
+
end
|
50
|
+
|
51
|
+
content = JSON.parse content
|
52
|
+
|
53
|
+
nodes = content['nodes']
|
54
|
+
edges = content['edges']
|
55
|
+
|
56
|
+
Graph.new(nodes, edges)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Return a JSON String which describe the given Graph
|
60
|
+
# @param graph [Graph]
|
61
|
+
# @param opts [Hash] A customizable set of options
|
62
|
+
# @return [String]
|
63
|
+
# @see Graph#write
|
64
|
+
def self.unparse(graph, opts=nil)
|
65
|
+
|
66
|
+
nodes = graph.nodes.map { |n| n.to_hash }
|
67
|
+
edges = graph.edges.map { |e| e.to_hash }
|
68
|
+
|
69
|
+
JSON.dump({ 'nodes' => nodes, 'edges' => edges })
|
70
|
+
end
|
71
|
+
end
|
data/tests/edge_tests.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# -*- coding: UTF-8 -*-
|
3
|
+
|
4
|
+
class Edge_test < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@@empty = Graph::Node.new
|
8
|
+
@@alice = Graph::Node.new('label' => 'Alice')
|
9
|
+
|
10
|
+
# Alice ----> Bob
|
11
|
+
# ↑ ↑
|
12
|
+
# | |
|
13
|
+
# Oscar -------'
|
14
|
+
@@sample_graph = Graph.new(
|
15
|
+
[
|
16
|
+
{ 'label' => 'Alice' },
|
17
|
+
{ 'label' => 'Bob' },
|
18
|
+
{ 'label' => 'Oscar' }
|
19
|
+
],
|
20
|
+
[
|
21
|
+
{ 'node1' => 'Alice', 'node2' => 'Bob' },
|
22
|
+
{ :node1 => 'Oscar', 'node2' => 'Alice'},
|
23
|
+
{ 'node1' => 'Oscar', :node2 => 'Bob'}
|
24
|
+
]
|
25
|
+
)
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_edge_node1_attr
|
30
|
+
assert_equal('Alice', @@sample_graph.edges[0].node1)
|
31
|
+
assert_equal('Oscar', @@sample_graph.edges[1].node1)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_edge_node2_attr
|
35
|
+
assert_equal('Alice', @@sample_graph.edges[1].node2)
|
36
|
+
assert_equal('Bob', @@sample_graph.edges[2].node2)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_edge_update
|
40
|
+
|
41
|
+
e = Graph::Edge.new
|
42
|
+
|
43
|
+
assert_equal(true, e.update({}).is_a?(Graph::Edge))
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_edge_init_with_another_edge
|
47
|
+
|
48
|
+
e = Graph::Edge.new({ :foo => 'bar' })
|
49
|
+
|
50
|
+
assert_equal( e, Graph::Edge.new(e) )
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class EdgeArray_test < Test::Unit::TestCase
|
57
|
+
|
58
|
+
def test_edgearray_push_edge
|
59
|
+
|
60
|
+
e = Graph::Edge.new({ :foo => 42 })
|
61
|
+
ea = Graph::EdgeArray.new([])
|
62
|
+
|
63
|
+
ea.push(e)
|
64
|
+
|
65
|
+
assert_equal(e, ea[0])
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_edgearray_push_hash
|
70
|
+
|
71
|
+
e = { :foo => 42 }
|
72
|
+
ea = Graph::EdgeArray.new([])
|
73
|
+
|
74
|
+
ea.push(e)
|
75
|
+
|
76
|
+
assert_equal(Graph::Edge.new(e), ea[0])
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_edgearray_push_no_edge_nor_hash
|
81
|
+
|
82
|
+
ea = Graph::EdgeArray.new([])
|
83
|
+
|
84
|
+
assert_raise(TypeError) do
|
85
|
+
|
86
|
+
ea.push(42)
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/tests/gdf_tests.rb
ADDED
@@ -0,0 +1,377 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# -*- coding: UTF-8 -*-
|
3
|
+
|
4
|
+
module Utils
|
5
|
+
def self.get_sample_graph
|
6
|
+
@@sample_graph_1
|
7
|
+
end
|
8
|
+
|
9
|
+
@@sample_graph_1 = "nodedef>label VARCHAR,num INT,biglabel VARCHAR\n"
|
10
|
+
@@sample_graph_1 += "toto,14,TOTO\nlala,5,LALA\ntiti,988,TITI\n"
|
11
|
+
@@sample_graph_1 += "edgedef>node1 VARCHAR,node2 VARCHAR,directed BOOLEAN\n"
|
12
|
+
@@sample_graph_1 += "toto,lala,true\nlala,titi,true\n"
|
13
|
+
@@sample_graph_1 += "titi,lala,false\ntiti,toto,true\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
class GDF_Graph_test < Test::Unit::TestCase
|
17
|
+
|
18
|
+
# == Graph#to_gdf == #
|
19
|
+
|
20
|
+
def test_empty_graph_to_gdf
|
21
|
+
g = Graph.new
|
22
|
+
empty_gdf = "nodedef>"
|
23
|
+
|
24
|
+
assert_equal(empty_gdf, g.to_gdf)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_sample_graph_to_gdf
|
28
|
+
gdf = Utils::get_sample_graph
|
29
|
+
g = GDF::parse(gdf)
|
30
|
+
assert_equal(gdf, g.to_gdf)
|
31
|
+
end
|
32
|
+
|
33
|
+
# == Graph#write('….gdf') == #
|
34
|
+
|
35
|
+
def test_empty_graph_write_gdf
|
36
|
+
g = Graph.new
|
37
|
+
|
38
|
+
f = Tempfile.new([ 'foo', '.gdf' ])
|
39
|
+
f.close
|
40
|
+
|
41
|
+
g.write(f.path)
|
42
|
+
g2 = GDF.load(f.path)
|
43
|
+
|
44
|
+
assert_equal(g, g2)
|
45
|
+
f.unlink
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class GDF_test < Test::Unit::TestCase
|
50
|
+
|
51
|
+
# == GDF::parse == #
|
52
|
+
|
53
|
+
def test_parse_empty_graph
|
54
|
+
g = GDF::parse('')
|
55
|
+
|
56
|
+
assert_equal([], g.nodes)
|
57
|
+
assert_equal([], g.edges)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_parse_space_after_nodedef
|
61
|
+
g = GDF::parse("nodedef> foo VARCHAR\nbar")
|
62
|
+
|
63
|
+
assert_equal(1, g.nodes.length)
|
64
|
+
assert_equal('bar', g.nodes[0]['foo'])
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_parse_quoted_value
|
68
|
+
code = <<EOC
|
69
|
+
nodedef>label VARCHAR
|
70
|
+
"foo"
|
71
|
+
EOC
|
72
|
+
|
73
|
+
g = GDF::parse(code)
|
74
|
+
assert_equal(1, g.nodes.length)
|
75
|
+
assert_equal('foo', g.nodes[0].attrs['label'])
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_parse_quoted_value_with_quote
|
79
|
+
code = <<EOC
|
80
|
+
nodedef>label VARCHAR
|
81
|
+
"fo""o"
|
82
|
+
EOC
|
83
|
+
|
84
|
+
g = GDF::parse(code)
|
85
|
+
assert_equal(1, g.nodes.length)
|
86
|
+
assert_equal('fo"o', g.nodes[0].attrs['label'])
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_parse_value_with_comma
|
90
|
+
code = <<EOC
|
91
|
+
nodedef>label VARCHAR,num INT
|
92
|
+
"foo,bar",42
|
93
|
+
EOC
|
94
|
+
|
95
|
+
g = GDF::parse(code)
|
96
|
+
assert_equal(1, g.nodes.length)
|
97
|
+
assert_equal('foo,bar', g.nodes[0].attrs['label'])
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_parse_empty_graph_with_nodedef
|
101
|
+
|
102
|
+
s = "nodedef>label VARCHAR\n"
|
103
|
+
|
104
|
+
g = GDF::parse(s)
|
105
|
+
|
106
|
+
assert_equal([], g.nodes)
|
107
|
+
assert_equal([], g.edges)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_parse_empty_graph_with_nodedef_and_edgedef
|
111
|
+
s = "nodedef>label VARCHAR\nedgedef>node1 VARCHAR,node2 VARCHAR\n"
|
112
|
+
g = GDF::parse(s)
|
113
|
+
|
114
|
+
assert_equal([], g.nodes)
|
115
|
+
assert_equal([], g.edges)
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_parse_one_node_no_edge_string_field
|
119
|
+
s = "nodedef>label VARCHAR\nfoo\n"
|
120
|
+
g = GDF::parse(s)
|
121
|
+
|
122
|
+
assert_equal(1, g.nodes.length)
|
123
|
+
assert_equal('foo', g.nodes[0]['label'])
|
124
|
+
assert_equal([], g.edges)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_parse_one_node_no_edge_tinyint_field
|
128
|
+
s = "nodedef>num TINYINT\n3\n"
|
129
|
+
g = GDF::parse(s)
|
130
|
+
|
131
|
+
assert_equal(1, g.nodes.length)
|
132
|
+
assert_equal(3, g.nodes[0]['num'])
|
133
|
+
assert_equal([], g.edges)
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_parse_one_node_no_edge_smallint_field
|
137
|
+
s = "nodedef>num SMALLINT\n3\n"
|
138
|
+
g = GDF::parse(s)
|
139
|
+
|
140
|
+
assert_equal(1, g.nodes.length)
|
141
|
+
assert_equal(3, g.nodes[0]['num'])
|
142
|
+
assert_equal([], g.edges)
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_parse_one_node_no_edge_int_field
|
146
|
+
s = "nodedef>num INT\n3\n"
|
147
|
+
g = GDF::parse(s)
|
148
|
+
|
149
|
+
assert_equal(1, g.nodes.length)
|
150
|
+
assert_equal(3, g.nodes[0]['num'])
|
151
|
+
assert_equal([], g.edges)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_parse_one_node_no_edge_negative_int_field
|
155
|
+
s = "nodedef>num INT\n-1337\n"
|
156
|
+
g = GDF::parse(s)
|
157
|
+
|
158
|
+
assert_equal(1, g.nodes.length)
|
159
|
+
assert_equal(-1337, g.nodes[0]['num'])
|
160
|
+
assert_equal([], g.edges)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_parse_one_node_no_edge_bigint_field
|
164
|
+
s = "nodedef>num BIGINT\n3\n"
|
165
|
+
g = GDF::parse(s)
|
166
|
+
|
167
|
+
assert_equal(1, g.nodes.length)
|
168
|
+
assert_equal(3, g.nodes[0]['num'])
|
169
|
+
assert_equal([], g.edges)
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_parse_one_node_no_edge_float_field
|
173
|
+
s = "nodedef>num FLOAT\n3\n"
|
174
|
+
g = GDF::parse(s)
|
175
|
+
|
176
|
+
assert_equal(1, g.nodes.length)
|
177
|
+
assert_equal(3.0, g.nodes[0]['num'])
|
178
|
+
assert_equal([], g.edges)
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_parse_one_node_no_edge_double_field
|
182
|
+
s = "nodedef>num FLOAT\n3\n"
|
183
|
+
g = GDF::parse(s)
|
184
|
+
|
185
|
+
assert_equal(1, g.nodes.length)
|
186
|
+
assert_equal(3.0, g.nodes[0]['num'])
|
187
|
+
assert_equal([], g.edges)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_parse_one_node_no_edge_real_field
|
191
|
+
s = "nodedef>num FLOAT\n3\n"
|
192
|
+
g = GDF::parse(s)
|
193
|
+
|
194
|
+
assert_equal(1, g.nodes.length)
|
195
|
+
assert_equal(3.0, g.nodes[0]['num'])
|
196
|
+
assert_equal([], g.edges)
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_parse_one_node_no_edge_negative_real_field
|
200
|
+
s = "nodedef>num FLOAT\n-42.14\n"
|
201
|
+
g = GDF::parse(s)
|
202
|
+
|
203
|
+
assert_equal(1, g.nodes.length)
|
204
|
+
assert_equal(-42.14, g.nodes[0]['num'])
|
205
|
+
assert_equal([], g.edges)
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_parse_one_node_no_edge_unknow_field_type
|
209
|
+
s = "nodedef>foo BAR\nfoobar"
|
210
|
+
g = GDF::parse(s)
|
211
|
+
|
212
|
+
assert_equal(1, g.nodes.length)
|
213
|
+
assert_equal('foobar', g.nodes[0]['foo'])
|
214
|
+
assert_equal([], g.edges)
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_parse_one_node_no_type
|
218
|
+
s = "nodedef>foo\nfoobar"
|
219
|
+
g = GDF::parse(s)
|
220
|
+
|
221
|
+
assert_equal(1, g.nodes.length)
|
222
|
+
assert_equal('foobar', g.nodes[0]['foo'])
|
223
|
+
assert_equal([], g.edges)
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_parse_one_node_builtin_visible_prop_no_type
|
227
|
+
s = "nodedef>visible,foo VARCHAR\n,bar\n"
|
228
|
+
g = GDF::parse(s)
|
229
|
+
|
230
|
+
assert_equal(1, g.nodes.length)
|
231
|
+
assert_equal('bar', g.nodes[0]['foo'])
|
232
|
+
assert_equal(false, g.nodes[0]['visible'])
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_parse_one_node_builtin_visible_prop_with_type
|
236
|
+
s = "nodedef>visible BOOLEAN,foo VARCHAR\n,bar\n"
|
237
|
+
g = GDF::parse(s)
|
238
|
+
|
239
|
+
assert_equal(1, g.nodes.length)
|
240
|
+
assert_equal('bar', g.nodes[0]['foo'])
|
241
|
+
assert_equal(false, g.nodes[0]['visible'])
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_parse_one_node_truthy_boolean_value
|
245
|
+
s = "nodedef>xyz BOOLEAN,foo VARCHAR\nxfalse,bar\n"
|
246
|
+
g = GDF::parse(s)
|
247
|
+
|
248
|
+
assert_equal(1, g.nodes.length)
|
249
|
+
assert_equal('bar', g.nodes[0]['foo'])
|
250
|
+
assert_equal(true, g.nodes[0]['xyz'])
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_parse_one_node_null_boolean_value
|
254
|
+
s = "nodedef>xyz BOOLEAN,foo VARCHAR\nnull,bar\n"
|
255
|
+
g = GDF::parse(s)
|
256
|
+
|
257
|
+
assert_equal(1, g.nodes.length)
|
258
|
+
assert_equal('bar', g.nodes[0]['foo'])
|
259
|
+
assert_equal(false, g.nodes[0]['xyz'])
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_parse_nodes_only_one_empty_boolean_value
|
263
|
+
s = "nodedef>xyz BOOLEAN\n\n\n"
|
264
|
+
g = GDF::parse(s)
|
265
|
+
|
266
|
+
assert_equal(2, g.nodes.length)
|
267
|
+
assert_equal(false, g.nodes[0]['xyz'])
|
268
|
+
assert_equal(false, g.nodes[1]['xyz'])
|
269
|
+
end
|
270
|
+
|
271
|
+
def test_parse_nodes_default_int_value
|
272
|
+
s = "nodedef>xyz INT default 42,foo VARCHAR\n,bar\n12,foo"
|
273
|
+
g = GDF::parse(s)
|
274
|
+
|
275
|
+
assert_equal(2, g.nodes.length)
|
276
|
+
assert_equal(42, g.nodes[0]['xyz'])
|
277
|
+
assert_equal(12, g.nodes[1]['xyz'])
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_parse_nodes_default_boolean_value_true
|
281
|
+
s = "nodedef>xyz BOOLEAN default true,foo VARCHAR\n,bar\nfalse,foo"
|
282
|
+
g = GDF::parse(s)
|
283
|
+
|
284
|
+
assert_equal(2, g.nodes.length)
|
285
|
+
assert_equal(true, g.nodes[0]['xyz'])
|
286
|
+
assert_equal(false, g.nodes[1]['xyz'])
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_parse_nodes_default_boolean_value_false
|
290
|
+
s = "nodedef>xyz BOOLEAN default false,foo VARCHAR\n,bar\ntrue,foo"
|
291
|
+
g = GDF::parse(s)
|
292
|
+
|
293
|
+
assert_equal(2, g.nodes.length)
|
294
|
+
assert_equal(false, g.nodes[0]['xyz'])
|
295
|
+
assert_equal(true, g.nodes[1]['xyz'])
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_parse_one_edge_no_type
|
299
|
+
s = "nodedef>label VARCHAR\nfoobar\nedgedef>node1,node2\nfoobar,foobar"
|
300
|
+
g = GDF::parse(s)
|
301
|
+
|
302
|
+
assert_equal(1, g.nodes.length)
|
303
|
+
assert_equal('foobar', g.nodes[0]['label'])
|
304
|
+
assert_equal('foobar', g.edges[0]['node1'])
|
305
|
+
assert_equal('foobar', g.edges[0]['node2'])
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_parse_sample_graph
|
309
|
+
g = GDF::parse(Utils::get_sample_graph)
|
310
|
+
|
311
|
+
assert_equal(3, g.nodes.length)
|
312
|
+
assert_equal(4, g.edges.length)
|
313
|
+
|
314
|
+
assert_equal('toto', g.nodes[0]['label'])
|
315
|
+
assert_equal('TOTO', g.nodes[0]['biglabel'])
|
316
|
+
assert_equal(988, g.nodes[2]['num'])
|
317
|
+
|
318
|
+
assert_equal('toto', g.edges[0]['node1'])
|
319
|
+
assert_equal('lala', g.edges[0]['node2'])
|
320
|
+
assert_equal(false, g.edges[2]['directed'])
|
321
|
+
|
322
|
+
end
|
323
|
+
|
324
|
+
# == GDF::unparse == #
|
325
|
+
|
326
|
+
def test_unparse_empty_graph
|
327
|
+
g = Graph.new
|
328
|
+
|
329
|
+
s = GDF::unparse(g)
|
330
|
+
|
331
|
+
assert_equal("nodedef>", s)
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_unparse_sample_graph
|
335
|
+
g1 = GDF::parse(Utils::get_sample_graph)
|
336
|
+
g2 = GDF::parse(GDF::unparse(g1))
|
337
|
+
|
338
|
+
assert_equal(g1, g2)
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_unparse_big_int
|
342
|
+
n = 2**40
|
343
|
+
g = Graph.new([{'n'=>n}])
|
344
|
+
gdf = GDF::unparse(g)
|
345
|
+
|
346
|
+
assert_equal("nodedef>n BIGINT\n#{n}\nedgedef>", gdf)
|
347
|
+
end
|
348
|
+
|
349
|
+
def test_unparse_big_int_gephi
|
350
|
+
n = 2**40
|
351
|
+
g = Graph.new([{'n'=>n}])
|
352
|
+
gdf = GDF::unparse(g, {:gephi=>true})
|
353
|
+
|
354
|
+
assert_equal("nodedef>n INT\n#{n}\nedgedef>", gdf)
|
355
|
+
end
|
356
|
+
|
357
|
+
def test_unparse_float_field
|
358
|
+
g = Graph.new([{ 'n' => 3.14 }])
|
359
|
+
gdf = GDF::unparse(g)
|
360
|
+
|
361
|
+
assert_equal("nodedef>n FLOAT\n3.14\nedgedef>", gdf)
|
362
|
+
end
|
363
|
+
|
364
|
+
def test_unparse_value_with_quote
|
365
|
+
g = Graph.new([{'n' => 'foo"bar'}])
|
366
|
+
gdf = GDF::unparse(g)
|
367
|
+
|
368
|
+
assert_equal("nodedef>n VARCHAR\n\"foo\"\"bar\"\nedgedef>", gdf)
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_unparse_value_with_comma
|
372
|
+
g = Graph.new([{'n' => 'foo,bar'}])
|
373
|
+
gdf = GDF::unparse(g)
|
374
|
+
|
375
|
+
assert_equal("nodedef>n VARCHAR\n\"foo,bar\"\nedgedef>", gdf)
|
376
|
+
end
|
377
|
+
end
|