1 local graph
= require
"graph"
2 local logger
= require
"logging.console"
3 local pretty
= require
"pl.pretty"
5 local function tmpname()
6 if graph
._SYSTEM
== "Win32" then
7 return "."..os
.tmpname()
12 ----------------------------------------------------------------------
14 ----------------------------------------------------------------------
15 local loglevel
= string.upper(arg
[1] or "INFO")
16 local log = logger("TEST:".."%message")
17 log:setLevel(loglevel
)
20 local intro
= function(fmt
, ...)
21 log:info("===== "..fmt
.."\n", ...)
24 local info
= function(fmt
, ...)
25 log:info(string.format(fmt
.."\n", ...))
29 local debug
= function(fmt
, ...)
30 log:debug(string.format(fmt
.."\n", ...))
35 local function collect()
36 collectgarbage("collect")
39 local function newgraph(name
, kind
)
40 local g
, err
= graph
.open(name
, kind
)
45 local showgraph
= (os
.getenv("SHOWGRAPH") == "yes") or false
46 local printgraph
= (os
.getenv("PRINTGRAPH") == "yes") or false
47 local showinfo
= (os
.getenv("SHOWINFO") == "yes") or false
49 local function gprint(g
)
50 if printgraph
== true then
56 local function _gshow(g
)
57 if showgraph
== true then
58 local fname
= tmpname()..".dot"
59 g
:write(fname
) os
.execute("dotty "..fname
)
64 local function gshow(g
)
65 if showgraph
== true then
70 local function gcompare(g
, ref
)
73 local fref
= io
.open(ref
, "r")
74 local sres
= fref
:read("*a")
75 local fnow
= io
.open(fn
, "r")
76 local snow
= fnow
:read("*a")
80 ----------------------------------------------------------------------
82 ----------------------------------------------------------------------
83 local function test_graph_base()
84 intro("Test graph: open and read ...")
86 -- New graph: create with discipline
87 g
[1] = assert(newgraph("G1-base", "undirected"))
88 debug("G1-base created: %s", tostring(g
[1]))
89 -- New graph: create with default discipline
90 g
[2] = assert(newgraph("G2-base"))
91 debug("G2-base created: %s", tostring(g
[2]))
92 -- New graph: read from file
93 g
[3] = assert(graph
.read("test/test_dat1.dot"))
94 debug("test_dat1.dot read: %s", tostring(g
[3]))
95 -- New graph: undirected
96 g
[4] = assert(newgraph("G4-base", "undirected"))
97 debug("G4-base created: %s", tostring(g
[4]))
102 for _
,h
in pairs(g
) do
103 debug(" %q: type=%s strict=%s directed=%s nnodes=%d nedges=%d id=%d",
104 h
.name
, type(h
), tostring(h
.isstrict
), tostring(h
.isdirected
),
105 h
.nnodes
, h
.nedges
, h
.id
)
108 -- New graph: error in reading
109 g
[5], err
= graph
.read("___does__not__exist__")
110 assert(g
[5] == nil and type(err
) == "string")
112 -- Close all created graphs
113 for _
,v
in pairs(g
) do
114 debug("closing %q", v
.name
)
120 local function test_graph_properties(g
)
121 intro("Test graph: properties ...")
126 local function test_graph_meta(g
)
127 intro("Test graph: metamethods ...")
128 local g1
= assert(graph
.open("G1-meta"))
129 local g2
= assert(graph
.open("G2-meta"))
135 collectgarbage("collect")
140 local function test_graph_write()
141 intro("Test graph: write ...")
142 local h
= assert(graph
.read("test/test_dat1.dot"))
147 log:debug("write to %s", fn
);
149 -- Compare contents with reference
150 local fref
= assert(io
.open("test/ref.dot","r"))
151 local sref
= assert(fref
:read("*a"))
152 log:debug("ref: %s", sref
)
153 local f
= assert(io
.open(fn
))
154 local s
= assert(f
:read("*a"))
155 log:debug("out: %s ", s
)
156 log:info("!!! ATTENTION: Todo: compare dot files")
163 local function test_graph_defattr()
164 intro("Test graph: default attributes ...")
165 local h
= assert(graph
.read("test/test_dat1.dot"))
166 -- Getting initial default attributes
167 debug(" Initial default attributes:")
168 debug(" graphs: %s", tostring(h
:getgraphattr()))
169 for k
,v
in pairs(h
:getgraphattr()) do
170 debug(" %s=%q", k
, v
)
172 debug(" nodes: %s", tostring(h
:getnodeattr()))
173 for k
,v
in pairs(h
:getnodeattr()) do
174 debug(" %s=%q", k
, v
)
176 debug(" edges: %s", tostring(h
:getedgeattr()))
177 for k
,v
in pairs(h
:getedgeattr()) do
178 debug(" %s=%q", k
, v
)
181 -- Set attributes in parent
182 debug("Default attributes after modifications:")
183 n
= assert(h
:setattr
{
184 edge
= {shape
="box", color
="blue", whatever
="noidea", anumber
=71, ['3']="spu"},
185 node
= {color
="red", whatever
="donotknow", anumber
=17, ['3'] = "ups"}
188 local h2
= assert(h
:subgraph("h2"))
189 local hh3
= assert(graph
.open("hh3"))
190 local hh4
= assert(hh3
:subgraph("hh4"))
192 -- Check: parent shares attribute with client if client doesn't define something
194 assert(h2
:defaults().edge
.whatever
== h
:defaults().edge
.whatever
)
196 -- Set attributes in childs
197 assert(h
:setattr
{edge
={att
="att"}})
198 assert(hh4
:setattr
{edge
={att
="tta"}})
199 assert(h2
:setattr
{edge
={att
="xtt2"}})
200 debug(" h.edge.att = %q", h
:defaults().edge
.att
or "nil")
201 debug(" h2.edge.att = %q", h2
:defaults().edge
.att
or "nil")
202 debug(" h3.edge.att = %q", hh3
:defaults().edge
.att
or "nil")
203 debug(" h4.edge.att = %q", hh4
:defaults().edge
.att
or "nil")
205 -- Check: child shares defaults with parent
206 assert(h
:defaults().edge
.att
~= h2
:defaults().edge
.att
)
207 assert(hh3
:defaults().edge
.att
== hh4
:defaults().edge
.att
)
209 -- Check: defaults in different subtrees are not shared
210 assert(h
:defaults().edge
.att
~= hh3
:defaults().edge
.att
)
214 status
, rv
, err
= pcall(h2
.close
, nil)
215 assert(status
== false)
223 local function test_graph_subgraph()
224 intro("Test graph: subgraphs ...")
225 local root
= assert(graph
.open("Root", "directed"))
226 local mother
= assert(root
:subgraph("Mother"))
227 local father
= assert(root
:subgraph("Father"))
228 assert(father
~= root
:subgraph("Mother"))
229 local son
= assert(mother
:subgraph("Son"))
230 local daughter
= assert(father
:subgraph("Daughter"))
232 debug("root=%q mother=%q son=%q daughter=%q",
233 root
.name
, mother
.name
, son
.name
, daughter
.name
)
234 debug("root=%d mother=%d son=%d daughter=%d",
235 root
.id
, mother
.id
, son
.id
, daughter
.id
)
236 debug("%q: parent=%q root=%q",
237 mother
.name
, mother
.parent
.name
, mother
.root
.name
)
238 debug("%q: parent=%q root=%q",
239 son
.name
, son
.parent
.name
, son
.root
.name
)
240 debug("%q: parent=%q root=%q",
241 daughter
.name
, daughter
.parent
.name
, daughter
.root
.name
)
242 -- Check parent/root relations
243 assert(root
== mother
.parent
)
244 assert(root
== son
.root
)
245 assert(mother
== son
.parent
)
246 assert(father
== daughter
.parent
)
247 assert(root
:subgraph("Mother") == mother
)
248 assert(root
:subgraph("Father") == father
)
249 assert(root
.isroot
== true)
250 assert(mother
.isroot
== false)
251 assert(father
.isroot
== false)
252 assert(son
.graph
== son
)
253 assert(root
.graph
== root
)
254 rv
, res1
, res2
= pcall(root
.subgraph
, root
)
256 -- This must close all other graphs created here !
257 debug("Closing graph root ...")
259 collectgarbage("collect")
263 local function test_graph_iterate()
264 intro("Test graph: graph iteration ...")
265 local root
= assert(graph
.open("Root", "directed"))
266 local father
= assert(root
:subgraph("Father"))
267 local mother
= assert(root
:subgraph("Mother"))
268 local son
= assert(mother
:subgraph("Son"))
269 local daughter
= assert(father
:subgraph("Daughter"))
272 t
[i
] = root
:subgraph("sub-"..i
)
275 debug("Iteration 1 - while ")
276 local g
= root
:getnext(nil)
278 debug(" next of %s: %s", root
.name
, g
.name
)
281 debug("Iteration 1 - repeat ")
286 debug(" next of %s: %s", root
.name
, g
.name
)
292 for g
in root
:walk() do
301 g
[i
] = root
:subgraph("sub-"..i
)
306 for g
in root
:walk() do
307 assert(g
.parent
== root
)
312 collectgarbage("collect")
316 g
= assert(graph
.read("test/test_dat2.dot"))
317 for v
in g
:walkgraphs() do
318 debug(" %s %s", v
.name
, v
.status
)
320 debug(" %s %s", w
.name
, v
.status
)
327 local function test_graph_test()
328 intro("Test graph: test ...")
329 local g
= assert(graph
.open("G", "strictdirected"))
330 local n1
= assert(g
:node("N1"))
331 local n2
= assert(g
:node("N2"))
332 local e1
= assert(g
:edge(n1
, n2
, "n1=>n2"))
333 local e2
= assert(g
:edge(n2
, n1
, "n2=>n1"))
340 local function test_graph_strict()
341 intro("Test graph: strict ...")
342 local g
= assert(graph
.open("G", "strictdirected"))
343 local n1
= assert(g
:node("N1"))
344 local n2
= assert(g
:node("N2"))
346 local e1
= assert(g
:edge(n1
, n2
, "n1=>n2"))
347 debug(" e1: %s label=%q name=%q", tostring(e1
), e1
.label
, e1
.name
)
348 -- repeated creation of edge fails for strict directed graphs
349 local e2
= assert(g
:edge(n1
, n2
, "n1...n2"))
350 debug(" e2: %s label=%q name=%q", tostring(e2
), e2
.label
, e2
.name
)
351 local e3
= assert(g
:edge(n2
, n1
, "n2=>n1"))
352 debug(" e3: %s label=%q name=%q", tostring(e3
), e3
.label
, e3
.name
)
353 local e4
= assert(g
:edge(n1
, n1
, "n1=>n1"))
354 debug(" e4: %s label=%q name=%q", tostring(e4
), e4
.label
, e4
.name
)
363 -- first edge must be present
364 debug(" Finding edge n1=>n2: %q", e1
.name
)
365 assert(g
:findedge(n1
, n2
, e1
.name
))
366 -- second edge must not be present
367 debug(" Finding edge n1...n2: %q", e2
.name
)
368 assert(g
:findedge(n1
, n2
, e2
.name
))
369 debug(" Finding edge n2=>n1 w/o name")
370 assert(g
:edge(n2
, n1
))
371 debug(" Closing graph")
373 -- collectgarbage("collect")
377 local function test_delete()
378 intro("Test graph: delete object ...")
379 local g
= graph
.open("G-delete")
380 local sg
= g
:subgraph("SG-delete")
381 local ssg
= sg
:subgraph("SSG-delete")
382 debug(" Delete: sg=%s", tostring(sg
))
383 local rv
, err
= g
:delete(sg
)
384 debug(" Close: g=%s", tostring(g
))
386 -- collectgarbage("collect")
390 local function test_close()
391 intro("Test graph: close ...")
393 local g
= graph
.open("G-close")
394 local sg1
= assert(g
:subgraph("SG1-close"))
395 local sg2
= assert(g
:subgraph("SG2-close"))
396 local ssg1
= assert(sg1
:subgraph("SSG1-close"))
398 debug("Collecting garbage...")
399 collectgarbage("collect")
403 local function test_close_error()
404 intro("Test graph: close with error ...")
405 local rv
, err
= pcall(graph
.close
, 0)
406 if not rv
then debug("Error while closing: %q", err
) end
410 local function test_node_base()
411 intro("Test node: base node tests ...")
412 local g
= assert(graph
.open("G-base"))
415 local n1
= assert(g
:node("N1"))
416 local n2
= assert(g
:node("N2"))
417 assert(g
== n1
.graph
)
418 assert(g
== n2
.graph
)
419 debug("n1 is %s", tostring(n1
))
420 debug("graph of n1 is %q", n1
.graph
.name
)
422 debug("n1 is %s", tostring(g
:node("N1")))
425 local n2
= assert(g
:node("N2"))
426 debug("n2 is %s", tostring(n2
))
429 collectgarbage("collect")
433 local function test_node_properties()
434 intro("Test node: node properties ...")
435 local g
= assert(graph
.open("G"))
436 local sg
= assert(g
:subgraph("SG"))
437 local n1
= assert(g
:node("Na1"))
438 local n2
= assert(g
:node("Na2"))
439 local n3
= assert(sg
:node("Na3"))
440 debug("nx.id = %d %d %d", n1
.id
, n2
.id
, n3
.id
)
441 debug("nx.name = %q %q %q", n1
.name
, n2
.name
, n3
.name
)
442 debug("nx.graph = %q %q %q", n1
.graph
.name
, n2
.graph
.name
, n3
.graph
.name
)
444 collectgarbage("collect")
448 local function test_node_meta()
449 intro("Test node: node metamethods ...")
450 local g
= assert(graph
.open("G"))
451 local n1
= assert(g
:node("Nx1"))
452 local n2
= assert(g
:node("Nx1"))
453 local n3
= assert(g
:node("Nx3"))
455 debug("Concatenate nodes %q %q with '..'", n1
.name
, n2
.name
)
456 local e
= assert(n1
..n2
)
457 e
.label
= "n1 ==> n2"
458 debug("e.label = %q", e
.label
)
459 debug("Concatenate nodes %q %q with '+'", n3
.name
, n1
.name
)
460 local e2
= assert(n3
+n1
)
461 e2
.label
= "n3 ==> n1"
462 debug("e2.label = %q", e2
.label
)
464 debug("Delete node %q", n1
.name
)
465 local rv
= assert(n1
:delete())
466 -- Check whether userdata became invalid after node deletion
467 local status
, rv
, err
= pcall(function(n
) return n
.name
end, n1
)
468 assert(status
== false)
469 debug("check userdata invalidation: status=%s rv=%s err=%q", tostring(status
), tostring(rv
), err
or "nil")
471 debug("Collecting garbage ...")
472 collectgarbage("collect")
476 local function test_node_subnode()
477 intro("Test node: subnodes ...")
478 local g
= assert(graph
.open("G"))
479 local sg1
= assert(g
:subgraph("SG1"))
480 local sg2
= assert(g
:subgraph("SG2"))
481 local n
= assert(sg1
:node("N1"))
483 local sn
= assert(sg2
:subnode(n
, true))
485 debug("n.name=%q sb.name=%q", n
.name
, sn
.name
)
486 debug("n.seq=%d sn.seq=%d", n
.seq
, sn
.seq
)
487 debug("n.id=%d sn.id=%d", n
.id
, sn
.id
)
494 debug("Collecting garbage ...")
495 collectgarbage("collect")
499 local function test_node_degree()
500 intro("Test node: node degree ...")
501 local g
= assert(graph
.open("G-degree"))
502 local n
= assert(g
:node("N1-degree"))
503 local rv
= assert(n
:degree())
504 debug("n:degree() = %d", rv
)
507 collectgarbage("collect")
511 local function test_node_degree2()
512 intro("Test node: node degree ...")
513 local g
= graph
.read("test/test_dat1.dot")
514 local n
= g
:node("NE_WEST")
515 debug("inputs: %d outputs: %d sum: %d",
516 n
:degree("*i"), n
:degree("*o"), n
:degree("*a"))
517 assert(n
:degree("*i") == 3)
518 assert(n
:degree("*o") == 4)
519 assert(n
:degree() == 7)
524 local function test_node_iterate()
525 intro("Test node: node iteration ...")
526 local g
= assert(graph
.open("G-nodeiter"))
529 n
[i
] = assert(g
:node("N"..i
.."-nodeiter"))
538 debug(" next node of %s: %s %d", g
.name
, n
.name
, n
.id
)
544 for n
in g
:walknodes() do
551 g
= assert(graph
.read("test/test_dat1.dot"))
552 for n
in g
:walknodes() do
558 sg
=assert(g
:subgraph("SG"))
562 debug(" sg.name=%s", h
.name
)
563 for n
in h
:walknodes() do
567 for n
in g
:walknodes() do
571 collectgarbage("collect")
575 local function test_edge_base()
576 intro("Test edge: edge base ...")
577 local g
= assert(graph
.open("G","strictdirected"))
578 local sg
= assert(g
:subgraph("SG"))
579 local n1
= assert(g
:node("N1"))
580 local n2
= assert(g
:node("N2"))
581 -- retrieve 'N2' into new variable for later use
582 local n3
= assert(g
:node("N2"))
584 local e1
= assert(g
:edge(n1
, n2
, "E1:N1=>N2"))
585 debug("e1.label=%q e1.name=%q", e1
.label
or "nil", e1
.name
or "nil")
586 assert(e1
.label
== "E1:N1=>N2")
588 -- 2. edge but with n3 instead of n2
589 local e3
= assert(g
:edge(n3
, n1
, "E2:N2=>N1"))
594 local ns1
= assert(sg
:node("SN1"))
595 local ns2
= assert(sg
:node("SN2"))
596 local ns3
= assert(sg
:node("SN3"))
597 local es1
= assert(sg
:edge(ns1
, ns2
, "ES2"))
598 local es2
= assert(g
:edge(n1
, ns2
, "XXX"))
599 local es3
= assert(ns3
:edge(n1
, "duda"))
600 local es4
= assert(ns3
:edge("IMP1", "ES2"))
601 -- retrieve edge check
602 local e2
= assert(g
:edge(n1
, n2
))
609 -- check head and tail
610 assert(e1
.tail
== n1
)
611 assert(e1
.head
== n2
)
616 collectgarbage("collect")
620 local function test_edge_subedge()
621 intro("Test edge: subedges ...")
622 local g
= assert(graph
.open("G"))
623 local sg1
= assert(g
:subgraph("SG1"))
624 local sg2
= assert(g
:subgraph("SG2"))
625 local n1
= assert(sg1
:node("N1"))
626 local n2
= assert(sg1
:node("N2"))
627 local e1
= assert(n1
:edge(n2
, "E1"))
629 local e2
= assert(sg2
:subedge(e1
, true))
630 assert(n1
== sg2
:node("N1"))
631 assert(n2
== sg2
:node("N2"))
635 collectgarbage("collect")
639 local function test_edge_iterate()
640 intro("Test edge: iteration ...")
641 local g
= assert(graph
.read("test/test_dat1.dot"))
643 debug("Interation 0")
644 local n
= g
:nextnode(nil)
646 debug(" node: %q", n
.name
)
651 for n
in g
:walknodes() do
652 debug(" node: %q", n
.name
)
653 for e
in n
:walkedges() do
654 debug(" edge id=%d name=%q label=%q ptr=%s", e
.id
, e
.name
, e
.label
or "-", tostring(e
))
655 if e
.tail
then debug(" - tail: %q", e
.tail
.name
) end
656 if e
.head
then debug(" - head: %q", e
.head
.name
) end
663 for n
in g
:walknodes() do
664 debug(" node: %q", n
.name
)
665 for e
in n
:walkinputs() do
666 debug(" input name=%q label=%q", e
.name
, e
.label
)
668 for e
in n
:walkoutputs() do
669 debug(" output name=%q label=%q", e
.name
, e
.label
)
674 collectgarbage("collect")
678 local function _test_attr()
679 intro("Test misc: attributes ...")
680 local g
= graph
.open("G")
682 node
= {shape
="box", color
="blue", width
=3},
683 edge
= {color
="red", label
=""}
685 local n1
= g
:node("N1")
686 local n2
= g
:node("N2")
689 n1
.anna
={x
=10,"blablabla"}
690 debug("n1.shape=%q %d %q %s", n1
.shape
, n1
.otto
, n1
.egon
, type(n1
.egon
))
691 debug("n2.shape=%q %d %d %q %s", n2
.shape
, n2
.otto
, n2
.otto
+10, n2
.egon
or "nil", type(n2
.otto
))
693 debug("n2.shape=%q", n2
.shape
)
696 local function test_attr()
697 intro("Test misc: attribute access ...")
698 local g
= assert(graph
.open("G"))
700 node
= {shape
="box", color
="blue", width
=3},
701 edge
= {color
="red", label
=""}})
702 local n
= assert(g
:node("N1"))
703 local n2
= assert(g
:node("N2"))
704 local n3
= assert(g
:node("N3"))
705 local e
= assert(n
:edge(n2
, "E1"))
706 local e2
= assert(n
:edge(n3
, "E2"))
709 assert(g
:type() == "graph")
710 assert(n2
:type() == "node")
711 assert(e
:type() == "edge")
713 assert(n
.shape
== "box")
714 debug("1. shape: %q", n
.shape
)
716 -- rv, err = pcall(function () print(n.hello) end)
717 -- assert(rv == false)
718 -- debug("Test: failed get error: %q", err)
722 debug("2. shape: %s width: %d", n
.shape
, tonumber(n
.width
))
725 -- rv, err = pcall(function(key, val) n[key] = val end, "hello", "helloval")
726 -- assert(rv == false)
727 -- debug("Test: failed set error: %q", err)
729 local xg
= graph
.open("XG")
730 local xn
= xg
:node("XN")
732 debug("xn.anysym=%s", xn
.anysym
)
733 assert(xn
.anysym
== "anysym")
734 local yn
= xg
:node("YN")
736 debug("yn.anysym=%s", yn
.anysym
)
737 assert(yn
.anysym
== "none")
744 e
.label
= "this is an edge"
749 local function test_anyattrib()
750 intro("Test misc: anyattrib ...")
751 g
= assert(graph
.open("G"))
752 n1
= assert(g
:node("N1"))
753 n2
= assert(g
:node("N2"))
754 e1
= assert(g
:edge(n1
, n2
, "n1=>n2"))
755 e2
= assert(g
:edge(n2
, n1
, "n2=>n1"))
758 assert(n1
.someval
== t
)
760 assert(n2
.someval
== true)
761 n1
.method
= function(self
, param
)
762 debug("node name: %q %q", self
.name
, param
)
766 e2
.method
= function(self
, param
)
767 debug("edge label: %q %q", self
.label
, param
)
770 assert(n1
:method("called n1") == "called n1")
771 assert(e2
:method("called e2") == "called e2")
773 assert(e2
[t
] == "hey")
774 assert(e2
[n1
.someval
] == "hey")
778 local function test_contains()
779 intro("Test misc: containment ...")
780 local g1
= assert(graph
.open("G1"))
781 g1
:declare
{node
={shape
="box"}}
782 local sg1
= assert(g1
:subgraph("SG1"))
783 local g2
= assert(graph
.open("G2"))
784 g2
:declare
{node
={shape
="box"}}
785 local g3
= assert(graph
.read("test/test_dat1.dot"))
786 local n1
= assert(g1
:node("N1")) n1
.shape
="circle"
787 local n2
= assert(g2
:node("N2"))
788 local n3
= assert(g2
:node("N1")) n3
.shape
="ellipse"
789 local e1
= assert(g2
:edge(n2
,n3
,"n2->n3"))
790 local e2
= assert(g1
:edge(n1
,n1
,"n1->n1"))
791 local err
, res1
, res2
= pcall(function() local e3
= assert(g1
:edge(n2
,n1
,"n2->n1")) end)
793 debug("Test: edge with nodes in different graphs: %q %q", tostring(res1
), tostring(res2
));
794 assert(g1
:contains(n1
) == true)
795 assert(g1
:contains(n2
) == false)
796 assert(g1
:contains(n3
) == false)
797 assert(g2
:contains(n1
) == false)
798 assert(g2
:contains(n2
) == true)
799 assert(g2
:contains(n3
) == true)
800 assert(g1
:node("N2", nil, true) == nil)
801 assert(g1
:node("N1", nil, true) == n1
)
802 assert(g1
:idnode(n1
.id
) == n1
)
803 assert(g2
:idnode(n2
.id
) ~= n3
)
804 debug("n1.id=%d n2.id=%d n3.id=%d", n1
.id
, n2
.id
, n3
.id
)
805 debug("e1.graph=%q e2.graph=%q", e1
.graph
.name
, e2
.graph
.name
)
808 -- print(n1:type(), n3:type())
809 -- print(n1.shape, n3.shape)
810 -- print("g1:", g1:contains(n1), g1:contains(n2), g1:contains(n3), g1:node("N2", false), g1:node("N1"))
811 -- print("g2:", g2:contains(n1), g2:contains(n2), g2:contains(n3), g2:node("N2", false), g2:node("N1"))
815 local function test_find()
816 intro("Test misc: finding ...")
817 local g
= assert(graph
.read("test/test_dat1.dot"))
818 local tail
= g
:findnode("NE_EAST")
819 local head
= g
:findnode("CE_WEST")
820 debug("tail.name = %q", tail
.name
)
821 debug("head.name = %q", head
.name
)
822 local e
= g
:findedge(tail
, head
)
823 assert(e
.label
== "out1 => in2")
824 debug("e.label = %q", e
.label
)
828 local function test_layout()
829 intro("Test layout: layout ...")
830 local g
, t
= graph
.open("Gx")
831 local e1
= g
:edge
{"n1", "n2", label
="n1=>n2"}
834 assert(g
:layout("dot"))
836 assert(g
:render("plain", fn
))
838 assert(g
:layout("circo"))
840 assert(g
:render("xdot", fn
))
847 local function test_cluster()
848 intro("Test misc: cluster ...")
849 local g
,t
= graph
.open("G", "directed")
850 g
:declare
{node
={shape
= "box"}, edge
={color
="red"}}
851 local c1
= g
:cluster("SG1")
852 local c2
= g
:cluster("SG2")
853 local n1
= c1
:node
{"n1", shape
= "circle"}
854 local n2
= c2
:node
{"n2", shape
= "ellipse"}
855 local n3
= c2
:node
{"n3"}
856 local e1
= g
:edge(n2
, n1
, "n2=>n1")
857 local e2
= g
:edge(n1
, n2
, "n1=>n2")
858 local e3
= g
:edge
{n1
, n2
, n3
, label
= "n1=>n2=>n3", color
="blue"}
859 assert(g
:type(c1
) == "graph")
860 assert(c1
.parent
== g
)
861 assert(c2
.parent
== g
)
868 local function test_graphtab()
869 intro("Test misc: graph from table ...")
870 local node
, edge
, subgraph
, cluster
, digraph
=
871 graph
.node
, graph
.edge
, graph
.subgraph
, graph
.cluster
, graph
.digraph
872 xn
= node
{"xn", color
="red"}
873 local g
= digraph
{"G",
874 node
= {shape
= "box", color
= "blue"},
875 edge
= {color
= "red"},
884 node
{"n1", shape
= "box", color
= "black"},
885 node
{"n2", shape
= "circle"},
886 node
{"n3", shape
= "ellipse"},
888 label
= "n1=>n2=>n3",
891 edge
{"sn2", "n1", label
="sn1=>n1"}
893 debug("Showing graph ...")
895 debug("g.name=%q", g
.name
)
897 for n
in g
:walknodes() do
898 debug(" n.name=%q n.shape=%q n.color=%q",
899 s(n
.name
), s(n
.shape
), s(n
.color
))
900 for e
in n
:walkedges() do
901 debug(" e.label=%q e.color=%q", s(e
.label
), s(e
.color
))
904 assert(g
.nnodes
== 6)
905 assert(g
.nedges
== 6)
906 debug(" %d nodes", g
.nnodes
)
907 debug(" %d edges", g
.nedges
)
913 local function test_xx()
914 local g
= graph
.open("G")
916 local n
= g
:node("A"..i
)
917 g
:node("B"..i
):edge(n
, "E"..i
)
922 local function test_huge()
923 intro("Test with huge graph ...")
924 local g
= graph
.open("G")
928 debug("Creating nodes ...")
930 nodes
[i
] = g
:node("N"..i
)
932 debug("Creating edges ...")
935 g
:edge(nodes
[i
],nodes
[j
])
939 -- debug("Writing ...")
950 test_graph_properties
,
963 test_node_properties
,
978 -- Layout and rendering
985 local function test()
986 for _
, f
in pairs(tests
) do
988 -- print(">>> ", gcinfo())
990 -- print(">>> ", gcinfo())
996 debug("Collecting garbage ...")
997 collectgarbage("collect")
998 debug("%s", collectgarbage("count"))