funit 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -0
- data/License.txt +263 -0
- data/Manifest.txt +25 -0
- data/README.txt +124 -0
- data/Rakefile +21 -0
- data/bin/funit +22 -0
- data/examples/CFD/FluxFunctions.f90 +34 -0
- data/examples/CFD/FluxFunctions.fun +47 -0
- data/examples/CFD/Gammas.f90 +7 -0
- data/examples/CFD/GasModel.f90 +16 -0
- data/examples/CFD/GasModel.fun +20 -0
- data/examples/ReadData/time_series_data.f90 +27 -0
- data/examples/ReadData/time_series_data.fun +28 -0
- data/examples/StopWatch/StopWatch.f90 +50 -0
- data/examples/StopWatch/StopWatch.fun +73 -0
- data/lib/funit.rb +35 -0
- data/lib/funit/assertions.rb +114 -0
- data/lib/funit/compiler.rb +33 -0
- data/lib/funit/functions.rb +100 -0
- data/lib/funit/testsuite.rb +197 -0
- data/test/test_compiler.rb +16 -0
- data/test/test_functions.rb +10 -0
- data/test/test_funit.rb +113 -0
- data/test/test_testsuite.rb +106 -0
- data/utils/funit-mode.el +111 -0
- metadata +98 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module FluxFunctions
|
2
|
+
|
3
|
+
implicit none
|
4
|
+
|
5
|
+
contains
|
6
|
+
|
7
|
+
subroutine CentralFlux( LeftState, RightState, InterfaceFlux )
|
8
|
+
real, intent(in) :: leftState
|
9
|
+
real, intent(in) :: rightState
|
10
|
+
real, intent(out) :: interfaceFlux
|
11
|
+
interfaceFlux = 0.5*(Flux(leftState)+Flux(rightState))
|
12
|
+
end subroutine CentralFlux
|
13
|
+
|
14
|
+
subroutine RoeFlux( LeftState, RightState, InterfaceFlux )
|
15
|
+
real, intent(in) :: leftState
|
16
|
+
real, intent(in) :: rightState
|
17
|
+
real, intent(out) :: interfaceFlux
|
18
|
+
interfaceFlux = 0.5*(Flux(leftState)+Flux(rightState)) &
|
19
|
+
- 0.5*RoeAvg(leftState,rightState)*(rightState-leftState)
|
20
|
+
end subroutine RoeFlux
|
21
|
+
|
22
|
+
function Flux( state )
|
23
|
+
real :: Flux
|
24
|
+
real, intent(in) :: state
|
25
|
+
Flux = 0.5*state**2
|
26
|
+
end function Flux
|
27
|
+
|
28
|
+
function RoeAvg( leftState, rightState )
|
29
|
+
real :: RoeAvg
|
30
|
+
real, intent(in) :: leftState, rightState
|
31
|
+
RoeAvg = 0.5*(leftState+rightState)
|
32
|
+
end function RoeAvg
|
33
|
+
|
34
|
+
end module FluxFunctions
|
@@ -0,0 +1,47 @@
|
|
1
|
+
real :: leftState, rightState, interfaceFlux
|
2
|
+
|
3
|
+
beginsetup
|
4
|
+
leftState = 0
|
5
|
+
rightState = 1
|
6
|
+
endsetup
|
7
|
+
|
8
|
+
beginTest FluxZero
|
9
|
+
real :: state
|
10
|
+
state = 0
|
11
|
+
IsEqualWithin( 0, Flux(state), 0.00001 )
|
12
|
+
endTest
|
13
|
+
|
14
|
+
beginTest FluxOne
|
15
|
+
real :: state = 1
|
16
|
+
IsEqualWithin( 0.5, Flux(state), 0.00001 )
|
17
|
+
endTest
|
18
|
+
|
19
|
+
beginTest RoeAvgZero
|
20
|
+
IsRealEqual( 0, RoeAvg(0.0,0.0) )
|
21
|
+
IsFalse( RoeAvg(0.0,0.0)==1 )
|
22
|
+
endTest
|
23
|
+
|
24
|
+
beginTest RoeAvgKnown
|
25
|
+
IsRealEqual( 0.5, RoeAvg(leftState,rightState) )
|
26
|
+
IsTrue( RoeAvg(leftState,rightState) > 0 )
|
27
|
+
endTest
|
28
|
+
|
29
|
+
beginTest CentralFluxKnown
|
30
|
+
call CentralFlux( leftState, rightState, interfaceFlux )
|
31
|
+
IsEqualWithin( 0.25, interfaceFlux, 0.001 )
|
32
|
+
IsEqualWithin( 0.25, interfaceFlux, 0.00000001 )
|
33
|
+
IsEqual( 0.25, interfaceFlux )
|
34
|
+
endTest
|
35
|
+
|
36
|
+
beginTest RoeFluxExpansionShock
|
37
|
+
leftState = -1
|
38
|
+
call RoeFlux( leftState, rightState, interfaceFlux )
|
39
|
+
IsEqual( 0.5, interfaceFlux )
|
40
|
+
endTest
|
41
|
+
|
42
|
+
beginTest RoeFluxZero
|
43
|
+
rightState = 0
|
44
|
+
call RoeFlux( leftState, rightState, interfaceFlux )
|
45
|
+
IsRealEqual( 0, interfaceFlux )
|
46
|
+
IsEqual( 0, interfaceFlux )
|
47
|
+
endTest
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module GasModel
|
2
|
+
|
3
|
+
use Gammas
|
4
|
+
|
5
|
+
implicit none
|
6
|
+
|
7
|
+
contains
|
8
|
+
|
9
|
+
subroutine PerfectP (Density, Energy, Pressure)
|
10
|
+
real, intent(in) :: Density
|
11
|
+
real, intent(in) :: Energy
|
12
|
+
real, intent(out) :: Pressure
|
13
|
+
Pressure = Density * Energy * ( Gamma - 1.0 )
|
14
|
+
end subroutine PerfectP
|
15
|
+
|
16
|
+
end module GasModel
|
@@ -0,0 +1,20 @@
|
|
1
|
+
real :: Pressure, Density, Energy
|
2
|
+
|
3
|
+
beginTest PerfectPZeroed
|
4
|
+
real, parameter :: zero = 0
|
5
|
+
call PerfectP (zero, zero, Pressure)
|
6
|
+
isRealEqual ( 0, Pressure )
|
7
|
+
IsEqualwithin ( 0, Pressure, 0.0000000001 )
|
8
|
+
endTest
|
9
|
+
|
10
|
+
begintest Warbler
|
11
|
+
endtest
|
12
|
+
|
13
|
+
beginTest PerfectPKnown
|
14
|
+
real :: Density = 1
|
15
|
+
Energy = 1
|
16
|
+
call PerfectP( Density, Energy, Pressure )
|
17
|
+
IsRealEqual( 0.4, Pressure )
|
18
|
+
IsTrue ( Pressure > 0 )
|
19
|
+
IsFalse( Pressure < 0 )
|
20
|
+
endTest
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module time_series_data
|
2
|
+
implicit none
|
3
|
+
integer, parameter :: MAX_POINTS = 100000 ! or use allocate
|
4
|
+
type date_time
|
5
|
+
integer :: year, month, day, hour, minute
|
6
|
+
end type date_time
|
7
|
+
type time_series
|
8
|
+
type(date_time) :: date_time
|
9
|
+
real :: value = 0.0
|
10
|
+
end type time_series
|
11
|
+
type(time_series), dimension(MAX_POINTS), save :: ts_data
|
12
|
+
contains
|
13
|
+
subroutine read_time_series( filename )
|
14
|
+
character(len=*), intent(in) :: filename
|
15
|
+
integer :: i, ios
|
16
|
+
open(10, file=filename, iostat=ios)
|
17
|
+
if (ios/=0) then
|
18
|
+
print *, 'failed to open file: >>', filename, '<<'
|
19
|
+
else
|
20
|
+
do i = 1, MAX_POINTS
|
21
|
+
read( 10, fmt='(i4,i2,i2,i2,i2,e20.12)', end=20 ) ts_data(i)
|
22
|
+
end do
|
23
|
+
print *, 'quit reading data after ', MAX_POINTS, ' points'
|
24
|
+
20 continue
|
25
|
+
end if
|
26
|
+
end subroutine read_time_series
|
27
|
+
end module time_series_data
|
@@ -0,0 +1,28 @@
|
|
1
|
+
character(len=*), parameter :: FILE = 'values.txt'
|
2
|
+
|
3
|
+
beginSetup
|
4
|
+
open(8, file=FILE)
|
5
|
+
write(8,'(a)'), '200609300000 0.223200546265E+003'
|
6
|
+
write(8,'(a)'), '200609300132 0.226001495361E+003'
|
7
|
+
close(8)
|
8
|
+
endSetup
|
9
|
+
|
10
|
+
beginTest load_time_series_data_from_file
|
11
|
+
call read_time_series( FILE )
|
12
|
+
IsEqual( 2006, ts_data(1)%date_time%year )
|
13
|
+
IsEqual( 9, ts_data(1)%date_time%month )
|
14
|
+
IsEqual( 30, ts_data(1)%date_time%day )
|
15
|
+
IsEqual( 0, ts_data(1)%date_time%hour )
|
16
|
+
IsEqual( 0, ts_data(1)%date_time%minute )
|
17
|
+
IsEqualWithin( 223.2, ts_data(1)%value, 0.1 )
|
18
|
+
IsEqual( 2006, ts_data(2)%date_time%year )
|
19
|
+
IsEqual( 9, ts_data(2)%date_time%month )
|
20
|
+
IsEqual( 30, ts_data(2)%date_time%day )
|
21
|
+
IsEqual( 1, ts_data(2)%date_time%hour )
|
22
|
+
IsEqual( 32, ts_data(2)%date_time%minute )
|
23
|
+
IsEqualWithin( 226.0, ts_data(2)%value, 0.1 )
|
24
|
+
endTest
|
25
|
+
|
26
|
+
beginTeardown
|
27
|
+
call system('rm '//FILE)
|
28
|
+
endTeardown
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module StopWatch
|
2
|
+
|
3
|
+
implicit none
|
4
|
+
|
5
|
+
public
|
6
|
+
|
7
|
+
logical :: notInitialized = .TRUE.
|
8
|
+
|
9
|
+
integer, dimension(8) :: last
|
10
|
+
|
11
|
+
contains
|
12
|
+
|
13
|
+
real function SecBetween(beginDnT, endDnT)
|
14
|
+
integer, dimension(8), intent(in) :: beginDnT, endDnT
|
15
|
+
real :: days, hours, minutes, seconds
|
16
|
+
integer, parameter :: yr=1, mo=2, day=3, utc=4, hr=5, mn=6, s=7, ms=8
|
17
|
+
|
18
|
+
continue
|
19
|
+
|
20
|
+
if ( endDnT(day) == beginDnT(day) ) then
|
21
|
+
days = 0
|
22
|
+
else
|
23
|
+
days = 1 ! note: assuming one day
|
24
|
+
endif
|
25
|
+
|
26
|
+
hours = endDnT(hr) - beginDnT(hr) + 24*days
|
27
|
+
minutes = endDnT(mn) - beginDnT(mn) + 60*hours
|
28
|
+
seconds = endDnT(s) - beginDnT(s) + 60*minutes
|
29
|
+
|
30
|
+
SecBetween = seconds + ( endDnT(ms) - beginDnT(ms) ) / 1000.
|
31
|
+
|
32
|
+
end function SecBetween
|
33
|
+
|
34
|
+
real function secSinceLast()
|
35
|
+
|
36
|
+
integer, dimension(8) :: now
|
37
|
+
|
38
|
+
if (notInitialized) then
|
39
|
+
notInitialized = .FALSE.
|
40
|
+
secSinceLast = 0.0
|
41
|
+
call date_and_time(values=last)
|
42
|
+
else
|
43
|
+
call date_and_time(values=now)
|
44
|
+
secSinceLast = secBetween(last, now)
|
45
|
+
last = now
|
46
|
+
endif
|
47
|
+
|
48
|
+
end function secSinceLast
|
49
|
+
|
50
|
+
end module StopWatch
|
@@ -0,0 +1,73 @@
|
|
1
|
+
integer, dimension(8) :: dateAndTime1, dateAndTime2
|
2
|
+
real :: seconds
|
3
|
+
|
4
|
+
beginSetup
|
5
|
+
NotInitialized = .TRUE.
|
6
|
+
last = 0
|
7
|
+
seconds = HUGE(0.0)
|
8
|
+
endSetup
|
9
|
+
|
10
|
+
beginTest SystemDateAndTimeWorks
|
11
|
+
call date_and_time(values=dateAndTime1)
|
12
|
+
IsTrue( dateAndTime1(1) /= -huge(0) )
|
13
|
+
IsTrue( size(dateAndTime1,1) == 8 )
|
14
|
+
endTest
|
15
|
+
|
16
|
+
! test secBetween
|
17
|
+
beginTest OneMSecDifference
|
18
|
+
dateAndTime1 = (/ 2000, 1, 1, 0, 0, 0, 0, 0 /)
|
19
|
+
dateAndTime2 = (/ 2000, 1, 1, 0, 0, 0, 0, 1 /)
|
20
|
+
seconds = SecBetween(dateAndTime1, dateAndTime2)
|
21
|
+
IsRealEqual( 0.001, seconds)
|
22
|
+
endTest
|
23
|
+
|
24
|
+
beginTest MinuteRollover
|
25
|
+
dateAndTime1 = (/ 2000, 1, 1, 0, 0, 0,59, 0 /)
|
26
|
+
dateAndTime2 = (/ 2000, 1, 1, 0, 0, 1, 0, 0 /)
|
27
|
+
seconds = SecBetween(dateAndTime1, dateAndTime2)
|
28
|
+
IsRealEqual( 1.0, seconds )
|
29
|
+
endTest
|
30
|
+
|
31
|
+
! test secSinceLast
|
32
|
+
beginTest InitializationState
|
33
|
+
IsTrue(notInitialized)
|
34
|
+
seconds = secSinceLast()
|
35
|
+
IsFalse(notInitialized)
|
36
|
+
seconds = secSinceLast()
|
37
|
+
IsFalse(notInitialized)
|
38
|
+
endTest
|
39
|
+
|
40
|
+
beginTest InitiallyReturnsZero
|
41
|
+
seconds = secSinceLast()
|
42
|
+
IsRealEqual( 0.0, seconds )
|
43
|
+
call timeDelay(seconds)
|
44
|
+
seconds = secSinceLast()
|
45
|
+
IsTrue( seconds /= 0.0 )
|
46
|
+
endTest
|
47
|
+
|
48
|
+
subroutine timeDelay (sum)
|
49
|
+
integer :: i
|
50
|
+
real :: sum
|
51
|
+
do i = 1, 1000000
|
52
|
+
sum = sum + i
|
53
|
+
enddo
|
54
|
+
end subroutine timeDelay
|
55
|
+
|
56
|
+
beginTest ComputesSeconds
|
57
|
+
seconds = secSinceLast()
|
58
|
+
call timeDelay (seconds)
|
59
|
+
seconds = secSinceLast()
|
60
|
+
IsTrue( seconds > 0.0 )
|
61
|
+
endTest
|
62
|
+
|
63
|
+
beginTest ComputesSecondsSpecial
|
64
|
+
real :: expectedSeconds
|
65
|
+
|
66
|
+
seconds = secSinceLast()
|
67
|
+
dateAndTime1 = last
|
68
|
+
call timeDelay (seconds)
|
69
|
+
seconds = secSinceLast()
|
70
|
+
dateAndTime2 = last
|
71
|
+
expectedSeconds = secBetween(dateAndTime1,dateAndTime2)
|
72
|
+
IsRealEqual( expectedSeconds, seconds )
|
73
|
+
endTest
|
data/lib/funit.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
require 'funit/compiler'
|
3
|
+
require 'funit/functions'
|
4
|
+
require 'funit/assertions'
|
5
|
+
require 'funit/testsuite'
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'fortran'
|
9
|
+
|
10
|
+
module Funit
|
11
|
+
|
12
|
+
VERSION = '0.9.0'
|
13
|
+
|
14
|
+
##
|
15
|
+
# run all tests
|
16
|
+
|
17
|
+
def run_tests
|
18
|
+
Compiler.new# a test for compiler env set (FIXME: remove this later)
|
19
|
+
write_test_runner( test_suites = parse_command_line )
|
20
|
+
test_suites.each{ |test_suite| TestSuite.new test_suite }
|
21
|
+
compile_tests test_suites
|
22
|
+
raise "TestRunner failed to execute." unless system './TestRunner'
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
#--
|
28
|
+
# Copyright 2006-2007 United States Government as represented by
|
29
|
+
# NASA Langley Research Center. No copyright is claimed in
|
30
|
+
# the United States under Title 17, U.S. Code. All Other Rights
|
31
|
+
# Reserved.
|
32
|
+
#
|
33
|
+
# This file is governed by the NASA Open Source Agreement.
|
34
|
+
# See License.txt for details.
|
35
|
+
#++
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
module Funit
|
4
|
+
|
5
|
+
##
|
6
|
+
# Fortran assertion macro definitions
|
7
|
+
|
8
|
+
module Assertions
|
9
|
+
|
10
|
+
def istrue(line)
|
11
|
+
line.match(/\((.+)\)/)
|
12
|
+
@type = 'IsTrue'
|
13
|
+
@condition = ".not.(#$1)"
|
14
|
+
@message = "\"#$1 is not true\""
|
15
|
+
syntax_error("invalid body for #@type",@suite_name) unless $1=~/\S+/
|
16
|
+
write_assert
|
17
|
+
end
|
18
|
+
|
19
|
+
def isfalse(line)
|
20
|
+
line.match(/\((.+)\)/)
|
21
|
+
@type = 'IsFalse'
|
22
|
+
@condition = "#$1"
|
23
|
+
@message = "\"#$1 is not false\""
|
24
|
+
syntax_error("invalid body for #@type",@suite_name) unless $1=~/\S+/
|
25
|
+
write_assert
|
26
|
+
end
|
27
|
+
|
28
|
+
def isrealequal(line)
|
29
|
+
line.match(/\((.*)\)/)
|
30
|
+
expected, actual = *(get_args($1))
|
31
|
+
@type = 'IsRealEqual'
|
32
|
+
@condition = ".not.(#{expected}+2*spacing(real(#{expected})).ge.#{actual} &\n .and.#{expected}-2*spacing(real(#{expected})).le.#{actual})"
|
33
|
+
@message = "\"#{actual} (\",#{actual},\") is not\",#{expected},\"within\",2*spacing(real(#{expected}))"
|
34
|
+
syntax_error("invalid body for #@type",@suite_name) unless $&
|
35
|
+
write_assert
|
36
|
+
end
|
37
|
+
|
38
|
+
def isequalwithin(line)
|
39
|
+
line.match(/\((.*)\)/)
|
40
|
+
expected, actual, tolerance = *(get_args($1))
|
41
|
+
@type = 'IsEqualWithin'
|
42
|
+
@condition = ".not.(#{actual}+#{tolerance}.ge.#{expected} &\n .and.#{actual}-#{tolerance}.le.#{expected})"
|
43
|
+
@message = "\"#{expected} (\",#{expected},\") is not\",#{actual},\"within\",#{tolerance}"
|
44
|
+
syntax_error("invalid body for #@type",@suite_name) unless $&
|
45
|
+
write_assert
|
46
|
+
end
|
47
|
+
|
48
|
+
def isequal(line)
|
49
|
+
line.match(/\((\w+\(.*\)|[^,]+),(.+)\)/)
|
50
|
+
@type = 'IsEqual'
|
51
|
+
@condition = ".not.(#$1==#$2)"
|
52
|
+
@message = "\"#$1 (\",#$1,\") is not\", #$2"
|
53
|
+
syntax_error("invalid body for #@type",@suite_name) unless $&
|
54
|
+
write_assert
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# An argument scanner thanks to James Edward Gray II
|
59
|
+
# by way of ruby-talk mailing list.
|
60
|
+
|
61
|
+
def get_args(string)
|
62
|
+
scanner = ::StringScanner.new(string)
|
63
|
+
result = scanner.eos? ? [] : ['']
|
64
|
+
paren_depth = 0
|
65
|
+
until scanner.eos?
|
66
|
+
if scanner.scan(/[^(),]+/)
|
67
|
+
# do nothing--we found the part of the argument we need to add
|
68
|
+
elsif scanner.scan(/\(/)
|
69
|
+
paren_depth += 1
|
70
|
+
elsif scanner.scan(/\)/)
|
71
|
+
paren_depth -= 1
|
72
|
+
elsif scanner.scan(/,\s*/) and paren_depth.zero?
|
73
|
+
result << ''
|
74
|
+
next
|
75
|
+
end
|
76
|
+
result.last << scanner.matched
|
77
|
+
end
|
78
|
+
result
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Translate the assertion to Fortran.
|
83
|
+
|
84
|
+
def write_assert
|
85
|
+
<<-OUTPUT
|
86
|
+
! #@type assertion
|
87
|
+
numAsserts = numAsserts + 1
|
88
|
+
if (noAssertFailed) then
|
89
|
+
if (#@condition) then
|
90
|
+
print *, " *#@type failed* in test #@test_name &
|
91
|
+
&[#{@suite_name}.fun:#{@line_number.to_s}]"
|
92
|
+
print *, " ", #@message
|
93
|
+
print *, ""
|
94
|
+
noAssertFailed = .false.
|
95
|
+
numFailures = numFailures + 1
|
96
|
+
else
|
97
|
+
numAssertsTested = numAssertsTested + 1
|
98
|
+
endif
|
99
|
+
endif
|
100
|
+
OUTPUT
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#--
|
107
|
+
# Copyright 2006-2007 United States Government as represented by
|
108
|
+
# NASA Langley Research Center. No copyright is claimed in
|
109
|
+
# the United States under Title 17, U.S. Code. All Other Rights
|
110
|
+
# Reserved.
|
111
|
+
#
|
112
|
+
# This file is governed by the NASA Open Source Agreement.
|
113
|
+
# See License.txt for details.
|
114
|
+
#++
|