Skip to content

Commit 0729097

Browse files
authored
Merge pull request #81 from sourceryinstitute/fix-vector-valued-test-functions
feat: support vector-valued test functions
2 parents 609b8a3 + c11bb6b commit 0729097

9 files changed

+171
-13
lines changed

.github/workflows/deploy-docs.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on: [push, pull_request]
55

66
jobs:
77
Build:
8-
runs-on: ubuntu-22.04
8+
runs-on: ubuntu-latest
99

1010
steps:
1111
- name: Checkout code
@@ -15,11 +15,12 @@ jobs:
1515
run: |
1616
sudo apt-get update
1717
sudo apt install -y python3-dev python3 build-essential graphviz
18-
sudo pip install ford markdown==3.3.4
18+
sudo pip install ford
1919
2020
- name: Build Developer Documenation
2121
run: |
2222
cd doc
23+
ford --version
2324
ford ford.md
2425
2526
- name: Upload Documentation

src/sourcery/sourcery_test_description_m.F90 renamed to src/sourcery/sourcery_test_description_m.f90

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ module sourcery_test_description_m
66

77
private
88
public :: test_description_t
9-
#ifdef __GFORTRAN__
109
public :: test_function_i
11-
#endif
1210

1311
abstract interface
1412
function test_function_i() result(passes)

src/sourcery/sourcery_test_result_m.f90

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ module sourcery_test_result_m
88

99
type test_result_t
1010
!! Encapsulate test descriptions and outcomes
11-
private
11+
!private
1212
type(string_t) description_
1313
logical passed_
1414
contains
1515
procedure :: characterize
1616
procedure :: passed
17+
procedure :: description_contains
1718
end type
1819

1920
interface test_result_t
@@ -26,7 +27,7 @@ elemental module function construct_from_character(description, passed) result(t
2627
type(test_result_t) test_result
2728
end function
2829

29-
module function construct_from_string(description, passed) result(test_result)
30+
elemental module function construct_from_string(description, passed) result(test_result)
3031
!! The result is a test_result_t object with the components defined by the dummy arguments
3132
implicit none
3233
type(string_t), intent(in) :: description
@@ -52,6 +53,14 @@ impure elemental module function passed(self) result(test_passed)
5253
logical test_passed
5354
end function
5455

56+
elemental module function description_contains(self, substring) result(substring_found)
57+
!! The result is true if and only if the test description contains the substring
58+
implicit none
59+
class(test_result_t), intent(in) :: self
60+
type(string_t), intent(in) :: substring
61+
logical substring_found
62+
end function
63+
5564
end interface
5665

5766
end module sourcery_test_result_m

src/sourcery/sourcery_test_result_s.f90

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@
2323
call co_all(test_passed)
2424
end procedure
2525

26+
module procedure description_contains
27+
substring_found = index(self%description_%string(), substring%string()) /= 0
28+
end procedure
29+
2630
end submodule sourcery_test_result_s

src/sourcery/sourcery_test_s.F90

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,18 @@
1111

1212
if (me==1) then
1313

14+
1415
first_report: &
1516
if (.not. allocated(test_description_substring)) then
1617
block
1718
type(command_line_t) command_line
1819
test_description_substring = command_line%flag_value("--contains")
1920
end block
2021
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.)"
22+
print*,"Running all tests."
23+
print*,"(Add '-- --contains <string>' to run only tests with subjects or descriptions containing the specified string.)"
2324
else
24-
print *,"Running only tests with descriptions containing '", test_description_substring,"'."
25+
print *,"Running only tests with subjects or descriptions containing '", test_description_substring,"'."
2526
end if
2627
end if first_report
2728

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
module sourcery_vector_test_description_m
2+
!! Define an abstraction for describing test intentions and array-valued test functions
3+
use sourcery_string_m, only : string_t
4+
use sourcery_test_result_m, only : test_result_t
5+
use assert_m, only : assert
6+
implicit none
7+
8+
private
9+
public :: vector_test_description_t
10+
public :: vector_function_strategy_t
11+
12+
abstract interface
13+
function vector_function_i() result(passes)
14+
implicit none
15+
logical, allocatable :: passes(:)
16+
end function
17+
end interface
18+
19+
type, abstract :: vector_function_strategy_t
20+
contains
21+
procedure(vector_function_i), deferred, nopass :: vector_function
22+
end type
23+
24+
type vector_test_description_t
25+
!! Encapsulate test descriptions and vector-valued test functions
26+
private
27+
type(string_t), allocatable :: description_vector_(:)
28+
class(vector_function_strategy_t), allocatable :: vector_function_strategy_
29+
contains
30+
procedure run
31+
procedure contains_text
32+
end type
33+
34+
interface vector_test_description_t
35+
36+
module function construct(description_vector, vector_function_strategy) result(vector_test_description)
37+
!! The result is a vector_test_description_t object with the components defined by the dummy arguments
38+
implicit none
39+
type(string_t), intent(in) :: description_vector(:)
40+
class(vector_function_strategy_t), intent(in) :: vector_function_strategy
41+
type(vector_test_description_t) vector_test_description
42+
end function
43+
44+
end interface
45+
46+
interface
47+
48+
impure module function run(self) result(test_results)
49+
!! The result encapsulates the test description and test outcome
50+
implicit none
51+
class(vector_test_description_t), intent(in) :: self
52+
type(test_result_t), allocatable :: test_results(:)
53+
end function
54+
55+
module function contains_text(self, substring) result(match_vector)
56+
!! The result is .true. if the test description includes the value of substring
57+
implicit none
58+
class(vector_test_description_t), intent(in) :: self
59+
character(len=*), intent(in) :: substring
60+
logical, allocatable :: match_vector(:)
61+
end function
62+
63+
end interface
64+
65+
contains
66+
67+
module procedure contains_text
68+
integer i
69+
associate(num_descriptions => size(self%description_vector_))
70+
allocate(match_vector(num_descriptions))
71+
do i = 1, num_descriptions
72+
match_vector(i) = index(self%description_vector_(i)%string(), substring ) /= 0
73+
end do
74+
end associate
75+
end procedure
76+
77+
module procedure construct
78+
vector_test_description%description_vector_ = description_vector
79+
vector_test_description%vector_function_strategy_ = vector_function_strategy
80+
end procedure
81+
82+
module procedure run
83+
associate(vector_result => self%vector_function_strategy_%vector_function())
84+
call assert(size(self%description_vector_)==size(vector_result), "sourcery_vector_test_description_s: size match")
85+
test_results = test_result_t(self%description_vector_, vector_result)
86+
end associate
87+
end procedure
88+
89+
end module sourcery_vector_test_description_m

