mountain_berry_fields-magic_comments 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ features/proving_grounds
19
+ .DS_Store
@@ -0,0 +1,5 @@
1
+ SimpleCov.start do
2
+ add_filter '/spec/'
3
+ add_filter '/features/'
4
+ add_filter 'formatter.rb' # this gets acceptance tested, not unit tested
5
+ end
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Josh Cheek
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+
4
+
5
+ task :rspec do
6
+ require 'rspec'
7
+ Dir.glob("spec/**/*_spec.rb").each { |filename| require File.expand_path filename }
8
+ RSpec::Core::Runner.run []
9
+ end
10
+
11
+ require 'cucumber/rake/task'
12
+ default_cucumber_opts = "features --format pretty --tags ~@not-implemented"
13
+ Cucumber::Rake::Task.new(:cucumber) { |t| t.cucumber_opts = default_cucumber_opts + " --tags ~@wip" }
14
+ Cucumber::Rake::Task.new('cucumber:wip') { |t| t.cucumber_opts = default_cucumber_opts + " --tags @wip" }
15
+
16
+ task default: [:rspec, :cucumber]
17
+
18
+
@@ -0,0 +1,7 @@
1
+ # Magic Comments strategy for Mountain Berry Fields
2
+
3
+ As this is an official plugin, it is documented as part of the main [MountainBerryFields](https://github.com/JoshCheek/mountain_berry_fields) code.
4
+
5
+ If you have it installed (`gem install mountain_berry_fields-magic_comments`), then it will be automatically loaded by MountainBerryFields, no further steps are necessary.
6
+ If you are using Bundler, make sure it is in your Gemfile. If using Rubygems, set it as a development dependency
7
+ ([example](https://github.com/JoshCheek/mountain_berry_fields/blob/be751536c8b0f94c84b09167fa83616b94b13b12/mountain_berry_fields.gemspec#L21)).
@@ -0,0 +1,46 @@
1
+ Given 'the file "$filename":' do |filename, body|
2
+ in_proving_grounds do
3
+ ensure_dir File.dirname filename
4
+ File.write filename, interpret_curlies(body)
5
+ end
6
+ end
7
+
8
+ When 'I run "$command"' do |command|
9
+ in_proving_grounds { cmdline command }
10
+ end
11
+
12
+ Then /^it exits with a status of (\d+)$/ do |status|
13
+ last_cmdline.exitstatus.should eq(status.to_i), "Expected #{status}, got #{last_cmdline.exitstatus}. STDERR: #{last_cmdline.stderr}"
14
+ end
15
+
16
+ Then /^it exits with a status of (\d+), and a stderr of:$/ do |status, stderr|
17
+ last_cmdline.exitstatus.should == status.to_i
18
+ last_cmdline.stderr.chomp.should == interpret_curlies(stderr).chomp
19
+ end
20
+
21
+ Then /^it prints nothing to (stdout|stderr)$/ do |descriptor|
22
+ last_cmdline.send(descriptor).should == ''
23
+ end
24
+
25
+ Then 'I see the file "$filename"' do |filename|
26
+ in_proving_grounds { File.exist?(filename).should be_true }
27
+ end
28
+
29
+ Then 'I see the file "$filename":' do |filename, body|
30
+ in_proving_grounds do
31
+ File.exist?(filename).should be_true, "#{filename} doesn't exist"
32
+
33
+ body && strip_trailing_whitespace(File.read(filename)).should ==
34
+ strip_trailing_whitespace(body)
35
+ end
36
+ end
37
+
38
+ Then 'I do not see the file "$filename"' do |filename|
39
+ in_proving_grounds { File.exist?(filename).should be_false }
40
+ end
41
+
42
+ And 'I pry' do
43
+ require 'pry'
44
+ binding.pry
45
+ end
46
+
@@ -0,0 +1,73 @@
1
+ require 'fileutils'
2
+ module ProvingGrounds
3
+ def proving_grounds_dir
4
+ File.expand_path "../../proving_grounds", __FILE__
5
+ end
6
+
7
+ def in_proving_grounds(&block)
8
+ make_proving_grounds
9
+ FileUtils.cd(proving_grounds_dir) { return block.call }
10
+ end
11
+
12
+ def make_proving_grounds
13
+ FileUtils.mkdir_p proving_grounds_dir
14
+ end
15
+
16
+ def remove_proving_grounds
17
+ FileUtils.rm_r proving_grounds_dir
18
+ end
19
+
20
+ def ensure_dir(dirname)
21
+ FileUtils.mkdir_p dirname
22
+ end
23
+ end
24
+
25
+
26
+ module Helpers
27
+ def interpret_curlies(string)
28
+ string.gsub /{{.*?}}/ do |code|
29
+ code.sub! /^{{/, ''
30
+ code.sub! /}}$/, ''
31
+ eval code
32
+ end
33
+ end
34
+
35
+ def strip_trailing_whitespace(text)
36
+ text.gsub /\s+$/, ''
37
+ end
38
+ end
39
+
40
+ require 'open3'
41
+ class CommandLine
42
+ module CukeHelpers
43
+ def cmdline(command, options={})
44
+ @last_cmdline = CommandLine.new(command, options)
45
+ @last_cmdline.execute
46
+ @last_cmdline
47
+ end
48
+
49
+ def last_cmdline
50
+ @last_cmdline
51
+ end
52
+ end
53
+
54
+ attr_reader :command, :options, :stderr, :stdout
55
+
56
+ def initialize(command, options={})
57
+ @command, @options = command, options
58
+ end
59
+
60
+ def execute
61
+ @stdout, @stderr, @status = Open3.capture3(command, @options)
62
+ end
63
+
64
+ def exitstatus
65
+ @status.exitstatus
66
+ end
67
+ end
68
+
69
+ ENV['RUBYLIB'] = File.expand_path "../../../lib", __FILE__
70
+ World ProvingGrounds
71
+ World CommandLine::CukeHelpers
72
+ World Helpers
73
+ After { remove_proving_grounds }
@@ -0,0 +1,69 @@
1
+ Feature: Testing with :magic_comments
2
+
3
+ Scenario: Passing magic comments
4
+ Given the file "Readme.mountain_berry_fields.md":
5
+ """
6
+ # Whatever
7
+
8
+ <% test 'basic addition', with: :magic_comments do %>
9
+ 1 + 1 # => 2
10
+ <% end %>
11
+
12
+ More shit here
13
+ """
14
+ When I run "mountain_berry_fields Readme.mountain_berry_fields.md"
15
+ Then it exits with a status of 0
16
+ And I see the file "Readme.md":
17
+ """
18
+ # Whatever
19
+
20
+ 1 + 1 # => 2
21
+
22
+ More shit here
23
+ """
24
+
25
+
26
+ Scenario: Failing magic comments
27
+ Given the file "Readme.mountain_berry_fields.md":
28
+ """
29
+ # Whatever
30
+
31
+ <% test 'basic addition', with: :magic_comments do %>
32
+ 1 + 2 # => 12
33
+ <% end %>
34
+
35
+ More shit here
36
+ """
37
+ When I run "mountain_berry_fields Readme.mountain_berry_fields.md"
38
+ Then it exits with a status of 1, and a stderr of:
39
+ """
40
+ FAILURE: basic addition
41
+ Expected: 1 + 2 # => 12
42
+ Actual: 1 + 2 # => 3
43
+ """
44
+ And I do not see the file "Readme.md"
45
+
46
+
47
+ Scenario: Invalid example
48
+ Given the file "Readme.mountain_berry_fields.md":
49
+ """
50
+ # Whatever
51
+
52
+ <% test 'basic addition', with: :magic_comments do %>
53
+ } + { # => 12
54
+ <% end %>
55
+
56
+ More shit here
57
+ """
58
+ When I run "mountain_berry_fields Readme.mountain_berry_fields.md"
59
+ Then it exits with a status of 1, and a stderr of:
60
+ """
61
+ FAILURE: basic addition
62
+ -:1: syntax error, unexpected '}'
63
+ } + { # => 12
64
+ ^
65
+
66
+ original file:
67
+ } + { # => 12
68
+ """
69
+ And I do not see the file "Readme.md"
@@ -0,0 +1,99 @@
1
+ require 'rcodetools/xmpfilter'
2
+ require 'mountain_berry_fields'
3
+
4
+ class MountainBerryFields
5
+ class Test
6
+
7
+ # test strategy for magic comments:
8
+ #
9
+ # 1 + 2 # => 3
10
+ #
11
+ # Like that, but if the output isn't 3, then this will fail your test
12
+ class MagicComments
13
+
14
+ Strategy.register :magic_comments, self
15
+ include Strategy
16
+
17
+ Deject self
18
+ dependency(:syntax_checker_class) { RubySyntaxChecker }
19
+
20
+ def syntax_checker
21
+ @syntax_checker ||= syntax_checker_class.new code_to_test
22
+ end
23
+
24
+ def result
25
+ @result ||= Rcodetools::XMPFilter.run(
26
+ code_to_test,
27
+ :interpreter => "ruby",
28
+ :options => [],
29
+ :min_codeline_size => 50,
30
+ :libs => [],
31
+ :evals => [],
32
+ :include_paths => [],
33
+ :dump => nil,
34
+ :wd => nil,
35
+ :warnings => false,
36
+ :use_parentheses => true,
37
+ :column => nil,
38
+ :output_stdout => true,
39
+ :test_script => nil,
40
+ :test_method => nil,
41
+ :detect_rct_fork => false,
42
+ :use_rbtest => false,
43
+ :detect_rbtest => false,
44
+ :execute_ruby_tmpfile => false
45
+ ).join
46
+ end
47
+
48
+ def syntax_error_message
49
+ return if syntax_checker.valid?
50
+ syntax_checker.invalid_message
51
+ end
52
+
53
+ def pass?
54
+ each_line_pair do |expected_line, actual_line|
55
+ return false unless normalize(expected_line) == normalize(actual_line)
56
+ end
57
+ true
58
+ end
59
+
60
+ def failure_message
61
+ syntax_error_message ||
62
+ each_line_pair do |expected_line, actual_line|
63
+ next if lines_match? expected_line, actual_line
64
+ return "Output had extra line: #{actual_line}\n" unless expected_line
65
+ return "Input had extra line: #{expected_line}\n" unless actual_line
66
+ return "Expected: #{expected_line.gsub /^\s+/, ''}\nActual: #{actual_line.lstrip.gsub /^\s+/, ''}\n" if expected_line != actual_line
67
+ end
68
+ end
69
+
70
+ def lines_match?(line1, line2)
71
+ normalize(line1) == normalize(line2)
72
+ end
73
+
74
+ def normalize(line)
75
+ return unless line
76
+ line.gsub!(/(#<\w+?):(0x[0-9a-f]+)/, '\1') # replace anonymous instances
77
+ line.gsub!(/#<(#<Class>):(0x[0-9a-f]+)>/, '#<\1>') # replace anonymous instances of anonymous classes end
78
+ line
79
+ end
80
+
81
+ def each_line_pair
82
+ result_lines = lines result
83
+ code_to_test_lines = lines code_to_test
84
+
85
+ while result_lines.any? || code_to_test_lines.any?
86
+ yield chomp_or_nil(code_to_test_lines.shift), chomp_or_nil(result_lines.shift)
87
+ end
88
+ end
89
+
90
+ def lines string
91
+ string.lines.to_a
92
+ end
93
+
94
+ def chomp_or_nil value
95
+ value && value.chomp
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Josh Cheek"]
5
+ gem.email = ["josh.cheek@gmail.com"]
6
+ gem.description = %q{Test code samples embedded in files like readmes}
7
+ gem.summary = %q{Test code samples embedded in files like readmes}
8
+ gem.homepage = "https://github.com/JoshCheek/mountain_berry_fields-magic_comments"
9
+
10
+ gem.files = `git ls-files`.split($\)
11
+ gem.executables = gem.files.grep(%r{^bin/}).map { |file| File.basename file }
12
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
+ gem.name = "mountain_berry_fields-magic_comments"
14
+ gem.require_paths = ["lib"]
15
+ gem.version = '1.0.0'
16
+
17
+ gem.add_runtime_dependency 'rcodetools', '~> 0.8.5.0'
18
+ gem.add_runtime_dependency 'deject', '~> 0.2.2'
19
+
20
+ gem.add_development_dependency 'mountain_berry_fields', '~> 1.0.0'
21
+ gem.add_development_dependency 'surrogate', '~> 0.5.1'
22
+ gem.add_development_dependency 'rspec', '~> 2.10.0'
23
+ gem.add_development_dependency 'cucumber', '~> 1.2.0'
24
+ gem.add_development_dependency 'rake'
25
+ gem.add_development_dependency 'pry'
26
+ end
@@ -0,0 +1,19 @@
1
+ require 'surrogate/rspec'
2
+ require 'mountain_berry_fields'
3
+ require 'mountain_berry_fields/test/magic_comments.rb'
4
+
5
+
6
+ RSpec::Matchers.define :pass do
7
+ match { |matcher| matcher.pass? }
8
+ end
9
+
10
+ module Mock
11
+ class SyntaxChecker
12
+ Surrogate.endow self
13
+ define(:initialize) { |syntax| }
14
+ define(:valid?) { true }
15
+ define(:invalid_message) { "shit ain't valid" }
16
+ end
17
+ end
18
+
19
+ MountainBerryFields::Test::MagicComments.override(:syntax_checker_class) { Mock::SyntaxChecker }
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ test_class = MountainBerryFields::Test
4
+
5
+ describe test_class::MagicComments do
6
+ it 'is registered it the strategy list under :magic_comments' do
7
+ test_class::Strategy.for(:magic_comments).should == described_class
8
+ end
9
+
10
+ specify '#pass? returns true if the output is the same as the input' do
11
+ described_class.new('1 + 1 # => 2').should pass
12
+ described_class.new('1 + 2 # => 2').should_not pass
13
+ described_class.new("a=1\nb=2\na+b # => 3").should pass
14
+ end
15
+
16
+ it 'ignores warnings in the output' do
17
+ described_class.new("1").should pass
18
+ end
19
+
20
+ it 'ignores differences that look like object inspections' do
21
+ described_class.new("Object.new # => #<Object:0x007f9ef108b578>").should pass
22
+ described_class.new("Object.new # => #<NotObject:0x007f9ef108b578>").should_not pass
23
+ described_class.new("Class.new.new # => #<#<Class:0x007fc6d388b548>:0x007fc6d388b4f8>").should pass
24
+ end
25
+
26
+ describe '#failure_message' do
27
+ it "provides Ruby's syntax message if the syntax is not valid" do
28
+ magic_comments = described_class.new '}'
29
+ syntax_checker = magic_comments.syntax_checker
30
+ syntax_checker.was initialized_with '}'
31
+ syntax_checker.will_have_valid? false # should surrogate provide: will_be_valid? ?
32
+ syntax_checker.will_have_invalid_message "} ain't no kinda valid"
33
+ magic_comments.should_not pass
34
+ magic_comments.failure_message.should == "} ain't no kinda valid"
35
+ end
36
+
37
+ it 'identifies the first output line that differs from the input' do
38
+ magic_comments = described_class.new <<-CODE.gsub(/^\s*/, '')
39
+ 1 + 2 # => 3
40
+ "a" + "b" # => "ba"
41
+ 5 + 6 # => 345678
42
+ CODE
43
+ magic_comments.pass?
44
+ magic_comments.failure_message.should == %Q(Expected: "a" + "b" # => "ba"\n) +
45
+ %Q(Actual: "a" + "b" # => "ab"\n)
46
+ end
47
+
48
+ it 'strips leading white spaces off of failures' do
49
+ magic_comments = described_class.new(" \t\t 1 + 1 # => 4")
50
+ magic_comments.pass?
51
+ magic_comments.failure_message.should == %Q(Expected: 1 + 1 # => 4\n) +
52
+ %Q(Actual: 1 + 1 # => 2\n)
53
+ end
54
+
55
+ it 'identifies missing output' do
56
+ magic_comments = described_class.new("puts 1\nputs 2\n")
57
+ magic_comments.pass?
58
+ magic_comments.failure_message.should == "Output had extra line: # >> 1\n"
59
+ end
60
+
61
+ it 'identifies missing input' do
62
+ magic_comments = described_class.new("puts 1\n# >> 1\n# >> 2\n")
63
+ magic_comments.pass?
64
+ magic_comments.failure_message.should == "Input had extra line: # >> 2\n"
65
+ end
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mountain_berry_fields-magic_comments
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh Cheek
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rcodetools
16
+ requirement: &70125641193040 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.5.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70125641193040
25
+ - !ruby/object:Gem::Dependency
26
+ name: deject
27
+ requirement: &70125641192560 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.2.2
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70125641192560
36
+ - !ruby/object:Gem::Dependency
37
+ name: mountain_berry_fields
38
+ requirement: &70125641192080 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70125641192080
47
+ - !ruby/object:Gem::Dependency
48
+ name: surrogate
49
+ requirement: &70125641191620 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.5.1
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70125641191620
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: &70125641191160 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 2.10.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70125641191160
69
+ - !ruby/object:Gem::Dependency
70
+ name: cucumber
71
+ requirement: &70125641190700 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 1.2.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70125641190700
80
+ - !ruby/object:Gem::Dependency
81
+ name: rake
82
+ requirement: &70125641190320 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70125641190320
91
+ - !ruby/object:Gem::Dependency
92
+ name: pry
93
+ requirement: &70125641189860 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70125641189860
102
+ description: Test code samples embedded in files like readmes
103
+ email:
104
+ - josh.cheek@gmail.com
105
+ executables: []
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - .gitignore
110
+ - .simplecov
111
+ - Gemfile
112
+ - LICENSE
113
+ - Rakefile
114
+ - Readme.md
115
+ - features/step_definitions/steps.rb
116
+ - features/support/env.rb
117
+ - features/test_with_magic_comments.feature
118
+ - lib/mountain_berry_fields/test/magic_comments.rb
119
+ - mountain_berry_fields-magic_comments.gemspec
120
+ - spec/spec_helper.rb
121
+ - spec/test/magic_comments_spec.rb
122
+ homepage: https://github.com/JoshCheek/mountain_berry_fields-magic_comments
123
+ licenses: []
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ! '>='
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 1.8.11
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: Test code samples embedded in files like readmes
146
+ test_files:
147
+ - features/step_definitions/steps.rb
148
+ - features/support/env.rb
149
+ - features/test_with_magic_comments.feature
150
+ - spec/spec_helper.rb
151
+ - spec/test/magic_comments_spec.rb
152
+ has_rdoc: