|
| 1 | +program main |
| 2 | + |
| 3 | +! for each set of command options, call this command recursively which will print the resulting parameters with a |
| 4 | +! given test command CMD from the TEST() array. |
| 5 | +! |
| 6 | +! Then read the expected values as a NAMELIST group from the test array and compare the expected |
| 7 | +! results with the actual results. |
| 8 | +! |
| 9 | +! the PARSE() subroutine is a copy of the app/main.f90 program except it creates and writes a NAMELIST file instead |
| 10 | +! of actually calling the subcommands. |
| 11 | +! |
| 12 | +! The program will exit with a non-zero status if any of the tests fail |
| 13 | + |
| 14 | +use, intrinsic :: iso_fortran_env, only : compiler_version, compiler_options |
| 15 | +implicit none |
| 16 | + |
| 17 | +! convenient arbitrary sizes for test |
| 18 | + |
| 19 | +! assuming no name over 15 characters to make output have shorter lines |
| 20 | +character(len=15),allocatable :: name(:),act_name(:) ; namelist/act_cli/act_name |
| 21 | +integer,parameter :: max_names=10 |
| 22 | + |
| 23 | +character(len=:),allocatable :: command |
| 24 | +character(len=:),allocatable :: cmd |
| 25 | +integer :: cstat, estat |
| 26 | +integer :: act_cstat, act_estat |
| 27 | +integer :: i, ios |
| 28 | +logical :: w_e,act_w_e ; namelist/act_cli/act_w_e |
| 29 | +logical :: w_t,act_w_t ; namelist/act_cli/act_w_t |
| 30 | + |
| 31 | +logical :: release,act_release ; namelist/act_cli/act_release |
| 32 | +character(len=:),allocatable :: args,act_args ; namelist/act_cli/act_args |
| 33 | +namelist/expected/cmd,cstat,estat,w_e,w_t,name,release,args |
| 34 | +integer :: lun |
| 35 | +logical,allocatable :: tally(:) |
| 36 | +logical,allocatable :: subtally(:) |
| 37 | +character(len=256) :: message |
| 38 | + |
| 39 | +! table of arguments to pass to program and expected non-default values for that execution in NAMELIST group format |
| 40 | +character(len=*),parameter :: tests(*)= [ character(len=256) :: & |
| 41 | + |
| 42 | +'CMD="new", ESTAT=1,', & |
| 43 | +'CMD="new -unknown", ESTAT=2,', & |
| 44 | +'CMD="new my_project another yet_another -with-test", ESTAT=2,', & |
| 45 | +'CMD="new my_project --with-executable", W_E=T, NAME="my_project",', & |
| 46 | +'CMD="new my_project --with-executable -with-test", W_E=T,W_T=T, NAME="my_project",', & |
| 47 | +'CMD="new my_project -with-test", W_T=T, NAME="my_project",', & |
| 48 | +'CMD="new my_project", NAME="my_project",', & |
| 49 | + |
| 50 | +'CMD="run", ', & |
| 51 | +'CMD="run my_project", NAME="my_project", ', & |
| 52 | +'CMD="run proj1 p2 project3", NAME="proj1","p2","project3", ', & |
| 53 | +'CMD="run proj1 p2 project3 --release", NAME="proj1","p2","project3",RELEASE=T,', & |
| 54 | +'CMD="run proj1 p2 project3 --release -- arg1 -x ""and a long one""", & |
| 55 | + &NAME="proj1","p2","project3",RELEASE=T ARGS="""arg1"" -x ""and a long one""", ', & |
| 56 | + |
| 57 | +'CMD="test", ', & |
| 58 | +'CMD="test my_project", NAME="my_project", ', & |
| 59 | +'CMD="test proj1 p2 project3", NAME="proj1","p2","project3", ', & |
| 60 | +'CMD="test proj1 p2 project3 --release", NAME="proj1","p2","project3",RELEASE=T,', & |
| 61 | +'CMD="test proj1 p2 project3 --release -- arg1 -x ""and a long one""", & |
| 62 | + &NAME="proj1","p2","project3",RELEASE=T ARGS="""arg1"" -x ""and a long one""", ', & |
| 63 | + |
| 64 | +'CMD="build", NAME= RELEASE=F,ARGS="",', & |
| 65 | +'CMD="build --release", NAME= RELEASE=T,ARGS="",', & |
| 66 | +' ' ] |
| 67 | +character(len=256) :: readme(3) |
| 68 | + |
| 69 | +readme(1)='&EXPECTED' ! top and bottom line for a NAMELIST group read from TEST() used to set the expected values |
| 70 | +readme(3)=' /' |
| 71 | +tally=[logical ::] ! an array that tabulates the command test results as pass or fail. |
| 72 | + |
| 73 | +if(command_argument_count().eq.0)then ! assume if called with no arguments to do the tests. This means you cannot |
| 74 | + ! have a test of no parameters. Could improve on this. |
| 75 | + ! if called with parameters assume this is a test and call the routine to |
| 76 | + ! parse the resulting values after calling the CLI command line parser |
| 77 | + ! and write the NAMELIST group so it can be read and tested against the |
| 78 | + ! expected results |
| 79 | + write(*,*)'start tests of the CLI command line parser' |
| 80 | + command=repeat(' ',4096) |
| 81 | + call get_command_argument(0,command) |
| 82 | + command=trim(command) |
| 83 | + write(*,*)'command=',command |
| 84 | + |
| 85 | + do i=1,size(tests) |
| 86 | + if(tests(i).eq.' ')then |
| 87 | + open(file='_test_cli',newunit=lun,delim='quote') |
| 88 | + close(unit=lun,status='delete') |
| 89 | + exit |
| 90 | + endif |
| 91 | + ! blank out name group EXPECTED |
| 92 | + name=[(repeat(' ',len(name)),i=1,max_names)] ! the words on the command line sans the subcommand name |
| 93 | + release=.false. ! --release |
| 94 | + w_e=.false. ! --with-executable |
| 95 | + w_t=.false. ! --with-test |
| 96 | + args=repeat(' ',132) ! -- ARGS |
| 97 | + cmd=repeat(' ',132) ! the command line arguments to test |
| 98 | + cstat=0 ! status values from EXECUTE_COMMAND_LINE() |
| 99 | + estat=0 |
| 100 | + readme(2)=' '//tests(i) ! select command options to test for CMD and set nondefault expected values |
| 101 | + read(readme,nml=expected) |
| 102 | + |
| 103 | + write(*,'(*(g0))')'START: TEST ',i,' CMD=',trim(cmd) |
| 104 | + ! call this program which will crack command line and write results to scratch file _test_cli |
| 105 | + call execute_command_line(command//' '//trim(cmd),cmdstat=act_cstat,exitstat=act_estat) |
| 106 | + if(cstat.eq.act_cstat.and.estat.eq.act_estat)then |
| 107 | + if(estat.eq.0)then |
| 108 | + open(file='_test_cli',newunit=lun,delim='quote') |
| 109 | + act_name=[(repeat(' ',len(act_name)),i=1,max_names)] |
| 110 | + act_release=.false. |
| 111 | + act_w_e=.false. |
| 112 | + act_w_t=.false. |
| 113 | + act_args=repeat(' ',132) |
| 114 | + read(lun,nml=act_cli,iostat=ios,iomsg=message) |
| 115 | + if(ios.ne.0)then |
| 116 | + write(*,'(a)')'ERROR:',trim(message) |
| 117 | + endif |
| 118 | + close(unit=lun) |
| 119 | + ! compare results to expected values |
| 120 | + subtally=[logical ::] |
| 121 | + call test_test('NAME',all(act_name.eq.name)) |
| 122 | + call test_test('RELEASE',act_release.eqv.release) |
| 123 | + call test_test('WITH_EXPECTED',act_w_e.eqv.w_e) |
| 124 | + call test_test('WITH_TESTED',act_w_t.eqv.w_t) |
| 125 | + call test_test('WITH_TEST',act_w_t.eqv.w_t) |
| 126 | + call test_test('ARGS',act_args.eq.args) |
| 127 | + if(all(subtally))then |
| 128 | + write(*,'(*(g0))')'PASSED: TEST ',i,' STATUS: expected ',cstat,' ',estat,' actual ',act_cstat,' ',act_estat,& |
| 129 | + & ' for [',trim(cmd),']' |
| 130 | + tally=[tally,.true.] |
| 131 | + else |
| 132 | + write(*,'(*(g0))')'FAILED: TEST ',i,' STATUS: expected ',cstat,' ',estat,' actual ',act_cstat,' ',act_estat,& |
| 133 | + & ' for [',trim(cmd),']' |
| 134 | + print '(4a)', & |
| 135 | + 'This file was compiled by ', & |
| 136 | + compiler_version(), & |
| 137 | + ' using the options ', & |
| 138 | + compiler_options() |
| 139 | + write(*,nml=act_cli,delim='quote') |
| 140 | + tally=[tally,.false.] |
| 141 | + endif |
| 142 | + else |
| 143 | + write(*,'(*(g0))')'PASSED: TEST ',i,' EXPECTED BAD STATUS: expected ',cstat,' ',estat, & |
| 144 | + ' actual ',act_cstat,' ',act_estat,' for [',trim(cmd),']' |
| 145 | + tally=[tally,.true.] |
| 146 | + endif |
| 147 | + else |
| 148 | + write(*,'(*(g0))')'FAILED: TEST ',i,'BAD STATUS: expected ',cstat,' ',estat,' actual ',act_cstat,' ',act_estat,& |
| 149 | + ' for [',trim(cmd),']' |
| 150 | + tally=[tally,.false.] |
| 151 | + endif |
| 152 | + enddo |
| 153 | + ! write up total results and if anything failed exit with a non-zero status |
| 154 | + write(*,'(*(g0))')'TALLY;',tally |
| 155 | + if(all(tally))then |
| 156 | + write(*,'(*(g0))')'PASSED: all ',count(tally),' tests passed ' |
| 157 | + else |
| 158 | + write(*,*)'FAILED: PASSED=',count(tally),' FAILED=',count(.not.tally) |
| 159 | + stop 4 |
| 160 | + endif |
| 161 | +else |
| 162 | + ! call this program with arguments |
| 163 | + !============================================= |
| 164 | + debugit: block |
| 165 | + integer :: j, ilen |
| 166 | + character(len=256) :: big_argument |
| 167 | + write(*,*)'arguments seen directly by program' |
| 168 | + do j=1,command_argument_count() |
| 169 | + call get_command_argument(number=j,value=big_argument,length=ilen) |
| 170 | + write(*,'(*(g0))')j,'[',big_argument(:ilen),']' |
| 171 | + enddo |
| 172 | + end block debugit |
| 173 | + !============================================= |
| 174 | + call parse() |
| 175 | +endif |
| 176 | + |
| 177 | +contains |
| 178 | + |
| 179 | +subroutine test_test(name,tst) |
| 180 | +character(len=*) :: name |
| 181 | +logical,intent(in) :: tst |
| 182 | + !!write(*,'(*(g0,1x))')' SUBTEST ',name,' ',merge('PASSED','FAILED',tst) |
| 183 | + subtally=[subtally,tst] |
| 184 | +end subroutine test_test |
| 185 | + |
| 186 | +subroutine parse() |
| 187 | +! all the extended types for settings from the main program |
| 188 | +use fpm_command_line, only: & |
| 189 | + fpm_cmd_settings, & |
| 190 | + fpm_new_settings, & |
| 191 | + fpm_build_settings, & |
| 192 | + fpm_run_settings, & |
| 193 | + fpm_test_settings, & |
| 194 | + fpm_install_settings, & |
| 195 | + get_command_line_settings |
| 196 | +use fpm, only: cmd_build, cmd_install, cmd_new, cmd_run, cmd_test |
| 197 | +class(fpm_cmd_settings), allocatable :: cmd_settings |
| 198 | +! duplicates the calls as seen in the main program for fpm |
| 199 | +call get_command_line_settings(cmd_settings) |
| 200 | + |
| 201 | +allocate (character(len=len(name)) :: act_name(0) ) |
| 202 | +act_args='' |
| 203 | +act_w_e=.false. |
| 204 | +act_w_t=.false. |
| 205 | +act_release=.false. |
| 206 | + |
| 207 | +select type(settings=>cmd_settings) |
| 208 | +type is (fpm_new_settings) |
| 209 | + act_w_e=settings%with_executable |
| 210 | + act_w_t=settings%with_test |
| 211 | + act_name=[trim(settings%name)] |
| 212 | +type is (fpm_build_settings) |
| 213 | + act_release=settings%release |
| 214 | +type is (fpm_run_settings) |
| 215 | + act_release=settings%release |
| 216 | + act_name=settings%name |
| 217 | + act_args=settings%args |
| 218 | +type is (fpm_test_settings) |
| 219 | + act_release=settings%release |
| 220 | + act_name=settings%name |
| 221 | + act_args=settings%args |
| 222 | +type is (fpm_install_settings) |
| 223 | +end select |
| 224 | + |
| 225 | +open(file='_test_cli',newunit=lun,delim='quote') |
| 226 | +write(lun,nml=act_cli,delim='quote') |
| 227 | +!!write(*,nml=act_cli) |
| 228 | +close(unit=lun) |
| 229 | + |
| 230 | +end subroutine parse |
| 231 | + |
| 232 | +end program main |
0 commit comments