lookout 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/README +645 -0
  2. data/Rakefile +9 -0
  3. data/lib/lookout.rb +34 -0
  4. data/lib/lookout/aphonic.rb +40 -0
  5. data/lib/lookout/benchmark.rb +11 -0
  6. data/lib/lookout/diff.rb +10 -0
  7. data/lib/lookout/diff/algorithms.rb +5 -0
  8. data/lib/lookout/diff/algorithms/difflib.rb +38 -0
  9. data/lib/lookout/diff/algorithms/difflib/position.rb +92 -0
  10. data/lib/lookout/diff/algorithms/difflib/position/to.rb +47 -0
  11. data/lib/lookout/diff/formats.rb +7 -0
  12. data/lib/lookout/diff/formats/hash.rb +53 -0
  13. data/lib/lookout/diff/formats/inline.rb +39 -0
  14. data/lib/lookout/diff/formats/unified.rb +57 -0
  15. data/lib/lookout/diff/group.rb +61 -0
  16. data/lib/lookout/diff/groups.rb +34 -0
  17. data/lib/lookout/diff/match.rb +36 -0
  18. data/lib/lookout/diff/operation.rb +33 -0
  19. data/lib/lookout/diff/operations.rb +36 -0
  20. data/lib/lookout/diff/operations/delete.rb +9 -0
  21. data/lib/lookout/diff/operations/equal.rb +27 -0
  22. data/lib/lookout/diff/operations/insert.rb +9 -0
  23. data/lib/lookout/diff/operations/replace.rb +9 -0
  24. data/lib/lookout/diff/range.rb +91 -0
  25. data/lib/lookout/equality.rb +178 -0
  26. data/lib/lookout/expectation.rb +50 -0
  27. data/lib/lookout/expectations.rb +62 -0
  28. data/lib/lookout/expectations/behavior.rb +20 -0
  29. data/lib/lookout/expectations/state.rb +29 -0
  30. data/lib/lookout/mock.rb +18 -0
  31. data/lib/lookout/mock/method.rb +70 -0
  32. data/lib/lookout/mock/method/arguments.rb +33 -0
  33. data/lib/lookout/mock/method/arguments/any.rb +11 -0
  34. data/lib/lookout/mock/method/arguments/anything.rb +11 -0
  35. data/lib/lookout/mock/method/arguments/list.rb +15 -0
  36. data/lib/lookout/mock/method/arguments/none.rb +11 -0
  37. data/lib/lookout/mock/method/arguments/one.rb +11 -0
  38. data/lib/lookout/mock/method/calls.rb +11 -0
  39. data/lib/lookout/mock/method/calls/class.rb +21 -0
  40. data/lib/lookout/mock/method/calls/exactly.rb +28 -0
  41. data/lib/lookout/mock/method/calls/instance.rb +25 -0
  42. data/lib/lookout/mock/method/calls/lower.rb +22 -0
  43. data/lib/lookout/mock/method/calls/upper.rb +22 -0
  44. data/lib/lookout/mock/methods.rb +12 -0
  45. data/lib/lookout/mock/object.rb +12 -0
  46. data/lib/lookout/object.rb +11 -0
  47. data/lib/lookout/output.rb +21 -0
  48. data/lib/lookout/rake/tasks.rb +36 -0
  49. data/lib/lookout/rake/tasks/gem.rb +49 -0
  50. data/lib/lookout/rake/tasks/tags.rb +16 -0
  51. data/lib/lookout/rake/tasks/test.rb +46 -0
  52. data/lib/lookout/rake/tasks/test/loader.rb +19 -0
  53. data/lib/lookout/recorder.rb +45 -0
  54. data/lib/lookout/recorder/not.rb +11 -0
  55. data/lib/lookout/recorder/tape.rb +21 -0
  56. data/lib/lookout/recorders.rb +6 -0
  57. data/lib/lookout/recorders/reception.rb +47 -0
  58. data/lib/lookout/recorders/state.rb +35 -0
  59. data/lib/lookout/result.rb +23 -0
  60. data/lib/lookout/results.rb +46 -0
  61. data/lib/lookout/results/error.rb +18 -0
  62. data/lib/lookout/results/error/exception.rb +36 -0
  63. data/lib/lookout/results/error/exception/backtrace.rb +41 -0
  64. data/lib/lookout/results/failure.rb +16 -0
  65. data/lib/lookout/results/failures.rb +6 -0
  66. data/lib/lookout/results/failures/behavior.rb +4 -0
  67. data/lib/lookout/results/failures/state.rb +4 -0
  68. data/lib/lookout/results/fulfilled.rb +9 -0
  69. data/lib/lookout/runners.rb +5 -0
  70. data/lib/lookout/runners/console.rb +22 -0
  71. data/lib/lookout/stub.rb +16 -0
  72. data/lib/lookout/stub/method.rb +105 -0
  73. data/lib/lookout/stub/methods.rb +18 -0
  74. data/lib/lookout/stub/object.rb +11 -0
  75. data/lib/lookout/ui.rb +7 -0
  76. data/lib/lookout/ui/console.rb +36 -0
  77. data/lib/lookout/ui/silent.rb +12 -0
  78. data/lib/lookout/version.rb +5 -0
  79. data/lib/lookout/xml.rb +17 -0
  80. data/test/unit/examples.rb +169 -0
  81. data/test/unit/lookout.rb +7 -0
  82. data/test/unit/lookout/diff.rb +4 -0
  83. data/test/unit/lookout/diff/algorithms/difflib.rb +56 -0
  84. data/test/unit/lookout/diff/algorithms/difflib/position.rb +92 -0
  85. data/test/unit/lookout/diff/algorithms/difflib/position/to.rb +12 -0
  86. data/test/unit/lookout/diff/formats/inline.rb +17 -0
  87. data/test/unit/lookout/diff/formats/unified.rb +67 -0
  88. data/test/unit/lookout/diff/group.rb +4 -0
  89. data/test/unit/lookout/diff/groups.rb +102 -0
  90. data/test/unit/lookout/diff/match.rb +5 -0
  91. data/test/unit/lookout/diff/operations.rb +22 -0
  92. data/test/unit/lookout/diff/operations/delete.rb +45 -0
  93. data/test/unit/lookout/diff/operations/equal.rb +45 -0
  94. data/test/unit/lookout/diff/operations/insert.rb +45 -0
  95. data/test/unit/lookout/diff/operations/replace.rb +45 -0
  96. data/test/unit/lookout/diff/range.rb +50 -0
  97. data/test/unit/lookout/equality.rb +113 -0
  98. data/test/unit/lookout/expectation.rb +39 -0
  99. data/test/unit/lookout/expectations.rb +58 -0
  100. data/test/unit/lookout/expectations/behavior.rb +35 -0
  101. data/test/unit/lookout/expectations/state.rb +29 -0
  102. data/test/unit/lookout/mock.rb +4 -0
  103. data/test/unit/lookout/mock/method.rb +143 -0
  104. data/test/unit/lookout/mock/method/arguments.rb +57 -0
  105. data/test/unit/lookout/mock/method/arguments/any.rb +11 -0
  106. data/test/unit/lookout/recorder.rb +11 -0
  107. data/test/unit/lookout/results.rb +30 -0
  108. data/test/unit/lookout/results/error.rb +7 -0
  109. data/test/unit/lookout/results/failures/behavior.rb +7 -0
  110. data/test/unit/lookout/results/failures/state.rb +7 -0
  111. data/test/unit/lookout/results/fulfilled.rb +7 -0
  112. data/test/unit/lookout/runners/console.rb +4 -0
  113. data/test/unit/lookout/stub.rb +4 -0
  114. data/test/unit/lookout/stub/method.rb +48 -0
  115. data/test/unit/lookout/ui/formatters/exception.rb +5 -0
  116. data/test/unit/lookout/ui/formatters/exception/backtrace.rb +11 -0
  117. data/test/unit/lookout/xml.rb +55 -0
  118. metadata +496 -0
