Skip to content

Commit

Permalink
chore(diagnosis_t): assert diagnostics allocated
Browse files Browse the repository at this point in the history
  • Loading branch information
rouson committed Jan 1, 2025
1 parent 2dbdaf6 commit ab70ef2
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 8 deletions.
59 changes: 59 additions & 0 deletions src/julienne/julienne_diagnosis_m.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
! Copyright (c) 2024, The Regents of the University of California and Sourcery Institute
! Terms of use are as specified in LICENSE.txt
module julienne_diagnosis_m
!! Define an abstraction for describing test outcomes and diagnostic information
use julienne_string_m, only : string_t
implicit none

private
public :: diagnosis_t

type diagnosis_t
!! Encapsulate test outcome and diagnostic information
private
logical passed_
character(len=:), allocatable :: diagnostics_
contains
procedure passed
procedure diagnostics
end type

interface diagnosis_t

elemental module function construct_from_string_t(passed, diagnostics) result(diagnosis)
!! The result is a diagnosis_t object with the components defined by the dummy arguments
implicit none
logical, intent(in) :: passed
type(string_t), intent(in) :: diagnostics
type(diagnosis_t) diagnosis
end function

elemental module function construct_from_character(passed, diagnostics) result(diagnosis)
!! The result is a diagnosis_t object with the components defined by the dummy arguments
implicit none
logical, intent(in) :: passed
character(len=*), intent(in) :: diagnostics
type(diagnosis_t) diagnosis
end function

end interface

interface

elemental module function passed(self) result(test_passed)
!! The result is .true. if the test passed
implicit none
class(diagnosis_t), intent(in) :: self
logical test_passed
end function

elemental module function diagnostics(self) result(diagnostics_string)
!! The result is a diagnostic string describing a failed test or a zero-length string if the test passed
implicit none
class(diagnosis_t), intent(in) :: self
type(string_t) diagnostics_string
end function

end interface

end module julienne_diagnosis_m
28 changes: 28 additions & 0 deletions src/julienne/julienne_diagnosis_s.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
! Copyright (c) 2024, The Regents of the University of California and Sourcery Institute
! Terms of use are as specified in LICENSE.txt

#include "assert_macros.h"

submodule(julienne_diagnosis_m) julienne_diagnosis_s
use assert_m
implicit none
contains
module procedure construct_from_string_t
diagnosis%passed_ = passed
diagnosis%diagnostics_ = diagnostics
end procedure

module procedure construct_from_character
diagnosis%passed_ = passed
diagnosis%diagnostics_ = diagnostics
end procedure

module procedure passed
test_passed = self%passed_
end procedure

module procedure diagnostics
call_assert(allocated(self%diagnostics_))
diagnostics_string = string_t(self%diagnostics_)
end procedure
end submodule julienne_diagnosis_s
11 changes: 11 additions & 0 deletions src/julienne/julienne_test_description_m.f90
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,35 @@ module julienne_test_description_m
!! Define an abstraction for describing test intentions and test functions
use julienne_string_m, only : string_t
use julienne_test_result_m, only : test_result_t
use julienne_diagnosis_m, only : diagnosis_t
implicit none

private
public :: test_description_t
public :: test_function_i
public :: diagnostic_function_i

abstract interface

function test_function_i() result(passes)
implicit none
logical passes
end function

function diagnostic_function_i() result(diagnosis)
import diagnosis_t
implicit none
type(diagnosis_t) diagnosis
end function

end interface

type test_description_t
!! Encapsulate test descriptions and test-functions
private
character(len=:), allocatable :: description_
procedure(test_function_i), pointer, nopass :: test_function_ => null()
procedure(diagnostic_function_i), pointer, nopass :: diagnostic_function_ => null()
contains
procedure run
generic :: contains_text => contains_string_t, contains_characters
Expand Down
12 changes: 11 additions & 1 deletion src/julienne/julienne_test_description_s.f90
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
! Copyright (c) 2024, The Regents of the University of California and Sourcery Institute
! Terms of use are as specified in LICENSE.txt

#include "assert_macros.h"

submodule(julienne_test_description_m) julienne_test_description_s
implicit none
contains
Expand All @@ -14,7 +17,14 @@
end procedure

module procedure run
test_result = test_result_t(self%description_, self%test_function_())
associate(testing => associated(self%test_function_), diagnosing => associated(self%diagnostic_function_))
call_assert(count([testing, diagnosing])==1)
if (testing) then
test_result = test_result_t(self%description_, self%test_function_())
else
test_result = test_result_t(self%description_, self%diagnostic_function_())
end if
end associate
end procedure

module procedure contains_string_t
Expand Down
11 changes: 10 additions & 1 deletion src/julienne/julienne_test_result_m.f90
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module julienne_test_result_m
!! Define an abstraction for describing test intentions and results
use julienne_string_m, only : string_t
use julienne_diagnosis_m, only : diagnosis_t
implicit none

