@@ -70,49 +70,69 @@ declare private function cover:_task-cancel-safe(
7070 try {
7171 (:TODO is this a good idea, or a bad idea??:)
7272 for $breakpoint in dbg:breakpoints ($id) return dbg:clear ($id, $breakpoint),
73- xdmp:request-cancel (xdmp:host (), xdmp:server ("TaskServer" ), $id) }
73+ dbg:detach ($id),
74+ if (fn:empty (dbg:wait ($id, 10 ))) then
75+ fn:error (xs:QName ("FAILED-TO-CANCEL" ), "unable to cancel a debugging request" )
76+ else ()
77+ }
7478 catch ($ex) {
7579 if ($ex/error:code eq 'XDMP-NOREQUEST' ) then ()
76- else xdmp:rethrow () }
80+ else xdmp:rethrow ()
81+ }
7782};
7883
84+ (:
85+ : @param $request the ID of a debug request
86+ : @param $uri URI of a module whose coverage we are observing
87+ : @param $limit maximum number of lines we'll try to observe
88+ : @param $results-map map:map containing line numbers
89+ :)
7990declare private function cover:_prepare-from-request (
8091 $request as xs:unsignedLong,
8192 $uri as xs:string,
8293 $limit as xs:integer,
8394 $results-map as map:map)
8495{
85- helper:log (text {'cover:_prepare-from-request' , ('request' , $request, 'module' , $uri)}),
8696 try {
87- let $lines-map := map:get ($results-map, $uri)[2 ]
88- (: Semi-infinite loop, to be broken using DBG-LINE.
89- : This avoids stack overflow errors.
90- :)
91- for $line in 1 to $limit
92- (: We only need to break once per line, but we set a breakpoint
93- : on every expression to maximize the odds of seeing that line.
94- : But dbg:line will return the same expression more than once,
95- : at the start of a module or when it sees an expression
96- : that covers multiple lines. So we call dbg:expr for the right info.
97- : Faster to loop once and call dbg:expr many extra times,
98- : or gather all unique expr-ids and then loop again?
99- : Because of the loop-break technique, one loop is easier.
100- :)
101- for $expr-id in dbg:line ($request, $uri, $line)
102- let $set := dbg:break ($request, $expr-id)
103- let $expr := dbg:expr ($request, $expr-id)
104- let $key := $expr/dbg:line/fn:string ()
105- where fn:not (map:get ($lines-map, $key))
106- return cover:_put ($lines-map, $key),
97+ let $wanted-lines-map := map:get ($results-map, $uri)[2 ]
98+ return
99+ if (fn:count (map:keys ($wanted-lines-map)) > 0 ) then
100+ (: We've already gathered information on these lines :)
101+ ()
102+ else (
103+ helper:log (text {'cover:_prepare-from-request' , ('request' , $request, 'module' , $uri)}),
104+ (: Semi-infinite loop, to be broken using DBG-LINE.
105+ : This avoids stack overflow errors.
106+ :)
107+ for $line in 1 to $limit
108+ (: We only need to break once per line, but we set a breakpoint
109+ : on every expression to maximize the odds of seeing that line.
110+ : But dbg:line will return the same expression more than once,
111+ : at the start of a module or when it sees an expression
112+ : that covers multiple lines. So we call dbg:expr for the right info.
113+ : Faster to loop once and call dbg:expr many extra times,
114+ : or gather all unique expr-ids and then loop again?
115+ : Because of the loop-break technique, one loop is easier.
116+ :)
117+ for $expr-id in dbg:line ($request, $uri, $line)
118+ let $set := dbg:break ($request, $expr-id)
119+ let $expr := dbg:expr ($request, $expr-id)
120+ let $key := $expr/dbg:line/fn:string ()
121+ where fn:not (map:get ($wanted-lines-map, $key))
122+ return cover:_put ($wanted-lines-map, $key),
107123
108- (: We should always hit EOF and DBG-LINE before this.
109- : Tell the caller that we could not do it.
110- :)
111- cover:_task-cancel-safe ($request),
112- fn:error ((), 'UNIT-TEST-TOOBIG' , ('Module is too large for code coverage limit:' , $limit))
124+ (: We should always hit EOF and DBG-LINE before this.
125+ : Tell the caller that we could not do it.
126+ :)
127+ cover:_task-cancel-safe ($request),
128+ fn:error ((), 'UNIT-TEST-TOOBIG' , ('Module is too large for code coverage limit:' , $limit))
129+ )
113130 } catch ($ex) {
114131 if ($ex/error:code = "DBG-LINE" ) then ()
115- else if ($ex/error:code = ("DBG-MODULEDNE" , "DBG-REQUESTRECORD" , "XDMP-MODNOTFOUND" )) then
132+ else if ($ex/error:code = "DBG-MODULEDNE" ) then
133+ (: Modules are not visible to this request unless they are used by the initiating main module. :)
134+ ()
135+ else if ($ex/error:code = ("DBG-REQUESTRECORD" , "XDMP-MODNOTFOUND" )) then
116136 helper:log ("Error executing " || $uri || " " || ($ex/*:code))
117137 else
118138 (
@@ -125,6 +145,10 @@ declare private function cover:_prepare-from-request(
125145
126146(:~
127147 : This function prepares code coverage information for the specified modules.
148+ :
149+ : @return map:map where the keys are module URIs and the values are a pair of maps. The first map's keys are the
150+ : lines that have code coverage (empty after this function); the second's keys are the lines that
151+ : we want to have covered.
128152 :)
129153declare private function cover:_prepare (
130154 $coverage-modules as xs:string+,
@@ -226,7 +250,8 @@ declare function cover:results(
226250(:~
227251 : Return a list of the XQuery modules eligible for code coverage.
228252:)
229- declare function list-coverage-modules () as xs:string* {
253+ declare function list-coverage-modules () as xs:string*
254+ {
230255 let $database-id as xs:unsignedLong := xdmp:modules-database ()
231256 let $modules-root as xs:string := xdmp:modules-root ()
232257 let $module-extensions as xs:string* := (".xqy" , ".xqe" , ".xq" , ".xquery" )
@@ -433,4 +458,4 @@ declare function cover:module-view(
433458 }
434459 return
435460 cover:module-view ($module, $format, $source, cover:_map-from-sequence ($wanted), cover:_map-from-sequence ($covered))
436- };
461+ };
0 commit comments