Skip to content

Commit 7f1e660

Browse files
committed
chore: pin spectator dependency version and improve unbuffered method robustness by handling nil sync state.
1 parent b1c6640 commit 7f1e660

3 files changed

Lines changed: 149 additions & 138 deletions

File tree

shard.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies:
1717
development_dependencies:
1818
spectator:
1919
gitlab: arctic-fox/spectator
20+
version: ~> 0.12.2
2021

2122
crystal: ">= 1.0.0"
2223

spec/support/test_helpers.cr

Lines changed: 79 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -8,143 +8,143 @@ module TestHelpers
88
property? closed : Bool = false
99
property read_timeout : Time::Span? = nil
1010
property mode : Symbol = :cooked
11-
11+
1212
def initialize(@input : Array(String) = [] of String)
1313
@input.each do |str|
1414
@input_buffer.concat(str.chars)
1515
end
1616
end
17-
17+
1818
def read(slice : Bytes) : Int32
1919
return 0 if @closed || @input_buffer.empty?
20-
20+
2121
bytes_read = 0
2222
slice.each_with_index do |_, i|
2323
break if @input_buffer.empty?
2424
char = @input_buffer.shift
2525
slice[i] = char.ord.to_u8
2626
bytes_read += 1
2727
end
28-
28+
2929
bytes_read
3030
end
31-
31+
3232
def write(slice : Bytes) : Nil
3333
@output_buffer += String.new(slice)
3434
end
35-
35+
3636
def close : Nil
3737
@closed = true
3838
end
39-
39+
4040
def fd : Int32
4141
-1
4242
end
43-
43+
4444
def blocking : Bool
4545
true
4646
end
47-
47+
4848
def blocking=(value : Bool)
4949
# no-op for mock
5050
end
51-
51+
5252
def read_timeout=(timeout : Time::Span?)
5353
@read_timeout = timeout
5454
end
55-
55+
5656
def cooked!
5757
@mode = :cooked
5858
end
59-
59+
6060
def raw!
6161
@mode = :raw
6262
end
63-
63+
6464
def echo!
6565
@mode = :echo
6666
end
67-
67+
6868
def tty?
6969
true
7070
end
71-
71+
7272
# Add more characters to the input buffer
7373
def inject_input(str : String)
7474
@input_buffer.concat(str.chars)
7575
end
76-
76+
7777
# Clear the output buffer and return its contents
7878
def consume_output : String
7979
output = @output_buffer
8080
@output_buffer = ""
8181
output
8282
end
8383
end
84-
84+
8585
# Helper to create key sequences
8686
module Keys
8787
ESC = "\e"
88-
88+
8989
def self.up
9090
"#{ESC}[A"
9191
end
92-
92+
9393
def self.down
9494
"#{ESC}[B"
9595
end
96-
96+
9797
def self.right
9898
"#{ESC}[C"
9999
end
100-
100+
101101
def self.left
102102
"#{ESC}[D"
103103
end
104-
104+
105105
def self.home
106106
"#{ESC}[H"
107107
end
108-
108+
109109
def self.end_key
110110
"#{ESC}[F"
111111
end
112-
112+
113113
def self.delete
114114
"#{ESC}[3~"
115115
end
116-
116+
117117
def self.backspace
118118
"\b"
119119
end
120-
120+
121121
def self.tab
122122
"\t"
123123
end
124-
124+
125125
def self.enter
126126
"\r"
127127
end
128-
128+
129129
def self.ctrl(letter : Char)
130130
(letter.upcase.ord - 64).chr
131131
end
132-
132+
133133
def self.alt(letter : Char)
134134
"#{ESC}#{letter}"
135135
end
136-
136+
137137
def self.f(num : Int32)
138138
case num
139-
when 1 then "#{ESC}OP"
140-
when 2 then "#{ESC}OQ"
141-
when 3 then "#{ESC}OR"
142-
when 4 then "#{ESC}OS"
143-
when 5 then "#{ESC}[15~"
144-
when 6 then "#{ESC}[17~"
145-
when 7 then "#{ESC}[18~"
146-
when 8 then "#{ESC}[19~"
147-
when 9 then "#{ESC}[20~"
139+
when 1 then "#{ESC}OP"
140+
when 2 then "#{ESC}OQ"
141+
when 3 then "#{ESC}OR"
142+
when 4 then "#{ESC}OS"
143+
when 5 then "#{ESC}[15~"
144+
when 6 then "#{ESC}[17~"
145+
when 7 then "#{ESC}[18~"
146+
when 8 then "#{ESC}[19~"
147+
when 9 then "#{ESC}[20~"
148148
when 10 then "#{ESC}[21~"
149149
when 11 then "#{ESC}[23~"
150150
when 12 then "#{ESC}[24~"
@@ -153,55 +153,54 @@ module TestHelpers
153153
end
154154
end
155155
end
156-
156+
157157
# Helper to create a mock file descriptor
158158
class MockFileDescriptor < IO::FileDescriptor
159159
property input_data : String = ""
160160
property output_data : String = ""
161161
property read_pos : Int32 = 0
162162
property? blocking_mode : Bool = true
163-
163+
164164
def initialize(fd : Int32 = 0)
165165
super(handle: fd.unsafe_as(LibC::Int), close_on_finalize: false)
166166
end
167-
168-
167+
169168
def blocking : Bool
170169
@blocking_mode
171170
end
172-
171+
173172
def blocking=(value : Bool)
174173
@blocking_mode = value
175174
end
176-
175+
177176
def read(slice : Bytes) : Int32
178177
return 0 if @read_pos >= @input_data.size
179-
178+
180179
bytes_to_read = Math.min(slice.size, @input_data.size - @read_pos)
181180
return 0 if bytes_to_read == 0
182-
181+
183182
@input_data.to_slice[@read_pos, bytes_to_read].copy_to(slice.to_unsafe, bytes_to_read)
184183
@read_pos += bytes_to_read
185184
bytes_to_read
186185
end
187-
186+
188187
def read_char : Char?
189188
return nil if @read_pos >= @input_data.size
190189
char = @input_data[@read_pos]
191190
@read_pos += 1
192191
char
193192
end
194-
193+
195194
def write(slice : Bytes) : Nil
196195
@output_data += String.new(slice)
197196
nil
198197
end
199-
198+
200199
def print(*args)
201200
args.each { |arg| @output_data += arg.to_s }
202201
nil
203202
end
204-
203+
205204
def puts(*args)
206205
if args.empty?
207206
@output_data += "\n"
@@ -210,95 +209,97 @@ module TestHelpers
210209
end
211210
nil
212211
end
213-
212+
214213
def close
215214
@closed = true
216215
nil
217216
end
218-
217+
219218
def closed? : Bool
220219
@closed
221220
end
222-
221+
223222
def reset
224223
@input_data = ""
225224
@output_data = ""
226225
@read_pos = 0
227226
end
228-
227+
229228
def inject_input(data : String)
230229
@input_data += data
231230
end
232-
231+
233232
def tty? : Bool
234233
true
235234
end
236-
235+
237236
def cooked : Nil
238237
# No-op for testing
239238
end
240-
239+
241240
def cooked! : Nil
242241
# No-op for testing
243242
end
244-
245-
def raw : Nil
243+
244+
def raw : Nil
246245
# No-op for testing
247246
end
248-
247+
249248
def raw! : Nil
250249
# No-op for testing
251250
end
252-
251+
253252
def echo=(value : Bool) : Nil
254253
# No-op for testing
255254
end
256-
257-
def sync? : Bool
258-
true
255+
256+
property? sync_state : Bool? = true
257+
258+
def sync? : Bool?
259+
@sync_state
259260
end
260-
261+
261262
def sync=(value : Bool)
262-
# No-op for testing
263+
@sync_state = value
263264
end
264-
265+
265266
def noecho(&block)
266267
yield
267268
end
268-
269+
269270
def raw(&block)
270271
yield
271272
end
272-
273+
273274
def cooked(&block)
274275
yield
275276
end
276277
end
277-
278+
278279
# Helper to capture events
279280
class EventCapture
280281
property events : Array({String, Term::Reader::KeyEvent}) = [] of {String, Term::Reader::KeyEvent}
281-
282+
282283
def handler
283284
->(name : String, event : Term::Reader::KeyEvent) {
284285
@events << {name, event}
285286
nil
286287
}
287288
end
288-
289+
289290
def clear
290291
@events.clear
291292
end
292-
293+
293294
def has_event?(name : String) : Bool
294295
@events.any? { |n, _| n == name }
295296
end
296-
297+
297298
def event_count(name : String) : Int32
298299
@events.count { |n, _| n == name }
299300
end
300301
end
301-
302+
302303
# Platform detection helpers
303304
def windows?
304305
{% if flag?(:windows) %}
@@ -307,8 +308,8 @@ module TestHelpers
307308
false
308309
{% end %}
309310
end
310-
311+
311312
def unix?
312313
!windows?
313314
end
314-
end
315+
end

0 commit comments

Comments
 (0)