diff --git a/README.md b/README.md index 0d8199e..8b48cf8 100644 --- a/README.md +++ b/README.md @@ -52,14 +52,6 @@ The [examples/README.md] file shows examples of writing constraints in notes on Downloading, Building, and Running Examples ------------------------------------------- -### Prerequisites -1. A Fortran 2018 compiler. -2. The [Fortran Package Manager]. -3. _Optional_: [OpenCoarrays] for parallel execution with the GNU Fortran compiler. - -Assert was developed primarily with `gfortran` 11.2.0 and `nagfor` 7.1. -Recent versions of the Cray and Intel compilers should also suffice. - ### Downloading Assert ``` git clone git@github.com:sourceryinstitute/assert @@ -70,29 +62,34 @@ cd assert #### Single-image (serial) execution The following command builds Assert and runs the full test suite in a single image: ``` -fpm test +fpm test --profile release ``` -where `fpm test` builds the Assert library and runs the test suite, including the tests. +which builds the Assert library and runs the test suite. #### Multi-image (parallel) execution With `gfortran` and OpenCoarrays installed, ``` -fpm test --compiler caf --runner "cafrun -n 2" +fpm test --compiler caf --profile release --runner "cafrun -n 2" ``` To build and test with the Numerical Algorithms Group (NAG) Fortran compiler version 7.1 or later, use ``` -fpm test --compiler=nagfor --flag="-coarray=cosmp -fpp -f2018" +fpm test --compiler=nagfor --profile release --flag="-coarray=cosmp -fpp -f2018" ``` ### Building and testing with the Intel `ifx` compiler ``` -fpm test --compiler ifx --flag -coarray +fpm test --compiler ifx --profile release --flag -coarray +``` +### Building and testing with the LLVM `flang-new` compiler +``` +fpm test --compiler flang-new --flag "-mmlir -allow-assumed-rank -O3" + ``` ### Building and testing with the Numerical Algorithms Group (NAG) compiler ``` -fpm test --compiler nagfor --flag "-fpp -coarray=cosmp" +fpm test --compiler nagfor --profile release --flag "-fpp -coarray=cosmp" ``` ### Building and testing with the Cray Compiler Environment (CCE) @@ -108,7 +105,7 @@ ftn $@ ``` Then build and test Assert with the command ``` -fpm test --compiler crayftn.sh +fpm test --compiler crayftn.sh --profile release ``` diff --git a/example/derived_type_diagnostic.F90 b/example/derived-type_diagnostic.F90 similarity index 100% rename from example/derived_type_diagnostic.F90 rename to example/derived-type_diagnostic.F90 diff --git a/example/false-assertion.F90 b/example/false-assertion.F90 new file mode 100644 index 0000000..1d74cab --- /dev/null +++ b/example/false-assertion.F90 @@ -0,0 +1,7 @@ +program false_assertion + use assert_m, only : assert + implicit none + + call assert(.false., "false-assertion: unconditionally failing test") + +end program diff --git a/example/intentionally_false_assertions.f90 b/example/intentionally_false_assertions.f90 deleted file mode 100644 index dd455c5..0000000 --- a/example/intentionally_false_assertions.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program intentionally_false_assertions - use assert_m, only : assert - implicit none - - call assert(.false., "main: unconditionally failing test") - -end program diff --git a/example/invoke-via-macro.F90 b/example/invoke-via-macro.F90 new file mode 100644 index 0000000..d87dabe --- /dev/null +++ b/example/invoke-via-macro.F90 @@ -0,0 +1,25 @@ +#include "../src/assert/assert_macros.h" + +program invoke_via_macro + !! Demonstrate how to invoke the 'assert' subroutine using a preprocessor macro that facilitates + !! the complete removal of the call in the absence of the compiler flag -DDEBUG. + use assert_m, only : assert, intrinsic_array_t, string + !! If an "only" clause is employed as above, it must include the "string" function that the + !! call_assert* macros reference when transforming the code below into "assert" subroutine calls. + implicit none + +#ifndef DEBUG + print * + print *,'To enable the "assert" call, define -DDEBUG, e.g., fpm run --example invoke-via-macro --flag "-DDEBUG -fcoarray=single"' + print * +#endif + + ! The C preprocessor will convert each call_assert* macro below into calls to the "assert" subroutine + ! (if -DDEBUG is in the compiler command) or into nothing (if -DDEBUG is not in the compiler command). + + call_assert(1==1) ! true assertion + call_assert_describe(2>0, "example assertion invocation via macro") ! true assertion + call_assert_diagnose(1+1==2, "example with scalar diagnostic data", 1+1) ! true assertion + call_assert_diagnose(1+1>2, "example with array diagnostic data" , intrinsic_array_t([1,1,2])) ! false assertion + +end program invoke_via_macro diff --git a/example/simple_assertions.f90 b/example/simple-assertions.f90 similarity index 100% rename from example/simple_assertions.f90 rename to example/simple-assertions.f90 diff --git a/example/support-assert-test-suite/check-exit-status.f90 b/example/support-assert-test-suite/check-exit-status.f90 new file mode 100644 index 0000000..a0c71d6 --- /dev/null +++ b/example/support-assert-test-suite/check-exit-status.f90 @@ -0,0 +1,14 @@ +program check_exit_status + ! Despite its location in the example subdirectory, this program is _not_ intended to + ! be a user-facing example. This program exists to work around an LLVM Flang (flang-new) + ! compiler issue. This program is invoked by test/test-assert-subroutine-error-termination.F90, + ! which reads the file this program writes to determine the exist status of the program + ! example/false-assertion.f90. The latter program intentionally error terminates in order + ! to test the case wehn assertion = .false. + implicit none + integer exit_status, unit + read(*,*) exit_status + open(newunit=unit, file="build/exit_status", status="unknown") + write(unit,*) exit_status + close(unit) +end program diff --git a/src/assert/assert_macros.h b/src/assert/assert_macros.h new file mode 100644 index 0000000..242e45f --- /dev/null +++ b/src/assert/assert_macros.h @@ -0,0 +1,9 @@ +#ifdef DEBUG +# define call_assert(assertion) call assert(assertion, "No description provided (see file " // __FILE__ // ", line " // string(__LINE__) // ")") +# define call_assert_describe(assertion, description) call assert(assertion, description // " in file " // __FILE__ // ", line " // string(__LINE__) // ": " ) +# define call_assert_diagnose(assertion, description, diagnostic_data) call assert(assertion, "file " // __FILE__ // ", line " // string(__LINE__) // ": " // description, diagnostic_data) +#else +# define call_assert(assertion) +# define call_assert_describe(assertion, description) +# define call_assert_diagnose(assertion, description, diagnostic_data) +#endif diff --git a/src/assert/intrinsic_array_s.F90 b/src/assert/intrinsic_array_s.F90 index 56d6ada..9a7bd01 100644 --- a/src/assert/intrinsic_array_s.F90 +++ b/src/assert/intrinsic_array_s.F90 @@ -1,4 +1,5 @@ submodule(intrinsic_array_m) intrinsic_array_s + use assert_m, only : assert implicit none contains @@ -11,6 +12,8 @@ select type(array) type is(complex) allocate(intrinsic_array%complex_1D, source = array) + type is(complex(kind(1.D0))) + allocate(intrinsic_array%complex_double_1D, source = array) type is(integer) allocate(intrinsic_array%integer_1D, source = array) type is(logical) @@ -18,14 +21,16 @@ type is(real) allocate(intrinsic_array%real_1D, source = array) type is(double precision) - allocate(intrinsic_array%double_precision_1D, source = array) + intrinsic_array%double_precision_1D = array class default - error stop "intrinsic_array_t construct: unsupported rank-1 type" + error stop "intrinsic_array_s(construct): unsupported rank-1 type" end select rank(2) select type(array) type is(complex) allocate(intrinsic_array%complex_2D, source = array) + type is(complex(kind(1.D0))) + allocate(intrinsic_array%complex_double_2D, source = array) type is(integer) allocate(intrinsic_array%integer_2D, source = array) type is(logical) @@ -35,13 +40,15 @@ type is(double precision) allocate(intrinsic_array%double_precision_2D, source = array) class default - error stop "intrinsic_array_t construct: unsupported rank-2 type" + error stop "intrinsic_array_s(construct): unsupported rank-2 type" end select rank(3) select type(array) type is(complex) allocate(intrinsic_array%complex_3D, source = array) + type is(complex(kind(1.D0))) + allocate(intrinsic_array%complex_double_3D, source = array) type is(integer) allocate(intrinsic_array%integer_3D, source = array) type is(logical) @@ -51,11 +58,11 @@ type is(double precision) allocate(intrinsic_array%double_precision_3D, source = array) class default - error stop "intrinsic_array_t construct: unsupported rank-3 type" + error stop "intrinsic_array_s(construct): unsupported rank-3 type" end select rank default - error stop "intrinsic_array_t construct: unsupported rank" + error stop "intrinsic_array_s(construct): unsupported rank" end select end procedure @@ -71,7 +78,7 @@ rank(3) allocate(intrinsic_array%complex_3D, source = array) rank default - error stop "intrinsic_array_t complex_array: unsupported rank" + error stop "intrinsic_array_s(complex_array): unsupported rank" end select end procedure @@ -86,7 +93,7 @@ rank(3) allocate(intrinsic_array%integer_3D, source = array) rank default - error stop "intrinsic_array_t integer_array: unsupported rank" + error stop "intrinsic_array_s(integer_array): unsupported rank" end select end procedure @@ -101,7 +108,7 @@ rank(3) allocate(intrinsic_array%logical_3D, source = array) rank default - error stop "intrinsic_array_t logical_array: unsupported rank" + error stop "intrinsic_array_s(logical_array): unsupported rank" end select end procedure @@ -116,7 +123,7 @@ rank(3) allocate(intrinsic_array%real_3D, source = array) rank default - error stop "intrinsic_array_t real_array: unsupported rank" + error stop "intrinsic_array_s(real_array): unsupported rank" end select end procedure @@ -131,28 +138,32 @@ rank(3) allocate(intrinsic_array%double_precision_3D, source = array) rank default - error stop "intrinsic_array_t double_precision_array: unsupported rank" + error stop "intrinsic_array_s(double_precision_array): unsupported rank" end select end procedure #endif - pure function one_allocated_component(self) result(one_allocated) + pure function allocated_components(self) type(intrinsic_array_t), intent(in) :: self - logical one_allocated - one_allocated = 1 == count( & - [ allocated(self%complex_1D), allocated(self%complex_double_1D), allocated(self%integer_1D), allocated(self%logical_1D), & - allocated(self%real_1D), allocated(self%complex_2D), allocated(self%complex_double_2D), allocated(self%integer_2D), & - allocated(self%logical_2D), allocated(self%real_2D), allocated(self%complex_3D), allocated(self%complex_double_3D), & - allocated(self%integer_3D), allocated(self%logical_3D), allocated(self%real_3D) & - ]) + logical, allocatable :: allocated_components(:) + allocated_components = [ & + allocated(self%complex_1D), allocated(self%real_1D), allocated(self%integer_1D), allocated(self%complex_double_1D) & + ,allocated(self%complex_2D), allocated(self%real_2D), allocated(self%integer_2D), allocated(self%complex_double_2D) & + ,allocated(self%complex_3D), allocated(self%real_3D), allocated(self%integer_3D), allocated(self%complex_double_3D) & + ,allocated(self%logical_1D), allocated(self%double_precision_1D) & + ,allocated(self%logical_2D), allocated(self%double_precision_2D) & + ,allocated(self%logical_3D), allocated(self%double_precision_3D) & + ] end function module procedure as_character - integer, parameter :: single_number_width=32 + integer, parameter :: single_number_width=64 - if (.not. one_allocated_component(self)) error stop "intrinsic_array_s(as_character): invalid number of allocated components" + associate(a => allocated_components(self)) + call assert(count(a) == 1, "intrinsic_array_s(as_character): invalid number of allocated components", intrinsic_array_t(a)) + end associate if (allocated(self%complex_1D)) then character_self = repeat(" ", ncopies = single_number_width*size(self%complex_1D)) @@ -182,7 +193,7 @@ pure function one_allocated_component(self) result(one_allocated) character_self = repeat(" ", ncopies = single_number_width*size(self%integer_2D)) write(character_self, *) self%integer_2D else if (allocated(self%logical_2D)) then - character_self = repeat(" ", ncopies = single_number_width*size(self%logical_1D)) + character_self = repeat(" ", ncopies = single_number_width*size(self%logical_2D)) write(character_self, *) self%logical_2D else if (allocated(self%real_2D)) then character_self = repeat(" ", ncopies = single_number_width*size(self%real_2D)) @@ -200,7 +211,7 @@ pure function one_allocated_component(self) result(one_allocated) character_self = repeat(" ", ncopies = single_number_width*size(self%integer_3D)) write(character_self, *) self%integer_3D else if (allocated(self%logical_3D)) then - character_self = repeat(" ", ncopies = single_number_width*size(self%logical_1D)) + character_self = repeat(" ", ncopies = single_number_width*size(self%logical_3D)) write(character_self, *) self%logical_3D else if (allocated(self%real_3D)) then character_self = repeat(" ", ncopies = single_number_width*size(self%real_3D)) diff --git a/src/assert/string_m.f90 b/src/assert/string_m.f90 new file mode 100644 index 0000000..2385c75 --- /dev/null +++ b/src/assert/string_m.f90 @@ -0,0 +1,16 @@ +module string_m + implicit none + +contains + + pure function string(number) result(number_as_string) + integer, intent(in) :: number + integer, parameter :: max_len=128 + character(len=max_len) :: untrimmed_string + character(len=:), allocatable :: number_as_string + + write(untrimmed_string, *) number + number_as_string = trim(adjustl(untrimmed_string)) + end function + +end module string_m diff --git a/src/assert_m.f90 b/src/assert_m.f90 index 23f36c5..0bd7b34 100644 --- a/src/assert_m.f90 +++ b/src/assert_m.f90 @@ -2,5 +2,6 @@ module assert_m use intrinsic_array_m use assert_subroutine_m use characterizable_m + use string_m, only : string implicit none end module assert_m diff --git a/test/run-false-assertion.sh b/test/run-false-assertion.sh new file mode 100755 index 0000000..22878f1 --- /dev/null +++ b/test/run-false-assertion.sh @@ -0,0 +1,3 @@ +#!/bin/bash +output=$(fpm run --example false_assertion --compiler flang-new --flag '-mmlir -allow-assumed-rank -O3' > /dev/null 2>&1) +echo $? diff --git a/test/test-assert-macro.F90 b/test/test-assert-macro.F90 new file mode 100644 index 0000000..23e4d14 --- /dev/null +++ b/test/test-assert-macro.F90 @@ -0,0 +1,46 @@ +program test_assert_macros + use assert_m + implicit none + + print * + print *,"The call_assert macro" + +#define DEBUG +#include "../../src/assert/assert_macros.h" + call_assert(1==1) + print *," passes on not error-terminating when an assertion expression evaluating to .true. is the only argument" + +#undef DEBUG +#include "../../src/assert/assert_macros.h" + call_assert(.false.) + print *," passes on being removed by the preprocessor when DEBUG is undefined" // new_line('') + + !------------------------------------------ + + print *,"The call_assert_describe macro" + +#define DEBUG +#include "../../src/assert/assert_macros.h" + call_assert_describe(.true., ".true.") + print *," passes on not error-terminating when assertion = .true. and a description is present" + +#undef DEBUG +#include "../../src/assert/assert_macros.h" + call_assert_describe(.false., "") + print *," passes on being removed by the preprocessor when DEBUG is undefined" // new_line('') + + !------------------------------------------ + + print *,"The call_assert_diagnose macro" + +#define DEBUG +#include "../../src/assert/assert_macros.h" + call_assert_diagnose(.true., ".true.", diagnostic_data=1) + print *," passes on not error-terminating when assertion = .true. and description and diagnostic_data are present" + +#undef DEBUG +#include "../../src/assert/assert_macros.h" + call_assert_describe(.false., "") + print *," passes on being removed by the preprocessor when DEBUG is undefined" + +end program diff --git a/test/test-assert-subroutine-error-termination.F90 b/test/test-assert-subroutine-error-termination.F90 new file mode 100644 index 0000000..14dd808 --- /dev/null +++ b/test/test-assert-subroutine-error-termination.F90 @@ -0,0 +1,70 @@ +program test_assert_subroutine_error_termination + !! Test "assert" subroutine calls that are intended to error terminate + use assert_m, only : assert + implicit none + + integer exit_status + + ! TODO: add '--profile release' if used in the 'fpm test' invocation that causes the program + ! ../example/test-assert-subroutine-error-termination.F90 to excute this example program. + + print * + print *,"The assert subroutine" + call execute_command_line( & +#ifdef __GFORTRAN__ + command = "fpm run --example false_assertion > /dev/null 2>&1", & +#elif NAGFOR + command = "fpm run --example false_assertion --compiler nagfor --flag -fpp > /dev/null 2>&1", & +#elif __flang__ + command = "./test/run-false-assertion.sh | fpm run --example check-exit-status", & +#elif __INTEL_COMPILER + command = "fpm run --example false_assertion --compiler ifx --flag -O3 > /dev/null 2>&1", & +#elif __CRAYFTN + command = "fpm run --example false_assertion --compiler crayftn.sh > /dev/null 2>&1", & +#else + command = "echo 'example/false_assertion.F90: unsupported compiler' && exit 1", & +#endif + wait = .true., & + exitstat = exit_status & + ) + +#ifndef __flang__ + block + logical error_termination + + error_termination = exit_status /=0 + call co_all(error_termination) + if (this_image()==1) then + if (error_termination) then + print *," passes on error-terminating when assertion = .false." + else + print *," FAILS to error-terminate when assertion = .false. (Yikes! Who designed this OS?)" + end if + end if + end block +#else + block + integer unit + open(newunit=unit, file="build/exit_status", status="old") + read(unit,*) exit_status + print *,trim(merge("passes","FAILS ",exit_status/=0)) // " on error-terminating when assertion = .false." + close(unit) + end block +#endif + +contains + + pure function and_operation(lhs,rhs) result(lhs_and_rhs) + logical, intent(in) :: lhs, rhs + logical lhs_and_rhs + lhs_and_rhs = lhs .and. rhs + end function + +#ifndef __flang__ + subroutine co_all(boolean) + logical, intent(inout) :: boolean + call co_reduce(boolean, and_operation) + end subroutine +#endif + +end program test_assert_subroutine_error_termination diff --git a/test/test-assert-subroutine-normal-termination.F90 b/test/test-assert-subroutine-normal-termination.F90 new file mode 100644 index 0000000..e5888f8 --- /dev/null +++ b/test/test-assert-subroutine-normal-termination.F90 @@ -0,0 +1,41 @@ +program test_assert_subroutine_normal_termination + !! Test direct calls to the "assert" subroutine that don't error-terminate + use assert_m, only : assert + use intrinsic_array_m, only : intrinsic_array_t + implicit none + + print * + print *,"The assert subroutine" + + call assert(assertion = .true., description = "3 keyword arguments ", diagnostic_data=0) + call assert( .true., description = "2 keyword arguments ", diagnostic_data=0) + call assert( .true., "1 keyword argument ", diagnostic_data=0) + call assert( .true., "0 keyword arguments ", 0) + call assert( .true., "no optional argument" ) +#ifndef __flang__ + sync all + if (this_image()==1) & +#endif + print *," passes on not error-terminating when assertion=.true. + combos of (non-)keyword and (non-)present optional arguments" + + + array_1D_diagnostic_data: & + block + complex, parameter :: complex_1D(*) = [(1.,0.), (0.,1.)] + integer, parameter :: integer_1D(*) = [1, 2] + logical, parameter :: logical_1D(*) = [.true., .true.] + real, parameter :: real_1D(*) = [1., 2.] + + call assert(all(abs(complex_1D) < 2.), "all(abs(complex_array) < 2.)", intrinsic_array_t(complex_1D)) + call assert(all(integer_1D < 3 ), "all(int_array < 3 )", intrinsic_array_t(integer_1D)) + call assert(all(logical_1D ), "all(logical_array )", intrinsic_array_t(logical_1D)) + call assert(all(real_1D < 3.), "all(real_array < 3.)", intrinsic_array_t( real_1D)) +#ifndef __flang__ + sync all + if (this_image()==1) & +#endif + print *," passes on not error-terminating when diagnostic_data = intrinsic_array_t({complex|integer|logical|real} 1D arrays)" + end block array_1D_diagnostic_data + + +end program test_assert_subroutine_normal_termination diff --git a/test/test-intrinsic_array.F90 b/test/test-intrinsic_array.F90 new file mode 100644 index 0000000..bc55159 --- /dev/null +++ b/test/test-intrinsic_array.F90 @@ -0,0 +1,226 @@ +program test_intrinsinc_array_t + !! Test direct intrinsic_array_t derive type construction and conversion to srings + use intrinsic_array_m, only : intrinsic_array_t + implicit none + + integer j + complex, parameter :: z = (-1., -1.) + complex, parameter :: complex_1D(*) = [(z, j=1,2 )] + complex, parameter :: complex_2D(*,*) = reshape([(z, j=1,2*2 )], [2, 2 ]) + complex, parameter :: complex_3D(*,*,*) = reshape([(z, j=1,2*2*2)], [2, 2, 2]) + complex(kind(1.D0)), parameter :: z_double = (-1.D0, -2.D0) + complex(kind(z_double)), parameter :: complex_double_1D(*) = [(z_double, j=1, 2 )] + complex(kind(z_double)), parameter :: complex_double_2D(*,*) = reshape([(z_double, j=1, 2*2 )], [2, 2 ]) + complex(kind(z_double)), parameter :: complex_double_3D(*,*,*) = reshape([(z_double, j=1, 2*2*2)], [2, 2, 2]) + integer, parameter :: integer_1D(*) = [(0, j=1,2 )] + integer, parameter :: integer_2D(*,*) = reshape([(1, j=1,2*2 )], [2, 2 ]) + integer, parameter :: integer_3D(*,*,*) = reshape([(2, j=1,2*2*2 )], [2, 2, 2]) + logical, parameter :: logical_1D(*) = [(.true., j=1,2 )] + logical, parameter :: logical_2D(*,*) = reshape([(.true., j=1,2*2 )], [2, 2 ]) + logical, parameter :: logical_3D(*,*,*) = reshape([(.true., j=1,2*2*2)], [2, 2, 2]) + +#ifndef __flang__ + if (this_image()==1) then +#endif + + print* + print*,"An intrinsic_array_t object" + print*," "//pass_fail(dble(integer_1D)) //" on construction from a 1D double-precision array and conversion to a string" + print*," "//pass_fail(dble(integer_2D)) //" on construction from a 2D double-precision array and conversion to a string" + print*," "//pass_fail(dble(integer_3D)) //" on construction from a 3D double-precision array and conversion to a string" + print*," "//pass_fail(integer_1D) //" on construction from a 1D integer array and conversion to a string" + print*," "//pass_fail(integer_2D) //" on construction from a 2D integer array and conversion to a string" + print*," "//pass_fail(integer_3D) //" on construction from a 3D integer array and conversion to a string" + print*," "//pass_fail(logical_1D) //" on construction from a 1D logical array and conversion to a string" + print*," "//pass_fail(logical_2D) //" on construction from a 2D logical array and conversion to a string" + print*," "//pass_fail(logical_3D) //" on construction from a 3D logical array and conversion to a string" + print*," "//pass_fail(real(integer_1D)) //" on construction from a 1D real array and conversion to a string" + print*," "//pass_fail(real(integer_2D)) //" on construction from a 2D real array and conversion to a string" + print*," "//pass_fail(real(integer_3D)) //" on construction from a 3D real array and conversion to a string" + print*," "//pass_fail(complex_1D) //" on construction from a 1D complex array and conversion to a string" + print*," "//pass_fail(complex_2D) //" on construction from a 2D complex array and conversion to a string" + print*," "//pass_fail(complex_3D) //" on construction from a 3D complex array and conversion to a string" + print*," "//pass_fail(complex_double_1D)//" on construction from a 1D double-precision complex array and conversion to a string" + print*," "//pass_fail(complex_double_2D)//" on construction from a 2D double-precision complex array and conversion to a string" + print*," "//pass_fail(complex_double_3D)//" on construction from a 3D double-precision complex array and conversion to a string" + +#ifndef __flang__ + end if +#endif + +contains + + + pure function pass_fail(to_write) + class(*), intent(in) :: to_write(..) + character(len=:), allocatable :: pass_fail + integer, parameter :: max_length = 2048 + character(len=max_length) array_as_string + type(intrinsic_array_t) intrinsic_array + + select rank(to_write) + rank(1) + select type(to_write) + type is(complex) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + complex from_read(size(to_write,1)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(complex(kind(0.D0))) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + complex from_read(size(to_write,1)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(double precision) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + double precision from_read(size(to_write,1)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(integer) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + integer from_read(size(to_write,1)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(logical) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + logical from_read(size(to_write,1)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read .eqv. to_write))) + end block + type is(real) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string, *) intrinsic_array%as_character() + block + real from_read(size(to_write,1)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + class default + error stop "test_intrinsic_array_t: unrecognized rank-1 type" + end select + rank(2) + select type(to_write) + type is(complex) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + complex from_read(size(to_write,1), size(to_write,2)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(complex(kind(1.D0))) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + complex from_read(size(to_write,1), size(to_write,2)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(double precision) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + double precision from_read(size(to_write,1), size(to_write,2)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(integer) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + integer from_read(size(to_write,1), size(to_write,2)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(logical) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + logical from_read(size(to_write,1), size(to_write,2)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read .eqv. to_write))) + end block + type is(real) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + real from_read(size(to_write,1), size(to_write,2)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + class default + error stop "test_intrinsic_array_t: unrecognized rank-2 type" + end select + rank(3) + select type(to_write) + type is(complex) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + complex from_read(size(to_write,1), size(to_write,2), size(to_write,3)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(complex(kind(0.D0))) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + complex from_read(size(to_write,1), size(to_write,2), size(to_write,3)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(double precision) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + double precision from_read(size(to_write,1), size(to_write,2), size(to_write,3)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(integer) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + integer from_read(size(to_write,1), size(to_write,2), size(to_write,3)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + type is(logical) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + logical from_read(size(to_write,1), size(to_write,2), size(to_write,3)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read .eqv. to_write))) + end block + type is(real) + intrinsic_array = intrinsic_array_t(to_write) + write(array_as_string,*) intrinsic_array%as_character() + block + real from_read(size(to_write,1), size(to_write,2), size(to_write,3)) + read(array_as_string,*) from_read + pass_fail = trim(merge("passes", "FAILS ", all(from_read == to_write))) + end block + class default + error stop "test_intrinsic_array_t: unrecognized rank-3 type" + end select + rank default + error stop "test_intrinsic_array_t: unsupported rank (3)" + end select + end function + +end program test_intrinsinc_array_t diff --git a/test/unit-tests/designed-to-error-terminate.F90 b/test/unit-tests/designed-to-error-terminate.F90 deleted file mode 100644 index e0c058e..0000000 --- a/test/unit-tests/designed-to-error-terminate.F90 +++ /dev/null @@ -1,56 +0,0 @@ -program designed_to_error_terminate - !! Test assertions that are intended to error terminate - use assert_m, only : assert - implicit none - - integer exit_status - - call execute_command_line( & - command = "fpm run --example intentionally_false_assertions > /dev/null 2>&1", & - wait = .true., & - exitstat = exit_status & - ) - - block - logical error_termination - - error_termination = exit_status /=0 - -#ifndef __flang__ - call co_all(error_termination) - - if (this_image()==1) then -#endif - - if (error_termination) then - print *, "----> All tests designed to error-terminate pass. <----" - else - print *, "----> One or more tests designed to error-terminate terminated normally. Yikes! Who designed this OS? <----" - end if - -#ifndef __flang__ - end if -#endif - - end block - -contains - - pure function and_operation(lhs,rhs) result(lhs_and_rhs) - logical, intent(in) :: lhs, rhs - logical lhs_and_rhs - - lhs_and_rhs = lhs .and. rhs - - end function - -#ifndef __flang__ - subroutine co_all(boolean) - logical, intent(inout) :: boolean - - call co_reduce(boolean, and_operation) - - end subroutine -#endif - -end program diff --git a/test/unit-tests/designed-to-terminate-normally.f90 b/test/unit-tests/designed-to-terminate-normally.f90 deleted file mode 100644 index db23a21..0000000 --- a/test/unit-tests/designed-to-terminate-normally.f90 +++ /dev/null @@ -1,43 +0,0 @@ -program designed_to_terminate_normally - !! Test assertions expected to succeed - use assert_m, only : assert - use intrinsic_array_m, only : intrinsic_array_t - implicit none - - scalar_diagnostic_data: & - block - complex, parameter :: z = (1.,1.) - integer, parameter :: n = 1 - logical, parameter :: bool = .true. - real, parameter :: x = 1. - - call assert(abs(z)>0, "main: z>0", diagnostic_data = z) - call assert(n>0, "main: i>0") - call assert(n>0, "main: n>0", n) - call assert(x>0., "main: x>0", x) - call assert(bool, "main: z>0", bool) - - end block scalar_diagnostic_data - - array_diagnostic_data: & - block - complex, parameter :: complex_array(*) = [(1.,0.), (0.,1.)] - integer, parameter :: integer_array(*) = [1, 2] - logical, parameter :: logical_array(*) = [.true., .true.] - real, parameter :: real_array(*) = [1., 2.] - - call assert(all(abs(complex_array) < 2.), "main: all(abs(complex_array) < 2.)", intrinsic_array_t(complex_array)) - call assert(all(integer_array < 3), "main: all(int_array < 3)", intrinsic_array_t(integer_array)) - call assert(all(logical_array), "main: all(logical_array)", intrinsic_array_t(logical_array)) - call assert(all(real_array < 3.), "main: all(real_array < 3.)", intrinsic_array_t(real_array)) - - end block array_diagnostic_data - -#ifndef __flang__ - sync all - - if (this_image()==1) & -#endif - print *, "----> All tests designed to terminate normally pass. <----" - -end program designed_to_terminate_normally