fake_io 0.1.0

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,1212 @@
1
+ require 'spec_helper'
2
+ require 'fake_io'
3
+
4
+ require 'classes/test_io'
5
+
6
+ describe FakeIO do
7
+ let(:chunks) { ["one\n", "two\nthree\n", "four\n"] }
8
+ let(:string) { chunks.join }
9
+ let(:bytes) { chunks.join.each_byte.to_a }
10
+ let(:chars) { chunks.join.each_char.to_a }
11
+ let(:lines) { chunks.join.each_line.to_a }
12
+
13
+ subject { TestIO.new(chunks) }
14
+
15
+ describe "#initialize" do
16
+ it "should open the IO stream" do
17
+ expect(subject).not_to be_closed
18
+ end
19
+
20
+ it "must default #autoclose? to true" do
21
+ expect(subject.autoclose?).to be(true)
22
+ end
23
+
24
+ it "must default #close_on_exec? to true" do
25
+ expect(subject.close_on_exec?).to be(true)
26
+ end
27
+
28
+ it "should set the file descriptor returned by io_open" do
29
+ expect(subject.fileno).to eq(3)
30
+ end
31
+
32
+ it "must set #pos to 0" do
33
+ expect(subject.pos).to eq(0)
34
+ end
35
+
36
+ it "must set #lineno to 0" do
37
+ expect(subject.lineno).to eq(0)
38
+ end
39
+
40
+ it "must set #eof to false" do
41
+ expect(subject.eof).to be(false)
42
+ end
43
+
44
+ it "must default #tty? to false" do
45
+ expect(subject.tty?).to be(false)
46
+ end
47
+
48
+ it "must default #pid to nil" do
49
+ expect(subject.pid).to be(nil)
50
+ end
51
+
52
+ it "must default #sync to false" do
53
+ expect(subject.sync).to be(false)
54
+ end
55
+
56
+ it "must default #external_encoding to Encoding.default_external" do
57
+ expect(subject.external_encoding).to eq(Encoding.default_external)
58
+ end
59
+ end
60
+
61
+ describe "#advise" do
62
+ it "must return nil" do
63
+ expect(subject.advise(:normal,0,0)).to be(nil)
64
+ end
65
+ end
66
+
67
+ describe "#autoclose=" do
68
+ let(:autoclose) { false }
69
+
70
+ before { subject.autoclose = autoclose }
71
+
72
+ it "must set #autoclose?" do
73
+ expect(subject.autoclose?).to be(autoclose)
74
+ end
75
+ end
76
+
77
+ describe "#autoclose?" do
78
+ it "must return true by default" do
79
+ expect(subject.autoclose?).to be(true)
80
+ end
81
+
82
+ context "when #autoclose= is set to false" do
83
+ before { subject.autoclose = false }
84
+
85
+ it "must return false" do
86
+ expect(subject.autoclose?).to be(false)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "#close_on_exec=" do
92
+ let(:close_on_exec) { false }
93
+
94
+ before { subject.close_on_exec = close_on_exec }
95
+
96
+ it "must set #close_on_exec?" do
97
+ expect(subject.close_on_exec?).to be(close_on_exec)
98
+ end
99
+ end
100
+
101
+ describe "#close_on_exec?" do
102
+ it "must return true by default" do
103
+ expect(subject.close_on_exec?).to be(true)
104
+ end
105
+
106
+ context "when #close_on_exec= is set to false" do
107
+ before { subject.close_on_exec = false }
108
+
109
+ it "must return false" do
110
+ expect(subject.close_on_exec?).to be(false)
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "#binmode" do
116
+ before { subject.binmode }
117
+
118
+ it "must cause #binmode? to return true" do
119
+ expect(subject.binmode?).to be(true)
120
+ end
121
+ end
122
+
123
+ describe "#binmode?" do
124
+ it "must return false by default" do
125
+ expect(subject.binmode?).to be(false)
126
+ end
127
+
128
+ context "when binmode is set" do
129
+ before { subject.binmode }
130
+
131
+ it "must return true" do
132
+ expect(subject.binmode?).to be(true)
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "#isatty" do
138
+ it "must return false by default" do
139
+ expect(subject.isatty).to be(false)
140
+ end
141
+ end
142
+
143
+ describe "#tty?" do
144
+ it "must return false by default" do
145
+ expect(subject.tty?).to be(false)
146
+ end
147
+ end
148
+
149
+ describe "#set_encoding" do
150
+ context "when given a single String" do
151
+ let(:string) { 'ASCII' }
152
+
153
+ before { subject.set_encoding(string) }
154
+
155
+ it "must set the #external_encoding" do
156
+ expect(subject.external_encoding).to eq(Encoding.find(string))
157
+ end
158
+
159
+ it "must not set the #internal_encoding" do
160
+ expect(subject.internal_encoding).to be(nil)
161
+ end
162
+
163
+ context "and the String contains a ':'" do
164
+ let(:ext_enc) { 'UTF-8' }
165
+ let(:int_enc) { 'ASCII' }
166
+ let(:string) { "#{ext_enc}:#{int_enc}" }
167
+
168
+ it "must set the #external_encoding" do
169
+ expect(subject.external_encoding).to eq(Encoding.find(ext_enc))
170
+ end
171
+
172
+ it "must set the #internal_encoding" do
173
+ expect(subject.internal_encoding).to eq(Encoding.find(int_enc))
174
+ end
175
+ end
176
+
177
+ context "and the String contains a ','" do
178
+ let(:ext_enc) { 'UTF-8' }
179
+ let(:int_enc) { 'ASCII' }
180
+ let(:string) { "#{ext_enc},#{int_enc}" }
181
+
182
+ it "must set the #external_encoding" do
183
+ expect(subject.external_encoding).to eq(Encoding.find(ext_enc))
184
+ end
185
+
186
+ it "must set the #internal_encoding" do
187
+ expect(subject.internal_encoding).to eq(Encoding.find(int_enc))
188
+ end
189
+ end
190
+ end
191
+
192
+ context "when given a single Encoding object" do
193
+ let(:encoding) { Encoding::ASCII }
194
+
195
+ before { subject.set_encoding(encoding) }
196
+
197
+ it "must set the #external_encoding" do
198
+ expect(subject.external_encoding).to eq(encoding)
199
+ end
200
+
201
+ it "must not set the #internal_encoding" do
202
+ expect(subject.internal_encoding).to be(nil)
203
+ end
204
+ end
205
+
206
+ context "when given two Encoding objects" do
207
+ let(:external_encoding) { Encoding::UTF_8 }
208
+ let(:internal_encoding) { Encoding::ASCII }
209
+
210
+ before { subject.set_encoding(external_encoding,internal_encoding) }
211
+
212
+ it "must set the #external_encoding" do
213
+ expect(subject.external_encoding).to eq(external_encoding)
214
+ end
215
+
216
+ it "must set the #internal_encoding" do
217
+ expect(subject.internal_encoding).to eq(internal_encoding)
218
+ end
219
+ end
220
+
221
+ context "when given another Object besides a String or an Encoding" do
222
+ it do
223
+ expect {
224
+ subject.set_encoding(Object.new)
225
+ }.to raise_error(TypeError,"argument must be a String or Encoding object")
226
+ end
227
+ end
228
+
229
+ context "when no arguments are given" do
230
+ it do
231
+ expect {
232
+ subject.set_encoding
233
+ }.to raise_error(ArgumentError,"wrong number of arguments (given 0, expected 1..3)")
234
+ end
235
+ end
236
+
237
+ context "when given more than three arguments" do
238
+ it do
239
+ expect {
240
+ subject.set_encoding(
241
+ Encoding::ASCII,
242
+ Encoding::ASCII,
243
+ Encoding::ASCII,
244
+ Encoding::ASCII
245
+ )
246
+ }.to raise_error(ArgumentError,"wrong number of arguments (given 4, expected 1..3)")
247
+ end
248
+ end
249
+ end
250
+
251
+ describe "#set_encoding_by_bom" do
252
+ class TestBOM
253
+
254
+ include FakeIO
255
+
256
+ def initialize(data)
257
+ @data = data
258
+ super()
259
+ end
260
+
261
+ private
262
+
263
+ def io_read
264
+ if (data = @data)
265
+ @data = nil
266
+ return data
267
+ else
268
+ raise(EOFError,"end of stream")
269
+ end
270
+ end
271
+
272
+ end
273
+
274
+ subject { TestBOM.new(data) }
275
+
276
+ before { subject.set_encoding_by_bom }
277
+
278
+ context "when the first byte is 0x00" do
279
+ context "and the second byte is 0x00" do
280
+ context "and the thrid byte is 0xFE" do
281
+ context "and the fourth byte is 0xFF" do
282
+ let(:data) do
283
+ "\x00\x00\xFE\xFFhello".force_encoding(Encoding::ASCII_8BIT)
284
+ end
285
+
286
+ let(:encoding) { Encoding::UTF_32BE }
287
+
288
+ it "must set #external_encoding to Encoding::UTF_32BE" do
289
+ expect(subject.external_encoding).to eq(encoding)
290
+ end
291
+
292
+ it "must consume the BOM bytes" do
293
+ expect(subject.read).to eq(
294
+ data.byteslice(4..).force_encoding(encoding)
295
+ )
296
+ end
297
+ end
298
+
299
+ context "but the fourth byte is not 0xFF" do
300
+ let(:data) do
301
+ "\x00\x00\xFEXhello".force_encoding(Encoding::ASCII_8BIT)
302
+ end
303
+
304
+ it "must not set #external_encoding" do
305
+ expect(subject.external_encoding).to be(
306
+ Encoding.default_external
307
+ )
308
+ end
309
+
310
+ it "must put the bytes back into the read buffer" do
311
+ expect(subject.read).to eq(
312
+ data.force_encoding(subject.external_encoding)
313
+ )
314
+ end
315
+ end
316
+
317
+ context "but EOF is reached" do
318
+ let(:data) do
319
+ "\x00\x00\xFE".force_encoding(Encoding::ASCII_8BIT)
320
+ end
321
+
322
+ it "must not set #external_encoding" do
323
+ expect(subject.external_encoding).to be(
324
+ Encoding.default_external
325
+ )
326
+ end
327
+
328
+ it "must put the bytes back into the read buffer" do
329
+ expect(subject.read).to eq(
330
+ data.force_encoding(subject.external_encoding)
331
+ )
332
+ end
333
+ end
334
+ end
335
+
336
+ context "but the third byte is not 0xFE" do
337
+ let(:data) do
338
+ "\x00\x00XXhello".force_encoding(Encoding::ASCII_8BIT)
339
+ end
340
+
341
+ it "must not set #external_encoding" do
342
+ expect(subject.external_encoding).to be(Encoding.default_external)
343
+ end
344
+
345
+ it "must put the bytes back into the read buffer" do
346
+ expect(subject.read).to eq(
347
+ data.force_encoding(subject.external_encoding)
348
+ )
349
+ end
350
+ end
351
+
352
+ context "but EOF is reached" do
353
+ let(:data) do
354
+ "\x00\x00".force_encoding(Encoding::ASCII_8BIT)
355
+ end
356
+
357
+ it "must not set #external_encoding" do
358
+ expect(subject.external_encoding).to be(Encoding.default_external)
359
+ end
360
+
361
+ it "must put the bytes back into the read buffer" do
362
+ expect(subject.read).to eq(
363
+ data.force_encoding(subject.external_encoding)
364
+ )
365
+ end
366
+ end
367
+ end
368
+
369
+ context "but the second byte is not 0x00" do
370
+ let(:data) do
371
+ "\x00XXXhello".force_encoding(Encoding::ASCII_8BIT)
372
+ end
373
+
374
+ it "must not set #external_encoding" do
375
+ expect(subject.external_encoding).to be(Encoding.default_external)
376
+ end
377
+
378
+ it "must put the bytes back into the read buffer" do
379
+ expect(subject.read).to eq(
380
+ data.force_encoding(subject.external_encoding)
381
+ )
382
+ end
383
+ end
384
+
385
+ context "but EOF is reached" do
386
+ let(:data) do
387
+ "\x00".force_encoding(Encoding::ASCII_8BIT)
388
+ end
389
+
390
+ it "must not set #external_encoding" do
391
+ expect(subject.external_encoding).to be(Encoding.default_external)
392
+ end
393
+
394
+ it "must put the bytes back into the read buffer" do
395
+ expect(subject.read).to eq(
396
+ data.force_encoding(subject.external_encoding)
397
+ )
398
+ end
399
+ end
400
+ end
401
+
402
+ context "but the first byte is not 0x00" do
403
+ let(:data) do
404
+ "XXXXhello".force_encoding(Encoding::ASCII_8BIT)
405
+ end
406
+
407
+ it "must not set #external_encoding" do
408
+ expect(subject.external_encoding).to be(Encoding.default_external)
409
+ end
410
+
411
+ it "must put the bytes back into the read buffer" do
412
+ expect(subject.read).to eq(
413
+ data.force_encoding(subject.external_encoding)
414
+ )
415
+ end
416
+ end
417
+
418
+ context "when the first byte is 0x28" do
419
+ context "and the second byte is 0x2F" do
420
+ context "and the third byte is 0x76" do
421
+ let(:data) do
422
+ "\x28\x2F\x76hello".force_encoding(Encoding::ASCII_8BIT)
423
+ end
424
+
425
+ let(:encoding) { Encoding::UTF_7 }
426
+
427
+ it "must set #external_encoding to Encoding::UTF_7" do
428
+ expect(subject.external_encoding).to eq(encoding)
429
+ end
430
+
431
+ it "must consume the BOM bytes" do
432
+ pending "Cannot convert from UTF-8 to UTF-7"
433
+
434
+ expect(subject.read).to eq(
435
+ data.byteslice(2..).force_encoding(encoding)
436
+ )
437
+ end
438
+ end
439
+
440
+ context "but the third byte is not 0x76" do
441
+ let(:data) do
442
+ "\x28\x2FXhello".force_encoding(Encoding::ASCII_8BIT)
443
+ end
444
+
445
+ it "must not set #external_encoding" do
446
+ expect(subject.external_encoding).to be(Encoding.default_external)
447
+ end
448
+
449
+ it "must put the bytes back into the read buffer" do
450
+ expect(subject.read).to eq(
451
+ data.force_encoding(subject.external_encoding)
452
+ )
453
+ end
454
+ end
455
+
456
+ context "but EOF is reached" do
457
+ let(:data) do
458
+ "\x28\x2F".force_encoding(Encoding::ASCII_8BIT)
459
+ end
460
+
461
+ it "must not set #external_encoding" do
462
+ expect(subject.external_encoding).to be(Encoding.default_external)
463
+ end
464
+
465
+ it "must put the bytes back into the read buffer" do
466
+ expect(subject.read).to eq(
467
+ data.force_encoding(subject.external_encoding)
468
+ )
469
+ end
470
+ end
471
+ end
472
+
473
+ context "but the second byte is not 0x2F" do
474
+ let(:data) do
475
+ "\x28XXhello".force_encoding(Encoding::ASCII_8BIT)
476
+ end
477
+
478
+ it "must not set #external_encoding" do
479
+ expect(subject.external_encoding).to be(Encoding.default_external)
480
+ end
481
+
482
+ it "must put the bytes back into the read buffer" do
483
+ expect(subject.read).to eq(
484
+ data.force_encoding(subject.external_encoding)
485
+ )
486
+ end
487
+ end
488
+
489
+ context "but EOF is reached" do
490
+ let(:data) do
491
+ "\x28".force_encoding(Encoding::ASCII_8BIT)
492
+ end
493
+
494
+ it "must not set #external_encoding" do
495
+ expect(subject.external_encoding).to be(Encoding.default_external)
496
+ end
497
+
498
+ it "must put the bytes back into the read buffer" do
499
+ expect(subject.read).to eq(
500
+ data.force_encoding(subject.external_encoding)
501
+ )
502
+ end
503
+ end
504
+ end
505
+
506
+ context "but the first byte is not 0x2F" do
507
+ let(:data) do
508
+ "XXXhello".force_encoding(Encoding::ASCII_8BIT)
509
+ end
510
+
511
+ it "must not set #external_encoding" do
512
+ expect(subject.external_encoding).to be(Encoding.default_external)
513
+ end
514
+
515
+ it "must put the bytes back into the read buffer" do
516
+ expect(subject.read).to eq(
517
+ data.force_encoding(subject.external_encoding)
518
+ )
519
+ end
520
+ end
521
+
522
+ context "when the first byte is 0xEF" do
523
+ context "and the second byte is 0xBB" do
524
+ context "and the third byte is 0xBF" do
525
+ let(:data) do
526
+ "\xEF\xBB\xBFhello".force_encoding(Encoding::ASCII_8BIT)
527
+ end
528
+
529
+ let(:encoding) { Encoding::UTF_8 }
530
+
531
+ it "must set #external_encoding to Encoding::UTF_8" do
532
+ expect(subject.external_encoding).to eq(encoding)
533
+ end
534
+
535
+ it "must consume the BOM bytes" do
536
+ expect(subject.read).to eq(
537
+ data.byteslice(3..).force_encoding(encoding)
538
+ )
539
+ end
540
+ end
541
+
542
+ context "but the third byte is not 0xBF" do
543
+ let(:data) do
544
+ "\xEF\xBBXhello".force_encoding(Encoding::ASCII_8BIT)
545
+ end
546
+
547
+ it "must not set #external_encoding" do
548
+ expect(subject.external_encoding).to be(Encoding.default_external)
549
+ end
550
+
551
+ it "must put the bytes back into the read buffer" do
552
+ expect(subject.read).to eq(
553
+ data.force_encoding(subject.external_encoding)
554
+ )
555
+ end
556
+ end
557
+
558
+ context "but EOF is reached" do
559
+ let(:data) do
560
+ "\xEF\xBB".force_encoding(Encoding::ASCII_8BIT)
561
+ end
562
+
563
+ it "must not set #external_encoding" do
564
+ expect(subject.external_encoding).to be(Encoding.default_external)
565
+ end
566
+
567
+ it "must put the bytes back into the read buffer" do
568
+ expect(subject.read).to eq(
569
+ data.force_encoding(subject.external_encoding)
570
+ )
571
+ end
572
+ end
573
+ end
574
+
575
+ context "but the second byte is not 0xBB" do
576
+ let(:data) do
577
+ "\xEFXXhello".force_encoding(Encoding::ASCII_8BIT)
578
+ end
579
+
580
+ it "must not set #external_encoding" do
581
+ expect(subject.external_encoding).to be(Encoding.default_external)
582
+ end
583
+
584
+ it "must put the bytes back into the read buffer" do
585
+ expect(subject.read).to eq(
586
+ data.force_encoding(subject.external_encoding)
587
+ )
588
+ end
589
+ end
590
+
591
+ context "but EOF is reached" do
592
+ let(:data) do
593
+ "\xEF".force_encoding(Encoding::ASCII_8BIT)
594
+ end
595
+
596
+ it "must not set #external_encoding" do
597
+ expect(subject.external_encoding).to be(Encoding.default_external)
598
+ end
599
+
600
+ it "must put the bytes back into the read buffer" do
601
+ expect(subject.read).to eq(
602
+ data.force_encoding(subject.external_encoding)
603
+ )
604
+ end
605
+ end
606
+ end
607
+
608
+ context "but the first byte is not 0xEF" do
609
+ let(:data) do
610
+ "XXXhello".force_encoding(Encoding::ASCII_8BIT)
611
+ end
612
+
613
+ it "must not set #external_encoding" do
614
+ expect(subject.external_encoding).to be(Encoding.default_external)
615
+ end
616
+
617
+ it "must put the bytes back into the read buffer" do
618
+ expect(subject.read).to eq(
619
+ data.force_encoding(subject.external_encoding)
620
+ )
621
+ end
622
+ end
623
+
624
+ context "when the first byte is 0xFE" do
625
+ context "and the second byte is 0xFF" do
626
+ let(:data) do
627
+ "\xFE\xFFhello".force_encoding(Encoding::ASCII_8BIT)
628
+ end
629
+
630
+ let(:encoding) { Encoding::UTF_16BE }
631
+
632
+ it "must set #external_encoding to Encoding::UTF_16BE" do
633
+ expect(subject.external_encoding).to eq(encoding)
634
+ end
635
+
636
+ it "must consume the BOM bytes" do
637
+ expect(subject.read).to eq(
638
+ data.byteslice(2..).force_encoding(encoding)
639
+ )
640
+ end
641
+ end
642
+
643
+ context "but the second byte is not 0xFF" do
644
+ let(:data) do
645
+ "\xFEXhello".force_encoding(Encoding::ASCII_8BIT)
646
+ end
647
+
648
+ it "must not set #external_encoding" do
649
+ expect(subject.external_encoding).to be(Encoding.default_external)
650
+ end
651
+
652
+ it "must put the bytes back into the read buffer" do
653
+ expect(subject.read).to eq(
654
+ data.force_encoding(subject.external_encoding)
655
+ )
656
+ end
657
+ end
658
+
659
+ context "but EOF is reached" do
660
+ let(:data) do
661
+ "\xFE".force_encoding(Encoding::ASCII_8BIT)
662
+ end
663
+
664
+ it "must not set #external_encoding" do
665
+ expect(subject.external_encoding).to be(Encoding.default_external)
666
+ end
667
+
668
+ it "must put the bytes back into the read buffer" do
669
+ expect(subject.read).to eq(
670
+ data.force_encoding(subject.external_encoding)
671
+ )
672
+ end
673
+ end
674
+ end
675
+
676
+ context "but the first byte is not 0xFE" do
677
+ let(:data) do
678
+ "XXhello".force_encoding(Encoding::ASCII_8BIT)
679
+ end
680
+
681
+ it "must not set #external_encoding" do
682
+ expect(subject.external_encoding).to be(Encoding.default_external)
683
+ end
684
+
685
+ it "must put the bytes back into the read buffer" do
686
+ expect(subject.read).to eq(
687
+ data.force_encoding(subject.external_encoding)
688
+ )
689
+ end
690
+ end
691
+
692
+ context "but EOF is reached" do
693
+ let(:data) do
694
+ "".force_encoding(Encoding::ASCII_8BIT)
695
+ end
696
+
697
+ it "must not set #external_encoding" do
698
+ expect(subject.external_encoding).to be(Encoding.default_external)
699
+ end
700
+ end
701
+
702
+ context "when the first byte is 0xFF" do
703
+ context "and the second byte is 0xFE" do
704
+ let(:data) do
705
+ "\xFF\xFEhello".force_encoding(Encoding::ASCII_8BIT)
706
+ end
707
+
708
+ let(:encoding) { Encoding::UTF_16LE }
709
+
710
+ it "must set #external_encoding to Encoding::UTF_16LE" do
711
+ expect(subject.external_encoding).to eq(encoding)
712
+ end
713
+
714
+ it "must consume the BOM bytes" do
715
+ expect(subject.read).to eq(
716
+ data.byteslice(2..).force_encoding(encoding)
717
+ )
718
+ end
719
+ end
720
+
721
+ context "but the second byte is not 0xFE" do
722
+ let(:data) do
723
+ "\xFFXhello".force_encoding(Encoding::ASCII_8BIT)
724
+ end
725
+
726
+ it "must not set #external_encoding" do
727
+ expect(subject.external_encoding).to be(Encoding.default_external)
728
+ end
729
+
730
+ it "must put the bytes back into the read buffer" do
731
+ expect(subject.read).to eq(
732
+ data.force_encoding(subject.external_encoding)
733
+ )
734
+ end
735
+ end
736
+
737
+ context "but EOF is reached" do
738
+ let(:data) do
739
+ "\xFF".force_encoding(Encoding::ASCII_8BIT)
740
+ end
741
+
742
+ it "must not set #external_encoding" do
743
+ expect(subject.external_encoding).to be(Encoding.default_external)
744
+ end
745
+
746
+ it "must put the bytes back into the read buffer" do
747
+ expect(subject.read).to eq(
748
+ data.force_encoding(subject.external_encoding)
749
+ )
750
+ end
751
+ end
752
+ end
753
+
754
+ context "but the first byte is not 0xFF" do
755
+ let(:data) do
756
+ "XXhello".force_encoding(Encoding::ASCII_8BIT)
757
+ end
758
+
759
+ it "must not set #external_encoding" do
760
+ expect(subject.external_encoding).to be(Encoding.default_external)
761
+ end
762
+
763
+ it "must put the bytes back into the read buffer" do
764
+ expect(subject.read).to eq(
765
+ data.force_encoding(subject.external_encoding)
766
+ )
767
+ end
768
+ end
769
+
770
+ context "but EOF is reached" do
771
+ let(:data) { "".force_encoding(Encoding::ASCII_8BIT) }
772
+
773
+ it "must not set #external_encoding" do
774
+ expect(subject.external_encoding).to be(Encoding.default_external)
775
+ end
776
+ end
777
+ end
778
+
779
+ describe "#each_chunk" do
780
+ it "should read each block of data" do
781
+ expect(subject.each_chunk.to_a).to eq(chunks)
782
+ end
783
+
784
+ it "must set the encoding of the String to Encoding.default_external" do
785
+ expect(subject.each_chunk.first.encoding).to eq(Encoding.default_external)
786
+ end
787
+
788
+ context "when #external_encoding diffs from Encoding.default_external" do
789
+ let(:external_encoding) { Encoding::ASCII_8BIT }
790
+
791
+ before { subject.external_encoding = external_encoding }
792
+
793
+ it "must set the encoding of the String to #external_encoding" do
794
+ expect(subject.each_chunk.first.encoding).to eq(subject.external_encoding)
795
+ end
796
+ end
797
+
798
+ it "must set #eof to true at the end" do
799
+ expect(subject.eof).to be(false)
800
+
801
+ subject.each_chunk { |chunk| }
802
+
803
+ expect(subject.eof).to be(true)
804
+ end
805
+
806
+ context "when #io_read raises an EOFError" do
807
+ it "must set #eof to true" do
808
+ allow(subject).to receive(:io_read).and_raise(EOFError)
809
+ expect(subject.eof).to be(false)
810
+
811
+ subject.each_chunk { |chunk| }
812
+
813
+ expect(subject.eof).to be(true)
814
+ end
815
+ end
816
+ end
817
+
818
+ describe "#read" do
819
+ context "when no length is given" do
820
+ it "should read all of the data" do
821
+ expect(subject.read).to eq(string)
822
+ end
823
+
824
+ it "must set the encoding of the String to Encoding.default_external" do
825
+ expect(subject.read.encoding).to eq(Encoding.default_external)
826
+ end
827
+
828
+ it "must advance #pos by the number of bytes read" do
829
+ previous_pos = subject.pos
830
+ read_data = subject.read
831
+
832
+ expect(subject.pos - previous_pos).to eq(read_data.bytesize)
833
+ end
834
+
835
+ context "when #external_encoding diffs from Encoding.default_external" do
836
+ let(:external_encoding) { Encoding::ASCII_8BIT }
837
+
838
+ before { subject.external_encoding = external_encoding }
839
+
840
+ it "must set the encoding of the String to #external_encoding" do
841
+ expect(subject.read.encoding).to eq(subject.external_encoding)
842
+ end
843
+ end
844
+
845
+ context "and when a buffer is also given" do
846
+ let(:buffer) { String.new }
847
+
848
+ it "must append the all read bytes to the buffer" do
849
+ subject.read(nil,buffer)
850
+
851
+ expect(buffer).to eq(string)
852
+ end
853
+ end
854
+ end
855
+
856
+ context "when a length is given" do
857
+ it "should read partial sections of the data" do
858
+ expect(subject.read(3)).to eq(string[0,3])
859
+ expect(subject.read(1)).to eq(string[3,1])
860
+ end
861
+
862
+ it "should read individual blocks of data" do
863
+ expect(subject.read(4)).to eq(string[0,4])
864
+ end
865
+
866
+ it "must advance #pos by the number of bytes read" do
867
+ previous_pos = subject.pos
868
+ length = 4
869
+ read_data = subject.read(length)
870
+
871
+ expect(subject.pos - previous_pos).to eq(length)
872
+ end
873
+
874
+ context "but the data is UTF-8" do
875
+ let(:chunks) { ["Σὲ ", "γνωρίζω ἀπὸ", " τὴν κόψη"] }
876
+
877
+ it "must read exactly N bytes, not N chars" do
878
+ expect(subject.read(1)).to eq(string.byteslice(0,1))
879
+ end
880
+ end
881
+
882
+ context "and when a buffer is also given" do
883
+ let(:buffer) { String.new }
884
+
885
+ it "must append the read bytes to the buffer" do
886
+ subject.read(3,buffer)
887
+ subject.read(1,buffer)
888
+
889
+ expect(buffer).to eq(string[0,3 + 1])
890
+ end
891
+ end
892
+ end
893
+ end
894
+
895
+ describe "#readpartial" do
896
+ let(:length) { 3 }
897
+
898
+ it "must read at most N bytes" do
899
+ expect(subject.readpartial(length).length).to eq(length)
900
+ end
901
+
902
+ it "must set the encoding of the String to Encoding.default_external" do
903
+ expect(subject.readpartial(length).encoding).to eq(Encoding.default_external)
904
+ end
905
+
906
+ context "when #external_encoding diffs from Encoding.default_external" do
907
+ let(:external_encoding) { Encoding::ASCII_8BIT }
908
+
909
+ before { subject.external_encoding = external_encoding }
910
+
911
+ it "must set the encoding of the String to #external_encoding" do
912
+ expect(subject.readpartial(length).encoding).to eq(subject.external_encoding)
913
+ end
914
+ end
915
+
916
+ context "when also given a buffer" do
917
+ let(:buffer) { String.new }
918
+
919
+ it "must append the read bytes to the buffer" do
920
+ subject.readpartial(length,buffer)
921
+ subject.readpartial(length,buffer)
922
+
923
+ expect(buffer).to eq(string[0,length * 2])
924
+ end
925
+ end
926
+ end
927
+
928
+ describe "#getbyte" do
929
+ it "should get byte" do
930
+ expect(subject.getbyte).to eq(bytes.first)
931
+ end
932
+ end
933
+
934
+ describe "#gets" do
935
+ it "should get a line" do
936
+ expect(subject.gets).to eq(lines.first)
937
+ end
938
+
939
+ it "must set the encoding of the String to Encoding.default_external" do
940
+ expect(subject.gets.encoding).to eq(Encoding.default_external)
941
+ end
942
+
943
+ context "when #external_encoding diffs from Encoding.default_external" do
944
+ let(:external_encoding) { Encoding::ASCII_8BIT }
945
+
946
+ before { subject.external_encoding = external_encoding }
947
+
948
+ it "must set the encoding of the String to #external_encoding" do
949
+ expect(subject.gets.encoding).to eq(subject.external_encoding)
950
+ end
951
+ end
952
+ end
953
+
954
+ describe "#readbyte" do
955
+ it "should read bytes" do
956
+ expect(subject.readbyte).to eq(bytes.first)
957
+ end
958
+ end
959
+
960
+ describe "#getc" do
961
+ it "should get a character" do
962
+ expect(subject.getc).to eq(chars.first)
963
+ end
964
+
965
+ it "must set the encoding of the String to Encoding.default_external" do
966
+ expect(subject.getc.encoding).to eq(Encoding.default_external)
967
+ end
968
+
969
+ context "when #external_encoding diffs from Encoding.default_external" do
970
+ let(:external_encoding) { Encoding::ASCII_8BIT }
971
+
972
+ before { subject.external_encoding = external_encoding }
973
+
974
+ it "must set the encoding of the String to #external_encoding" do
975
+ expect(subject.getc.encoding).to eq(subject.external_encoding)
976
+ end
977
+ end
978
+ end
979
+
980
+ describe "#readchar" do
981
+ it "should read a char" do
982
+ expect(subject.readchar).to eq(chars.first)
983
+ end
984
+
985
+ it "must set the encoding of the String to Encoding.default_external" do
986
+ expect(subject.readchar.encoding).to eq(Encoding.default_external)
987
+ end
988
+
989
+ context "when #external_encoding diffs from Encoding.default_external" do
990
+ let(:external_encoding) { Encoding::ASCII_8BIT }
991
+
992
+ before { subject.external_encoding = external_encoding }
993
+
994
+ it "must set the encoding of the String to #external_encoding" do
995
+ expect(subject.readchar.encoding).to eq(subject.external_encoding)
996
+ end
997
+ end
998
+ end
999
+
1000
+ describe "#ungetc" do
1001
+ it "should un-get characters back into the IO stream" do
1002
+ data = subject.read(4)
1003
+ data.each_char.reverse_each { |c| subject.ungetc(c) }
1004
+
1005
+ expect(subject.read(4)).to eq(data)
1006
+ end
1007
+
1008
+ it "must decrement #pos" do
1009
+ data = subject.read(4)
1010
+ previous_pos = subject.pos
1011
+ char = data.chars.last
1012
+
1013
+ subject.ungetc(char)
1014
+
1015
+ expect(previous_pos - subject.pos).to eq(char.bytesize)
1016
+ end
1017
+ end
1018
+
1019
+ describe "#readline" do
1020
+ it "should read a line" do
1021
+ expect(subject.readline).to eq(lines.first)
1022
+ end
1023
+
1024
+ it "must set the encoding of the String to Encoding.default_external" do
1025
+ expect(subject.readline.encoding).to eq(Encoding.default_external)
1026
+ end
1027
+
1028
+ context "when #external_encoding diffs from Encoding.default_external" do
1029
+ let(:external_encoding) { Encoding::ASCII_8BIT }
1030
+
1031
+ before { subject.external_encoding = external_encoding }
1032
+
1033
+ it "must set the encoding of the String to #external_encoding" do
1034
+ expect(subject.readline.encoding).to eq(subject.external_encoding)
1035
+ end
1036
+ end
1037
+ end
1038
+
1039
+ describe "#readlines" do
1040
+ it "should read all lines" do
1041
+ expect(subject.readlines).to eq(lines)
1042
+ end
1043
+
1044
+ it "must set the encoding of the String to Encoding.default_external" do
1045
+ expect(subject.readlines.map(&:encoding)).to all(eq(Encoding.default_external))
1046
+ end
1047
+
1048
+ context "when #external_encoding diffs from Encoding.default_external" do
1049
+ let(:external_encoding) { Encoding::ASCII_8BIT }
1050
+
1051
+ before { subject.external_encoding = external_encoding }
1052
+
1053
+ it "must set the encoding of the String to #external_encoding" do
1054
+ expect(subject.readlines.map(&:encoding)).to all(eq(subject.external_encoding))
1055
+ end
1056
+ end
1057
+ end
1058
+
1059
+ describe "#each_byte" do
1060
+ it "should read each byte of data" do
1061
+ expect(subject.each_byte.to_a).to eq(bytes)
1062
+ end
1063
+ end
1064
+
1065
+ describe "#each_char" do
1066
+ context "when a block is given" do
1067
+ it "must yield each read char of the data" do
1068
+ expect { |b|
1069
+ subject.each_char(&b)
1070
+ }.to yield_successive_args(*chars)
1071
+ end
1072
+ end
1073
+
1074
+ context "when no block is given" do
1075
+ it "must return an Enumerator that read each char of data" do
1076
+ expect(subject.each_char.to_a).to eq(chars)
1077
+ end
1078
+ end
1079
+
1080
+ it "must set the encoding of the String to Encoding.default_external" do
1081
+ expect(subject.each_char.map(&:encoding)).to all(eq(Encoding.default_external))
1082
+ end
1083
+
1084
+ context "when #external_encoding diffs from Encoding.default_external" do
1085
+ let(:external_encoding) { Encoding::ASCII_8BIT }
1086
+
1087
+ before { subject.external_encoding = external_encoding }
1088
+
1089
+ it "must set the encoding of the String to #external_encoding" do
1090
+ expect(subject.each_char.map(&:encoding)).to all(eq(subject.external_encoding))
1091
+ end
1092
+ end
1093
+ end
1094
+
1095
+ describe "#each_line" do
1096
+ it "should read each line of data" do
1097
+ expect(subject.each_line.to_a).to eq(lines)
1098
+ end
1099
+
1100
+ it "must set the encoding of the String to Encoding.default_external" do
1101
+ expect(subject.each_line.map(&:encoding)).to all(eq(Encoding.default_external))
1102
+ end
1103
+
1104
+ context "when #external_encoding diffs from Encoding.default_external" do
1105
+ let(:external_encoding) { Encoding::ASCII_8BIT }
1106
+
1107
+ before { subject.external_encoding = external_encoding }
1108
+
1109
+ it "must set the encoding of the String to #external_encoding" do
1110
+ expect(subject.each_line.map(&:encoding)).to all(eq(subject.external_encoding))
1111
+ end
1112
+ end
1113
+ end
1114
+
1115
+ describe "#write" do
1116
+ let(:data) { "foo" }
1117
+
1118
+ it "must call #io_write with the data" do
1119
+ expect(subject).to receive(:io_write).with(data)
1120
+
1121
+ subject.write(data)
1122
+ end
1123
+
1124
+ context "when the given data is not a String" do
1125
+ let(:data) { :foo }
1126
+
1127
+ it "must convert the data to a String before calling #io_write" do
1128
+ expect(subject).to receive(:io_write).with(data.to_s)
1129
+
1130
+ subject.write(data)
1131
+ end
1132
+ end
1133
+
1134
+ context "when #internal_encoding is not nil" do
1135
+ let(:internal_encoding) { Encoding::ASCII_8BIT }
1136
+ let(:encoded_data) { data.encode(internal_encoding) }
1137
+
1138
+ before { subject.internal_encoding = internal_encoding }
1139
+
1140
+ it "it must convert the given data to #internal_encoding before calling #io_write" do
1141
+ expect(data).to receive(:force_encoding).with(internal_encoding).and_return(encoded_data)
1142
+ expect(subject).to receive(:io_write).with(encoded_data)
1143
+
1144
+ subject.write(data)
1145
+ end
1146
+ end
1147
+
1148
+ context "when the object is not opened for writing" do
1149
+ before { subject.close_write }
1150
+
1151
+ it do
1152
+ expect {
1153
+ subject.write(data)
1154
+ }.to raise_error(IOError,"closed for writing")
1155
+ end
1156
+ end
1157
+ end
1158
+
1159
+ describe "#to_io" do
1160
+ it "must return self" do
1161
+ expect(subject.to_io).to be(subject)
1162
+ end
1163
+ end
1164
+
1165
+ describe "#inspect" do
1166
+ let(:fd) { subject.instance_variable_get('@fd') }
1167
+
1168
+ it "must return the inspected object as a string, including the @fd" do
1169
+ expect(subject.inspect).to eq("#<#{subject.class}: #{fd}>")
1170
+ end
1171
+ end
1172
+
1173
+ context "when running under Ruby 2.x" do
1174
+ if RUBY_VERSION < '3.'
1175
+ it "must define #bytes" do
1176
+ expect(subject).to respond_to(:bytes)
1177
+ end
1178
+
1179
+ it "must define #chars" do
1180
+ expect(subject).to respond_to(:chars)
1181
+ end
1182
+
1183
+ it "must define #codepoints" do
1184
+ expect(subject).to respond_to(:codepoints)
1185
+ end
1186
+
1187
+ it "must define #lines" do
1188
+ expect(subject).to respond_to(:lines)
1189
+ end
1190
+ end
1191
+ end
1192
+
1193
+ context "when running under Ruby 3.x" do
1194
+ if RUBY_VERSION > '3.'
1195
+ it "must not define #bytes" do
1196
+ expect(subject).to_not respond_to(:bytes)
1197
+ end
1198
+
1199
+ it "must not define #chars" do
1200
+ expect(subject).to_not respond_to(:chars)
1201
+ end
1202
+
1203
+ it "must not define #codepoints" do
1204
+ expect(subject).to_not respond_to(:codepoints)
1205
+ end
1206
+
1207
+ it "must not define #lines" do
1208
+ expect(subject).to_not respond_to(:lines)
1209
+ end
1210
+ end
1211
+ end
1212
+ end