funit-12 0.12.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/History.txt +113 -0
- data/License.txt +263 -0
- data/Manifest.txt +29 -0
- data/README.txt +124 -0
- data/bin/funit-12 +72 -0
- data/examples/CFD/FluxFunctions.f90 +34 -0
- data/examples/CFD/FluxFunctions.fun +51 -0
- data/examples/CFD/Gammas.f90 +7 -0
- data/examples/CFD/GasModel.f90 +16 -0
- data/examples/CFD/GasModel.fun +24 -0
- data/examples/ReadData/time_series_data.f90 +27 -0
- data/examples/ReadData/time_series_data.fun +33 -0
- data/examples/StopWatch/StopWatch.f90 +50 -0
- data/examples/StopWatch/StopWatch.fun +77 -0
- data/lib/funit.rb +87 -0
- data/lib/funit/assertions.rb +125 -0
- data/lib/funit/c_tools.rb +205 -0
- data/lib/funit/compiler.rb +33 -0
- data/lib/funit/functions.rb +150 -0
- data/lib/funit/testsuite.rb +211 -0
- data/pitch/slides.tex +138 -0
- data/test/test_compiler.rb +16 -0
- data/test/test_functions.rb +10 -0
- data/test/test_funit.rb +125 -0
- data/test/test_testsuite.rb +111 -0
- data/utils/errorFinder.el +88 -0
- data/utils/funit-generic-mode.el +22 -0
- data/utils/funit-mode.el +113 -0
- metadata +118 -0
data/bin/funit-12
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
# Main fUnit routine
|
4
|
+
|
5
|
+
begin require 'rubygems'; rescue LoadError; end
|
6
|
+
|
7
|
+
$:.push "#{File.dirname $0}/../lib"
|
8
|
+
require 'funit'
|
9
|
+
require 'optparse'
|
10
|
+
require 'ostruct'
|
11
|
+
|
12
|
+
include Funit
|
13
|
+
|
14
|
+
funit_data = OpenStruct.new
|
15
|
+
funit_data.prog_source_dirs = ['.']
|
16
|
+
funit_data.c_code = Funit::C_compile.new
|
17
|
+
|
18
|
+
OptionParser.new do |opts|
|
19
|
+
opts.banner = <<-END_OF_HELP
|
20
|
+
To use fUnit, type:
|
21
|
+
funit [-options] [test_file_name(s)]
|
22
|
+
The argument(s) is optional. If no argument is given, then all the .fun files inside the working directory will be used.
|
23
|
+
END_OF_HELP
|
24
|
+
|
25
|
+
opts.separator ""
|
26
|
+
opts.separator "Specific options:"
|
27
|
+
|
28
|
+
opts.on("-s","--source <dir>",String,"Specify a directory for the non-test source") do |dir|
|
29
|
+
funit_data.prog_source_dirs << dir.chomp("/")
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-l","--link_c_code <dir>",String,"Specify a directory of C/C++ code that must be compiled/linked") do |dir|
|
33
|
+
funit_data.c_code.compile_library(dir)
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on_tail("--clean","To remove the files generated by funit") do
|
37
|
+
funit_data.c_code.clean_c_code
|
38
|
+
Funit::clean_genFiles
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.separator ""
|
43
|
+
opts.separator "Common options:"
|
44
|
+
|
45
|
+
opts.on_tail("-v","--version","Print version") do
|
46
|
+
puts "funit version #{Funit::VERSION}"
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on_tail("-h", "--help", "Detailed overview of funit options") do
|
51
|
+
puts opts
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
|
55
|
+
end.parse!
|
56
|
+
|
57
|
+
funit_data.prog_source_dirs.flatten!
|
58
|
+
funit_data.prog_source_dirs.uniq!
|
59
|
+
|
60
|
+
Funit::check_for_FSFLAG
|
61
|
+
|
62
|
+
Funit::run_tests(funit_data)
|
63
|
+
|
64
|
+
#--
|
65
|
+
# Copyright 2006-2007 United States Government as represented by
|
66
|
+
# NASA Langley Research Center. No copyright is claimed in
|
67
|
+
# the United States under Title 17, U.S. Code. All Other Rights
|
68
|
+
# Reserved.
|
69
|
+
#
|
70
|
+
# This file is governed by the NASA Open Source Agreement.
|
71
|
+
# See License.txt for details.
|
72
|
+
#++
|
@@ -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,51 @@
|
|
1
|
+
test_suite FluxFunctions
|
2
|
+
|
3
|
+
real :: leftState, rightState, interfaceFlux
|
4
|
+
|
5
|
+
setup
|
6
|
+
leftState = 0
|
7
|
+
rightState = 1
|
8
|
+
end setup
|
9
|
+
|
10
|
+
test FluxZero
|
11
|
+
real :: state
|
12
|
+
state = 0
|
13
|
+
Assert_Equal_Within( 0, Flux(state), 0.00001 )
|
14
|
+
end test
|
15
|
+
|
16
|
+
test FluxOne
|
17
|
+
real :: state = 1
|
18
|
+
Assert_Equal_Within( 0.5, Flux(state), 0.00001 )
|
19
|
+
end test
|
20
|
+
|
21
|
+
test RoeAvgZero
|
22
|
+
Assert_Real_Equal( 0, RoeAvg(0.0,0.0) )
|
23
|
+
Assert_False( RoeAvg(0.0,0.0)==1 )
|
24
|
+
end test
|
25
|
+
|
26
|
+
test RoeAvgKnown
|
27
|
+
Assert_Real_Equal( 0.5, RoeAvg(leftState,rightState) )
|
28
|
+
Assert_True( RoeAvg(leftState,rightState) > 0 )
|
29
|
+
end test
|
30
|
+
|
31
|
+
test CentralFluxKnown
|
32
|
+
call CentralFlux( leftState, rightState, interfaceFlux )
|
33
|
+
Assert_Equal_Within( 0.25, interfaceFlux, 0.001 )
|
34
|
+
Assert_Equal_Within( 0.25, interfaceFlux, 0.00000001 )
|
35
|
+
Assert_Equal( 0.25, interfaceFlux )
|
36
|
+
end test
|
37
|
+
|
38
|
+
test RoeFluxExpansionShock
|
39
|
+
leftState = -1
|
40
|
+
call RoeFlux( leftState, rightState, interfaceFlux )
|
41
|
+
Assert_Equal( 0.5, interfaceFlux )
|
42
|
+
end test
|
43
|
+
|
44
|
+
test RoeFluxZero
|
45
|
+
rightState = 0
|
46
|
+
call RoeFlux( leftState, rightState, interfaceFlux )
|
47
|
+
Assert_Real_Equal( 0, interfaceFlux )
|
48
|
+
Assert_Equal( 0, interfaceFlux )
|
49
|
+
end test
|
50
|
+
|
51
|
+
end test_suite
|
@@ -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,24 @@
|
|
1
|
+
test_suite GasModel
|
2
|
+
|
3
|
+
real :: Pressure, Density, Energy
|
4
|
+
|
5
|
+
test PerfectPZeroed
|
6
|
+
real, parameter :: zero = 0
|
7
|
+
call PerfectP (zero, zero, Pressure)
|
8
|
+
Assert_Real_Equal( 0, Pressure )
|
9
|
+
Assert_Equal_within( 0, Pressure, 0.0000000001 )
|
10
|
+
end test
|
11
|
+
|
12
|
+
test Warbler
|
13
|
+
end test
|
14
|
+
|
15
|
+
test PerfectPKnown
|
16
|
+
real :: Density = 1
|
17
|
+
Energy = 1
|
18
|
+
call PerfectP( Density, Energy, Pressure )
|
19
|
+
Assert_Real_Equal( 0.4, Pressure )
|
20
|
+
Assert_True( Pressure > 0 )
|
21
|
+
Assert_False( Pressure < 0 )
|
22
|
+
end test
|
23
|
+
|
24
|
+
end test_suite
|
@@ -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,33 @@
|
|
1
|
+
test_suite time_series_data
|
2
|
+
|
3
|
+
character(len=10), parameter :: FILE = 'values.txt'
|
4
|
+
|
5
|
+
setup
|
6
|
+
open(8, file=FILE)
|
7
|
+
write(8,'(a)'), '200609300000 0.223200546265E+003'
|
8
|
+
write(8,'(a)'), '200609300132 0.226001495361E+003'
|
9
|
+
close(8)
|
10
|
+
end setup
|
11
|
+
|
12
|
+
test load_time_series_data_from_file
|
13
|
+
call read_time_series( FILE )
|
14
|
+
Assert_Equal( 2006, ts_data(1)%date_time%year )
|
15
|
+
Assert_Equal( 9, ts_data(1)%date_time%month )
|
16
|
+
Assert_Equal( 30, ts_data(1)%date_time%day )
|
17
|
+
Assert_Equal( 0, ts_data(1)%date_time%hour )
|
18
|
+
Assert_Equal( 0, ts_data(1)%date_time%minute )
|
19
|
+
Assert_Equal_Within( 223.2, ts_data(1)%value, 0.1 )
|
20
|
+
Assert_Equal( 2006, ts_data(2)%date_time%year )
|
21
|
+
Assert_Equal( 9, ts_data(2)%date_time%month )
|
22
|
+
Assert_Equal( 30, ts_data(2)%date_time%day )
|
23
|
+
Assert_Equal( 1, ts_data(2)%date_time%hour )
|
24
|
+
Assert_Equal( 32, ts_data(2)%date_time%minute )
|
25
|
+
Assert_Equal_Within( 226.0, ts_data(2)%value, 0.1 )
|
26
|
+
end test
|
27
|
+
|
28
|
+
teardown
|
29
|
+
call system('/bin/rm '//FILE)
|
30
|
+
end teardown
|
31
|
+
|
32
|
+
end test_suite
|
33
|
+
|
@@ -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,77 @@
|
|
1
|
+
test_suite StopWatch
|
2
|
+
|
3
|
+
integer, dimension(8) :: dateAndTime1, dateAndTime2
|
4
|
+
real :: seconds
|
5
|
+
|
6
|
+
setup
|
7
|
+
NotInitialized = .TRUE.
|
8
|
+
last = 0
|
9
|
+
seconds = HUGE(0.0)
|
10
|
+
end setup
|
11
|
+
|
12
|
+
test SystemDateAndTimeWorks
|
13
|
+
call date_and_time(values=dateAndTime1)
|
14
|
+
Assert_True( dateAndTime1(1) /= -huge(0) )
|
15
|
+
Assert_True( size(dateAndTime1,1) == 8 )
|
16
|
+
end test
|
17
|
+
|
18
|
+
! test secBetween
|
19
|
+
test OneMSecDifference
|
20
|
+
dateAndTime1 = (/ 2000, 1, 1, 0, 0, 0, 0, 0 /)
|
21
|
+
dateAndTime2 = (/ 2000, 1, 1, 0, 0, 0, 0, 1 /)
|
22
|
+
seconds = SecBetween(dateAndTime1, dateAndTime2)
|
23
|
+
Assert_Real_Equal( 0.001, seconds)
|
24
|
+
end test
|
25
|
+
|
26
|
+
test MinuteRollover
|
27
|
+
dateAndTime1 = (/ 2000, 1, 1, 0, 0, 0,59, 0 /)
|
28
|
+
dateAndTime2 = (/ 2000, 1, 1, 0, 0, 1, 0, 0 /)
|
29
|
+
seconds = SecBetween(dateAndTime1, dateAndTime2)
|
30
|
+
Assert_Real_Equal( 1.0, seconds )
|
31
|
+
end test
|
32
|
+
|
33
|
+
! test secSinceLast
|
34
|
+
test InitializationState
|
35
|
+
Assert_True(notInitialized)
|
36
|
+
seconds = secSinceLast()
|
37
|
+
Assert_False(notInitialized)
|
38
|
+
seconds = secSinceLast()
|
39
|
+
Assert_False(notInitialized)
|
40
|
+
end test
|
41
|
+
|
42
|
+
test InitiallyReturnsZero
|
43
|
+
seconds = secSinceLast()
|
44
|
+
Assert_Real_Equal( 0.0, seconds )
|
45
|
+
call timeDelay(seconds)
|
46
|
+
seconds = secSinceLast()
|
47
|
+
Assert_True( seconds /= 0.0 )
|
48
|
+
end test
|
49
|
+
|
50
|
+
subroutine timeDelay (sum)
|
51
|
+
integer :: i
|
52
|
+
real :: sum
|
53
|
+
do i = 1, 1000000
|
54
|
+
sum = sum + i
|
55
|
+
enddo
|
56
|
+
end subroutine timeDelay
|
57
|
+
|
58
|
+
test ComputesSeconds
|
59
|
+
seconds = secSinceLast()
|
60
|
+
call timeDelay (seconds)
|
61
|
+
seconds = secSinceLast()
|
62
|
+
Assert_True( seconds > 0.0 )
|
63
|
+
end test
|
64
|
+
|
65
|
+
test ComputesSecondsSpecial
|
66
|
+
real :: expectedSeconds
|
67
|
+
|
68
|
+
seconds = secSinceLast()
|
69
|
+
dateAndTime1 = last
|
70
|
+
call timeDelay (seconds)
|
71
|
+
seconds = secSinceLast()
|
72
|
+
dateAndTime2 = last
|
73
|
+
expectedSeconds = secBetween(dateAndTime1,dateAndTime2)
|
74
|
+
Assert_Real_Equal( expectedSeconds, seconds )
|
75
|
+
end test
|
76
|
+
|
77
|
+
end test_suite
|
data/lib/funit.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
require 'fortran_dependencies'
|
4
|
+
rescue LoadError
|
5
|
+
STDERR.puts "gem install fortran"
|
6
|
+
exit 1
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'funit/compiler'
|
10
|
+
require 'funit/functions'
|
11
|
+
require 'funit/assertions'
|
12
|
+
require 'funit/testsuite'
|
13
|
+
require 'funit/c_tools'
|
14
|
+
require 'fileutils'
|
15
|
+
|
16
|
+
module Funit
|
17
|
+
|
18
|
+
VERSION = '0.12.1'
|
19
|
+
|
20
|
+
##
|
21
|
+
# run all tests
|
22
|
+
|
23
|
+
def run_tests(funit_data)
|
24
|
+
Compiler.new# a test for compiler env set (FIXME: remove this later)
|
25
|
+
write_test_runner( test_files = parse_command_line )
|
26
|
+
test_suites = []
|
27
|
+
test_files.each{ |test_file|
|
28
|
+
tf_content = IO.read(test_file+'.fun')
|
29
|
+
tf_content.scan(/test_suite\s+(\w+)(.*?)end\s+test_suite/m).each{|ts|
|
30
|
+
ts_name = $1
|
31
|
+
ts_content = $2
|
32
|
+
if((!File.exist?(ts_name+"_fun.f90")) || File.mtime(ts_name+"_fun.f90") < File.mtime(test_file+".fun")) then
|
33
|
+
if ( File.read(ts_name+'.f90').match(/\s*module\s+#{ts_name}/i) ) then
|
34
|
+
TestSuite.new(ts_name, ts_content, false)
|
35
|
+
else
|
36
|
+
TestSuite.new(ts_name, ts_content, true)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
test_suites.push(ts_name)
|
40
|
+
}
|
41
|
+
}
|
42
|
+
compile_tests(test_suites,funit_data)
|
43
|
+
exit 1 unless system "env PATH='.' TestRunner"
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# remove files generated by fUnit
|
48
|
+
|
49
|
+
def clean_genFiles
|
50
|
+
module_names = Dir["**/*.fun"].map{|mn| mn.chomp(".fun")}
|
51
|
+
tbCancelled = module_names.map{|mn| mn+"_fun."} + ["TestRunner."]
|
52
|
+
tbCancelled = tbCancelled.map{|tbc| [tbc+"f90",tbc+"o",tbc+"MOD"]}.flatten
|
53
|
+
tbCancelled += Dir["**/TestRunner"]
|
54
|
+
tbCancelled += Dir["**/makeTestRunner"]
|
55
|
+
tbCancelled = (tbCancelled+tbCancelled.map{|tbc| tbc.downcase}).uniq
|
56
|
+
FileUtils.rm_f(tbCancelled)
|
57
|
+
end
|
58
|
+
|
59
|
+
def check_for_FSFLAG
|
60
|
+
if(ENV['FSFLAG'].nil?) then
|
61
|
+
puts <<-EOF
|
62
|
+
No environment variable FSFLAG set.
|
63
|
+
|
64
|
+
For example for most compilers such as gfortran you will need: -I
|
65
|
+
sh: export FSFLAG=-I
|
66
|
+
csh: setenv FSFLAG -I
|
67
|
+
windows: set FSFLAG=-I
|
68
|
+
|
69
|
+
but for some such as Sun's f95 compiler you will need: -M
|
70
|
+
sh: export FSFLAG=-M
|
71
|
+
csh: setenv FSFLAG -M
|
72
|
+
windows: set FSFLAG=-M
|
73
|
+
EOF
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
#--
|
80
|
+
# Copyright 2006-2007 United States Government as represented by
|
81
|
+
# NASA Langley Research Center. No copyright is claimed in
|
82
|
+
# the United States under Title 17, U.S. Code. All Other Rights
|
83
|
+
# Reserved.
|
84
|
+
#
|
85
|
+
# This file is governed by the NASA Open Source Agreement.
|
86
|
+
# See License.txt for details.
|
87
|
+
#++
|