@@ -0,0 +1,50 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Lookout::Expectation
4
+ def self.on(expected, file, line, &block)
5
+ (expected.is_a?(Lookout::Recorder) ?
6
+ Lookout::Expectations::Behavior :
7
+ Lookout::Expectations::State).new(expected, file, line, &block)
8
+ end
9
+
10
+ def initialize(expected, file, line, &block)
11
+ @expected, @file, @line, @block = expected, file, line.to_i, block
12
+ end
13
+
14
+ def evaluate
15
+ Lookout::Stub.methods{ |stubs| @stubs = stubs; evaluate_with_stubs }.tap{ @stubs = nil }
16
+ end
17
+
18
+ def stub(*args)
19
+ raise ArgumentError,
20
+ 'wrong number of arguments (%d for 1)' % args.length unless args.count < 2
21
+ return Lookout::Stub::Object.new if args.length < 1
22
+ case args[0]
23
+ when Hash
24
+ Lookout::Stub::Object.new.tap{ |stub|
25
+ args[0].each do |name, value|
26
+ @stubs.define(stub, name){ value }
27
+ end
28
+ }
29
+ else
30
+ Method.new(@stubs, args[0])
31
+ end
32
+ end
33
+
34
+ attr_reader :file, :line
35
+
36
+ private
37
+
38
+ class Method < Lookout::Aphonic
39
+ undef extend
40
+ undef is_a?
41
+
42
+ def initialize(stubs, object)
43
+ @stubs, @object = stubs, object
44
+ end
45
+
46
+ def method_missing(method, &body)
47
+ @stubs.define(@object, method, &body)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,62 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Expectations
4
+ autoload :Behavior, 'lookout/expectations/behavior'
5
+ autoload :State, 'lookout/expectations/state'
6
+
7
+ include Enumerable
8
+
9
+ def initialize
10
+ @expectations = []
11
+ end
12
+
13
+ def mock
14
+ Lookout::Mock::Object.new
15
+ end
16
+
17
+ def arg
18
+ Lookout::Mock::Method::Arguments::Anything.new
19
+ end
20
+
21
+ def without_arguments
22
+ Lookout::Mock::Method::Arguments::None.new
23
+ end
24
+
25
+ def stub
26
+ Lookout::Stub::Object.new
27
+ end
28
+
29
+ def output(string)
30
+ Lookout::Output.new(string)
31
+ end
32
+
33
+ def xml(string)
34
+ Lookout::XML.new(string)
35
+ end
36
+
37
+ def expect(expected, &block)
38
+ file, line = /\A(.*):(\d+)(?::in .*)?\z/.match(caller.first)[1..2]
39
+ @expectations << Lookout::Expectation.on(expected, file, line, &block)
40
+ expected
41
+ end
42
+
43
+ def evaluate(ui = Lookout::UI::Console.new, results = Lookout::Results.new)
44
+ ui.start
45
+ ui.summarize results, Lookout::Benchmark.time{
46
+ each(ENV['LINE'] ? ENV['LINE'].to_i : nil) do |expectation|
47
+ results << expectation.evaluate.tap{ |result| ui.report result }
48
+ end
49
+ }
50
+ results
51
+ end
52
+
53
+ def each(line = nil)
54
+ return enum_for(:each, line) unless block_given?
55
+ (line ?
56
+ Array(@expectations.reverse.find{ |e| e.line <= line }) :
57
+ @expectations).each do |expectation|
58
+ yield expectation
59
+ end
60
+ self
61
+ end
62
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Expectations::Behavior
4
+ include Lookout::Expectation
5
+
6
+ def evaluate_with_stubs
7
+ Lookout::Mock.methods do |mocks|
8
+ @expected.subject! mocks, @stubs
9
+ instance_exec @expected.subject, &@block if @block
10
+ @expected.verify
11
+ end
12
+ Lookout::Results::Fulfilled.new(file, line)
13
+ rescue Lookout::Recorders::State::Error => e
14
+ Lookout::Results::Failures::State.new(file, line, e.message)
15
+ rescue Lookout::Mock::Error => e
16
+ Lookout::Results::Failures::Behavior.new(file, line, e.message)
17
+ rescue Exception => e
18
+ Lookout::Results::Error.new(file, line, nil, e)
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Expectations::State
4
+ include Lookout::Expectation
5
+
6
+ def evaluate_with_stubs
7
+ check(@block ? instance_exec(@expected, &@block) : false)
8
+ rescue Exception => e
9
+ return check(e) if StandardError === @expected and @expected.class == e.class
10
+ return Lookout::Results::Fulfilled.new(file, line) if @expected.eql? e.class
11
+ Lookout::Results::Error.new(file, line,
12
+ if Class === @expected and StandardError >= @expected
13
+ Lookout::Equality.message(@expected, e.class)
14
+ elsif StandardError === @expected
15
+ Lookout::Equality.message(@expected.class, e.class)
16
+ else
17
+ nil
18
+ end,
19
+ e)
20
+ end
21
+
22
+ private
23
+
24
+ def check(actual)
25
+ (@expected == actual or Lookout::Equality.equal? @expected, actual) ?
26
+ Lookout::Results::Fulfilled.new(file, line) :
27
+ Lookout::Results::Failures::State.new(file, line, Lookout::Equality.message(@expected, actual))
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Lookout::Mock
4
+ autoload :Method, 'lookout/mock/method'
5
+ autoload :Methods, 'lookout/mock/methods'
6
+ autoload :Object, 'lookout/mock/object'
7
+
8
+ Error = Class.new(StandardError)
9
+
10
+ class << self
11
+ def methods
12
+ methods = Methods.new
13
+ yield methods
14
+ ensure
15
+ methods.undefine if methods
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,70 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Mock::Method < Lookout::Stub::Method
4
+ autoload :Arguments, 'lookout/mock/method/arguments'
5
+ autoload :Calls, 'lookout/mock/method/calls'
6
+
7
+ def initialize(object, method, *args, &body)
8
+ super object, method, &body
9
+ @args = Arguments.new(*args)
10
+ at_least_once
11
+ end
12
+
13
+ def never
14
+ exactly(0)
15
+ end
16
+
17
+ def at_most_once
18
+ at_most(1)
19
+ end
20
+
21
+ def once
22
+ exactly(1)
23
+ end
24
+
25
+ def at_least_once
26
+ at_least(1)
27
+ end
28
+
29
+ def twice
30
+ exactly(2)
31
+ end
32
+
33
+ def at_most(times)
34
+ @calls = Calls::Upper.new(self, times)
35
+ self
36
+ end
37
+
38
+ def exactly(times)
39
+ @calls = Calls::Exactly.new(self, times)
40
+ self
41
+ end
42
+
43
+ def at_least(times)
44
+ @calls = Calls::Lower.new(self, times)
45
+ self
46
+ end
47
+
48
+ def call(*args, &block)
49
+ @calls.call
50
+ @args.verify(*args)
51
+ super
52
+ rescue Lookout::Mock::Error => e
53
+ raise e, '%s: %s' % [self, e]
54
+ end
55
+
56
+ def verify
57
+ @calls.verify
58
+ self
59
+ end
60
+
61
+ def to_s
62
+ '%p.%s%p' % [@object, @method, @args]
63
+ end
64
+
65
+ private
66
+
67
+ def stash
68
+ :"__mocked_method_#{@method}"
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Mock::Method::Arguments
4
+ autoload :Any, 'lookout/mock/method/arguments/any'
5
+ autoload :Anything, 'lookout/mock/method/arguments/anything'
6
+ autoload :List, 'lookout/mock/method/arguments/list'
7
+ autoload :None, 'lookout/mock/method/arguments/none'
8
+
9
+ Error = Class.new(Lookout::Mock::Error)
10
+
11
+ def initialize(*args)
12
+ self.args = args
13
+ end
14
+
15
+ def verify(*args)
16
+ @args == args or
17
+ raise Error, 'unexpected arguments: (%s)≠(%p)' %
18
+ [args.map{ |arg| arg.inspect }.join(', '), @args]
19
+ end
20
+
21
+ def inspect
22
+ result = @args.inspect
23
+ result.empty? ? "" : '(%s)' % result
24
+ end
25
+
26
+ protected
27
+
28
+ def args=(args)
29
+ return @args = Any.new if args.empty?
30
+ none = args.find{ |arg| arg.is_a? None } and return @args = none
31
+ @args = List.new(args)
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Mock::Method::Arguments::Any
4
+ def ==(other)
5
+ true
6
+ end
7
+
8
+ def inspect
9
+ '*args, &block'
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Mock::Method::Arguments::Anything
4
+ def ==(other)
5
+ true
6
+ end
7
+
8
+ def inspect
9
+ 'arg'
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Mock::Method::Arguments::List
4
+ def initialize(args)
5
+ @args = args
6
+ end
7
+
8
+ def ==(other)
9
+ Lookout::Equality.equal?(@args, other)
10
+ end
11
+
12
+ def inspect
13
+ @args.map{ |arg| arg.inspect }.join(', ')
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Mock::Method::Arguments::None
4
+ def ==(other)
5
+ other.empty?
6
+ end
7
+
8
+ def inspect
9
+ ""
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Mock::Method::Arguments::Any
4
+ def ==(other)
5
+ other.count == 1
6
+ end
7
+
8
+ def inspect
9
+ 'arg'
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Lookout::Mock::Method::Calls
4
+ autoload :Class, 'lookout/mock/method/calls/class'
5
+ autoload :Exactly, 'lookout/mock/method/calls/exactly'
6
+ autoload :Instance, 'lookout/mock/method/calls/instance'
7
+ autoload :Lower, 'lookout/mock/method/calls/lower'
8
+ autoload :Upper, 'lookout/mock/method/calls/upper'
9
+
10
+ Error = ::Class.new(Lookout::Mock::Error)
11
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Lookout::Mock::Method::Calls::Class
4
+ def format(limit, calls, format = nil)
5
+ return formats[limit][calls] unless format
6
+ if limit == -1
7
+ formats.default = Hash.new([format, [:@method, :@expected, :@calls]])
8
+ elsif calls == -1
9
+ formats[limit].default = [format, [:@method, :@calls]]
10
+ else
11
+ formats[limit][calls] = [format, [:@method]]
12
+ end
13
+ self
14
+ end
15
+
16
+ private
17
+
18
+ def formats
19
+ @formats ||= Hash.new{ |hash, key| hash[key] = {} }
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Lookout::Mock::Method::Calls::Exactly
4
+ extend Lookout::Mock::Method::Calls::Class
5
+ include Lookout::Mock::Method::Calls::Instance
6
+
7
+ format 0, 1, 'expected %s not to be called'
8
+ format 0, 2, 'expected %s not to be called, but was called twice'
9
+ format 0, -1, 'expected %s not to be called, but was called %d times'
10
+ format 1, 0, 'expected %s to be called'
11
+ format 1, 2, 'expected %s to be called once, not twice'
12
+ format 1, -1, 'expected %s to be called once, not %d times'
13
+ format 2, 0, 'expected %s to be called twice'
14
+ format 2, 1, 'expected %s to be called twice, but was only called once'
15
+ format 2, -1, 'expected %s to be called twice, not %d times'
16
+ format(-1, -1, 'expected %s to be called %d times, not %d times')
17
+
18
+ def initialize(method, limit)
19
+ raise ArgumentError, 'limit must be >= 0' unless limit >= 0
20
+ super
21
+ end
22
+
23
+ private
24
+
25
+ def satisfied?
26
+ @calls == @limit
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Lookout::Mock::Method::Calls::Instance
4
+ def initialize(method, limit)
5
+ @method, @limit = method, limit
6
+ @calls = 0
7
+ end
8
+
9
+ def call
10
+ @calls += 1
11
+ self
12
+ end
13
+
14
+ def verify
15
+ raise Lookout::Mock::Method::Calls::Error, message unless satisfied?
16
+ self
17
+ end
18
+
19
+ private
20
+
21
+ def message
22
+ format, variables = self.class.format(@limit, @calls)
23
+ format % variables.map{ |v| instance_variable_get(v) }
24
+ end
25
+ end