Coverage Report

Watched: 14 fns/opr within #.CommTools.CommTools

The test suite was executed once:

Executed atAPLVersionMemory (MB)
2024-08-04 10:34:35Windows-64 ⋄ 19.0.49376.0 ⋄ W ⋄ Development ⋄ Unicode113

Overall 90% of the testable code is covered.

(Comment lines, empty lines, all :End* lines etc. are ignored)

7 of the fns/opr are 100% covered.

Function/OperatorLines not executedCoverage
#.CommTools.CommTools.Copyright101
#.CommTools.CommTools.Help101
#.CommTools.CommTools.Pause4←≢21,31-338324
#.CommTools.CommTools.AskForNumber7←≢10-11,53-55,59,648546
#.CommTools.CommTools.AskForText4←≢10-11,39,528938
#.CommTools.CommTools.Select6←≢14-15,56-57,59-609380
#.CommTools.CommTools.YesOrNo5←≢12-13,26,67,709370
#.CommTools.CommTools.Assert1000
#.CommTools.CommTools.Cleanup1005
#.CommTools.CommTools.ErrNo1001
#.CommTools.CommTools.LF1001
#.CommTools.CommTools.Public1008
#.CommTools.CommTools.ReplaceCRbyLF1000
#.CommTools.CommTools.Version1001

Listings

