Create CODE_OF_CONDUCT.md
[luagraph.git] / test / test.lua
blob49e183e11144c4043f907f85197b162fe538129d
1 local graph = require "graph"
2 local logger = require "logging.console"
3 local pretty = require "pl.pretty"
4 local tmp_prefix
5 local function tmpname()
6 if graph._SYSTEM == "Win32" then
7 return "."..os.tmpname()
8 else
9 return os.tmpname()
10 end
11 end
12 ----------------------------------------------------------------------
13 -- Logging
14 ----------------------------------------------------------------------
15 local loglevel = string.upper(arg[1] or "INFO")
16 local log = logger("TEST:".."%message")
17 log:setLevel(loglevel)
18 print()
20 local intro = function(fmt, ...)
21 log:info("===== "..fmt.."\n", ...)
22 io.stdout:flush()
23 end
24 local info = function(fmt, ...)
25 log:info(string.format(fmt.."\n", ...))
26 io.stdout:flush()
27 end
28 _debug=debug
29 local debug = function(fmt, ...)
30 log:debug(string.format(fmt.."\n", ...))
31 io.stdout:flush()
32 end
35 local function collect()
36 collectgarbage("collect")
37 end
39 local function newgraph(name, kind)
40 local g, err = graph.open(name, kind)
41 assert(g, err);
42 return g
43 end
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
51 print()
52 g:write()
53 end
54 end
56 local function _gshow(g)
57 if showgraph == true then
58 local fname = tmpname()..".dot"
59 g:write(fname) os.execute("dotty "..fname)
60 os.remove(fname)
61 end
62 end
64 local function gshow(g)
65 if showgraph == true then
66 g:show()
67 end
68 end
70 local function gcompare(g, ref)
71 local fn = tmpname()
72 g:write(fn)
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")
77 assert(sres == snow)
78 end
80 ----------------------------------------------------------------------
81 -- Tests
82 ----------------------------------------------------------------------
83 local function test_graph_base()
84 intro("Test graph: open and read ...")
85 local g = {}, err
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]))
100 -- Show properties
101 debug("Properties:")
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)
115 assert(v:close())
117 intro("passed")
120 local function test_graph_properties(g)
121 intro("Test graph: properties ...")
122 -- Show properties
123 intro("passed")
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"))
130 local h = g1
131 assert(h == g1)
132 assert(h ~= g2)
133 g1:close()
134 g2:close()
135 collectgarbage("collect")
136 intro("passed")
137 return h
140 local function test_graph_write()
141 intro("Test graph: write ...")
142 local h = assert(graph.read("test/test_dat1.dot"))
143 -- Write to stdout
144 gprint(h)
145 -- Write to file
146 local fn = tmpname()
147 log:debug("write to %s", fn);
148 h:write(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")
157 fref:close()
158 f:close()
159 h:close()
160 intro("passed")
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"}
187 assert(n == 9)
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
193 -- different
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)
211 debug("close 'h'")
212 h:close()
213 debug("close 'h2'")
214 status, rv, err = pcall(h2.close, nil)
215 assert(status == false)
216 debug("close 'hh4'")
217 hh4:close()
218 debug("close 'hh3'")
219 hh3:close()
220 intro("passed")
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"))
231 -- Print the tree
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)
255 assert(rv == false)
256 -- This must close all other graphs created here !
257 debug("Closing graph root ...")
258 root:close()
259 collectgarbage("collect")
260 intro("passed")
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"))
270 local t = {}
271 for i = 1, 10 do
272 t[i] = root:subgraph("sub-"..i)
274 -- Iteration 1
275 debug("Iteration 1 - while ")
276 local g = root:getnext(nil)
277 while g do
278 debug(" next of %s: %s", root.name, g.name)
279 g = root:getnext(g)
281 debug("Iteration 1 - repeat ")
282 local g = nil
283 repeat
284 g = root:getnext(g)
285 if g ~= nil then
286 debug(" next of %s: %s", root.name, g.name)
288 until g == nil
290 -- Iteration 2
291 debug("Iteration 2")
292 for g in root:walk() do
293 debug(" %s", g.name)
294 for h in g:walk() do
295 debug(" %s", h.name)
299 local g = {}
300 for i = 1, 20 do
301 g[i] = root:subgraph("sub-"..i)
304 -- Iteration 3
305 debug("Iteration 3")
306 for g in root:walk() do
307 assert(g.parent == root)
310 -- Closes all graphs
311 root:close()
312 collectgarbage("collect")
314 -- Iteration 4
315 debug("Iteration 4")
316 g = assert(graph.read("test/test_dat2.dot"))
317 for v in g:walkgraphs() do
318 debug(" %s %s", v.name, v.status)
319 for w in v:walk() do
320 debug(" %s %s", w.name, v.status)
323 g:close()
324 intro("passed")
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"))
334 if showinfo then
335 e1:info()
336 e2:info()
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)
355 if showinfo then
356 n1:info()
357 n2:info()
358 e1:info()
359 e2:info()
360 e3:info()
361 e4:info()
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")
372 g:close()
373 -- collectgarbage("collect")
374 intro("passed")
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))
385 g:close()
386 -- collectgarbage("collect")
387 intro("passed")
390 local function test_close()
391 intro("Test graph: close ...")
392 -- Closing graphs
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"))
397 assert(g:close())
398 debug("Collecting garbage...")
399 collectgarbage("collect")
400 intro("passed")
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
407 intro("passed")
410 local function test_node_base()
411 intro("Test node: base node tests ...")
412 local g = assert(graph.open("G-base"))
414 -- Implict creation
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)
421 -- Lookup
422 debug("n1 is %s", tostring(g:node("N1")))
424 -- A second node
425 local n2 = assert(g:node("N2"))
426 debug("n2 is %s", tostring(n2))
428 g:close()
429 collectgarbage("collect")
430 intro("passed")
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)
443 g:close()
444 collectgarbage("collect")
445 intro("passed")
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"))
454 assert(n1 == n2)
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)
463 gprint(g)
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")
470 g:close()
471 debug("Collecting garbage ...")
472 collectgarbage("collect")
473 intro("passed")
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"))
482 gprint(g)
483 local sn = assert(sg2:subnode(n, true))
484 assert(n == sn)
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)
488 gprint(g)
489 n:delete()
490 gprint(g)
491 sg1:close()
492 gprint(g)
493 g:close()
494 debug("Collecting garbage ...")
495 collectgarbage("collect")
496 intro("passed")
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)
505 n:delete()
506 g:close()
507 collectgarbage("collect")
508 intro("passed")
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)
520 g:close()
521 intro("passed")
524 local function test_node_iterate()
525 intro("Test node: node iteration ...")
526 local g = assert(graph.open("G-nodeiter"))
527 local n = {}
528 for i = 1, 20 do
529 n[i] = assert(g:node("N"..i.."-nodeiter"))
532 -- Iteration 1
533 debug("Iteration 1")
534 local n = nil
535 repeat
536 n = g:nextnode(n)
537 if n then
538 debug(" next node of %s: %s %d", g.name, n.name, n.id)
540 until n == nil
542 -- Iteration 2
543 debug("Iteration 2")
544 for n in g:walknodes() do
545 debug(" %s", n.name)
547 g:close()
549 -- Iteration 3
550 debug("Iteration 3")
551 g = assert(graph.read("test/test_dat1.dot"))
552 for n in g:walknodes() do
553 debug(" %s", n.name)
556 -- Iteration 4
557 debug("Iteration 4")
558 sg =assert(g:subgraph("SG"))
559 sn1 = sg:node("SN1")
560 sn2 = sg:node("SN2")
561 for h in g:walk() do
562 debug(" sg.name=%s", h.name)
563 for n in h:walknodes() do
564 debug(" %s", n.name)
567 for n in g:walknodes() do
568 debug(" %s", n.name)
570 g:close()
571 collectgarbage("collect")
572 intro("passed")
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"))
583 -- 1. edge
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"))
590 assert(e1 ~= e3)
591 e1.headport = "head"
592 e3.tailport = "tail"
593 -- Insert a subgraph
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))
603 if showinfo then
604 e1:info()
605 e2:info()
607 assert(e1 == e2)
609 -- check head and tail
610 assert(e1.tail == n1)
611 assert(e1.head == n2)
612 gprint(g)
613 e1:delete()
614 gprint(g)
615 g:close()
616 collectgarbage("collect")
617 intro("passed")
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"))
628 gprint(g)
629 local e2 = assert(sg2:subedge(e1, true))
630 assert(n1 == sg2:node("N1"))
631 assert(n2 == sg2:node("N2"))
632 assert(e1 == e2)
633 gprint(g)
634 g:close()
635 collectgarbage("collect")
636 intro("passed")
639 local function test_edge_iterate()
640 intro("Test edge: iteration ...")
641 local g = assert(graph.read("test/test_dat1.dot"))
642 -- Iteration 1
643 debug("Interation 0")
644 local n = g:nextnode(nil)
645 while n do
646 debug(" node: %q", n.name)
647 n = g:nextnode(n)
649 if false then
650 debug("Iteration 1")
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
660 -- Iteration 2
661 if false then
662 debug("Iteration 2")
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)
673 g:close()
674 collectgarbage("collect")
675 intro("passed")
678 local function _test_attr()
679 intro("Test misc: attributes ...")
680 local g = graph.open("G")
681 assert(g:declare{
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")
687 n2.otto=100
688 n1.egon="hallo"
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))
692 n2.shape = "circle"
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"))
699 assert(g:declare{
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"))
707 gprint(g)
708 -- Types
709 assert(g:type() == "graph")
710 assert(n2:type() == "node")
711 assert(e:type() == "edge")
712 -- Get
713 assert(n.shape == "box")
714 debug("1. shape: %q", n.shape)
715 -- Failed get
716 -- rv, err = pcall(function () print(n.hello) end)
717 -- assert(rv == false)
718 -- debug("Test: failed get error: %q", err)
719 -- Set
720 n.shape = "circle"
721 n.width = 5
722 debug("2. shape: %s width: %d", n.shape, tonumber(n.width))
723 gprint(g)
724 -- Failed set
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)
728 -- Implicit set
729 local xg = graph.open("XG")
730 local xn = xg:node("XN")
731 xn.anysym = "anysym"
732 debug("xn.anysym=%s", xn.anysym)
733 assert(xn.anysym == "anysym")
734 local yn = xg:node("YN")
735 yn.anysym="none"
736 debug("yn.anysym=%s", yn.anysym)
737 assert(yn.anysym == "none")
738 -- Just a try
739 n.shape="box"
740 n2.shape="circle"
741 n2.color="red"
742 n.width=1
743 e.color = "green"
744 e.label = "this is an edge"
745 gshow(g)
746 intro("passed");
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"))
756 local t = {1,2,3}
757 n1.someval = t
758 assert(n1.someval == t)
759 n2.someval = true
760 assert(n2.someval == true)
761 n1.method = function(self, param)
762 debug("node name: %q %q", self.name, param)
763 return param
765 e1.someval = 17.2
766 e2.method = function(self, param)
767 debug("edge label: %q %q", self.label, param)
768 return param
770 assert(n1:method("called n1") == "called n1")
771 assert(e2:method("called e2") == "called e2")
772 e2[t] = "hey"
773 assert(e2[t] == "hey")
774 assert(e2[n1.someval] == "hey")
775 intro("passed");
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)
792 assert(err == false)
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)
806 gprint(g1)
807 gprint(g2)
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"))
812 intro("passed");
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)
825 intro("passed");
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"}
832 local fn = tmpname()
833 debug("Layout:")
834 assert(g:layout("dot"))
835 debug("PLAIN:")
836 assert(g:render("plain", fn))
837 debug("Layout:")
838 assert(g:layout("circo"))
839 debug("XDOT:")
840 assert(g:render("xdot", fn))
841 debug("Cleanup ...")
842 os.remove(fn)
843 g:close()
844 intro("passed");
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)
862 gprint(g)
863 gshow(g)
864 g:close()
865 intro("passed")
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"},
876 cluster{"SG",
877 edge{
878 node{"sn1"},
879 node{"sn2"},
883 edge{
884 node{"n1", shape = "box", color = "black"},
885 node{"n2", shape = "circle"},
886 node{"n3", shape = "ellipse"},
888 label = "n1=>n2=>n3",
889 color = "green"
891 edge{"sn2", "n1", label="sn1=>n1"}
893 debug("Showing graph ...")
894 gshow(g)
895 debug("g.name=%q", g.name)
896 local s = tostring
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)
908 gprint(g)
909 g:close()
910 intro("passed")
913 local function test_xx()
914 local g = graph.open("G")
915 for i = 1,500 do
916 local n = g:node("A"..i)
917 g:node("B"..i):edge(n, "E"..i)
919 g:write("x3.dot")
922 local function test_huge()
923 intro("Test with huge graph ...")
924 local g = graph.open("G")
925 local j = 1
926 local N = 30
927 local nodes={}
928 debug("Creating nodes ...")
929 for i = 1, N do
930 nodes[i] = g:node("N"..i)
932 debug("Creating edges ...")
933 for i = 1, N do
934 for j = i, N do
935 g:edge(nodes[i],nodes[j])
938 gshow(g)
939 -- debug("Writing ...")
940 -- g:write("x3.dot")
941 intro("passed")
945 local tests = {
946 -- Graph tests
947 --[[
949 test_graph_base,
950 test_graph_properties,
951 test_graph_meta,
952 test_graph_write,
953 test_graph_subgraph,
954 test_graph_defattr,
955 test_graph_iterate,
956 -- test_graph_test,
957 test_graph_strict,
958 test_delete,
959 test_close,
960 test_close_error,
961 -- Node tests
962 test_node_base,
963 test_node_properties,
964 test_node_meta,
965 test_node_degree,
966 test_node_degree2,
967 test_node_iterate,
968 -- Edge tests
969 test_edge_base,
970 test_edge_iterate,
971 -- Misc tests
972 test_attr,
973 test_contains,
974 test_find,
975 test_anyattrib,
976 test_cluster,
977 test_graphtab,
978 -- Layout and rendering
979 test_layout,
980 test_huge
981 --[[
985 local function test()
986 for _, f in pairs(tests) do
988 -- print(">>> ", gcinfo())
990 -- print(">>> ", gcinfo())
993 test()
995 -- Collect garbage
996 debug("Collecting garbage ...")
997 collectgarbage("collect")
998 debug("%s", collectgarbage("count"))
1000 info("FINISHED")