private
Expand All @@ -11,7 +12,7 @@ module julienne_test_result_m
type test_result_t
!! Encapsulate test descriptions and outcomes
private
character(len=:), allocatable :: description_
character(len=:), allocatable :: description_, diagnostics_
logical passed_
contains
procedure :: characterize
Expand Down Expand Up @@ -39,6 +40,14 @@ elemental module function construct_from_string(description, passed) result(test
type(test_result_t) test_result
end function

elemental module function construct_from_diagnosis(description, diagnosis) result(test_result)
!! The result is a test_result_t object with the components defined by the dummy arguments
implicit none
character(len=*), intent(in) :: description
type(diagnosis_t), intent(in) :: diagnosis
type(test_result_t) test_result
end function

end interface

interface
Expand Down
8 changes: 8 additions & 0 deletions src/julienne/julienne_test_result_s.f90
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@
test_result%passed_ = passed
end procedure

module procedure construct_from_diagnosis
test_result%description_ = description
test_result%passed_ = diagnosis%passed()
test_result%diagnostics_ = diagnosis%diagnostics()
end procedure

module procedure characterize
characterization = trim(merge("passes on ", "FAILS on ", self%passed_)) // " " // trim(self%description_) // "."
if (allocated(self%diagnostics_) .and. .not. self%passed_) &
characterization = characterization // new_line('') // " diagnostics: " // self%diagnostics_
end procedure

module procedure passed
Expand Down
38 changes: 32 additions & 6 deletions test/string_test.F90
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ function results() result(test_results)
test_description_t &
(string_t('constructing from a default integer'), constructs_from_default_integer), &
test_description_t &
(string_t('constructing from a real value'), constructs_from_real), &
(string_t('constructing from a default real value'), constructs_from_default_real), &
test_description_t &
(string_t('constructing from a double precision value'), constructs_from_double_precision), &
test_description_t &
(string_t('supporting unary operator(.cat.) for array arguments'), concatenates_elements), &
test_description_t &
Expand Down Expand Up @@ -97,8 +99,8 @@ function results() result(test_results)
! Work around missing Fortran 2008 feature: associating a procedure actual argument with a procedure pointer dummy argument:
procedure(test_function_i), pointer :: &
check_allocation_ptr, supports_equivalence_ptr, supports_non_equivalence_ptr, supports_concatenation_ptr, &
assigns_string_ptr, assigns_character_ptr, constructs_from_integer_ptr, constructs_from_real_ptr, concatenates_ptr, &
extracts_key_ptr, extracts_real_ptr, extracts_string_ptr, extracts_logical_ptr, extracts_integer_array_ptr, &
assigns_string_ptr, assigns_character_ptr, constructs_from_integer_ptr, constructs_from_default_real_ptr, constructs_from_double_precision_ptr, &
concatenates_ptr, extracts_key_ptr, extracts_real_ptr, extracts_string_ptr, extracts_logical_ptr, extracts_integer_array_ptr, &
extracts_real_array_ptr, extracts_integer_ptr, extracts_file_base_ptr, extracts_file_name_ptr, &
! Remove code that exposes a gfortran compiler bug:
! extracts_string_array_ptr, &
Expand All @@ -112,7 +114,8 @@ function results() result(test_results)
assigns_string_ptr => assigns_string_t_to_character
assigns_character_ptr => assigns_character_to_string_t
constructs_from_integer_ptr => constructs_from_default_integer
constructs_from_real_ptr => constructs_from_real
constructs_from_double_precision_ptr => constructs_from_double_precision
constructs_from_default_real_ptr => constructs_from_default_real
concatenates_ptr => concatenates_elements
extracts_key_ptr => extracts_key
extracts_real_ptr => extracts_real_value
Expand Down Expand Up @@ -142,7 +145,8 @@ function results() result(test_results)
test_description_t(string_t('assigning a string_t object to a character variable'), assigns_string_ptr), &
test_description_t(string_t('assigning a character variable to a string_t object'), assigns_character_ptr), &
test_description_t(string_t('constructing from a default integer'), constructs_from_integer_ptr), &
test_description_t(string_t('constructing from a real value'), constructs_from_real_ptr), &
test_description_t(string_t('constructing from a default real value'), constructs_from_default_real_ptr), &
test_description_t(string_t('constructing from a double precision value'), constructs_from_double_precision_ptr), &
test_description_t(string_t('supporting unary operator(.cat.) for array arguments'), concatenates_ptr), &
test_description_t(string_t("extracting a key string from a colon-separated key/value pair"), extracts_key_ptr), &
test_description_t(string_t("extracting a real value from a colon-separated key/value pair"), extracts_real_ptr), &
Expand Down Expand Up @@ -471,7 +475,7 @@ function constructs_from_default_integer() result(passed)
#endif
end function

function constructs_from_real() result(passed)
function constructs_from_default_real() result(passed)
logical passed
real, parameter :: real_value = -1./1024. ! use a negative power of 2 an exactly representable rational number
real read_value
Expand All @@ -492,7 +496,29 @@ function constructs_from_real() result(passed)
passed = read_value == real_value
end block
#endif
end function

function constructs_from_double_precision() result(passed)
logical passed
double precision, parameter :: real_value = -1./1024. ! use a negative power of 2 an exactly representable rational number
real read_value
character(len=:), allocatable :: character_representation

#ifndef _CRAYFTN
associate(string => string_t(real_value))
character_representation = string%string()
read(character_representation, *) read_value
passed = read_value == real_value
end associate
#else
block
type(string_t) string
string = string_t(real_value)
character_representation = string%string()
read(character_representation, *) read_value
passed = read_value == real_value
end block
#endif
end function

function extracts_file_base_name() result(passed)
Expand Down

0 comments on commit ab70ef2

Please sign in to comment.