funit 0.9.0
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.
- 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,33 @@
|
|
1
|
+
module Funit
|
2
|
+
|
3
|
+
##
|
4
|
+
# Fortran compiler
|
5
|
+
|
6
|
+
class Compiler
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
error_message = <<-COMPILER
|
10
|
+
Fortran compiler environment variable 'FC' not set.
|
11
|
+
|
12
|
+
For example, if you had the g95 compiler:
|
13
|
+
|
14
|
+
sh: export FC=g95
|
15
|
+
csh: setenv FC g95
|
16
|
+
windows: set FC=C:\\Program Files\\g95
|
17
|
+
COMPILER
|
18
|
+
raise error_message unless ENV['FC']
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
#--
|
26
|
+
# Copyright 2006-2007 United States Government as represented by
|
27
|
+
# NASA Langley Research Center. No copyright is claimed in
|
28
|
+
# the United States under Title 17, U.S. Code. All Other Rights
|
29
|
+
# Reserved.
|
30
|
+
#
|
31
|
+
# This file is governed by the NASA Open Source Agreement.
|
32
|
+
# See License.txt for details.
|
33
|
+
#++
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Funit
|
4
|
+
|
5
|
+
TEST_RUNNER = ERB.new %q{
|
6
|
+
! TestRunner.f90 - runs fUnit test suites
|
7
|
+
!
|
8
|
+
! <%= File.basename $0 %> generated this file on <%= Time.now %>.
|
9
|
+
|
10
|
+
program TestRunner
|
11
|
+
<%= test_suites.inject('') { |result,test_suite| result << "\n use #{test_suite}_fun" } %>
|
12
|
+
|
13
|
+
implicit none
|
14
|
+
|
15
|
+
integer :: numTests, numAsserts, numAssertsTested, numFailures
|
16
|
+
|
17
|
+
<% test_suites.each do |ts| %>
|
18
|
+
print *, ""
|
19
|
+
print *, "<%= ts %> test suite:"
|
20
|
+
call test_<%= ts %> &
|
21
|
+
( numTests, numAsserts, numAssertsTested, numFailures )
|
22
|
+
print *, "Passed", numAssertsTested, "of", numAsserts, &
|
23
|
+
"possible asserts comprising", &
|
24
|
+
numTests-numFailures, "of", numTests, "tests."
|
25
|
+
<% end %>
|
26
|
+
print *, ""
|
27
|
+
|
28
|
+
end program TestRunner
|
29
|
+
}.gsub(/^/,' '), nil, '<>' # turn off newlines due to <%%>
|
30
|
+
|
31
|
+
def requested_modules(module_names)
|
32
|
+
if (module_names.empty?)
|
33
|
+
module_names = Dir["*.fun"].each{ |mod| mod.chomp! ".fun" }
|
34
|
+
end
|
35
|
+
module_names
|
36
|
+
end
|
37
|
+
|
38
|
+
def funit_exists?(module_name)
|
39
|
+
File.exists? "#{module_name}.fun"
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_command_line
|
43
|
+
|
44
|
+
module_names = requested_modules(ARGV)
|
45
|
+
|
46
|
+
if module_names.empty?
|
47
|
+
raise " *Error: no test suites found in this directory"
|
48
|
+
end
|
49
|
+
|
50
|
+
module_names.each do |mod|
|
51
|
+
unless funit_exists?(mod)
|
52
|
+
error_message = <<-FUNITDOESNOTEXIST
|
53
|
+
Error: could not find test suite #{mod}.fun
|
54
|
+
Test suites available in this directory:
|
55
|
+
#{requested_modules([]).join(' ')}
|
56
|
+
|
57
|
+
Usage: #{File.basename $0} [test names (w/o .fun suffix)]
|
58
|
+
FUNITDOESNOTEXIST
|
59
|
+
raise error_message
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
def write_test_runner test_suites
|
66
|
+
File.open("TestRunner.f90", "w") do |file|
|
67
|
+
file.puts TEST_RUNNER.result(binding)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def syntax_error( message, test_suite )
|
72
|
+
raise "\n *Error: #{message} [#{test_suite}.fun:#$.]\n\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
def warning( message, test_suite )
|
76
|
+
$stderr.puts "\n *Warning: #{message} [#{test_suite}.fun:#$.]"
|
77
|
+
end
|
78
|
+
|
79
|
+
def compile_tests test_suites
|
80
|
+
puts "computing dependencies"
|
81
|
+
dependencies = Fortran::Dependencies.new
|
82
|
+
puts "locating associated source files and sorting for compilation"
|
83
|
+
required_sources = dependencies.required_source_files('TestRunner.f90')
|
84
|
+
|
85
|
+
puts compile = "#{ENV['FC']} #{ENV['FCFLAGS']} -o TestRunner \\\n #{required_sources.join(" \\\n ")}"
|
86
|
+
|
87
|
+
raise "Compile failed." unless system compile
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
#--
|
93
|
+
# Copyright 2006-2007 United States Government as represented by
|
94
|
+
# NASA Langley Research Center. No copyright is claimed in
|
95
|
+
# the United States under Title 17, U.S. Code. All Other Rights
|
96
|
+
# Reserved.
|
97
|
+
#
|
98
|
+
# This file is governed by the NASA Open Source Agreement.
|
99
|
+
# See License.txt for details.
|
100
|
+
#++
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'funit/assertions'
|
2
|
+
require 'funit/functions'
|
3
|
+
require 'ftools' # FIXME: use fileutils
|
4
|
+
|
5
|
+
module Funit
|
6
|
+
|
7
|
+
include Assertions # FIXME
|
8
|
+
|
9
|
+
##
|
10
|
+
# Create testsuite wrapper code
|
11
|
+
|
12
|
+
class TestSuite < File
|
13
|
+
|
14
|
+
ASSERTION_PATTERN = /Is(RealEqual|False|True|EqualWithin|Equal)\(.*\)/i
|
15
|
+
KEYWORDS = /(begin|end)(Setup|Teardown|Test)|Is(RealEqual|Equal|False|True|EqualWithin)\(.*\)/i
|
16
|
+
COMMENT_LINE = /^\s*!/
|
17
|
+
|
18
|
+
include Funit #FIXME
|
19
|
+
|
20
|
+
def initialize suite_name
|
21
|
+
@line_number = 'blank'
|
22
|
+
@suite_name = suite_name
|
23
|
+
return nil unless funit_exists?(suite_name)
|
24
|
+
File.delete(suite_name+"_fun.f90") if File.exists?(suite_name+"_fun.f90")
|
25
|
+
super(suite_name+"_fun.f90","w")
|
26
|
+
@tests, @setup, @teardown = [], [], []
|
27
|
+
top_wrapper
|
28
|
+
expand
|
29
|
+
close
|
30
|
+
end
|
31
|
+
|
32
|
+
def top_wrapper
|
33
|
+
puts <<-TOP
|
34
|
+
! #{@suite_name}_fun.f90 - a unit test suite for #{@suite_name}.f90
|
35
|
+
!
|
36
|
+
! #{File.basename $0} generated this file from #{@suite_name}.fun
|
37
|
+
! at #{Time.now}
|
38
|
+
|
39
|
+
module #{@suite_name}_fun
|
40
|
+
|
41
|
+
use #{@suite_name}
|
42
|
+
|
43
|
+
implicit none
|
44
|
+
|
45
|
+
logical :: noAssertFailed
|
46
|
+
|
47
|
+
public :: test_#@suite_name
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
integer :: numTests = 0
|
52
|
+
integer :: numAsserts = 0
|
53
|
+
integer :: numAssertsTested = 0
|
54
|
+
integer :: numFailures = 0
|
55
|
+
|
56
|
+
TOP
|
57
|
+
end
|
58
|
+
|
59
|
+
def expand
|
60
|
+
funit_file = @suite_name+".fun"
|
61
|
+
$stderr.print "expanding #{funit_file}..."
|
62
|
+
|
63
|
+
funit_contents = IO.readlines(funit_file)
|
64
|
+
@funit_total_lines = funit_contents.length
|
65
|
+
|
66
|
+
while (line = funit_contents.shift) && line !~ KEYWORDS
|
67
|
+
puts line
|
68
|
+
end
|
69
|
+
|
70
|
+
funit_contents.unshift line
|
71
|
+
|
72
|
+
puts " contains\n\n"
|
73
|
+
|
74
|
+
while (line = funit_contents.shift)
|
75
|
+
case line
|
76
|
+
when COMMENT_LINE
|
77
|
+
puts line
|
78
|
+
when /beginSetup/i
|
79
|
+
add_to_setup funit_contents
|
80
|
+
when /beginTeardown/i
|
81
|
+
add_to_teardown funit_contents
|
82
|
+
when /XbeginTest\s+(\w+)/i
|
83
|
+
ignore_test($1,funit_contents)
|
84
|
+
when /beginTest\s+(\w+)/i
|
85
|
+
a_test($1,funit_contents)
|
86
|
+
when /beginTest/i
|
87
|
+
syntax_error "no name given for beginTest", @suite_name
|
88
|
+
when /end(Setup|Teardown|Test)/i
|
89
|
+
syntax_error "no matching begin#$1 for an #$&", @suite_name
|
90
|
+
when ASSERTION_PATTERN
|
91
|
+
syntax_error "#$1 assert not in a test block", @suite_name
|
92
|
+
else
|
93
|
+
puts line
|
94
|
+
end
|
95
|
+
end
|
96
|
+
$stderr.puts "done."
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_to_setup funit_contents
|
100
|
+
while (line = funit_contents.shift) && line !~ /endSetup/i
|
101
|
+
@setup.push line
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def add_to_teardown funit_contents
|
106
|
+
while (line = funit_contents.shift) && line !~ /endTeardown/i
|
107
|
+
@teardown.push line
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def ignore_test test_name, funit_contents
|
112
|
+
warning("Ignoring test: #{test_name}", @suite_name)
|
113
|
+
line = funit_contents.shift while line !~ /endTest/i
|
114
|
+
end
|
115
|
+
|
116
|
+
def a_test test_name, funit_contents
|
117
|
+
@test_name = test_name
|
118
|
+
@tests.push test_name
|
119
|
+
syntax_error("test name #@test_name not unique",@suite_name) if (@tests.uniq!)
|
120
|
+
|
121
|
+
puts " subroutine #{test_name}\n\n"
|
122
|
+
|
123
|
+
num_of_asserts = 0
|
124
|
+
|
125
|
+
while (line = funit_contents.shift) && line !~ /endTest/i
|
126
|
+
case line
|
127
|
+
when COMMENT_LINE
|
128
|
+
puts line
|
129
|
+
when /Is(RealEqual|False|True|EqualWithin|Equal)/i
|
130
|
+
@line_number = @funit_total_lines - funit_contents.length
|
131
|
+
num_of_asserts += 1
|
132
|
+
puts send( $&.downcase!, line )
|
133
|
+
else
|
134
|
+
puts line
|
135
|
+
end
|
136
|
+
end
|
137
|
+
warning("no asserts in test", @suite_name) if num_of_asserts == 0
|
138
|
+
|
139
|
+
puts "\n numTests = numTests + 1\n\n"
|
140
|
+
puts " end subroutine #{test_name}\n\n"
|
141
|
+
end
|
142
|
+
|
143
|
+
def close
|
144
|
+
puts "\n subroutine Setup"
|
145
|
+
puts @setup
|
146
|
+
puts " noAssertFailed = .true."
|
147
|
+
puts " end subroutine Setup\n\n"
|
148
|
+
|
149
|
+
puts "\n subroutine Teardown"
|
150
|
+
puts @teardown
|
151
|
+
puts " end subroutine Teardown\n\n"
|
152
|
+
|
153
|
+
puts <<-NEXTONE
|
154
|
+
|
155
|
+
subroutine test_#{@suite_name}( nTests, nAsserts, nAssertsTested, nFailures )
|
156
|
+
|
157
|
+
integer :: nTests
|
158
|
+
integer :: nAsserts
|
159
|
+
integer :: nAssertsTested
|
160
|
+
integer :: nFailures
|
161
|
+
|
162
|
+
continue
|
163
|
+
NEXTONE
|
164
|
+
|
165
|
+
@tests.each do |test_name|
|
166
|
+
puts "\n call Setup"
|
167
|
+
puts " call #{test_name}"
|
168
|
+
puts " call Teardown"
|
169
|
+
end
|
170
|
+
|
171
|
+
puts <<-LASTONE
|
172
|
+
|
173
|
+
nTests = numTests
|
174
|
+
nAsserts = numAsserts
|
175
|
+
nAssertsTested = numAssertsTested
|
176
|
+
nFailures = numFailures
|
177
|
+
|
178
|
+
end subroutine test_#{@suite_name}
|
179
|
+
|
180
|
+
end module #{@suite_name}_fun
|
181
|
+
LASTONE
|
182
|
+
super
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
#--
|
190
|
+
# Copyright 2006-2007 United States Government as represented by
|
191
|
+
# NASA Langley Research Center. No copyright is claimed in
|
192
|
+
# the United States under Title 17, U.S. Code. All Other Rights
|
193
|
+
# Reserved.
|
194
|
+
#
|
195
|
+
# This file is governed by the NASA Open Source Agreement.
|
196
|
+
# See License.txt for details.
|
197
|
+
#++
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'funit/compiler'
|
3
|
+
|
4
|
+
class TestCompiler < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_no_environment_compiler_name
|
7
|
+
begin
|
8
|
+
orig_FC = ENV['FC']
|
9
|
+
ENV['FC'] = nil
|
10
|
+
assert_raises(RuntimeError) {Funit::Compiler.new}
|
11
|
+
ensure
|
12
|
+
ENV['FC'] = orig_FC
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/test/test_funit.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'funit'
|
3
|
+
require 'ftools' # FIXME: migrate to fileutils
|
4
|
+
|
5
|
+
class TestFunit < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include Funit # FIXME
|
8
|
+
include Funit::Assertions # FIXME
|
9
|
+
|
10
|
+
def setup
|
11
|
+
File.rm_f(*Dir["dummyunit*"])
|
12
|
+
File.rm_f(*Dir["unit*"])
|
13
|
+
File.rm_f(*Dir["ydsbe*"])
|
14
|
+
File.rm_f(*Dir["lmzd*"])
|
15
|
+
File.rm_f(*Dir["ldfdl*"])
|
16
|
+
File.rm_f(*Dir["ydsbe*"])
|
17
|
+
File.rm_f(*Dir["TestRunner*"])
|
18
|
+
File.rm_f(*Dir["a.out"])
|
19
|
+
end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
File.rm_f(*Dir["dummyunit*"])
|
23
|
+
File.rm_f(*Dir["unit*"])
|
24
|
+
File.rm_f(*Dir["ydsbe*"])
|
25
|
+
File.rm_f(*Dir["lmzd*"])
|
26
|
+
File.rm_f(*Dir["ldfdl*"])
|
27
|
+
File.rm_f(*Dir["ydsbe*"])
|
28
|
+
File.rm_f(*Dir["TestRunner*"])
|
29
|
+
File.rm_f(*Dir["a.out"])
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_main_driver_compiles
|
33
|
+
write_test_runner []
|
34
|
+
assert File.exists?("TestRunner.f90")
|
35
|
+
assert system("#{ENV['FC']} TestRunner.f90")
|
36
|
+
assert File.exists?("a.out")
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_is_equal
|
40
|
+
@suite_name = "dummy"
|
41
|
+
@test_name = "dummy"
|
42
|
+
@line_number = "dummy"
|
43
|
+
isequal("IsEqual(1.0,m(1,1))")
|
44
|
+
assert_equal '.not.(1.0==m(1,1))', @condition
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_is_real_equal
|
48
|
+
@suite_name = "dummy"
|
49
|
+
@test_name = "dummy"
|
50
|
+
@line_number = "dummy"
|
51
|
+
isrealequal("IsRealEqual(a,b)")
|
52
|
+
ans = <<-EOF
|
53
|
+
.not.(a+2*spacing(real(a)).ge.b &
|
54
|
+
.and.a-2*spacing(real(a)).le.b)
|
55
|
+
EOF
|
56
|
+
assert_equal ans.chomp, @condition
|
57
|
+
assert_equal '"b (",b,") is not",a,"within",2*spacing(real(a))', @message
|
58
|
+
isrealequal("IsRealEqual(1.0,m(1,1))")
|
59
|
+
ans = <<-EOF
|
60
|
+
.not.(1.0+2*spacing(real(1.0)).ge.m(1,1) &
|
61
|
+
.and.1.0-2*spacing(real(1.0)).le.m(1,1))
|
62
|
+
EOF
|
63
|
+
assert_equal ans.chomp, @condition
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_handles_dependency
|
67
|
+
File.open('unit.f90','w') do |f|
|
68
|
+
f.printf "module unit\n use unita, only : a\nend module unit\n"
|
69
|
+
end
|
70
|
+
File.open('unita.f90','w') do |f|
|
71
|
+
f.printf "module unita\n integer :: a = 5\nend module unita\n"
|
72
|
+
end
|
73
|
+
File.open('unit.fun','w') do |f|
|
74
|
+
f.printf "beginTest a_gets_set\n IsEqual(5, a)\nendTest\n"
|
75
|
+
end
|
76
|
+
assert_nothing_raised{run_tests}
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_embedded_dependencies
|
80
|
+
File.open('unit.f90','w') do |f|
|
81
|
+
f.printf "module unit\n use unita, only : a\nend module unit\n"
|
82
|
+
end
|
83
|
+
File.open('unita.f90','w') do |f|
|
84
|
+
f.printf "module unita\n use unitb, only : b \n integer :: a = b\nend module unita\n"
|
85
|
+
end
|
86
|
+
File.open('unitb.f90','w') do |f|
|
87
|
+
f.printf "module unitb\n integer,parameter :: b = 5\nend module unitb\n"
|
88
|
+
end
|
89
|
+
File.open('unit.fun','w') do |f|
|
90
|
+
f.printf "beginTest a_gets_set\n IsEqual(5, a)\nendTest\n"
|
91
|
+
end
|
92
|
+
assert_nothing_raised{run_tests}
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_requested_modules
|
96
|
+
assert_equal ["asdfga"], requested_modules(["asdfga"])
|
97
|
+
assert_equal ["asd","fga"], requested_modules(["asd","fga"])
|
98
|
+
assert requested_modules([]).empty?
|
99
|
+
modules = %w[ldfdl lmzd]
|
100
|
+
funits = modules.map{|f| f+'.fun'}.join(' ')
|
101
|
+
system "touch "+funits
|
102
|
+
assert_equal modules, requested_modules([])
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_funit_exists_method
|
106
|
+
module_name = "ydsbe"
|
107
|
+
File.rm_f(module_name+".fun")
|
108
|
+
assert_equal false, funit_exists?(module_name)
|
109
|
+
system "touch "+module_name+".fun"
|
110
|
+
assert funit_exists?(module_name)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|