Exspec 1.0.1

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,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