From 668e73133739c37f9abd99afee92601d8aa94f30 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 3 Dec 2018 14:47:27 +0100 Subject: [PATCH 01/29] Start implementation of callgraph module --- modules/callgraph/inspect2graphml.xqm | 119 ++++++++++++++++++ .../tests/inspect2graphml-test-runner.xq | 14 +++ .../callgraph/tests/inspect2graphml-test.xql | 46 +++++++ .../tests/xqm/inspect2graphml-testmodule.xqm | 21 ++++ .../tests/xqm/inspect2graphml-testmodule2.xqm | 25 ++++ 5 files changed, 225 insertions(+) create mode 100644 modules/callgraph/inspect2graphml.xqm create mode 100644 modules/callgraph/tests/inspect2graphml-test-runner.xq create mode 100644 modules/callgraph/tests/inspect2graphml-test.xql create mode 100644 modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm create mode 100644 modules/callgraph/tests/xqm/inspect2graphml-testmodule2.xqm diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm new file mode 100644 index 0000000..c08bce6 --- /dev/null +++ b/modules/callgraph/inspect2graphml.xqm @@ -0,0 +1,119 @@ +xquery version "3.1"; + +module namespace inspect2graphml="https://sade.textgrid.de/ns/inspect2graphml"; + +import module namespace console="http://exist-db.org/xquery/console"; +import module namespace inspect="http://exist-db.org/xquery/inspection"; + + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; +declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; + + + +declare function inspect2graphml:main($xqm-or-collection as xs:string) as element(graphml:graphml)* { + if(not(ends-with($xqm-or-collection, ".xqm"))) then + (inspect2graphml:transform-collection($xqm-or-collection), + console:log("mit xqm")) + else if(ends-with($xqm-or-collection, ".xqm")) then + (inspect2graphml:transform-xqm($xqm-or-collection), + console:log("mit coll")) + else + () +}; + + +declare function inspect2graphml:transform-collection($xqm-or-collection as xs:string) +as element(graphml:graphml) { + element graphml:graphml { + attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, + element graphml:graph { + attribute id {"base-graph"}, + attribute edgedefault {"directed"}, + for $resource in collection($xqm-or-collection) return + let $xqm := base-uri($resource) + let $inspect-result := inspect:inspect-module(xs:anyURI($xqm)) + let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqm, false()) + + return + element graphml:node { + attribute id {util:hash($xqm, "md5")}, + local:sort-edges-and-nodes($transformed-subgraph) + } + } + } +}; + + +declare function inspect2graphml:transform-xqm($xqm-or-collection as xs:string) +as element(graphml:graphml) { + let $inspect-result := inspect:inspect-module(xs:anyURI($xqm-or-collection)) + return + element graphml:graphml { + attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, + let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqm-or-collection, true()) + return local:sort-edges-and-nodes($transformed-subgraph) + } +}; + + +declare function inspect2graphml:transform($nodes as node()*, $xqm-or-collection +as xs:string, $single-module as xs:boolean) as node()* { + for $node in $nodes return + typeswitch ($node) + + case element(module) return + local:make-graph($node, $xqm-or-collection, $single-module) + + case element(function) return + (local:make-node($node), + inspect2graphml:transform($node/node(), $xqm-or-collection, $single-module)) + + case element(calls) return + let $source-function := $node/ancestor::function[1] + let $prefix := substring-before($source-function/@name, ":") + for $called in $node/function + return + (element graphml:edge { + attribute source {$source-function/@name}, + attribute target {$called/@name} + }, + if($single-module + and not(substring-before($called/@name, ":") = $prefix)) then + local:make-node($called) + else + ()) + + default return + () +}; + +declare function local:make-graph($node as node(), $xqm-or-collection as xs:string, +$single-module as xs:boolean) +as element(graphml:graph) { + element graphml:graph { + attribute id {$node/@prefix}, + attribute edgedefault {"directed"}, + inspect2graphml:transform($node/node(), $xqm-or-collection, $single-module) + } +}; + + +declare function local:make-node($node as node()) as element(graphml:node) { + element graphml:node { + attribute id {$node/@name} + } +}; + +declare function local:sort-edges-and-nodes($graph as element(graphml:graph)) +as element(graphml:graph) { + element graphml:graph { + $graph/@*, + for $node in $graph/graphml:node + order by $node/@id + return $node, + for $edge in $graph/graphml:edge + order by $edge/@source, $edge/@target + return $edge + } +}; \ No newline at end of file diff --git a/modules/callgraph/tests/inspect2graphml-test-runner.xq b/modules/callgraph/tests/inspect2graphml-test-runner.xq new file mode 100644 index 0000000..ae67138 --- /dev/null +++ b/modules/callgraph/tests/inspect2graphml-test-runner.xq @@ -0,0 +1,14 @@ +xquery version "3.1"; + + +(: This main module starts the tests stored in inspect2graphml-test.xql. :) + +import module namespace inspect2graphml-test = "https://sade.textgrid.de/ns/inspect2graphml-test" at "inspect2graphml-test.xql"; +import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; +import module namespace console="http://exist-db.org/xquery/console"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; + +test:suite( + util:list-functions("https://sade.textgrid.de/ns/inspect2graphml-test") +) diff --git a/modules/callgraph/tests/inspect2graphml-test.xql b/modules/callgraph/tests/inspect2graphml-test.xql new file mode 100644 index 0000000..9568a49 --- /dev/null +++ b/modules/callgraph/tests/inspect2graphml-test.xql @@ -0,0 +1,46 @@ +xquery version "3.1"; + +(: This library module contains XQSuite tests for the inspect2graphml module + : stored in inspect2graphml.xqm :) + +module namespace inspect2graphml-test = "https://sade.textgrid.de/ns/inspect2graphml-test"; + +import module namespace inspect2graphml="https://sade.textgrid.de/ns/inspect2graphml" at "../inspect2graphml.xqm"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; +declare namespace test="http://exist-db.org/xquery/xqsuite"; + + +declare + %test:name("Testing the test") + %test:args("some input") + %test:assertEmpty + function inspect2graphml-test:a-test-the-test($node as text()) { + () +}; + + +declare + %test:name("Testing a simple module with module node as input") + %test:args("Some Documentation Michelle Weidling 1.0 the name of the current filexs:string The path where the HTML is storedDetermines the directory where an HTML file should be saved. 1.0 Michelle Weidling ") + %test:assertEquals("") + function inspect2graphml-test:ba-simple-graph($node as element(*)) { + inspect2graphml:transform($node, "test", true()) +}; + +declare + %test:name("Testing a simple module with URI as input") + %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") + %test:assertEquals("") + function inspect2graphml-test:bb-simple-graph($uri-or-coll as xs:string) { + inspect2graphml:main($uri-or-coll) +}; + + +declare + %test:name("Testing two simple module with collection path as input") + %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") + %test:assertEquals("") + function inspect2graphml-test:bc-simple-graph($uri-or-coll as xs:string) { + inspect2graphml:main($uri-or-coll) +}; \ No newline at end of file diff --git a/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm b/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm new file mode 100644 index 0000000..219c4fe --- /dev/null +++ b/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm @@ -0,0 +1,21 @@ +xquery version "3.1"; + +module namespace inspect2graphml-testmodule="https://sade.textgrid.de/ns/inspect2graphml-test-module"; + +declare function inspect2graphml-testmodule:main() as xs:boolean { + let $url := "some-url" + let $url-return := inspect2graphml-testmodule:get-value($url) + let $set-value := inspect2graphml-testmodule:set-value($url) + return + true() +}; + +declare function inspect2graphml-testmodule:get-value($url as xs:string) as xs:string { + "return value" +}; + +declare function inspect2graphml-testmodule:set-value($url as xs:string) as empty-sequence() { + let $value := inspect2graphml-testmodule:get-value($url) + return + () +}; \ No newline at end of file diff --git a/modules/callgraph/tests/xqm/inspect2graphml-testmodule2.xqm b/modules/callgraph/tests/xqm/inspect2graphml-testmodule2.xqm new file mode 100644 index 0000000..193fd8d --- /dev/null +++ b/modules/callgraph/tests/xqm/inspect2graphml-testmodule2.xqm @@ -0,0 +1,25 @@ +xquery version "3.1"; + +module namespace inspect2graphml-testmodule2="https://sade.textgrid.de/ns/inspect2graphml-test-module2"; + +import module namespace inspect2graphml-testmodule="https://sade.textgrid.de/ns/inspect2graphml-test-module" at "inspect2graphml-testmodule.xqm"; + + +declare function inspect2graphml-testmodule2:main() as xs:boolean { + let $url := "some-url" + let $url-return := inspect2graphml-testmodule2:get-value($url) + let $set-value1 := inspect2graphml-testmodule2:set-value($url) + let $set-value2 := inspect2graphml-testmodule:set-value($url) + return + true() +}; + +declare function inspect2graphml-testmodule2:get-value($url as xs:string) as xs:string { + "return value" +}; + +declare function inspect2graphml-testmodule2:set-value($url as xs:string) as empty-sequence() { + let $value := inspect2graphml-testmodule:get-value($url) + return + () +}; \ No newline at end of file -- GitLab From d10a27ffd4ba561f3cd7a883927e09756047b008 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 3 Dec 2018 16:19:19 +0100 Subject: [PATCH 02/29] Remove surplus code --- modules/callgraph/inspect2graphml.xqm | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index c08bce6..08c3489 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -5,19 +5,14 @@ module namespace inspect2graphml="https://sade.textgrid.de/ns/inspect2graphml"; import module namespace console="http://exist-db.org/xquery/console"; import module namespace inspect="http://exist-db.org/xquery/inspection"; - declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; - - declare function inspect2graphml:main($xqm-or-collection as xs:string) as element(graphml:graphml)* { if(not(ends-with($xqm-or-collection, ".xqm"))) then - (inspect2graphml:transform-collection($xqm-or-collection), - console:log("mit xqm")) + inspect2graphml:transform-collection($xqm-or-collection) else if(ends-with($xqm-or-collection, ".xqm")) then - (inspect2graphml:transform-xqm($xqm-or-collection), - console:log("mit coll")) + inspect2graphml:transform-xqm($xqm-or-collection) else () }; -- GitLab From 1b34cc1602ea9ae74102276473e9376f4778902d Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 3 Dec 2018 16:19:38 +0100 Subject: [PATCH 03/29] Implement basic transformation to DOT --- modules/callgraph/graphml2dot.xsl | 113 ++++++++++++++++++ .../tests/graphml2dot-test-runner.xq | 14 +++ modules/callgraph/tests/graphml2dot-test.xql | 20 ++++ 3 files changed, 147 insertions(+) create mode 100644 modules/callgraph/graphml2dot.xsl create mode 100644 modules/callgraph/tests/graphml2dot-test-runner.xq create mode 100644 modules/callgraph/tests/graphml2dot-test.xql diff --git a/modules/callgraph/graphml2dot.xsl b/modules/callgraph/graphml2dot.xsl new file mode 100644 index 0000000..f0506a8 --- /dev/null +++ b/modules/callgraph/graphml2dot.xsl @@ -0,0 +1,113 @@ + + + + + + + + + digraph g { + + } + + + + + + node [shape=box, style=filled, color=" + + + + "]; + + + + + + + + + + + + " + + " + [shape=box]; + + + + + + " + + " + + -> + + " + + " + ; + + + + + + + + + #90b0d4 + + + #e6f2ff + + + #eee6ff + + + #ffffe6 + + + #f9ecec + + + #bfe0ba + + + #bfd2e3 + + + #dbaddb + + + #decbb2 + + + #e0b7b6 + + + #d9f09e + + + #f5a1a4 + + + #faf0a5 + + + #8acca0 + + + #cfb88c + + + #d18ecb + + + + + + #555544 + + \ No newline at end of file diff --git a/modules/callgraph/tests/graphml2dot-test-runner.xq b/modules/callgraph/tests/graphml2dot-test-runner.xq new file mode 100644 index 0000000..27f5b62 --- /dev/null +++ b/modules/callgraph/tests/graphml2dot-test-runner.xq @@ -0,0 +1,14 @@ +xquery version "3.1"; + + +(: This main module starts the tests stored in graphml2dot-test.xql. :) + +import module namespace graphml2dot-test = "https://sade.textgrid.de/ns/graphml2dot-test" at "graphml2dot-test.xql"; +import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; +import module namespace console="http://exist-db.org/xquery/console"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; + +test:suite( + util:list-functions("https://sade.textgrid.de/ns/graphml2dot-test") +) diff --git a/modules/callgraph/tests/graphml2dot-test.xql b/modules/callgraph/tests/graphml2dot-test.xql new file mode 100644 index 0000000..304de43 --- /dev/null +++ b/modules/callgraph/tests/graphml2dot-test.xql @@ -0,0 +1,20 @@ +xquery version "3.1"; + +(: This library module contains XQSuite tests for the inspect2graphml module + : stored in inspect2graphml.xqm :) + +module namespace graphml2dot-test = "https://sade.textgrid.de/ns/graphml2dot-test"; + +import module namespace graphml2dot="https://sade.textgrid.de/ns/graphml2dot" at "../graphml2dot.xqm"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; +declare namespace test="http://exist-db.org/xquery/xqsuite"; + + +declare + %test:name("Testing the test") + %test:args("some input") + %test:assertEmpty + function graphml2dot-test:a-test-the-test($node as text()) { + () +}; \ No newline at end of file -- GitLab From 9441d4238fac6452ff54c6862d3045cca8c05dd9 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 3 Dec 2018 14:47:27 +0100 Subject: [PATCH 04/29] Start implementation of callgraph module --- modules/callgraph/inspect2graphml.xqm | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index 08c3489..b79cb6b 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -18,7 +18,7 @@ declare function inspect2graphml:main($xqm-or-collection as xs:string) as elemen }; -declare function inspect2graphml:transform-collection($xqm-or-collection as xs:string) +declare function inspect2graphml:transform-collection($xqm-or-collection as xs:string) as element(graphml:graphml) { element graphml:graphml { attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, @@ -29,7 +29,7 @@ as element(graphml:graphml) { let $xqm := base-uri($resource) let $inspect-result := inspect:inspect-module(xs:anyURI($xqm)) let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqm, false()) - + return element graphml:node { attribute id {util:hash($xqm, "md5")}, @@ -40,7 +40,7 @@ as element(graphml:graphml) { }; -declare function inspect2graphml:transform-xqm($xqm-or-collection as xs:string) +declare function inspect2graphml:transform-xqm($xqm-or-collection as xs:string) as element(graphml:graphml) { let $inspect-result := inspect:inspect-module(xs:anyURI($xqm-or-collection)) return @@ -52,18 +52,18 @@ as element(graphml:graphml) { }; -declare function inspect2graphml:transform($nodes as node()*, $xqm-or-collection +declare function inspect2graphml:transform($nodes as node()*, $xqm-or-collection as xs:string, $single-module as xs:boolean) as node()* { for $node in $nodes return typeswitch ($node) - + case element(module) return local:make-graph($node, $xqm-or-collection, $single-module) - + case element(function) return (local:make-node($node), inspect2graphml:transform($node/node(), $xqm-or-collection, $single-module)) - + case element(calls) return let $source-function := $node/ancestor::function[1] let $prefix := substring-before($source-function/@name, ":") @@ -78,13 +78,13 @@ as xs:string, $single-module as xs:boolean) as node()* { local:make-node($called) else ()) - + default return () }; declare function local:make-graph($node as node(), $xqm-or-collection as xs:string, -$single-module as xs:boolean) +$single-module as xs:boolean) as element(graphml:graph) { element graphml:graph { attribute id {$node/@prefix}, @@ -111,4 +111,4 @@ as element(graphml:graph) { order by $edge/@source, $edge/@target return $edge } -}; \ No newline at end of file +}; -- GitLab From aab35b3b82fbb3fe932d32e2a63bd7cfab357194 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 11:00:41 +0100 Subject: [PATCH 05/29] Extend tests --- modules/callgraph/tests/inspect2graphml-test.xql | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/callgraph/tests/inspect2graphml-test.xql b/modules/callgraph/tests/inspect2graphml-test.xql index 9568a49..fc81d6b 100644 --- a/modules/callgraph/tests/inspect2graphml-test.xql +++ b/modules/callgraph/tests/inspect2graphml-test.xql @@ -38,9 +38,17 @@ declare declare - %test:name("Testing two simple module with collection path as input") + %test:name("Testing two simple modules with collection path as input") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") %test:assertEquals("") function inspect2graphml-test:bc-simple-graph($uri-or-coll as xs:string) { inspect2graphml:main($uri-or-coll) +}; + +declare + %test:name("Testing transformation from GraphML to DOT with one module") + %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") + %test:assertEquals("") + function inspect2graphml-test:ca-simple-graphml-to-dot($xqm as xs:string) { + inspect2graphml:main($uri-or-coll) }; \ No newline at end of file -- GitLab From ceae11461593c6b324577fac5f450d4cd67fd3d8 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 11:04:11 +0100 Subject: [PATCH 06/29] Add first draft for callgraph main module --- modules/callgraph/callgraph.xqm | 40 ++++++++++++++++ .../callgraph/tests/callgraph-test-runner.xq | 14 ++++++ modules/callgraph/tests/callgraph-test.xql | 46 +++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 modules/callgraph/callgraph.xqm create mode 100644 modules/callgraph/tests/callgraph-test-runner.xq create mode 100644 modules/callgraph/tests/callgraph-test.xql diff --git a/modules/callgraph/callgraph.xqm b/modules/callgraph/callgraph.xqm new file mode 100644 index 0000000..58d55c6 --- /dev/null +++ b/modules/callgraph/callgraph.xqm @@ -0,0 +1,40 @@ +xquery version "3.1"; + +module namespace callgraph="https://sade.textgrid.de/ns/callgraph"; + +import module namespace config="https://sade.textgrid.de/ns/config" at "../config.xqm"; +import module namespace console="http://exist-db.org/xquery/console"; +import module namespace inspect="http://exist-db.org/xquery/inspection"; +import module namespace inspect2graphml="https://sade.textgrid.de/ns/inspect2graphml" at "inspect2graphml.xqm"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; +declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; + +declare variable $callgraph:xslt := $config:app-root || "/modules/callgraph/graphml2dot.xsl"; + +(: possible options: + : * URI of a single module, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm" + : * all modules of a given collection, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/" + : * the whole SADE app ($option = "full") :) +declare function callgraph:main($option as xs:string*) { + if(ends-with($option, ".xqm") + or $option = "full" + or xmldb:collection-available($option)) then + let $dot := callgraph:get-dot($option) + let $svg := callgraph:get-svg($dot) + return $svg + else + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH01"), + "Invalid option '" || $option || "'. Please enter a base URI, a collection path or 'full' as argument.") +}; + +declare function callgraph:get-dot($option as xs:string*) { + let $xslt := doc($callgraph:xslt) + let $graphml := inspect2graphml:main($option) + return + transform:transform($graphml, $xslt, ()) +}; + +declare function callgraph:get-svg($dot as xs:string) { + $dot +}; \ No newline at end of file diff --git a/modules/callgraph/tests/callgraph-test-runner.xq b/modules/callgraph/tests/callgraph-test-runner.xq new file mode 100644 index 0000000..3274d4b --- /dev/null +++ b/modules/callgraph/tests/callgraph-test-runner.xq @@ -0,0 +1,14 @@ +xquery version "3.1"; + + +(: This main module starts the tests stored in callgraph-test.xql. :) + +import module namespace callgraph-test = "https://sade.textgrid.de/ns/callgraph-test" at "callgraph-test.xql"; +import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; +import module namespace console="http://exist-db.org/xquery/console"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; + +test:suite( + util:list-functions("https://sade.textgrid.de/ns/callgraph-test") +) diff --git a/modules/callgraph/tests/callgraph-test.xql b/modules/callgraph/tests/callgraph-test.xql new file mode 100644 index 0000000..ae90f10 --- /dev/null +++ b/modules/callgraph/tests/callgraph-test.xql @@ -0,0 +1,46 @@ +xquery version "3.1"; + +(: This library module contains XQSuite tests for the callgraph module + : stored in callgraph.xqm :) + +module namespace callgraph-test = "https://sade.textgrid.de/ns/callgraph-test"; + +import module namespace callgraph="https://sade.textgrid.de/ns/callgraph" at "../callgraph.xqm"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; +declare namespace test="http://exist-db.org/xquery/xqsuite"; + + +declare + %test:name("Testing error message by error code") + %test:args("an invalid option") + %test:assertError("CALLGRAPH01") + function callgraph-test:aa-test-error($option as xs:string) { + callgraph:main($option) +}; + +declare + %test:name("Testing error message by error description") + %test:args("an invalid option") + %test:assertError("Invalid option 'an invalid option'. Please enter a base URI, a collection path or 'full' as argument.") + function callgraph-test:ab-test-error($option as xs:string) { + callgraph:main($option) +}; + + +declare + %test:name("Testing DOT ouput for a single module") + %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") + %test:assertEquals("digraph g {node [shape=box, style=filled, color=""#90b0d4""];""inspect2graphml-testmodule:get-value"" [shape=box];""inspect2graphml-testmodule:main"" [shape=box];""inspect2graphml-testmodule:set-value"" [shape=box];""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:get-value"";""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule:set-value"" -> ""inspect2graphml-testmodule:get-value"";}") + function callgraph-test:ba-dot($option as xs:string) { + callgraph:main($option) +}; + + +declare + %test:name("Testing DOT ouput for two modules") + %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") + %test:assertEquals("digraph g {node [shape=box, style=filled, color=""#90b0d4""];""inspect2graphml-testmodule:get-value"" [shape=box];""inspect2graphml-testmodule:main"" [shape=box];""inspect2graphml-testmodule:set-value"" [shape=box];""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:get-value"";""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule:set-value"" -> ""inspect2graphml-testmodule:get-value"";node [shape=box, style=filled, color=""#e6f2ff""];""inspect2graphml-testmodule2:get-value"" [shape=box];""inspect2graphml-testmodule2:main"" [shape=box];""inspect2graphml-testmodule2:set-value"" [shape=box];""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:get-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:set-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule2:set-value"" -> ""inspect2graphml-testmodule:get-value"";}") + function callgraph-test:bb-dot($option as xs:string) { + callgraph:main($option) +}; \ No newline at end of file -- GitLab From 9f5d1a6db25dc0e6264482404ec892b66429cebc Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 15:34:22 +0100 Subject: [PATCH 07/29] Further work on first draft --- config.xml | 8 +- modules/callgraph/callgraph.xqm | 55 ++++- modules/callgraph/graphml/graphml.xml | 61 ++++++ modules/callgraph/inspect2graphml.xqm | 110 +++++++--- modules/callgraph/svg/output.svg | 227 +++++++++++++++++++++ modules/callgraph/tests/callgraph-test.xql | 19 +- 6 files changed, 442 insertions(+), 38 deletions(-) create mode 100644 modules/callgraph/graphml/graphml.xml create mode 100644 modules/callgraph/svg/output.svg diff --git a/config.xml b/config.xml index 3281e20..f41fcdc 100644 --- a/config.xml +++ b/config.xml @@ -1,3 +1,4 @@ + + + local:soapElement + + local:soapElement + + + local:soapHeader + + local:soapHeader + + + local:tgAuth-call + + local:tgAuth-call + + + tgclient:confserv + + tgclient:confserv + + + tgclient:createAggregation + + tgclient:createAggregation + + + tgclient:createData + + tgclient:createData + + + tgclient:createAggregation->tgclient:createData + + + + + tgclient:get + + tgclient:get + + + tgclient:getData + + tgclient:getData + + + tgclient:get->tgclient:getData + + + + + tgclient:getMeta + + tgclient:getMeta + + + tgclient:get->tgclient:getMeta + + + + + tgclient:getAggregatedUris + + tgclient:getAggregatedUris + + + tgclient:sparql + + tgclient:sparql + + + tgclient:getAggregatedUris->tgclient:sparql + + + + + tgclient:remove-prefix + + tgclient:remove-prefix + + + tgclient:tgauth-tgAssignedProjects + + tgclient:tgauth-tgAssignedProjects + + + tgclient:tgauth-tgAssignedProjects->local:soapElement + + + + + tgclient:tgauth-tgAssignedProjects->local:soapHeader + + + + + tgclient:tgauth-tgAssignedProjects->local:tgAuth-call + + + + + tgclient:tgsearch-navigation-agg + + tgclient:tgsearch-navigation-agg + + + tgclient:tgsearch-query-filter + + tgclient:tgsearch-query-filter + + + local:copy-filter-elements + + local:copy-filter-elements + + + local:copy-filter-elements->local:copy-filter-elements + + + + + local:image-store + + local:image-store + + + local:image-store->local:image-store + + + + + local:prepare + + local:prepare + + + config:get + + config:get + + + local:prepare->config:get + + + + + local:progress + + local:progress + + + tgconnect:prerender + + tgconnect:prerender + + + tgconnect:publish + + tgconnect:publish + + + tgconnect:publish->tgclient:getAggregatedUris + + + + + tgconnect:publish->tgclient:getData + + + + + tgconnect:publish->tgclient:getMeta + + + + + tgconnect:publish->tgclient:remove-prefix + + + + + tgconnect:publish->local:image-store + + + + + tgconnect:publish->local:prepare + + + + + tgconnect:publish->tgconnect:publish + + + + + tgconnect:publish->config:get + + + + + tgconnect:store + + tgconnect:store + + + tgmenu:list + + tgmenu:list + + + tgmenu:template + + tgmenu:template + + + tgmenu:template->tgmenu:list + + + + + \ No newline at end of file diff --git a/modules/callgraph/tests/callgraph-test.xql b/modules/callgraph/tests/callgraph-test.xql index ae90f10..9e5abbf 100644 --- a/modules/callgraph/tests/callgraph-test.xql +++ b/modules/callgraph/tests/callgraph-test.xql @@ -33,7 +33,7 @@ declare %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") %test:assertEquals("digraph g {node [shape=box, style=filled, color=""#90b0d4""];""inspect2graphml-testmodule:get-value"" [shape=box];""inspect2graphml-testmodule:main"" [shape=box];""inspect2graphml-testmodule:set-value"" [shape=box];""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:get-value"";""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule:set-value"" -> ""inspect2graphml-testmodule:get-value"";}") function callgraph-test:ba-dot($option as xs:string) { - callgraph:main($option) + callgraph:get-dot($option) }; @@ -42,5 +42,22 @@ declare %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") %test:assertEquals("digraph g {node [shape=box, style=filled, color=""#90b0d4""];""inspect2graphml-testmodule:get-value"" [shape=box];""inspect2graphml-testmodule:main"" [shape=box];""inspect2graphml-testmodule:set-value"" [shape=box];""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:get-value"";""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule:set-value"" -> ""inspect2graphml-testmodule:get-value"";node [shape=box, style=filled, color=""#e6f2ff""];""inspect2graphml-testmodule2:get-value"" [shape=box];""inspect2graphml-testmodule2:main"" [shape=box];""inspect2graphml-testmodule2:set-value"" [shape=box];""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:get-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:set-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule2:set-value"" -> ""inspect2graphml-testmodule:get-value"";}") function callgraph-test:bb-dot($option as xs:string) { + callgraph:get-dot($option) +}; + +declare + %test:name("Testing SVG error behavior") + %test:args("") + %test:assertError("CALLGRAPH05") + function callgraph-test:c-svg($dot as xs:string) { + callgraph:get-svg($dot) +}; + + +declare + %test:name("Testing SVG clearance for a simple module") + %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") + %test:assertEquals("/db/apps/sade/modules/callgraph/svg/output.svg") + function callgraph-test:d-svg($option as xs:string) { callgraph:main($option) }; \ No newline at end of file -- GitLab From 5b3fa78492d7db43b3a97503d42066c532aae55d Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 16:01:39 +0100 Subject: [PATCH 08/29] Simplify inspect2graphml.xqm --- modules/callgraph/graphml/graphml.xml | 80 +++---- modules/callgraph/inspect2graphml.xqm | 105 ++++----- modules/callgraph/svg/output.svg | 323 +++++++++----------------- 3 files changed, 183 insertions(+), 325 deletions(-) diff --git a/modules/callgraph/graphml/graphml.xml b/modules/callgraph/graphml/graphml.xml index ae110aa..3dccaaa 100644 --- a/modules/callgraph/graphml/graphml.xml +++ b/modules/callgraph/graphml/graphml.xml @@ -1,60 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index 8c78b90..170b0c7 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -12,79 +12,41 @@ declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; declare function inspect2graphml:main($option as xs:string) as item()+ { - let $graphml := - if(not(ends-with($option, ".xqm")) - and not($option = "full")) then - inspect2graphml:transform-collection($option) - else if(ends-with($option, ".xqm")) then - inspect2graphml:transform-xqm($option) - (: $option = "full :) - else - inspect2graphml:transform-whole-app() + let $graphml := inspect2graphml:get-graphml($option) return ($graphml, xmldb:store($config:app-root || "/modules/callgraph/graphml/", "graphml.xml", $graphml)) }; -declare function inspect2graphml:transform-collection($option as xs:string) -as element(graphml:graphml) { - let $xqms := - for $child in xmldb:get-child-resources($option) return - if(contains($child, ".xqm")) then - $option || "/" || $child - else - () +declare function inspect2graphml:get-graphml($option as xs:string) { + let $xqms := local:get-xqms($option) return - element graphml:graphml { - attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, - element graphml:graph { - attribute id {"base-graph"}, - attribute edgedefault {"directed"}, - for $xqm in $xqms return - let $inspect-result := inspect:inspect-module(xs:anyURI($xqm)) - let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqm, false()) - - return - element graphml:node { - attribute id {util:hash($xqm, "md5")}, - local:sort-edges-and-nodes($transformed-subgraph) - } + if(count($xqms) = 1) then + element graphml:graphml { + attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, + let $inspect-result := inspect:inspect-module(xs:anyURI($xqms)) + let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqms, true()) + return local:sort-edges-and-nodes($transformed-subgraph) } - } -}; - - -declare function inspect2graphml:transform-xqm($option as xs:string) -as element(graphml:graphml) { - let $inspect-result := inspect:inspect-module(xs:anyURI($option)) - return - element graphml:graphml { - attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, - let $transformed-subgraph := inspect2graphml:transform($inspect-result, $option, true()) - return local:sort-edges-and-nodes($transformed-subgraph) - } -}; - -declare function inspect2graphml:transform-whole-app() { - element graphml:graphml { - attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, - element graphml:graph { - attribute id {"base-graph"}, - attribute edgedefault {"directed"}, - let $xqms := inspect2graphml:find-xqms($config:app-root) - for $xqm in $xqms - let $inspect-result := inspect:inspect-module(xs:anyURI($xqm)) - let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqm, false()) - - return - element graphml:node { - attribute id {util:hash($xqm, "md5")}, - local:sort-edges-and-nodes($transformed-subgraph) - } - } - } + else + element graphml:graphml { + attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, + element graphml:graph { + attribute id {"base-graph"}, + attribute edgedefault {"directed"}, + for $xqm in $xqms return + let $inspect-result := inspect:inspect-module(xs:anyURI($xqm)) + let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqm, false()) + + return + element graphml:node { + attribute id {util:hash($xqm, "md5")}, + local:sort-edges-and-nodes($transformed-subgraph) + } + } + } }; @@ -137,6 +99,21 @@ as xs:string, $single-module as xs:boolean) as node()* { () }; +declare function local:get-xqms($option as xs:string) { + switch ($option) + case "full" return inspect2graphml:find-xqms($config:app-root) + + default return + if(ends-with($option, ".xqm")) then + $option + else + for $child in xmldb:get-child-resources($option) return + if(contains($child, ".xqm")) then + $option || "/" || $child + else + () +}; + declare function local:make-node($node as node()) as element(graphml:node) { element graphml:node { diff --git a/modules/callgraph/svg/output.svg b/modules/callgraph/svg/output.svg index 35aef94..4bfae94 100644 --- a/modules/callgraph/svg/output.svg +++ b/modules/callgraph/svg/output.svg @@ -1,227 +1,132 @@ - - + + g - + - local:soapElement - - local:soapElement - + inspect2graphml:find-xqms + + inspect2graphml:find-xqms + + + inspect2graphml:find-xqms->inspect2graphml:find-xqms + + + + + functx:substring-after-last + + functx:substring-after-last + + + inspect2graphml:find-xqms->functx:substring-after-last + + + - local:soapHeader - - local:soapHeader - - - local:tgAuth-call - - local:tgAuth-call - + inspect2graphml:get-graphml + + inspect2graphml:get-graphml + - tgclient:confserv - - tgclient:confserv - - - tgclient:createAggregation - - tgclient:createAggregation - - - tgclient:createData - - tgclient:createData - - - tgclient:createAggregation->tgclient:createData - - - - - tgclient:get - - tgclient:get - - - tgclient:getData - - tgclient:getData - - - tgclient:get->tgclient:getData - - - - - tgclient:getMeta - - tgclient:getMeta - + inspect2graphml:transform + + inspect2graphml:transform + - tgclient:get->tgclient:getMeta - - - - - tgclient:getAggregatedUris - - tgclient:getAggregatedUris - - - tgclient:sparql - - tgclient:sparql - + inspect2graphml:get-graphml->inspect2graphml:transform + + + + + local:get-xqms + + local:get-xqms + - tgclient:getAggregatedUris->tgclient:sparql - - - - - tgclient:remove-prefix - - tgclient:remove-prefix - - - tgclient:tgauth-tgAssignedProjects - - tgclient:tgauth-tgAssignedProjects - + inspect2graphml:get-graphml->local:get-xqms + + + + + local:sort-edges-and-nodes + + local:sort-edges-and-nodes + - tgclient:tgauth-tgAssignedProjects->local:soapElement - - - + inspect2graphml:get-graphml->local:sort-edges-and-nodes + + + + + inspect2graphml:main + + inspect2graphml:main + - tgclient:tgauth-tgAssignedProjects->local:soapHeader - - - + inspect2graphml:main->inspect2graphml:get-graphml + + + - tgclient:tgauth-tgAssignedProjects->local:tgAuth-call - - - - - tgclient:tgsearch-navigation-agg - - tgclient:tgsearch-navigation-agg - - - tgclient:tgsearch-query-filter - - tgclient:tgsearch-query-filter - - - local:copy-filter-elements - - local:copy-filter-elements - + inspect2graphml:transform->inspect2graphml:transform + + + + + local:make-node + + local:make-node + - local:copy-filter-elements->local:copy-filter-elements - - - - - local:image-store - - local:image-store - + inspect2graphml:transform->local:make-node + + + - local:image-store->local:image-store - - - - - local:prepare - - local:prepare - - - config:get - - config:get - + local:get-xqms->inspect2graphml:find-xqms + + + + + callgraph:clear-svg + + callgraph:clear-svg + + + callgraph:get-dot + + callgraph:get-dot + - local:prepare->config:get - - - - - local:progress - - local:progress - - - tgconnect:prerender - - tgconnect:prerender - - - tgconnect:publish - - tgconnect:publish - - - tgconnect:publish->tgclient:getAggregatedUris - - - - - tgconnect:publish->tgclient:getData - - - - - tgconnect:publish->tgclient:getMeta - - - - - tgconnect:publish->tgclient:remove-prefix - - - + callgraph:get-dot->inspect2graphml:main + + + + + callgraph:get-svg + + callgraph:get-svg + + + callgraph:main + + callgraph:main + + + callgraph:main->callgraph:clear-svg + + + - tgconnect:publish->local:image-store - - - + callgraph:main->callgraph:get-dot + + + - tgconnect:publish->local:prepare - - - - - tgconnect:publish->tgconnect:publish - - - - - tgconnect:publish->config:get - - - - - tgconnect:store - - tgconnect:store - - - tgmenu:list - - tgmenu:list - - - tgmenu:template - - tgmenu:template - - - tgmenu:template->tgmenu:list - - + callgraph:main->callgraph:get-svg + + \ No newline at end of file -- GitLab From d1a86f133d079b0f56d44db5268c0eb536705d85 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 16:17:01 +0100 Subject: [PATCH 09/29] Update tests --- .../tests/graphml2dot-test-runner.xq | 14 ------------- modules/callgraph/tests/graphml2dot-test.xql | 20 ------------------- .../callgraph/tests/inspect2graphml-test.xql | 12 +++++------ 3 files changed, 6 insertions(+), 40 deletions(-) delete mode 100644 modules/callgraph/tests/graphml2dot-test-runner.xq delete mode 100644 modules/callgraph/tests/graphml2dot-test.xql diff --git a/modules/callgraph/tests/graphml2dot-test-runner.xq b/modules/callgraph/tests/graphml2dot-test-runner.xq deleted file mode 100644 index 27f5b62..0000000 --- a/modules/callgraph/tests/graphml2dot-test-runner.xq +++ /dev/null @@ -1,14 +0,0 @@ -xquery version "3.1"; - - -(: This main module starts the tests stored in graphml2dot-test.xql. :) - -import module namespace graphml2dot-test = "https://sade.textgrid.de/ns/graphml2dot-test" at "graphml2dot-test.xql"; -import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; -import module namespace console="http://exist-db.org/xquery/console"; - -declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; - -test:suite( - util:list-functions("https://sade.textgrid.de/ns/graphml2dot-test") -) diff --git a/modules/callgraph/tests/graphml2dot-test.xql b/modules/callgraph/tests/graphml2dot-test.xql deleted file mode 100644 index 304de43..0000000 --- a/modules/callgraph/tests/graphml2dot-test.xql +++ /dev/null @@ -1,20 +0,0 @@ -xquery version "3.1"; - -(: This library module contains XQSuite tests for the inspect2graphml module - : stored in inspect2graphml.xqm :) - -module namespace graphml2dot-test = "https://sade.textgrid.de/ns/graphml2dot-test"; - -import module namespace graphml2dot="https://sade.textgrid.de/ns/graphml2dot" at "../graphml2dot.xqm"; - -declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; -declare namespace test="http://exist-db.org/xquery/xqsuite"; - - -declare - %test:name("Testing the test") - %test:args("some input") - %test:assertEmpty - function graphml2dot-test:a-test-the-test($node as text()) { - () -}; \ No newline at end of file diff --git a/modules/callgraph/tests/inspect2graphml-test.xql b/modules/callgraph/tests/inspect2graphml-test.xql index fc81d6b..faf369f 100644 --- a/modules/callgraph/tests/inspect2graphml-test.xql +++ b/modules/callgraph/tests/inspect2graphml-test.xql @@ -1,6 +1,6 @@ xquery version "3.1"; -(: This library module contains XQSuite tests for the inspect2graphml module +(: This library module contains XQSuite tests for the inspect2graphml module : stored in inspect2graphml.xqm :) module namespace inspect2graphml-test = "https://sade.textgrid.de/ns/inspect2graphml-test"; @@ -31,7 +31,7 @@ declare declare %test:name("Testing a simple module with URI as input") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") - %test:assertEquals("") + %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/graphml.xml") function inspect2graphml-test:bb-simple-graph($uri-or-coll as xs:string) { inspect2graphml:main($uri-or-coll) }; @@ -40,7 +40,7 @@ declare declare %test:name("Testing two simple modules with collection path as input") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") - %test:assertEquals("") + %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/graphml.xml") function inspect2graphml-test:bc-simple-graph($uri-or-coll as xs:string) { inspect2graphml:main($uri-or-coll) }; @@ -48,7 +48,7 @@ declare declare %test:name("Testing transformation from GraphML to DOT with one module") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") - %test:assertEquals("") + %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/graphml.xml") function inspect2graphml-test:ca-simple-graphml-to-dot($xqm as xs:string) { - inspect2graphml:main($uri-or-coll) -}; \ No newline at end of file + inspect2graphml:main($xqm) +}; -- GitLab From 9e4faa12bdcfa3fb0ab452d2e93c2f2d71489c52 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 08:19:54 +0100 Subject: [PATCH 10/29] Update tests --- modules/callgraph/tests/inspect2graphml-test.xql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/callgraph/tests/inspect2graphml-test.xql b/modules/callgraph/tests/inspect2graphml-test.xql index faf369f..3215be9 100644 --- a/modules/callgraph/tests/inspect2graphml-test.xql +++ b/modules/callgraph/tests/inspect2graphml-test.xql @@ -25,7 +25,7 @@ declare %test:args("Some Documentation Michelle Weidling 1.0 the name of the current filexs:string The path where the HTML is storedDetermines the directory where an HTML file should be saved. 1.0 Michelle Weidling ") %test:assertEquals("") function inspect2graphml-test:ba-simple-graph($node as element(*)) { - inspect2graphml:transform($node, "test", true()) + inspect2graphml:transform($node, true()) }; declare -- GitLab From 2f508b33874657c6d8f13a1dae97d00000aca614 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 08:20:42 +0100 Subject: [PATCH 11/29] Add docs --- modules/callgraph/callgraph.xqm | 84 ++++++++++++++++++++--- modules/callgraph/inspect2graphml.xqm | 99 ++++++++++++++++++++++++--- 2 files changed, 165 insertions(+), 18 deletions(-) diff --git a/modules/callgraph/callgraph.xqm b/modules/callgraph/callgraph.xqm index a6441d6..5ef241f 100644 --- a/modules/callgraph/callgraph.xqm +++ b/modules/callgraph/callgraph.xqm @@ -1,5 +1,28 @@ xquery version "3.1"; +(:~ + : This module creates an SVG image of call graph of + : + : * a given module + : * the modules of a given collection + : * the modules of the whole SADE app + : + : A module is defined as a file that ends with '.xqm'. + : While the SVG image is stored to /db/apps/sade/modules/callgraph/svg, + : the intermediate GraphML representation of the call graph is saved to + : /db/apps/sade/modules/callgraph/graphml and could be re-used in other + : applications. + : + : This module was roughly inspired by the graphviz app for eXist-db which can be + : found at https://github.com/KitWallace/graphviz. + : + : @author Michelle Weidling + : @since v3.1.0 + : @see https://github.com/KitWallace/graphviz + : + : :) + + module namespace callgraph="https://sade.textgrid.de/ns/callgraph"; import module namespace config="https://sade.textgrid.de/ns/config" at "../config.xqm"; @@ -12,11 +35,21 @@ declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; declare variable $callgraph:xslt := $config:app-root || "/modules/callgraph/graphml2dot.xsl"; -(: possible options: - : * URI of a single module, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm" - : * all modules of a given collection, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/" - : * the whole SADE app ($option = "full") :) -declare function callgraph:main($option as xs:string*) { + +(:~ + : Creates an SVG file of one or more modules depending on the given $option. + : Possible options are: + : * an URI of a single module, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm" + : * a collection URI, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/" + : * "full" which will consider all *.xqm in the SADE app + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $option Selects the modules which should be displayed in the output SVG file + : @return Message that indicates a successfull transformation + : @error The given option is invalid. + : :) +declare function callgraph:main($option as xs:string) as xs:string { if(ends-with($option, ".xqm") or $option = "full" or xmldb:collection-available($option)) then @@ -24,14 +57,26 @@ declare function callgraph:main($option as xs:string*) { let $svg-output := callgraph:get-svg($dot) let $svg := callgraph:clear-svg($svg-output) - return $svg + return "Call graph creation successfull." else error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH01"), "Invalid option '" || $option || "'. Please enter a base URI, a collection path or 'full' as argument.") }; -declare function callgraph:get-dot($option as xs:string*) { +(:~ + : Gets a DOT representation of the given module, the modules of a collection or + : all modules of the SADE app. + : + : @author Michelle Weidling + : @since v3.1.0 + : @see https://en.wikipedia.org/wiki/DOT_(graph_description_language) + : @param $option Selects the modules which should be displayed in the output SVG file + : @return Message that indicates a successfull transformation + : @error GraphML couldn't be transformed to DOT. + : @error The DOT file is empty. + : :) +declare function callgraph:get-dot($option as xs:string) as xs:string { let $xslt := doc($callgraph:xslt) let $graphml := inspect2graphml:main($option) let $dot := @@ -53,7 +98,18 @@ declare function callgraph:get-dot($option as xs:string*) { }; -declare function callgraph:get-svg($dot as xs:string) { +(:~ + : Creates an SVG file based of a given DOT file. + : + : @author Michelle Weidling + : @since v3.1.0 + : @see https://en.wikipedia.org/wiki/DOT_(graph_description_language) + : @param $dot A graph described in DOT + : @return The lines of the SVG file + : @error DOT couldn't be transformed to SVG. + : @error The SVG file is empty. + : :) +declare function callgraph:get-svg($dot as xs:string) as element(line)+ { let $conf := $config:app-root || "/config.xml" let $cmd := doc($conf)//*[@key = "dot-cmd"]/string() let $target-dir := doc($conf)//*[@key = "target-dir"]/string() @@ -78,7 +134,17 @@ declare function callgraph:get-svg($dot as xs:string) { }; -declare function callgraph:clear-svg($svg as element(execution)) { +(:~ + : Since the output of callgraph:get-svg consists of multiple line elements that + : contain the XML representation of the SVG, this function extracts the SVG data + : and creates a valid SVG file. + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $svg Multiple line elements that hold the SVG data + : @return The path to the stored SVG file. + : :) +declare function callgraph:clear-svg($svg as element(execution)) as xs:string { let $lines := $svg//line let $content := for $line in subsequence($lines, 7) return diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index 170b0c7..f63128f 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -1,4 +1,19 @@ xquery version "3.1"; +(:~ + : This module creates a GraphML representation of one or more given modules or + : even the whole SADE app. For this we take the information retrieved by + : inspect:inspect-module and convert the relevant nodes to GraphML. + : + : It was roughly inspired by the graphviz app for eXist-db which can be + : found at https://github.com/KitWallace/graphviz. + : + : @author Michelle Weidling + : @since v3.1.0 + : @see https://github.com/KitWallace/graphviz + : @see http://graphml.graphdrawing.org/specification.html + : + : :) + module namespace inspect2graphml="https://sade.textgrid.de/ns/inspect2graphml"; @@ -11,6 +26,15 @@ declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; +(:~ + : The interface for other modules. + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph.xqm for valid options) + : @return The graph representation as element(graphml:graphml) + : @return The path to the stored GraphML file + : :) declare function inspect2graphml:main($option as xs:string) as item()+ { let $graphml := inspect2graphml:get-graphml($option) return @@ -19,14 +43,23 @@ declare function inspect2graphml:main($option as xs:string) as item()+ { }; -declare function inspect2graphml:get-graphml($option as xs:string) { +(:~ + : Creates a GraphML representation of one or more given modules or + : even the whole SADE app. + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph.xqm for valid options) + : :) +declare function inspect2graphml:get-graphml($option as xs:string) as +element(graphml:graphml) { let $xqms := local:get-xqms($option) return if(count($xqms) = 1) then element graphml:graphml { attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, let $inspect-result := inspect:inspect-module(xs:anyURI($xqms)) - let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqms, true()) + let $transformed-subgraph := inspect2graphml:transform($inspect-result, true()) return local:sort-edges-and-nodes($transformed-subgraph) } @@ -38,7 +71,7 @@ declare function inspect2graphml:get-graphml($option as xs:string) { attribute edgedefault {"directed"}, for $xqm in $xqms return let $inspect-result := inspect:inspect-module(xs:anyURI($xqm)) - let $transformed-subgraph := inspect2graphml:transform($inspect-result, $xqm, false()) + let $transformed-subgraph := inspect2graphml:transform($inspect-result, false()) return element graphml:node { @@ -50,7 +83,16 @@ declare function inspect2graphml:get-graphml($option as xs:string) { }; -declare function inspect2graphml:find-xqms($collection as xs:string) { +(:~ + : Recursively retrieves all *.xqm files of a given collection and all its + : descendant collections. + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $collection The collection URI + : @return A sequence of all module URIs that have $collection as ancestor + : :) +declare function inspect2graphml:find-xqms($collection as xs:string) as xs:string+ { for $child in collection($collection) let $uri := base-uri($child) let $last-uri-part := functx:substring-after-last($uri, "/") @@ -64,8 +106,18 @@ declare function inspect2graphml:find-xqms($collection as xs:string) { inspect2graphml:find-xqms($uri) }; -declare function inspect2graphml:transform($nodes as node()*, $option -as xs:string, $single-module as xs:boolean) as node()* { + +(:~ + : Transforms the relevant nodes that have been generated by inspect:inspect-module + : to GraphML elements. + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $nodes The nodes that are a result of inspect:inspect-module + : @param $single-module A flag denoting if the user wants only a single module to be examined. In this case all functions have to be converted to graphml:node which otherwise would lead to redundancies. + : @return The transformed node(s) + : :) +declare function inspect2graphml:transform($nodes as node()*, $single-module as xs:boolean) as node()* { for $node in $nodes return typeswitch ($node) @@ -73,12 +125,12 @@ as xs:string, $single-module as xs:boolean) as node()* { element graphml:graph { attribute id {$node/@prefix}, attribute edgedefault {"directed"}, - inspect2graphml:transform($node/node(), $option, $single-module) + inspect2graphml:transform($node/node(), $single-module) } case element(function) return (local:make-node($node), - inspect2graphml:transform($node/node(), $option, $single-module)) + inspect2graphml:transform($node/node(), $single-module)) case element(calls) return let $source-function := $node/ancestor::function[1] @@ -99,7 +151,16 @@ as xs:string, $single-module as xs:boolean) as node()* { () }; -declare function local:get-xqms($option as xs:string) { + +(:~ + : Gets all relevant *.xqm files. + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph.xqm for valid options) + : @return A sequence of module URIs + : :) +declare function local:get-xqms($option as xs:string) as xs:string* { switch ($option) case "full" return inspect2graphml:find-xqms($config:app-root) @@ -115,12 +176,32 @@ declare function local:get-xqms($option as xs:string) { }; +(:~ + : Creates a graphml:node element. + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $node The current result node of inspect:inspect-module + : @return A respective graphml:node element + : :) declare function local:make-node($node as node()) as element(graphml:node) { element graphml:node { attribute id {$node/@name} } }; + +(:~ + : As the output of inspect2graphml:transform mixes up graphml:node and graphml:edge + : because of document order, this function sorts them: We want all graphml:node + : to be listed alphabetically first, followed by all graphml:edge elements. + : + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $graph A (sub-)graph with nodes and edges + : @return A graph with sorted nodes and edges + : :) declare function local:sort-edges-and-nodes($graph as element(graphml:graph)) as element(graphml:graph) { element graphml:graph { -- GitLab From d9924191bdfebdc58e4375797cdae45e1e87711e Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 3 Dec 2018 16:19:38 +0100 Subject: [PATCH 12/29] Implement basic transformation to DOT --- .../tests/graphml2dot-test-runner.xq | 14 +++++++++++++ modules/callgraph/tests/graphml2dot-test.xql | 20 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 modules/callgraph/tests/graphml2dot-test-runner.xq create mode 100644 modules/callgraph/tests/graphml2dot-test.xql diff --git a/modules/callgraph/tests/graphml2dot-test-runner.xq b/modules/callgraph/tests/graphml2dot-test-runner.xq new file mode 100644 index 0000000..27f5b62 --- /dev/null +++ b/modules/callgraph/tests/graphml2dot-test-runner.xq @@ -0,0 +1,14 @@ +xquery version "3.1"; + + +(: This main module starts the tests stored in graphml2dot-test.xql. :) + +import module namespace graphml2dot-test = "https://sade.textgrid.de/ns/graphml2dot-test" at "graphml2dot-test.xql"; +import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; +import module namespace console="http://exist-db.org/xquery/console"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; + +test:suite( + util:list-functions("https://sade.textgrid.de/ns/graphml2dot-test") +) diff --git a/modules/callgraph/tests/graphml2dot-test.xql b/modules/callgraph/tests/graphml2dot-test.xql new file mode 100644 index 0000000..304de43 --- /dev/null +++ b/modules/callgraph/tests/graphml2dot-test.xql @@ -0,0 +1,20 @@ +xquery version "3.1"; + +(: This library module contains XQSuite tests for the inspect2graphml module + : stored in inspect2graphml.xqm :) + +module namespace graphml2dot-test = "https://sade.textgrid.de/ns/graphml2dot-test"; + +import module namespace graphml2dot="https://sade.textgrid.de/ns/graphml2dot" at "../graphml2dot.xqm"; + +declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; +declare namespace test="http://exist-db.org/xquery/xqsuite"; + + +declare + %test:name("Testing the test") + %test:args("some input") + %test:assertEmpty + function graphml2dot-test:a-test-the-test($node as text()) { + () +}; \ No newline at end of file -- GitLab From 8976f16eeca57caa174538a690ee81517d5bd43e Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 11:04:11 +0100 Subject: [PATCH 13/29] Add first draft for callgraph main module --- modules/callgraph/callgraph.xqm | 52 +++++++++++----------- modules/callgraph/tests/callgraph-test.xql | 4 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/modules/callgraph/callgraph.xqm b/modules/callgraph/callgraph.xqm index 5ef241f..649c71b 100644 --- a/modules/callgraph/callgraph.xqm +++ b/modules/callgraph/callgraph.xqm @@ -1,25 +1,25 @@ xquery version "3.1"; -(:~ +(:~ : This module creates an SVG image of call graph of - : + : : * a given module : * the modules of a given collection : * the modules of the whole SADE app - : + : : A module is defined as a file that ends with '.xqm'. : While the SVG image is stored to /db/apps/sade/modules/callgraph/svg, - : the intermediate GraphML representation of the call graph is saved to - : /db/apps/sade/modules/callgraph/graphml and could be re-used in other + : the intermediate GraphML representation of the call graph is saved to + : /db/apps/sade/modules/callgraph/graphml and could be re-used in other : applications. - : + : : This module was roughly inspired by the graphviz app for eXist-db which can be : found at https://github.com/KitWallace/graphviz. - : + : : @author Michelle Weidling : @since v3.1.0 : @see https://github.com/KitWallace/graphviz - : + : : :) @@ -42,7 +42,7 @@ declare variable $callgraph:xslt := $config:app-root || "/modules/callgraph/grap : * an URI of a single module, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm" : * a collection URI, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/" : * "full" which will consider all *.xqm in the SADE app - : + : : @author Michelle Weidling : @since v3.1.0 : @param $option Selects the modules which should be displayed in the output SVG file @@ -56,10 +56,10 @@ declare function callgraph:main($option as xs:string) as xs:string { let $dot := callgraph:get-dot($option) let $svg-output := callgraph:get-svg($dot) let $svg := callgraph:clear-svg($svg-output) - + return "Call graph creation successfull." else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH01"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH01"), "Invalid option '" || $option || "'. Please enter a base URI, a collection path or 'full' as argument.") }; @@ -67,7 +67,7 @@ declare function callgraph:main($option as xs:string) as xs:string { (:~ : Gets a DOT representation of the given module, the modules of a collection or : all modules of the SADE app. - : + : : @author Michelle Weidling : @since v3.1.0 : @see https://en.wikipedia.org/wiki/DOT_(graph_description_language) @@ -81,26 +81,26 @@ declare function callgraph:get-dot($option as xs:string) as xs:string { let $graphml := inspect2graphml:main($option) let $dot := try { - (: $graphml[1] is graphml:graphml, + (: $graphml[1] is graphml:graphml, $graphml[2] is path to stored XML :) transform:transform($graphml[1], $xslt, ()) } catch * { - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH02"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH02"), "Could not transform GraphML to DOT.") } - + return if(normalize-space($dot) != "") then $dot else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH03"), - "DOT file is empty.") + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH03"), + "DOT file is empty.") }; (:~ : Creates an SVG file based of a given DOT file. - : + : : @author Michelle Weidling : @since v3.1.0 : @see https://en.wikipedia.org/wiki/DOT_(graph_description_language) @@ -118,19 +118,19 @@ declare function callgraph:get-svg($dot as xs:string) as element(line)+ { {$target-dir} {$dot} - let $output := + let $output := try { process:execute(($cmd, "-Tsvg"), $options) } catch * { - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH04"), - "Could not transform the given DOT file to SVG.") + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH04"), + "Could not transform the given DOT file to SVG.") } return if($output//stdout/line) then $output else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH05"), - "SVG output empty.") + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH05"), + "SVG output empty.") }; @@ -138,7 +138,7 @@ declare function callgraph:get-svg($dot as xs:string) as element(line)+ { : Since the output of callgraph:get-svg consists of multiple line elements that : contain the XML representation of the SVG, this function extracts the SVG data : and creates a valid SVG file. - : + : : @author Michelle Weidling : @since v3.1.0 : @param $svg Multiple line elements that hold the SVG data @@ -146,10 +146,10 @@ declare function callgraph:get-svg($dot as xs:string) as element(line)+ { : :) declare function callgraph:clear-svg($svg as element(execution)) as xs:string { let $lines := $svg//line - let $content := + let $content := for $line in subsequence($lines, 7) return $line/string() let $cleared-svg := string-join($content, "") return xmldb:store($config:app-root || "/modules/callgraph/svg/", "output.svg", $cleared-svg) -}; \ No newline at end of file +}; diff --git a/modules/callgraph/tests/callgraph-test.xql b/modules/callgraph/tests/callgraph-test.xql index 9e5abbf..588a5c3 100644 --- a/modules/callgraph/tests/callgraph-test.xql +++ b/modules/callgraph/tests/callgraph-test.xql @@ -1,6 +1,6 @@ xquery version "3.1"; -(: This library module contains XQSuite tests for the callgraph module +(: This library module contains XQSuite tests for the callgraph module : stored in callgraph.xqm :) module namespace callgraph-test = "https://sade.textgrid.de/ns/callgraph-test"; @@ -60,4 +60,4 @@ declare %test:assertEquals("/db/apps/sade/modules/callgraph/svg/output.svg") function callgraph-test:d-svg($option as xs:string) { callgraph:main($option) -}; \ No newline at end of file +}; -- GitLab From 39585f9df7c7c259d6c5c815122530c4f986a06a Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 15:34:22 +0100 Subject: [PATCH 14/29] Further work on first draft --- modules/callgraph/graphml/graphml.xml | 2 +- modules/callgraph/svg/output.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/callgraph/graphml/graphml.xml b/modules/callgraph/graphml/graphml.xml index 3dccaaa..3294242 100644 --- a/modules/callgraph/graphml/graphml.xml +++ b/modules/callgraph/graphml/graphml.xml @@ -34,4 +34,4 @@ - \ No newline at end of file + diff --git a/modules/callgraph/svg/output.svg b/modules/callgraph/svg/output.svg index 4bfae94..358439d 100644 --- a/modules/callgraph/svg/output.svg +++ b/modules/callgraph/svg/output.svg @@ -129,4 +129,4 @@ - \ No newline at end of file + -- GitLab From f2d70a80699f80ebce5d2b9fea25a6171760b5f7 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 16:01:39 +0100 Subject: [PATCH 15/29] Simplify inspect2graphml.xqm --- modules/callgraph/inspect2graphml.xqm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index f63128f..b794d6d 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -151,6 +151,21 @@ declare function inspect2graphml:transform($nodes as node()*, $single-module as () }; +declare function local:get-xqms($option as xs:string) { + switch ($option) + case "full" return inspect2graphml:find-xqms($config:app-root) + + default return + if(ends-with($option, ".xqm")) then + $option + else + for $child in xmldb:get-child-resources($option) return + if(contains($child, ".xqm")) then + $option || "/" || $child + else + () +}; + (:~ : Gets all relevant *.xqm files. -- GitLab From 2a4b3005da07b0390733dd412e15cc6fd69f8f5d Mon Sep 17 00:00:00 2001 From: mrodzis Date: Tue, 4 Dec 2018 16:17:01 +0100 Subject: [PATCH 16/29] Update tests --- .../tests/graphml2dot-test-runner.xq | 14 ------------- modules/callgraph/tests/graphml2dot-test.xql | 20 ------------------- 2 files changed, 34 deletions(-) delete mode 100644 modules/callgraph/tests/graphml2dot-test-runner.xq delete mode 100644 modules/callgraph/tests/graphml2dot-test.xql diff --git a/modules/callgraph/tests/graphml2dot-test-runner.xq b/modules/callgraph/tests/graphml2dot-test-runner.xq deleted file mode 100644 index 27f5b62..0000000 --- a/modules/callgraph/tests/graphml2dot-test-runner.xq +++ /dev/null @@ -1,14 +0,0 @@ -xquery version "3.1"; - - -(: This main module starts the tests stored in graphml2dot-test.xql. :) - -import module namespace graphml2dot-test = "https://sade.textgrid.de/ns/graphml2dot-test" at "graphml2dot-test.xql"; -import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; -import module namespace console="http://exist-db.org/xquery/console"; - -declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; - -test:suite( - util:list-functions("https://sade.textgrid.de/ns/graphml2dot-test") -) diff --git a/modules/callgraph/tests/graphml2dot-test.xql b/modules/callgraph/tests/graphml2dot-test.xql deleted file mode 100644 index 304de43..0000000 --- a/modules/callgraph/tests/graphml2dot-test.xql +++ /dev/null @@ -1,20 +0,0 @@ -xquery version "3.1"; - -(: This library module contains XQSuite tests for the inspect2graphml module - : stored in inspect2graphml.xqm :) - -module namespace graphml2dot-test = "https://sade.textgrid.de/ns/graphml2dot-test"; - -import module namespace graphml2dot="https://sade.textgrid.de/ns/graphml2dot" at "../graphml2dot.xqm"; - -declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; -declare namespace test="http://exist-db.org/xquery/xqsuite"; - - -declare - %test:name("Testing the test") - %test:args("some input") - %test:assertEmpty - function graphml2dot-test:a-test-the-test($node as text()) { - () -}; \ No newline at end of file -- GitLab From 6e52774735cdfa9f68fcb6c4ff1cdbb2c30ab214 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 10:23:00 +0100 Subject: [PATCH 17/29] Finalize docs --- config.xml | 1 + docs/callgraphs.md | 57 ++++++++++++++ modules/callgraph/callgraph.xqm | 104 +++++++++++++++----------- modules/callgraph/inspect2graphml.xqm | 80 ++++++++++---------- 4 files changed, 161 insertions(+), 81 deletions(-) create mode 100644 docs/callgraphs.md diff --git a/config.xml b/config.xml index f41fcdc..cb14b6a 100644 --- a/config.xml +++ b/config.xml @@ -110,6 +110,7 @@ + dot diff --git a/docs/callgraphs.md b/docs/callgraphs.md new file mode 100644 index 0000000..ffeb223 --- /dev/null +++ b/docs/callgraphs.md @@ -0,0 +1,57 @@ +# Call graphs (call multigraphs) + +This modules examines XQuery modules and creates an SVG representation of their respective call graphs. +These call graphs are useful as an overview of how the SADE app and project specific extensions work and can be used as illustration of the app's architecture, for improving a module's structure while developing, ... +To meet the different needs of users, three ways of using this module are possible: + +You can create the call graph of +* a single module +* all modules that belong to a collection +* the whole SADE app + +In case several modules are inspected all functions that belong to one module have the same color in the graph to + + + +## Requirements +Please make sure you have **[GraphViz](http://graphviz.org/)** installed whereever the database runs (on your computer, on a VM, ...). + + +## Configuration +For the module to work properly you have to consider on which kind of operating system (Windows, Unix, MacOS, ...) the database runs. +Simply change the following line in `config.xml` to the command line invocation of `dot` that is used by your OS: + +``` +dot +``` + +The option defaults to Unix. + + +## How to create call graphs +Before using the call graph module please make sure you have the module imported with + +``` +import module namespace callgraph="https://sade.textgrid.de/ns/callgraph" at "${path/to/module}/callgraph.xqm"; +``` + +To generate a call graph all you have to do is calling the function + +``` +callgraph:main("/some/input") +``` +where the input can be the following: + +* an URI of a single module, e.g. `/db/apps/sade/modules/some-module.xqm` +* the URI of a collection, e.g. `/db/apps/sade/modules/my-project-collection` +* `full` (generates a call graph for the whole SADE app) + +The call graph SVG is stored to `/db/apps/sade/modules/callgraph/svg` while the GraphML representation can be found at `/db/apps/sade/modules/callgraph/graphml`. + + +## How it works (in detail) +Depending on which input option you select (cf. "How to create call graphs" above) one or more modules are examined by eXist-db's `inspect:inspect-module` function which returns some information about the module(s) and the functions within. + +This information is then converted into a **[GraphML](http://graphml.graphdrawing.org/)** representation of the module as a directed graph (`graphml:graph`) in which all calling and called functions are represented as a `graphml:node` element. In case several modules are inspected duplicates are avoided. The calling/called connection between two functions is denoted by a `graphml:edge` element where the calling function becomes the `graphml:edge/@source` and the called one the `graphml:edge/@target`. + +This GraphML document is then saved to `/db/apps/sade/callgraph/graphml` and serves as input for generating a **[DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language))** representation of the graph which in turn is used as input for `dot` to create an SVG file that is saved to `/db/apps/sade/callgraph/svg`. \ No newline at end of file diff --git a/modules/callgraph/callgraph.xqm b/modules/callgraph/callgraph.xqm index 649c71b..4d6ca89 100644 --- a/modules/callgraph/callgraph.xqm +++ b/modules/callgraph/callgraph.xqm @@ -1,25 +1,25 @@ xquery version "3.1"; -(:~ +(:~ : This module creates an SVG image of call graph of - : + : : * a given module : * the modules of a given collection : * the modules of the whole SADE app - : + : : A module is defined as a file that ends with '.xqm'. : While the SVG image is stored to /db/apps/sade/modules/callgraph/svg, - : the intermediate GraphML representation of the call graph is saved to - : /db/apps/sade/modules/callgraph/graphml and could be re-used in other + : the intermediate GraphML representation of the call graph is saved to + : /db/apps/sade/modules/callgraph/graphml and could be re-used in other : applications. - : + : : This module was roughly inspired by the graphviz app for eXist-db which can be : found at https://github.com/KitWallace/graphviz. - : + : : @author Michelle Weidling : @since v3.1.0 : @see https://github.com/KitWallace/graphviz - : + : : :) @@ -27,6 +27,7 @@ module namespace callgraph="https://sade.textgrid.de/ns/callgraph"; import module namespace config="https://sade.textgrid.de/ns/config" at "../config.xqm"; import module namespace console="http://exist-db.org/xquery/console"; +import module namespace functx="http://www.functx.com"; import module namespace inspect="http://exist-db.org/xquery/inspection"; import module namespace inspect2graphml="https://sade.textgrid.de/ns/inspect2graphml" at "inspect2graphml.xqm"; @@ -42,24 +43,25 @@ declare variable $callgraph:xslt := $config:app-root || "/modules/callgraph/grap : * an URI of a single module, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm" : * a collection URI, e.g. "/db/apps/sade/modules/callgraph/tests/xqm/" : * "full" which will consider all *.xqm in the SADE app - : + : : @author Michelle Weidling : @since v3.1.0 : @param $option Selects the modules which should be displayed in the output SVG file : @return Message that indicates a successfull transformation - : @error The given option is invalid. + : @error The given option is invalid : :) declare function callgraph:main($option as xs:string) as xs:string { if(ends-with($option, ".xqm") or $option = "full" or xmldb:collection-available($option)) then - let $dot := callgraph:get-dot($option) + let $filename := local:get-filename($option) + let $dot := callgraph:get-dot($option, $filename) let $svg-output := callgraph:get-svg($dot) - let $svg := callgraph:clear-svg($svg-output) - + let $svg := callgraph:clear-svg($svg-output, $filename) + return "Call graph creation successfull." else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH01"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH01"), "Invalid option '" || $option || "'. Please enter a base URI, a collection path or 'full' as argument.") }; @@ -67,47 +69,48 @@ declare function callgraph:main($option as xs:string) as xs:string { (:~ : Gets a DOT representation of the given module, the modules of a collection or : all modules of the SADE app. - : + : : @author Michelle Weidling : @since v3.1.0 : @see https://en.wikipedia.org/wiki/DOT_(graph_description_language) - : @param $option Selects the modules which should be displayed in the output SVG file - : @return Message that indicates a successfull transformation - : @error GraphML couldn't be transformed to DOT. - : @error The DOT file is empty. + : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph:main) + : @return The DOT representation of the call graph + : @error GraphML couldn't be transformed to DOT + : @error The DOT file is empty : :) -declare function callgraph:get-dot($option as xs:string) as xs:string { +declare function callgraph:get-dot($option as xs:string, $filename as xs:string) +as xs:string { let $xslt := doc($callgraph:xslt) - let $graphml := inspect2graphml:main($option) + let $graphml := inspect2graphml:main($option, $filename) let $dot := try { - (: $graphml[1] is graphml:graphml, + (: $graphml[1] is graphml:graphml, $graphml[2] is path to stored XML :) transform:transform($graphml[1], $xslt, ()) } catch * { - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH02"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH02"), "Could not transform GraphML to DOT.") } - + return if(normalize-space($dot) != "") then $dot else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH03"), - "DOT file is empty.") + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH03"), + "DOT file is empty.") }; (:~ : Creates an SVG file based of a given DOT file. - : + : : @author Michelle Weidling : @since v3.1.0 : @see https://en.wikipedia.org/wiki/DOT_(graph_description_language) - : @param $dot A graph described in DOT - : @return The lines of the SVG file - : @error DOT couldn't be transformed to SVG. - : @error The SVG file is empty. + : @param $dot A graph denoted in DOT + : @return The lines of the SVG file as element(line) + : @error DOT couldn't be transformed to SVG + : @error The SVG file is empty : :) declare function callgraph:get-svg($dot as xs:string) as element(line)+ { let $conf := $config:app-root || "/config.xml" @@ -118,19 +121,34 @@ declare function callgraph:get-svg($dot as xs:string) as element(line)+ { {$target-dir} {$dot} - let $output := + let $output := try { process:execute(($cmd, "-Tsvg"), $options) } catch * { - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH04"), - "Could not transform the given DOT file to SVG.") + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH04"), + "Could not transform the given DOT file to SVG.") } return if($output//stdout/line) then $output else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH05"), - "SVG output empty.") + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH05"), + "SVG output empty.") +}; + +(:~ Generates the SVG filename from the given $option. + : + : @author Michelle Weidling + : @since v3.1.0 + : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph:main) + : @return The SVG filename + : :) +declare function local:get-filename($option as xs:string) as xs:string { + if($option = "full") then + "sade-full" + else + functx:substring-after-last($option, "/") + => replace(".", "-") }; @@ -138,18 +156,20 @@ declare function callgraph:get-svg($dot as xs:string) as element(line)+ { : Since the output of callgraph:get-svg consists of multiple line elements that : contain the XML representation of the SVG, this function extracts the SVG data : and creates a valid SVG file. - : + : : @author Michelle Weidling : @since v3.1.0 : @param $svg Multiple line elements that hold the SVG data - : @return The path to the stored SVG file. + : @param $filename The name of the generated SVG file + : @return The path to the stored SVG file : :) -declare function callgraph:clear-svg($svg as element(execution)) as xs:string { +declare function callgraph:clear-svg($svg as element(execution), $filename as +xs:string) as xs:string { let $lines := $svg//line - let $content := + let $content := for $line in subsequence($lines, 7) return $line/string() let $cleared-svg := string-join($content, "") return - xmldb:store($config:app-root || "/modules/callgraph/svg/", "output.svg", $cleared-svg) -}; + xmldb:store($config:app-root || "/modules/callgraph/svg/", $filename || ".svg", $cleared-svg) +}; \ No newline at end of file diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index b794d6d..a21026d 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -1,24 +1,23 @@ xquery version "3.1"; -(:~ +(:~ : This module creates a GraphML representation of one or more given modules or - : even the whole SADE app. For this we take the information retrieved by + : even the whole SADE app. To achieve this we take the information retrieved by : inspect:inspect-module and convert the relevant nodes to GraphML. - : - : It was roughly inspired by the graphviz app for eXist-db which can be - : found at https://github.com/KitWallace/graphviz. - : + : + : The process was roughly inspired by the graphviz app for eXist-db which can + : be found at https://github.com/KitWallace/graphviz. + : : @author Michelle Weidling : @since v3.1.0 : @see https://github.com/KitWallace/graphviz : @see http://graphml.graphdrawing.org/specification.html - : + : : :) module namespace inspect2graphml="https://sade.textgrid.de/ns/inspect2graphml"; import module namespace config="https://sade.textgrid.de/ns/config" at "../config.xqm"; -import module namespace console="http://exist-db.org/xquery/console"; import module namespace functx="http://www.functx.com"; import module namespace inspect="http://exist-db.org/xquery/inspection"; @@ -28,30 +27,31 @@ declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; (:~ : The interface for other modules. - : + : : @author Michelle Weidling : @since v3.1.0 - : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph.xqm for valid options) + : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph:main for valid options) : @return The graph representation as element(graphml:graphml) : @return The path to the stored GraphML file : :) -declare function inspect2graphml:main($option as xs:string) as item()+ { +declare function inspect2graphml:main($option as xs:string, $filename +as xs:string) as item()+ { let $graphml := inspect2graphml:get-graphml($option) return ($graphml, - xmldb:store($config:app-root || "/modules/callgraph/graphml/", "graphml.xml", $graphml)) + xmldb:store($config:app-root || "/modules/callgraph/graphml/", $filename || "-graphml.xml", $graphml)) }; (:~ - : Creates a GraphML representation of one or more given modules or - : even the whole SADE app. - : + : Creates a GraphML representation of one or more given modules or even the + : whole SADE app. + : : @author Michelle Weidling : @since v3.1.0 - : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph.xqm for valid options) + : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph:main for valid options) : :) -declare function inspect2graphml:get-graphml($option as xs:string) as +declare function inspect2graphml:get-graphml($option as xs:string) as element(graphml:graphml) { let $xqms := local:get-xqms($option) return @@ -62,7 +62,7 @@ element(graphml:graphml) { let $transformed-subgraph := inspect2graphml:transform($inspect-result, true()) return local:sort-edges-and-nodes($transformed-subgraph) } - + else element graphml:graphml { attribute xsi:schemaLocation {"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"}, @@ -72,7 +72,7 @@ element(graphml:graphml) { for $xqm in $xqms return let $inspect-result := inspect:inspect-module(xs:anyURI($xqm)) let $transformed-subgraph := inspect2graphml:transform($inspect-result, false()) - + return element graphml:node { attribute id {util:hash($xqm, "md5")}, @@ -84,12 +84,12 @@ element(graphml:graphml) { (:~ - : Recursively retrieves all *.xqm files of a given collection and all its + : Recursively retrieves all *.xqm files of a given collection and all its : descendant collections. - : + : : @author Michelle Weidling : @since v3.1.0 - : @param $collection The collection URI + : @param $collection The collection URI, e.g. "/db/apps/sade/callgraph/" : @return A sequence of all module URIs that have $collection as ancestor : :) declare function inspect2graphml:find-xqms($collection as xs:string) as xs:string+ { @@ -102,6 +102,7 @@ declare function inspect2graphml:find-xqms($collection as xs:string) as xs:strin (: other documents than xqm :) else if(contains($last-uri-part, ".")) then () + (: subcollections :) else inspect2graphml:find-xqms($uri) }; @@ -110,28 +111,28 @@ declare function inspect2graphml:find-xqms($collection as xs:string) as xs:strin (:~ : Transforms the relevant nodes that have been generated by inspect:inspect-module : to GraphML elements. - : + : : @author Michelle Weidling : @since v3.1.0 - : @param $nodes The nodes that are a result of inspect:inspect-module - : @param $single-module A flag denoting if the user wants only a single module to be examined. In this case all functions have to be converted to graphml:node which otherwise would lead to redundancies. + : @param $nodes The nodes that are the result of inspect:inspect-module + : @param $single-module A flag denoting if the user wants only a single module to be considered. In this case all function elements have to be converted to graphml:node which otherwise would lead to redundancies. : @return The transformed node(s) : :) declare function inspect2graphml:transform($nodes as node()*, $single-module as xs:boolean) as node()* { for $node in $nodes return typeswitch ($node) - + case element(module) return element graphml:graph { attribute id {$node/@prefix}, attribute edgedefault {"directed"}, inspect2graphml:transform($node/node(), $single-module) } - + case element(function) return (local:make-node($node), inspect2graphml:transform($node/node(), $single-module)) - + case element(calls) return let $source-function := $node/ancestor::function[1] let $prefix := substring-before($source-function/@name, ":") @@ -146,7 +147,7 @@ declare function inspect2graphml:transform($nodes as node()*, $single-module as local:make-node($called) else ()) - + default return () }; @@ -169,16 +170,16 @@ declare function local:get-xqms($option as xs:string) { (:~ : Gets all relevant *.xqm files. - : + : : @author Michelle Weidling : @since v3.1.0 - : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph.xqm for valid options) + : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph:main for valid options) : @return A sequence of module URIs : :) declare function local:get-xqms($option as xs:string) as xs:string* { switch ($option) case "full" return inspect2graphml:find-xqms($config:app-root) - + default return if(ends-with($option, ".xqm")) then $option @@ -193,7 +194,7 @@ declare function local:get-xqms($option as xs:string) as xs:string* { (:~ : Creates a graphml:node element. - : + : : @author Michelle Weidling : @since v3.1.0 : @param $node The current result node of inspect:inspect-module @@ -207,11 +208,12 @@ declare function local:make-node($node as node()) as element(graphml:node) { (:~ - : As the output of inspect2graphml:transform mixes up graphml:node and graphml:edge - : because of document order, this function sorts them: We want all graphml:node - : to be listed alphabetically first, followed by all graphml:edge elements. - : - : + : As the output of inspect2graphml:transform mixes up graphml:node and + : graphml:edge, this function sorts them: We want all graphml:node to be listed + : first, followed by all graphml:edge elements. The order depend on the node ID + : and the source and target attribute respectively. + : + : : @author Michelle Weidling : @since v3.1.0 : @param $graph A (sub-)graph with nodes and edges @@ -228,4 +230,4 @@ as element(graphml:graph) { order by $edge/@source, $edge/@target return $edge } -}; +}; \ No newline at end of file -- GitLab From a5a1b77ee642f384c9358d526cd428d5679b13d6 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 11:03:13 +0100 Subject: [PATCH 18/29] Add filename as input param --- modules/callgraph/callgraph.xqm | 36 +++++++++++++-------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/modules/callgraph/callgraph.xqm b/modules/callgraph/callgraph.xqm index 4d6ca89..411eeba 100644 --- a/modules/callgraph/callgraph.xqm +++ b/modules/callgraph/callgraph.xqm @@ -47,21 +47,28 @@ declare variable $callgraph:xslt := $config:app-root || "/modules/callgraph/grap : @author Michelle Weidling : @since v3.1.0 : @param $option Selects the modules which should be displayed in the output SVG file + : @param $filename The filename without extension, e.g. "output" : @return Message that indicates a successfull transformation : @error The given option is invalid + : @error The given filename is invalid : :) -declare function callgraph:main($option as xs:string) as xs:string { +declare function callgraph:main($option as xs:string, $filename as xs:string) as xs:string { if(ends-with($option, ".xqm") or $option = "full" or xmldb:collection-available($option)) then - let $filename := local:get-filename($option) + let $filename := + if(contains($filename, ".")) then + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH01"), + "Invalid filename '" || $filename || "'. Please enter a filename without file extension.") + else + $filename let $dot := callgraph:get-dot($option, $filename) let $svg-output := callgraph:get-svg($dot) let $svg := callgraph:clear-svg($svg-output, $filename) return "Call graph creation successfull." else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH01"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH02"), "Invalid option '" || $option || "'. Please enter a base URI, a collection path or 'full' as argument.") }; @@ -88,7 +95,7 @@ as xs:string { $graphml[2] is path to stored XML :) transform:transform($graphml[1], $xslt, ()) } catch * { - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH02"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH03"), "Could not transform GraphML to DOT.") } @@ -96,7 +103,7 @@ as xs:string { if(normalize-space($dot) != "") then $dot else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH03"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH04"), "DOT file is empty.") }; @@ -125,32 +132,17 @@ declare function callgraph:get-svg($dot as xs:string) as element(line)+ { try { process:execute(($cmd, "-Tsvg"), $options) } catch * { - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH04"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH05"), "Could not transform the given DOT file to SVG.") } return if($output//stdout/line) then $output else - error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH05"), + error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH06"), "SVG output empty.") }; -(:~ Generates the SVG filename from the given $option. - : - : @author Michelle Weidling - : @since v3.1.0 - : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph:main) - : @return The SVG filename - : :) -declare function local:get-filename($option as xs:string) as xs:string { - if($option = "full") then - "sade-full" - else - functx:substring-after-last($option, "/") - => replace(".", "-") -}; - (:~ : Since the output of callgraph:get-svg consists of multiple line elements that -- GitLab From ce24c67e79eeb0c133745ed380798475a65ab633 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 11:06:23 +0100 Subject: [PATCH 19/29] Integrate module tests in automatic test module --- modules/callgraph/tests/callgraph-test-runner.xq | 14 -------------- .../tests/inspect2graphml-test-runner.xq | 14 -------------- test.xqm | 16 +++++++++++++++- 3 files changed, 15 insertions(+), 29 deletions(-) delete mode 100644 modules/callgraph/tests/callgraph-test-runner.xq delete mode 100644 modules/callgraph/tests/inspect2graphml-test-runner.xq diff --git a/modules/callgraph/tests/callgraph-test-runner.xq b/modules/callgraph/tests/callgraph-test-runner.xq deleted file mode 100644 index 3274d4b..0000000 --- a/modules/callgraph/tests/callgraph-test-runner.xq +++ /dev/null @@ -1,14 +0,0 @@ -xquery version "3.1"; - - -(: This main module starts the tests stored in callgraph-test.xql. :) - -import module namespace callgraph-test = "https://sade.textgrid.de/ns/callgraph-test" at "callgraph-test.xql"; -import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; -import module namespace console="http://exist-db.org/xquery/console"; - -declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; - -test:suite( - util:list-functions("https://sade.textgrid.de/ns/callgraph-test") -) diff --git a/modules/callgraph/tests/inspect2graphml-test-runner.xq b/modules/callgraph/tests/inspect2graphml-test-runner.xq deleted file mode 100644 index ae67138..0000000 --- a/modules/callgraph/tests/inspect2graphml-test-runner.xq +++ /dev/null @@ -1,14 +0,0 @@ -xquery version "3.1"; - - -(: This main module starts the tests stored in inspect2graphml-test.xql. :) - -import module namespace inspect2graphml-test = "https://sade.textgrid.de/ns/inspect2graphml-test" at "inspect2graphml-test.xql"; -import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; -import module namespace console="http://exist-db.org/xquery/console"; - -declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; - -test:suite( - util:list-functions("https://sade.textgrid.de/ns/inspect2graphml-test") -) diff --git a/test.xqm b/test.xqm index 402a2c9..ab2e34e 100644 --- a/test.xqm +++ b/test.xqm @@ -3,12 +3,14 @@ xquery version "3.1"; module namespace tests="https://sade.textgrid.de/ns/tests"; import module namespace app="https://sade.textgrid.de/ns/app" at "modules/app.xqm"; +import module namespace callgraph-test = "https://sade.textgrid.de/ns/callgraph-test" at "modules/callgraph/tests/callgraph-test.xq"; import module namespace config="https://sade.textgrid.de/ns/config" at "modules/config.xqm"; +import module namespace inspect2graphml-test = "https://sade.textgrid.de/ns/inspect2graphml-test" at "modules/callgraph/tests/inspect2graphml-test.xq"; import module namespace multiviewer="https://sade.textgrid.de/ns/multiviewer" at "modules/multiviewer.xqm"; import module namespace nav="https://sade.textgrid.de/ns/navigation" at "modules/navigation.xqm"; import module namespace tgconnect="https://sade.textgrid.de/ns/connect" at "modules/textgrid/connect.xqm"; -declare namespace test="http://exist-db.org/xquery/xqsuite"; +import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; declare variable $tests:node := ; declare variable $tests:model := map{}; @@ -177,3 +179,15 @@ return } }; + +(: ************* :) +(: * CALLGRAPH * :) +(: ************* :) + +declare function tests:callgraph-main() { + test:suite(util:list-functions("https://sade.textgrid.de/ns/callgraph-test")) +}; + +declare function tests:inspect2graphml-main() { + test:suite(util:list-functions("https://sade.textgrid.de/ns/inspect2graphml-test")) +}; \ No newline at end of file -- GitLab From e029a72c8f8f3ac45420d5b72f83b08e5c3cd91e Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 11:08:06 +0100 Subject: [PATCH 20/29] Rename test files --- .../{callgraph-test.xql => callgraph-test.xq} | 25 ++++++++++++------- ...aphml-test.xql => inspect2graphml-test.xq} | 16 ++++++------ 2 files changed, 24 insertions(+), 17 deletions(-) rename modules/callgraph/tests/{callgraph-test.xql => callgraph-test.xq} (82%) rename modules/callgraph/tests/{inspect2graphml-test.xql => inspect2graphml-test.xq} (92%) diff --git a/modules/callgraph/tests/callgraph-test.xql b/modules/callgraph/tests/callgraph-test.xq similarity index 82% rename from modules/callgraph/tests/callgraph-test.xql rename to modules/callgraph/tests/callgraph-test.xq index 588a5c3..1b0c4a3 100644 --- a/modules/callgraph/tests/callgraph-test.xql +++ b/modules/callgraph/tests/callgraph-test.xq @@ -10,13 +10,20 @@ import module namespace callgraph="https://sade.textgrid.de/ns/callgraph" at ".. declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; declare namespace test="http://exist-db.org/xquery/xqsuite"; +declare + %test:name("Testing filename error message by error code") + %test:args("invalid-filename.svg") + %test:assertError("CALLGRAPH01") + function callgraph-test:aa-test-error($option as xs:string) { + callgraph:main($option, "test-2") +}; declare - %test:name("Testing error message by error code") + %test:name("Testing option error message by error code") %test:args("an invalid option") - %test:assertError("CALLGRAPH01") + %test:assertError("CALLGRAPH02") function callgraph-test:aa-test-error($option as xs:string) { - callgraph:main($option) + callgraph:main($option, "test-2") }; declare @@ -24,7 +31,7 @@ declare %test:args("an invalid option") %test:assertError("Invalid option 'an invalid option'. Please enter a base URI, a collection path or 'full' as argument.") function callgraph-test:ab-test-error($option as xs:string) { - callgraph:main($option) + callgraph:main($option, "test-2") }; @@ -33,7 +40,7 @@ declare %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") %test:assertEquals("digraph g {node [shape=box, style=filled, color=""#90b0d4""];""inspect2graphml-testmodule:get-value"" [shape=box];""inspect2graphml-testmodule:main"" [shape=box];""inspect2graphml-testmodule:set-value"" [shape=box];""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:get-value"";""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule:set-value"" -> ""inspect2graphml-testmodule:get-value"";}") function callgraph-test:ba-dot($option as xs:string) { - callgraph:get-dot($option) + callgraph:get-dot($option, "inspect2graphml-testmodule-xqm") }; @@ -42,13 +49,13 @@ declare %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") %test:assertEquals("digraph g {node [shape=box, style=filled, color=""#90b0d4""];""inspect2graphml-testmodule:get-value"" [shape=box];""inspect2graphml-testmodule:main"" [shape=box];""inspect2graphml-testmodule:set-value"" [shape=box];""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:get-value"";""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule:set-value"" -> ""inspect2graphml-testmodule:get-value"";node [shape=box, style=filled, color=""#e6f2ff""];""inspect2graphml-testmodule2:get-value"" [shape=box];""inspect2graphml-testmodule2:main"" [shape=box];""inspect2graphml-testmodule2:set-value"" [shape=box];""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:get-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:set-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule2:set-value"" -> ""inspect2graphml-testmodule:get-value"";}") function callgraph-test:bb-dot($option as xs:string) { - callgraph:get-dot($option) + callgraph:get-dot($option, "tests-collection") }; declare %test:name("Testing SVG error behavior") %test:args("") - %test:assertError("CALLGRAPH05") + %test:assertError("CALLGRAPH06") function callgraph-test:c-svg($dot as xs:string) { callgraph:get-svg($dot) }; @@ -57,7 +64,7 @@ declare declare %test:name("Testing SVG clearance for a simple module") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") - %test:assertEquals("/db/apps/sade/modules/callgraph/svg/output.svg") + %test:assertEquals("Call graph creation successfull.") function callgraph-test:d-svg($option as xs:string) { - callgraph:main($option) + callgraph:main($option, "inspect2graphml-testmodule-xqm2") }; diff --git a/modules/callgraph/tests/inspect2graphml-test.xql b/modules/callgraph/tests/inspect2graphml-test.xq similarity index 92% rename from modules/callgraph/tests/inspect2graphml-test.xql rename to modules/callgraph/tests/inspect2graphml-test.xq index 3215be9..4c5abdd 100644 --- a/modules/callgraph/tests/inspect2graphml-test.xql +++ b/modules/callgraph/tests/inspect2graphml-test.xq @@ -31,24 +31,24 @@ declare declare %test:name("Testing a simple module with URI as input") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") - %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/graphml.xml") - function inspect2graphml-test:bb-simple-graph($uri-or-coll as xs:string) { - inspect2graphml:main($uri-or-coll) + %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/inspect2graphml-test-graphml.xml") + function inspect2graphml-test:bb-simple-graph($option as xs:string) { + inspect2graphml:main($option, "inspect2graphml-test") }; declare %test:name("Testing two simple modules with collection path as input") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") - %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/graphml.xml") - function inspect2graphml-test:bc-simple-graph($uri-or-coll as xs:string) { - inspect2graphml:main($uri-or-coll) + %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/inspect2graphml-test2-graphml.xml") + function inspect2graphml-test:bc-simple-graph($option as xs:string) { + inspect2graphml:main($option, "inspect2graphml-test2") }; declare %test:name("Testing transformation from GraphML to DOT with one module") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") - %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/graphml.xml") + %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/inspect2graphml-test3-graphml.xml") function inspect2graphml-test:ca-simple-graphml-to-dot($xqm as xs:string) { - inspect2graphml:main($xqm) + inspect2graphml:main($xqm, "inspect2graphml-test3") }; -- GitLab From 1ba24ce317cfea9a97038fd5ad6b4647a29b1ef1 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 11:09:56 +0100 Subject: [PATCH 21/29] Add samples --- .../graphml/callgraph-modules-graphml.xml | 37 +++++ modules/callgraph/svg/callgraph-modules.svg | 132 ++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 modules/callgraph/graphml/callgraph-modules-graphml.xml create mode 100644 modules/callgraph/svg/callgraph-modules.svg diff --git a/modules/callgraph/graphml/callgraph-modules-graphml.xml b/modules/callgraph/graphml/callgraph-modules-graphml.xml new file mode 100644 index 0000000..3dccaaa --- /dev/null +++ b/modules/callgraph/graphml/callgraph-modules-graphml.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/callgraph/svg/callgraph-modules.svg b/modules/callgraph/svg/callgraph-modules.svg new file mode 100644 index 0000000..4bfae94 --- /dev/null +++ b/modules/callgraph/svg/callgraph-modules.svg @@ -0,0 +1,132 @@ + + + + g + + + inspect2graphml:find-xqms + + inspect2graphml:find-xqms + + + inspect2graphml:find-xqms->inspect2graphml:find-xqms + + + + + functx:substring-after-last + + functx:substring-after-last + + + inspect2graphml:find-xqms->functx:substring-after-last + + + + + inspect2graphml:get-graphml + + inspect2graphml:get-graphml + + + inspect2graphml:transform + + inspect2graphml:transform + + + inspect2graphml:get-graphml->inspect2graphml:transform + + + + + local:get-xqms + + local:get-xqms + + + inspect2graphml:get-graphml->local:get-xqms + + + + + local:sort-edges-and-nodes + + local:sort-edges-and-nodes + + + inspect2graphml:get-graphml->local:sort-edges-and-nodes + + + + + inspect2graphml:main + + inspect2graphml:main + + + inspect2graphml:main->inspect2graphml:get-graphml + + + + + inspect2graphml:transform->inspect2graphml:transform + + + + + local:make-node + + local:make-node + + + inspect2graphml:transform->local:make-node + + + + + local:get-xqms->inspect2graphml:find-xqms + + + + + callgraph:clear-svg + + callgraph:clear-svg + + + callgraph:get-dot + + callgraph:get-dot + + + callgraph:get-dot->inspect2graphml:main + + + + + callgraph:get-svg + + callgraph:get-svg + + + callgraph:main + + callgraph:main + + + callgraph:main->callgraph:clear-svg + + + + + callgraph:main->callgraph:get-dot + + + + + callgraph:main->callgraph:get-svg + + + + + \ No newline at end of file -- GitLab From 7667b7512cd6a1254e3ce2751504f1093c70fa41 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 11:10:14 +0100 Subject: [PATCH 22/29] Update docs --- docs/callgraphs.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/callgraphs.md b/docs/callgraphs.md index ffeb223..657fa9c 100644 --- a/docs/callgraphs.md +++ b/docs/callgraphs.md @@ -38,14 +38,16 @@ import module namespace callgraph="https://sade.textgrid.de/ns/callgraph" at "${ To generate a call graph all you have to do is calling the function ``` -callgraph:main("/some/input") +callgraph:main("/some/input", "filename") ``` -where the input can be the following: +where the first input parameter can be the following: * an URI of a single module, e.g. `/db/apps/sade/modules/some-module.xqm` * the URI of a collection, e.g. `/db/apps/sade/modules/my-project-collection` * `full` (generates a call graph for the whole SADE app) +The second parameter is the desired filename without file extension. + The call graph SVG is stored to `/db/apps/sade/modules/callgraph/svg` while the GraphML representation can be found at `/db/apps/sade/modules/callgraph/graphml`. -- GitLab From cb019644ca9e15178b24d1c8d4d2079bae1933ce Mon Sep 17 00:00:00 2001 From: mrodzis Date: Wed, 5 Dec 2018 16:27:00 +0100 Subject: [PATCH 23/29] Extend docs --- docs/about.md | 1 + docs/callgraphs.md | 35 +++++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/docs/about.md b/docs/about.md index c2740de..d23d095 100644 --- a/docs/about.md +++ b/docs/about.md @@ -39,6 +39,7 @@ version is a completely rewritten one. - [Dokuwiki](dokuwikiParser.md) - multi-language support - [prepared for optionally prerendering](prerendering.md) +- create [call graphs](callgraphs.md) of modules ### Third party addons - SemToNotes diff --git a/docs/callgraphs.md b/docs/callgraphs.md index 657fa9c..424a241 100644 --- a/docs/callgraphs.md +++ b/docs/callgraphs.md @@ -2,58 +2,65 @@ This modules examines XQuery modules and creates an SVG representation of their respective call graphs. These call graphs are useful as an overview of how the SADE app and project specific extensions work and can be used as illustration of the app's architecture, for improving a module's structure while developing, ... + To meet the different needs of users, three ways of using this module are possible: You can create the call graph of + * a single module * all modules that belong to a collection * the whole SADE app -In case several modules are inspected all functions that belong to one module have the same color in the graph to - ## Requirements -Please make sure you have **[GraphViz](http://graphviz.org/)** installed whereever the database runs (on your computer, on a VM, ...). +Please make sure you have [GraphViz](http://graphviz.org/) installed wherever the database runs (on your computer, on a VM, ...). ## Configuration For the module to work properly you have to consider on which kind of operating system (Windows, Unix, MacOS, ...) the database runs. Simply change the following line in `config.xml` to the command line invocation of `dot` that is used by your OS: -``` -dot +```xml +\dot ``` -The option defaults to Unix. +The option defaults to Unix' `dot` command. ## How to create call graphs Before using the call graph module please make sure you have the module imported with ``` -import module namespace callgraph="https://sade.textgrid.de/ns/callgraph" at "${path/to/module}/callgraph.xqm"; +import module namespace callgraph="https://sade.textgrid.de/ns/callgraph" at "$(path/to/module)/callgraph.xqm"; ``` To generate a call graph all you have to do is calling the function ``` -callgraph:main("/some/input", "filename") +callgraph:main("/some/input/as/string", "filename/as/string") ``` where the first input parameter can be the following: -* an URI of a single module, e.g. `/db/apps/sade/modules/some-module.xqm` -* the URI of a collection, e.g. `/db/apps/sade/modules/my-project-collection` +* the base URI of a single module, e.g. `/db/apps/sade/modules/some-module.xqm` +* the URI of a collection as path, e.g. `/db/apps/sade/modules/my-project-collection` * `full` (generates a call graph for the whole SADE app) -The second parameter is the desired filename without file extension. +The second parameter is the desired filename __without__ file extension. The call graph SVG is stored to `/db/apps/sade/modules/callgraph/svg` while the GraphML representation can be found at `/db/apps/sade/modules/callgraph/graphml`. ## How it works (in detail) -Depending on which input option you select (cf. "How to create call graphs" above) one or more modules are examined by eXist-db's `inspect:inspect-module` function which returns some information about the module(s) and the functions within. +Depending on which input option you select (cf. "How to create call graphs" above) one or more modules are examined by eXist-db's `inspect:inspect-module` function which returns some information about the module(s) and its functions. + +This information is then converted into a [GraphML](http://graphml.graphdrawing.org/) representation of the module as a directed graph in which all calling and called functions are represented as a `graphml:node` element. In case several modules are inspected duplicates are avoided. The calling/called connection between two functions is denoted by a `graphml:edge` element where the calling function becomes the edge's `@source` and the called one the edge's `@target`. + +This GraphML document is then saved to `/db/apps/sade/callgraph/graphml` and serves as input for generating a [DOT](https://graphviz.gitlab.io/_pages/doc/info/lang.html) representation of the graph which in turn is used by `dot` to create an SVG file that is saved to `/db/apps/sade/callgraph/svg`. + + +## Sample output -This information is then converted into a **[GraphML](http://graphml.graphdrawing.org/)** representation of the module as a directed graph (`graphml:graph`) in which all calling and called functions are represented as a `graphml:node` element. In case several modules are inspected duplicates are avoided. The calling/called connection between two functions is denoted by a `graphml:edge` element where the calling function becomes the `graphml:edge/@source` and the called one the `graphml:edge/@target`. +The following image has been generated by the callgraph-module and illustrates how its modules and functions interact: -This GraphML document is then saved to `/db/apps/sade/callgraph/graphml` and serves as input for generating a **[DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language))** representation of the graph which in turn is used as input for `dot` to create an SVG file that is saved to `/db/apps/sade/callgraph/svg`. \ No newline at end of file +![Call graph](http://localhost:8080/exist/apps/sade/modules/callgraph/svg/callgraph-modules.svg) \ No newline at end of file -- GitLab From 4c99eb655c2cebb78581c90e155c5173ab5cbdb1 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Thu, 6 Dec 2018 09:42:39 +0100 Subject: [PATCH 24/29] Remove surplus code --- modules/callgraph/graphml2dot.xsl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/callgraph/graphml2dot.xsl b/modules/callgraph/graphml2dot.xsl index f0506a8..e9b2cac 100644 --- a/modules/callgraph/graphml2dot.xsl +++ b/modules/callgraph/graphml2dot.xsl @@ -106,8 +106,4 @@ - - - #555544 - \ No newline at end of file -- GitLab From f8318b6fec89ec6caf9e12bcaba9414a88a358b7 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 10 Dec 2018 10:38:17 +0100 Subject: [PATCH 25/29] Clear leftovers of rebase --- modules/callgraph/graphml/graphml.xml | 37 -------- modules/callgraph/inspect2graphml.xqm | 15 --- modules/callgraph/svg/output.svg | 132 -------------------------- 3 files changed, 184 deletions(-) delete mode 100644 modules/callgraph/graphml/graphml.xml delete mode 100644 modules/callgraph/svg/output.svg diff --git a/modules/callgraph/graphml/graphml.xml b/modules/callgraph/graphml/graphml.xml deleted file mode 100644 index 3294242..0000000 --- a/modules/callgraph/graphml/graphml.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index a21026d..3cb2c69 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -152,21 +152,6 @@ declare function inspect2graphml:transform($nodes as node()*, $single-module as () }; -declare function local:get-xqms($option as xs:string) { - switch ($option) - case "full" return inspect2graphml:find-xqms($config:app-root) - - default return - if(ends-with($option, ".xqm")) then - $option - else - for $child in xmldb:get-child-resources($option) return - if(contains($child, ".xqm")) then - $option || "/" || $child - else - () -}; - (:~ : Gets all relevant *.xqm files. diff --git a/modules/callgraph/svg/output.svg b/modules/callgraph/svg/output.svg deleted file mode 100644 index 358439d..0000000 --- a/modules/callgraph/svg/output.svg +++ /dev/null @@ -1,132 +0,0 @@ - - - - g - - - inspect2graphml:find-xqms - - inspect2graphml:find-xqms - - - inspect2graphml:find-xqms->inspect2graphml:find-xqms - - - - - functx:substring-after-last - - functx:substring-after-last - - - inspect2graphml:find-xqms->functx:substring-after-last - - - - - inspect2graphml:get-graphml - - inspect2graphml:get-graphml - - - inspect2graphml:transform - - inspect2graphml:transform - - - inspect2graphml:get-graphml->inspect2graphml:transform - - - - - local:get-xqms - - local:get-xqms - - - inspect2graphml:get-graphml->local:get-xqms - - - - - local:sort-edges-and-nodes - - local:sort-edges-and-nodes - - - inspect2graphml:get-graphml->local:sort-edges-and-nodes - - - - - inspect2graphml:main - - inspect2graphml:main - - - inspect2graphml:main->inspect2graphml:get-graphml - - - - - inspect2graphml:transform->inspect2graphml:transform - - - - - local:make-node - - local:make-node - - - inspect2graphml:transform->local:make-node - - - - - local:get-xqms->inspect2graphml:find-xqms - - - - - callgraph:clear-svg - - callgraph:clear-svg - - - callgraph:get-dot - - callgraph:get-dot - - - callgraph:get-dot->inspect2graphml:main - - - - - callgraph:get-svg - - callgraph:get-svg - - - callgraph:main - - callgraph:main - - - callgraph:main->callgraph:clear-svg - - - - - callgraph:main->callgraph:get-dot - - - - - callgraph:main->callgraph:get-svg - - - - - -- GitLab From 32c63f1b3f97085976f409e0326cb4dfd9da4a2c Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 10 Dec 2018 11:01:42 +0100 Subject: [PATCH 26/29] Simplify finding *.xqm files --- .../graphml/callgraph-modules-graphml.xml | 12 +- modules/callgraph/inspect2graphml.xqm | 32 +--- modules/callgraph/svg/callgraph-modules.svg | 154 ++++++++---------- 3 files changed, 72 insertions(+), 126 deletions(-) diff --git a/modules/callgraph/graphml/callgraph-modules-graphml.xml b/modules/callgraph/graphml/callgraph-modules-graphml.xml index 3dccaaa..dbd4a64 100644 --- a/modules/callgraph/graphml/callgraph-modules-graphml.xml +++ b/modules/callgraph/graphml/callgraph-modules-graphml.xml @@ -1,27 +1,23 @@ - + - + - - - + - - - + diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index 3cb2c69..01e8551 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -18,6 +18,7 @@ xquery version "3.1"; module namespace inspect2graphml="https://sade.textgrid.de/ns/inspect2graphml"; import module namespace config="https://sade.textgrid.de/ns/config" at "../config.xqm"; +import module namespace console="http://exist-db.org/xquery/console"; import module namespace functx="http://www.functx.com"; import module namespace inspect="http://exist-db.org/xquery/inspection"; @@ -53,7 +54,7 @@ as xs:string) as item()+ { : :) declare function inspect2graphml:get-graphml($option as xs:string) as element(graphml:graphml) { - let $xqms := local:get-xqms($option) + let $xqms := inspect2graphml:get-xqms($option) return if(count($xqms) = 1) then element graphml:graphml { @@ -83,31 +84,6 @@ element(graphml:graphml) { }; -(:~ - : Recursively retrieves all *.xqm files of a given collection and all its - : descendant collections. - : - : @author Michelle Weidling - : @since v3.1.0 - : @param $collection The collection URI, e.g. "/db/apps/sade/callgraph/" - : @return A sequence of all module URIs that have $collection as ancestor - : :) -declare function inspect2graphml:find-xqms($collection as xs:string) as xs:string+ { - for $child in collection($collection) - let $uri := base-uri($child) - let $last-uri-part := functx:substring-after-last($uri, "/") - return - if(contains($last-uri-part, ".xqm")) then - $uri - (: other documents than xqm :) - else if(contains($last-uri-part, ".")) then - () - (: subcollections :) - else - inspect2graphml:find-xqms($uri) -}; - - (:~ : Transforms the relevant nodes that have been generated by inspect:inspect-module : to GraphML elements. @@ -161,9 +137,9 @@ declare function inspect2graphml:transform($nodes as node()*, $single-module as : @param $option Selects the modules which should be displayed in the output SVG file (cf. callgraph:main for valid options) : @return A sequence of module URIs : :) -declare function local:get-xqms($option as xs:string) as xs:string* { +declare function inspect2graphml:get-xqms($option as xs:string) as xs:string* { switch ($option) - case "full" return inspect2graphml:find-xqms($config:app-root) + case "full" return (collection($config:app-root)/base-uri())[ends-with(., ".xqm")] default return if(ends-with($option, ".xqm")) then diff --git a/modules/callgraph/svg/callgraph-modules.svg b/modules/callgraph/svg/callgraph-modules.svg index 4bfae94..d1db658 100644 --- a/modules/callgraph/svg/callgraph-modules.svg +++ b/modules/callgraph/svg/callgraph-modules.svg @@ -1,132 +1,106 @@ - - - + + g - + - inspect2graphml:find-xqms - - inspect2graphml:find-xqms - - - inspect2graphml:find-xqms->inspect2graphml:find-xqms - - - - - functx:substring-after-last - - functx:substring-after-last - - - inspect2graphml:find-xqms->functx:substring-after-last - - - - inspect2graphml:get-graphml - - inspect2graphml:get-graphml + + inspect2graphml:get-graphml + + + inspect2graphml:get-xqms + + inspect2graphml:get-xqms + + + inspect2graphml:get-graphml->inspect2graphml:get-xqms + + inspect2graphml:transform - - inspect2graphml:transform + + inspect2graphml:transform - + inspect2graphml:get-graphml->inspect2graphml:transform - - - - - local:get-xqms - - local:get-xqms - - - inspect2graphml:get-graphml->local:get-xqms - - + + - + local:sort-edges-and-nodes - - local:sort-edges-and-nodes + + local:sort-edges-and-nodes - + inspect2graphml:get-graphml->local:sort-edges-and-nodes - - + + inspect2graphml:main - - inspect2graphml:main + + inspect2graphml:main - + inspect2graphml:main->inspect2graphml:get-graphml - - + + - + inspect2graphml:transform->inspect2graphml:transform - - + + - + local:make-node - - local:make-node + + local:make-node - + inspect2graphml:transform->local:make-node - - - - - local:get-xqms->inspect2graphml:find-xqms - - + + - + callgraph:clear-svg - - callgraph:clear-svg + + callgraph:clear-svg - + callgraph:get-dot - - callgraph:get-dot + + callgraph:get-dot - + callgraph:get-dot->inspect2graphml:main - - + + - + callgraph:get-svg - - callgraph:get-svg + + callgraph:get-svg - + callgraph:main - - callgraph:main + + callgraph:main - + callgraph:main->callgraph:clear-svg - - + + - + callgraph:main->callgraph:get-dot - - + + - + callgraph:main->callgraph:get-svg - - + + \ No newline at end of file -- GitLab From efd70a451eaf621108a68414f1c1e8a7203b3d67 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 10 Dec 2018 11:29:38 +0100 Subject: [PATCH 27/29] Update ordering mechanism for nodes --- modules/callgraph/inspect2graphml.xqm | 2 +- modules/callgraph/tests/callgraph-test.xq | 2 +- modules/callgraph/tests/inspect2graphml-test.xq | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/callgraph/inspect2graphml.xqm b/modules/callgraph/inspect2graphml.xqm index 01e8551..4feceee 100644 --- a/modules/callgraph/inspect2graphml.xqm +++ b/modules/callgraph/inspect2graphml.xqm @@ -185,7 +185,7 @@ as element(graphml:graph) { element graphml:graph { $graph/@*, for $node in $graph/graphml:node - order by $node/@id + order by $node/@id/string() ascending return $node, for $edge in $graph/graphml:edge order by $edge/@source, $edge/@target diff --git a/modules/callgraph/tests/callgraph-test.xq b/modules/callgraph/tests/callgraph-test.xq index 1b0c4a3..35b2060 100644 --- a/modules/callgraph/tests/callgraph-test.xq +++ b/modules/callgraph/tests/callgraph-test.xq @@ -47,7 +47,7 @@ declare declare %test:name("Testing DOT ouput for two modules") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") - %test:assertEquals("digraph g {node [shape=box, style=filled, color=""#90b0d4""];""inspect2graphml-testmodule:get-value"" [shape=box];""inspect2graphml-testmodule:main"" [shape=box];""inspect2graphml-testmodule:set-value"" [shape=box];""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:get-value"";""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule:set-value"" -> ""inspect2graphml-testmodule:get-value"";node [shape=box, style=filled, color=""#e6f2ff""];""inspect2graphml-testmodule2:get-value"" [shape=box];""inspect2graphml-testmodule2:main"" [shape=box];""inspect2graphml-testmodule2:set-value"" [shape=box];""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:get-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:set-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule2:set-value"" -> ""inspect2graphml-testmodule:get-value"";}") + %test:assertEquals("digraph g {node [shape=box, style=filled, color=""#90b0d4""];""inspect2graphml-testmodule2:get-value"" [shape=box];""inspect2graphml-testmodule2:main"" [shape=box];""inspect2graphml-testmodule2:set-value"" [shape=box];""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:get-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule2:set-value"";""inspect2graphml-testmodule2:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule2:set-value"" -> ""inspect2graphml-testmodule:get-value"";node [shape=box, style=filled, color=""#e6f2ff""];""inspect2graphml-testmodule:get-value"" [shape=box];""inspect2graphml-testmodule:main"" [shape=box];""inspect2graphml-testmodule:set-value"" [shape=box];""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:get-value"";""inspect2graphml-testmodule:main"" -> ""inspect2graphml-testmodule:set-value"";""inspect2graphml-testmodule:set-value"" -> ""inspect2graphml-testmodule:get-value"";}") function callgraph-test:bb-dot($option as xs:string) { callgraph:get-dot($option, "tests-collection") }; diff --git a/modules/callgraph/tests/inspect2graphml-test.xq b/modules/callgraph/tests/inspect2graphml-test.xq index 4c5abdd..394bb53 100644 --- a/modules/callgraph/tests/inspect2graphml-test.xq +++ b/modules/callgraph/tests/inspect2graphml-test.xq @@ -40,7 +40,7 @@ declare declare %test:name("Testing two simple modules with collection path as input") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/") - %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/inspect2graphml-test2-graphml.xml") + %test:assertEquals("", "/db/apps/sade/modules/callgraph/graphml/inspect2graphml-test2-graphml.xml") function inspect2graphml-test:bc-simple-graph($option as xs:string) { inspect2graphml:main($option, "inspect2graphml-test2") }; -- GitLab From 335fc1baf79ef4b568bcfc3c6ab79788b8a63eed Mon Sep 17 00:00:00 2001 From: mrodzis Date: Mon, 10 Dec 2018 12:49:21 +0100 Subject: [PATCH 28/29] Move transformation to DOT in callgraph.xqm --- modules/callgraph/callgraph.xqm | 60 +++++++- .../graphml/callgraph-modules-graphml.xml | 26 ++-- modules/callgraph/graphml2dot.xsl | 109 -------------- modules/callgraph/svg/callgraph-modules.svg | 141 ++++++++++-------- modules/callgraph/tests/callgraph-test.xq | 42 ++++++ 5 files changed, 189 insertions(+), 189 deletions(-) delete mode 100644 modules/callgraph/graphml2dot.xsl diff --git a/modules/callgraph/callgraph.xqm b/modules/callgraph/callgraph.xqm index 411eeba..b7b31ea 100644 --- a/modules/callgraph/callgraph.xqm +++ b/modules/callgraph/callgraph.xqm @@ -35,7 +35,11 @@ declare namespace graphml="http://graphml.graphdrawing.org/xmlns"; declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; declare variable $callgraph:xslt := $config:app-root || "/modules/callgraph/graphml2dot.xsl"; - +declare variable $callgraph:colors := + ("#90b0d4", "#e6f2ff", "#eee6ff", "#ffffe6", + "#f9ecec", "#bfe0ba", "#bfd2e3", "#dbaddb", + "#decbb2", "#e0b7b6", "#d9f09e", "#f5a1a4", + "#faf0a5", "#8acca0", "#cfb88c", "#d18ecb"); (:~ : Creates an SVG file of one or more modules depending on the given $option. @@ -87,13 +91,13 @@ declare function callgraph:main($option as xs:string, $filename as xs:string) as : :) declare function callgraph:get-dot($option as xs:string, $filename as xs:string) as xs:string { - let $xslt := doc($callgraph:xslt) let $graphml := inspect2graphml:main($option, $filename) let $dot := try { (: $graphml[1] is graphml:graphml, $graphml[2] is path to stored XML :) - transform:transform($graphml[1], $xslt, ()) + callgraph:transform2dot($graphml[1]) + => string-join("") } catch * { error( QName("https://sade.textgrid.de/ns/app", "CALLGRAPH03"), "Could not transform GraphML to DOT.") @@ -108,6 +112,56 @@ as xs:string { }; +(:~ + : Transforms the given GraphML elements to DOT. + : + : @author Michelle Weidling + : @since v3.1.0 + : @see https://en.wikipedia.org/wiki/DOT_(graph_description_language) + : @param $nodes The GraphML nodes generated by inspect2graphml:main + : @return The DOT representation of the call graph + : :) +declare function callgraph:transform2dot($nodes as element()*) as node()* { + for $node in $nodes return + typeswitch ($node) + + case element(graphml:graphml) return + (text{"digraph g {"}, + callgraph:transform2dot($node/node()), + text{"}"}) + + case element(graphml:graph) return + if($node/@id = "base-graph") then + callgraph:transform2dot($node/node()) + else + (text{"node [shape=box, style=filled, color="""}, + text{$callgraph:colors[count($node/preceding::graphml:graph) + 1]}, + text{"""];"}, + callgraph:transform2dot($node/node())) + + case element(graphml:node) return + if($node/parent::graphml:graph[@id = "base-graph"]) then + callgraph:transform2dot($node/node()) + else + (text{""""}, + text{$node/@id}, + text{""" [shape=box];"}) + + case element(graphml:edge) return + (text{""""}, + text{$node/@source}, + text{""""}, + text{" -> "}, + text{""""}, + text{$node/@target}, + text{""";"}) + + default return + callgraph:transform2dot($node/node()) +}; + + + (:~ : Creates an SVG file based of a given DOT file. : diff --git a/modules/callgraph/graphml/callgraph-modules-graphml.xml b/modules/callgraph/graphml/callgraph-modules-graphml.xml index dbd4a64..34fee6e 100644 --- a/modules/callgraph/graphml/callgraph-modules-graphml.xml +++ b/modules/callgraph/graphml/callgraph-modules-graphml.xml @@ -1,6 +1,20 @@ + + + + + + + + + + + + + + @@ -17,17 +31,5 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/modules/callgraph/graphml2dot.xsl b/modules/callgraph/graphml2dot.xsl deleted file mode 100644 index e9b2cac..0000000 --- a/modules/callgraph/graphml2dot.xsl +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - digraph g { - - } - - - - - - node [shape=box, style=filled, color=" - - - - "]; - - - - - - - - - - - - " - - " - [shape=box]; - - - - - - " - - " - - -> - - " - - " - ; - - - - - - - - - #90b0d4 - - - #e6f2ff - - - #eee6ff - - - #ffffe6 - - - #f9ecec - - - #bfe0ba - - - #bfd2e3 - - - #dbaddb - - - #decbb2 - - - #e0b7b6 - - - #d9f09e - - - #f5a1a4 - - - #faf0a5 - - - #8acca0 - - - #cfb88c - - - #d18ecb - - - - \ No newline at end of file diff --git a/modules/callgraph/svg/callgraph-modules.svg b/modules/callgraph/svg/callgraph-modules.svg index d1db658..b6c8980 100644 --- a/modules/callgraph/svg/callgraph-modules.svg +++ b/modules/callgraph/svg/callgraph-modules.svg @@ -1,106 +1,117 @@ + g - + + callgraph:clear-svg + + callgraph:clear-svg + + + callgraph:get-dot + + callgraph:get-dot + + + inspect2graphml:main + + inspect2graphml:main + + + callgraph:get-dot->inspect2graphml:main + + + + + callgraph:get-svg + + callgraph:get-svg + + + callgraph:main + + callgraph:main + + + callgraph:main->callgraph:clear-svg + + + + + callgraph:main->callgraph:get-dot + + + + + callgraph:main->callgraph:get-svg + + + + + callgraph:transform2dot + + callgraph:transform2dot + + + callgraph:transform2dot->callgraph:transform2dot + + + + inspect2graphml:get-graphml - + inspect2graphml:get-graphml + + + inspect2graphml:main->inspect2graphml:get-graphml + + - + inspect2graphml:get-xqms - + inspect2graphml:get-xqms - + inspect2graphml:get-graphml->inspect2graphml:get-xqms - + inspect2graphml:transform - + inspect2graphml:transform - + inspect2graphml:get-graphml->inspect2graphml:transform - + local:sort-edges-and-nodes - + local:sort-edges-and-nodes - + inspect2graphml:get-graphml->local:sort-edges-and-nodes - - - inspect2graphml:main - - inspect2graphml:main - - - inspect2graphml:main->inspect2graphml:get-graphml - - - + inspect2graphml:transform->inspect2graphml:transform - + local:make-node - + local:make-node - + inspect2graphml:transform->local:make-node - - - callgraph:clear-svg - - callgraph:clear-svg - - - callgraph:get-dot - - callgraph:get-dot - - - callgraph:get-dot->inspect2graphml:main - - - - - callgraph:get-svg - - callgraph:get-svg - - - callgraph:main - - callgraph:main - - - callgraph:main->callgraph:clear-svg - - - - - callgraph:main->callgraph:get-dot - - - - - callgraph:main->callgraph:get-svg - - \ No newline at end of file diff --git a/modules/callgraph/tests/callgraph-test.xq b/modules/callgraph/tests/callgraph-test.xq index 35b2060..e5bcc0a 100644 --- a/modules/callgraph/tests/callgraph-test.xq +++ b/modules/callgraph/tests/callgraph-test.xq @@ -35,6 +35,48 @@ declare }; +declare + %test:name("Test DOT output from graphml:graphml") + %test:args("") + %test:assertEquals("digraph g {", "}") + function callgraph-test:transform2dot-001($element as element()) { + callgraph:transform2dot($element) +}; + + +declare + %test:name("Test DOT output from graphml:graph") + %test:args("") + %test:assertEmpty + + %test:args("") + %test:assertEquals("node [shape=box, style=filled, color=""", "#90b0d4", """];") + function callgraph-test:transform2dot-002($element as element()) { + callgraph:transform2dot($element) +}; + + +declare + %test:name("Test DOT output from graphml:node") + %test:args("") + %test:assertEquals("node [shape=box, style=filled, color=""", "#90b0d4", """];", """", "some-function", """ [shape=box];") + + %test:args("") + %test:assertEmpty + function callgraph-test:transform2dot-003($element as element()) { + callgraph:transform2dot($element) +}; + + +declare + %test:name("Test DOT output from graphml:edge") + %test:args("") + %test:assertEquals("""", "some-function", """", " -> ", """", "another-function", """;") + function callgraph-test:transform2dot-004($element as element()) { + callgraph:transform2dot($element) +}; + + declare %test:name("Testing DOT ouput for a single module") %test:args("/db/apps/sade/modules/callgraph/tests/xqm/inspect2graphml-testmodule.xqm") -- GitLab From b53465ce68f4760362ada0d07b387fe15e272039 Mon Sep 17 00:00:00 2001 From: mrodzis Date: Thu, 13 Dec 2018 15:32:38 +0100 Subject: [PATCH 29/29] Move tests to test.xq --- test.xq | 11 ++++++++++- test.xqm | 14 -------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/test.xq b/test.xq index d9d5568..93e218b 100644 --- a/test.xq +++ b/test.xq @@ -2,4 +2,13 @@ xquery version "3.1"; import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql"; import module namespace tests="https://sade.textgrid.de/ns/tests" at "test.xqm"; -test:suite(util:list-functions("https://sade.textgrid.de/ns/tests")) +(: callgraph :) +import module namespace callgraph-test = "https://sade.textgrid.de/ns/callgraph-test" at "modules/callgraph/tests/callgraph-test.xq"; +import module namespace inspect2graphml-test = "https://sade.textgrid.de/ns/inspect2graphml-test" at "modules/callgraph/tests/inspect2graphml-test.xq"; + + +test:suite(util:list-functions("https://sade.textgrid.de/ns/tests")), + +(: * CALLGRAPH * :) +test:suite(util:list-functions("https://sade.textgrid.de/ns/callgraph-test")), +test:suite(util:list-functions("https://sade.textgrid.de/ns/inspect2graphml-test")) \ No newline at end of file diff --git a/test.xqm b/test.xqm index ab2e34e..fbf9a21 100644 --- a/test.xqm +++ b/test.xqm @@ -3,9 +3,7 @@ xquery version "3.1"; module namespace tests="https://sade.textgrid.de/ns/tests"; import module namespace app="https://sade.textgrid.de/ns/app" at "modules/app.xqm"; -import module namespace callgraph-test = "https://sade.textgrid.de/ns/callgraph-test" at "modules/callgraph/tests/callgraph-test.xq"; import module namespace config="https://sade.textgrid.de/ns/config" at "modules/config.xqm"; -import module namespace inspect2graphml-test = "https://sade.textgrid.de/ns/inspect2graphml-test" at "modules/callgraph/tests/inspect2graphml-test.xq"; import module namespace multiviewer="https://sade.textgrid.de/ns/multiviewer" at "modules/multiviewer.xqm"; import module namespace nav="https://sade.textgrid.de/ns/navigation" at "modules/navigation.xqm"; import module namespace tgconnect="https://sade.textgrid.de/ns/connect" at "modules/textgrid/connect.xqm"; @@ -179,15 +177,3 @@ return } }; - -(: ************* :) -(: * CALLGRAPH * :) -(: ************* :) - -declare function tests:callgraph-main() { - test:suite(util:list-functions("https://sade.textgrid.de/ns/callgraph-test")) -}; - -declare function tests:inspect2graphml-main() { - test:suite(util:list-functions("https://sade.textgrid.de/ns/inspect2graphml-test")) -}; \ No newline at end of file -- GitLab