mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			368 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			APL
		
	
	
	
	
	
			
		
		
	
	
			368 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			APL
		
	
	
	
	
	
| :NameSpace UT
 | ||
| 
 | ||
|     sac ← 0
 | ||
|     expect_orig ← expect ← ⎕NS⍬
 | ||
|     exception ← ⍬
 | ||
|     nexpect_orig ← nexpect ← ⎕NS⍬
 | ||
| 
 | ||
|     ∇ {Z}←{Conf}run Argument;PRE_test;POST_test;TEST_step;COVER_step;FromSpace
 | ||
|      
 | ||
|       load_display_if_not_already_loaded
 | ||
|       load_salt_scripts_into_current_namespace_if_configured
 | ||
|      
 | ||
|       FromSpace←1⊃⎕RSI
 | ||
|      
 | ||
|       PRE_test←{}
 | ||
|       POST_test←{}
 | ||
|       COVER_step←{}
 | ||
|       :If 0≠⎕NC'Conf'
 | ||
|           :If Conf has'cover_target'
 | ||
|               PRE_test←{{}⎕PROFILE'start'}
 | ||
|               POST_test←{{}⎕PROFILE'stop'}
 | ||
|           :EndIf
 | ||
|       :EndIf
 | ||
|      
 | ||
|       :If is_function Argument
 | ||
|           TEST_step←single_function_test_function
 | ||
|           COVER_file←Argument,'_coverage.html'
 | ||
|      
 | ||
|       :ElseIf is_list_of_functions Argument
 | ||
|           TEST_step←list_of_functions_test_function
 | ||
|           COVER_file←'list_coverage.html'
 | ||
|      
 | ||
|       :ElseIf is_file Argument
 | ||
|           TEST_step←file_test_function
 | ||
|           COVER_file←(get_file_name Argument),'_coverage.html'
 | ||
|      
 | ||
|       :ElseIf is_dir Argument
 | ||
|           test_files←test_files_in_dir Argument
 | ||
|           TEST_step←test_dir_function
 | ||
|           Argument←test_files
 | ||
|       :EndIf
 | ||
|      
 | ||
|       :If 0≠⎕NC'Conf'
 | ||
|           :If Conf has'cover_target'
 | ||
|               COVER_step←{Conf,←⊂('cover_file'COVER_file)
 | ||
|                   generate_coverage_page Conf}
 | ||
|           :EndIf
 | ||
|       :EndIf
 | ||
|      
 | ||
|       PRE_test ⍬
 | ||
|       Z←FromSpace TEST_step Argument
 | ||
|       POST_test ⍬
 | ||
|       COVER_step ⍬
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ load_display_if_not_already_loaded
 | ||
|       :If 0=⎕NC'#.DISPLAY'
 | ||
|           'DISPLAY'#.⎕CY'display'
 | ||
|       :EndIf
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ load_salt_scripts_into_current_namespace_if_configured
 | ||
|       :If 0≠⎕NC'#.UT.appdir'
 | ||
|           :If ⍬≢#.UT.appdir
 | ||
|               ⎕SE.SALT.Load #.UT.appdir,'src/*.dyalog -target=#'
 | ||
|               ⎕SE.SALT.Load #.UT.appdir,'test/*.dyalog -target=#'
 | ||
|           :EndIf
 | ||
|       :EndIf
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←FromSpace single_function_test_function TestName
 | ||
|       Z←run_ut FromSpace TestName
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←FromSpace list_of_functions_test_function ListOfNames;t
 | ||
|       t←⎕TS
 | ||
|       Z←run_ut¨{FromSpace ⍵}¨ListOfNames
 | ||
|       t←⎕TS-t
 | ||
|       ('Test execution report')print_passed_crashed_failed Z t
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←FromSpace file_test_function FilePath;FileNS;Functions;TestFunctions;t
 | ||
|       FileNS←⎕SE.SALT.Load FilePath,' -target=#'
 | ||
|       Functions←↓FileNS.⎕NL 3
 | ||
|       TestFunctions←(is_test¨Functions)/Functions
 | ||
|       :If (0/⍬,⊂0/'')≡TestFunctions
 | ||
|           ⎕←'No test functions found'
 | ||
|           Z←⍬
 | ||
|       :Else
 | ||
|           t←⎕TS
 | ||
|           Z←run_ut¨{FileNS ⍵}¨TestFunctions
 | ||
|           t←⎕TS-t
 | ||
