fUnit 0.0.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.
@@ -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