sus 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,34 +27,32 @@ module Sus
27
27
  # Styled output output.
28
28
  module Output
29
29
  class Buffered
30
- def initialize(output)
31
- @output = output
32
- @buffer = Array.new
30
+ def initialize
31
+ @output = Array.new
33
32
  end
34
33
 
35
34
  attr :output
36
- attr :buffer
37
35
 
38
- def append(output)
39
- @buffer.each do |operation|
40
- output.public_send(*operation)
41
- end
36
+ def each(&block)
37
+ @output.each(&block)
38
+ end
39
+
40
+ def append(buffer)
41
+ @output.concat(buffer.output)
42
42
  end
43
43
 
44
44
  def string
45
45
  io = StringIO.new
46
- append(Text.new(io))
46
+ Text.new(io).append(@output)
47
47
  return io.string
48
48
  end
49
49
 
50
50
  def indent
51
- @buffer << [:indent]
52
- @output.indent
51
+ @output << [:indent]
53
52
  end
54
53
 
55
54
  def outdent
56
- @buffer << [:outdent]
57
- @output.outdent
55
+ @output << [:outdent]
58
56
  end
59
57
 
60
58
  def indented
@@ -65,13 +63,11 @@ module Sus
65
63
  end
66
64
 
67
65
  def write(*arguments)
68
- @output.write(*arguments)
69
- @buffer << [:write, *arguments]
66
+ @output << [:write, *arguments]
70
67
  end
71
68
 
72
69
  def puts(*arguments)
73
- @output.puts(*arguments)
74
- @buffer << [:puts, *arguments]
70
+ @output << [:puts, *arguments]
75
71
  end
76
72
  end
77
73
  end
@@ -76,6 +76,7 @@ module Sus
76
76
  offset = @current_count - index
77
77
 
78
78
  @output.write("\e[#{offset}F\e[K")
79
+
79
80
  soft_wrap do
80
81
  line.print(@output)
81
82
  end
@@ -29,6 +29,9 @@ module Sus
29
29
  class Null
30
30
  def initialize
31
31
  end
32
+
33
+ def append(buffer)
34
+ end
32
35
 
33
36
  def indent
34
37
  end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require_relative 'bar'
24
+ require_relative 'status'
25
+ require_relative 'lines'
26
+
27
+ module Sus
28
+ module Output
29
+ class Progress
30
+ def self.now
31
+ ::Process.clock_gettime(Process::CLOCK_MONOTONIC)
32
+ end
33
+
34
+ def initialize(output, total = 0, minimum_output_duration: 1.0)
35
+ @output = output
36
+ @subject = subject
37
+
38
+ @start_time = Progress.now
39
+
40
+ if @output.interactive?
41
+ @bar = Bar.new
42
+ @lines = Lines.new(@output)
43
+ @lines[0] = @bar
44
+ end
45
+
46
+ @current = 0
47
+ @total = total
48
+ end
49
+
50
+ attr :subject
51
+ attr :current
52
+ attr :total
53
+
54
+ def duration
55
+ Progress.now - @start_time
56
+ end
57
+
58
+ def progress
59
+ @current.to_f / @total.to_f
60
+ end
61
+
62
+ def remaining
63
+ @total - @current
64
+ end
65
+
66
+ def average_duration
67
+ if @current > 0
68
+ duration / @current
69
+ end
70
+ end
71
+
72
+ def estimated_remaining_time
73
+ if average_duration = self.average_duration
74
+ average_duration * remaining
75
+ end
76
+ end
77
+
78
+ # Increase the amont of work done.
79
+ def increment(amount = 1)
80
+ @current += amount
81
+
82
+ @bar&.update(@current, @total, self.to_s)
83
+ @lines&.redraw(0)
84
+
85
+ return self
86
+ end
87
+
88
+ # Increase the total size of the progress.
89
+ def expand(amount = 1)
90
+ @total += amount
91
+
92
+ @bar&.update(@current, @total, self.to_s)
93
+ @lines&.redraw(0)
94
+
95
+ return self
96
+ end
97
+
98
+ def report(index, context, state)
99
+ @lines&.[]=(index+1, Status.new(state, context))
100
+
101
+ return self
102
+ end
103
+
104
+ def clear
105
+ @lines&.clear
106
+ end
107
+
108
+ def to_s
109
+ if estimated_remaining_time = self.estimated_remaining_time
110
+ "#{@current}/#{@total} completed in #{formatted_duration(self.duration)}, #{formatted_duration(estimated_remaining_time)} remaining"
111
+ else
112
+ "#{@current}/#{@total} completed"
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def formatted_duration(duration)
119
+ seconds = duration.floor
120
+
121
+ if seconds < 60.0
122
+ return "#{seconds}s"
123
+ end
124
+
125
+ minutes = (duration / 60.0).floor
126
+ seconds = (seconds - (minutes * 60)).round
127
+
128
+ if minutes < 60.0
129
+ return "#{minutes}m#{seconds}s"
130
+ end
131
+
132
+ hours = (minutes / 60.0).floor
133
+ minutes = (minutes - (hours * 60)).round
134
+
135
+ if hours < 24.0
136
+ return "#{hours}h#{minutes}m"
137
+ end
138
+
139
+ days = (hours / 24.0).floor
140
+ hours = (hours - (days * 24)).round
141
+
142
+ return "#{days}d#{hours}h"
143
+ end
144
+ end
145
+ end
146
+ end
@@ -35,6 +35,12 @@ module Sus
35
35
  @styles[:indent] = @indent
36
36
  end
37
37
 
38
+ def append(buffer)
39
+ buffer.each do |operation|
40
+ self.public_send(*operation)
41
+ end
42
+ end
43
+
38
44
  attr :io
39
45
 
40
46
  INDENTATION = "\t"
data/lib/sus/output.rb CHANGED
@@ -4,6 +4,7 @@ require_relative 'output/text'
4
4
  require_relative 'output/xterm'
5
5
 
6
6
  require_relative 'output/null'
7
+ require_relative 'output/progress'
7
8
 
8
9
  module Sus
9
10
  module Output
@@ -35,7 +36,7 @@ module Sus
35
36
  end
36
37
 
37
38
  def self.buffered
38
- Buffered.new(Null.new)
39
+ Buffered.new
39
40
  end
40
41
  end
41
42
  end
@@ -12,17 +12,12 @@ module Sus
12
12
 
13
13
  # Didn't throw any exception, so the expectation failed:
14
14
  assertions.assert(false, self)
15
- rescue => exception
16
- # Did we throw the right kind of exception?
17
- if exception.is_a?(@exception_class)
18
- # Did it have the right message?
19
- if @message
20
- assertions.assert(@message === exception.message)
21
- else
22
- assertions.assert(true, self)
23
- end
15
+ rescue @exception_class => exception
16
+ # Did it have the right message?
17
+ if @message
18
+ assertions.assert(@message === exception.message)
24
19
  else
25
- raise
20
+ assertions.assert(true, self)
26
21
  end
27
22
  end
28
23
  end
@@ -0,0 +1,147 @@
1
+
2
+ require_relative 'respond_to'
3
+
4
+ module Sus
5
+ class Receive
6
+ CALL_ORIGINAL = Object.new
7
+
8
+ def initialize(base, method)
9
+ @base = base
10
+ @method = method
11
+
12
+ @times = Once.new
13
+ @arguments = nil
14
+ @options = nil
15
+ @block = nil
16
+ @returning = CALL_ORIGINAL
17
+ end
18
+
19
+ def print(output)
20
+ output.write("receive ", :variable, @method.to_s, :reset, " ")
21
+ end
22
+
23
+ def with_arguments(*arguments)
24
+ @arguments = WithArguments.new(arguments)
25
+ return self
26
+ end
27
+
28
+ def with_options(*options)
29
+ @options = WithOptions.new(options)
30
+ return self
31
+ end
32
+
33
+ def with_block
34
+ @block = WithBlock.new
35
+ return self
36
+ end
37
+
38
+ def and_return(*returning)
39
+ if returning.size == 1
40
+ @returning = returning.first
41
+ else
42
+ @returning = returning
43
+ end
44
+ return self
45
+ end
46
+
47
+ def validate(mock, assertions, arguments, options, block)
48
+ @arguments.call(assertions, arguments) if @arguments
49
+ @options.call(assertions, options) if @options
50
+ @block.call(assertions, block) if @block
51
+ end
52
+
53
+ def call(assertions, subject)
54
+ assertions.nested(self) do |assertions|
55
+ mock = @base.mock(subject)
56
+
57
+ called = 0
58
+
59
+ if call_original?
60
+ mock.before(@method) do |*arguments, **options, &block|
61
+ called += 1
62
+
63
+ validate(mock, assertions, arguments, options, block)
64
+ end
65
+ else
66
+ mock.replace(@method) do |*arguments, **options, &block|
67
+ called += 1
68
+
69
+ validate(mock, assertions, arguments, options, block)
70
+
71
+ next @returning
72
+ end
73
+ end
74
+
75
+ assertions.defer do
76
+ @times.call(assertions, called)
77
+ end
78
+ end
79
+ end
80
+
81
+ def call_original?
82
+ @returning == CALL_ORIGINAL
83
+ end
84
+
85
+ class WithArguments
86
+ def initialize(arguments)
87
+ @arguments = arguments
88
+ end
89
+
90
+ def print(output)
91
+ output.write("with arguments ", :variable, @arguments.inspect)
92
+ end
93
+
94
+ def call(assertions, subject)
95
+ assertions.nested(self) do |assertions|
96
+ Expect.new(assertions, subject).to(Be == @arguments)
97
+ end
98
+ end
99
+ end
100
+
101
+ class WithOptions
102
+ def initialize(options)
103
+ @options = options
104
+ end
105
+
106
+ def print(output)
107
+ output.write("with options ", :variable, @options.inspect)
108
+ end
109
+
110
+ def call(assertions, subject)
111
+ assertions.nested(self) do |assertions|
112
+ Expect.new(assertions, subject).to(Be.new(:include?, @options))
113
+ end
114
+ end
115
+ end
116
+
117
+ class WithBlock
118
+ def print(output)
119
+ output.write("with block")
120
+ end
121
+
122
+ def call(assertions, subject)
123
+ assertions.nested(self) do |assertions|
124
+ Expect.new(assertions, subject).not.to(Be == nil)
125
+ end
126
+ end
127
+ end
128
+
129
+ class Once
130
+ def print(output)
131
+ output.write("once")
132
+ end
133
+
134
+ def call(assertions, subject)
135
+ assertions.nested(self) do |assertions|
136
+ Expect.new(assertions, subject).to(Be == 1)
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ class Base
143
+ def receive(method)
144
+ Receive.new(self, method)
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,86 @@
1
+ module Sus
2
+ class RespondTo
3
+ class WithParameters
4
+ # @parameter [Array(Symbol)] List of method parameters in the expected order, must include at least all required parameters but can also list optional parameters.
5
+ def initialize(parameters)
6
+ @parameters = parameters
7
+ end
8
+
9
+ def call(assertions, subject)
10
+ parameters = @parameters.dup
11
+
12
+ assertions.nested(self) do |assertions|
13
+ expected_name = parameters.shift
14
+
15
+ subject.each do |type, name|
16
+ case type
17
+ when :req
18
+ assertions.assert(name == expected_name, "parameter #{expected_name} is required, but was #{name}")
19
+ when :opt
20
+ break if expected_name.nil?
21
+ assertions.assert(name == expected_name, "parameter #{expected_name} is specified, but was #{name}")
22
+ else
23
+ break
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ class WithOptions
31
+ def initialize(options)
32
+ @options = options
33
+ end
34
+
35
+ def print(output)
36
+ output.write("with options ", :variable, @options.inspect)
37
+ end
38
+
39
+ def call(assertions, subject)
40
+ options = {}
41
+ @options.each{|name| options[name] = nil}
42
+
43
+ subject.each do |type, name|
44
+ options[name] = type
45
+ end
46
+
47
+ assertions.nested(self) do |assertions|
48
+ options.each do |name, type|
49
+ assertions.assert(type != nil, "option #{name}: is required")
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def initialize(method)
56
+ @method = method
57
+ @parameters = nil
58
+ @options = nil
59
+ end
60
+
61
+ def with_options(*options)
62
+ @options = WithOptions.new(options)
63
+ return self
64
+ end
65
+
66
+ def print(output)
67
+ output.write("respond to ", :variable, @method.to_s)
68
+ end
69
+
70
+ def call(assertions, subject)
71
+ assertions.nested(self) do |assertions|
72
+ assertions.assert(subject.respond_to?(@method), self)
73
+
74
+ parameters = subject.method(@method).parameters
75
+ @parameters.call(assertions, parameters) if @parameters
76
+ @options.call(assertions, parameters) if @options
77
+ end
78
+ end
79
+ end
80
+
81
+ class Base
82
+ def respond_to(method)
83
+ RespondTo.new(method)
84
+ end
85
+ end
86
+ end
data/lib/sus/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sus
4
- VERSION = "0.7.0"
4
+ VERSION = "0.8.0"
5
5
  end
