butterfly_net 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +169 -0
- data/lib/butterfly_net/commands.rb +13 -1
- data/lib/butterfly_net/file_writer.rb +40 -13
- data/lib/butterfly_net/test_unit_adapter.rb +12 -11
- data/lib/butterfly_net/test_unit_method.rb +53 -34
- data/test/test_unit_adapter_test.rb +24 -8
- data/test/test_unit_method_test.rb +159 -68
- metadata +4 -4
- data/README +0 -71
data/README.md
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
Butterfly Net
|
2
|
+
=============
|
3
|
+
|
4
|
+
[Home page and source]: http://butterflynet.org
|
5
|
+
[Rubygems page]: http://rubygems.org/gems/butterfly_net
|
6
|
+
|
7
|
+
Author: Chris Smith (quartzmo -at- gmail.com)
|
8
|
+
|
9
|
+
|
10
|
+
## DESCRIPTION
|
11
|
+
|
12
|
+
IRB and Rails console history captured as Test::Unit tests. (RSpec and others hopefully soon to come.)
|
13
|
+
|
14
|
+
|
15
|
+
## INSTALL
|
16
|
+
|
17
|
+
Butterfly Net is available as a gem from rubygems.org (http://rubygems.org/gems/butterfly_net), or as source from
|
18
|
+
butterflynet.org.
|
19
|
+
|
20
|
+
sudo gem install butterfly_net
|
21
|
+
|
22
|
+
To automatically require Butterfly Net on every IRB session, add the following to your ~/.irbrc:
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'butterfly_net'
|
26
|
+
|
27
|
+
|
28
|
+
## USAGE
|
29
|
+
|
30
|
+
### Command methods
|
31
|
+
|
32
|
+
The following commands can be used in any IRB-based console.
|
33
|
+
|
34
|
+
* bn, bn_open- Open a new test case, closing the current test case if one exists. Args: file_name:string (optional; '.rb' will appended if needed)
|
35
|
+
* bnc, bn_close - Close the active test case, and write the output to a file.
|
36
|
+
* m, bn_method - Close the current test method (or block), naming it with the arg method_name:string (optional)
|
37
|
+
|
38
|
+
### Example Usage in IRB
|
39
|
+
|
40
|
+
$ irb
|
41
|
+
irb(main):001:0> bn 'irb_tests'
|
42
|
+
=> true
|
43
|
+
irb(main):002:0> a = 1
|
44
|
+
=> 1
|
45
|
+
irb(main):003:0> a += 2
|
46
|
+
=> 3
|
47
|
+
irb(main):004:0> m 'plusequals'
|
48
|
+
=> true
|
49
|
+
irb(main):005:0> require 'bigdecimal'
|
50
|
+
=> true
|
51
|
+
irb(main):006:0> infinity = BigDecimal('Infinity')
|
52
|
+
=> #<BigDecimal:114ed34,'Infinity',4(4)>
|
53
|
+
irb(main):007:0> BigDecimal.new("1.0") / BigDecimal.new("0.0") == infinity
|
54
|
+
=> true
|
55
|
+
irb(main):008:0> m 'bigdecimal_infinity'
|
56
|
+
=> true
|
57
|
+
irb(main):009:0> exit
|
58
|
+
butterfly_net: irb_tests.rb closed
|
59
|
+
true
|
60
|
+
$ cat irb_tests.rb
|
61
|
+
require "test/unit"
|
62
|
+
|
63
|
+
# IRB test capture courtesy of butterfly_net (butterflynet.org)
|
64
|
+
class MyTest < Test::Unit::TestCase
|
65
|
+
|
66
|
+
def test_plusequals
|
67
|
+
a = 1
|
68
|
+
assert_equal(3, a += 2)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_bigdecimal_infinity
|
72
|
+
require 'bigdecimal'
|
73
|
+
infinity = BigDecimal('Infinity')
|
74
|
+
assert(BigDecimal.new("1.0") / BigDecimal.new("0.0") == infinity)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
$ ruby irb_tests.rb
|
79
|
+
Loaded suite irb_tests
|
80
|
+
Started
|
81
|
+
..
|
82
|
+
Finished in 0.001603 seconds.
|
83
|
+
|
84
|
+
2 tests, 2 assertions, 0 failures, 0 errors
|
85
|
+
|
86
|
+
|
87
|
+
### Ruby on Rails console
|
88
|
+
|
89
|
+
For repeatable tests, be sure to load the Rails test environment with "./script/console test".
|
90
|
+
In a Rails project, you can run all tests with the standard rake command 'rake test',
|
91
|
+
or an individual test by adding the test directory to the path with the option -I when you invoke Ruby.
|
92
|
+
|
93
|
+
chris$ ./script/console test
|
94
|
+
Loading test environment (Rails 2.3.4)
|
95
|
+
>> bn "test/unit/person_console_test"
|
96
|
+
. . .
|
97
|
+
>> Person.count
|
98
|
+
=> 2
|
99
|
+
>> exit
|
100
|
+
. . .
|
101
|
+
chris$ ruby -Itest test/unit/person_console_test.rb
|
102
|
+
. . .
|
103
|
+
1 tests, 1 assertions, 0 failures, 0 errors
|
104
|
+
|
105
|
+
|
106
|
+
## KNOWN ISSUES
|
107
|
+
|
108
|
+
This section covers issues which may not be resolved quickly. Feel free to lend a hand!
|
109
|
+
|
110
|
+
### Object inspect output
|
111
|
+
|
112
|
+
Butterfly Net relies on an expectation value responding with valid Ruby code to the inspect method, which is the case for core
|
113
|
+
classes such as Hash and Array. However, it's not the case with most classes, many of which respond with the familiar
|
114
|
+
#<...> notation, which can't be interpreted.
|
115
|
+
|
116
|
+
For example:
|
117
|
+
|
118
|
+
assert_equal(#<BigDecimal:11511d8,'Infinity',4(24)>, BigDecimal.new("1.0") / BigDecimal.new("0.0")) # doesn't work
|
119
|
+
|
120
|
+
The workaround is to assign expected values to a variable. Of course, you have to know what to expect in order to do this,
|
121
|
+
which may take a few tries. Sorry.
|
122
|
+
|
123
|
+
|
124
|
+
### Inline variable assignment
|
125
|
+
|
126
|
+
Butterfly Net tries to detect simple assignments, such as "a = 1", in order to write them out clearly,
|
127
|
+
without enclosing assertions. In some cases this causes it to miss statements that should be tested.
|
128
|
+
|
129
|
+
For example:
|
130
|
+
|
131
|
+
irb(main):002:0> a = 1; a + 1
|
132
|
+
=> 2
|
133
|
+
irb(main):003:0> "a=1".split('=')
|
134
|
+
=> ["a", "1"]
|
135
|
+
|
136
|
+
results in
|
137
|
+
|
138
|
+
def test_1
|
139
|
+
a = 1; a + 1 # should have been a = 1; assert_equal(2, a + 1)
|
140
|
+
"a=1".split('=') # should have been assert_equal(["a", "1"],"a=1".split('='))
|
141
|
+
end
|
142
|
+
|
143
|
+
In order to avoid this issue, just put assignments (and anything that looks like an assignment) on separate lines.
|
144
|
+
|
145
|
+
|
146
|
+
## LICENSE
|
147
|
+
|
148
|
+
The MIT License
|
149
|
+
|
150
|
+
Copyright (c) 2010 Chris Smith
|
151
|
+
|
152
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
153
|
+
a copy of this software and associated documentation files (the
|
154
|
+
'Software'), to deal in the Software without restriction, including
|
155
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
156
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
157
|
+
permit persons to whom the Software is furnished to do so, subject to
|
158
|
+
the following conditions:
|
159
|
+
|
160
|
+
The above copyright notice and this permission notice shall be
|
161
|
+
included in all copies or substantial portions of the Software.
|
162
|
+
|
163
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
164
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
165
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
166
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
167
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
168
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
169
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -21,8 +21,9 @@ module ButterflyNet
|
|
21
21
|
file_name += ".rb" unless file_name =~ /.rb$/
|
22
22
|
@file = FileWriter.new(file_name, start_index)
|
23
23
|
Kernel.at_exit { puts @file.close if @file; @file = nil }
|
24
|
-
puts "butterfly_net: #{file_name} opened at Readline::HISTORY ##{start_index}"
|
25
24
|
true
|
25
|
+
rescue
|
26
|
+
false
|
26
27
|
end
|
27
28
|
|
28
29
|
def bn_close
|
@@ -37,9 +38,20 @@ module ButterflyNet
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
41
|
+
def bn_method(method_name=nil)
|
42
|
+
check_for_readline
|
43
|
+
if @file
|
44
|
+
@file.new_assertion_set(method_name)
|
45
|
+
else
|
46
|
+
puts "butterfly_net: First invoke 'bn' or 'bn_open' to begin a session"
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
40
51
|
|
41
52
|
alias :bn :bn_open
|
42
53
|
alias :bnc :bn_close
|
54
|
+
alias :m :bn_method
|
43
55
|
|
44
56
|
private
|
45
57
|
|
@@ -7,33 +7,60 @@ module ButterflyNet
|
|
7
7
|
def initialize(file_name, start_index)
|
8
8
|
@file_name = file_name
|
9
9
|
@start_index = start_index
|
10
|
+
@adapter = TestUnitAdapter.new
|
10
11
|
end
|
11
12
|
|
12
|
-
def new_assertion_set
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
def close
|
13
|
+
def new_assertion_set(method_name)
|
18
14
|
lines = Readline::HISTORY.to_a
|
19
15
|
@end_index ||= Readline::HISTORY.size - 3 # in case of no call to 'bn_close'
|
20
16
|
if @end_index < 0 || lines[@start_index..@end_index].empty?
|
21
|
-
puts "butterfly_net: #{@file_name} closed, no file written to disk"
|
22
17
|
false
|
23
18
|
else
|
24
|
-
|
19
|
+
|
25
20
|
|
26
21
|
lines[@start_index..@end_index].each do |line|
|
27
|
-
adapter.add_command(line)
|
22
|
+
@adapter.add_command(line)
|
28
23
|
end
|
29
24
|
|
30
|
-
adapter.
|
25
|
+
@adapter.close_assertion_set(method_name)
|
26
|
+
@start_index = Readline::HISTORY.size - 1
|
27
|
+
@end_index = nil
|
31
28
|
|
32
|
-
puts "butterfly_net: #{@file_name} closed after Readline::HISTORY ##{@end_index}"
|
33
29
|
true
|
34
30
|
end
|
35
|
-
rescue Exception =>
|
36
|
-
puts "butterfly_net: Error generating tests: #{
|
31
|
+
rescue Exception => e
|
32
|
+
puts "butterfly_net: Error generating tests: #{e}"
|
33
|
+
puts e.backtrace
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def close
|
39
|
+
lines = Readline::HISTORY.to_a
|
40
|
+
@end_index ||= Readline::HISTORY.size - 3 # in case of no call to 'bn_close'
|
41
|
+
# if @adapter.empty?
|
42
|
+
# puts "butterfly_net: #{@file_name} closed, no file written to disk."
|
43
|
+
#
|
44
|
+
# false
|
45
|
+
#
|
46
|
+
# else
|
47
|
+
if @end_index < 0 || lines[@start_index..@end_index].empty?
|
48
|
+
puts "butterfly_net: #{@file_name} closed"
|
49
|
+
else
|
50
|
+
lines[@start_index..@end_index].each do |line|
|
51
|
+
@adapter.add_command(line)
|
52
|
+
end
|
53
|
+
puts "butterfly_net: #{@file_name} closed, with #{@end_index - @start_index + 1} lines, from '#{lines[@start_index]}' to '#{lines[@end_index]}'"
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
@adapter.create_file(@file_name)
|
58
|
+
|
59
|
+
true
|
60
|
+
# end
|
61
|
+
rescue Exception => e
|
62
|
+
puts "butterfly_net: Error generating tests: #{e}"
|
63
|
+
puts e.backtrace
|
37
64
|
false
|
38
65
|
end
|
39
66
|
|
@@ -12,22 +12,28 @@ module ButterflyNet
|
|
12
12
|
@assertion_sets.last << line
|
13
13
|
end
|
14
14
|
|
15
|
-
def close_assertion_set
|
15
|
+
def close_assertion_set(method_name = nil)
|
16
|
+
@assertion_sets.last.name = (method_name ? method_name : @assertion_sets.size)
|
16
17
|
@assertion_sets << TestUnitMethod.new
|
17
18
|
end
|
18
19
|
|
20
|
+
def empty?
|
21
|
+
@assertion_sets.empty?
|
22
|
+
end
|
23
|
+
|
19
24
|
def create_file(filename)
|
20
|
-
return nil if
|
25
|
+
return nil if empty?
|
21
26
|
|
22
27
|
#todo detect existing file, and delete last 'end' line
|
23
28
|
file = File.open(filename, 'a+') # starts at end of file if file exists
|
24
29
|
|
25
30
|
if defined? ActiveSupport::TestCase # rails # todo support earlier versions of rails
|
26
|
-
file.puts "require \"test_helper\"\n\nclass
|
31
|
+
file.puts "require \"test_helper\"\n\n# script/console test capture courtesy of butterfly_net (butterflynet.org)\nclass MyTest < ActiveSupport::TestCase"
|
27
32
|
else
|
28
|
-
file.puts "require \"test/unit\"\n\nclass
|
33
|
+
file.puts "require \"test/unit\"\n\n# IRB test capture courtesy of butterfly_net (butterflynet.org)\nclass MyTest < Test::Unit::TestCase"
|
29
34
|
end
|
30
35
|
|
36
|
+
|
31
37
|
test_methods.each do |test_method|
|
32
38
|
file.puts "\n #{test_method}"
|
33
39
|
end
|
@@ -41,13 +47,8 @@ module ButterflyNet
|
|
41
47
|
end
|
42
48
|
|
43
49
|
def test_methods
|
44
|
-
|
45
|
-
@assertion_sets.
|
46
|
-
|
47
|
-
|
48
|
-
method_strings << assertions.text(i + 1)
|
49
|
-
end
|
50
|
-
method_strings
|
50
|
+
@assertion_sets.last.name = @assertion_sets.size unless @assertion_sets.last.name # done here for testing
|
51
|
+
@assertion_sets.collect {|i| i.text }.compact
|
51
52
|
end
|
52
53
|
|
53
54
|
end
|
@@ -1,67 +1,55 @@
|
|
1
1
|
module ButterflyNet
|
2
2
|
class TestUnitMethod
|
3
3
|
|
4
|
+
attr_accessor :name
|
5
|
+
|
4
6
|
def initialize
|
5
|
-
@
|
7
|
+
@commands = []
|
6
8
|
end
|
7
9
|
|
8
10
|
def <<(line)
|
9
|
-
@
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.simple_assignment_only?(line) # todo: extract to line class
|
13
|
-
line =~ /[^=<>!*%\/+-\\|&]=[^=~]/
|
11
|
+
@commands << line
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
elsif expected && expected == line # type not supported, assume object inequality
|
20
|
-
"assert_not_equal((#{expected}), #{line})"
|
21
|
-
elsif expected == "true" # use simple assert() for true boolean expressions
|
22
|
-
"assert(#{line})"
|
23
|
-
elsif expected
|
24
|
-
"assert_equal(#{expected}, #{line})"
|
25
|
-
else
|
26
|
-
nil
|
27
|
-
end
|
14
|
+
def name=(name)
|
15
|
+
name = underscore(name)
|
16
|
+
@name = name =~ /^test_/ ? name : "test_#{name}"
|
28
17
|
end
|
29
18
|
|
30
|
-
def
|
31
|
-
|
19
|
+
def self.assignment_or_require?(line) # todo: extract to line class
|
20
|
+
line =~ /require\s*['|"]\w+['|"]|[^=<>!*%\/+-\\|&]=[^=~]/
|
32
21
|
end
|
33
22
|
|
34
|
-
def text
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
23
|
+
def text
|
24
|
+
purge_bad_commands
|
25
|
+
lines_string = ""
|
26
|
+
@commands.each_index do |i|
|
27
|
+
text = assertion(i)
|
28
|
+
lines_string += " #{text}\n" if text
|
39
29
|
end
|
40
|
-
|
30
|
+
lines_string.empty? ? nil : "def #{@name}\n#{lines_string} end"
|
41
31
|
end
|
42
32
|
|
43
|
-
def
|
33
|
+
def assertion(current_i)
|
44
34
|
|
45
|
-
current_line = @
|
35
|
+
current_line = @commands[current_i]
|
46
36
|
commands = current_line
|
47
37
|
start_i = current_i
|
48
38
|
|
49
39
|
begin
|
50
40
|
retval = eval commands
|
51
|
-
rescue
|
41
|
+
rescue Exception
|
52
42
|
start_i -= 1
|
53
|
-
commands = @
|
43
|
+
commands = @commands[start_i..current_i].join("\n")
|
54
44
|
|
55
45
|
if start_i < 0
|
56
|
-
|
57
|
-
return nil
|
46
|
+
return nil # give up, can't go further back
|
58
47
|
else
|
59
48
|
retry
|
60
49
|
end
|
61
50
|
end
|
62
|
-
if
|
51
|
+
if TestUnitMethod.assignment_or_require?(current_line)
|
63
52
|
current_line
|
64
|
-
|
65
53
|
elsif instances_equal_by_value?(retval) # expression result supports value equality
|
66
54
|
|
67
55
|
if retval == true # use simple assert() for true boolean expressions
|
@@ -84,6 +72,37 @@ module ButterflyNet
|
|
84
72
|
instance == instance.dup rescue true # can't dup Fixnum, et al...
|
85
73
|
end
|
86
74
|
|
75
|
+
private
|
76
|
+
|
77
|
+
|
78
|
+
def purge_bad_commands
|
79
|
+
begin
|
80
|
+
commands = ""
|
81
|
+
index = 0
|
82
|
+
@commands.each_with_index do |current_line, i|
|
83
|
+
index = i
|
84
|
+
commands += current_line + "\n"
|
85
|
+
eval commands
|
86
|
+
end
|
87
|
+
|
88
|
+
rescue Exception
|
89
|
+
# delete offender and start again from the beginning
|
90
|
+
@commands.delete_at index
|
91
|
+
end
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
# Adapted from ActiveSupport Inflector
|
96
|
+
def underscore(name)
|
97
|
+
name.to_s.strip.
|
98
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
99
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2').
|
100
|
+
tr("-", "_").
|
101
|
+
tr(" ", "_").
|
102
|
+
downcase
|
103
|
+
end
|
104
|
+
|
105
|
+
|
87
106
|
|
88
107
|
end
|
89
108
|
end
|
@@ -22,7 +22,6 @@ class TestUnitAdapterTest < Test::Unit::TestCase
|
|
22
22
|
def test_test_methods_single
|
23
23
|
@adapter.add_command("1 + 1")
|
24
24
|
expected = "def test_1\n assert_equal(2, 1 + 1)\n end"
|
25
|
-
@adapter.test_methods
|
26
25
|
assert_equal expected, @adapter.test_methods.first
|
27
26
|
end
|
28
27
|
|
@@ -30,7 +29,6 @@ class TestUnitAdapterTest < Test::Unit::TestCase
|
|
30
29
|
@adapter.add_command("1 + 1")
|
31
30
|
@adapter.add_command("1 + 2")
|
32
31
|
expected = "def test_1\n assert_equal(2, 1 + 1)\n assert_equal(3, 1 + 2)\n end"
|
33
|
-
@adapter.test_methods
|
34
32
|
assert_equal expected, @adapter.test_methods.last
|
35
33
|
end
|
36
34
|
|
@@ -38,7 +36,13 @@ class TestUnitAdapterTest < Test::Unit::TestCase
|
|
38
36
|
@adapter.add_command("a = 1")
|
39
37
|
@adapter.add_command("a + 2")
|
40
38
|
expected = "def test_1\n a = 1\n assert_equal(3, a + 2)\n end"
|
41
|
-
@adapter.test_methods
|
39
|
+
assert_equal expected, @adapter.test_methods.last
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_test_methods_require
|
43
|
+
@adapter.add_command("require 'bigdecimal'")
|
44
|
+
@adapter.add_command("BigDecimal(\"1.0\") - 0.5")
|
45
|
+
expected = "def test_1\n require 'bigdecimal'\n assert_equal(0.5, BigDecimal(\"1.0\") - 0.5)\n end"
|
42
46
|
assert_equal expected, @adapter.test_methods.last
|
43
47
|
end
|
44
48
|
|
@@ -46,9 +50,20 @@ class TestUnitAdapterTest < Test::Unit::TestCase
|
|
46
50
|
@adapter.add_command("1 + 1")
|
47
51
|
@adapter.close_assertion_set
|
48
52
|
@adapter.add_command("1 + 2")
|
49
|
-
|
50
|
-
@adapter.test_methods
|
51
|
-
|
53
|
+
assert_equal "def test_1\n assert_equal(2, 1 + 1)\n end", @adapter.test_methods.first
|
54
|
+
assert_equal "def test_2\n assert_equal(3, 1 + 2)\n end", @adapter.test_methods.last
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_test_methods_naming
|
58
|
+
@adapter.add_command("1 + 1")
|
59
|
+
@adapter.close_assertion_set 'test_one_plus_one'
|
60
|
+
assert_equal "def test_one_plus_one\n assert_equal(2, 1 + 1)\n end", @adapter.test_methods.first
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_test_methods_bad_input
|
64
|
+
@adapter.add_command("BADCOMMAND")
|
65
|
+
@adapter.close_assertion_set
|
66
|
+
assert_nil @adapter.test_methods.first
|
52
67
|
end
|
53
68
|
|
54
69
|
def test_create_file
|
@@ -56,7 +71,8 @@ class TestUnitAdapterTest < Test::Unit::TestCase
|
|
56
71
|
expected = <<-EOF
|
57
72
|
require "test/unit"
|
58
73
|
|
59
|
-
|
74
|
+
# IRB test capture courtesy of butterfly_net (butterflynet.org)
|
75
|
+
class MyTest < Test::Unit::TestCase
|
60
76
|
|
61
77
|
def test_1
|
62
78
|
assert_equal(2, 1 + 1)
|
@@ -64,7 +80,7 @@ class TempTest < Test::Unit::TestCase
|
|
64
80
|
|
65
81
|
end
|
66
82
|
EOF
|
67
|
-
@adapter.create_file('temp_test.rb')
|
83
|
+
@adapter.create_file('temp_test.rb') # todo: write to memory instead of file...
|
68
84
|
assert_equal expected, File.open('temp_test.rb').readlines.join('')
|
69
85
|
end
|
70
86
|
|
@@ -8,174 +8,265 @@ class TestUnitMethodTest < Test::Unit::TestCase
|
|
8
8
|
|
9
9
|
def setup
|
10
10
|
@method = TestUnitMethod.new
|
11
|
+
@method.name = "1"
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
assert TestUnitMethod.
|
14
|
+
def test_assignment_or_require_true
|
15
|
+
assert TestUnitMethod.assignment_or_require? "a=1"
|
15
16
|
end
|
16
17
|
|
17
|
-
# def
|
18
|
-
# assert TestUnitMethod.
|
18
|
+
# def test_assignment_or_require_true_orequals todo: solve orequals in regex
|
19
|
+
# assert TestUnitMethod.assignment_or_require? "a ||= 1"
|
19
20
|
# end
|
20
21
|
|
21
|
-
def
|
22
|
-
assert TestUnitMethod.
|
22
|
+
def test_assignment_or_require_true_whitespace
|
23
|
+
assert TestUnitMethod.assignment_or_require? "a = 1"
|
23
24
|
end
|
24
25
|
|
25
|
-
def
|
26
|
-
assert TestUnitMethod.
|
26
|
+
def test_assignment_or_require_true_contains_equals
|
27
|
+
assert TestUnitMethod.assignment_or_require? "a = (1 == 1)"
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
-
assert
|
30
|
+
def test_assignment_or_require_true_require_bigdecimal
|
31
|
+
assert TestUnitMethod.assignment_or_require? "require 'bigdecimal'"
|
31
32
|
end
|
32
33
|
|
33
|
-
def
|
34
|
-
assert
|
34
|
+
def test_assignment_or_require_true_require
|
35
|
+
assert TestUnitMethod.assignment_or_require? "require 'rubygems'"
|
35
36
|
end
|
36
37
|
|
37
|
-
def
|
38
|
-
assert
|
38
|
+
def test_assignment_or_require_true_require_no_spaces
|
39
|
+
assert TestUnitMethod.assignment_or_require? "require\"rubygems\""
|
39
40
|
end
|
40
41
|
|
41
|
-
def
|
42
|
-
|
42
|
+
def test_assignment_or_require_false
|
43
|
+
assert !TestUnitMethod.assignment_or_require?("a + 1")
|
43
44
|
end
|
44
45
|
|
45
|
-
def
|
46
|
-
|
46
|
+
def test_assignment_or_require_false_with_equals
|
47
|
+
assert !TestUnitMethod.assignment_or_require?("a == 1")
|
47
48
|
end
|
48
49
|
|
49
|
-
def
|
50
|
-
|
50
|
+
def test_assignment_or_require_false_threequals
|
51
|
+
assert !TestUnitMethod.assignment_or_require?("a===1")
|
51
52
|
end
|
52
53
|
|
53
|
-
def
|
54
|
-
assert !TestUnitMethod.
|
54
|
+
def test_assignment_or_require_false_regex
|
55
|
+
assert !TestUnitMethod.assignment_or_require?("'a' =~ /a/")
|
55
56
|
end
|
56
57
|
|
57
|
-
def
|
58
|
-
assert !TestUnitMethod.
|
58
|
+
def test_assignment_or_require_false_regex
|
59
|
+
assert !TestUnitMethod.assignment_or_require?("'a' =~ /a/")
|
59
60
|
end
|
60
61
|
|
61
|
-
def
|
62
|
-
assert !TestUnitMethod.
|
62
|
+
def test_assignment_or_require_false_lessthanequals
|
63
|
+
assert !TestUnitMethod.assignment_or_require?("1 <= 1")
|
63
64
|
end
|
64
65
|
|
65
|
-
def
|
66
|
-
assert !TestUnitMethod.
|
66
|
+
def test_assignment_or_require_false_greaterthanequals
|
67
|
+
assert !TestUnitMethod.assignment_or_require?("1 >= 1")
|
67
68
|
end
|
68
69
|
|
69
|
-
def
|
70
|
-
assert !TestUnitMethod.
|
70
|
+
def test_assignment_or_require_false_flyingsaucer
|
71
|
+
assert !TestUnitMethod.assignment_or_require?("1 <=> 1")
|
71
72
|
end
|
72
73
|
|
73
|
-
def
|
74
|
-
assert !TestUnitMethod.
|
74
|
+
def test_assignment_or_require_false_notequal
|
75
|
+
assert !TestUnitMethod.assignment_or_require?("1 != 0")
|
75
76
|
end
|
76
77
|
|
77
|
-
def
|
78
|
-
assert !TestUnitMethod.
|
78
|
+
def test_assignment_or_require_false_modequal
|
79
|
+
assert !TestUnitMethod.assignment_or_require?("a %= 1")
|
79
80
|
end
|
80
81
|
|
81
|
-
def
|
82
|
-
assert !TestUnitMethod.
|
82
|
+
def test_assignment_or_require_false_orequal
|
83
|
+
assert !TestUnitMethod.assignment_or_require?("a |= 1")
|
83
84
|
end
|
84
85
|
|
85
|
-
def
|
86
|
-
assert !TestUnitMethod.
|
86
|
+
def test_assignment_or_require_false_plusequal
|
87
|
+
assert !TestUnitMethod.assignment_or_require?("a += 1")
|
87
88
|
end
|
88
89
|
|
89
|
-
def
|
90
|
-
assert !TestUnitMethod.
|
90
|
+
def test_assignment_or_require_false_minusequal
|
91
|
+
assert !TestUnitMethod.assignment_or_require?("a -= 1")
|
91
92
|
end
|
92
93
|
|
93
|
-
def
|
94
|
-
assert !TestUnitMethod.
|
94
|
+
def test_assignment_or_require_false_divideequal
|
95
|
+
assert !TestUnitMethod.assignment_or_require?("a /= 1")
|
95
96
|
end
|
96
97
|
|
97
|
-
def
|
98
|
-
assert !TestUnitMethod.
|
98
|
+
def test_assignment_or_require_false_andequal
|
99
|
+
assert !TestUnitMethod.assignment_or_require?("a &= 1")
|
99
100
|
end
|
100
101
|
|
102
|
+
def test_assignment_or_require_false_shiftrightequal
|
103
|
+
assert !TestUnitMethod.assignment_or_require?("a >>= 1")
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_assignment_or_require_false_shiftleftequal
|
107
|
+
assert !TestUnitMethod.assignment_or_require?("a <<= 1")
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_assignment_or_require_false_timesequal
|
111
|
+
assert !TestUnitMethod.assignment_or_require?("a *= 1")
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_name_uppercase
|
115
|
+
@method.name = "MYMETHOD"
|
116
|
+
assert_equal("test_mymethod", @method.name)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_name_camelcase
|
120
|
+
@method.name = "MyMethod"
|
121
|
+
assert_equal("test_my_method", @method.name)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_name_hyphenated
|
125
|
+
@method.name = "my-Method"
|
126
|
+
assert_equal("test_my_method", @method.name)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_name_spaces
|
130
|
+
@method.name = " my Method "
|
131
|
+
assert_equal("test_my_method", @method.name)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_test_methods_naming_no_changes
|
135
|
+
@method.name = 'test_one_plus_one'
|
136
|
+
assert_equal("test_one_plus_one", @method.name)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_test_methods_naming_prepends_test
|
140
|
+
@method.name = 'one_plus_one'
|
141
|
+
assert_equal("test_one_plus_one", @method.name)
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
# def test_text_split_statements_into_lines todo
|
147
|
+
# @method << "a = 1; a + 1"
|
148
|
+
# assert_equal "def test_1\n a = 1\n assert_equal(2, a + 1)\n end", @method.text
|
149
|
+
# end
|
150
|
+
|
151
|
+
def test_purge_unexpected_identifier
|
152
|
+
@method << "a = 1"
|
153
|
+
@method << "2b" # syntax error, unexpected tIDENTIFIER, expecting $end
|
154
|
+
@method << "a += 1"
|
155
|
+
assert_equal "def test_1\n a = 1\n assert_equal(2, a += 1)\n end", @method.text
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_purge_unexpected_identifiers
|
159
|
+
@method << "a += 1" # undefined method `+' for nil:NilClass
|
160
|
+
@method << "a = 1"
|
161
|
+
@method << "a += 1"
|
162
|
+
assert_equal "def test_1\n a = 1\n assert_equal(2, a += 1)\n end", @method.text
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_text_require
|
166
|
+
@method << "require 'rubygems'"
|
167
|
+
@method << "require'active_support'"
|
168
|
+
@method << "'CamelCase'.underscore"
|
169
|
+
assert_equal "def test_1\n require 'rubygems'\n require'active_support'\n assert_equal(\"camel_case\", 'CamelCase'.underscore)\n end", @method.text
|
170
|
+
end
|
101
171
|
|
102
172
|
def test_expected_boolean
|
103
173
|
line = "1 == 1"
|
104
174
|
@method << line
|
105
|
-
assert_equal("assert(#{line})", @method.
|
175
|
+
assert_equal("assert(#{line})", @method.assertion(0))
|
106
176
|
end
|
107
177
|
|
108
178
|
def test_assertion_fixnum
|
109
179
|
line = "1"
|
110
180
|
@method << line
|
111
|
-
assert_equal("assert_equal(#{line}, #{line})", @method.
|
181
|
+
assert_equal("assert_equal(#{line}, #{line})", @method.assertion(0))
|
112
182
|
end
|
113
183
|
|
114
184
|
def test_assertion_boolean_false
|
115
185
|
line = "1 != 1"
|
116
186
|
@method << line
|
117
|
-
assert_equal("assert_equal(false, #{line})", @method.
|
187
|
+
assert_equal("assert_equal(false, #{line})", @method.assertion(0))
|
118
188
|
end
|
119
189
|
|
120
|
-
|
121
|
-
|
122
190
|
def test_array_add
|
123
191
|
@method << "a = []"
|
124
192
|
line2 = "a << \"1\""
|
125
193
|
@method << line2
|
126
|
-
assert_equal("assert_equal([\"1\"], #{line2})", @method.
|
194
|
+
assert_equal("assert_equal([\"1\"], #{line2})", @method.assertion(1))
|
127
195
|
end
|
128
196
|
|
129
197
|
def test_butterfly_net
|
130
198
|
@method << "method = TestUnitMethod.new"
|
131
199
|
@method << "method << \"1 + 1\""
|
132
|
-
assert_equal("assert_equal([\"1 + 1\"], method << \"1 + 1\")", @method.
|
200
|
+
assert_equal("assert_equal([\"1 + 1\"], method << \"1 + 1\")", @method.assertion(1))
|
133
201
|
end
|
134
202
|
|
135
|
-
|
136
|
-
|
137
|
-
def test_text_from_expression_boolean
|
203
|
+
def test_assertion_boolean
|
138
204
|
line = "1 == 1"
|
139
205
|
@method << line
|
140
|
-
assert_equal("assert(#{line})", @method.
|
206
|
+
assert_equal("assert(#{line})", @method.assertion(0))
|
141
207
|
end
|
142
208
|
|
143
|
-
def
|
209
|
+
def test_assertion_string
|
144
210
|
line = "'a' + 'b'"
|
145
211
|
@method << line
|
146
|
-
assert_equal("assert_equal(\"ab\", #{line})", @method.
|
212
|
+
assert_equal("assert_equal(\"ab\", #{line})", @method.assertion(0))
|
147
213
|
end
|
148
214
|
|
149
|
-
def
|
215
|
+
def test_assertion_nil
|
150
216
|
line = "[].first"
|
151
217
|
@method << line
|
152
|
-
assert_equal("assert_nil(#{line})", @method.
|
218
|
+
assert_equal("assert_nil(#{line})", @method.assertion(0))
|
153
219
|
end
|
154
220
|
|
155
|
-
def
|
221
|
+
def test_assertion_boolean
|
156
222
|
line = "1 == 1"
|
157
223
|
@method << line
|
158
|
-
assert_equal("assert(#{line})", @method.
|
224
|
+
assert_equal("assert(#{line})", @method.assertion(0))
|
159
225
|
end
|
160
226
|
|
161
|
-
def
|
227
|
+
def test_assertion_object_not_equal
|
162
228
|
line = "Object.new"
|
163
229
|
@method << line
|
164
|
-
assert_equal("assert_not_equal((#{line}), #{line})", @method.
|
230
|
+
assert_equal("assert_not_equal((#{line}), #{line})", @method.assertion(0))
|
165
231
|
end
|
166
232
|
|
167
|
-
def
|
233
|
+
def test_assertion_array
|
168
234
|
line = "([1,2,3])[0..0]"
|
169
235
|
@method << line
|
170
|
-
assert_equal("assert_equal([1], #{line})", @method.
|
236
|
+
assert_equal("assert_equal([1], #{line})", @method.assertion(0))
|
171
237
|
end
|
172
238
|
|
173
|
-
def
|
174
|
-
line = "
|
239
|
+
def test_assertion_illegal_input
|
240
|
+
line = "badtext"
|
175
241
|
@method << line
|
176
|
-
assert_nil @method.
|
242
|
+
assert_nil @method.assertion(0)
|
177
243
|
end
|
178
244
|
|
245
|
+
def test_text
|
246
|
+
@method << "1 + 1"
|
247
|
+
assert_equal "def test_1\n assert_equal(2, 1 + 1)\n end", @method.text
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
|
252
|
+
def test_text_bad_input_constant
|
253
|
+
@method << "BADCONSTANT"
|
254
|
+
assert_nil @method.text
|
255
|
+
end
|
256
|
+
|
257
|
+
|
258
|
+
|
259
|
+
|
260
|
+
|
261
|
+
|
262
|
+
|
263
|
+
|
264
|
+
|
265
|
+
|
266
|
+
|
267
|
+
|
268
|
+
|
269
|
+
|
179
270
|
# non-project tests (scratchpad)
|
180
271
|
|
181
272
|
def test_eval_scope
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: butterfly_net
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Smith
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-21 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -22,7 +22,7 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
-
- README
|
25
|
+
- README.md
|
26
26
|
- lib/butterfly_net/commands.rb
|
27
27
|
- lib/butterfly_net/file_writer.rb
|
28
28
|
- lib/butterfly_net/test_unit_adapter.rb
|
@@ -32,7 +32,7 @@ files:
|
|
32
32
|
- test/test_unit_adapter_test.rb
|
33
33
|
- test/test_unit_method_test.rb
|
34
34
|
has_rdoc: true
|
35
|
-
homepage: http://
|
35
|
+
homepage: http://www.butterflynet.org
|
36
36
|
licenses: []
|
37
37
|
|
38
38
|
post_install_message:
|
data/README
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
butterfly_net
|
2
|
-
|
3
|
-
Version: 0.0.2
|
4
|
-
|
5
|
-
Author: Chris Smith
|
6
|
-
Email: quartzmo@gmail.com
|
7
|
-
Project homepage: http://github.com/quartzmo/butterfly_net
|
8
|
-
|
9
|
-
DESCRIPTION
|
10
|
-
|
11
|
-
IRB history captured as Test::Unit tests. (RSpec and others hopefully soon to come.)
|
12
|
-
|
13
|
-
INSTALL
|
14
|
-
|
15
|
-
1. gem sources -a http://gemcutter.org
|
16
|
-
2. sudo gem install butterfly_net
|
17
|
-
3. To automatically require butterfly_net on every IRB session, add the following to your ~/.irbrc:
|
18
|
-
|
19
|
-
require 'rubygems'
|
20
|
-
require 'butterfly_net'
|
21
|
-
|
22
|
-
USAGE
|
23
|
-
|
24
|
-
Command methods:
|
25
|
-
|
26
|
-
bn, bn_open - Open an active test case, with optional string arg file_name ('.rb' is appended if needed)
|
27
|
-
bnc, bn_close - Close the active test case, and write the output to a file
|
28
|
-
|
29
|
-
Ruby on Rails console:
|
30
|
-
|
31
|
-
For repeatable tests, be sure to load the Rails test environment with "./script/console test".
|
32
|
-
In a Rails project, you can run all tests with the standard rake command 'rake test',
|
33
|
-
or an individual test by adding the test directory to the path with the option -I when you invoke Ruby.
|
34
|
-
|
35
|
-
chris$ ./script/console test
|
36
|
-
Loading test environment (Rails 2.3.4)
|
37
|
-
>> bn "test/unit/person_console_test"
|
38
|
-
. . .
|
39
|
-
>> Person.count
|
40
|
-
=> 2
|
41
|
-
>> exit
|
42
|
-
. . .
|
43
|
-
chris$ ruby -Itest test/unit/person_console_test.rb
|
44
|
-
. . .
|
45
|
-
1 tests, 1 assertions, 0 failures, 0 errors
|
46
|
-
|
47
|
-
|
48
|
-
LICENSE
|
49
|
-
|
50
|
-
(The MIT License)
|
51
|
-
|
52
|
-
Copyright (c) 2010 Chris Smith
|
53
|
-
|
54
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
55
|
-
a copy of this software and associated documentation files (the
|
56
|
-
'Software'), to deal in the Software without restriction, including
|
57
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
58
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
59
|
-
permit persons to whom the Software is furnished to do so, subject to
|
60
|
-
the following conditions:
|
61
|
-
|
62
|
-
The above copyright notice and this permission notice shall be
|
63
|
-
included in all copies or substantial portions of the Software.
|
64
|
-
|
65
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
66
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
67
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
68
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
69
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
70
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
71
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|