andyw8-seeing_is_believing 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +60 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +2 -0
  6. data/README.md +70 -0
  7. data/Rakefile +88 -0
  8. data/appveyor.yml +32 -0
  9. data/bin/seeing_is_believing +7 -0
  10. data/docs/example.gif +0 -0
  11. data/docs/frog-brown.png +0 -0
  12. data/docs/sib-streaming.gif +0 -0
  13. data/features/deprecated-flags.feature +91 -0
  14. data/features/errors.feature +155 -0
  15. data/features/examples.feature +423 -0
  16. data/features/flags.feature +852 -0
  17. data/features/regression.feature +898 -0
  18. data/features/support/env.rb +102 -0
  19. data/features/xmpfilter-style.feature +471 -0
  20. data/lib/seeing_is_believing/binary/align_chunk.rb +47 -0
  21. data/lib/seeing_is_believing/binary/align_file.rb +24 -0
  22. data/lib/seeing_is_believing/binary/align_line.rb +25 -0
  23. data/lib/seeing_is_believing/binary/annotate_end_of_file.rb +56 -0
  24. data/lib/seeing_is_believing/binary/annotate_every_line.rb +52 -0
  25. data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +179 -0
  26. data/lib/seeing_is_believing/binary/comment_lines.rb +36 -0
  27. data/lib/seeing_is_believing/binary/commentable_lines.rb +126 -0
  28. data/lib/seeing_is_believing/binary/config.rb +455 -0
  29. data/lib/seeing_is_believing/binary/data_structures.rb +58 -0
  30. data/lib/seeing_is_believing/binary/engine.rb +161 -0
  31. data/lib/seeing_is_believing/binary/format_comment.rb +79 -0
  32. data/lib/seeing_is_believing/binary/interline_align.rb +57 -0
  33. data/lib/seeing_is_believing/binary/remove_annotations.rb +113 -0
  34. data/lib/seeing_is_believing/binary/rewrite_comments.rb +62 -0
  35. data/lib/seeing_is_believing/binary.rb +73 -0
  36. data/lib/seeing_is_believing/code.rb +139 -0
  37. data/lib/seeing_is_believing/compatibility.rb +28 -0
  38. data/lib/seeing_is_believing/debugger.rb +32 -0
  39. data/lib/seeing_is_believing/error.rb +17 -0
  40. data/lib/seeing_is_believing/evaluate_by_moving_files.rb +195 -0
  41. data/lib/seeing_is_believing/event_stream/consumer.rb +221 -0
  42. data/lib/seeing_is_believing/event_stream/events.rb +193 -0
  43. data/lib/seeing_is_believing/event_stream/handlers/debug.rb +61 -0
  44. data/lib/seeing_is_believing/event_stream/handlers/record_exit_events.rb +26 -0
  45. data/lib/seeing_is_believing/event_stream/handlers/stream_json_events.rb +23 -0
  46. data/lib/seeing_is_believing/event_stream/handlers/update_result.rb +41 -0
  47. data/lib/seeing_is_believing/event_stream/producer.rb +178 -0
  48. data/lib/seeing_is_believing/hard_core_ensure.rb +58 -0
  49. data/lib/seeing_is_believing/hash_struct.rb +206 -0
  50. data/lib/seeing_is_believing/result.rb +89 -0
  51. data/lib/seeing_is_believing/safe.rb +112 -0
  52. data/lib/seeing_is_believing/swap_files.rb +90 -0
  53. data/lib/seeing_is_believing/the_matrix.rb +97 -0
  54. data/lib/seeing_is_believing/version.rb +3 -0
  55. data/lib/seeing_is_believing/wrap_expressions.rb +265 -0
  56. data/lib/seeing_is_believing/wrap_expressions_with_inspect.rb +19 -0
  57. data/lib/seeing_is_believing.rb +69 -0
  58. data/seeing_is_believing.gemspec +84 -0
  59. data/spec/binary/alignment_specs.rb +27 -0
  60. data/spec/binary/comment_lines_spec.rb +852 -0
  61. data/spec/binary/config_spec.rb +831 -0
  62. data/spec/binary/engine_spec.rb +114 -0
  63. data/spec/binary/format_comment_spec.rb +210 -0
  64. data/spec/binary/marker_spec.rb +71 -0
  65. data/spec/binary/remove_annotations_spec.rb +342 -0
  66. data/spec/binary/rewrite_comments_spec.rb +106 -0
  67. data/spec/code_spec.rb +233 -0
  68. data/spec/debugger_spec.rb +45 -0
  69. data/spec/evaluate_by_moving_files_spec.rb +204 -0
  70. data/spec/event_stream_spec.rb +762 -0
  71. data/spec/hard_core_ensure_spec.rb +120 -0
  72. data/spec/hash_struct_spec.rb +514 -0
  73. data/spec/seeing_is_believing_spec.rb +1094 -0
  74. data/spec/sib_spec_helpers/version.rb +17 -0
  75. data/spec/spec_helper.rb +26 -0
  76. data/spec/spec_helper_spec.rb +16 -0
  77. data/spec/wrap_expressions_spec.rb +1013 -0
  78. metadata +340 -0
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'seeing_is_believing/debugger'
3
+ require 'stringio'
4
+
5
+ RSpec.describe SeeingIsBelieving::Debugger do
6
+ let(:stream) { StringIO.new }
7
+
8
+ specify 'is enabled when given a stream' do
9
+ expect(described_class.new(stream: nil)).to_not be_enabled
10
+ expect(described_class.new(stream: stream)).to be_enabled
11
+ end
12
+
13
+ specify 'colour is disabled by default' do
14
+ expect(described_class.new).to_not be_coloured
15
+ expect(described_class.new(colour: false)).to_not be_coloured
16
+ expect(described_class.new(colour: true)).to be_coloured
17
+ end
18
+
19
+ context 'when given a stream' do
20
+ it 'prints the the context and the value of the block' do
21
+ described_class.new(stream: stream).context('C') { 'V' }
22
+ expect(stream.string).to eq "C:\nV\n"
23
+ end
24
+
25
+ it 'colours the context when colour is set to true' do
26
+ described_class.new(stream: stream, colour: true).context('C') { 'V' }
27
+ expect(stream.string).to eq "#{described_class::CONTEXT_COLOUR}C:#{described_class::RESET_COLOUR}\nV\n"
28
+ end
29
+ end
30
+
31
+ context 'when not given a stream' do
32
+ it 'prints nothing' do
33
+ described_class.new.context('C') { 'V' }
34
+ expect(stream.string).to be_empty
35
+ end
36
+
37
+ it 'does not evaluate the blocks' do
38
+ described_class.new.context('C') { fail }
39
+ end
40
+ end
41
+
42
+ specify '::Null is a disabled debugger' do
43
+ expect(described_class::Null).to_not be_enabled
44
+ end
45
+ end
@@ -0,0 +1,204 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'seeing_is_believing/evaluate_by_moving_files'
5
+ require 'seeing_is_believing/event_stream/handlers/update_result'
6
+ require 'fileutils'
7
+ require 'childprocess'
8
+
9
+ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
10
+ let(:filedir) { File.expand_path '../proving_grounds', __dir__ }
11
+ let(:filename) { File.join filedir, 'some_filename' }
12
+
13
+ before { FileUtils.mkdir_p filedir }
14
+
15
+ def matrix_file
16
+ 'seeing_is_believing/the_matrix'
17
+ end
18
+
19
+ def null_options(overrides={})
20
+ { event_handler: lambda { |*| } }
21
+ end
22
+
23
+ def invoke(program, options={})
24
+ result = SeeingIsBelieving::Result.new
25
+ options[:event_handler] ||= SeeingIsBelieving::EventStream::Handlers::UpdateResult.new(result)
26
+ evaluator = described_class.new(filename, program, program, options)
27
+ FileUtils.rm_f evaluator.backup_path
28
+ evaluator.call
29
+ result
30
+ end
31
+
32
+ it 'evaluates the code as the given file' do
33
+ expect(invoke('print __FILE__').stdout).to eq filename
34
+ end
35
+
36
+ it 'evaluates the code when the given file DNE' do
37
+ FileUtils.rm_f filename
38
+ expect(invoke('print 1').stdout).to eq '1'
39
+ end
40
+
41
+ it 'evaluates the code when the given file Exists' do
42
+ FileUtils.touch filename
43
+ expect(invoke('print 1').stdout).to eq '1'
44
+ end
45
+
46
+ it 'raises an error when the temp file already exists' do
47
+ evaluator = described_class.new(filename, '', '', null_options)
48
+ FileUtils.touch evaluator.backup_path
49
+ expect { evaluator.call }.to raise_error SeeingIsBelieving::TempFileAlreadyExists
50
+ end
51
+
52
+ it 'does not change the original file' do
53
+ File.open(filename, 'w') { |f| f.write "ORIGINAL" }
54
+ invoke '1 + 1'
55
+ expect(File.read filename).to eq "ORIGINAL"
56
+ end
57
+
58
+ it 'uses HardCoreEnsure to move the file back' do
59
+ evaluator = described_class.new filename, 'PROGRAM', 'PROGRAM', null_options
60
+ File.open(filename, 'w') { |f| f.write 'ORIGINAL' }
61
+ FileUtils.rm_rf evaluator.backup_path
62
+ expect(SeeingIsBelieving::HardCoreEnsure).to receive(:call) do |options|
63
+ # initial state
64
+ expect(File.exist? evaluator.backup_path).to eq false
65
+ expect(File.read filename).to eq 'ORIGINAL'
66
+
67
+ # after code
68
+ options[:code].call rescue nil
69
+ expect(File.read evaluator.backup_path).to eq 'ORIGINAL'
70
+ expect(File.read filename).to eq 'PROGRAM'
71
+
72
+ # after ensure
73
+ options[:ensure].call
74
+ expect(File.read filename).to eq 'ORIGINAL'
75
+ expect(File.exist? evaluator.backup_path).to eq false
76
+ end
77
+ evaluator.call
78
+ end
79
+
80
+ it 'uses HardCoreEnsure to delete the file if it wrote it where one did not previously exist' do
81
+ evaluator = described_class.new filename, 'PROGRAM', 'PROGRAM', null_options
82
+ FileUtils.rm_rf filename
83
+ expect(SeeingIsBelieving::HardCoreEnsure).to receive(:call) do |options|
84
+ # initial state
85
+ expect(File.exist? filename).to eq false
86
+
87
+ # after code
88
+ options[:code].call rescue nil
89
+ expect(File.read filename).to eq 'PROGRAM'
90
+
91
+ # after ensure
92
+ options[:ensure].call
93
+ expect(File.exist? filename).to eq false
94
+ end
95
+ evaluator.call
96
+ end
97
+
98
+ it 'can require files' do
99
+ other_filename1 = File.join filedir, 'other1.rb'
100
+ other_filename2 = File.join filedir, 'other2.rb'
101
+ File.open(other_filename1, 'w') { |f| f.puts "puts 123" }
102
+ File.open(other_filename2, 'w') { |f| f.puts "puts 456" }
103
+ result = invoke '', require_files: [matrix_file, other_filename1, other_filename2]
104
+ expect(result.stdout).to eq "123\n456\n"
105
+ end
106
+
107
+ it 'can set the load path' do
108
+ File.open(File.join(filedir, 'other1.rb'), 'w') { |f| f.puts "puts 123" }
109
+ result = invoke '', require_files: [matrix_file, 'other1'], load_path_dirs: [filedir]
110
+ expect(result.stdout).to eq "123\n"
111
+ end
112
+
113
+ it 'can set the encoding' do
114
+ test = -> { expect(invoke('print "ç"', encoding: 'u').stdout).to eq "ç" }
115
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
116
+ pending "Rubinius doesn't seem to use -Kx, but rather -U"
117
+ test.call
118
+ else
119
+ test.call
120
+ end
121
+ end
122
+
123
+ it 'sets the program\'s working directory to the file\'s directory, when given local_cwd' do
124
+ wd = Dir.pwd
125
+ Dir.chdir '/'
126
+ begin
127
+ root = File.expand_path '/'
128
+ result = invoke 'print Dir.pwd'
129
+ expect(result.stdout).to eq root
130
+ dir, cwd, file_path = invoke(<<-RUBY, local_cwd: true).stdout.lines.map(&:chomp)
131
+ puts File.expand_path(__dir__)
132
+ puts Dir.pwd
133
+ puts __FILE__
134
+ RUBY
135
+ expect(dir).to_not eq root
136
+ expect(cwd).to eq dir
137
+ expect(file_path).to eq File.basename(filename)
138
+ ensure
139
+ Dir.chdir wd
140
+ end
141
+ end
142
+
143
+ it 'does not blow up on exceptions raised in at_exit blocks' do
144
+ expect { invoke 'at_exit { raise "zomg" }' }.to_not raise_error
145
+ end
146
+
147
+ it 'can provide stdin as a string or stream' do
148
+ expect(invoke('p gets', provided_input: 'a').stdout).to eq %("a"\n)
149
+ require 'stringio'
150
+ result = invoke 'p gets', provided_input: StringIO.new('b')
151
+ expect(result.stdout).to eq %("b"\n)
152
+ end
153
+
154
+ it 'must provide an event handler, which receives the process\'s events' do
155
+ # raises error
156
+ expect { described_class.new(filename, "", "", {}) }
157
+ .to raise_error ArgumentError, /event_handler/
158
+
159
+ # sees all the events
160
+ seen = []
161
+ invoke '1', event_handler: lambda { |e| seen << e }
162
+ expect(seen).to_not be_empty
163
+ expect(seen.last).to eq SeeingIsBelieving::EventStream::Events::Finished.new
164
+ end
165
+
166
+ it 'can set a timeout, which interrupts the process group and then waits for the events to finish' do
167
+ pre = Time.now
168
+ result = invoke <<-RUBY, timeout_seconds: 0.5
169
+ child_pid = spawn 'ruby', '-e', 'sleep' # child makes a grandchild which sleeps
170
+ puts Process.pid, child_pid # print ids so we can check they got killed
171
+ $stdout.flush
172
+ sleep # child sleeps
173
+ RUBY
174
+ post = Time.now
175
+ expect(result.timeout?).to eq true
176
+ expect(result.timeout_seconds).to eq 0.5
177
+ expect(post - pre).to be > 0.5
178
+ child_id, grandchild_id, *rest = result.stdout.lines
179
+ expect(child_id).to match /^\d+$/
180
+ expect(grandchild_id).to match /^\d+$/
181
+ expect(rest).to be_empty
182
+ expect { Process.wait child_id.to_i } .to raise_error /no.*processes/i
183
+ expect { Process.wait grandchild_id.to_i } .to raise_error /no.*processes/i
184
+ end
185
+
186
+ it 'raises an ArgumentError if given arguments it doesn\'t know' do
187
+ expect { invoke '1', watisthis: :idontknow }
188
+ .to raise_error ArgumentError, /watisthis/
189
+ end
190
+
191
+ it 'doesn\'t explode or do anything else obnoxious when the input stream is closed' do
192
+ infinite_string = Object.new
193
+ def infinite_string.each_char
194
+ loop { yield 'c' }
195
+ end
196
+ result = nil
197
+ expect {
198
+ result = invoke '$stdin.close', provided_input: infinite_string
199
+ }.to_not output.to_stderr
200
+ expect(result.exitstatus).to eq 0
201
+ expect(result.stderr).to be_empty
202
+ expect(result.stdout).to be_empty
203
+ end
204
+ end