|           (FilePath,' tests')print_passed_crashed_failed Z t
 | ||
|       :EndIf
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←FromSpace test_dir_function Test_files
 | ||
|       :If Test_files≡⍬/⍬,⊂''
 | ||
|           ⎕←'No test files found'
 | ||
|           Z←⍬
 | ||
|       :Else
 | ||
|           Z←#.UT.run¨Test_files
 | ||
|       :EndIf
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←get_file_name Argument;separator
 | ||
|       separator←⊃⌽(Argument∊'/\')/⍳⍴Argument
 | ||
|       Z←¯7↓separator↓Argument
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ generate_coverage_page Conf;ProfileData;CoverResults;HTML
 | ||
|       ProfileData←⎕PROFILE'data'
 | ||
|       ToCover←retrieve_coverables¨(⊃'cover_target'in Conf)
 | ||
|       :If (⍴ToCover)≡(⍴⊂1)
 | ||
|           ToCover←⊃ToCover
 | ||
|       :EndIf
 | ||
|       Representations←get_representation¨ToCover
 | ||
|       CoverResults←ProfileData∘generate_cover_result¨↓ToCover,[1.5]Representations
 | ||
|       HTML←generate_html CoverResults
 | ||
|       Conf write_html_to_page HTML
 | ||
|       ⎕PROFILE'clear'
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←retrieve_coverables Something;nc;functions
 | ||
|       nc←⎕NC Something
 | ||
|       :If nc=3
 | ||
|           Z←Something
 | ||
|       :ElseIf nc=9
 | ||
|           functions←strip¨↓⍎Something,'.⎕NL 3'
 | ||
|           Z←{(Something,'.',⍵)}¨functions
 | ||
|       :EndIf
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←strip input
 | ||
|       Z←(input≠' ')/input
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←get_representation Function;nc;rep
 | ||
|       nc←⎕NC⊂Function
 | ||
|       :If nc=3.1
 | ||
|           rep←↓⎕CR Function
 | ||
|           rep[1]←⊂'∇',⊃rep[1]
 | ||
|           rep,←⊂'∇'
 | ||
|           rep←↑rep
 | ||
|       :Else
 | ||
|           rep←⎕CR Function
 | ||
|       :EndIf
 | ||
|       Z←rep
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←ProfileData generate_cover_result(name representation);Indices;lines;functionlines;covered_lines
 | ||
|       Indices←({name≡⍵}¨ProfileData[;1])/⍳⍴ProfileData[;1]
 | ||
|       lines←ProfileData[Indices;2]
 | ||
|       nc←⎕NC⊂name
 | ||
|       :If 3.1=nc
 | ||
|           functionlines←¯2+⍴↓representation
 | ||
|       :Else
 | ||
|           functionlines←⊃⍴↓representation
 | ||
|       :EndIf
 | ||
|       covered_lines←(⍬∘≢¨lines)/lines
 | ||
|       Z←(nc lines functionlines covered_lines representation)
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←generate_html CoverResults;Covered;Total;Percentage;CoverageText;ColorizedCode;Timestamp;Page
 | ||
|       Covered←⊃⊃+/{⍴4⊃⍵}¨CoverResults
 | ||
|       Total←⊃⊃+/{3⊃⍵}¨CoverResults
 | ||
|       Percentage←100×Covered÷Total
 | ||
|       CoverageText←'Coverage: ',Percentage,'% (',Covered,'/',Total,')'
 | ||
|       ColorizedCode←⊃,/{colorize_code_by_coverage ⍵}¨CoverResults
 | ||
|       Timestamp←generate_timestamp_text
 | ||
|       Page←⍬
 | ||
|       Page,←⊂⍬,'<html>'
 | ||
|       Page,←⊂⍬,'<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>'
 | ||
|       Page,←⊂⍬,'<style>pre cov {line-height:80%;}'
 | ||
|       Page,←⊂⍬,'pre cov {color: green;}'
 | ||
|       Page,←⊂⍬,'pre uncov {line-height:80%;}'
 | ||
|       Page,←⊂⍬,'pre uncov {color:red;}</style>'
 | ||
|       Page,←⊂⍬,CoverageText
 | ||
|       Page,←⊂⍬,'<pre>'
 | ||
|       Page,←ColorizedCode
 | ||
|       Page,←⊂⍬,'</pre>'
 | ||
|       Page,←Timestamp
 | ||
|       Page,←⊂⍬,'</html>'
 | ||
|       Z←Page
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←colorize_code_by_coverage CoverResult;Colors;Ends;Code
 | ||
|       :If 3.1=⊃CoverResult
 | ||
|           Colors←(2+3⊃CoverResult)⍴⊂'<uncov>'
 | ||
|           Colors[1]←⊂''
 | ||
|           Colors[⍴Colors]←⊂''
 | ||
|           Ends←(2+3⊃CoverResult)⍴⊂'</uncov>'
 | ||
|           Ends[1]←⊂''
 | ||
|           Ends[⍴Ends]←⊂''
 | ||
|       :Else
 | ||
|           Colors←(3⊃CoverResult)⍴⊂'<uncov>'
 | ||
|           Ends←(3⊃CoverResult)⍴⊂'</uncov>'
 | ||
|       :EndIf
 | ||
|       Colors[1+4⊃CoverResult]←⊂'<cov>'
 | ||
|       Ends[1+4⊃CoverResult]←⊂'</cov>'
 | ||
|       Code←↓5⊃CoverResult
 | ||
|       Z←Colors,[1.5]Code
 | ||
|       Z←{⍺,(⎕UCS 13),⍵}/Z,Ends
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←generate_timestamp_text;TS;YYMMDD;HHMMSS
 | ||
|       TS←⎕TS
 | ||
|       YYMMDD←⊃{⍺,'-',⍵}/3↑TS
 | ||
|       HHMMSS←⊃{⍺,':',⍵}/3↑3↓TS
 | ||
|       Z←'Page generated: ',YYMMDD,'|',HHMMSS
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Conf write_html_to_page Page;tie;filename
 | ||
|       filename←(⊃'cover_out'in Conf),(⊃'cover_file'in Conf)
 | ||
|       :Trap 22
 | ||
|           tie←filename ⎕NTIE 0
 | ||
|           filename ⎕NERASE tie
 | ||
|           filename ⎕NCREATE tie
 | ||
|       :Else
 | ||
|           tie←filename ⎕NCREATE 0
 | ||
|       :EndTrap
 | ||
|       Simple_array←⍕⊃,/Page
 | ||
|       (⎕UCS'UTF-8'⎕UCS Simple_array)⎕NAPPEND tie
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←is_function Argument
 | ||
|       Z←'_TEST'≡¯5↑Argument
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←is_list_of_functions Argument
 | ||
|       Z←2=≡Argument
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←is_file Argument
 | ||
|       Z←'.dyalog'≡¯7↑Argument
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←is_dir Argument;attr
 | ||
|       :If 'Linux'≡5↑⊃'.'⎕WG'APLVersion'
 | ||
|           Z←'yes'≡⊃⎕CMD'test -d ',Argument,' && echo yes || echo no'
 | ||
|       :Else
 | ||
|           'gfa'⎕NA'I kernel32|GetFileAttributes* <0t'
 | ||
|           :If Z←¯1≠attr←gfa⊂Argument ⍝ If file exists
 | ||
|               Z←⊃2 16⊤attr           ⍝ Return bit 4
 | ||
|           :EndIf
 | ||
|       :EndIf
 | ||
|     ∇
 | ||
| 
 | ||
| 
 | ||
|     ∇ Z←test_files_in_dir Argument
 | ||
|       :If 'Linux'≡5↑⊃'.'⎕WG'APLVersion'
 | ||
|           Z←⎕SH'find ',Argument,' -name \*_tests.dyalog'
 | ||
|       :Else
 | ||
|           #.⎕CY'files'
 | ||
|           Z←#.Files.Dir Argument,'\*_tests.dyalog'
 | ||
|           Z←(Argument,'\')∘,¨Z
 | ||
|       :EndIf
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←run_ut ut_data;returned;crashed;pass;crash;fail;message
 | ||
|       (returned crashed time)←execute_function ut_data
 | ||
|       (pass crash fail)←determine_pass_crash_or_fail returned crashed
 | ||
|       message←determine_message pass fail crashed(2⊃ut_data)returned time
 | ||
|       print_message_to_screen message
 | ||
|       Z←(pass crash fail)
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←execute_function ut_data;function;t
 | ||
|       reset_UT_globals
 | ||
|       function←(⍕(⊃ut_data[1])),'.',⊃ut_data[2]
 | ||
|       :Trap sac
 | ||
|           :If 3.2≡⎕NC⊂function
 | ||
|               t←⎕TS
 | ||
|               Z←(⍎function,' ⍬')0
 | ||
|               t←⎕TS-t
 | ||
|           :Else
 | ||
|               t←⎕TS
 | ||
|               Z←(⍎function)0
 | ||
|               t←⎕TS-t
 | ||
|           :EndIf
 | ||
|      
 | ||
|       :Else
 | ||
|           Z←(↑⎕DM)1
 | ||
|           :If exception≢⍬
 | ||
|               expect←exception
 | ||
|               Z[2]←0
 | ||
|               t←⎕TS-t
 | ||
|           :EndIf
 | ||
|       :EndTrap
 | ||
|       Z,←⊂t
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ reset_UT_globals
 | ||
|       expect_orig ← expect← ⎕NS⍬
 | ||
|       exception←⍬
 | ||
|       nexpect_orig ← nexpect← ⎕NS⍬
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←is_test FunctionName;wsIndex
 | ||
|       wsIndex←FunctionName⍳' '
 | ||
|       FunctionName←(wsIndex-1)↑FunctionName
 | ||
|       Z←'_TEST'≡¯5↑FunctionName
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Heading print_passed_crashed_failed(ArrayRes time)
 | ||
|       ⎕←'-----------------------------------------'
 | ||
|       ⎕←Heading
 | ||
|       ⎕←'    ⍋  Passed: ',+/{1⊃⍵}¨ArrayRes
 | ||
|       ⎕←'    ⍟ Crashed: ',+/{2⊃⍵}¨ArrayRes
 | ||
|       ⎕←'    ⍒  Failed: ',+/{3⊃⍵}¨ArrayRes
 | ||
|       ⎕←'    ○ Runtime: ',time[5],'m',time[6],'s',time[7],'ms'
 | ||
|     ∇
 | ||
|     
 | ||
|     determine_pass_crash_or_fail←{
 | ||
|       r c←⍵ ⋄ 0≠c:0 1 0 ⋄ z←(0 0 1)(1 0 0)
 | ||
|       expect_orig≢expect:(⎕IO+expect≡r)⊃z ⋄ (⎕IO+nexpect≢r)⊃z
 | ||
|     }
 | ||
| 
 | ||
|     ∇ Z←determine_message(pass fail crashed name returned time)
 | ||
|       :If crashed
 | ||
|           Z←'CRASHED: 'failure_message name returned
 | ||
|       :ElseIf pass
 | ||
|           Z←'Passed ',time[5],'m',time[6],'s',time[7],'ms'
 | ||
|       :Else
 | ||
|           Z←'FAILED: 'failure_message name returned
 | ||
|       :EndIf
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ print_message_to_screen message
 | ||
|       ⎕←message
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←term_to_text Term;Text;Rows
 | ||
|       Text←#.DISPLAY Term
 | ||
|       Rows←1⊃⍴Text
 | ||
|       Z←(Rows 4⍴''),Text
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←Cause failure_message(name returned);hdr;exp;expterm;got;gotterm
 | ||
|       hdr←Cause,name
 | ||
|       exp←'Expected'
 | ||
|       expterm←term_to_text #.UT.expect
 | ||
|       got←'Got'
 | ||
|       gotterm←term_to_text returned
 | ||
|       Z←align_and_join_message_parts hdr exp expterm got gotterm
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←align_and_join_message_parts Parts;hdr;exp;expterm;got;gotterm;R1;C1;R2;C2;W
 | ||
|       (hdr exp expterm got gotterm)←Parts
 | ||
|       (R1 C1)←⍴expterm
 | ||
|       (R2 C2)←⍴gotterm
 | ||
|       W←⊃⊃⌈/C1 C2(⍴hdr)(⍴exp)(⍴got)
 | ||
|       Z←(W↑hdr),[0.5](W↑exp)
 | ||
|       Z←Z⍪(R1 W↑expterm)
 | ||
|       Z←Z⍪(W↑got)
 | ||
|       Z←Z⍪(R2 W↑gotterm)
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←confparam in config
 | ||
|       Z←1↓⊃({confparam≡⊃⍵}¨config)/config
 | ||
|     ∇
 | ||
| 
 | ||
|     ∇ Z←config has confparam
 | ||
|       Z←∨/{confparam≡⊃⍵}¨config
 | ||
|     ∇
 | ||
| 
 | ||
| :EndNameSpace
 |