Exspec 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ require_relative "../../exspec"
2
+ require_relative "irb_context_manager"
3
+ require_relative "irb_patch"
4
+
5
+ module Exspec
6
+ class IrbExspec < Exspec
7
+ def initialize(context, workspace)
8
+ @irb_context = context
9
+ @irb_workspace = workspace
10
+ @irb_context_manager = IrbContextManager.new self
11
+ super :context_manager => @irb_context_manager
12
+ end
13
+
14
+ attr_reader :irb_context, :irb_workspace
15
+
16
+ def irb_execute(line, &eval)
17
+ @irb_context_manager.define_eval &eval if block_given?
18
+ execute line
19
+ end
20
+
21
+ def expect_inspect(expect=nil, comment=nil)
22
+ if expect.nil? && @irb_context.io.is_a?(IRB::ReadlineInputMethod)
23
+ puts "What inspect value do you expect (only the static content, press up to get the last one):"
24
+ history = @irb_context.io.history
25
+ @irb_context.io.history = [inspect_last_value]
26
+ @irb_context.io.prompt = "fuzzy expectation: "
27
+ input = @irb_context.io.gets.strip
28
+ @irb_context.io.history = history
29
+ expect = input.empty? ? expect : input
30
+ end
31
+ super expect, comment
32
+ end
33
+
34
+ def self.start_irb
35
+ require_relative "irb_patch"
36
+ started = Extension.apply :start_irb, nil, true
37
+ IRB.start unless started
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,51 @@
1
+ require "irb"
2
+ require_relative "irb_exspec"
3
+
4
+ require 'io/console'
5
+
6
+ module IRB
7
+ class Context
8
+ alias_method :_initialize, :initialize
9
+ alias_method :_evaluate, :evaluate
10
+
11
+ def initialize(irb, workspace = nil, input_method = nil, output_method = nil)
12
+ _initialize(irb, workspace, input_method, output_method)
13
+ @exspec = Exspec::IrbExspec.new self, @workspace
14
+ end
15
+
16
+ def evaluate(line, line_no)
17
+ @exspec.irb_execute line do |instruction|
18
+ _evaluate instruction, line_no
19
+ end
20
+ end
21
+
22
+ def inspect
23
+ "#<#{self.class.name}>"
24
+ end
25
+ end
26
+
27
+ class ReadlineInputMethod
28
+ def history
29
+ HISTORY.collect.to_a
30
+ end
31
+
32
+ def history=(value)
33
+ HISTORY.clear
34
+ HISTORY.push(*value)
35
+ end
36
+ end
37
+ end
38
+
39
+ class RubyLex
40
+ alias_method :_lex, :lex
41
+
42
+ def lex
43
+ if peek_equal?(Exspec::COMMAND_PREFIX)
44
+ identify_comment
45
+ ungetc
46
+ token
47
+ return get_readed
48
+ end
49
+ _lex
50
+ end
51
+ end
@@ -0,0 +1,71 @@
1
+ module Exspec
2
+ class Logger
3
+ def initialize
4
+ @log = []
5
+ @enabled = true
6
+ @erased_last = false
7
+ end
8
+
9
+ def enabled?
10
+ @enabled
11
+ end
12
+
13
+ def enabled=(value)
14
+ @enabled = value
15
+ end
16
+
17
+ def entries
18
+ @log
19
+ end
20
+
21
+ def instructions
22
+ @log.map{ |entry| entry[:instruction] }
23
+ end
24
+
25
+ def clear
26
+ @log.clear
27
+ end
28
+
29
+ def log(instruction, value)
30
+ if @enabled
31
+ instruction.gsub! /\n+/, ";\n"
32
+ @log << {:instruction => instruction.strip, :value => value}
33
+ @erased_last = false
34
+ end
35
+ value
36
+ end
37
+
38
+ def erase_last_instruction
39
+ erasing = !@erased_last
40
+ if erasing
41
+ @log.pop
42
+ @erased_last = true
43
+ end
44
+ erasing
45
+ end
46
+
47
+ def last_instruction
48
+ return nil if @log.empty?
49
+ @log.last[:instruction]
50
+ end
51
+
52
+ def last_value
53
+ return nil if @log.empty?
54
+ @log.last[:value]
55
+ end
56
+
57
+ def last_entry
58
+ return nil if @log.empty?
59
+ @log.last
60
+ end
61
+
62
+ def without_logging
63
+ enabled = enabled?
64
+ self.enabled = false
65
+ val = yield
66
+ ensure
67
+ self.enabled = enabled
68
+ val
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,93 @@
1
+ module Exspec
2
+ class RegressionTestReporter < Reporter
3
+ SpecFailedError = Class.new(StandardError)
4
+
5
+ def initialize
6
+ @indent = 0
7
+ @specs = []
8
+ @failed = []
9
+ super
10
+ end
11
+
12
+ alias_method :_puts, :puts
13
+ alias_method :_print, :print
14
+
15
+ attr_reader :specs, :failed
16
+
17
+ def indent
18
+ " " * (@indent * 4)
19
+ end
20
+
21
+ def puts(text); end
22
+ def print(text); end
23
+
24
+ def puts_indented(text)
25
+ _puts "" if !@on_new_line
26
+ _puts indent + text
27
+ @on_new_line = true
28
+ $stdout.flush
29
+ end
30
+
31
+ def print_indented(text)
32
+ _print indent if @on_new_line
33
+ _print text
34
+ @on_new_line = false
35
+ $stdout.flush
36
+ end
37
+
38
+ def start_stack(spec)
39
+ puts_indented "Start spec stack #{spec.full_name}"
40
+ @indent += 1
41
+ end
42
+
43
+ def finish_stack(spec)
44
+ @indent -= 1
45
+ puts_indented "Finished spec stack #{spec.full_name}"
46
+ puts_indented "---------------------------------" if @indent == 0
47
+ end
48
+
49
+ def start_spec(spec)
50
+ @spec = spec
51
+ @specs << spec unless @specs.include?(spec)
52
+ puts_indented "Start test #{spec.full_name}"
53
+ @indent += 1
54
+ end
55
+
56
+ def finish_spec(spec)
57
+ @indent -= 1
58
+ puts_indented "Finished test #{spec.full_name}"
59
+ end
60
+
61
+ def execute_instruction(instruction, index, line)
62
+ @line = line
63
+ @instruction = instruction
64
+ print_indented "."
65
+ end
66
+
67
+ def skip_signal
68
+ raise SkipSignal
69
+ end
70
+
71
+ def spec_failed(message)
72
+ failed << @spec unless failed.include?(@spec)
73
+ puts_indented "==> #{message}"
74
+ _print "XXXX"
75
+ puts_indented "(line: #{@line}, instruction: \"#{@instruction}\")"
76
+ raise SpecFailedError.new message
77
+ end
78
+
79
+ def spec_succeeded(message)
80
+ puts_indented "==> #{message}"
81
+ end
82
+
83
+ def exception(exception)
84
+ if exception.is_a?(SpecFailedError)
85
+ raise exception
86
+ end
87
+ end
88
+
89
+ def show_comment(text)
90
+ puts_indented("#" + text)
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,29 @@
1
+ module Exspec
2
+ class Reporter
3
+ def start_stack(spec); end
4
+ def finish_stack(spec); end
5
+ def start_spec(spec); end
6
+ def finish_spec(spec); end
7
+ def execute_instruction(instruction, index, line); end
8
+ def executed_instruction(instruction, index, line); end
9
+ def exception(exception); end
10
+ def skip_signal(breaking); end
11
+ def show_comment(text); end
12
+
13
+ def puts(text)
14
+ Kernel.puts text
15
+ end
16
+
17
+ def print(text)
18
+ Kernel.print text
19
+ end
20
+
21
+ def spec_failed(message)
22
+ puts message
23
+ end
24
+
25
+ def spec_succeeded(message)
26
+ puts message
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,107 @@
1
+ require "active_support/core_ext"
2
+
3
+ class Spec
4
+ def self.name(description)
5
+ name = File.basename(description, File.extname(description))
6
+ name = name.split(".").last.strip
7
+ name.gsub(/ +/, "_").underscore
8
+ end
9
+
10
+ def initialize(spec_manager, name, file, parent=nil)
11
+ @spec_manager = spec_manager
12
+ @name = name
13
+ @file = file
14
+ @parent = parent
15
+ end
16
+
17
+ attr_reader :name, :file
18
+
19
+ def full_name
20
+ ".#{stack.map(&:name).join "."}"
21
+ end
22
+
23
+ def description
24
+ name.gsub("_", " ").capitalize + "."
25
+ end
26
+
27
+ def full_description
28
+ stack.map(&:description).join " "
29
+ end
30
+
31
+ def parent
32
+ @parent || @spec_manager.parent(self)
33
+ end
34
+
35
+ def exist?
36
+ File.file? file
37
+ end
38
+
39
+ def for_instructions(&block)
40
+ content = File.read(file)
41
+ buffer = []
42
+ index = 0
43
+ content.each_line.with_index do |line, line_index|
44
+ line.strip!
45
+ if line.end_with? ";"
46
+ buffer << line.chop
47
+ else
48
+ buffer << line
49
+ block.call buffer.join("\n"), index, (line_index + 1)
50
+ buffer.clear
51
+ index += 1
52
+ end
53
+ end
54
+ end
55
+
56
+ def stack
57
+ return @stack if @stack
58
+ reverse_stack = []
59
+ reverse_stack << self
60
+ spec = self
61
+ while spec = spec.parent
62
+ reverse_stack << spec
63
+ end
64
+ @stack = reverse_stack.reverse
65
+ end
66
+
67
+ def directory
68
+ file.chomp(File.extname(file))
69
+ end
70
+
71
+ def load
72
+ @spec_manager.exspec.load self
73
+ end
74
+
75
+ def run
76
+ @spec_manager.exspec.run self
77
+ end
78
+
79
+ def run
80
+ @spec_manager.exspec.run_stack self
81
+ end
82
+
83
+ def include
84
+ @spec_manager.exspec.include self
85
+ end
86
+
87
+ def children
88
+ @spec_manager.specs self
89
+ end
90
+
91
+ def hash
92
+ file.hash
93
+ end
94
+
95
+ def ==(spec)
96
+ return false if !spec.is_a?(self.class)
97
+ file.eql? spec.file
98
+ end
99
+
100
+ def eql?(spec)
101
+ self == spec
102
+ end
103
+
104
+ def inspect
105
+ "#<Spec:#{full_name}>"
106
+ end
107
+ end
@@ -0,0 +1,93 @@
1
+ require "fileutils"
2
+ require_relative "spec"
3
+
4
+ module Exspec
5
+ class SpecManager
6
+ def initialize(exspec)
7
+ @exspec = exspec
8
+ @current_spec = nil
9
+ end
10
+
11
+ attr_reader :exspec
12
+ attr_accessor :current_spec
13
+
14
+ def save(logger, description)
15
+ spec = create_spec description
16
+ file = spec.file
17
+ FileUtils.mkdir_p(File.dirname(file))
18
+ File.open(file, "w") do |f|
19
+ f.write(logger.instructions.join "\n")
20
+ end
21
+ @current_spec = spec
22
+ end
23
+
24
+ def spec(description)
25
+ return description if description.kind_of?(Spec) || description.nil?
26
+
27
+ description = description.strip
28
+ parent = description.start_with?(SPEC_SEPARATOR) ? nil : current_spec
29
+ parent_dir = parent.nil? ? TEST_DIR : parent.directory
30
+ file = File.expand_path(description, parent_dir)
31
+ return create_spec file if File.file?(file)
32
+
33
+ current = parent
34
+ description.split(SPEC_SEPARATOR).each do |spec|
35
+ spec.strip!
36
+ next if spec.empty?
37
+ current = create_spec spec, current
38
+ end
39
+ current
40
+ end
41
+
42
+ def parent(description)
43
+ spec = spec(description)
44
+ parent_dir = File.dirname(spec.file)
45
+ parent_file = parent_dir + SPEC_EXTENSION
46
+ return nil if parent_dir == TEST_DIR || !File.exist?(parent_file)
47
+ parent_name = Spec.name(parent_file)
48
+ create_spec parent_name, nil, parent_file
49
+ end
50
+
51
+ def specs(parent=current_spec, recursive=false)
52
+ parent = "" if parent.nil?
53
+ if parent.is_a?(String)
54
+ parent = parent.strip
55
+ relative_directory = current_spec.nil? ? TEST_DIR : current_spec.directory
56
+ parent_directory = File.expand_path(parent, relative_directory)
57
+ return find_specs(parent_directory, recursive) if File.directory?(parent_directory)
58
+ end
59
+ parent = spec(parent)
60
+ return [] if parent.nil? || !parent.exist?
61
+ find_specs(parent.directory, recursive)
62
+ end
63
+
64
+ private
65
+
66
+ def file(name, parent)
67
+ directory = parent.nil? ? TEST_DIR : parent.file.chomp(SPEC_EXTENSION)
68
+ File.join(directory, name + SPEC_EXTENSION)
69
+ end
70
+
71
+ def create_spec(description, parent=current_spec, file=nil)
72
+ name = Spec.name description
73
+ parent = (parent.nil? || !parent.exist?) ? nil : parent
74
+ file = File.file?(description) ? description : file(name, parent) if file.nil?
75
+ Spec.new self, name, file, parent
76
+ end
77
+
78
+ def find_specs(directory, recursively=false)
79
+ specs = []
80
+ return specs unless File.directory? directory
81
+ Dir.entries(directory).sort.each do |file|
82
+ next if file.gsub(".", "").empty?
83
+ file = File.expand_path(file, directory)
84
+ if File.directory? file
85
+ specs.push(*find_specs(file, recursively)) if recursively
86
+ elsif file.end_with? SPEC_EXTENSION
87
+ specs << create_spec(file)
88
+ end
89
+ end
90
+ specs
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,55 @@
1
+ module Exspec
2
+ class SpecRunner
3
+ def initialize(exspec)
4
+ @exspec = exspec
5
+ end
6
+
7
+ delegate :reporter, :to => :@exspec
8
+
9
+ attr_accessor :break_on_skip_signal
10
+
11
+ def run(specs)
12
+ return run_specs specs if specs.is_a? Enumerable
13
+ spec = @exspec.spec(specs)
14
+ val = nil
15
+ reporter.start_spec spec
16
+ spec.for_instructions do |instruction, index, line|
17
+ reporter.execute_instruction instruction, index, line
18
+ begin
19
+ val = @exspec.execute instruction
20
+ rescue SkipSignal
21
+ reporter.skip_signal break_on_skip_signal
22
+ break if break_on_skip_signal
23
+ rescue Exception => e
24
+ reporter.exception e
25
+ ensure
26
+ reporter.executed_instruction instruction, index, line
27
+ end
28
+ end
29
+ val
30
+ ensure
31
+ reporter.finish_spec spec
32
+ end
33
+
34
+ def run_stack(spec)
35
+ spec = @exspec.spec(spec)
36
+ reporter.start_stack spec
37
+ spec.stack.each do |spec|
38
+ begin
39
+ run spec
40
+ rescue
41
+ break
42
+ end
43
+ end
44
+ ensure
45
+ reporter.finish_stack spec
46
+ end
47
+
48
+ def run_specs(specs)
49
+ specs.each do |spec|
50
+ @exspec.reset
51
+ run_stack(spec)
52
+ end
53
+ end
54
+ end
55
+ end