#.CommTools.CommTools.Copyright — 0%
r←Copyright →[1] r←'Copyright by Kai Jaeger ⋄ https://kai-jaeger.de ⋄ kai@aplteam.com'
#.CommTools.CommTools.Help — 0%
Help →[1] ⎕SE.UCMD'ADOC ',⍕⎕THIS
#.CommTools.CommTools.Pause — 83%
{flag}←{lineFlag}Pause msg [1] ⍝ Prints `msg` to he session and tells the user that she must press <enter> if she wants to continue. [2] ⍝ By entering "`∘∘∘`" the user may interrupt `Pause`: this activates a stop.\\ [3] ⍝ The optional left argument `lineFlag` defaults to 0. If it's 1 then a line is printed. The length [4] ⍝ is defined by `⎕PW-1`.\\ [5] ⍝ You can prevent `Pause` from displaying the message and requiring the user to press <enter>, [6] ⍝ refer to the documentation with ]ADoc CommTools\\ [7] ⍝ The function will return 1 in case it did present the message and stopped, and 0 otherwise. [8] lineFlag←{0=⎕NC ⍵:0 ⋄ ⍎⍵}'lineFlag' [9] msg←⊃LF{⍺,⍺⍺,⍵}/⊆msg [10] msg←ReplaceCRbyLF msg [11] flag←1 [12] :If AliasChar∊msg [13] :If 0<⎕NC'NoPause' [14] (alias msg)←{l←⍵⍳AliasChar ⋄ (l↑⍵)(l↓⍵)}msg [15] flag←~∨/({⍵↑⍨⍵⍳AliasChar}¨⊆NoPause)≡¨⊂alias [16] :EndIf [17] :Else [18] :If 0<⎕NC'NoPause' [19] :If NoPause≡1 [20] :OrIf ∨/(⊆NoPause)∊⊆msg →[21] :OrIf ∨/(NoPause/⍨~AliasChar∊¨NoPause){⍺≡¨(≢¨⍺)↑¨(≢⍺)⍴⊂⍵}{⍵↑⍨¯1+⍵⍳LF}msg [22] flag←0 [23] :EndIf [24] :EndIf [25] :EndIf [26] :If flag [27] :If lineFlag [28] ⍞←((⎕PW-1)⍴'─'),LF [29] :EndIf [30] :If AliasChar∊msg →[31] ind←msg⍳AliasChar →[32] :AndIf ∧/~(ind↑msg)∊' ',LF →[33] msg←ind↓msg [34] :EndIf [35] input←⍞,0/⍞←({0=≢⍵:⍵ ⋄ ⍵,LF}msg),'In order to continue press <enter> ' [36] :If '∘∘∘'≡¯3↑input [37] (1+⊃⎕LC)⎕STOP⊃⎕SI [38] ∘∘∘ ⍝ Deliberate stop caused by user input [39] :EndIf [40] :EndIf [41] ⍝Done
#.CommTools.CommTools.AskForNumber — 85%
value←{enforce}(CheckFn AskForNumber)question [1] ⍝ Operator asking a question and allowing the user to enter a number.\\ [2] ⍝ By entering "`∘∘∘`" the user may interrupt `AskForNumber`: this activates a stop.\\ [3] ⍝ `CheckFn` is supposed to be a function that gets the input as `⍵` and must return a Boolean [4] ⍝ with a 1 indicating that the input is okay and 0 that it is not. If you don't need/want [5] ⍝ a check function pass `{1}` as left operand.\\ [6] ⍝ If the user refuses to enter a number an empty vector is returned. [7] ⍝ However, you might prevent this from happening by specifying a 1 as `⍺` (`enforce`), meaning that [8] ⍝ the user must enter a number in order to continue. [9] :If '?'≡question →[10] value←(⍕⎕THIS),'.AskForNumber_Answers←1 2⍴'' '' '' ''' →[11] :Return [12] :EndIf [13] enforce←{0<⎕NC ⍵:⍎⍵ ⋄ 0}'enforce' [14] value←⍬ [15] success←flag←0 [16] :If ~(≡question)∊0 1 [17] question←1↓⊃,/LF,¨question [18] :EndIf [19] question←ReplaceCRbyLF question [20] question←{⍵↓⍨+/∧\' '=⍵}question [21] :Repeat [22] firstPart←{⍵↑⍨⍵⍳LF}question [23] :If 0<⎕NC'AskForNumber_Answers' [24] AskForNumber_Answers←(0<≢¨' '~⍨¨AskForNumber_Answers[;1])⌿AskForNumber_Answers [25] AskForNumber_Answers[;1]←{⍵↓⍨+/∧\' '=⍵}¨AskForNumber_Answers[;1] [26] :AndIf 0<≢AskForNumber_Answers [27] :If AliasChar∊firstPart [28] ind←firstPart⍳AliasChar [29] :AndIf ∧/~(LF,' ')∊ind↑question [30] (alias question)←ind{(⍺↑⍵)(⍺↓⍵)}firstPart [31] flag←0<+/bool←({⍵↑⍨⍵⍳AliasChar}¨AskForNumber_Answers[;1])≡¨⊂alias [32] :ElseIf ~flag←0<+/bool←AskForNumber_Answers[;1]≡¨⊂firstPart [33] flag←0<+/bool←firstPart∘{⍵≡(≢⍵)↑⍺}¨AskForNumber_Answers[;1] [34] :EndIf [35] :If flag [36] 'Multiple pre-prepared answers qualify?!'Assert 1=+/bool [37] input←⍕2⊃AskForNumber_Answers[bool⍳1;] [38] :EndIf [39] :Else [40] :If (⌊/firstPart⍳' ',LF)>firstPart⍳AliasChar [41] question←{~AliasChar∊⍵:⍵ ⋄ ⍵↓⍨⍵⍳AliasChar}question [42] :EndIf [43] :EndIf [44] :If ~flag [45] input←⍞,0/⍞←question,': ' [46] :If '∘∘∘'≡¯3↑input [47] (1+⊃⎕LC)⎕STOP⊃⎕SI [48] ∘∘∘ ⍝ Deliberate stop caused by user input [49] :EndIf [50] input←{⍵↑⍨1+-(⌽⍵)⍳':'}input [51] :EndIf [52] :If 0=≢input~' ' →[53] :AndIf ~enforce →[54] value←⍬ →[55] :Return [56] :Else [57] (valid value)←⎕VFI input [58] :If 1≠≢valid →[59] ⎕←'Please enter precisely one number' [60] :ElseIf valid [61] success←CheckFn value [62] value←⊃value [63] :Else →[64] ⎕←'You did not enter a valid number, please retry!' [65] :EndIf [66] :EndIf [67] :Until success [68] ⍝Done
#.CommTools.CommTools.AskForText — 89%
text←{enforce}(CheckFn AskForText)question [1] ⍝ Operator asking a question and allowing the user to enter text.\\ [2] ⍝ By entering "`∘∘∘`" the user may interrupt `AskForText`: this activates a stop.\\ [3] ⍝ `CheckFn` is supposed to be a function that gets the input as `⍵` and must return a Boolean [4] ⍝ with a 1 indicating that the input is okay and 0 that it is not. If you don't need/want [5] ⍝ a check function pass `{1}` as left operand.\\ [6] ⍝ If the user refuses to enter anything an empty vector is returned. [7] ⍝ However, you might prevent this from happening by specifying a 1 as `⍺` (`enforce`), meaning that [8] ⍝ the user must enter something in order to continue. [9] :If '?'≡question →[10] text←(⍕⎕THIS),'.AskForText_Answers←1 2⍴'' '' '' ''' →[11] :Return [12] :EndIf [13] enforce←{0<⎕NC ⍵:⍎⍵ ⋄ 0}'enforce' [14] text←'' [15] success←flag←0 [16] :If ~(≡question)∊0 1 [17] question←1↓⊃,/LF,¨question [18] :EndIf [19] question←ReplaceCRbyLF question [20] question←{⍵↓⍨+/∧\' '=⍵}question [21] :Repeat [22] firstPart←{⍵↑⍨⍵⍳LF}question [23] :If 0<⎕NC'AskForText_Answers' [24] AskForText_Answers←(0<≢¨' '~⍨¨AskForText_Answers[;1])⌿AskForText_Answers [25] AskForText_Answers[;1]←{⍵↓⍨+/∧\' '=⍵}¨AskForText_Answers[;1] [26] :AndIf 0<≢AskForText_Answers [27] :If AliasChar∊question [28] (alias question)←{l←⍵⍳AliasChar ⋄ (l↑⍵)(l↓⍵)}question [29] flag←0<+/bool←({⍵↑⍨⍵⍳AliasChar}¨AskForText_Answers[;1])≡¨⊂alias [30] :ElseIf ~flag←0<+/bool←AskForText_Answers[;1]≡¨⊂question [31] flag←0<+/bool←question∘{⍵≡(≢⍵)↑⍺}¨AskForText_Answers[;1] [32] :EndIf [33] :If flag [34] 'Multiple pre-prepared answers qualify?!'Assert 1=+/bool [35] text←2⊃AskForText_Answers[bool⍳1;] [36] :EndIf [37] :Else [38] :If (⌊/firstPart⍳' ',LF)>firstPart⍳AliasChar →[39] question←{~AliasChar∊⍵:⍵ ⋄ ⍵↓⍨⍵⍳AliasChar}question [40] :EndIf [41] :EndIf [42] :If ~flag [43] text←⍞,0/⍞←question,': ' [44] :If '∘∘∘'≡¯3↑text [45] (1+⊃⎕LC)⎕STOP⊃⎕SI [46] ∘∘∘ ⍝ Deliberate stop caused by user input [47] :EndIf [48] text←(≢{⍵↑⍨-¯1+(⌽⍵)⍳LF}question,': ')↓text [49] :EndIf [50] :If 0=≢text [51] :If enforce →[52] ⎕←'You must enter something!' [53] :Else [54] :Return [55] :EndIf [56] :Else [57] success←CheckFn text [58] :EndIf [59] :Until success [60] ⍝Done
#.CommTools.CommTools.Select — 93%
index←{x}Select choices [1] ⍝ Presents `choices` as a numbered list and allows the user to select either exactly one or multiple ones. [2] ⍝ Selecting just one is the default.\\ [3] ⍝ The optional left argument allows you to specify multiple (positional) choices: [4] ⍝ * `caption` is shown above the choices; must be a simple character vector [5] ⍝ * `manyFlag` defaults to 0 (meaning just one item might be selected) or 1, in which case multiple items can be selected [6] ⍝ * `mustFlag` forces the user to select at least one option\\ [7] ⍝ Notes: [8] ⍝ * `choices` must not have more than 999 items\\ [9] ⍝ * By entering "`∘∘∘`" the user may interrupt `Select` by running onto a stop vector, overcoming the bug that ⍞ cannot be interrupted [10] ⍝ * If the user aborts by entering "q" (for "quit") `⍬` will be returned [11] ⍝ You can make `Select` select none, one or several choices automatically, refer to the documentation [12] ⍝ with ]ADoc CommTools\\ [13] :If '?'≡choices →[14] index←(⍕⎕THIS),'.Select_Choices←1 2⍴'' '' '' ''' →[15] :Return [16] :EndIf [17] x←{0<⎕NC ⍵:⊆⍎⍵ ⋄ ''}'x' [18] (caption manyFlag mustFlag)←x,(⍴,x)↓'' 0 0 [19] '"caption" must be a simple character vector'Assert 1=≡caption←,caption [20] '"caption" must not contain line feeds (⎕UCS 10)'Assert~LF∊caption [21] '"caption" must not contain carriage returns (⎕UCS 13)'Assert~(⎕UCS 13)∊caption [22] ⎕IO←1 ⋄ ⎕ML←1 [23] 'Invalid right argument; must be a vector of text vectors.'⎕SIGNAL ErrNo/⍨2≠|≡choices [24] 'Right argument has more than 999 items'⎕SIGNAL ErrNo/⍨999<≢choices [25] flag←0 [26] firstPart←{⍵↑⍨⍵⍳LF}caption [27] :If 0<⎕NC'Select_Choices' [28] Select_Choices←(0<≢¨Select_Choices[;1])⌿Select_Choices [29] :AndIf 0<≢Select_Choices [30] :If AliasChar∊caption [31] (alias caption)←{l←⍵⍳AliasChar ⋄ (l↑⍵)(l↓⍵)}caption [32] flag←0<+/bool←({⍵↑⍨(,⍵)⍳AliasChar}¨Select_Choices[;1])≡¨⊂alias [33] :Else [34] :If 0=+/bool←Select_Choices[;1]≡¨⊂caption [35] bool←caption∘{⍵≡⍺↑⍨≢⍵}¨Select_Choices[;1] [36] :EndIf [37] flag←0<+/bool [38] :EndIf [39] :If flag [40] 'Multiple choices qualify?!'Assert 1=+/bool [41] index←2⊃Select_Choices[bool⍳1;] [42] :If (⊂index)∊0 ⍬ [43] index←⍬ [44] :ElseIf ' '=1↑0⍴∊index ⍝ Text?! [45] :If '*'=¯1↑index [46] index←((¯1+≢index)↑¨{⍵↓⍨+/∧\' '=⍵}¨choices)⍳⊂(¯1↓index) [47] 'Invalid selection'Assert index∊⍳≢choices [48] :ElseIf '*'=1↑index [49] index←((-¯1+≢index)↑¨{⍵↓⍨+/∧\' '=⍵}¨choices)⍳⊂(1↓index) [50] 'Invalid selection'Assert index∊⍳≢choices [51] :ElseIf (,'a')≡,index [52] index←⍳≢choices [53] :ElseIf (,'q')≡,index [54] index←⍬ [55] :ElseIf 0<≢buff←⍸index∘≡¨choices →[56] index←buff →[57] 'Invalid selection'Assert index∊⍳≢choices [58] :ElseIf 1=≢index←⍸index∘≡¨(≢index)↑¨{⍵↓⍨+/∧\' '=⍵}¨choices →[59] index←⊃index →[60] 'Invalid selection'Assert index∊⍳≢choices [61] :Else [62] 'Invalid selection'Assert 0 [63] :EndIf [64] :Else [65] 'Invalid selection'Assert∧/index∊⍳≢choices [66] :EndIf [67] :EndIf [68] :EndIf [69] :If ~flag [70] flag2←0 [71] :Repeat [72] blankFlag←0≠≢caption [73] :If AliasChar∊caption [74] :If (firstPart⍳' ')>firstPart⍳AliasChar [75] caption←{~AliasChar∊⍵:⍵ ⋄ ⍵↓⍨⍵⍳AliasChar}caption [76] :EndIf [77] :EndIf [78] ⎕←{⍵↑'---',(blankFlag/' '),caption,(blankFlag/' '),⍵⍴'-'}⎕PW-1 [79] ⎕←⍪{((⊂'. '),¨⍨(⊂3 0)⍕¨⍳≢⍵),¨⍵}choices [80] ⎕←'' [81] question←'Select one ',(manyFlag/'or more '),'item',((manyFlag)/'s'),' ' [82] question,←((manyFlag∨~mustFlag)/'('),((~mustFlag)/'q=quit'),((manyFlag∧~mustFlag)/', '),(manyFlag/'a=all'),((manyFlag∨~mustFlag)/')'),' :' [83] :If 0<≢answer←⍞,0/⍞←question [84] answer←(⍴question)↓answer [85] :If '∘∘∘'≡¯3↑answer [86] (1+⊃⎕LC)⎕STOP⊃⎕SI [87] ∘∘∘ ⍝ Deliberate stop caused by user input [88] :EndIf [89] :If 1=≢answer [90] :AndIf answer∊'Qq',manyFlag/'Aa' [91] :If answer∊'Qq' [92] :If 0=mustFlag [93] index←⍬ [94] flag2←1 [95] :EndIf [96] :Else [97] index←⍳≢choices [98] flag2←1 [99] :EndIf [100] :Else [101] (bool value)←⎕VFI answer [102] :If ∧/bool [103] :AndIf manyFlag∨1=+/bool [104] value←bool/value [105] :AndIf ∧/value∊⍳⍴choices [106] index←value [107] flag2←0≠≢index [108] :EndIf [109] :EndIf [110] :EndIf [111] :Until flag2 [112] index←{1<≢⍵:⍵ ⋄ ⊃⍵}⍣(⍬≢index)⊣index [113] :EndIf [114] ⍝Done
#.CommTools.CommTools.YesOrNo — 93%
yesOrNo←{default}YesOrNo question [1] ⍝ Asks a simple question and allows just "Y" (or "y") or "N" (or "n") as answers.\\ [2] ⍝ The question may be a simple character vector, possibly with `⎕UCS 10` in between, [3] ⍝ or a vector of simple character vectors.\\ [4] ⍝ You may specify a default via the optional left argument which when specified [5] ⍝ rules what happens when the user just presses <enter>. [6] ⍝ `default` must be either 1 (yes) or 0 (no).\\ [7] ⍝ By entering "`∘∘∘`" the user may interrupt `YesOrNo`: this activates a stop.\\ [8] ⍝ You can make `YesOrNo` answer the question automatically, refer to the documentation [9] ⍝ with ]ADoc CommTools\\ [10] ⍝ Note that this function does **not** work as intended when traced! [11] :If '?'≡question →[12] yesOrNo←(⍕⎕THIS),'.YesOrNo_Answers←0 2⍴'' ''' →[13] :Return [14] :EndIf [15] isOkay←0 [16] default←{0<⎕NC ⍵:⍎⍵ ⋄ ''}'default' [17] isOkay←0 [18] :If ~(≡question)∊0 1 [19] question←1↓⊃,/LF,¨question [20] :EndIf [21] question←ReplaceCRbyLF question [22] question←{⍵↓⍨+/∧\' '=⍵}question [23] :If 0≠≢default [24] 'Left argument must be a scalar'⎕SIGNAL 11/⍨1≠≢default [25] :AndIf ~default∊0 1 →[26] 'The left argument. if specified, must be a Boolean or empty'⎕SIGNAL 11 [27] :EndIf [28] flag←1 [29] firstPart←{⍵↑⍨⍵⍳LF}question [30] :If 0<⎕NC'YesOrNo_Answers' [31] YesOrNo_Answers←(0<≢¨' '~⍨¨YesOrNo_Answers[;1])⌿YesOrNo_Answers [32] :AndIf 0<≢YesOrNo_Answers [33] :If AliasChar∊firstPart [34] ind←firstPart⍳AliasChar [35] (alias question)←ind{(⍺↑⍵)(⍺↓⍵)}firstPart [36] flag←0<+/bool←({⍵↑⍨⍵⍳AliasChar}¨YesOrNo_Answers[;1])≡¨⊂alias [37] :ElseIf ~flag←0<+/bool←YesOrNo_Answers[;1]≡¨⊂question [38] :AndIf ~flag←0<+/bool←question∘{⍵≡(≢⍵)↑⍺}¨YesOrNo_Answers[;1] [39] :AndIf LF∊question [40] buff←{⍵↓⍨+/∧\' '=⍵}⊃¯1↑LF(≠⊆⊢)question [41] flag←0<+/bool←YesOrNo_Answers[;1]≡¨⊂buff [42] :EndIf [43] :If flag [44] 'Multiple pre-prepared answers qualify?!'Assert 1=+/bool [45] answer←2⊃YesOrNo_Answers[bool⍳1;] [46] :If 0=≢answer [47] yesOrNo←default [48] :Else [49] ('Invalid answer: ',answer)Assert answer∊'YyNn' [50] yesOrNo←answer∊'Yy' [51] :EndIf [52] :EndIf [53] :Else [54] flag←0 [55] :EndIf [56] :If ~flag [57] :If 0=≢default [58] add←' (y/n) ' [59] :Else [60] :If default [61] add←' (Y/n) ' [62] :Else [63] add←' (y/N) ' [64] :EndIf [65] :EndIf [66] :If 1<≡question →[67] question←1↓⊃,/LF,¨question [68] :EndIf [69] :If (⌊/firstPart⍳' ',LF)>firstPart⍳AliasChar →[70] question←{~AliasChar∊⍵:⍵ ⋄ ⍵↓⍨⍵⍳AliasChar}question,add [71] :Else [72] question,←add [73] :EndIf [74] :Repeat [75] ⎕←'' [76] ⍞←question [77] answer←⍞ [78] :If answer≡question ⍝ Did ... (since version 18.0 trailing blanks are not removed anymore) [79] :OrIf (≢answer)=¯1+≢question ⍝ ... the ... [80] :OrIf 0=≢answer ⍝ ... user ... [81] :OrIf question≡(-≢question)↑answer ⍝ ... just ... [82] dtb←{⍵↓⍨-+/∧\' '=⌽⍵} [83] answer2←dtb answer [84] :OrIf answer2≡((-≢answer2)↑LF{~⍺∊⍵:⍵ ⋄ ' ',dtb ⍺{⌽⍵↑⍨1+⍵⍳⍺}⌽⍵}question) ⍝ ... press ... [85] :OrIf answer≡{1↓⊃¯1↑(⍵=LF)⊂⍵}LF,question ⍝ ... <enter>? [86] :If 0≠≢default [87] yesOrNo←default [88] isOkay←1 [89] :EndIf [90] :Else [91] :If '∘∘∘'≡¯3↑answer [92] (1+⊃⎕LC)⎕STOP⊃⎕SI [93] ∘∘∘ ⍝ Deliberate stop caused by user input [94] :EndIf [95] answer←¯1↑{⍵↓⍨-+/∧\' '=⌽⍵}answer [96] :If answer∊'YyNn' [97] isOkay←1 [98] yesOrNo←answer∊'Yy' [99] :EndIf [100] :EndIf [101] :Until isOkay [102] :EndIf [103] ⍝Done
#.CommTools.CommTools.Assert — 100%
Assert←{⍺←'' ⋄ (,1)≡,⍵:r←1 ⋄ ⎕ML←1 ⋄ ⍺ ⎕SIGNAL 1↓(⊃∊⍵),11}
#.CommTools.CommTools.Cleanup — 100%
Cleanup [1] ⎕EX'Select_Choices' [2] ⎕EX'YesOrNo_Answers' [3] ⎕EX'NoPause' [4] ⎕EX'AskForNumber_Answers' [5] ⎕EX'AskForText_Answers'
#.CommTools.CommTools.ErrNo — 100%
r←ErrNo [1] r←811
#.CommTools.CommTools.LF — 100%
r←LF [1] r←⎕UCS 10
#.CommTools.CommTools.Public — 100%
r←Public [1] r←'' [2] r,←⊂'AskForText' [3] r,←⊂'AskForNumber' [4] r,←⊂'Select' [5] r,←⊂'YesOrNo' [6] r,←⊂'Pause' [7] r,←⊂'Cleanup' [8] r,←⊂'Help'
#.CommTools.CommTools.ReplaceCRbyLF — 100%
ReplaceCRbyLF←{LF@(⍸⍵=⎕UCS 13)⊣⍵}
#.CommTools.CommTools.Version — 100%
r←Version [1] ⍝ See also `History` [2] r←'CommTools' '1.7.1' '2023-11-04'