src/sourcery_m.F90

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ module sourcery_m
77
use sourcery_file_m, only : file_t
88
use sourcery_string_m, only : string_t, operator(.cat.)
99
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
10+
use sourcery_test_description_m, only : test_description_t, test_function_i
1411
use sourcery_test_result_m, only : test_result_t
12+
use sourcery_vector_test_description_m, only : vector_test_description_t, vector_function_strategy_t
1513
use sourcery_user_defined_collectives_m, only : co_all
1614

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

test/main.f90

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ program main
88
use sourcery_m, only : command_line_t
99
use test_result_test_m, only : test_result_test_t
1010
use test_description_test_m, only : test_description_test_t
11+
use vector_test_description_test_m, only : vector_test_description_test_t
1112
use user_defined_collectives_test_m, only : collectives_test_t
1213
implicit none
1314

@@ -20,6 +21,7 @@ program main
2021
type(string_test_t) string_test
2122
type(test_result_test_t) test_result_test
2223
type(test_description_test_t) test_description_test
24+
type(vector_test_description_test_t) vector_test_description_test
2325

2426
integer :: passes=0, tests=0
2527

@@ -43,6 +45,7 @@ program main
4345
call string_test%report(passes, tests)
4446
call test_result_test%report(passes, tests)
4547
call test_description_test%report(passes, tests)
48+
call vector_test_description_test%report(passes,tests)
4649
if (.not. GitHub_CI()) call command_line_test%report(passes, tests)
4750

4851
if (this_image()==1) print *, new_line('a'), "_________ In total, ",passes," of ",tests, " tests pass. _________"

test/vector_test_description_test.f90

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module vector_test_description_test_m
2+
!! Verify vector_test_description_t object behavior
3+
use sourcery_m, only : &
4+
string_t, test_result_t, vector_test_description_t, test_t, test_description_substring, vector_function_strategy_t
5+
implicit none
6+
7+
private
8+
public :: vector_test_description_test_t
9+
10+
type, extends(test_t) :: vector_test_description_test_t
11+
contains
12+
procedure, nopass :: subject
13+
procedure, nopass :: results
14+
end type
15+
16+
type, extends(vector_function_strategy_t) :: two_vector_tautology_t
17+
contains
18+
procedure, nopass :: vector_function
19+
end type
20+
21+
contains
22+
23+
pure function subject() result(specimen)
24+
character(len=:), allocatable :: specimen
25+
specimen = "The vector_test_description_t type"
26+
end function
27+
28+
function vector_function() result(passed)
29+
logical, allocatable :: passed(:)
30+
passed = [.true., .true.]
31+
end function
32+
33+
function results() result(test_results)
34+
type(test_result_t), allocatable :: test_results(:)
35+
type(two_vector_tautology_t) two_vector_tautology
36+
37+
associate( &
38+
vector_test_description => vector_test_description_t([string_t("construction"),string_t("assignment")], two_vector_tautology)&
39+
)
40+
associate(substring_in_subject => index(subject(), test_description_substring) /= 0)
41+
associate(substring_in_description => vector_test_description%contains_text(test_description_substring))
42+
if (substring_in_subject) then
43+
test_results = vector_test_description%run()
44+
else if (any(substring_in_description)) then
45+
test_results = vector_test_description%run()
46+
test_results = pack(test_results, test_results%description_contains(string_t(test_description_substring)))
47+
else
48+
test_results = [test_result_t::]
49+
end if
50+
end associate
51+
end associate
52+
end associate
53+
end function
54+
55+
end module vector_test_description_test_m

0 commit comments

Comments
 (0)