funit-12 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
#++
|