Skip to content

Commit 5c67bc7

Browse files
authored
Merge pull request #76 from sourceryinstitute/run-tests-selectively
Run tests selectively
2 parents e8660b4 + 0983f29 commit 5c67bc7

24 files changed

+752
-305
lines changed

README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Sourcery Library
22
================
33

4-
A grab bag of useful tricks in Fortran 2018.
4+
A grab bag of useful tricks in Fortran 2023.
55

66
```fortran
77
-:/+-
@@ -82,6 +82,16 @@ git clone [email protected]:sourceryinstitute/sourcery
8282

8383
Building and Testing
8484
--------------------
85+
### Test-Suite Usage
86+
Executing `fpm test -- --help` prints the following message:
87+
```
88+
Usage: fpm test -- [--help] | [--contains <substring>]
89+
90+
where square brackets ([]) denote optional arguments, a pipe (|) separates alternative arguments,
91+
angular brackets (<>) denote a user-provided value, and passing a substring limits execution to
92+
the tests with test subjects or test descriptions containing the user-specified substring.
93+
```
94+
8595
### Single-image (serial) testing with GNU Fortran (`gfortran`)
8696
With recent versions of [GNU Fortran] (gfortran) and [OpenCoarrays] installed,
8797
execute the following command in a `zsh` or `bash`-like shell:
@@ -99,7 +109,7 @@ Substitute the desired number of images for the `4` above.
99109

100110
### Testing with the Numerical Algorithms Group (`nagfor`) compiler
101111
```zsh
102-
fpm test --compiler nagfor --flag "-fpp -coarray=cosmp"
112+
fpm test --compiler nagfor --flag -fpp
103113
```
104114

105115
### Building and testing with the Cray Compiler Environment (CCE)
@@ -147,4 +157,3 @@ documentation.
147157
[Building the documentation]: #building-the-documentation
148158
[Sourcery GitHub Pages site]: http://sourceryinstitute.github.io/sourcery/
149159
[`ford`]: https://github.com/Fortran-FOSS-Programmers/ford
150-
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
program check_command_line_argument
2+
!! This program serves the dual purposes of
3+
!! 1. Showing how to use the command_line_t derived type to check whether a
4+
!! command-line argument is present and
5+
!! 2. Supporting the test suite verification of this same behavior.
6+
!!
7+
!! Running this program as follows with the command
8+
!!
9+
!! fpm run --example check-command-line-argument -- --some-argument
10+
!!
11+
!! should result in normal termination.
12+
use assert_m, only : assert
13+
use sourcery_m, only : command_line_t
14+
implicit none
15+
16+
type(command_line_t) command_line
17+
logical argument_passed
18+
19+
argument_passed = command_line%argument_present(["--some-argument"])
20+
21+
call assert(argument_passed, "check_command_line_argument: argument present")
22+
end program

example/handle-missing-flag.f90

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
program handle_missing_flag
2+
!! This program serves the dual purposes of
3+
!!
4+
!! 1. Showing an example of a command-line with an expected flag missing an
5+
!! 2. Supporting the test suite check that the returned value has zero length.
6+
!!
7+
!! Running this program as follows with the command
8+
!!
9+
!! fpm run --example handle-missing-flag -- --empty-flag
10+
!!
11+
!! should result in normal termination.
12+
use assert_m, only : assert
13+
use sourcery_m, only : command_line_t
14+
implicit none
15+
16+
type(command_line_t) command_line
17+
character(len=:), allocatable :: flag_value
18+
character(len=*), parameter :: expected_name=""
19+
20+
flag_value = command_line%flag_value("--empty-flag")
21+
22+
call assert(flag_value==expected_name,"handle_missing_flag: expected empty flag value", flag_value)
23+
end program

src/sourcery/sourcery_command_line_s.f90

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,28 @@
3939
integer argnum, arglen, flag_value_length
4040
character(len=:), allocatable :: arg
4141

42-
43-
flag_search: &
44-
do argnum = 1,command_argument_count()
45-
46-
if (allocated(arg)) deallocate(arg)
47-
48-
call get_command_argument(argnum, length=arglen)
49-
allocate(character(len=arglen) :: arg)
50-
call get_command_argument(argnum, arg)
51-
52-
if (arg==flag) then
53-
call get_command_argument(argnum+1, length=flag_value_length)
54-
allocate(character(len=flag_value_length) :: flag_value)
55-
call get_command_argument(argnum+1, flag_value)
56-
exit flag_search
42+
associate(argcount => command_argument_count())
43+
if (argcount==0) then
44+
flag_value=""
45+
else
46+
flag_search: &
47+
do argnum = 1,argcount
48+
49+
if (allocated(arg)) deallocate(arg)
50+
51+
call get_command_argument(argnum, length=arglen)
52+
allocate(character(len=arglen) :: arg)
53+
call get_command_argument(argnum, arg)
54+
55+
if (arg==flag) then
56+
call get_command_argument(argnum+1, length=flag_value_length)
57+
allocate(character(len=flag_value_length) :: flag_value)
58+
call get_command_argument(argnum+1, flag_value)
59+
exit flag_search
60+
end if
61+
end do flag_search
5762
end if
58-
end do flag_search
63+
end associate
5964

6065
end procedure
6166

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
module sourcery_test_description_m
2+
!! Define an abstraction for describing test intentions and test functions
3+
use sourcery_string_m, only : string_t
4+
use sourcery_test_result_m, only : test_result_t
5+
implicit none
6+
7+
private
8+
public :: test_description_t
9+
#ifdef __GFORTRAN__
10+
public :: test_function_i
11+
#endif
12+
13+
abstract interface
14+
function test_function_i() result(passes)
15+
implicit none
16+
logical passes
17+
end function
18+
end interface
19+
20+
type test_description_t
21+
!! Encapsulate test descriptions and test-functions
22+
private
23+
type(string_t) description_
24+
procedure(test_function_i), pointer, nopass :: test_function_ => null()
25+
contains
26+
procedure run
27+
procedure contains_text
28+
end type
29+
30+
interface test_description_t
31+
32+
module function construct(description, test_function) result(test_description)
33+
!! The result is a test_description_t object with the components defined by the dummy arguments
34+
implicit none
35+
type(string_t), intent(in) :: description
36+
procedure(test_function_i), intent(in), pointer :: test_function
37+
type(test_description_t) test_description
38+
end function
39+
40+
end interface
41+
42+
interface
43+
44+
impure elemental module function run(self) result(test_result)
45+
!! The result encapsulates the test description and test outcome
46+
implicit none
47+
class(test_description_t), intent(in) :: self
48+
type(test_result_t) test_result
49+
end function
50+
51+
impure elemental module function contains_text(self, substring) result(match)
52+
!! The result is .true. if the test description includes the value of substring
53+
implicit none
54+
class(test_description_t), intent(in) :: self
55+
type(string_t), intent(in) :: substring
56+
logical match
57+
end function
58+
59+
end interface
60+
61+
end module sourcery_test_description_m
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
submodule(sourcery_test_description_m) sourcery_test_description_s
2+
implicit none
3+
4+
contains
5+
6+
module procedure construct
7+
test_description%description_ = description
8+
test_description%test_function_ => test_function
9+
end procedure
10+
11+
module procedure run
12+
test_result = test_result_t(self%description_, self%test_function_())
13+
end procedure
14+
15+
module procedure contains_text
16+
match = index(self%description_%string(), substring%string()) /= 0
17+
end procedure
18+
19+
end submodule sourcery_test_description_s

src/sourcery/sourcery_test_m.f90

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ module sourcery_test_m
66
implicit none
77

88
private
9-
public :: test_t, test_result_t
9+
public :: test_t, test_description_substring
10+
11+
character(len=:), allocatable, protected :: test_description_substring
1012

1113
type, abstract :: test_t
1214
!! Facilitate testing and test reporting

src/sourcery/sourcery_test_result_m.f90

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
module sourcery_test_result_m
22
!! Define an abstraction for describing test intentions and results
3+
use sourcery_string_m, only : string_t
34
implicit none
45

56
private
67
public :: test_result_t
78

89
type test_result_t
9-
!! Encapsulate test descriptions and outcomes and reporting
10+
!! Encapsulate test descriptions and outcomes
1011
private
11-
character(len=:), allocatable :: description_
12+
type(string_t) description_
1213
logical passed_
1314
contains
1415
procedure :: characterize
@@ -17,14 +18,22 @@ module sourcery_test_result_m
1718

1819
interface test_result_t
1920

20-
elemental module function construct(description, passed) result(test_result)
21+
elemental module function construct_from_character(description, passed) result(test_result)
2122
!! The result is a test_result_t object with the components defined by the dummy arguments
2223
implicit none
2324
character(len=*), intent(in) :: description
2425
logical, intent(in) :: passed
2526
type(test_result_t) test_result
2627
end function
2728

29+
module function construct_from_string(description, passed) result(test_result)
30+
!! The result is a test_result_t object with the components defined by the dummy arguments
31+
implicit none
32+
type(string_t), intent(in) :: description
33+
logical, intent(in) :: passed
34+
type(test_result_t) test_result
35+
end function
36+
2837
end interface
2938

3039
interface

src/sourcery/sourcery_test_result_s.f90

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44

55
contains
66

7-
module procedure construct
7+
module procedure construct_from_character
8+
test_result%description_ = description
9+
test_result%passed_ = passed
10+
end procedure
11+
12+
module procedure construct_from_string
813
test_result%description_ = description
914
test_result%passed_ = passed
1015
end procedure
1116

1217
module procedure characterize
13-
characterization = trim(merge("passes on ", "FAILS on ", self%passed_)) // " " // trim(self%description_) // "."
18+
characterization = trim(merge("passes on ", "FAILS on ", self%passed_)) // " " // trim(self%description_%string()) // "."
1419
end procedure
1520

1621
module procedure passed

src/sourcery/sourcery_test_s.F90

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,36 @@
11
submodule(sourcery_test_m) sourcery_test_s
22
use sourcery_user_defined_collectives_m, only : co_all
3+
use sourcery_command_line_m, only : command_line_t
34
implicit none
45

56
contains
67

78
module procedure report
89

910
associate(me => this_image())
10-
if (me==1) print *, new_line('a'), test%subject()
1111

12+
if (me==1) then
13+
14+
first_report: &
15+
if (.not. allocated(test_description_substring)) then
16+
block
17+
type(command_line_t) command_line
18+
test_description_substring = command_line%flag_value("--contains")
19+
end block
20+
if (len(test_description_substring)==0) then
21+
print *,"Running all tests."
22+
print *,"(Add '-- --contains <string> to run only tests with descriptions containing the specified string.)"
23+
else
24+
print *,"Running only tests with descriptions containing '", test_description_substring,"'."
25+
end if
26+
end if first_report
27+
28+
print *, new_line('a'), test%subject()
29+
30+
end if
31+
32+
call co_broadcast(test_description_substring, source_image=1)
33+
1234
#ifndef _CRAYFTN
1335
associate(test_results => test%results())
1436
associate(num_tests => size(test_results))

src/sourcery_m.f90 renamed to src/sourcery_m.F90

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ module sourcery_m
66
use sourcery_formats_m, only : csv, cscv, separated_values
77
use sourcery_file_m, only : file_t
88
use sourcery_string_m, only : string_t, operator(.cat.)
9+
use sourcery_test_m, only : test_t, test_description_substring
10+
use sourcery_test_description_m, only : test_description_t
11+
#ifdef __GFORTRAN__
12+
use sourcery_test_description_m, only : test_function_i
13+
#endif
914
use sourcery_test_result_m, only : test_result_t
10-
use sourcery_test_m, only : test_t
1115
use sourcery_user_defined_collectives_m, only : co_all
1216

1317
!! legacy modules (likely to be removed in a future release):

0 commit comments

Comments
 (0)