ITM Grid Service Library: Fortran 90

src/itm_assert/itm_assert.f90

Go to the documentation of this file.
00001 module itm_assert
00002 
00003   !> Assertions for Fortran 90, written by H.-J. Klingshirn
00004 
00005   !> @author 
00006 
00007   use itm_types , ITM_R8 => R8, ITM_R4 => R4
00008   use itm_string 
00009 
00010   implicit none
00011 
00012   private
00013 
00014   public assertSetStopMode, assertSetMsgPrefix, assertStopOnFailed, assert, assertEqual, assertReset
00015 
00016   logical, save :: defaultDoStop = .true.
00017   integer, save :: failCount = 0
00018   integer, save :: msgPrefixLen = 0
00019   character(256), save :: msgPrefix
00020 
00021 contains
00022 
00023   !> Private subroutine that handles a failed assertion. Prints out the
00024   !> fail message (msgPrefix + failmsg, depending on what is given), and 
00025   !> either stops of does assertion bookkeeping. 
00026 
00027   !> @param failmsg The fail message to print
00028   !> @param doStop Controls whether to stop execution. If doStop .true., 
00029   !> the program is stopped. If .false., only the fail message is printed
00030   !> and bookkeeping is done for delayed stopping (@see assertStopOnFailed)
00031 
00032   subroutine assertFail( failmsg, doStop )
00033     character(*), intent(in), optional :: failmsg
00034     logical, intent(in), optional :: doStop
00035 
00036     ! internal
00037     logical :: lDoStop
00038 
00039     lDoStop = defaultDoStop
00040     if ( present( doStop ) ) lDoStop = doStop
00041 
00042     if ( present( failmsg ) ) then
00043             if ( msgPrefixLen > 0 ) then
00044                     write (*,*) 'itm_assert: '//msgPrefix(1:msgPrefixLen)//' '//failmsg
00045             else
00046                     write (*,*) 'itm_assert: '//failmsg       
00047             end if
00048     else
00049             if ( msgPrefixLen > 0 ) then
00050                     write (*,*) 'itm_assert: '//msgPrefix(1:msgPrefixLen)
00051             end if
00052     end if
00053 
00054     if ( lDoStop ) then
00055        stop "itm_assert: an assertion failed, stopping immediately."
00056     else
00057        failCount = failCount + 1
00058        write(*,*) "itm_assert: an assertion failed, continuing."
00059     end if
00060     
00061   end subroutine assertFail
00062 
00063 
00064   !> Set the default assertion stop behaviour. 
00065 
00066   !> @param doStop .true. means immediate
00067   !> stop on fail, .false. means don't stop on fail (for use with 
00068   !> delayed stopping, @see assertStopOnFailed). The default value is .true.,
00069   !> it is set if doStop is omitted.
00070   subroutine assertSetStopMode( doStop )
00071     logical, intent(in), optional :: doStop
00072 
00073     if ( present( doStop ) ) then
00074             defaultDoStop = doStop
00075     else
00076             ! if no argument given, just set default again
00077             defaultDoStop = .true.           
00078     end if
00079     
00080   end subroutine assertSetStopMode
00081 
00082 
00083   !> Set a prefix for the assertion fail message.
00084   !> @param prefix The prefix string for the fail messages. Optional. If 
00085   !> omitted, clear the prefix string (i.e. no prefix is used anymore)
00086   subroutine assertSetMsgPrefix( prefix )
00087     character(len=*), intent(in), optional :: prefix
00088 
00089     if ( present( prefix ) ) then
00090             msgPrefixLen = min( len(prefix), len( msgPrefix ) )
00091             msgPrefix(1:msgPrefixLen) = prefix(1:msgPrefixLen)
00092     else
00093             msgPrefixLen = 0
00094     end if
00095     
00096   end subroutine assertSetMsgPrefix
00097 
00098 
00099   !> Reset the assertion module to its default state.
00100   !>
00101   !> Reset stop mode and message prefix to their default values.
00102   !> Also resets the fail counter, i.e. any previous failed assertions are forgotton.
00103   subroutine assertReset()
00104     call assertSetStopMode()       
00105     call assertSetMsgPrefix()
00106     failCount = 0
00107   end subroutine assertReset
00108   
00109 
00110   !> Stop if a previously called assertion failed (delayed stop). 
00111 
00112   !> This is useful if the
00113   !> default stop mode is set to continue on failed assertions (which
00114   !> can be enabled by call assertSetStopMode( .false. ). 
00115 
00116   !> @param failmsg Message to print if assertion(s) failed.
00117   !> @param doStop Controls stop behaviour, @see assert. Overrides the default
00118   !> set with @see assertSetStopMode
00119 
00120   subroutine assertStopOnFailed( failmsg, doStop )
00121     character(*), intent(in), optional :: failmsg
00122     logical, intent(in), optional :: doStop
00123 
00124     ! internal
00125     logical :: lDoStop 
00126     
00127     lDoStop = .true. ! default for this routine is to stop, regardless of current module default    
00128     if ( present( doStop ) ) lDoStop = doStop ! ...but can be overridden again with optional argument
00129 
00130     if ( present( failmsg ) ) then
00131             ! ...use given message
00132             call assert( failCount == 0, failmsg, lDoStop )
00133     else
00134             ! ...or substitute generic message
00135             call assert( failCount == 0, itmInt2Str( failCount )//' assertions failed', lDoStop )
00136     end if
00137     failCount = 0
00138 
00139   end subroutine assertStopOnFailed
00140   
00141 
00142   !> A generic assertion, tests a given logical expression. 
00143 
00144   !> If it evaluates to .false.,
00145   !> print the fail message and possibly stop execution.
00146   !> 
00147   !> @param test The logical expression to test.
00148   !> @param failmsg The message to print on fail. If omitted, a generic message is printed. Can be modified with a prefix (see assertSetMsgPrefix)
00149   !> @param doStop Controls whether to stop execution. If doStop .true., 
00150   !> the program is stopped. If .false., only the fail message is printed
00151   !> and bookkeeping is done for delayed stopping (see assertStopOnFailed).
00152   !> If given, overrides the default behaviour  set by assertSetStopMode.
00153 
00154   !> @see assertStopOnFailed
00155   !> @see assertSetStopMode
00156   !> @see assertSetMsgPrefix
00157 
00158   !> @author H.-J. Klingshirn 
00159   !> @version 1.0 
00160 
00161   subroutine assert( test, failmsg, doStop )
00162     logical, intent(in) :: test
00163     character(*), intent(in), optional :: failmsg
00164     logical, intent(in), optional :: doStop
00165 
00166     if ( .not. test ) then
00167        call assertFail( failmsg, doStop )
00168     end if
00169 
00170   end subroutine assert
00171 
00172 
00173   !> Test double precision floating point numbers for equality.
00174 
00175   !> @param x1, x2 The values to test
00176   !> @param failmsg Same as for assert
00177   !> @param doStop Same as for assert
00178   !> @see assert
00179 
00180   subroutine assertEqual( x1, x2, failmsg, doStop )
00181     real(ITM_R8), intent(in) :: x1, x2
00182     character(*), intent(in), optional :: failmsg
00183     logical, intent(in), optional :: doStop
00184 
00185     ! x1 is reference value
00186     ! x2 is actual value
00187 
00188     if ( .not. ( ( ( x1 + 2 * spacing( real( x1 ) ) ) >= x2 ) 
00189             .and. ( x1 - 2 * spacing( real( x1 ) ) ) <= x2 ) ) then
00190 
00191        call assertFail( failmsg, doStop )
00192 
00193     end if
00194     
00195   end subroutine assertEqual
00196 
00197 
00198 end module itm_assert
 All Classes Namespaces Files Functions Variables