data/lib/sus.rb CHANGED
@@ -9,6 +9,9 @@ require_relative 'sus/expect'
9
9
  require_relative 'sus/be'
10
10
  require_relative 'sus/be_within'
11
11
 
12
+ require_relative 'sus/mock'
13
+ require_relative 'sus/receive'
14
+
12
15
  require_relative 'sus/raise_exception'
13
16
  require_relative 'sus/have_duration'
14
17
 
data.tar.gz.sig ADDED
Binary file
metadata CHANGED
@@ -1,14 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain: []
11
- date: 2022-07-01 00:00:00.000000000 Z
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
14
+ ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
15
+ CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
16
+ MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
17
+ MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
18
+ bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
19
+ igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
20
+ 9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
21
+ sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
22
+ e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
23
+ XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
24
+ RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
25
+ tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
26
+ zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
27
+ xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
28
+ BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
29
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
30
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
31
+ cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl
32
+ xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/
33
+ c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp
34
+ 8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws
35
+ JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP
36
+ eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt
37
+ Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
38
+ voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
39
+ -----END CERTIFICATE-----
40
+ date: 2022-08-15 00:00:00.000000000 Z
12
41
  dependencies: []
13
42
  description:
14
43
  email:
@@ -25,6 +54,7 @@ files:
25
54
  - lib/sus/base.rb
26
55
  - lib/sus/be.rb
27
56
  - lib/sus/be_within.rb
57
+ - lib/sus/clock.rb
28
58
  - lib/sus/config.rb
29
59
  - lib/sus/context.rb
30
60
  - lib/sus/describe.rb
@@ -37,17 +67,20 @@ files:
37
67
  - lib/sus/it.rb
38
68
  - lib/sus/it_behaves_like.rb
39
69
  - lib/sus/let.rb
70
+ - lib/sus/mock.rb
40
71
  - lib/sus/output.rb
41
72
  - lib/sus/output/bar.rb
42
73
  - lib/sus/output/buffered.rb
43
74
  - lib/sus/output/lines.rb
44
75
  - lib/sus/output/null.rb
76
+ - lib/sus/output/progress.rb
45
77
  - lib/sus/output/status.rb
46
78
  - lib/sus/output/text.rb
47
79
  - lib/sus/output/xterm.rb
48
- - lib/sus/progress.rb
49
80
  - lib/sus/raise_exception.rb
81
+ - lib/sus/receive.rb
50
82
  - lib/sus/registry.rb
83
+ - lib/sus/respond_to.rb
51
84
  - lib/sus/shared.rb
52
85
  - lib/sus/version.rb
53
86
  - lib/sus/with.rb
metadata.gz.sig ADDED
@@ -0,0 +1,2 @@
1
+ ����M�Ȣ��3�'L��z} �6W���ED(�|L�������@����=�%�m鶖�������~�eZi�4+��V�H7�b}�ڤ�/�Tu��/�nd���T���%�IK�������;�=ٗ�2+���ν��7�p��aÕ�^kL����3�/Q"��c��0^YT�P��=nN0���=R'�E�Eⱻ � ��� DY�u�a��-�)��ن2�BY��|궖'� ���\5G��`c�۬8�s���`�Fvo�T��
2
+ S��2%�nl��H�CT��`�Nc;�9���n.[�^=�Vm��%�I�P.��rš�p!uG��oۮdDW��k�b]����+e�A�Y�FK[[�n%�y91;�����7�+���:���