picard 0.0.2

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,5 @@
1
+ .idea
2
+ .bundle
3
+ *.gem
4
+ Gemfile.lock
5
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.test_files = FileList['test/picard/*_test.rb']
6
+ t.verbose = true
7
+ end
@@ -0,0 +1,4 @@
1
+ require "picard/version"
2
+
3
+ module Picard
4
+ end
@@ -0,0 +1,65 @@
1
+ require 'live_ast'
2
+ require 'ruby2ruby'
3
+
4
+ module Picard
5
+ class AstHelper
6
+ ResultItem = Struct.new(:index, :ast)
7
+
8
+ def all_statements method
9
+ method_ast = method.to_ast
10
+ body_statements = extract_statements(method_ast)[1..-1]
11
+ wrap_in_result_items body_statements
12
+ end
13
+
14
+ def find_all_statements_in_block items, block_name
15
+ start_index = find_index_of_statements_calling(items, block_name)
16
+ end_index = find_index_of_statements_calling(items, :where)
17
+ end_index = -1 unless end_index
18
+ start_index ? items[start_index + 1 ... end_index] : []
19
+ end
20
+
21
+ def wrap_assertion ast
22
+ Sexp.new(:call, nil, :assert, Sexp.new(:arglist, ast))
23
+ end
24
+
25
+ def replace_statement method, index, new_ast
26
+ method_ast = method.to_ast
27
+ body_statements = extract_statements(method_ast)
28
+ body_statements[index + 1] = new_ast
29
+ end
30
+
31
+ def extract_ast method
32
+ method.to_ast
33
+ end
34
+
35
+ def find_all_local_variables_in_block items, block_name
36
+ index = find_index_of_statements_calling(items, block_name)
37
+ return [] unless index
38
+ items[index + 1 .. -1].find_all do |e|
39
+ e.ast[0] == :lasgn
40
+ end.collect do |e|
41
+ e.ast[1]
42
+ end
43
+ end
44
+
45
+ private
46
+ def find_index_of_statements_calling(items, method_name)
47
+ items.index do |item|
48
+ ast = item.ast
49
+ ast[0] == :call and ast[2] == method_name
50
+ end
51
+ end
52
+
53
+ def extract_statements method_ast
54
+ method_ast[3][1]
55
+ end
56
+
57
+ def wrap_in_result_items asts
58
+ res = []
59
+ asts.each_with_index do |e, i|
60
+ res << ResultItem.new(i, e)
61
+ end
62
+ res
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,17 @@
1
+ module Picard
2
+ class ClassRipper
3
+ def test_method? method_name
4
+ method_name.to_s.start_with? 'test_'
5
+ end
6
+
7
+ def all_test_method_names clazz
8
+ clazz.public_instance_methods.find_all do |m|
9
+ test_method? m
10
+ end
11
+ end
12
+
13
+ def replace_method clazz, new_method
14
+ clazz.class_eval new_method
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module Picard
2
+ class ExpectBlock
3
+ def self.invoke *args
4
+ yield *args
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ require 'live_ast'
2
+ require 'live_ast/to_ruby'
3
+ require 'ruby2ruby'
4
+
5
+ module Picard
6
+ class MethodRipper
7
+ def initialize ast_helper = AstHelper.new
8
+ @ast_helper = ast_helper
9
+ end
10
+
11
+ def wrap_all_assertions method
12
+ all_statements = @ast_helper.all_statements(method)
13
+ assertions = @ast_helper.find_all_statements_in_block(all_statements, :expect)
14
+ replace_all_statements_with_assertions assertions, method
15
+ ast_to_str @ast_helper.extract_ast(method)
16
+ end
17
+
18
+ private
19
+
20
+ def replace_all_statements_with_assertions assertions, method
21
+ assertions.each do |e|
22
+ wrapped = @ast_helper.wrap_assertion(e.ast)
23
+ @ast_helper.replace_statement(method, e.index, wrapped)
24
+ end
25
+ end
26
+
27
+ def ast_to_str ast
28
+ str = Ruby2Ruby.new.process(ast)
29
+ remove_spaces str
30
+ end
31
+
32
+ def remove_spaces str
33
+ str.gsub(/\n\s+/, "\n")
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ require 'live_ast'
2
+ require 'live_ast/to_ruby'
3
+ require 'ruby2ruby'
4
+
5
+ module Picard
6
+ class Preprocessor
7
+ def initialize class_ripper = ClassRipper.new, method_ripper = MethodRipper.new
8
+ @class_ripper = class_ripper
9
+ @method_ripper = method_ripper
10
+ @preprocessed_methods = []
11
+ end
12
+
13
+ def preprocess_class clazz
14
+ all_test_methods = @class_ripper.all_test_method_names(clazz)
15
+ all_test_methods.each do |m|
16
+ preprocess_method clazz, m
17
+ end
18
+ end
19
+
20
+ def preprocess_method clazz, method_name
21
+ return if preprocessed?(method_name)
22
+ return unless @class_ripper.test_method?(method_name)
23
+
24
+ mark_as_preprocessed method_name
25
+ replace_method_with_preprocessed clazz, method_name
26
+ end
27
+
28
+ private
29
+
30
+ def replace_method_with_preprocessed clazz, method_name
31
+ method = clazz.instance_method(method_name)
32
+ new_method_str = @method_ripper.wrap_all_assertions(method)
33
+ @class_ripper.replace_method clazz, new_method_str
34
+ end
35
+
36
+ def preprocessed? method_name
37
+ @preprocessed_methods.include? method_name
38
+ end
39
+
40
+ def mark_as_preprocessed method_name
41
+ @preprocessed_methods << method_name
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ module Picard
2
+ module DummyMethods
3
+ def given
4
+ end
5
+
6
+ def expect
7
+ end
8
+ end
9
+
10
+ module ClassMethods
11
+ def method_added name
12
+ @tr ||= Picard::Preprocessor.new
13
+ @tr.preprocess_method self, name
14
+ end
15
+ end
16
+
17
+ module TestUnit
18
+ def self.included clazz
19
+ clazz.send :include, DummyMethods
20
+ clazz.send :extend, ClassMethods
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Picard
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "picard/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "picard"
7
+ s.version = Picard::VERSION
8
+ s.authors = ["Victor Savkin"]
9
+ s.email = ["vic.savkin@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Test framework inspired by Spock}
12
+ s.description = %q{Test framework inspired by Spock}
13
+
14
+ s.rubyforge_project = "picard"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'live_ast', '= 1.0.2'
22
+ s.add_dependency 'live_ast_ripper', '= 0.6.5'
23
+ s.add_development_dependency 'rr'
24
+ s.add_development_dependency 'picard', '= 0.0.1'
25
+ end
@@ -0,0 +1,99 @@
1
+ require_relative '../test_helper'
2
+
3
+ class Picard::AstHelperTest < Test::Unit::TestCase
4
+ class TestClass
5
+ def test_method
6
+ x = 10
7
+
8
+ expect
9
+ x == 10
10
+ x == 12
11
+
12
+ where
13
+ y = 1
14
+ end
15
+
16
+ def method_without_assertions
17
+ 'dummy'
18
+ end
19
+
20
+ def test_method_to_replace_statements
21
+ 'dummy'
22
+ end
23
+
24
+ def test_method_with_where_block
25
+ x = 10
26
+
27
+ where
28
+ y = 20
29
+ z = 30
30
+ end
31
+ end
32
+
33
+ def setup
34
+ @helper = Picard::AstHelper.new
35
+ end
36
+
37
+ def test_should_return_all_statements_of_method
38
+ method = TestClass.instance_method(:test_method)
39
+ actual = @helper.all_statements(method)
40
+
41
+ assert_equal 0, actual[0].index
42
+ assert_equal s(:lasgn, :x, s(:lit, 10)), actual[0].ast
43
+
44
+ assert_equal 1, actual[1].index
45
+ assert_equal s(:call, nil, :expect, s(:arglist)), actual[1].ast
46
+
47
+ assert_equal 2, actual[2].index
48
+ assert_equal s(:call, s(:lvar, :x), :==, s(:arglist, s(:lit, 10))), actual[2].ast
49
+
50
+ assert_equal 3, actual[3].index
51
+ assert_equal s(:call, s(:lvar, :x), :==, s(:arglist, s(:lit, 12))), actual[3].ast
52
+ end
53
+
54
+ def test_should_find_all_statements_in_specified_block
55
+ method = TestClass.instance_method(:test_method)
56
+ all_statements = @helper.all_statements(method)
57
+ actual = @helper.find_all_statements_in_block(all_statements, :expect)
58
+
59
+ assert_equal 2, actual.size
60
+
61
+ assert_equal 2, actual[0].index
62
+ assert_equal s(:call, s(:lvar, :x), :==, s(:arglist, s(:lit, 10))), actual[0].ast
63
+
64
+ assert_equal 3, actual[1].index
65
+ assert_equal s(:call, s(:lvar, :x), :==, s(:arglist, s(:lit, 12))), actual[1].ast
66
+ end
67
+
68
+ def test_should_return_empty_array_if_specified_method_call_was_not_found
69
+ method = TestClass.instance_method(:method_without_assertions)
70
+ all_statements = @helper.all_statements(method)
71
+ actual = @helper.find_all_statements_in_block(all_statements, :expect)
72
+ assert_equal [], actual
73
+ end
74
+
75
+ def test_should_wrap_assertion
76
+ result = @helper.wrap_assertion(s(:lit, true))
77
+ assert_equal s(:call, nil, :assert, s(:arglist, s(:lit, true))), result
78
+ end
79
+
80
+ def test_should_replace_statement
81
+ method = TestClass.instance_method(:test_method_to_replace_statements)
82
+ @helper.replace_statement(method, 0, s(:lit, true))
83
+
84
+ all_statements = @helper.all_statements(method)
85
+ assert_equal s(:lit, true), all_statements[0].ast
86
+ end
87
+
88
+ def test_should_return_list_of_all_local_variables_defined_after_specified_method_call
89
+ method = TestClass.instance_method(:test_method_with_where_block)
90
+ all_statements = @helper.all_statements(method)
91
+ actual = @helper.find_all_local_variables_in_block(all_statements, :where)
92
+ assert_equal [:y, :z], actual
93
+ end
94
+
95
+ private
96
+ def s(*args)
97
+ Sexp.new *args
98
+ end
99
+ end
@@ -0,0 +1,44 @@
1
+ require_relative '../test_helper'
2
+
3
+ class Picard::ClassRipperTest < Test::Unit::TestCase
4
+ class TestClass
5
+ def test_one; end
6
+ def test_two; end
7
+ def three; end
8
+ end
9
+
10
+ class TestClassWithoutTestMethods
11
+ def method1; end
12
+ end
13
+
14
+ class DummyClass
15
+ def dummy
16
+ 'dummy'
17
+ end
18
+ end
19
+
20
+ def setup
21
+ @ripper = Picard::ClassRipper.new
22
+ end
23
+
24
+ def test_should_return_if_method_is_test_method
25
+ assert @ripper.test_method?('test_method')
26
+ assert !@ripper.test_method?('regular_method')
27
+ end
28
+
29
+ def test_should_return_list_of_all_test_methods
30
+ test_methods = @ripper.all_test_method_names(TestClass)
31
+ assert_equal [:test_one, :test_two], test_methods
32
+ end
33
+
34
+ def test_should_return_empty_list_if_there_are_no_test_methods
35
+ test_methods = @ripper.all_test_method_names(TestClassWithoutTestMethods)
36
+ assert_equal [], test_methods
37
+ end
38
+
39
+ def test_should_replace_method_implementation
40
+ @ripper.replace_method(DummyClass, "def dummy\n 'replaced' \n end")
41
+ assert_equal 'replaced', DummyClass.new.dummy
42
+ end
43
+ end
44
+
@@ -0,0 +1,20 @@
1
+ require_relative '../test_helper'
2
+
3
+ class Picard::ExpectBlockTest < Test::Unit::TestCase
4
+
5
+ def test_should_call_passed_block
6
+ res = nil
7
+ Picard::ExpectBlock.invoke do
8
+ res = true
9
+ end
10
+ assert res
11
+ end
12
+
13
+ def test_should_use_passed_variables_in_block
14
+ res = nil
15
+ Picard::ExpectBlock.invoke(true) do |x|
16
+ res = x
17
+ end
18
+ assert res
19
+ end
20
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../test_helper'
2
+
3
+ class Picard::MethodRipperTest < Test::Unit::TestCase
4
+ class TestClass
5
+ def test_method
6
+ given
7
+ something
8
+ expect
9
+ 1 == 1
10
+ 2 == 2
11
+ end
12
+
13
+ def regular_method
14
+ 1 == 1
15
+ 2 == 2
16
+ end
17
+ end
18
+
19
+ def setup
20
+ @ripper = Picard::MethodRipper.new
21
+ end
22
+
23
+ def test_should_wrap_all_assertions_after_expect_method_call
24
+ method = TestClass.instance_method(:test_method)
25
+ new_method_str = @ripper.wrap_all_assertions(method)
26
+ assert_equal "def test_method\ngiven\nsomething\nexpect\nassert((1 == 1))\nassert((2 == 2))\nend", new_method_str
27
+ end
28
+
29
+ def test_should_return_existing_implementation_if_there_was_no_expect_method_call
30
+ method = TestClass.instance_method(:regular_method)
31
+ new_method_str = @ripper.wrap_all_assertions(method)
32
+ assert_equal "def regular_method\n(1 == 1)\n(2 == 2)\nend", new_method_str
33
+ end
34
+ end
@@ -0,0 +1,114 @@
1
+ require_relative '../test_helper'
2
+
3
+ class Picard::PreprocessorTest < Test::Unit::TestCase
4
+ include RR::Adapters::RRMethods
5
+
6
+ class BaseTestClass
7
+ attr_reader :assert_args
8
+
9
+ def initialize
10
+ @assert_args = []
11
+ end
12
+
13
+ def given
14
+ end
15
+
16
+ def expect
17
+ end
18
+
19
+ def where
20
+ end
21
+
22
+ def assert arg
23
+ @assert_args << arg
24
+ end
25
+ end
26
+
27
+ # We need to use a class per test for test isolation
28
+ class TestClass < BaseTestClass
29
+ def test_method
30
+ expect
31
+ 1 == 2
32
+ end
33
+ end
34
+
35
+ def test_should_wrap_all_assertions_after_expect_in_all_test_methods
36
+ tr = Picard::Preprocessor.new
37
+ tr.preprocess_class(TestClass)
38
+
39
+ tc = TestClass.new
40
+ tc.test_method
41
+ assert_equal [false], tc.assert_args
42
+ end
43
+
44
+
45
+ class TestClass2 < BaseTestClass
46
+ def test_method
47
+ expect
48
+ 1 == 2
49
+ end
50
+ end
51
+
52
+ def test_should_wrap_all_assertions_in_specified_method
53
+ tr = Picard::Preprocessor.new
54
+ tr.preprocess_method(TestClass2, :test_method)
55
+
56
+ tc = TestClass2.new
57
+ tc.test_method
58
+ assert_equal [false], tc.assert_args
59
+ end
60
+
61
+
62
+ class TestClass3 < BaseTestClass
63
+ def test_method
64
+ expect
65
+ 1 == 2
66
+ end
67
+ end
68
+
69
+ def test_should_not_preprocess_the_same_method_twice
70
+ tr = Picard::Preprocessor.new
71
+ tr.preprocess_method(TestClass3, :test_method)
72
+ tr.preprocess_method(TestClass3, :test_method)
73
+
74
+ tc = TestClass3.new
75
+ tc.test_method
76
+ assert_equal [false], tc.assert_args
77
+ end
78
+
79
+
80
+ class TestClass4 < BaseTestClass
81
+ def regular_method
82
+ 1 == 2
83
+ end
84
+ end
85
+
86
+ def test_should_ignore_non_test_methods
87
+ tr = Picard::Preprocessor.new
88
+ tr.preprocess_method(TestClass4, :regular_method)
89
+
90
+ tc = TestClass4.new
91
+ tc.regular_method
92
+ assert_equal [], tc.assert_args
93
+ end
94
+
95
+
96
+ #class TestClass5 < BaseTestClass
97
+ # def test_method
98
+ # expect
99
+ # x == 1
100
+ #
101
+ # where
102
+ # x = 2
103
+ # end
104
+ #end
105
+ #
106
+ #def test_should_use_local_variables_from_where_block
107
+ # tr = Picard::Preprocessor.new ClassRipper.new,
108
+ # tr.preprocess_method(TestClass5, :test_method)
109
+ #
110
+ # tc = TestClass5.new
111
+ # tc.test_method
112
+ # assert_equal [false], tc.assert_args
113
+ #end
114
+ end
@@ -0,0 +1,27 @@
1
+ require_relative '../test_helper'
2
+
3
+ class Picard::TestUnitTest < Test::Unit::TestCase
4
+ class TestUsingPicard
5
+ include Picard::TestUnit
6
+ attr_reader :assert_args
7
+
8
+ def test_method
9
+ given
10
+ x = 1
11
+
12
+ expect
13
+ x == 2
14
+ end
15
+
16
+ def assert arg
17
+ @assert_args ||= []
18
+ @assert_args << arg
19
+ end
20
+ end
21
+
22
+ def test_should_add_assertions_to_all_test_methods
23
+ test = TestUsingPicard.new
24
+ test.test_method
25
+ assert_equal [false], test.assert_args
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ require 'test/unit'
2
+ require 'rr'
3
+
4
+ require_relative '../lib/picard/ast_helper'
5
+ require_relative '../lib/picard/class_ripper'
6
+ require_relative '../lib/picard/preprocessor'
7
+ require_relative '../lib/picard/method_ripper'
8
+ require_relative '../lib/picard/expect_block'
9
+ require_relative '../lib/picard/test_unit'
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: picard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Victor Savkin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-05 00:00:00.000000000 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: live_ast
17
+ requirement: &2168700440 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - =
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2168700440
26
+ - !ruby/object:Gem::Dependency
27
+ name: live_ast_ripper
28
+ requirement: &2168699820 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - =
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *2168699820
37
+ - !ruby/object:Gem::Dependency
38
+ name: rr
39
+ requirement: &2168699280 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *2168699280
48
+ - !ruby/object:Gem::Dependency
49
+ name: picard
50
+ requirement: &2168698520 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - =
54
+ - !ruby/object:Gem::Version
55
+ version: 0.0.1
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *2168698520
59
+ description: Test framework inspired by Spock
60
+ email:
61
+ - vic.savkin@gmail.com
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - Gemfile
68
+ - Gemfile.lock
69
+ - Rakefile
70
+ - lib/picard.rb
71
+ - lib/picard/ast_helper.rb
72
+ - lib/picard/class_ripper.rb
73
+ - lib/picard/expect_block.rb
74
+ - lib/picard/method_ripper.rb
75
+ - lib/picard/preprocessor.rb
76
+ - lib/picard/test_unit.rb
77
+ - lib/picard/version.rb
78
+ - picard.gemspec
79
+ - test/picard/ast_helper_test.rb
80
+ - test/picard/class_ripper_test.rb
81
+ - test/picard/expect_block_test.rb
82
+ - test/picard/method_ripper_test.rb
83
+ - test/picard/preprocessor_test.rb
84
+ - test/picard/test_unit_test.rb
85
+ - test/test_helper.rb
86
+ has_rdoc: true
87
+ homepage: ''
88
+ licenses: []
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project: picard
107
+ rubygems_version: 1.6.2
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: Test framework inspired by Spock
111
+ test_files:
112
+ - test/picard/ast_helper_test.rb
113
+ - test/picard/class_ripper_test.rb
114
+ - test/picard/expect_block_test.rb
115
+ - test/picard/method_ripper_test.rb
116
+ - test/picard/preprocessor_test.rb
117
+ - test/picard/test_unit_test.rb
118
+ - test/test_helper.rb