fUnit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,124 @@
1
+ module Funit
2
+
3
+ class Compiler
4
+
5
+ attr_reader :name
6
+
7
+ def initialize( name=ENV['F9X'] )
8
+ errorMessage = <<-ENVIRON
9
+
10
+ Fortran compiler environment variable 'F9X' not set:
11
+
12
+ for bourne-based shells: export F9X=lf95 (in .profile)
13
+ for c-based shells: setenv F9X lf95 (in .login)
14
+ for windows: set F9X=C:\\Program Files\\lf95 (in autoexec.bat)
15
+
16
+ ENVIRON
17
+ raise(errorMessage) unless @name = name
18
+ end
19
+
20
+ end
21
+
22
+ def requestedModules(moduleNames)
23
+ if (moduleNames.empty?)
24
+ moduleNames = Dir["*MT.ftk"].each{ |mod| mod.chomp! "MT.ftk" }
25
+ end
26
+ moduleNames
27
+ end
28
+
29
+ def ftkExists?(moduleName)
30
+ File.exists? moduleName+"MT.ftk"
31
+ end
32
+
33
+ def parseCommandLine
34
+
35
+ moduleNames = requestedModules(ARGV)
36
+
37
+ if moduleNames.empty?
38
+ raise " *Error: no test suites found in this directory"
39
+ end
40
+
41
+ moduleNames.each do |mod|
42
+ unless ftkExists?(mod)
43
+ errorMessage = <<-FTKDOESNOTEXIST
44
+ Error: could not find test suite #{mod}MT.ftk
45
+ Test suites available in this directory:
46
+ #{requestedModules([]).join(' ')}
47
+
48
+ Usage: #{File.basename $0} [test names (w/o MT.ftk suffix)]
49
+ FTKDOESNOTEXIST
50
+ raise errorMessage
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ def writeTestRunner testSuites
57
+
58
+ File.delete("TestRunner.f90") if File.exists?("TestRunner.f90")
59
+ testRunner = File.new "TestRunner.f90", "w"
60
+
61
+ testRunner.puts <<-HEADER
62
+ ! TestRunner.f90 - runs Fortran mobility test suites
63
+ !
64
+ ! [Dynamically generated by #{File.basename $0} Ruby script #{Time.now}.]
65
+
66
+ program TestRunner
67
+
68
+ HEADER
69
+
70
+ testSuites.each { |testSuite| testRunner.puts " use #{testSuite}MT" }
71
+
72
+ testRunner.puts <<-DECLARE
73
+
74
+ implicit none
75
+
76
+ integer :: numTests, numAsserts, numAssertsTested, numFailures
77
+ DECLARE
78
+
79
+ testSuites.each do |testSuite|
80
+ testRunner.puts <<-TRYIT
81
+
82
+ print *, ""
83
+ print *, "#{testSuite} test suite:"
84
+ call MT#{testSuite}( numTests, &
85
+ numAsserts, numAssertsTested, numFailures )
86
+ print *, "Passed", numAssertsTested, "of", numAsserts, &
87
+ "possible asserts comprising", &
88
+ numTests-numFailures, "of", numTests, "tests."
89
+ TRYIT
90
+ end
91
+
92
+ testRunner.puts "\n print *, \"\""
93
+ testRunner.puts "\nend program TestRunner"
94
+ testRunner.close
95
+ File.chmod(0444,"TestRunner.f90")
96
+ end
97
+
98
+ def syntaxError( message, testSuite )
99
+ raise "\n *Error: #{message} [#{testSuite}MT.ftk:#$.]\n\n"
100
+ end
101
+
102
+ def warning( message, testSuite )
103
+ $stderr.puts "\n *Warning: #{message} [#{testSuite}MT.ftk:#$.]"
104
+ end
105
+
106
+ def compileTests testSuites
107
+ require 'fortran_deps'
108
+
109
+ puts "computing dependencies"
110
+ dependencies = Depend.new(['.', '../LibF90', '../PHYSICS_DEPS'])
111
+ puts "locating associated source files and sorting for compilation"
112
+ requiredSources = dependencies.required_source_files('TestRunner.f90')
113
+
114
+ puts compile = "#{ENV['F9X']} #{ENV['F9X_LDFLAGS']} -o TestRunner \\\n #{requiredSources.join(" \\\n ")}"
115
+
116
+ raise "Compile failed." unless system(compile)
117
+
118
+ end
119
+
120
+ # set some regular expressions:
121
+ $keyword = /(begin|end)(Setup|Teardown|Test)|Is(RealEqual|Equal|False|True|EqualWithin)\(.*\)/i
122
+ $commentLine = /^\s*!/
123
+
124
+ end # module Funit
@@ -0,0 +1,180 @@
1
+ module Funit
2
+
3
+ include Funit::Assertions
4
+
5
+ class TestSuite < File
6
+
7
+ include Funit
8
+
9
+ def initialize suiteName
10
+ @lineNumber = 'blank'
11
+ @suiteName = suiteName
12
+ return nil unless ftkExists?(suiteName)
13
+ File.delete(suiteName+"MT.f90") if File.exists?(suiteName+"MT.f90")
14
+ super(suiteName+"MT.f90","w")
15
+ @tests, @setup, @teardown = Array.new, Array.new, Array.new
16
+ topWrapper
17
+ expand
18
+ close
19
+ end
20
+
21
+ def topWrapper
22
+ puts <<-TOP
23
+ ! #{@suiteName}MT.f90 - a Fortran mobility test suite for #{@suiteName}.f90
24
+ !
25
+ ! [dynamically generated from #{@suiteName}MT.ftk
26
+ ! by #{File.basename $0} Ruby script #{Time.now}]
27
+
28
+ module #{@suiteName}MT
29
+
30
+ use #{@suiteName}
31
+
32
+ implicit none
33
+
34
+ private
35
+
36
+ public :: MT#{@suiteName}
37
+
38
+ logical :: noAssertFailed
39
+
40
+ integer :: numTests = 0
41
+ integer :: numAsserts = 0
42
+ integer :: numAssertsTested = 0
43
+ integer :: numFailures = 0
44
+
45
+ TOP
46
+ end
47
+
48
+ def expand
49
+
50
+ ftkFile = @suiteName+"MT.ftk"
51
+ $stderr.puts "parsing #{ftkFile}"
52
+
53
+ ftk = IO.readlines(ftkFile)
54
+ @ftkTotalLines = ftk.length
55
+
56
+ while (line = ftk.shift) && line !~ $keyword
57
+ puts line
58
+ end
59
+
60
+ ftk.unshift line
61
+
62
+ puts " contains\n\n"
63
+
64
+ while (line = ftk.shift)
65
+ case line
66
+ when $commentLine
67
+ puts line
68
+ when /beginSetup/i
69
+ addtoSetup ftk
70
+ when /beginTeardown/i
71
+ addtoTeardown ftk
72
+ when /XbeginTest\s+(\w+)/i
73
+ ignoreTest($1,ftk)
74
+ when /beginTest\s+(\w+)/i
75
+ aTest($1,ftk)
76
+ when /beginTest/i
77
+ syntaxError "no name given for beginTest", @suiteName
78
+ when /end(Setup|Teardown|Test)/i
79
+ syntaxError "no matching begin#$1 for an #$&", @suiteName
80
+ when $assertRegEx
81
+ syntaxError "#$1 assert not in a test block", @suiteName
82
+ else
83
+ puts line
84
+ end
85
+ end # while
86
+
87
+ $stderr.puts "completed #{ftkFile}"
88
+
89
+ end
90
+
91
+ def addtoSetup ftk
92
+ while (line = ftk.shift) && line !~ /endSetup/i
93
+ @setup.push line
94
+ end
95
+ end
96
+
97
+ def addtoTeardown ftk
98
+ while (line = ftk.shift) && line !~ /endTeardown/i
99
+ @teardown.push line
100
+ end
101
+ end
102
+
103
+ def ignoreTest testName, ftk
104
+ warning("Ignoring test: #{testName}", @suiteName)
105
+ line = ftk.shift while line !~ /endTest/i
106
+ end
107
+
108
+ def aTest testName, ftk
109
+ @testName = testName
110
+ @tests.push testName
111
+ syntaxError("test name #@testName not unique",@suiteName) if (@tests.uniq!)
112
+
113
+ puts " subroutine Test#{testName}\n\n"
114
+
115
+ numOfAsserts = 0
116
+
117
+ while (line = ftk.shift) && line !~ /endTest/i
118
+ case line
119
+ when $commentLine
120
+ puts line
121
+ when /Is(RealEqual|False|True|EqualWithin|Equal)/i
122
+ @lineNumber = @ftkTotalLines - ftk.length
123
+ numOfAsserts += 1
124
+ puts send( $&.downcase!, line )
125
+ else
126
+ puts line
127
+ end
128
+ end
129
+ warning("no asserts in test", @suiteName) if numOfAsserts == 0
130
+
131
+ puts "\n numTests = numTests + 1\n\n"
132
+ puts " end subroutine Test#{testName}\n\n"
133
+ end
134
+
135
+ def close
136
+ puts "\n subroutine Setup"
137
+ puts @setup
138
+ puts " noAssertFailed = .true."
139
+ puts " end subroutine Setup\n\n"
140
+
141
+ puts "\n subroutine Teardown"
142
+ puts @teardown
143
+ puts " end subroutine Teardown\n\n"
144
+
145
+ puts <<-NEXTONE
146
+
147
+ subroutine MT#{@suiteName}( nTests, nAsserts, nAssertsTested, nFailures )
148
+
149
+ integer :: nTests
150
+ integer :: nAsserts
151
+ integer :: nAssertsTested
152
+ integer :: nFailures
153
+
154
+ continue
155
+ NEXTONE
156
+
157
+ @tests.each do |testName|
158
+ puts "\n call Setup"
159
+ puts " call Test#{testName}"
160
+ puts " call Teardown"
161
+ end
162
+
163
+ puts <<-LASTONE
164
+
165
+ nTests = numTests
166
+ nAsserts = numAsserts
167
+ nAssertsTested = numAssertsTested
168
+ nFailures = numFailures
169
+
170
+ end subroutine MT#{@suiteName}
171
+
172
+ end module #{@suiteName}MT
173
+ LASTONE
174
+ super
175
+ File.chmod(0444,@suiteName+"MT.f90")
176
+ end
177
+
178
+ end # class TestSuite
179
+
180
+ end # module Funit
data/lib/funit.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'funit/functions'
2
+ require 'funit/assertions'
3
+ require 'funit/test_suite'
4
+
5
+ module Funit
6
+
7
+ def runAllFtks
8
+
9
+ Compiler.new # a test for compiler env set (remove this later)
10
+
11
+ writeTestRunner(testSuites = parseCommandLine)
12
+
13
+ # convert each *MT.ftk file into a pure Fortran9x file:
14
+
15
+ testSuites.each do |testSuite|
16
+ testSuiteF90 = TestSuite.new(testSuite)
17
+ end
18
+
19
+ compileTests testSuites
20
+
21
+ raise "Failed to execute TestRunner" unless system("./TestRunner")
22
+
23
+ end
24
+
25
+ end
data/lib/mklinks ADDED
@@ -0,0 +1,5 @@
1
+ ln -s ../examples/CFD/GasModel.f90 .
2
+ ln -s ../examples/CFD/GasModelTS.ftk .
3
+ ln -s ../examples/CFD/Gammas.f90 .
4
+ ln -s ../examples/CFD/FluxFunctions.f90 .
5
+ ln -s ../examples/CFD/FluxFunctionsTS.ftk .
@@ -0,0 +1,30 @@
1
+ $:.unshift File.join( File.dirname(__FILE__), '..', 'lib' )
2
+ require 'test/unit'
3
+ require 'funit/functions'
4
+
5
+ class TestCompiler < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @compilerStub = 'dummyCompiler'
9
+ @oldCompilerName = ENV['F9X']
10
+ end
11
+
12
+ def test_explicit_compiler_name
13
+ assert_equal @compilerStub, Funit::Compiler.new(@compilerStub).name
14
+ end
15
+
16
+ def test_compiler_name_from_environment
17
+ ENV['F9X'] = @compilerStub
18
+ assert_equal @compilerStub, Funit::Compiler.new.name
19
+ end
20
+
21
+ def test_no_environment_compiler_name
22
+ ENV['F9X'] = nil
23
+ assert_raises(RuntimeError) {Funit::Compiler.new}
24
+ end
25
+
26
+ def teardown
27
+ ENV['F9X'] = @oldCompilerName
28
+ end
29
+
30
+ end
@@ -0,0 +1,167 @@
1
+ $:.unshift File.join( File.dirname(__FILE__), '..', 'lib' )
2
+ require 'test/unit'
3
+ require 'fortran_deps'
4
+ require 'fileutils'
5
+
6
+ class TestFortranDeps < Test::Unit::TestCase
7
+
8
+ def setup
9
+ Dir.mkdir 'DependenciesFixture'
10
+ Dir.chdir 'DependenciesFixture'
11
+ Dir.mkdir 'lib'
12
+ Dir.chdir 'lib'
13
+ File.open('solution.f90','w') do |f|
14
+ f.puts "module solution\nuse area\nend module solution"
15
+ end
16
+ Dir.chdir '..'
17
+ Dir.mkdir 'src'
18
+ Dir.chdir 'src'
19
+ File.open('main.F90','w') do |f|
20
+ f.puts 'program whizzard'
21
+ f.puts " use grid\n use solution\n use circle"
22
+ f.puts 'end program whizzard'
23
+ end
24
+ File.open('grid.f90','w'){ |f| f.puts "module grid\nuse area\nend module grid" }
25
+ File.open('shapes.f90','w') do |f|
26
+ f.puts "module rectangle_fun3d\nend module rectangle_fun3d"
27
+ f.puts "module circle\n use area\nend module circle"
28
+ end
29
+ File.open('area.f90','w'){ |f| f.puts "module area\nend module area" }
30
+ File.open('externalUse.f90','w') do |f|
31
+ f.puts "program user\nuse cantFindModule\nend program"
32
+ end
33
+ @dep = Depend.new
34
+ end
35
+
36
+ def test_finds_which_modules_a_source_file_uses
37
+ assert_equal %w[grid solution circle], @dep.modules_used_in( 'main.F90' )
38
+ end
39
+
40
+ def test_finds_modules_defined_in_source_file
41
+ assert_equal %w[rectangle_fun3d circle], @dep.modules_defined_in( 'shapes.f90' )
42
+ end
43
+
44
+ def test_create_module_definition_hash
45
+ assert_equal %w[circle rectangle_fun3d],
46
+ @dep.build_dictionary_of_modules_in( 'shapes.f90' ).keys.sort
47
+ end
48
+
49
+ def test_locating_all_fortran_files_in_search_path
50
+ files = %w[ ../lib/solution.f90 ./area.f90 ./externalUse.f90
51
+ ./grid.f90 ./main.F90 ./shapes.f90 ]
52
+ @dep.fortran_files_within.each do |file|
53
+ assert files.include?(file)
54
+ end
55
+ end
56
+
57
+ def test_build_hash_with_source_files
58
+ f90 = %w[./grid.f90 ../lib/solution.f90 ./shapes.f90 ./area.f90]
59
+ hash = @dep.build_dictionary_of_modules_in( f90 )
60
+ assert_equal \
61
+ %w[./shapes.f90 ./shapes.f90 ./area.f90 ../lib/solution.f90 ./grid.f90].sort,
62
+ hash.values.sort
63
+ assert_equal %w[rectangle_fun3d circle area solution grid].sort, hash.keys.sort
64
+ assert_equal hash , @dep.build_hash_of_modules_in_files_within
65
+ end
66
+
67
+ def test_dependency_generation_elements
68
+ directoryHash = @dep.build_hash_of_modules_in_files_within
69
+
70
+ sourceFile = "main.F90"
71
+ modules = @dep.modules_used_in( sourceFile )
72
+ assert_equal %w[grid solution circle], modules
73
+
74
+ newSourceFiles = modules.collect{ |mod| directoryHash[mod] }
75
+ assert_equal %w[./grid.f90 ../lib/solution.f90 ./shapes.f90], newSourceFiles
76
+
77
+ newModules = newSourceFiles.collect do |file|
78
+ @dep.modules_used_in( file )
79
+ end.flatten.uniq
80
+
81
+ assert_equal ["area"], newModules
82
+ end
83
+
84
+ def test_makefile_dependency_line_generation
85
+ sourceFile = "main.F90"
86
+ makeGolden=String.new <<-GOLDEN
87
+ main.o: main.F90 \\
88
+ grid.o \\
89
+ solution.o \\
90
+ shapes.o
91
+ GOLDEN
92
+ assert_equal makeGolden, @dep.makefile_dependency_line(sourceFile)
93
+ end
94
+
95
+ def test_makefile_dependency_recurses_properly
96
+ makeGolden=String.new <<-GOLDEN
97
+ main.o: main.F90 \\
98
+ grid.o \\
99
+ solution.o \\
100
+ shapes.o
101
+ grid.o: grid.f90 \\
102
+ area.o
103
+ area.o: area.f90
104
+ solution.f90: ../lib/solution.f90
105
+ \tln -sf ../lib/solution.f90 .
106
+ solution.o: solution.f90 \\
107
+ area.o
108
+ shapes.o: shapes.f90 \\
109
+ area.o
110
+ GOLDEN
111
+
112
+ goldSplit = makeGolden.split("\n")
113
+ testSplit = @dep.dependencies('main.F90').split("\n")
114
+
115
+ while (gold = goldSplit.shift) && (test = testSplit.shift)
116
+ assert_equal gold, test
117
+ end
118
+ end
119
+
120
+ def test_source_file_dependency_hash
121
+ @dep.source_file_dependencies('main.F90')
122
+ assert_equal( 5, @dep.file_dependencies.size )
123
+ expected = {
124
+ "./area.f90" => [],
125
+ "./grid.f90" => ["./area.f90"],
126
+ "../lib/solution.f90" => ["./area.f90"],
127
+ "./shapes.f90" => ["./area.f90"],
128
+ "main.F90" => ["./grid.f90", "../lib/solution.f90", "./shapes.f90"]
129
+ }
130
+ assert_equal expected, @dep.file_dependencies
131
+ end
132
+
133
+ def test_finds_required_source_files
134
+ expected = %w[./area.f90 ./shapes.f90 ../lib/solution.f90 ./grid.f90 ./main.F90]
135
+ found = @dep.required_source_files('./main.F90')
136
+ assert_equal expected.size, found.size
137
+ assert_equal './main.F90', found.last
138
+ assert_equal './area.f90', found.first
139
+ end
140
+
141
+ def test_finds_required_source_files_unordered
142
+ @dep.dependencies('main.F90')
143
+ sources = @dep.source_files
144
+ expected = %w[ main.F90 grid.f90 area.f90 solution.f90 shapes.f90 ]
145
+ assert_equal expected.size, sources.size
146
+ assert_equal 'shapes.f90', sources.last
147
+ assert_equal 'main.F90', sources.first
148
+ assert_equal expected, sources
149
+ end
150
+
151
+ def test_can_find_required_source_files_twice
152
+ files = %w[./main.F90 ./shapes.f90 ./area.f90 ../lib/solution.f90 ./grid.f90]
153
+ @dep.required_source_files('./main.F90')
154
+ assert_equal files.sort, @dep.required_source_files('./main.F90').sort
155
+ end
156
+
157
+ def test_recognizes_external_modules
158
+ file = './externalUse.f90'
159
+ assert_equal [file], @dep.required_source_files(file).sort
160
+ end
161
+
162
+ def teardown
163
+ Dir.chdir '../..'
164
+ FileUtils.rm_rf 'DependenciesFixture'
165
+ end
166
+
167
+ end
data/tests/tc_funit.rb ADDED
@@ -0,0 +1,104 @@
1
+ $:.unshift File.join( File.dirname(__FILE__), '..', 'lib' )
2
+ require 'test/unit'
3
+ require 'funit'
4
+ require 'ftools'
5
+
6
+ class TestFunit < Test::Unit::TestCase
7
+
8
+ include Funit
9
+ include Funit::Assertions
10
+
11
+ def test_main_driver_compiles
12
+ writeTestRunner []
13
+ assert File.exists?("TestRunner.f90")
14
+ assert system("#{Compiler.new.name} TestRunner.f90")
15
+ assert File.exists?("a.out")
16
+ end
17
+
18
+ def test_is_equal
19
+ @suiteName = "dummy"
20
+ @testName = "dummy"
21
+ @lineNumber = "dummy"
22
+ isequal("IsEqual(1.0,m(1,1))")
23
+ assert_equal '.not.(1.0==m(1,1))', @condition
24
+ end
25
+
26
+ def test_is_real_equal
27
+ @suiteName = "dummy"
28
+ @testName = "dummy"
29
+ @lineNumber = "dummy"
30
+ isrealequal("IsRealEqual(a,b)")
31
+ ans = <<EOF
32
+ .not.(a+2*spacing(real(a)).ge.b &
33
+ .and.a-2*spacing(real(a)).le.b)
34
+ EOF
35
+ assert_equal ans.chomp, @condition
36
+ assert_equal '"b (",b,") is not",a,"within",2*spacing(real(a))', @message
37
+
38
+ isrealequal("IsRealEqual(1.0,m(1,1))")
39
+ ans = <<EOF
40
+ .not.(1.0+2*spacing(real(1.0)).ge.m(1,1) &
41
+ .and.1.0-2*spacing(real(1.0)).le.m(1,1))
42
+ EOF
43
+ assert_equal ans.chomp, @condition
44
+ end
45
+
46
+ def test_handles_dependency
47
+ File.open('unit.f90','w') do |f|
48
+ f.printf "module unit\n use unita, only : a\nend module unit\n"
49
+ end
50
+ File.open('unita.f90','w') do |f|
51
+ f.printf "module unita\n integer :: a = 5\nend module unita\n"
52
+ end
53
+ File.open('unitMT.ftk','w') do |f|
54
+ f.printf "beginTest A\n IsEqual(5, a)\nendTest\n"
55
+ end
56
+ assert_nothing_raised{runAllFtks}
57
+ end
58
+
59
+ def test_embedded_dependencies
60
+ File.open('unit.f90','w') do |f|
61
+ f.printf "module unit\n use unita, only : a\nend module unit\n"
62
+ end
63
+ File.open('unita.f90','w') do |f|
64
+ f.printf "module unita\n use unitb, only : b \n integer :: a = b\nend module unita\n"
65
+ end
66
+ File.open('unitb.f90','w') do |f|
67
+ f.printf "module unitb\n integer,parameter :: b = 5\nend module unitb\n"
68
+ end
69
+ File.open('unitMT.ftk','w') do |f|
70
+ f.printf "beginTest A\n IsEqual(5, a)\nendTest\n"
71
+ end
72
+ assert_nothing_raised{runAllFtks}
73
+ end
74
+
75
+ def test_requested_modules
76
+ assert_equal ["asdfga"], requestedModules(["asdfga"])
77
+ assert_equal ["asd","fga"], requestedModules(["asd","fga"])
78
+ assert requestedModules([]).empty?
79
+ modules = %w[ldfdl lmzd]
80
+ ftks = modules.map{|f| f+'MT.ftk'}.join(' ')
81
+ system "touch "+ftks
82
+ assert_equal modules, requestedModules([])
83
+ end
84
+
85
+ def test_FTK_exists
86
+ moduleName = "ydsbe"
87
+ File.rm_f(moduleName+"MT.ftk")
88
+ assert_equal false, ftkExists?(moduleName)
89
+ system "touch "+moduleName+"MT.ftk"
90
+ assert ftkExists?(moduleName)
91
+ end
92
+
93
+ def teardown
94
+ File.rm_f(*Dir["dummyunit*"])
95
+ File.rm_f(*Dir["unit*"])
96
+ File.rm_f(*Dir["ydsbe*"])
97
+ File.rm_f(*Dir["lmzd*"])
98
+ File.rm_f(*Dir["ldfdl*"])
99
+ File.rm_f(*Dir["ydsbe*"])
100
+ File.rm_f(*Dir["TestRunner*"])
101
+ File.rm_f(*Dir["a.out"])
102
+ end
103
+
104
+ end