iocheck 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Akira Hayakawa
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # iocheck
2
+
3
+ ## Motivation "Make Refactoring Safe."
4
+ There are thousand of softwares without test codes and
5
+ you do not have much time to add test programs to the software which disrespectively called legacy.
6
+ Some kind of softwares, such as visualization softwares, are hard to test and these softwares are usually left untested.
7
+
8
+ iocheck is in the opposite side of QuickCheck, a Haskell de-facto standard testing framework for purely functional codes.
9
+ Instead of checking the pure property of the softwares like QuickCheck does,
10
+ iocheck checks the standard output with which any kind of programming languages equip.
11
+
12
+ iocheck helps engineers working on legacy softwares who wants to refactor these software safely.
13
+ If the software is written in COBOL or Fortran, it is OK. There is a hope called iocheck.
14
+ All you have to do is write a main program to
15
+ give some states of the program running to standard output,
16
+ create test file, refactor a little bit and run iocheck to make sure no behavior changed.
17
+
18
+ In summery, standard IO is equipped with any kind of languages even if they are almost out-dated.
19
+ With iocheck testing framework, you can test legacy softwares usually written in those languages
20
+ without any learning cost.
21
+
22
+ ## Installation
23
+ iocheck can be installed from rubygems repository, just type
24
+
25
+ ```bash
26
+ gem install iocheck
27
+ ```
28
+
29
+ ## Contributing to iocheck
30
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
31
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
32
+ * Fork the project
33
+ * Start a feature/bugfix branch
34
+ * Commit and push until you are happy with your contribution
35
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
36
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
37
+
38
+ ## Copyright
39
+ Copyright (c) 2011 Akira Hayakawa (@akiradeveloper). See LICENSE.txt for
40
+ further details.
41
+
data/lib/iocheck.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative "iocheck/policy"
2
+ require_relative "iocheck/test"
3
+ require_relative "iocheck/tester"
@@ -0,0 +1,61 @@
1
+ module IOCheck
2
+
3
+ class Policy
4
+ def initialize
5
+ @result = nil
6
+ end
7
+ attr_reader :result
8
+
9
+ # Expected -> Actual -> Either
10
+ def evaluate(expected, actual)
11
+ raise NoMethodError, "You must override this method."
12
+ end
13
+
14
+ def run!(expected, actual)
15
+ @result = evaluate(expected, actual)
16
+ end
17
+
18
+ class Success
19
+ end
20
+
21
+ class Failure
22
+ def initialize(log)
23
+ @log = log
24
+ end
25
+ attr_reader :log
26
+ end
27
+
28
+ class Either
29
+ def initialize(pred, log)
30
+ if pred
31
+ @stat = ::IOCheck::Policy::Success.new
32
+ else
33
+ @stat = ::IOCheck::Policy::Failure.new(log)
34
+ end
35
+ end
36
+ def evaluate
37
+ @stat
38
+ end
39
+ end
40
+
41
+ class Block < Policy
42
+ def initialize(&blk)
43
+ super
44
+ @blk = blk
45
+ end
46
+
47
+ def evaluate(expected, actual)
48
+ @blk.call(expected, actual)
49
+ end
50
+ end
51
+
52
+ def self.by_bytes
53
+ Block.new do |expected, actual|
54
+ # TODO: Better to show the diff to the user.
55
+ Either.new(
56
+ actual.bytes == expected.bytes,
57
+ "Bytes not exactly matched").evaluate
58
+ end
59
+ end
60
+ end # end of class Policy
61
+ end # end of module IOCheck
@@ -0,0 +1,215 @@
1
+ require_relative "policy"
2
+ require_relative "tester"
3
+
4
+ module IOCheck
5
+
6
+ def self.name(cmd)
7
+ cn = cmd.clone
8
+ if cn.start_with?( "./" )
9
+ cn[0..1] = "dotslash"
10
+ end
11
+ cn.split(" ").join("_")
12
+ end
13
+
14
+ def self.strip(bytes)
15
+ bytes.strip
16
+ end
17
+
18
+ def self.readfile(name)
19
+ dir = ::IOCheck::Env["dir"]
20
+ if self.include?(name, "#{dir}/lock")
21
+ x = "#{dir}/lock/#{name}"
22
+ elsif self.include?(name, "#{dir}/unlock")
23
+ x = "#{dir}/unlock/#{name}"
24
+ else
25
+ raise ArgumentError, "readfile not found."
26
+ end
27
+ x
28
+ end
29
+
30
+ def self.writefile(name)
31
+ dir = ::IOCheck::Env["dir"]
32
+ "#{dir}/unlock/#{name}"
33
+ end
34
+
35
+ def self.include?(name, dir)
36
+ Dir.open(dir).each do |f|
37
+ return true if f == name
38
+ end
39
+ return false
40
+ end
41
+
42
+ class Test
43
+ def initialize(cmd)
44
+ @command = Command.new(cmd)
45
+ @policies = [Policy.by_bytes]
46
+ @repeat = 1
47
+ @desc = ""
48
+ end
49
+
50
+ def repeat(n)
51
+ @repeat = n
52
+ self
53
+ end
54
+
55
+ def describe(desc)
56
+ @desc = desc
57
+ self
58
+ end
59
+
60
+ def by(policy)
61
+ @policies << policy
62
+ self
63
+ end
64
+
65
+ def name
66
+ ::IOCheck.name( @command.cmd )
67
+ end
68
+
69
+ def locked?
70
+ true if ::IOCheck.include?(name, "#{::IOCheck::Env["dir"]}/lock")
71
+ end
72
+
73
+ def update!
74
+ return if locked?
75
+
76
+ do_run!
77
+ f = File.open( ::IOCheck.writefile(name), "w")
78
+ f.write( @command.actual.bytes )
79
+ f.close
80
+ end
81
+
82
+ def do_run!
83
+ @command.run!(@repeat)
84
+ end
85
+
86
+ def run!
87
+ do_run!
88
+ @policies.each do |p|
89
+ p.run!( expected, @command.actual )
90
+ end
91
+ end
92
+
93
+ def ready
94
+ RakeTask.new(self).create_tasks
95
+ end
96
+
97
+ def show
98
+ n_success = 0
99
+ n_failure = 0
100
+ log = []
101
+ @policies.each do |p|
102
+ if p.result.class == ::IOCheck::Policy::Success
103
+ n_success += 1
104
+ elsif p.result.class == ::IOCheck::Policy::Failure
105
+ n_failure += 1
106
+ log << p.result.log
107
+ else
108
+ raise Error
109
+ end
110
+ end
111
+ puts "Test Name : #{name}"
112
+ puts "Description : #{@desc}"
113
+ puts "Minor Success : #{n_success}"
114
+ puts "Minor Failure : #{n_failure}"
115
+ puts "# Log --------:"
116
+ puts log.join("\n")
117
+ end
118
+
119
+ private
120
+
121
+ def expected
122
+ Expected.new(self)
123
+ end
124
+
125
+ class Command
126
+ def initialize(cmd)
127
+ @cmd = cmd
128
+ @actual = Actual.new
129
+ end
130
+ attr_reader :cmd, :actual
131
+
132
+ def run!(repeat)
133
+ repeat.times do
134
+ @actual << Actual::Result.new( @cmd )
135
+ end
136
+ @actual.repeat = repeat
137
+ end
138
+
139
+ class Actual
140
+ def initialize
141
+ @results = []
142
+ end
143
+ attr_accessor :repeat
144
+
145
+ def <<(result)
146
+ @results << result
147
+ end
148
+ def bytes
149
+ # TODO: assert all the results are equal in bytes?
150
+ ::IOCheck.strip( @results[0].bytes )
151
+ end
152
+ class Result
153
+ def initialize(cmd)
154
+ @cmd = cmd
155
+ run!
156
+ end
157
+ attr_reader :bytes
158
+ private
159
+ def run!
160
+ # TODO: more things like measuring the time.
161
+ x = `#{@cmd}`
162
+ @bytes = ::IOCheck.strip( x )
163
+ end
164
+ end # end of class Result
165
+ end # end of class Actual
166
+ end # end of class Command
167
+
168
+ class Expected
169
+ def initialize(test)
170
+ @test = test
171
+ end
172
+ def repeat
173
+ @test.repeat
174
+ end
175
+ def bytes
176
+ content = File.read( ::IOCheck.readfile(@test.name) )
177
+ ::IOCheck.strip( content )
178
+ end
179
+ end # end of class Expected
180
+
181
+ class RakeTask
182
+ def initialize(test)
183
+ @test = test
184
+ end
185
+ def create_tasks
186
+ create_update_task
187
+ create_run_task
188
+ end
189
+ def create_update_task
190
+ namespace "iocheck" do
191
+ namespace "update" do
192
+ task @test.name do
193
+ @test.update!
194
+ end
195
+ end
196
+ end
197
+ end
198
+ def create_run_task
199
+ namespace "iocheck" do
200
+ task @test.name do
201
+ @test.run!
202
+ @test.show
203
+ end
204
+ end
205
+ end
206
+ end # end of class RakeTask
207
+ end # end of class Test
208
+ end # end of module IOCheck
209
+
210
+ if __FILE__ == $0
211
+ p ::IOCheck.name("tree")
212
+ p ::IOCheck.writefile("tree")
213
+ p ::IOCheck.readfile("tree")
214
+ p ::IOCheck.strip("\n aa bbb\n ccff \n ")
215
+ end
@@ -0,0 +1,74 @@
1
+ module IOCheck
2
+
3
+ Env = {}
4
+ ::IOCheck::Env["dir"] = "./iocheck"
5
+
6
+ class Tester
7
+
8
+ def initialize
9
+ @tests = []
10
+ end
11
+
12
+ def <<(test)
13
+ @tests << test
14
+ end
15
+
16
+ def run!
17
+ @tests.each { |t| t.run! }
18
+ end
19
+
20
+ def update!
21
+ @tests.each { |t| t.update! }
22
+ end
23
+
24
+ def ready
25
+ @tests.each do |t|
26
+ t.ready
27
+ end
28
+ namespace "iocheck" do
29
+ task "update" => @tests.map { |t| "iocheck:update:#{t.name}" }
30
+ end
31
+ task "iocheck" do
32
+ run!
33
+ show
34
+ end
35
+ create_lock_tasks
36
+ end
37
+
38
+ def create_lock_tasks
39
+ locked = @tests.select { |t| t.locked? }
40
+ unlocked = @tests.select { |t| ! t.locked? }
41
+ dir = ::IOCheck::Env["dir"]
42
+
43
+ namespace "iocheck" do
44
+ task "lock" => unlocked.map { |t| "iocheck:lock:#{t.name}" }
45
+ unlocked.each do |t|
46
+ namespace "lock" do
47
+ task t.name do
48
+ dest = dir + "/" + "lock"
49
+ mv ::IOCheck.readfile(t.name), dest
50
+ end
51
+ end
52
+ end
53
+ task "unlock" => locked.map { |t| "iocheck:unlock:#{t.name}" }
54
+ locked.each do |t|
55
+ namespace "unlock" do
56
+ task t.name do
57
+ dest = dir + "/" + "unlock"
58
+ mv ::IOCheck.readfile(t.name), dest
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+ def show
67
+ # TODO: This is a temporary implementation.
68
+ @tests.each do |t|
69
+ t.show
70
+ end
71
+ # TODO: Here, summary result should be written.
72
+ end
73
+ end # end of class Tester
74
+ end # end of module IOCheck
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: iocheck
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Akira Hayakawa
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-06 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &21844540 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.3.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *21844540
25
+ - !ruby/object:Gem::Dependency
26
+ name: bundler
27
+ requirement: &21844060 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *21844060
36
+ - !ruby/object:Gem::Dependency
37
+ name: jeweler
38
+ requirement: &21843580 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.6.4
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *21843580
47
+ - !ruby/object:Gem::Dependency
48
+ name: rcov
49
+ requirement: &21755800 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *21755800
58
+ description: Make refactoring for legacy softwares safe.
59
+ email: ruby.wktk@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files:
63
+ - LICENSE.txt
64
+ - README.md
65
+ files:
66
+ - lib/iocheck.rb
67
+ - lib/iocheck/policy.rb
68
+ - lib/iocheck/test.rb
69
+ - lib/iocheck/tester.rb
70
+ - LICENSE.txt
71
+ - README.md
72
+ homepage: http://github.com/akiradeveloper/iocheck
73
+ licenses:
74
+ - MIT
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ segments:
86
+ - 0
87
+ hash: -2015204035547287083
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 1.8.6
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: IO-based testing framework.
100
+ test_files: []