1require_relative '../../spec_helper'
2require_relative 'fixtures/classes'
3
4describe "Array#[]=" do
5  it "sets the value of the element at index" do
6    a = [1, 2, 3, 4]
7    a[2] = 5
8    a[-1] = 6
9    a[5] = 3
10    a.should == [1, 2, 5, 6, nil, 3]
11
12    a = []
13    a[4] = "e"
14    a.should == [nil, nil, nil, nil, "e"]
15    a[3] = "d"
16    a.should == [nil, nil, nil, "d", "e"]
17    a[0] = "a"
18    a.should == ["a", nil, nil, "d", "e"]
19    a[-3] = "C"
20    a.should == ["a", nil, "C", "d", "e"]
21    a[-1] = "E"
22    a.should == ["a", nil, "C", "d", "E"]
23    a[-5] = "A"
24    a.should == ["A", nil, "C", "d", "E"]
25    a[5] = "f"
26    a.should == ["A", nil, "C", "d", "E", "f"]
27    a[1] = []
28    a.should == ["A", [], "C", "d", "E", "f"]
29    a[-1] = nil
30    a.should == ["A", [], "C", "d", "E", nil]
31  end
32
33  it "sets the section defined by [start,length] to other" do
34    a = [1, 2, 3, 4, 5, 6]
35    a[0, 1] = 2
36    a[3, 2] = ['a', 'b', 'c', 'd']
37    a.should == [2, 2, 3, "a", "b", "c", "d", 6]
38  end
39  it "replaces the section defined by [start,length] with the given values" do
40    a = [1, 2, 3, 4, 5, 6]
41    a[3, 2] = 'a', 'b', 'c', 'd'
42    a.should == [1, 2, 3, "a", "b", "c", "d", 6]
43  end
44
45  it "just sets the section defined by [start,length] to other even if other is nil" do
46    a = ['a', 'b', 'c', 'd', 'e']
47    a[1, 3] = nil
48    a.should == ["a", nil, "e"]
49  end
50
51  it "returns nil if the rhs is nil" do
52    a = [1, 2, 3]
53    (a[1, 3] = nil).should == nil
54    (a[1..3] = nil).should == nil
55  end
56
57  it "sets the section defined by range to other" do
58    a = [6, 5, 4, 3, 2, 1]
59    a[1...2] = 9
60    a[3..6] = [6, 6, 6]
61    a.should == [6, 9, 4, 6, 6, 6]
62  end
63
64  it "replaces the section defined by range with the given values" do
65    a = [6, 5, 4, 3, 2, 1]
66    a[3..6] = :a, :b, :c
67    a.should == [6, 5, 4, :a, :b, :c]
68  end
69
70  it "just sets the section defined by range to other even if other is nil" do
71    a = [1, 2, 3, 4, 5]
72    a[0..1] = nil
73    a.should == [nil, 3, 4, 5]
74  end
75
76  it 'expands and nil-pads the array if section assigned by range is outside array boundaries' do
77    a = ['a']
78    a[3..4] = ['b', 'c']
79    a.should == ['a', nil, nil, 'b', 'c']
80  end
81
82  it "calls to_int on its start and length arguments" do
83    obj = mock('to_int')
84    obj.stub!(:to_int).and_return(2)
85
86    a = [1, 2, 3, 4]
87    a[obj, 0] = [9]
88    a.should == [1, 2, 9, 3, 4]
89    a[obj, obj] = []
90    a.should == [1, 2, 4]
91    a[obj] = -1
92    a.should == [1, 2, -1]
93  end
94
95  it "checks frozen before attempting to coerce arguments" do
96    a = [1,2,3,4].freeze
97    lambda {a[:foo] = 1}.should raise_error(frozen_error_class)
98    lambda {a[:foo, :bar] = 1}.should raise_error(frozen_error_class)
99  end
100
101  it "sets elements in the range arguments when passed ranges" do
102    ary = [1, 2, 3]
103    rhs = [nil, [], ["x"], ["x", "y"]]
104    (0 .. ary.size + 2).each do |a|
105      (a .. ary.size + 3).each do |b|
106        rhs.each do |c|
107          ary1 = ary.dup
108          ary1[a .. b] = c
109          ary2 = ary.dup
110          ary2[a, 1 + b-a] = c
111          ary1.should == ary2
112
113          ary1 = ary.dup
114          ary1[a ... b] = c
115          ary2 = ary.dup
116          ary2[a, b-a] = c
117          ary1.should == ary2
118        end
119      end
120    end
121  end
122
123  it "inserts the given elements with [range] which the range is zero-width" do
124    ary = [1, 2, 3]
125    ary[1...1] = 0
126    ary.should == [1, 0, 2, 3]
127    ary[1...1] = [5]
128    ary.should == [1, 5, 0, 2, 3]
129    ary[1...1] = :a, :b, :c
130    ary.should == [1, :a, :b, :c, 5, 0, 2, 3]
131  end
132
133  it "inserts the given elements with [start, length] which length is zero" do
134    ary = [1, 2, 3]
135    ary[1, 0] = 0
136    ary.should == [1, 0, 2, 3]
137    ary[1, 0] = [5]
138    ary.should == [1, 5, 0, 2, 3]
139    ary[1, 0] = :a, :b, :c
140    ary.should == [1, :a, :b, :c, 5, 0, 2, 3]
141  end
142
143  # Now we only have to test cases where the start, length interface would
144  # have raise an exception because of negative size
145  it "inserts the given elements with [range] which the range has negative width" do
146    ary = [1, 2, 3]
147    ary[1..0] = 0
148    ary.should == [1, 0, 2, 3]
149    ary[1..0] = [4, 3]
150    ary.should == [1, 4, 3, 0, 2, 3]
151    ary[1..0] = :a, :b, :c
152    ary.should == [1, :a, :b, :c, 4, 3, 0, 2, 3]
153  end
154
155  it "just inserts nil if the section defined by range is zero-width and the rhs is nil" do
156    ary = [1, 2, 3]
157    ary[1...1] = nil
158    ary.should == [1, nil, 2, 3]
159  end
160
161  it "just inserts nil if the section defined by range has negative width and the rhs is nil" do
162    ary = [1, 2, 3]
163    ary[1..0] = nil
164    ary.should == [1, nil, 2, 3]
165  end
166
167  it "does nothing if the section defined by range is zero-width and the rhs is an empty array" do
168    ary = [1, 2, 3]
169    ary[1...1] = []
170    ary.should == [1, 2, 3]
171  end
172  it "does nothing if the section defined by range has negative width and the rhs is an empty array" do
173    ary = [1, 2, 3, 4, 5]
174    ary[1...0] = []
175    ary.should == [1, 2, 3, 4, 5]
176    ary[-2..2] = []
177    ary.should == [1, 2, 3, 4, 5]
178  end
179
180  it "tries to convert Range elements to Integers using #to_int with [m..n] and [m...n]" do
181    from = mock('from')
182    to = mock('to')
183
184    # So we can construct a range out of them...
185    def from.<=>(o) 0 end
186    def to.<=>(o) 0 end
187
188    def from.to_int() 1 end
189    def to.to_int() -2 end
190
191    a = [1, 2, 3, 4]
192
193    a[from .. to] = ["a", "b", "c"]
194    a.should == [1, "a", "b", "c", 4]
195
196    a[to .. from] = ["x"]
197    a.should == [1, "a", "b", "x", "c", 4]
198    lambda { a["a" .. "b"] = []  }.should raise_error(TypeError)
199    lambda { a[from .. "b"] = [] }.should raise_error(TypeError)
200  end
201
202  it "raises an IndexError when passed indexes out of bounds" do
203    a = [1, 2, 3, 4]
204    lambda { a[-5] = ""      }.should raise_error(IndexError)
205    lambda { a[-5, -1] = ""  }.should raise_error(IndexError)
206    lambda { a[-5, 0] = ""   }.should raise_error(IndexError)
207    lambda { a[-5, 1] = ""   }.should raise_error(IndexError)
208    lambda { a[-5, 2] = ""   }.should raise_error(IndexError)
209    lambda { a[-5, 10] = ""  }.should raise_error(IndexError)
210
211    lambda { a[-5..-5] = ""  }.should raise_error(RangeError)
212    lambda { a[-5...-5] = "" }.should raise_error(RangeError)
213    lambda { a[-5..-4] = ""  }.should raise_error(RangeError)
214    lambda { a[-5...-4] = "" }.should raise_error(RangeError)
215    lambda { a[-5..10] = ""  }.should raise_error(RangeError)
216    lambda { a[-5...10] = "" }.should raise_error(RangeError)
217
218    # ok
219    a[0..-9] = [1]
220    a.should == [1, 1, 2, 3, 4]
221  end
222
223  it "calls to_ary on its rhs argument for multi-element sets" do
224    obj = mock('to_ary')
225    def obj.to_ary() [1, 2, 3] end
226    ary = [1, 2]
227    ary[0, 0] = obj
228    ary.should == [1, 2, 3, 1, 2]
229    ary[1, 10] = obj
230    ary.should == [1, 1, 2, 3]
231  end
232
233  it "does not call to_ary on rhs array subclasses for multi-element sets" do
234    ary = []
235    ary[0, 0] = ArraySpecs::ToAryArray[5, 6, 7]
236    ary.should == [5, 6, 7]
237  end
238
239  it "raises a #{frozen_error_class} on a frozen array" do
240    lambda { ArraySpecs.frozen_array[0, 0] = [] }.should raise_error(frozen_error_class)
241  end
242end
243
244describe "Array#[]= with [index]" do
245  it "returns value assigned if idx is inside array" do
246    a = [1, 2, 3, 4, 5]
247    (a[3] = 6).should == 6
248  end
249
250  it "returns value assigned if idx is right beyond right array boundary" do
251    a = [1, 2, 3, 4, 5]
252    (a[5] = 6).should == 6
253  end
254
255  it "returns value assigned if idx far beyond right array boundary" do
256    a = [1, 2, 3, 4, 5]
257    (a[10] = 6).should == 6
258  end
259
260  it "sets the value of the element at index" do
261    a = [1, 2, 3, 4]
262    a[2] = 5
263    a[-1] = 6
264    a[5] = 3
265    a.should == [1, 2, 5, 6, nil, 3]
266  end
267
268  it "sets the value of the element if it is right beyond the array boundary" do
269    a = [1, 2, 3, 4]
270    a[4] = 8
271    a.should == [1, 2, 3, 4, 8]
272  end
273
274end
275
276describe "Array#[]= with [index, count]" do
277  it "returns non-array value if non-array value assigned" do
278    a = [1, 2, 3, 4, 5]
279    (a[2, 3] = 10).should == 10
280  end
281
282  it "returns array if array assigned" do
283    a = [1, 2, 3, 4, 5]
284    (a[2, 3] = [4, 5]).should == [4, 5]
285  end
286
287  it "just sets the section defined by [start,length] to nil even if the rhs is nil" do
288    a = ['a', 'b', 'c', 'd', 'e']
289    a[1, 3] = nil
290    a.should == ["a", nil, "e"]
291  end
292
293  it "just sets the section defined by [start,length] to nil if negative index within bounds, cnt > 0 and the rhs is nil" do
294    a = ['a', 'b', 'c', 'd', 'e']
295    a[-3, 2] = nil
296    a.should == ["a", "b", nil, "e"]
297  end
298
299  it "replaces the section defined by [start,length] to other" do
300    a = [1, 2, 3, 4, 5, 6]
301    a[0, 1] = 2
302    a[3, 2] = ['a', 'b', 'c', 'd']
303    a.should == [2, 2, 3, "a", "b", "c", "d", 6]
304  end
305
306  it "replaces the section to other if idx < 0 and cnt > 0" do
307    a = [1, 2, 3, 4, 5, 6]
308    a[-3, 2] = ["x", "y", "z"]
309    a.should == [1, 2, 3, "x", "y", "z", 6]
310  end
311
312  it "replaces the section to other even if cnt spanning beyond the array boundary" do
313    a = [1, 2, 3, 4, 5]
314    a[-1, 3] = [7, 8]
315    a.should == [1, 2, 3, 4, 7, 8]
316  end
317
318  it "pads the Array with nils if the span is past the end" do
319    a = [1, 2, 3, 4, 5]
320    a[10, 1] = [1]
321    a.should == [1, 2, 3, 4, 5, nil, nil, nil, nil, nil, 1]
322
323    b = [1, 2, 3, 4, 5]
324    b[10, 0] = [1]
325    a.should == [1, 2, 3, 4, 5, nil, nil, nil, nil, nil, 1]
326  end
327
328  it "inserts other section in place defined by idx" do
329    a = [1, 2, 3, 4, 5]
330    a[3, 0] = [7, 8]
331    a.should == [1, 2, 3, 7, 8, 4, 5]
332
333    b = [1, 2, 3, 4, 5]
334    b[1, 0] = b
335    b.should == [1, 1, 2, 3, 4, 5, 2, 3, 4, 5]
336  end
337
338  it "raises an IndexError when passed start and negative length" do
339    a = [1, 2, 3, 4]
340    lambda { a[-2, -1] = "" }.should raise_error(IndexError)
341    lambda { a[0, -1] = ""  }.should raise_error(IndexError)
342    lambda { a[2, -1] = ""  }.should raise_error(IndexError)
343    lambda { a[4, -1] = ""  }.should raise_error(IndexError)
344    lambda { a[10, -1] = "" }.should raise_error(IndexError)
345    lambda { [1, 2, 3, 4,  5][2, -1] = [7, 8] }.should raise_error(IndexError)
346  end
347end
348
349describe "Array#[]= with [m..n]" do
350  it "returns non-array value if non-array value assigned" do
351    a = [1, 2, 3, 4, 5]
352    (a[2..4] = 10).should == 10
353    (a.[]=(2..4, 10)).should == 10
354  end
355
356  it "returns array if array assigned" do
357    a = [1, 2, 3, 4, 5]
358    (a[2..4] = [7, 8]).should == [7, 8]
359    (a.[]=(2..4, [7, 8])).should == [7, 8]
360  end
361
362  it "just sets the section defined by range to nil even if the rhs is nil" do
363    a = [1, 2, 3, 4, 5]
364    a[0..1] = nil
365    a.should == [nil, 3, 4, 5]
366  end
367
368  it "just sets the section defined by range to nil if m and n < 0 and the rhs is nil" do
369    a = [1, 2, 3, 4, 5]
370    a[-3..-2] = nil
371    a.should == [1, 2, nil, 5]
372  end
373
374  it "replaces the section defined by range" do
375    a = [6, 5, 4, 3, 2, 1]
376    a[1...2] = 9
377    a[3..6] = [6, 6, 6]
378    a.should == [6, 9, 4, 6, 6, 6]
379  end
380
381  it "replaces the section if m and n < 0" do
382    a = [1, 2, 3, 4, 5]
383    a[-3..-2] = [7, 8, 9]
384    a.should == [1, 2, 7, 8, 9, 5]
385  end
386
387  it "replaces the section if m < 0 and n > 0" do
388    a = [1, 2, 3, 4, 5]
389    a[-4..3] = [8]
390    a.should == [1, 8, 5]
391  end
392
393  it "inserts the other section at m if m > n" do
394    a = [1, 2, 3, 4, 5]
395    a[3..1] = [8]
396    a.should == [1, 2, 3, 8, 4, 5]
397  end
398
399  describe "Range subclasses" do
400    before :each do
401      @range_incl = ArraySpecs::MyRange.new(1, 2)
402      @range_excl = ArraySpecs::MyRange.new(-3, -1, true)
403    end
404
405    it "accepts Range subclasses" do
406      a = [1, 2, 3, 4]
407
408      a[@range_incl] = ["a", "b"]
409      a.should == [1, "a", "b", 4]
410      a[@range_excl] = ["A", "B"]
411      a.should == [1, "A", "B", 4]
412    end
413
414    it "returns non-array value if non-array value assigned" do
415      a = [1, 2, 3, 4, 5]
416      (a[@range_incl] = 10).should == 10
417      (a.[]=(@range_incl, 10)).should == 10
418    end
419
420    it "returns array if array assigned" do
421      a = [1, 2, 3, 4, 5]
422      (a[@range_incl] = [7, 8]).should == [7, 8]
423      a.[]=(@range_incl, [7, 8]).should == [7, 8]
424    end
425  end
426end
427
428describe "Array#[] after a shift" do
429  it "works for insertion" do
430    a = [1,2]
431    a.shift
432    a.shift
433    a[0,0] = [3,4]
434    a.should == [3,4]
435  end
436end
437