From 60a4f4649de5b6577ed6a104a27eb73dabb443bf Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Tue, 5 Aug 2025 20:21:52 -0500 Subject: [PATCH 01/11] feat(assert): specific procedure with logical arg This commit adds a new specific procedure for the call_julienne_assert generic interface. The new procedure, subroutine assert_assert, has one required logical argument in addition to character 'file' and integer 'line' arguments analogous to those in the julienne_assert subroutine. Like julienne_assert, the new subroutine calls the 'assert' in the Assert library (https://go.lbl.gov/assert). --- src/julienne/julienne_test_diagnosis_m.F90 | 11 +++++++++++ src/julienne/julienne_test_diagnosis_s.F90 | 8 ++++++++ test/modules/assert_test_m.F90 | 14 +++++++++++--- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/julienne/julienne_test_diagnosis_m.F90 b/src/julienne/julienne_test_diagnosis_m.F90 index fe1e7a642..02d51e6c6 100644 --- a/src/julienne/julienne_test_diagnosis_m.F90 +++ b/src/julienne/julienne_test_diagnosis_m.F90 @@ -60,6 +60,7 @@ module julienne_test_diagnosis_m interface call_julienne_assert_ pure module subroutine julienne_assert(test_diagnosis, file, line) + !! Public procedure. !! Use cases: !! 1. When invoked via the generic interface, the preprocessor passes the 'file' and 'line' dummy arguments automatically. !! 2. When invoked directly, there is 1 argument: an expression containing defined operations such as 1 .equalsExpected. 1 @@ -69,6 +70,16 @@ pure module subroutine julienne_assert(test_diagnosis, file, line) integer, intent(in), optional :: line end subroutine + pure module subroutine assert_assert(assertion, file, line) + !! Private wrapper for the assert subroutine in the Assert library (https://go.lbl.gov/assert). + !! Invoke this procedure via the call_julienne_assert_ generic interface with only the required logical argument. + !! The preprocessor will insert the optional 'file' and 'line' arguments. + implicit none + logical, intent(in) :: assertion + character(len=*), intent(in), optional :: file + integer, intent(in), optional :: line + end subroutine + end interface interface operator(.all.) diff --git a/src/julienne/julienne_test_diagnosis_s.F90 b/src/julienne/julienne_test_diagnosis_s.F90 index 249fb974c..6fd2a4d50 100644 --- a/src/julienne/julienne_test_diagnosis_s.F90 +++ b/src/julienne/julienne_test_diagnosis_s.F90 @@ -549,4 +549,12 @@ pure function aggregate_vector_diagnosis(diagnoses) result(diagnosis) call assert_always(test_diagnosis%test_passed_, diagnostics_string) end procedure + module procedure assert_assert + character(len=:), allocatable :: diagnostics_string + diagnostics_string = "" + if (present(file)) diagnostics_string = diagnostics_string // " in file " // file + if (present(line)) diagnostics_string = diagnostics_string // " at line " // string_t(line) + call assert_always(assertion, diagnostics_string) + end procedure + end submodule julienne_test_diagnosis_s diff --git a/test/modules/assert_test_m.F90 b/test/modules/assert_test_m.F90 index f4acae7f4..68fbca1e6 100644 --- a/test/modules/assert_test_m.F90 +++ b/test/modules/assert_test_m.F90 @@ -40,7 +40,8 @@ function results() result(test_results) type(test_result_t), allocatable :: test_results(:) associate(descriptions => [ & - test_description_t("invocation with an expression containing Julienne operators", check_macro_with_expression) & + test_description_t("invocation with an expression containing Julienne operators", check_macro_with_julienne_idiom) & + ,test_description_t("invocation with a logical expression", check_macro_with_logical_assertion) & ]) associate(substring_in_subject => index(subject(), test_description_substring) /= 0) associate(substring_in_test_diagnosis => descriptions%contains_text(test_description_substring)) @@ -61,10 +62,12 @@ function results() result(test_results) type(test_result_t), allocatable :: test_results(:) type(test_description_t), allocatable :: descriptions(:) procedure(diagnosis_function_i), pointer :: & - check_macro_with_expression_ptr => check_macro_with_expression + check_macro_with_julienne_idiom_ptr => check_macro_with_julienne_idiom & + ,check_macro_with_logical_assertion_ptr => check_macro_with_logical_assertion descriptions = [ & test_description_t("invocation via macro with an expression containing Julienne operators", check_macro_with_expression_ptr)& + ,test_description_t("invocation with a logical expression", check_macro_with_logical_assertion_ptr) & ] block @@ -81,10 +84,15 @@ function results() result(test_results) #endif - function check_macro_with_expression() result(test_diagnosis) + function check_macro_with_julienne_idiom() result(test_diagnosis) type(test_diagnosis_t) test_diagnosis call_julienne_assert(1. .approximates. 2. .within. 3.) test_diagnosis = test_diagnosis_t(.true., "") end function + function check_macro_with_logical_assertion() result(test_diagnosis) + type(test_diagnosis_t) test_diagnosis + call_julienne_assert(1==1) + end function + end module assert_test_m From d8563b79c85387baebafd4805b4e7a0ed0f742a4 Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Tue, 5 Aug 2025 21:19:57 -0500 Subject: [PATCH 02/11] doc(README): desc assert_assert specific procedure --- README.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8b4decd69..07c014065 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,8 @@ Getting Started --------------- ### Writing Assertions To write a Julienne assertion, insert a function-like preprocessor macro -`call_julienne_assert` on a single line as in the following program: +`call_julienne_assert` on a single line as in each of the two macro +invocations below: ```fortran #include "julienne-assertion-macros.h" program main @@ -164,14 +165,24 @@ program main implicit none real, parameter :: x=1., y=2., tolerance=3. call_julienne_assert(x .approximates. y .within. tolerance) + call_julienne_assert(abs(x-y) < tolerance) end program ``` -where inserting `-DASSERTIONS` in a compile command will expand the macro to +where inserting `-DASSERTIONS` in a compile command will expand the macros to ```fortran - call call_julienne_assert_(x .approximates. y .within. tolerance) + call call_julienne_assert_(x .approximates. y .within. tolerance, __FILE__, __LINE__) + call call_julienne_assert_(abs(x-y) < tolerance, __FILE__, __LINE__) ``` -and where dots (`.`) delimit Julienne operators and the parenthetical expression -evaluates to a Julienne `test_diagnosis_t` object. +and where dots (`.`) delimit Julienne operators. The above expression containing +Julienne operators evaluates to a Julienne `test_diagnosis_t` object, whereas +expression on the subsequent line containing intrinsic operators evaluates to a +`logical` value. If an assertion containing a Julienne expression fails, the +error stop code will contain diagnostic information constructed automatically by +Julienne. If an assertion containing a `logical` experession evaluates to `false.`, +the error stop code will contain a literal copy of the expression. In either +case, the error stop code will also contain the file and line number, which the +function-like macro inserts automatically via the `__FILE__` and `__LINE__` macros, +respectively. ### Writing Unit Tests Writing tests using Julienne involves constructing a test-description array, From 0d7794d3f31b7935e7a260b49545c747262f0e20 Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Tue, 5 Aug 2025 21:50:29 -0500 Subject: [PATCH 03/11] doc(README): improve discussion of assert_assert --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 07c014065..9fb3ad678 100644 --- a/README.md +++ b/README.md @@ -171,18 +171,18 @@ end program where inserting `-DASSERTIONS` in a compile command will expand the macros to ```fortran call call_julienne_assert_(x .approximates. y .within. tolerance, __FILE__, __LINE__) - call call_julienne_assert_(abs(x-y) < tolerance, __FILE__, __LINE__) + call call_julienne_assert_(allocated(a), __FILE__, __LINE__) ``` and where dots (`.`) delimit Julienne operators. The above expression containing Julienne operators evaluates to a Julienne `test_diagnosis_t` object, whereas -expression on the subsequent line containing intrinsic operators evaluates to a -`logical` value. If an assertion containing a Julienne expression fails, the -error stop code will contain diagnostic information constructed automatically by -Julienne. If an assertion containing a `logical` experession evaluates to `false.`, -the error stop code will contain a literal copy of the expression. In either -case, the error stop code will also contain the file and line number, which the -function-like macro inserts automatically via the `__FILE__` and `__LINE__` macros, -respectively. +expression `allocated(a)` on the subsequent line evaluates to a `logical` value. +If an assertion containing a Julienne expression fails, Julienne inserts diagnostic +information into the stop code in an ultimate `error stop`. If an expression +evaluates to a `logical` value of `false.`, the error stop code will contain a +literal copy of the expression (e.g., `allocated(a)`). In either case, Julienne +also inserts the file and line number into the stop code using via the `__FILE__` +and `__LINE__` macros, respectively. Most compilers write the resulting stop code +to `error_unit`. ### Writing Unit Tests Writing tests using Julienne involves constructing a test-description array, From 88b578088601871e613265492c80eea921e07a44 Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Tue, 5 Aug 2025 21:53:54 -0500 Subject: [PATCH 04/11] fix(assert_test): test function name --- test/modules/assert_test_m.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/modules/assert_test_m.F90 b/test/modules/assert_test_m.F90 index 68fbca1e6..857511463 100644 --- a/test/modules/assert_test_m.F90 +++ b/test/modules/assert_test_m.F90 @@ -66,7 +66,7 @@ function results() result(test_results) ,check_macro_with_logical_assertion_ptr => check_macro_with_logical_assertion descriptions = [ & - test_description_t("invocation via macro with an expression containing Julienne operators", check_macro_with_expression_ptr)& + test_description_t("invocation via macro with an expression containing Julienne operators", check_macro_with_julienne_idiom_ptr) & ,test_description_t("invocation with a logical expression", check_macro_with_logical_assertion_ptr) & ] From 17fdf41d2c6f243cd88a64e847d0405819e71137 Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Wed, 6 Aug 2025 06:58:07 -0700 Subject: [PATCH 05/11] chore(fpm): update to Assert 3.0.2 --- fpm.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpm.toml b/fpm.toml index a2d5f1dd2..251ef84ee 100644 --- a/fpm.toml +++ b/fpm.toml @@ -1,7 +1,7 @@ name = "julienne" [dependencies] -assert = {git = "https://github.com/berkeleylab/assert", tag = "3.0.0"} +assert = {git = "https://github.com/berkeleylab/assert", tag = "3.0.2"} [install] library = true From f3b749d162eafd75bc3ffee4a26f3c5e023de7c8 Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Wed, 6 Aug 2025 06:58:32 -0700 Subject: [PATCH 06/11] feat: switch assertions to call_julienne_assert --- src/julienne/julienne_bin_s.F90 | 6 ++--- src/julienne/julienne_file_s.F90 | 8 +++---- src/julienne/julienne_string_s.F90 | 23 ++++++++++--------- src/julienne/julienne_test_description_s.F90 | 16 ++++++------- src/julienne/julienne_test_diagnosis_s.F90 | 7 +++--- .../julienne_vector_test_description_s.F90 | 8 +++---- 6 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/julienne/julienne_bin_s.F90 b/src/julienne/julienne_bin_s.F90 index 094352195..a9be91e13 100644 --- a/src/julienne/julienne_bin_s.F90 +++ b/src/julienne/julienne_bin_s.F90 @@ -1,17 +1,17 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt -#include "assert_macros.h" +#include "julienne-assert-macros.h" submodule(julienne_bin_m) julienne_bin_s - use assert_m + use julienne_m, only : call_julienne_assert_, operator(.isAtLeast.) implicit none contains module procedure construct - call_assert(num_items>=num_bins) + call_julienne_assert(num_items .isAtLeast. num_bins) associate( remainder => mod(num_items, num_bins), items_per_bin => num_items/num_bins) diff --git a/src/julienne/julienne_file_s.F90 b/src/julienne/julienne_file_s.F90 index a8c689827..58dba4080 100644 --- a/src/julienne/julienne_file_s.F90 +++ b/src/julienne/julienne_file_s.F90 @@ -1,11 +1,11 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt -#include "assert_macros.h" +#include "julienne-assert-macros.h" submodule(julienne_file_m) julienne_file_s use iso_fortran_env, only : iostat_end, iostat_eor, output_unit - use assert_m + use julienne_m, only : call_julienne_assert_ implicit none contains @@ -17,7 +17,7 @@ module procedure write_to_output_unit integer l - call_assert(allocated(self%lines_)) + call_julienne_assert(allocated(self%lines_)) do l = 1, size(self%lines_) write(output_unit, '(a)') self%lines_(l)%string() @@ -27,7 +27,7 @@ module procedure write_to_character_file_name integer file_unit, l - call_assert(allocated(self%lines_)) + call_julienne_assert(allocated(self%lines_)) open(newunit=file_unit, file=file_name, form='formatted', status='unknown', action='write') diff --git a/src/julienne/julienne_string_s.F90 b/src/julienne/julienne_string_s.F90 index 77306e7a5..fef51a7f5 100644 --- a/src/julienne/julienne_string_s.F90 +++ b/src/julienne/julienne_string_s.F90 @@ -1,9 +1,10 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt -#include "assert_macros.h" + +#include "julienne-assert-macros.h" submodule(julienne_string_m) julienne_string_s - use assert_m + use julienne_m, only : call_julienne_assert_, operator(.equalsExpected.) implicit none integer, parameter :: integer_width_supremum = 11, default_real_width_supremum = 20, double_precision_width_supremum = 25 @@ -185,7 +186,7 @@ module procedure get_real character(len=:), allocatable :: raw_line, string_value - call_assert(key==self%get_json_key()) + call_julienne_assert(key .equalsExpected. self%get_json_key()) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -204,7 +205,7 @@ module procedure get_double_precision character(len=:), allocatable :: raw_line, string_value - call_assert(key==self%get_json_key()) + call_julienne_assert(key==self%get_json_key()) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -247,7 +248,7 @@ character(len=:), allocatable :: raw_line integer i, comma, opening_quotes, closing_quotes - call_assert(key==self%get_json_key()) + call_julienne_assert(key .equalsExpected. self%get_json_key()) raw_line = self%string() @@ -275,7 +276,7 @@ character(len=:), allocatable :: raw_line - call_assert(key==self%get_json_key()) + call_julienne_assert(key .equalsExpected. self%get_json_key()) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -299,7 +300,7 @@ module procedure get_logical character(len=:), allocatable :: raw_line, string_value - call_assert(key==self%get_json_key()) + call_julienne_assert(key .equalsExpected.self%get_json_key()) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -309,7 +310,7 @@ else string_value = trim(adjustl((text_after_colon(:trailing_comma-1)))) end if - call_assert(string_value=="true" .or. string_value=="false") + call_julienne_assert(any(string_value==["true","false"])) value_ = string_value == "true" end associate end associate @@ -319,7 +320,7 @@ module procedure get_integer character(len=:), allocatable :: raw_line, string_value - call_assert(key==self%get_json_key()) + call_julienne_assert(key .equalsExpected. self%get_json_key()) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -360,7 +361,7 @@ real, allocatable :: real_array(:) integer i - call_assert(key==self%get_json_key()) + call_julienne_assert(key .equalsExpected. self%get_json_key()) raw_line = self%string() associate(colon => index(raw_line, ":")) @@ -384,7 +385,7 @@ double precision, allocatable :: double_precision_array(:) integer i - call_assert(key==self%get_json_key()) + call_julienne_assert(key .equalsExpected. self%get_json_key()) raw_line = self%string() associate(colon => index(raw_line, ":")) diff --git a/src/julienne/julienne_test_description_s.F90 b/src/julienne/julienne_test_description_s.F90 index 45c3dffbd..ee428519e 100644 --- a/src/julienne/julienne_test_description_s.F90 +++ b/src/julienne/julienne_test_description_s.F90 @@ -1,27 +1,27 @@ ! Copyright (c) 20242-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt -#include "assert_macros.h" +#include "julienne-assert-macros.h" submodule(julienne_test_description_m) julienne_test_description_s - use assert_m + use julienne_m, only : call_julienne_assert_ implicit none contains module procedure construct_from_characters test_description%description_ = description if (present(diagnosis_function)) test_description%diagnosis_function_ => diagnosis_function - call_assert(allocated(test_description%description_)) + call_julienne_assert(allocated(test_description%description_)) end procedure module procedure construct_from_string test_description%description_ = description if (present(diagnosis_function)) test_description%diagnosis_function_ => diagnosis_function - call_assert(allocated(test_description%description_)) + call_julienne_assert(allocated(test_description%description_)) end procedure module procedure run - call_assert(allocated(self%description_)) + call_julienne_assert(allocated(self%description_)) if (associated(self%diagnosis_function_)) then test_result = test_result_t(self%description_, self%diagnosis_function_()) else @@ -30,17 +30,17 @@ end procedure module procedure contains_string_t - call_assert(allocated(self%description_)) + call_julienne_assert(allocated(self%description_)) match = index(self%description_, substring%string()) /= 0 end procedure module procedure contains_characters - call_assert(allocated(self%description_)) + call_julienne_assert(allocated(self%description_)) match = index(self%description_, substring) /= 0 end procedure module procedure equals - call_assert(allocated(lhs%description_) .and. allocated(rhs%description_)) + call_julienne_assert(allocated(lhs%description_) .and. allocated(rhs%description_)) lhs_eq_rhs = (lhs%description_ == rhs%description_) if (associated(lhs%diagnosis_function_) .and. associated(rhs%diagnosis_function_)) & lhs_eq_rhs = lhs_eq_rhs .and. associated(lhs%diagnosis_function_, rhs%diagnosis_function_) diff --git a/src/julienne/julienne_test_diagnosis_s.F90 b/src/julienne/julienne_test_diagnosis_s.F90 index 6fd2a4d50..ad373156a 100644 --- a/src/julienne/julienne_test_diagnosis_s.F90 +++ b/src/julienne/julienne_test_diagnosis_s.F90 @@ -2,11 +2,12 @@ ! Terms of use are as specified in LICENSE.txt #include "language-support.F90" +#include "julienne-assert-macros.h" #include "assert_macros.h" submodule(julienne_test_diagnosis_m) julienne_test_diagnosis_s - use assert_m - use julienne_string_m, only : operator(.csv.), operator(.cat.) + use assert_m, only : assert_always + use julienne_m, only : operator(.csv.), operator(.cat.), call_julienne_assert_ implicit none contains @@ -537,7 +538,7 @@ pure function aggregate_vector_diagnosis(diagnoses) result(diagnosis) end procedure module procedure diagnostics_string - call_assert(allocated(self%diagnostics_string_)) + call_julienne_assert(allocated(self%diagnostics_string_)) string_ = string_t(self%diagnostics_string_) end procedure diff --git a/src/julienne/julienne_vector_test_description_s.F90 b/src/julienne/julienne_vector_test_description_s.F90 index fd091d79b..aff1a1934 100644 --- a/src/julienne/julienne_vector_test_description_s.F90 +++ b/src/julienne/julienne_vector_test_description_s.F90 @@ -1,17 +1,17 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt -#include "assert_macros.h" +#include "julienne-assert-macros.h" submodule(julienne_vector_test_description_m) julienne_vector_test_description_s - use assert_m + use julienne_m, only : call_julienne_assert_ implicit none contains module procedure contains_characters integer i - call_assert(allocated(self%descriptions_)) + call_julienne_assert(allocated(self%descriptions_)) match_vector = [(index(self%descriptions_(i)%string(), substring) /= 0, i = 1, size(self%descriptions_))] end procedure @@ -45,7 +45,7 @@ module function construct_from_strings(descriptions, vector_diagnosis_function) associate(diagnoses => self%vector_diagnosis_function_()) #if defined(ASSERTIONS) associate(num_descriptions => size(self%descriptions_), num_results => size(diagnoses)) - call_assert(num_descriptions == num_results) + call_julienne_assert(num_descriptions == num_results) end associate #endif test_results = test_result_t(self%descriptions_, diagnoses) From 849721a50f51a91101c65f8f2ed88f995f9370ad Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Wed, 6 Aug 2025 07:23:53 -0700 Subject: [PATCH 07/11] refac: mv assert utils to separate mod, submod --- src/julienne/julienne_assert_m.f90 | 38 +++++++++++++++++++ src/julienne/julienne_assert_s.f90 | 27 +++++++++++++ src/julienne/julienne_command_line_m.f90 | 1 + src/julienne/julienne_command_line_s.f90 | 1 + src/julienne/julienne_file_m.f90 | 1 + src/julienne/julienne_formats_m.F90 | 1 + src/julienne/julienne_formats_s.F90 | 1 + src/julienne/julienne_github_ci_m.f90 | 1 + src/julienne/julienne_github_ci_s.f90 | 1 + src/julienne/julienne_string_m.f90 | 1 + src/julienne/julienne_test_description_m.f90 | 1 + src/julienne/julienne_test_diagnosis_m.F90 | 30 +-------------- src/julienne/julienne_test_diagnosis_s.F90 | 18 --------- src/julienne/julienne_test_result_m.f90 | 1 + src/julienne/julienne_test_result_s.f90 | 1 + .../julienne_user_defined_collectives_m.f90 | 1 + .../julienne_vector_test_description_m.F90 | 1 + src/julienne_m.f90 | 18 ++++----- 18 files changed, 88 insertions(+), 56 deletions(-) create mode 100644 src/julienne/julienne_assert_m.f90 create mode 100644 src/julienne/julienne_assert_s.f90 diff --git a/src/julienne/julienne_assert_m.f90 b/src/julienne/julienne_assert_m.f90 new file mode 100644 index 000000000..8b8155fb0 --- /dev/null +++ b/src/julienne/julienne_assert_m.f90 @@ -0,0 +1,38 @@ +! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute +! Terms of use are as specified in LICENSE.txt + +module julienne_assert_m + !! Define interfaces for writing assertions + use julienne_test_diagnosis_m, only : test_diagnosis_t + implicit none + + private + public :: call_julienne_assert_ + public :: julienne_assert + + interface call_julienne_assert_ + + pure module subroutine julienne_assert(test_diagnosis, file, line) + !! Public procedure. + !! Use cases: + !! 1. When invoked via the generic interface, the preprocessor passes the 'file' and 'line' dummy arguments automatically. + !! 2. When invoked directly, there is 1 argument: an expression containing defined operations such as 1 .equalsExpected. 1 + implicit none + type(test_diagnosis_t), intent(in) :: test_diagnosis + character(len=*), intent(in), optional :: file + integer, intent(in), optional :: line + end subroutine + + pure module subroutine assert_assert(assertion, file, line) + !! Private wrapper for the assert subroutine in the Assert library (https://go.lbl.gov/assert). + !! Invoke this procedure via the call_julienne_assert_ generic interface with only the required logical argument. + !! The preprocessor will insert the optional 'file' and 'line' arguments. + implicit none + logical, intent(in) :: assertion + character(len=*), intent(in), optional :: file + integer, intent(in), optional :: line + end subroutine + + end interface + +end module julienne_assert_m diff --git a/src/julienne/julienne_assert_s.f90 b/src/julienne/julienne_assert_s.f90 new file mode 100644 index 000000000..d680d843e --- /dev/null +++ b/src/julienne/julienne_assert_s.f90 @@ -0,0 +1,27 @@ +! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute +! Terms of use are as specified in LICENSE.txt + +submodule(julienne_assert_m) julienne_assert_s + use assert_m, only : assert_always + use julienne_m, only : string_t + implicit none + +contains + + module procedure julienne_assert + character(len=:), allocatable :: diagnostics_string + diagnostics_string = test_diagnosis%diagnostics_string_ + if (present(file)) diagnostics_string = diagnostics_string // " in file " // file + if (present(line)) diagnostics_string = diagnostics_string // " at line " // string_t(line) + call assert_always(test_diagnosis%test_passed_, diagnostics_string) + end procedure + + module procedure assert_assert + character(len=:), allocatable :: diagnostics_string + diagnostics_string = "" + if (present(file)) diagnostics_string = diagnostics_string // " in file " // file + if (present(line)) diagnostics_string = diagnostics_string // " at line " // string_t(line) + call assert_always(assertion, diagnostics_string) + end procedure + +end submodule julienne_assert_s diff --git a/src/julienne/julienne_command_line_m.f90 b/src/julienne/julienne_command_line_m.f90 index 5c13d1276..c555d7e0d 100644 --- a/src/julienne/julienne_command_line_m.f90 +++ b/src/julienne/julienne_command_line_m.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_command_line_m !! return command line argument information implicit none diff --git a/src/julienne/julienne_command_line_s.f90 b/src/julienne/julienne_command_line_s.f90 index ddffdcc59..5413b87dd 100644 --- a/src/julienne/julienne_command_line_s.f90 +++ b/src/julienne/julienne_command_line_s.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + submodule(julienne_command_line_m) julienne_command_line_s implicit none diff --git a/src/julienne/julienne_file_m.f90 b/src/julienne/julienne_file_m.f90 index 1fae2a5cf..7a113638b 100644 --- a/src/julienne/julienne_file_m.f90 +++ b/src/julienne/julienne_file_m.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_file_m !! A representation of a file as an object use julienne_string_m, only : string_t diff --git a/src/julienne/julienne_formats_m.F90 b/src/julienne/julienne_formats_m.F90 index 386b8d08f..345201516 100644 --- a/src/julienne/julienne_formats_m.F90 +++ b/src/julienne/julienne_formats_m.F90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_formats_m !! Useful strings for formatting `print` and `write` statements implicit none diff --git a/src/julienne/julienne_formats_s.F90 b/src/julienne/julienne_formats_s.F90 index 62adb6680..f2f3ac3d3 100644 --- a/src/julienne/julienne_formats_s.F90 +++ b/src/julienne/julienne_formats_s.F90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + submodule(julienne_formats_m) julienne_formats_s !! Construct separated-value formats implicit none diff --git a/src/julienne/julienne_github_ci_m.f90 b/src/julienne/julienne_github_ci_m.f90 index 466085dc7..c43c7b8da 100644 --- a/src/julienne/julienne_github_ci_m.f90 +++ b/src/julienne/julienne_github_ci_m.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_github_ci_m !! Detect whether a program is running in GitHub Continuous Integration (CI) implicit none diff --git a/src/julienne/julienne_github_ci_s.f90 b/src/julienne/julienne_github_ci_s.f90 index 893ee1824..37eedb17d 100644 --- a/src/julienne/julienne_github_ci_s.f90 +++ b/src/julienne/julienne_github_ci_s.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + submodule(julienne_github_ci_m) julienne_github_ci_s implicit none diff --git a/src/julienne/julienne_string_m.f90 b/src/julienne/julienne_string_m.f90 index ed5c4a5fb..6742273af 100644 --- a/src/julienne/julienne_string_m.f90 +++ b/src/julienne/julienne_string_m.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_string_m use iso_c_binding, only : c_bool implicit none diff --git a/src/julienne/julienne_test_description_m.f90 b/src/julienne/julienne_test_description_m.f90 index 432ad7201..29deb2d16 100644 --- a/src/julienne/julienne_test_description_m.f90 +++ b/src/julienne/julienne_test_description_m.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_test_description_m !! Define an abstraction for describing test intentions and test functions use julienne_string_m, only : string_t diff --git a/src/julienne/julienne_test_diagnosis_m.F90 b/src/julienne/julienne_test_diagnosis_m.F90 index 02d51e6c6..6e1d61e47 100644 --- a/src/julienne/julienne_test_diagnosis_m.F90 +++ b/src/julienne/julienne_test_diagnosis_m.F90 @@ -4,15 +4,12 @@ #include "language-support.F90" module julienne_test_diagnosis_m - !! Define abstractions, defined operations, and procedures for writing correctness checks in - !! the form of assertions and tests. + !! Define abstractions, defined operations, and procedures for writing correctness checks use julienne_string_m, only : string_t implicit none private public :: test_diagnosis_t - public :: call_julienne_assert_ - public :: julienne_assert public :: operator(.all.) public :: operator(.and.) public :: operator(.also.) @@ -57,31 +54,6 @@ module julienne_test_diagnosis_m end type #endif - interface call_julienne_assert_ - - pure module subroutine julienne_assert(test_diagnosis, file, line) - !! Public procedure. - !! Use cases: - !! 1. When invoked via the generic interface, the preprocessor passes the 'file' and 'line' dummy arguments automatically. - !! 2. When invoked directly, there is 1 argument: an expression containing defined operations such as 1 .equalsExpected. 1 - implicit none - type(test_diagnosis_t), intent(in) :: test_diagnosis - character(len=*), intent(in), optional :: file - integer, intent(in), optional :: line - end subroutine - - pure module subroutine assert_assert(assertion, file, line) - !! Private wrapper for the assert subroutine in the Assert library (https://go.lbl.gov/assert). - !! Invoke this procedure via the call_julienne_assert_ generic interface with only the required logical argument. - !! The preprocessor will insert the optional 'file' and 'line' arguments. - implicit none - logical, intent(in) :: assertion - character(len=*), intent(in), optional :: file - integer, intent(in), optional :: line - end subroutine - - end interface - interface operator(.all.) #ifndef __GFORTRAN__ diff --git a/src/julienne/julienne_test_diagnosis_s.F90 b/src/julienne/julienne_test_diagnosis_s.F90 index ad373156a..17b3fe677 100644 --- a/src/julienne/julienne_test_diagnosis_s.F90 +++ b/src/julienne/julienne_test_diagnosis_s.F90 @@ -3,10 +3,8 @@ #include "language-support.F90" #include "julienne-assert-macros.h" -#include "assert_macros.h" submodule(julienne_test_diagnosis_m) julienne_test_diagnosis_s - use assert_m, only : assert_always use julienne_m, only : operator(.csv.), operator(.cat.), call_julienne_assert_ implicit none contains @@ -542,20 +540,4 @@ pure function aggregate_vector_diagnosis(diagnoses) result(diagnosis) string_ = string_t(self%diagnostics_string_) end procedure - module procedure julienne_assert - character(len=:), allocatable :: diagnostics_string - diagnostics_string = test_diagnosis%diagnostics_string_ - if (present(file)) diagnostics_string = diagnostics_string // " in file " // file - if (present(line)) diagnostics_string = diagnostics_string // " at line " // string_t(line) - call assert_always(test_diagnosis%test_passed_, diagnostics_string) - end procedure - - module procedure assert_assert - character(len=:), allocatable :: diagnostics_string - diagnostics_string = "" - if (present(file)) diagnostics_string = diagnostics_string // " in file " // file - if (present(line)) diagnostics_string = diagnostics_string // " at line " // string_t(line) - call assert_always(assertion, diagnostics_string) - end procedure - end submodule julienne_test_diagnosis_s diff --git a/src/julienne/julienne_test_result_m.f90 b/src/julienne/julienne_test_result_m.f90 index dcca9e018..bbb48ece1 100644 --- a/src/julienne/julienne_test_result_m.f90 +++ b/src/julienne/julienne_test_result_m.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_test_result_m !! Define an abstraction for describing test intentions and results use julienne_string_m, only : string_t diff --git a/src/julienne/julienne_test_result_s.f90 b/src/julienne/julienne_test_result_s.f90 index 166529109..7ab620c41 100644 --- a/src/julienne/julienne_test_result_s.f90 +++ b/src/julienne/julienne_test_result_s.f90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + submodule(julienne_test_result_m) julienne_test_result_s use julienne_user_defined_collectives_m, only : co_all implicit none diff --git a/src/julienne/julienne_user_defined_collectives_m.f90 b/src/julienne/julienne_user_defined_collectives_m.f90 index 2c8da12da..57973a3e7 100644 --- a/src/julienne/julienne_user_defined_collectives_m.f90 +++ b/src/julienne/julienne_user_defined_collectives_m.f90 @@ -4,6 +4,7 @@ ! "Multi-Dimensional Physics Implementation into Fuel Analysis under Steady-state and Transients (FAST)", ! contract # NRC-HQ-60-17-C-0007 ! + module julienne_user_defined_collectives_m !! User-defined collective subroutines. implicit none diff --git a/src/julienne/julienne_vector_test_description_m.F90 b/src/julienne/julienne_vector_test_description_m.F90 index d3ac452eb..4d3da0a7a 100644 --- a/src/julienne/julienne_vector_test_description_m.F90 +++ b/src/julienne/julienne_vector_test_description_m.F90 @@ -1,5 +1,6 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_vector_test_description_m !! Define an abstraction for describing test intentions and array-valued test functions use julienne_string_m, only : string_t diff --git a/src/julienne_m.f90 b/src/julienne_m.f90 index cd232fa14..1540f6556 100644 --- a/src/julienne_m.f90 +++ b/src/julienne_m.f90 @@ -1,17 +1,24 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt + module julienne_m !! Global aggregation of all public entities + use julienne_assert_m, only : call_julienne_assert_, julienne_assert use julienne_bin_m, only : bin_t use julienne_command_line_m, only : command_line_t use julienne_file_m, only : file_t use julienne_formats_m, only : separated_values, csv use julienne_github_ci_m, only : github_ci + use julienne_string_m, only : & + string_t & + ,array_of_strings & + ,operator(.cat.) & + ,operator(.csv.) & + ,operator(.separatedBy.) & ! same as operator(.sv.) + ,operator(.sv.) use julienne_test_description_m, only : test_description_t, diagnosis_function_i use julienne_test_diagnosis_m, only : & test_diagnosis_t & - ,call_julienne_assert_ & - ,julienne_assert & ,operator(.all.) & ,operator(.and.) & ,operator(.also.) & @@ -28,13 +35,6 @@ module julienne_m ,operator(.within.) & ,operator(.withinFraction.) & ,operator(.withinPercentage.) - use julienne_string_m, only : & - string_t & - ,array_of_strings & - ,operator(.cat.) & - ,operator(.csv.) & - ,operator(.separatedBy.) & ! same as operator(.sv.) - ,operator(.sv.) use julienne_test_m, only : test_t, test_description_substring use julienne_test_result_m, only : test_result_t From bdb6d476cc21e1fbe0c90c7f6ed648ec706771ea Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Wed, 6 Aug 2025 08:48:20 -0700 Subject: [PATCH 08/11] fix(assert): use test_{passed,diagnostics} getters --- src/julienne/julienne_assert_s.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/julienne/julienne_assert_s.f90 b/src/julienne/julienne_assert_s.f90 index d680d843e..cdb86d93e 100644 --- a/src/julienne/julienne_assert_s.f90 +++ b/src/julienne/julienne_assert_s.f90 @@ -10,10 +10,10 @@ module procedure julienne_assert character(len=:), allocatable :: diagnostics_string - diagnostics_string = test_diagnosis%diagnostics_string_ + diagnostics_string = test_diagnosis%diagnostics_string() if (present(file)) diagnostics_string = diagnostics_string // " in file " // file if (present(line)) diagnostics_string = diagnostics_string // " at line " // string_t(line) - call assert_always(test_diagnosis%test_passed_, diagnostics_string) + call assert_always(test_diagnosis%test_passed(), diagnostics_string) end procedure module procedure assert_assert From 209b95782a9ce5001bc458c5beb9e65dfce54319 Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Wed, 6 Aug 2025 08:56:41 -0700 Subject: [PATCH 09/11] fix(assert_test): def macro_with_logical result --- test/modules/assert_test_m.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/test/modules/assert_test_m.F90 b/test/modules/assert_test_m.F90 index 857511463..b1ad58566 100644 --- a/test/modules/assert_test_m.F90 +++ b/test/modules/assert_test_m.F90 @@ -93,6 +93,7 @@ function check_macro_with_julienne_idiom() result(test_diagnosis) function check_macro_with_logical_assertion() result(test_diagnosis) type(test_diagnosis_t) test_diagnosis call_julienne_assert(1==1) + test_diagnosis = test_diagnosis_t(.true., "") end function end module assert_test_m From 4b6f19eaee6300cb2ca6223b2dd935af11d6e67a Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Wed, 6 Aug 2025 08:59:58 -0700 Subject: [PATCH 10/11] feat(test_diagnosis_t): default-init test_passed_ This commit default-initializes the test_diagnosis_t test_passed_ component to .false. --- src/julienne/julienne_test_diagnosis_m.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/julienne/julienne_test_diagnosis_m.F90 b/src/julienne/julienne_test_diagnosis_m.F90 index 6e1d61e47..901866a84 100644 --- a/src/julienne/julienne_test_diagnosis_m.F90 +++ b/src/julienne/julienne_test_diagnosis_m.F90 @@ -30,7 +30,7 @@ module julienne_test_diagnosis_m type test_diagnosis_t !! Encapsulate test outcome and diagnostic information private - logical test_passed_ + logical :: test_passed_ = .false. character(len=:), allocatable :: diagnostics_string_ contains procedure test_passed From 655e848277bc26d73dba7946b26ebd6b51982c25 Mon Sep 17 00:00:00 2001 From: Damian Rouson Date: Wed, 6 Aug 2025 20:10:48 -0700 Subject: [PATCH 11/11] chore/fix/doc/test: macro removal, array constructor This commit 1. Adds a test of the removal of the call_assert_julienne function-like macro when the ASSERTIONS macro is undefined and 2. Fixes a character array constructor to have same-length elements. 3. Improves the documenation of the julienne_assert subroutine. 4. Rewrites some assertions for clarity (reversing operands). 5. Removes assert_assert and directs users to the Assert library for similar functionality. --- src/julienne/julienne_assert_m.f90 | 43 +++++++++++++------ src/julienne/julienne_assert_s.f90 | 8 ---- src/julienne/julienne_file_s.F90 | 8 ++-- src/julienne/julienne_string_s.F90 | 20 +++++---- src/julienne/julienne_test_description_s.F90 | 14 +++--- src/julienne/julienne_test_diagnosis_s.F90 | 7 +-- .../julienne_vector_test_description_s.F90 | 8 ++-- test/false-assertion.F90 | 18 -------- test/modules/assert_test_m.F90 | 43 ++++++++++++------- ...st-julienne_assert-intentional-failure.F90 | 26 +++++++++++ 10 files changed, 115 insertions(+), 80 deletions(-) delete mode 100644 test/false-assertion.F90 create mode 100644 test/test-julienne_assert-intentional-failure.F90 diff --git a/src/julienne/julienne_assert_m.f90 b/src/julienne/julienne_assert_m.f90 index 8b8155fb0..8fe2570ae 100644 --- a/src/julienne/julienne_assert_m.f90 +++ b/src/julienne/julienne_assert_m.f90 @@ -13,26 +13,41 @@ module julienne_assert_m interface call_julienne_assert_ pure module subroutine julienne_assert(test_diagnosis, file, line) - !! Public procedure. - !! Use cases: - !! 1. When invoked via the generic interface, the preprocessor passes the 'file' and 'line' dummy arguments automatically. - !! 2. When invoked directly, there is 1 argument: an expression containing defined operations such as 1 .equalsExpected. 1 + !! This subroutine wraps the Assert library's `assert` subroutine. + !! + !! Use Cases + !! --------- + !! 1. Invoke julienne_assert via the generic interface `call_julienne_assert` to + !! facilitate complete removal when compiling without the flag `-DASSERTIONS`. + !! 2. Invoke julienne_assert via direct procedure call to guarantee execution. + !! + !! Usage + !! ----- + !! Make the only actual argument an expression containing `test_diagnosis_t` defined + !! operations, such as `x .approximates. y .within. tolerance`. The expression + !! result will be a `test_diagnosis_t` object on which `julienne_assert` will invoke + !! the `diagnostics_string()` type-bound procedure, the result of which julienne_assert + !! will include in the stop code of an `error stop` if the expresssion is untrue. + !! The resulting stop code will contain such information as the operand values and + !! roles (expected value, actual value, tolerance value). In use case 1, compiling + !! with `-DASSERTIONS` will cause the preprocessor to insert the corresponding + !! invocations's line number and the encompassing file's name as the `file` and `line` + !! arguments, respectively, which `julienne_assert` will include in the stop code. + !! Most compilers will write the stop code to `error_unit`. + !! + !! If a literal reproduction of the test expression suffices, such as when the + !! expression is `allocated(a)`, then instead invoke the Assert library's `assert` + !! subroutine by that library's `call_assert` macro or by direct call. + !! When invoking via the macro, make the only actual argument, `assertion`, a + !! `logical` expression. Then if compiling with `-DASSERTIONS` and if the assertion + !! evaluates to `.false.`, the stop code will include the text of the expression + !! argument, the file name, and the line number of the `call_assert` macro invocation. implicit none type(test_diagnosis_t), intent(in) :: test_diagnosis character(len=*), intent(in), optional :: file integer, intent(in), optional :: line end subroutine - pure module subroutine assert_assert(assertion, file, line) - !! Private wrapper for the assert subroutine in the Assert library (https://go.lbl.gov/assert). - !! Invoke this procedure via the call_julienne_assert_ generic interface with only the required logical argument. - !! The preprocessor will insert the optional 'file' and 'line' arguments. - implicit none - logical, intent(in) :: assertion - character(len=*), intent(in), optional :: file - integer, intent(in), optional :: line - end subroutine - end interface end module julienne_assert_m diff --git a/src/julienne/julienne_assert_s.f90 b/src/julienne/julienne_assert_s.f90 index cdb86d93e..a3380069e 100644 --- a/src/julienne/julienne_assert_s.f90 +++ b/src/julienne/julienne_assert_s.f90 @@ -16,12 +16,4 @@ call assert_always(test_diagnosis%test_passed(), diagnostics_string) end procedure - module procedure assert_assert - character(len=:), allocatable :: diagnostics_string - diagnostics_string = "" - if (present(file)) diagnostics_string = diagnostics_string // " in file " // file - if (present(line)) diagnostics_string = diagnostics_string // " at line " // string_t(line) - call assert_always(assertion, diagnostics_string) - end procedure - end submodule julienne_assert_s diff --git a/src/julienne/julienne_file_s.F90 b/src/julienne/julienne_file_s.F90 index 58dba4080..a8c689827 100644 --- a/src/julienne/julienne_file_s.F90 +++ b/src/julienne/julienne_file_s.F90 @@ -1,11 +1,11 @@ ! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute ! Terms of use are as specified in LICENSE.txt -#include "julienne-assert-macros.h" +#include "assert_macros.h" submodule(julienne_file_m) julienne_file_s use iso_fortran_env, only : iostat_end, iostat_eor, output_unit - use julienne_m, only : call_julienne_assert_ + use assert_m implicit none contains @@ -17,7 +17,7 @@ module procedure write_to_output_unit integer l - call_julienne_assert(allocated(self%lines_)) + call_assert(allocated(self%lines_)) do l = 1, size(self%lines_) write(output_unit, '(a)') self%lines_(l)%string() @@ -27,7 +27,7 @@ module procedure write_to_character_file_name integer file_unit, l - call_julienne_assert(allocated(self%lines_)) + call_assert(allocated(self%lines_)) open(newunit=file_unit, file=file_name, form='formatted', status='unknown', action='write') diff --git a/src/julienne/julienne_string_s.F90 b/src/julienne/julienne_string_s.F90 index fef51a7f5..f5323805c 100644 --- a/src/julienne/julienne_string_s.F90 +++ b/src/julienne/julienne_string_s.F90 @@ -2,8 +2,10 @@ ! Terms of use are as specified in LICENSE.txt #include "julienne-assert-macros.h" +#include "assert_macros.h" submodule(julienne_string_m) julienne_string_s + use assert_m use julienne_m, only : call_julienne_assert_, operator(.equalsExpected.) implicit none @@ -186,7 +188,7 @@ module procedure get_real character(len=:), allocatable :: raw_line, string_value - call_julienne_assert(key .equalsExpected. self%get_json_key()) + call_julienne_assert(self%get_json_key() .equalsExpected. key) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -205,7 +207,7 @@ module procedure get_double_precision character(len=:), allocatable :: raw_line, string_value - call_julienne_assert(key==self%get_json_key()) + call_julienne_assert(self%get_json_key() .equalsExpected. key) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -248,7 +250,7 @@ character(len=:), allocatable :: raw_line integer i, comma, opening_quotes, closing_quotes - call_julienne_assert(key .equalsExpected. self%get_json_key()) + call_julienne_assert(self%get_json_key() .equalsExpected. key) raw_line = self%string() @@ -276,7 +278,7 @@ character(len=:), allocatable :: raw_line - call_julienne_assert(key .equalsExpected. self%get_json_key()) + call_julienne_assert(self%get_json_key() .equalsExpected. key) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -300,7 +302,7 @@ module procedure get_logical character(len=:), allocatable :: raw_line, string_value - call_julienne_assert(key .equalsExpected.self%get_json_key()) + call_julienne_assert(self%get_json_key() .equalsExpected. key) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -310,7 +312,7 @@ else string_value = trim(adjustl((text_after_colon(:trailing_comma-1)))) end if - call_julienne_assert(any(string_value==["true","false"])) + call_assert(any(string_value==['true ', 'false'])) value_ = string_value == "true" end associate end associate @@ -320,7 +322,7 @@ module procedure get_integer character(len=:), allocatable :: raw_line, string_value - call_julienne_assert(key .equalsExpected. self%get_json_key()) + call_julienne_assert(self%get_json_key() .equalsExpected. key) raw_line = self%string() associate(text_after_colon => raw_line(index(raw_line, ':')+1:)) @@ -361,7 +363,7 @@ real, allocatable :: real_array(:) integer i - call_julienne_assert(key .equalsExpected. self%get_json_key()) + call_julienne_assert(self%get_json_key() .equalsExpected. key) raw_line = self%string() associate(colon => index(raw_line, ":")) @@ -385,7 +387,7 @@ double precision, allocatable :: double_precision_array(:) integer i - call_julienne_assert(key .equalsExpected. self%get_json_key()) + call_julienne_assert(self%get_json_key() .equalsExpected. key) raw_line = self%string() associate(colon => index(raw_line, ":")) diff --git a/src/julienne/julienne_test_description_s.F90 b/src/julienne/julienne_test_description_s.F90 index ee428519e..5f0ed2328 100644 --- a/src/julienne/julienne_test_description_s.F90 +++ b/src/julienne/julienne_test_description_s.F90 @@ -2,8 +2,10 @@ ! Terms of use are as specified in LICENSE.txt #include "julienne-assert-macros.h" +#include "assert_macros.h" submodule(julienne_test_description_m) julienne_test_description_s + use assert_m use julienne_m, only : call_julienne_assert_ implicit none contains @@ -11,17 +13,17 @@ module procedure construct_from_characters test_description%description_ = description if (present(diagnosis_function)) test_description%diagnosis_function_ => diagnosis_function - call_julienne_assert(allocated(test_description%description_)) + call_assert(allocated(test_description%description_)) end procedure module procedure construct_from_string test_description%description_ = description if (present(diagnosis_function)) test_description%diagnosis_function_ => diagnosis_function - call_julienne_assert(allocated(test_description%description_)) + call_assert(allocated(test_description%description_)) end procedure module procedure run - call_julienne_assert(allocated(self%description_)) + call_assert(allocated(self%description_)) if (associated(self%diagnosis_function_)) then test_result = test_result_t(self%description_, self%diagnosis_function_()) else @@ -30,17 +32,17 @@ end procedure module procedure contains_string_t - call_julienne_assert(allocated(self%description_)) + call_assert(allocated(self%description_)) match = index(self%description_, substring%string()) /= 0 end procedure module procedure contains_characters - call_julienne_assert(allocated(self%description_)) + call_assert(allocated(self%description_)) match = index(self%description_, substring) /= 0 end procedure module procedure equals - call_julienne_assert(allocated(lhs%description_) .and. allocated(rhs%description_)) + call_assert(allocated(lhs%description_) .and. allocated(rhs%description_)) lhs_eq_rhs = (lhs%description_ == rhs%description_) if (associated(lhs%diagnosis_function_) .and. associated(rhs%diagnosis_function_)) & lhs_eq_rhs = lhs_eq_rhs .and. associated(lhs%diagnosis_function_, rhs%diagnosis_function_) diff --git a/src/julienne/julienne_test_diagnosis_s.F90 b/src/julienne/julienne_test_diagnosis_s.F90 index 17b3fe677..241a032b9 100644 --- a/src/julienne/julienne_test_diagnosis_s.F90 +++ b/src/julienne/julienne_test_diagnosis_s.F90 @@ -2,10 +2,11 @@ ! Terms of use are as specified in LICENSE.txt #include "language-support.F90" -#include "julienne-assert-macros.h" +#include "assert_macros.h" submodule(julienne_test_diagnosis_m) julienne_test_diagnosis_s - use julienne_m, only : operator(.csv.), operator(.cat.), call_julienne_assert_ + use assert_m + use julienne_m, only : operator(.cat.) implicit none contains @@ -536,7 +537,7 @@ pure function aggregate_vector_diagnosis(diagnoses) result(diagnosis) end procedure module procedure diagnostics_string - call_julienne_assert(allocated(self%diagnostics_string_)) + call_assert(allocated(self%diagnostics_string_)) string_ = string_t(self%diagnostics_string_) end procedure diff --git a/src/julienne/julienne_vector_test_description_s.F90 b/src/julienne/julienne_vector_test_description_s.F90 index aff1a1934..307593f14 100644 --- a/src/julienne/julienne_vector_test_description_s.F90 +++ b/src/julienne/julienne_vector_test_description_s.F90 @@ -2,16 +2,18 @@ ! Terms of use are as specified in LICENSE.txt #include "julienne-assert-macros.h" +#include "assert_macros.h" submodule(julienne_vector_test_description_m) julienne_vector_test_description_s - use julienne_m, only : call_julienne_assert_ + use julienne_m, only : call_julienne_assert_, operator(.equalsExpected.) + use assert_m implicit none contains module procedure contains_characters integer i - call_julienne_assert(allocated(self%descriptions_)) + call_assert(allocated(self%descriptions_)) match_vector = [(index(self%descriptions_(i)%string(), substring) /= 0, i = 1, size(self%descriptions_))] end procedure @@ -45,7 +47,7 @@ module function construct_from_strings(descriptions, vector_diagnosis_function) associate(diagnoses => self%vector_diagnosis_function_()) #if defined(ASSERTIONS) associate(num_descriptions => size(self%descriptions_), num_results => size(diagnoses)) - call_julienne_assert(num_descriptions == num_results) + call_julienne_assert(num_descriptions .equalsExpected. num_results) end associate #endif test_results = test_result_t(self%descriptions_, diagnoses) diff --git a/test/false-assertion.F90 b/test/false-assertion.F90 deleted file mode 100644 index 1fc4cbe12..000000000 --- a/test/false-assertion.F90 +++ /dev/null @@ -1,18 +0,0 @@ -! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute -! Terms of use are as specified in LICENSE.txt - -program false_assertion - !! Test an assertion that is hardwired to fail by directly calling julienne_assert - !! with a false test_diagnosis_t expression. - -#ifdef RUN_FALSE_ASSERTIONS - - use julienne_m, only : operator(.equalsExpected.), julienne_assert - implicit none - - call julienne_assert(1 .equalsExpected. 2) - -#endif - -end program - diff --git a/test/modules/assert_test_m.F90 b/test/modules/assert_test_m.F90 index b1ad58566..5933b469a 100644 --- a/test/modules/assert_test_m.F90 +++ b/test/modules/assert_test_m.F90 @@ -3,12 +3,15 @@ #include "language-support.F90" #include "julienne-assert-macros.h" +#include "assert_macros.h" module assert_test_m - !! Test Julienne's assert generic interface - + !! Test Julienne's call_julienne_assert generic interface + use assert_m ! Import call_assert macro use julienne_m, only : & call_julienne_assert_ & + ,julienne_assert & + ,operator(.equalsExpected.) & ,test_diagnosis_t & ,test_t & ,test_description_t & @@ -31,7 +34,7 @@ module assert_test_m pure function subject() result(specimen) character(len=:), allocatable :: specimen - specimen = "The call_julienne_assert macro" + specimen = "The julienne_assert subroutine" end function #if HAVE_PROCEDURE_ACTUAL_FOR_POINTER_DUMMY @@ -40,8 +43,9 @@ function results() result(test_results) type(test_result_t), allocatable :: test_results(:) associate(descriptions => [ & - test_description_t("invocation with an expression containing Julienne operators", check_macro_with_julienne_idiom) & - ,test_description_t("invocation with a logical expression", check_macro_with_logical_assertion) & + test_description_t("invocation via the call_julienne_assert macro", check_call_julienne_assert_macro) & + ,test_description_t("invocation via direct call", check_julienne_assert_call) & + ,test_description_t("invocation removal after undefining the ASSERTIONS macro", check_macro_removal) & ]) associate(substring_in_subject => index(subject(), test_description_substring) /= 0) associate(substring_in_test_diagnosis => descriptions%contains_text(test_description_substring)) @@ -62,12 +66,13 @@ function results() result(test_results) type(test_result_t), allocatable :: test_results(:) type(test_description_t), allocatable :: descriptions(:) procedure(diagnosis_function_i), pointer :: & - check_macro_with_julienne_idiom_ptr => check_macro_with_julienne_idiom & - ,check_macro_with_logical_assertion_ptr => check_macro_with_logical_assertion - + check_call_julienne_assert_macro_ptr => check_call_julienne_assert_macro & + ,check_julienne_assert_call_ptr => check_julienne_assert_call & + ,check_macro_removal_ptr => check_macro_removal descriptions = [ & - test_description_t("invocation via macro with an expression containing Julienne operators", check_macro_with_julienne_idiom_ptr) & - ,test_description_t("invocation with a logical expression", check_macro_with_logical_assertion_ptr) & + test_description_t("invoking the call_julienne_assert macro", check_call_julienne_assert_macro_ptr) & + ,test_description_t("directly calling julienne_assert", check_julienne_assert_call_ptr) & + ,test_description_t("removal when the ASSERTIONS macro is defined as 0", check_macro_removal_ptr) & ] block @@ -84,16 +89,24 @@ function results() result(test_results) #endif - function check_macro_with_julienne_idiom() result(test_diagnosis) + function check_call_julienne_assert_macro() result(test_diagnosis) type(test_diagnosis_t) test_diagnosis call_julienne_assert(1. .approximates. 2. .within. 3.) - test_diagnosis = test_diagnosis_t(.true., "") + test_diagnosis = test_diagnosis_t(test_passed=.true., diagnostics_string="") + end function + + function check_julienne_assert_call() result(test_diagnosis) + type(test_diagnosis_t) test_diagnosis + call julienne_assert(1. .approximates. 2. .within. 3.) + test_diagnosis = test_diagnosis_t(test_passed=.true., diagnostics_string="") end function - function check_macro_with_logical_assertion() result(test_diagnosis) + function check_macro_removal() result(test_diagnosis) type(test_diagnosis_t) test_diagnosis - call_julienne_assert(1==1) - test_diagnosis = test_diagnosis_t(.true., "") +#undef ASSERTIONS +#include "julienne-assert-macros.h" + call_julienne_assert(5 .equalsExpected. 9) + test_diagnosis = test_diagnosis_t(test_passed=.true., diagnostics_string="") end function end module assert_test_m diff --git a/test/test-julienne_assert-intentional-failure.F90 b/test/test-julienne_assert-intentional-failure.F90 new file mode 100644 index 000000000..1b30dda14 --- /dev/null +++ b/test/test-julienne_assert-intentional-failure.F90 @@ -0,0 +1,26 @@ +! Copyright (c) 2024-2025, The Regents of the University of California and Sourcery Institute +! Terms of use are as specified in LICENSE.txt + +#include "julienne-assert-macros.h" + +program test_julienne_assert_intentional_failure + !! Conditionally test an assertion that is hardwired to fail. + +#ifdef RUN_FALSE_ASSERTIONS + + use julienne_m, only : operator(.equalsExpected.), call_julienne_assert_ + implicit none + print '(a)', new_line('') // 'Test julienne_assert intentional failure: ' // new_line('') + call_julienne_assert(1 .equalsExpected. 2) + +#else + + print * + print '(a)', 'Skipping the test in ' // __FILE__ // '.' + print '(a)', 'Add the following to your fpm command to test assertion failure: --flag "-DASSERTIONS -DRUN_FALSE_ASSERTIONS"' + print * + +#endif + +end program +