diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..facf88a767 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.rbc diff --git a/1.8/core/array/allocate_spec.rb b/1.8/core/array/allocate_spec.rb new file mode 100644 index 0000000000..9518934185 --- /dev/null +++ b/1.8/core/array/allocate_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Array.allocate" do + it "returns an instance of Array" do + ary = Array.allocate + ary.should be_kind_of(Array) + end + + it "returns a fully-formed instance of Array" do + ary = Array.allocate + ary.size.should == 0 + ary << 1 + ary.should == [1] + end +end diff --git a/1.8/core/array/append_spec.rb b/1.8/core/array/append_spec.rb new file mode 100644 index 0000000000..f1482f68ea --- /dev/null +++ b/1.8/core/array/append_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#<<" do + it "pushes the object onto the end of the array" do + ([ 1, 2 ] << "c" << "d" << [ 3, 4 ]).should == [1, 2, "c", "d", [3, 4]] + end + + it "returns self to allow chaining" do + a = [] + b = a + (a << 1).equal?(b).should == true + (a << 2 << 3).equal?(b).should == true + end + + it "correctly resizes the Array" do + a = [] + a.size.should == 0 + a << :foo + a.size.should == 1 + a << :bar << :baz + a.size.should == 3 + + a = [1, 2, 3] + a.shift + a.shift + a.shift + a << :foo + a.should == [:foo] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array << 5 }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/array_spec.rb b/1.8/core/array/array_spec.rb new file mode 100644 index 0000000000..4479ae6b51 --- /dev/null +++ b/1.8/core/array/array_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Array" do + it "includes Enumerable" do + Array.ancestors.include?(Enumerable).should == true + end +end diff --git a/1.8/core/array/assoc_spec.rb b/1.8/core/array/assoc_spec.rb new file mode 100644 index 0000000000..a675f5030d --- /dev/null +++ b/1.8/core/array/assoc_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#assoc" do + it "returns the first array whose 1st item is == obj or nil" do + s1 = ["colors", "red", "blue", "green"] + s2 = [:letters, "a", "b", "c"] + s3 = [4] + s4 = [nil, nil] + a = [s1, s2, s3, s4] + a.assoc(s1.first).should == s1 + a.assoc(s2.first).should == s2 + a.assoc(s3.first).should == s3 + a.assoc(s4.first).should == s4 + a.assoc(4).should == [4] + a.assoc("key not in array").should == nil + end + + it "calls == on first element of each array" do + key1 = 'it' + key2 = mock('key2') + items = [['not it', 1], [ArraySpecs::AssocKey.new, 2], ['na', 3]] + + items.assoc(key1).should == items[1] + items.assoc(key2).should == nil + end + + it "ignores any non-Array elements" do + [1, 2, 3].assoc(2).should == nil + s1 = [4] + s2 = [5, 4, 3] + a = ["foo", [], s1, s2, nil, []] + a.assoc(s1.first).should == s1 + a.assoc(s2.first).should == s2 + end +end diff --git a/1.8/core/array/at_spec.rb b/1.8/core/array/at_spec.rb new file mode 100644 index 0000000000..0cd424f729 --- /dev/null +++ b/1.8/core/array/at_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#at" do + it "returns the element at index" do + a = [1, 2, 3, 4, 5, 6] + a.at(0).should == 1 + a.at(-2).should == 5 + a.at(10).should == nil + a.at(-7).should == nil + end + + it "calls to_int on its argument" do + a = ["a", "b", "c"] + a.at(0.5).should == "a" + + obj = mock('to_int') + obj.should_receive(:to_int).and_return(2) + a.at(obj).should == "c" + + obj = mock('method_missing to_int') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(2) + a.at(obj).should == "c" + end + + it "raises TypeError if its argument can't be coerced" do + a = ["a", "b", "c"] + + lambda { a.at("cat") }.should raise_error(TypeError) + end +end diff --git a/1.8/core/array/clear_spec.rb b/1.8/core/array/clear_spec.rb new file mode 100644 index 0000000000..99a173c739 --- /dev/null +++ b/1.8/core/array/clear_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#clear" do + it "removes all elements" do + a = [1, 2, 3, 4] + a.clear.equal?(a).should == true + a.should == [] + end + + it "returns self" do + a = [1] + oid = a.object_id + a.clear.object_id.should == oid + end + + it "leaves the Array empty" do + a = [1] + a.clear + a.empty?.should == true + a.size.should == 0 + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + a = [1] + a.freeze + lambda { a.clear }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/clone_spec.rb b/1.8/core/array/clone_spec.rb new file mode 100644 index 0000000000..80eecd8476 --- /dev/null +++ b/1.8/core/array/clone_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/clone' + +describe "Array#clone" do + it_behaves_like :array_clone, :clone + + not_compliant_on :rubinius do + it "copies frozen status from the original" do + a = [1, 2, 3, 4] + b = [1, 2, 3, 4] + a.freeze + aa = a.clone + bb = b.clone + + aa.frozen?.should == true + bb.frozen?.should == false + end + end +end diff --git a/1.8/core/array/collect_spec.rb b/1.8/core/array/collect_spec.rb new file mode 100644 index 0000000000..704aab7cee --- /dev/null +++ b/1.8/core/array/collect_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/collect' + +describe "Array#collect" do + it_behaves_like(:array_collect, :collect) +end + +describe "Array#collect!" do + it_behaves_like(:array_collect_b, :collect!) +end diff --git a/1.8/core/array/compact_spec.rb b/1.8/core/array/compact_spec.rb new file mode 100644 index 0000000000..87d784f6ee --- /dev/null +++ b/1.8/core/array/compact_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#compact" do + it "returns a copy of array with all nil elements removed" do + a = [1, 2, 4] + a.compact.should == [1, 2, 4] + a = [1, nil, 2, 4] + a.compact.should == [1, 2, 4] + a = [1, 2, 4, nil] + a.compact.should == [1, 2, 4] + a = [nil, 1, 2, 4] + a.compact.should == [1, 2, 4] + end + + it "returns subclass instance for Array subclasses" do + ArraySpecs::MyArray[1, 2, 3, nil].compact.class.should == ArraySpecs::MyArray + end +end + +describe "Array#compact!" do + it "removes all nil elements" do + a = ['a', nil, 'b', false, 'c'] + a.compact!.equal?(a).should == true + a.should == ["a", "b", false, "c"] + a = [nil, 'a', 'b', false, 'c'] + a.compact!.equal?(a).should == true + a.should == ["a", "b", false, "c"] + a = ['a', 'b', false, 'c', nil] + a.compact!.equal?(a).should == true + a.should == ["a", "b", false, "c"] + end + + it "returns nil if there are no nil elements to remove" do + [1, 2, false, 3].compact!.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.compact! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/comparison_spec.rb b/1.8/core/array/comparison_spec.rb new file mode 100644 index 0000000000..f53abb449f --- /dev/null +++ b/1.8/core/array/comparison_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#<=>" do + it "calls <=> left to right and return first non-0 result" do + [-1, +1, nil, "foobar"].each do |result| + lhs = Array.new(3) { mock("#{result}") } + rhs = Array.new(3) { mock("#{result}") } + + lhs[0].should_receive(:<=>).with(rhs[0]).and_return(0) + lhs[1].should_receive(:<=>).with(rhs[1]).and_return(result) + lhs[2].should_not_receive(:<=>) + + (lhs <=> rhs).should == result + end + end + + it "returns 0 if the arrays are equal" do + ([] <=> []).should == 0 + ([1, 2, 3, 4, 5, 6] <=> [1, 2, 3, 4, 5.0, 6.0]).should == 0 + end + + it "returns -1 if the array is shorter than the other array" do + ([] <=> [1]).should == -1 + ([1, 1] <=> [1, 1, 1]).should == -1 + end + + it "returns +1 if the array is longer than the other array" do + ([1] <=> []).should == +1 + ([1, 1, 1] <=> [1, 1]).should == +1 + end + + it "calls to_ary on its argument" do + obj = mock('to_ary') + def obj.to_ary() [1, 2, 3] end + ([4, 5] <=> obj).should == ([4, 5] <=> obj.to_ary) + + obj = mock('method_missing to_ary') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).and_return([4, 5]) + ([4, 5] <=> obj).should == 0 + end + + it "does not call to_ary on array subclasses" do + ([5, 6, 7] <=> ArraySpecs::ToAryArray[5, 6, 7]).should == 0 + end +end diff --git a/1.8/core/array/concat_spec.rb b/1.8/core/array/concat_spec.rb new file mode 100644 index 0000000000..26662d7e7d --- /dev/null +++ b/1.8/core/array/concat_spec.rb @@ -0,0 +1,42 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#concat" do + it "appends the elements in the other array" do + ary = [1, 2, 3] + ary.concat([9, 10, 11]).equal?(ary).should == true + ary.should == [1, 2, 3, 9, 10, 11] + ary.concat([]) + ary.should == [1, 2, 3, 9, 10, 11] + end + + it "does not loop endlessly when argument is self" do + ary = ["x", "y"] + ary.concat(ary).should == ["x", "y", "x", "y"] + end + + it "calls to_ary on its argument" do + obj = mock('to_ary') + def obj.to_ary() ["x", "y"] end + [4, 5, 6].concat(obj).should == [4, 5, 6, "x", "y"] + + obj = mock('method_missing to_ary') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).and_return([:x]) + [].concat(obj).should == [:x] + end + + it "does not call to_ary on array subclasses" do + [].concat(ArraySpecs::ToAryArray[5, 6, 7]).should == [5, 6, 7] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when Array is frozen and modification occurs" do + lambda { ArraySpecs.frozen_array.concat [1] }.should raise_error(TypeError) + end + + it "does not raise a TypeError when Array is frozen but no modification occurs" do + ArraySpecs.frozen_array.concat [] # ok, no modification + end + end +end diff --git a/1.8/core/array/constructor_spec.rb b/1.8/core/array/constructor_spec.rb new file mode 100644 index 0000000000..f065ec3f88 --- /dev/null +++ b/1.8/core/array/constructor_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array.[]" do + it "returns a new array populated with the given elements" do + Array.[](5, true, nil, 'a', "Ruby").should == [5, true, nil, "a", "Ruby"] + + a = ArraySpecs::MyArray.[](5, true, nil, 'a', "Ruby") + a.class.should == ArraySpecs::MyArray + a.inspect.should == [5, true, nil, "a", "Ruby"].inspect + end +end + +describe "Array[]" do + it "is a synonym for .[]" do + Array[5, true, nil, 'a', "Ruby"].should == Array.[](5, true, nil, "a", "Ruby") + + a = ArraySpecs::MyArray[5, true, nil, 'a', "Ruby"] + a.class.should == ArraySpecs::MyArray + a.inspect.should == [5, true, nil, "a", "Ruby"].inspect + end +end diff --git a/1.8/core/array/delete_at_spec.rb b/1.8/core/array/delete_at_spec.rb new file mode 100644 index 0000000000..715443a6e5 --- /dev/null +++ b/1.8/core/array/delete_at_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#delete_at" do + it "removes the element at the specified index" do + a = [1, 2, 3, 4] + a.delete_at(2) + a.should == [1, 2, 4] + a.delete_at(-1) + a.should == [1, 2] + end + + it "returns the removed element at the specified index" do + a = [1, 2, 3, 4] + a.delete_at(2).should == 3 + a.delete_at(-1).should == 4 + end + + it "returns nil and makes no modification if the index is out of range" do + a = [1, 2] + a.delete_at(3).should == nil + a.should == [1, 2] + a.delete_at(-3).should == nil + a.should == [1, 2] + end + + it "calls to_int on its argument" do + obj = mock('to_int') + def obj.to_int() -1 end + [1, 2].delete_at(obj).should == 2 + + obj = mock('method_missing to_int') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(-1) + [1, 2].delete_at(obj).should == 2 + end + + it "accepts negative indices" do + a = [1, 2] + a.delete_at(-2).should == 1 + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { [1,2,3].freeze.delete_at(0) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/delete_if_spec.rb b/1.8/core/array/delete_if_spec.rb new file mode 100644 index 0000000000..06671ecd11 --- /dev/null +++ b/1.8/core/array/delete_if_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#delete_if" do + it "removes each element for which block returns true" do + a = [ "a", "b", "c" ] + a.delete_if { |x| x >= "b" }.equal?(a).should == true + a.should == ["a"] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.delete_if {} }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/delete_spec.rb b/1.8/core/array/delete_spec.rb new file mode 100644 index 0000000000..7cecf52cd6 --- /dev/null +++ b/1.8/core/array/delete_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#delete" do + it "removes elements that are #== to object" do + x = mock('delete') + def x.==(other) 3 == other end + + a = [1, 2, 3, x, 4, 3, 5, x] + a.delete mock('not contained') + a.should == [1, 2, 3, x, 4, 3, 5, x] + + a.delete 3 + a.should == [1, 2, 4, 5] + end + + it "returns object or nil if no elements match object" do + [1, 2, 4, 5].delete(1).should == 1 + [1, 2, 4, 5].delete(3).should == nil + end + + it "may be given a block that is executed if no element matches object" do + [].delete('a') {:not_found}.should == :not_found + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array if a modification would take place" do + lambda { [1, 2, 3].freeze.delete(1) }.should raise_error(TypeError) + end + + it "returns false on a frozen array if a modification does not take place" do + [1, 2, 3].freeze.delete(0).should == nil + end + end +end diff --git a/1.8/core/array/dup_spec.rb b/1.8/core/array/dup_spec.rb new file mode 100644 index 0000000000..93b78f3d95 --- /dev/null +++ b/1.8/core/array/dup_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/clone' + +describe "Array#dup" do + it_behaves_like :array_clone, :dup # FIX: no, clone and dup are not alike + + it "should dup subclasses and return an instance of the subclass" do + a = [:array, [:lit, 1], [:lit, 2]] + b = ArraySpecs::Sexp.new << :array << [:lit, 1] << [:lit, 2] + + a.dup.should == a + b.dup.should == b + end +end diff --git a/1.8/core/array/each_index_spec.rb b/1.8/core/array/each_index_spec.rb new file mode 100644 index 0000000000..73430b27ad --- /dev/null +++ b/1.8/core/array/each_index_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#each_index" do + it "passes the index of each element to the block" do + a = [] + x = ['a', 'b', 'c', 'd'] + x.each_index { |i| a << i }.equal?(x).should == true + a.should == [0, 1, 2, 3] + end + + it "passes the index of each element to the block even if the array is changed during iteration" do + a = [] + x = [10, 11, 12, 13,] + x.each_index {|i| a << i; x << x[i]+5 if (x[i]%2).zero? }.equal?(x).should == true + a.should == [0, 1, 2, 3, 4, 5] + end + + it "passes the index from 0..size even if size changes" do + a = [] + x = [10, 11, 12, 13, 14] + x.each_index {|i| a << i; x.pop if (x[i]%2).zero? }.equal?(x).should == true + a.should == [0, 1, 2] + + a = [] + x = [10, 11, 12, 13, 14] + x.each_index {|i| a << i; x.shift if (x[i]%2).zero? }.equal?(x).should == true + a.should == [0, 1, 2] + end +end diff --git a/1.8/core/array/each_spec.rb b/1.8/core/array/each_spec.rb new file mode 100644 index 0000000000..030a479645 --- /dev/null +++ b/1.8/core/array/each_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#each" do + it "yields each element to the block" do + a = [] + x = [1, 2, 3] + x.each { |item| a << item }.equal?(x).should == true + a.should == [1, 2, 3] + end + + it "yields each element to the block even if the array is changed during iteration" do + a = [1, 2, 3, 4, 5] + b = [] + a.each {|x| b << x; a << x+5 if (x%2).zero? } + b.should == [1, 2, 3, 4, 5, 7, 9] + end + + it "yields only elements that are still in the array" do + a = [0, 1, 2, 3, 4] + b = [] + a.each {|x| b << x; a.pop if (x%2).zero? } + b.should == [0, 1, 2] + end + + it "yields elements based on an internal index" do + a = [0, 1, 2, 3, 4] + b = [] + a.each {|x| b << x; a.shift if (x%2).zero? } + b.should == [0, 2, 4] + end + + it "yields each element to a block that takes multiple arguments" do + a = [[1, 2], :a, [3, 4]] + b = [] + + a.each { |x, y| b << x } + b.should == [1, :a, 3] + + b = [] + a.each { |x, y| b << y } + b.should == [2, nil, 4] + end +end diff --git a/1.8/core/array/element_reference_spec.rb b/1.8/core/array/element_reference_spec.rb new file mode 100644 index 0000000000..b3771ba490 --- /dev/null +++ b/1.8/core/array/element_reference_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/slice' + +describe "Array#[]" do + it_behaves_like(:array_slice, :[]) +end + +describe "Array.[]" do + it "[] should return a new array populated with the given elements" do + array = Array[1, 'a', nil] + array[0].should == 1 + array[1].should == 'a' + array[2].should == nil + end + + it "when applied to a literal nested array, unpacks its elements into the containing array" do + Array[1, 2, *[3, 4, 5]].should == [1, 2, 3, 4, 5] + end + + it "when applied to a nested referenced array, unpacks its elements into the containing array" do + splatted_array = Array[3, 4, 5] + Array[1, 2, *splatted_array].should == [1, 2, 3, 4, 5] + end +end diff --git a/1.8/core/array/element_set_spec.rb b/1.8/core/array/element_set_spec.rb new file mode 100644 index 0000000000..e52965b010 --- /dev/null +++ b/1.8/core/array/element_set_spec.rb @@ -0,0 +1,468 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#[]=" do + it "sets the value of the element at index" do + a = [1, 2, 3, 4] + a[2] = 5 + a[-1] = 6 + a[5] = 3 + a.should == [1, 2, 5, 6, nil, 3] + + a = [] + a[4] = "e" + a.should == [nil, nil, nil, nil, "e"] + a[3] = "d" + a.should == [nil, nil, nil, "d", "e"] + a[0] = "a" + a.should == ["a", nil, nil, "d", "e"] + a[-3] = "C" + a.should == ["a", nil, "C", "d", "e"] + a[-1] = "E" + a.should == ["a", nil, "C", "d", "E"] + a[-5] = "A" + a.should == ["A", nil, "C", "d", "E"] + a[5] = "f" + a.should == ["A", nil, "C", "d", "E", "f"] + a[1] = [] + a.should == ["A", [], "C", "d", "E", "f"] + a[-1] = nil + a.should == ["A", [], "C", "d", "E", nil] + end + + it "removes the section defined by start, length when set to nil" do + a = ['a', 'b', 'c', 'd', 'e'] + a[1, 3] = nil + a.should == ["a", "e"] + end + + it "sets the section defined by start, length to other" do + a = [1, 2, 3, 4, 5, 6] + a[0, 1] = 2 + a[3, 2] = ['a', 'b', 'c', 'd'] + a.should == [2, 2, 3, "a", "b", "c", "d", 6] + end + + it "removes the section defined by range when set to nil" do + a = [1, 2, 3, 4, 5] + a[0..1] = nil + a.should == [3, 4, 5] + end + + it "sets the section defined by range to other" do + a = [6, 5, 4, 3, 2, 1] + a[1...2] = 9 + a[3..6] = [6, 6, 6] + a.should == [6, 9, 4, 6, 6, 6] + end + + it "calls to_int on its start and length arguments" do + obj = mock('2') + def obj.to_int() 2 end + + a = [1, 2, 3, 4] + a[obj, 0] = [9] + a.should == [1, 2, 9, 3, 4] + a[obj, obj] = [] + a.should == [1, 2, 4] + a[obj] = -1 + a.should == [1, 2, -1] + end + + it "sets elements in the range arguments when passed ranges" do + ary = [1, 2, 3] + rhs = [nil, [], ["x"], ["x", "y"]] + (0 .. ary.size + 2).each do |a| + (a .. ary.size + 3).each do |b| + rhs.each do |c| + ary1 = ary.dup + ary1[a .. b] = c + ary2 = ary.dup + ary2[a, 1 + b-a] = c + ary1.should == ary2 + + ary1 = ary.dup + ary1[a ... b] = c + ary2 = ary.dup + ary2[a, b-a] = c + ary1.should == ary2 + end + end + end + + # Now we only have to test cases where the start, length interface would + # have raise an exception because of negative size + ary[1...1] = [5] + ary.should == [1, 5, 2, 3] + ary[1..0] = [4, 3] + ary.should == [1, 4, 3, 5, 2, 3] + ary[-1..0] = nil + ary.should == [1, 4, 3, 5, 2, 3] + ary[-3..2] = [] + ary.should == [1, 4, 3, 5, 2, 3] + ary[4..2] = [] + ary.should == [1, 4, 3, 5, 2, 3] + end + + it "calls to_int on range arguments" do + from = mock('from') + to = mock('to') + + # So we can construct a range out of them... + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + def from.to_int() 1 end + def to.to_int() -2 end + + a = [1, 2, 3, 4] + + a[from .. to] = ["a", "b", "c"] + a.should == [1, "a", "b", "c", 4] + + a[to .. from] = ["x"] + a.should == [1, "a", "b", "x", "c", 4] + lambda { a["a" .. "b"] = [] }.should raise_error(TypeError) + lambda { a[from .. "b"] = [] }.should raise_error(TypeError) + + from = mock('from') + to = mock('to') + + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + from.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + from.should_receive(:method_missing).with(:to_int).and_return(1) + to.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + to.should_receive(:method_missing).with(:to_int).and_return(-2) + + a = [1, 2, 3, 4] + a[from .. to] = ["a", "b", "c"] + end + + it "raises an IndexError when passed indexes out of bounds" do + a = [1, 2, 3, 4] + lambda { a[-5] = "" }.should raise_error(IndexError) + lambda { a[-5, -1] = "" }.should raise_error(IndexError) + lambda { a[-5, 0] = "" }.should raise_error(IndexError) + lambda { a[-5, 1] = "" }.should raise_error(IndexError) + lambda { a[-5, 2] = "" }.should raise_error(IndexError) + lambda { a[-5, 10] = "" }.should raise_error(IndexError) + + lambda { a[-5..-5] = "" }.should raise_error(RangeError) + lambda { a[-5...-5] = "" }.should raise_error(RangeError) + lambda { a[-5..-4] = "" }.should raise_error(RangeError) + lambda { a[-5...-4] = "" }.should raise_error(RangeError) + lambda { a[-5..10] = "" }.should raise_error(RangeError) + lambda { a[-5...10] = "" }.should raise_error(RangeError) + + # ok + a[0..-9] = [1] + a.should == [1, 1, 2, 3, 4] + end + + it "calls to_ary on its rhs argument for multi-element sets" do + obj = mock('to_ary') + def obj.to_ary() [1, 2, 3] end + ary = [1, 2] + ary[0, 0] = obj + ary.should == [1, 2, 3, 1, 2] + ary[1, 10] = obj + ary.should == [1, 1, 2, 3] + end + + it "does not call to_ary on rhs array subclasses for multi-element sets" do + ary = [] + ary[0, 0] = ArraySpecs::ToAryArray[5, 6, 7] + ary.should == [5, 6, 7] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array[0, 0] = [] }.should raise_error(TypeError) + end + end +end + +describe "Array#[]= with [index]" do + it "returns value assigned if idx is inside array" do + a = [1, 2, 3, 4, 5] + (a[3] = 6).should == 6 + end + + it "returns value assigned if idx is right beyond right array boundary" do + a = [1, 2, 3, 4, 5] + (a[5] = 6).should == 6 + end + + it "returns value assigned if idx far beyond right array boundary" do + a = [1, 2, 3, 4, 5] + (a[10] = 6).should == 6 + end + + it "sets the value of the element at index" do + a = [1, 2, 3, 4] + a[2] = 5 + a[-1] = 6 + a[5] = 3 + a.should == [1, 2, 5, 6, nil, 3] + end + + it "sets the value of the element if it is right beyond the array boundary" do + a = [1, 2, 3, 4] + a[4] = 8 + a.should == [1, 2, 3, 4, 8] + end + +end + +describe "Array#[]= with [index, count]" do + it "returns non-array value if non-array value assigned" do + a = [1, 2, 3, 4, 5] + (a[2, 3] = 10).should == 10 + end + + it "returns array if array assigned" do + a = [1, 2, 3, 4, 5] + (a[2, 3] = [4, 5]).should == [4, 5] + end + + it "removes the section defined by start, length when set to nil" do + a = ['a', 'b', 'c', 'd', 'e'] + a[1, 3] = nil + a.should == ["a", "e"] + end + + it "removes the section when set to nil if negative index within bounds and cnt > 0" do + a = ['a', 'b', 'c', 'd', 'e'] + a[-3, 2] = nil + a.should == ["a", "b", "e"] + end + + it "replaces the section defined by start, length to other" do + a = [1, 2, 3, 4, 5, 6] + a[0, 1] = 2 + a[3, 2] = ['a', 'b', 'c', 'd'] + a.should == [2, 2, 3, "a", "b", "c", "d", 6] + end + + it "replaces the section to other if idx < 0 and cnt > 0" do + a = [1, 2, 3, 4, 5, 6] + a[-3, 2] = ["x", "y", "z"] + a.should == [1, 2, 3, "x", "y", "z", 6] + end + + it "replaces the section to other even if cnt spanning beyond the array boundary" do + a = [1, 2, 3, 4, 5] + a[-1, 3] = [7, 8] + a.should == [1, 2, 3, 4, 7, 8] + end + + it "pads the Array with nils if the span is past the end" do + a = [1, 2, 3, 4, 5] + a[10, 1] = [1] + a.should == [1, 2, 3, 4, 5, nil, nil, nil, nil, nil, 1] + + b = [1, 2, 3, 4, 5] + b[10, 0] = [1] + a.should == [1, 2, 3, 4, 5, nil, nil, nil, nil, nil, 1] + end + + it "inserts other section in place defined by idx" do + a = [1, 2, 3, 4, 5] + a[3, 0] = [7, 8] + a.should == [1, 2, 3, 7, 8, 4, 5] + + b = [1, 2, 3, 4, 5] + b[1, 0] = b + b.should == [1, 1, 2, 3, 4, 5, 2, 3, 4, 5] + end + + it "raises an IndexError when passed start and negative length" do + a = [1, 2, 3, 4] + lambda { a[-2, -1] = "" }.should raise_error(IndexError) + lambda { a[0, -1] = "" }.should raise_error(IndexError) + lambda { a[2, -1] = "" }.should raise_error(IndexError) + lambda { a[4, -1] = "" }.should raise_error(IndexError) + lambda { a[10, -1] = "" }.should raise_error(IndexError) + lambda { [1, 2, 3, 4, 5][2, -1] = [7, 8] }.should raise_error(IndexError) + end + + it "sets elements when passed start, length" do + a = []; a[0, 0] = nil; a.should == [] + a = []; a[2, 0] = nil; a.should == [nil, nil] + a = []; a[0, 2] = nil; a.should == [] + a = []; a[2, 2] = nil; a.should == [nil, nil] + + a = []; a[0, 0] = []; a.should == [] + a = []; a[2, 0] = []; a.should == [nil, nil] + a = []; a[0, 2] = []; a.should == [] + a = []; a[2, 2] = []; a.should == [nil, nil] + + a = []; a[0, 0] = ["a"]; a.should == ["a"] + a = []; a[2, 0] = ["a"]; a.should == [nil, nil, "a"] + a = []; a[0, 2] = ["a"]; a.should == ["a"] + a = []; a[2, 2] = ["a"]; a.should == [nil, nil, "a"] + + a = []; a[0, 0] = ["a","b"]; a.should == ["a", "b"] + a = []; a[2, 0] = ["a","b"]; a.should == [nil, nil, "a", "b"] + a = []; a[0, 2] = ["a","b"]; a.should == ["a", "b"] + a = []; a[2, 2] = ["a","b"]; a.should == [nil, nil, "a", "b"] + + a = []; a[0, 0] = ["a","b","c"]; a.should == ["a", "b", "c"] + a = []; a[2, 0] = ["a","b","c"]; a.should == [nil, nil, "a", "b", "c"] + a = []; a[0, 2] = ["a","b","c"]; a.should == ["a", "b", "c"] + a = []; a[2, 2] = ["a","b","c"]; a.should == [nil, nil, "a", "b", "c"] + + a = [1, 2, 3, 4] + a[0, 0] = []; a.should == [1, 2, 3, 4] + a[1, 0] = []; a.should == [1, 2, 3, 4] + a[-1,0] = []; a.should == [1, 2, 3, 4] + + a = [1, 2, 3, 4] + a[0, 0] = [8, 9, 9]; a.should == [8, 9, 9, 1, 2, 3, 4] + a = [1, 2, 3, 4] + a[1, 0] = [8, 9, 9]; a.should == [1, 8, 9, 9, 2, 3, 4] + a = [1, 2, 3, 4] + a[-1,0] = [8, 9, 9]; a.should == [1, 2, 3, 8, 9, 9, 4] + a = [1, 2, 3, 4] + a[4, 0] = [8, 9, 9]; a.should == [1, 2, 3, 4, 8, 9, 9] + + a = [1, 2, 3, 4] + a[0, 1] = [9]; a.should == [9, 2, 3, 4] + a[1, 1] = [8]; a.should == [9, 8, 3, 4] + a[-1,1] = [7]; a.should == [9, 8, 3, 7] + a[4, 1] = [9]; a.should == [9, 8, 3, 7, 9] + + a = [1, 2, 3, 4] + a[0, 1] = [8, 9]; a.should == [8, 9, 2, 3, 4] + a = [1, 2, 3, 4] + a[1, 1] = [8, 9]; a.should == [1, 8, 9, 3, 4] + a = [1, 2, 3, 4] + a[-1,1] = [8, 9]; a.should == [1, 2, 3, 8, 9] + a = [1, 2, 3, 4] + a[4, 1] = [8, 9]; a.should == [1, 2, 3, 4, 8, 9] + + a = [1, 2, 3, 4] + a[0, 2] = [8, 9]; a.should == [8, 9, 3, 4] + a = [1, 2, 3, 4] + a[1, 2] = [8, 9]; a.should == [1, 8, 9, 4] + a = [1, 2, 3, 4] + a[-2,2] = [8, 9]; a.should == [1, 2, 8, 9] + a = [1, 2, 3, 4] + a[-1,2] = [8, 9]; a.should == [1, 2, 3, 8, 9] + a = [1, 2, 3, 4] + a[4, 2] = [8, 9]; a.should == [1, 2, 3, 4, 8, 9] + + a = [1, 2, 3, 4] + a[0, 2] = [7, 8, 9]; a.should == [7, 8, 9, 3, 4] + a = [1, 2, 3, 4] + a[1, 2] = [7, 8, 9]; a.should == [1, 7, 8, 9, 4] + a = [1, 2, 3, 4] + a[-2,2] = [7, 8, 9]; a.should == [1, 2, 7, 8, 9] + a = [1, 2, 3, 4] + a[-1,2] = [7, 8, 9]; a.should == [1, 2, 3, 7, 8, 9] + a = [1, 2, 3, 4] + a[4, 2] = [7, 8, 9]; a.should == [1, 2, 3, 4, 7, 8, 9] + + a = [1, 2, 3, 4] + a[0, 2] = [1, 1.25, 1.5, 1.75, 2] + a.should == [1, 1.25, 1.5, 1.75, 2, 3, 4] + a[1, 1] = a[3, 1] = [] + a.should == [1, 1.5, 2, 3, 4] + a[0, 2] = [1] + a.should == [1, 2, 3, 4] + a[5, 0] = [4, 3, 2, 1] + a.should == [1, 2, 3, 4, nil, 4, 3, 2, 1] + a[-2, 5] = nil + a.should == [1, 2, 3, 4, nil, 4, 3] + a[-2, 5] = [] + a.should == [1, 2, 3, 4, nil] + a[0, 2] = nil + a.should == [3, 4, nil] + a[0, 100] = [1, 2, 3] + a.should == [1, 2, 3] + a[0, 2] *= 2 + a.should == [1, 2, 1, 2, 3] + a[0, 2] |= [2, 3, 4] + a.should == [1, 2, 3, 4, 1, 2, 3] + a[2, 0] += [3, 2, 2] + a.should == [1, 2, 3, 2, 2, 3, 4, 1, 2, 3] + a[0, 4] -= [2, 3] + a.should == [1, 2, 3, 4, 1, 2, 3] + a[0, 6] &= [4] + a.should == [4, 3] + end + +end + +describe "Array#[]= with [m..n]" do + it "returns non-array value if non-array value assigned" do + a = [1, 2, 3, 4, 5] + (a[2..4] = 10).should == 10 + end + + it "returns array if array assigned" do + a = [1, 2, 3, 4, 5] + (a[2..4] = [7, 8]).should == [7, 8] + end + + it "removes the section defined by range when set to nil" do + a = [1, 2, 3, 4, 5] + a[0..1] = nil + a.should == [3, 4, 5] + end + + it "removes the section when set to nil if m and n < 0" do + a = [1, 2, 3, 4, 5] + a[-3..-2] = nil + a.should == [1, 2, 5] + end + + it "replaces the section defined by range" do + a = [6, 5, 4, 3, 2, 1] + a[1...2] = 9 + a[3..6] = [6, 6, 6] + a.should == [6, 9, 4, 6, 6, 6] + end + + it "replaces the section if m and n < 0" do + a = [1, 2, 3, 4, 5] + a[-3..-2] = [7, 8, 9] + a.should == [1, 2, 7, 8, 9, 5] + end + + it "replaces the section if m < 0 and n > 0" do + a = [1, 2, 3, 4, 5] + a[-4..3] = [8] + a.should == [1, 8, 5] + end + + it "inserts the other section at m if m > n" do + a = [1, 2, 3, 4, 5] + a[3..1] = [8] + a.should == [1, 2, 3, 8, 4, 5] + end + + it "accepts Range subclasses" do + a = [1, 2, 3, 4] + range_incl = ArraySpecs::MyRange.new(1, 2) + range_excl = ArraySpecs::MyRange.new(-3, -1, true) + + a[range_incl] = ["a", "b"] + a.should == [1, "a", "b", 4] + a[range_excl] = ["A", "B"] + a.should == [1, "A", "B", 4] + end +end + +describe "Array#[] after a shift" do + it "works for insertion" do + a = [1,2] + a.shift + a.shift + a[0,0] = [3,4] + a.should == [3,4] + end +end + diff --git a/1.8/core/array/empty_spec.rb b/1.8/core/array/empty_spec.rb new file mode 100644 index 0000000000..c025e25977 --- /dev/null +++ b/1.8/core/array/empty_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#empty?" do + it "returns true if the array has no elements" do + [].empty?.should == true + [1].empty?.should == false + [1, 2].empty?.should == false + end +end diff --git a/1.8/core/array/eql_spec.rb b/1.8/core/array/eql_spec.rb new file mode 100644 index 0000000000..858abbf945 --- /dev/null +++ b/1.8/core/array/eql_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#eql?" do + it "returns true if other is the same array" do + a, b = [1], [2] + + a.eql?(b).should == false + a.eql?(a).should == true + end + + it "returns true if other has the same length and elements" do + a = [1, 2, 3, 4] + b = [1, 2, 3, 4] + c = [1, 2] + d = ['a', 'b', 'c', 'd'] + + a.eql?(b).should == true + a.eql?(c).should == false + a.eql?(d).should == false + [].eql?([]).should == true + end + + it "ignores array class differences" do + ArraySpecs::MyArray[1, 2, 3].eql?([1, 2, 3]).should == true + ArraySpecs::MyArray[1, 2, 3].eql?(ArraySpecs::MyArray[1, 2, 3]).should == true + [1, 2, 3].eql?(ArraySpecs::MyArray[1, 2, 3]).should == true + end +end diff --git a/1.8/core/array/equal_value_spec.rb b/1.8/core/array/equal_value_spec.rb new file mode 100644 index 0000000000..a2e46720ae --- /dev/null +++ b/1.8/core/array/equal_value_spec.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#==" do + it "returns true if each element is == to the corresponding element in the other array" do + [].should == [] + ["a", "c", 7].should == ["a", "c", 7] + + obj = mock('5') + def obj.==(other) true end + [obj].should == [5] + end + + it "returns false if any element is not == to the corresponding element in the other the array" do + ([ "a", "c" ] == [ "a", "c", 7 ]).should == false + end + + it "returns false immediately when sizes of the arrays differ" do + obj = mock('1') + obj.should_not_receive(:==) + + [].should_not == [obj] + [obj].should_not == [] + end + + # Broken in MRI as well. See MRI bug #11585: + # http://rubyforge.org/tracker/index.php?func=detail&aid=11585&group_id=426&atid=1698 + compliant_on(:r19) do + it "calls to_ary on its argument" do + obj = mock('to_ary') + obj.should_receive(:to_ary).and_return([1, 2, 3]) + + [1, 2, 3].should == obj + end + end + + it "does not call to_ary on array subclasses" do + [5, 6, 7].should == ArraySpecs::ToAryArray[5, 6, 7] + end + + it "ignores array class differences" do + ArraySpecs::MyArray[1, 2, 3].should == [1, 2, 3] + ArraySpecs::MyArray[1, 2, 3].should == ArraySpecs::MyArray[1, 2, 3] + [1, 2, 3].should == ArraySpecs::MyArray[1, 2, 3] + end +end diff --git a/1.8/core/array/fetch_spec.rb b/1.8/core/array/fetch_spec.rb new file mode 100644 index 0000000000..c5deff241f --- /dev/null +++ b/1.8/core/array/fetch_spec.rb @@ -0,0 +1,55 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#fetch" do + it "returns the element at index" do + [1, 2, 3].fetch(1).should == 2 + [nil].fetch(0).should == nil + end + + it "counts negative indices backwards from end" do + [1, 2, 3, 4].fetch(-1).should == 4 + end + + it "raises an IndexError if there is no element at index" do + lambda { [1, 2, 3].fetch(3) }.should raise_error(IndexError) + lambda { [1, 2, 3].fetch(-4) }.should raise_error(IndexError) + lambda { [].fetch(0) }.should raise_error(IndexError) + end + + it "returns default if there is no element at index if passed a default value" do + [1, 2, 3].fetch(5, :not_found).should == :not_found + [1, 2, 3].fetch(5, nil).should == nil + [1, 2, 3].fetch(-4, :not_found).should == :not_found + [nil].fetch(0, :not_found).should == nil + end + + it "returns the value of block if there is no element at index if passed a block" do + [1, 2, 3].fetch(9) { |i| i * i }.should == 81 + [1, 2, 3].fetch(-9) { |i| i * i }.should == 81 + end + + it "passes the original index argument object to the block, not the converted Integer" do + o = mock('5') + def o.to_int(); 5; end + + [1, 2, 3].fetch(o) { |i| i }.equal?(o).should == true + end + +$VERBOSE, old = nil, $VERBOSE + it "gives precedence to the default block over the default argument" do + [1, 2, 3].fetch(9, :foo) { |i| i * i }.should == 81 + end +$VERBOSE = old + + it "calls to_int on its argument" do + x = mock('0') + def x.to_int() 0 end + [1, 2, 3].fetch(x).should == 1 + + x = mock('1') + x.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + x.should_receive(:method_missing).with(:to_int).and_return(0) + [1, 2, 3].fetch(x).should == 1 + end +end diff --git a/1.8/core/array/fill_spec.rb b/1.8/core/array/fill_spec.rb new file mode 100644 index 0000000000..a298ef40a5 --- /dev/null +++ b/1.8/core/array/fill_spec.rb @@ -0,0 +1,116 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#fill" do + it "replaces all elements in the array with object" do + ary = ['a', 'b', 'c', 'duh'] + ary.fill(8).should == [8, 8, 8, 8] + + str = "x" + ary.fill(str).should == [str, str, str, str] + str << "y" + ary.should == [str, str, str, str] + end + + it "replaces length elements with object beginning with start index" do + [1, 2, 3, 4, 5].fill('a', 2, 2).should == [1, 2, "a", "a", 5] + [1, 2, 3, 4, 5].fill('a', 2, 5).should == [1, 2, "a", "a", "a", "a", "a"] + [1, 2, 3, 4, 5].fill('a', 2, -2).should == [1, 2, 3, 4, 5] + [1, 2, 3, 4, 5].fill('a', 2, 0).should == [1, 2, 3, 4, 5] + + [1, 2, 3, 4, 5].fill('a', -2, 2).should == [1, 2, 3, "a", "a"] + [1, 2, 3, 4, 5].fill('a', -2, 4).should == [1, 2, 3, "a", "a", "a", "a"] + [1, 2, 3, 4, 5].fill('a', -2, -2).should == [1, 2, 3, 4, 5] + [1, 2, 3, 4, 5].fill('a', -2, 0).should == [1, 2, 3, 4, 5] + end + + it "calls to_int on start and length" do + x = mock('2') + def x.to_int() 2 end + [1, 2, 3, 4, 5].fill('a', x, x).should == [1, 2, "a", "a", 5] + + x = mock('2') + x.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + x.should_receive(:method_missing).with(:to_int).twice.and_return(2) + [1, 2, 3, 4, 5].fill('a', x, x).should == [1, 2, "a", "a", 5] + end + + it "starts at 0 if the negative index is before the start of the array" do + [1, 2, 3, 4, 5].fill('a', -25, 3).should == ['a', 'a', 'a', 4, 5] + [1, 2, 3, 4, 5].fill('a', -10, 10).should == %w|a a a a a a a a a a| + end + + it "does not change the Array given an index and a count of 0" do + [1, 2, 3].fill('a', 1, 0).should == [1, 2, 3] + end + + it "does not raise an exception if given an index and a negative count whose absolute value does not exceed the index" do + lambda { [1, 2, 3].fill('a', 3, -1)}.should_not raise_error(ArgumentError) + lambda { [1, 2, 3].fill('a', 3, -2)}.should_not raise_error(ArgumentError) + lambda { [1, 2, 3].fill('a', 3, -3)}.should_not raise_error(ArgumentError) + end + + it "raises an ArgumentError if given an index and a negative count whose absolute value exceeds the index" do + lambda { [1, 2, 3].fill('a', 3, -4)}.should raise_error(ArgumentError) + lambda { [1, 2, 3].fill('a', 1, -3)}.should raise_error(ArgumentError) + lambda { [1, 2, 3].fill('a', 1, -300000)}.should raise_error(ArgumentError) + end + + it "replaces elements in range with object" do + [1, 2, 3, 4, 5, 6].fill(8, 0..3).should == [8, 8, 8, 8, 5, 6] + [1, 2, 3, 4, 5, 6].fill(8, 0...3).should == [8, 8, 8, 4, 5, 6] + [1, 2, 3, 4, 5, 6].fill('x', 4..6).should == [1, 2, 3, 4, 'x', 'x', 'x'] + [1, 2, 3, 4, 5, 6].fill('x', 4...6).should == [1, 2, 3, 4, 'x', 'x'] + [1, 2, 3, 4, 5, 6].fill('x', -2..-1).should == [1, 2, 3, 4, 'x', 'x'] + [1, 2, 3, 4, 5, 6].fill('x', -2...-1).should == [1, 2, 3, 4, 'x', 6] + [1, 2, 3, 4, 5, 6].fill('x', -2...-2).should == [1, 2, 3, 4, 5, 6] + [1, 2, 3, 4, 5, 6].fill('x', -2..-2).should == [1, 2, 3, 4, 'x', 6] + [1, 2, 3, 4, 5, 6].fill('x', -2..0).should == [1, 2, 3, 4, 5, 6] + [1, 2, 3, 4, 5, 6].fill('x', 0...0).should == [1, 2, 3, 4, 5, 6] + [1, 2, 3, 4, 5, 6].fill('x', 1..1).should == [1, 'x', 3, 4, 5, 6] + end + + it "replaces all elements with the value of block (index given to block)" do + [nil, nil, nil, nil].fill { |i| i * 2 }.should == [0, 2, 4, 6] + end + + it "replaces length elements beginning with start with the value of block" do + [true, false, true, false, true, false, true].fill(1, 4) { |i| i + 3 }.should == [true, 4, 5, 6, 7, false, true] + end + + it "replaces all elements in range with the value of block" do + [1, 1, 1, 1, 1, 1].fill(1..6) { |i| i + 1 }.should == [1, 2, 3, 4, 5, 6, 7] + end + + it "increases the Array size when necessary" do + a = [1, 2, 3] + a.size.should == 3 + a.fill 'a', 0, 10 + a.size.should == 10 + end + + it "raises an ArgumentError if the wrong number of arguments is given" do + lambda { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError) + lambda { [].fill('a', 1, true) {|i|} }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the index is not numeric" do + lambda { [].fill 'a', true }.should raise_error(TypeError) + end + + it "raises a TypeError with range and length argument" do + lambda { [].fill('x', 0 .. 2, 5) }.should raise_error(TypeError) + end + + it "ignores length if it is nil" do + a = [1, 2, 3] + a.fill('x', 1, nil) + a.should == [1, 'x', 'x'] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.fill('x') }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/first_spec.rb b/1.8/core/array/first_spec.rb new file mode 100644 index 0000000000..a6115f005f --- /dev/null +++ b/1.8/core/array/first_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#first" do + it "returns the first element" do + %w{a b c}.first.should == 'a' + [nil].first.should == nil + end + + it "returns nil if self is empty" do + [].first.should == nil + end + + it "returns the first count elements" do + [true, false, true, nil, false].first(2).should == [true, false] + end + + it "returns an empty array when passed count on an empty array" do + [].first(0).should == [] + [].first(1).should == [] + end + + it "returns an empty array when passed count == 0" do + [1, 2, 3, 4, 5].first(0).should == [] + end + + it "returns an array containing the first element when passed count == 1" do + [1, 2, 3, 4, 5].first(1).should == [1] + end + + it "raises an ArgumentError when count is negative" do + lambda { [1, 2].first(-1) }.should raise_error(ArgumentError) + end + + it "returns the entire array when count > length" do + [1, 2, 3, 4, 5, 9].first(10).should == [1, 2, 3, 4, 5, 9] + end + + it "calls to_int on count" do + obj = mock('2') + def obj.to_int() 2 end + [1, 2, 3, 4, 5].first(obj).should == [1, 2] + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(2) + [1, 2, 3, 4, 5].first(obj).should == [1, 2] + end + + it "does not return subclass instance when passed count on Array subclasses" do + ArraySpecs::MyArray[].first(0).class.should == Array + ArraySpecs::MyArray[].first(2).class.should == Array + ArraySpecs::MyArray[1, 2, 3].first(0).class.should == Array + ArraySpecs::MyArray[1, 2, 3].first(1).class.should == Array + ArraySpecs::MyArray[1, 2, 3].first(2).class.should == Array + end +end diff --git a/1.8/core/array/fixtures/classes.rb b/1.8/core/array/fixtures/classes.rb new file mode 100644 index 0000000000..83f5c6e694 --- /dev/null +++ b/1.8/core/array/fixtures/classes.rb @@ -0,0 +1,40 @@ +module ArraySpecs + def self.frozen_array + @frozen_array ||= [1,2,3] + @frozen_array.freeze + @frozen_array + end + + class MyArray < Array; end + + class Sexp < Array + def initialize(*args) + super(args) + end + end + + class ToAryArray < Array + def to_ary() ["to_ary", "was", "called!"] end + end + + class MyRange < Range; end + + class AssocKey + def ==(other); other == 'it'; end + end + + class D + def <=>(obj) + return 4 <=> obj unless obj.class == D + 0 + end + end + + class SubArray < Array + attr_reader :special + + def initialize(size=0) + @special = size + end + end +end diff --git a/1.8/core/array/flatten_spec.rb b/1.8/core/array/flatten_spec.rb new file mode 100644 index 0000000000..cf81594d6b --- /dev/null +++ b/1.8/core/array/flatten_spec.rb @@ -0,0 +1,74 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#flatten" do + it "returns a one-dimensional flattening recursively" do + [[[1, [2, 3]],[2, 3, [4, [4, [5, 5]], [1, 2, 3]]], [4]], []].flatten.should == [1, 2, 3, 2, 3, 4, 4, 5, 5, 1, 2, 3, 4] + end + + it "does not call flatten on elements" do + obj = mock('[1,2]') + def obj.flatten() [1, 2] end + [obj, obj].flatten.should == [obj, obj] + + obj = [5, 4] + def obj.flatten() [1, 2] end + [obj, obj].flatten.should == [5, 4, 5, 4] + end + + it "raises an ArgumentError on recursive arrays" do + x = [] + x << x + lambda { x.flatten }.should raise_error(ArgumentError) + + x = [] + y = [] + x << y + y << x + lambda { x.flatten }.should raise_error(ArgumentError) + end + + it "returns subclass instance for Array subclasses" do + ArraySpecs::MyArray[].flatten.class.should == ArraySpecs::MyArray + ArraySpecs::MyArray[1, 2, 3].flatten.class.should == ArraySpecs::MyArray + ArraySpecs::MyArray[1, [2], 3].flatten.class.should == ArraySpecs::MyArray + [ArraySpecs::MyArray[1, 2, 3]].flatten.class.should == Array + end +end + +describe "Array#flatten!" do + it "modifies array to produce a one-dimensional flattening recursively" do + a = [[[1, [2, 3]],[2, 3, [4, [4, [5, 5]], [1, 2, 3]]], [4]], []] + a.flatten!.equal?(a).should == true + a.should == [1, 2, 3, 2, 3, 4, 4, 5, 5, 1, 2, 3, 4] + end + + it "returns nil if no modifications took place" do + a = [1, 2, 3] + a.flatten!.should == nil + end + + it "raises an ArgumentError on recursive arrays" do + x = [] + x << x + lambda { x.flatten! }.should raise_error(ArgumentError) + + x = [] + y = [] + x << y + y << x + lambda { x.flatten! }.should raise_error(ArgumentError) + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on frozen arrays when modification would take place" do + nested_ary = [1, 2, []] + nested_ary.freeze + lambda { nested_ary.flatten! }.should raise_error(TypeError) + end + + it "does not raise on frozen arrays when no modification would take place" do + ArraySpecs.frozen_array.flatten! # ok, already flat + end + end +end diff --git a/1.8/core/array/frozen_spec.rb b/1.8/core/array/frozen_spec.rb new file mode 100644 index 0000000000..75d8767cad --- /dev/null +++ b/1.8/core/array/frozen_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +compliant_on :ruby, :jruby do + describe "Array#frozen?" do + it "returns true if array is frozen" do + a = [1, 2, 3] + a.frozen?.should == false + a.freeze + a.frozen?.should == true + end + + it "returns true if array is temporarily frozen while being sort!ed" do + a = [1, 2, 3] + a.sort! { |x,y| a.frozen?.should == true; x <=> y } + end + + it "returns false for arrays being sorted (they aren't temporarily frozen)" do + a = [1, 2, 3] + a.sort { |x,y| a.frozen?.should == false; x <=> y } + end + end +end diff --git a/1.8/core/array/hash_spec.rb b/1.8/core/array/hash_spec.rb new file mode 100644 index 0000000000..b484cabec9 --- /dev/null +++ b/1.8/core/array/hash_spec.rb @@ -0,0 +1,60 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#hash" do + it "returns the same fixnum for arrays with the same content" do + [].respond_to?(:hash).should == true + + [[], [1, 2, 3]].each do |ary| + ary.hash.should == ary.dup.hash + ary.hash.class.should == Fixnum + end + end + + # Too much of an implementation detail? -rue + compliant_on :ruby, :jruby do + it "calls to_int on result of calling hash on each element" do + ary = Array.new(5) do + # Can't use should_receive here because it calls hash() + obj = mock('0') + def obj.hash() + def self.to_int() freeze; 0 end + return self + end + obj + end + + ary.hash + ary.each { |obj| obj.frozen?.should == true } + + hash = mock('1') + hash.should_receive(:to_int).and_return(1.hash) + + obj = mock('@hash') + obj.instance_variable_set(:@hash, hash) + def obj.hash() @hash end + + [obj].hash.should == [1].hash + end + end + + it "ignores array class differences" do + ArraySpecs::MyArray[].hash.should == [].hash + ArraySpecs::MyArray[1, 2].hash.should == [1, 2].hash + end + + it "returns same hash code for arrays with the same content" do + a = [1, 2, 3, 4] + a.fill 'a', 0..3 + b = %w|a a a a| + a.hash.should == b.hash + end + + it "returns the same value if arrays are #eql?" do + a = [1, 2, 3, 4] + a.fill 'a', 0..3 + b = %w|a a a a| + a.hash.should == b.hash + a.eql?(b).should == true + end +end diff --git a/1.8/core/array/include_spec.rb b/1.8/core/array/include_spec.rb new file mode 100644 index 0000000000..6fbb8ff276 --- /dev/null +++ b/1.8/core/array/include_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#include?" do + it "returns true if object is present, false otherwise" do + [1, 2, "a", "b"].include?("c").should == false + [1, 2, "a", "b"].include?("a").should == true + end + + it "determines presence by using element == obj" do + o = mock('') + + [1, 2, "a", "b"].include?(o).should == false + + def o.==(other); other == 'a'; end + + [1, 2, o, "b"].include?('a').should == true + end + + it "calls == on elements from left to right until success" do + key = "x" + one = mock('one') + two = mock('two') + three = mock('three') + one.should_receive(:==).any_number_of_times.and_return(false) + two.should_receive(:==).any_number_of_times.and_return(true) + three.should_not_receive(:==) + ary = [one, two, three] + ary.include?(key).should == true + end +end diff --git a/1.8/core/array/index_spec.rb b/1.8/core/array/index_spec.rb new file mode 100644 index 0000000000..b940a6097e --- /dev/null +++ b/1.8/core/array/index_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#index" do + it "returns the index of the first element == to object" do + x = mock('3') + def x.==(obj) 3 == obj; end + + [2, x, 3, 1, 3, 1].index(3).should == 1 + end + + it "returns 0 if first element == to object" do + [2, 1, 3, 2, 5].index(2).should == 0 + end + + it "returns size-1 if only last element == to object" do + [2, 1, 3, 1, 5].index(5).should == 4 + end + + it "returns nil if no element == to object" do + [2, 1, 1, 1, 1].index(3).should == nil + end +end diff --git a/1.8/core/array/indexes_spec.rb b/1.8/core/array/indexes_spec.rb new file mode 100644 index 0000000000..f8ed8372e8 --- /dev/null +++ b/1.8/core/array/indexes_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/indexes' + +old, $VERBOSE = $VERBOSE, nil +describe "Array#indexes" do + it_behaves_like(:array_indexes, :indexes) +end +$VERBOSE = old diff --git a/1.8/core/array/indices_spec.rb b/1.8/core/array/indices_spec.rb new file mode 100644 index 0000000000..59158cb998 --- /dev/null +++ b/1.8/core/array/indices_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/indexes' + +old, $VERBOSE = $VERBOSE, nil +describe "Array#indices" do + it_behaves_like(:array_indexes, :indices) +end +$VERBOSE = old diff --git a/1.8/core/array/initialize_copy_spec.rb b/1.8/core/array/initialize_copy_spec.rb new file mode 100644 index 0000000000..7671ad4120 --- /dev/null +++ b/1.8/core/array/initialize_copy_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/replace' + +describe "Array#initialize_copy" do + it "is private" do + [].private_methods.map { |m| m.to_s }.include?("initialize_copy").should == true + end + + it_behaves_like(:array_replace, :initialize_copy) +end diff --git a/1.8/core/array/initialize_spec.rb b/1.8/core/array/initialize_spec.rb new file mode 100644 index 0000000000..fd639ac806 --- /dev/null +++ b/1.8/core/array/initialize_spec.rb @@ -0,0 +1,70 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#initialize" do + it "is private" do + [].private_methods.should include("initialize") + end + + it "replaces self with the other array" do + o = [2] + def o.special() size end + a = [1, o, 3] + ary = Array.new a + ary[1].special.should == 1 + + b = [1, [2], 3] + ary.send :initialize, b + + b.==(ary).should == true + lambda { b[1].special }.should raise_error(NoMethodError) + lambda { ary[1].special }.should raise_error(NoMethodError) + end + + it "is called on subclasses" do + a = ArraySpecs::SubArray.new 10 + a.special.should == 10 + a.should == [] + + b = ArraySpecs::SubArray.new [1,2,3] + b.special.should == [1,2,3] + b.should == [] + end + + it "does nothing when passed self" do + ary = [1, 2, 3] + ary.instance_eval { initialize(ary) } + ary.should == [1, 2, 3] + end + + it "sets the array to size and fills with the object when passed size, object" do + a = [] + a.instance_eval { initialize(2, [3]) } + a.should == [[3], [3]] + a[0].__id__.should == a[1].__id__ + [].instance_eval { initialize(1) }.should == [nil] + end + + it "raises an ArgumentError if size is negative" do + lambda { [].instance_eval { initialize(-1, :a) } }.should raise_error(ArgumentError) + lambda { [1, 2, 3].instance_eval { initialize(-1) } }.should raise_error(ArgumentError) + end + + it "calls to_int on array size" do + obj = mock('1') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(1) + + [1, 2].instance_eval { initialize(obj, :a) } + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on frozen arrays even if the array would not be 'modified'" do + # This is true at least 1.8.6p111 onwards + lambda { ArraySpecs.frozen_array.instance_eval { initialize } }.should raise_error(TypeError) + + lambda { ArraySpecs.frozen_array.instance_eval { initialize(1) } }.should raise_error(TypeError) + lambda { ArraySpecs.frozen_array.instance_eval { initialize([1, 2, 3]) } }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/insert_spec.rb b/1.8/core/array/insert_spec.rb new file mode 100644 index 0000000000..4f794e1f04 --- /dev/null +++ b/1.8/core/array/insert_spec.rb @@ -0,0 +1,78 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#insert" do + it "inserts objects before the element at index for non-negative index" do + ary = [] + ary.insert(0, 3).equal?(ary).should == true + ary.should == [3] + + ary.insert(0, 1, 2).equal?(ary).should == true + ary.should == [1, 2, 3] + ary.insert(0) + ary.should == [1, 2, 3] + + # Let's just assume insert() always modifies the array from now on. + ary.insert(1, 'a').should == [1, 'a', 2, 3] + ary.insert(0, 'b').should == ['b', 1, 'a', 2, 3] + ary.insert(5, 'c').should == ['b', 1, 'a', 2, 3, 'c'] + ary.insert(7, 'd').should == ['b', 1, 'a', 2, 3, 'c', nil, 'd'] + ary.insert(10, 5, 4).should == ['b', 1, 'a', 2, 3, 'c', nil, 'd', nil, nil, 5, 4] + end + + it "appends objects to the end of the array for index == -1" do + [1, 3, 3].insert(-1, 2, 'x', 0.5).should == [1, 3, 3, 2, 'x', 0.5] + end + + it "inserts objects after the element at index with negative index" do + ary = [] + ary.insert(-1, 3).should == [3] + ary.insert(-2, 2).should == [2, 3] + ary.insert(-3, 1).should == [1, 2, 3] + ary.insert(-2, -3).should == [1, 2, -3, 3] + ary.insert(-1, []).should == [1, 2, -3, 3, []] + ary.insert(-2, 'x', 'y').should == [1, 2, -3, 3, 'x', 'y', []] + ary = [1, 2, 3] + end + + it "pads with nils if the index to be inserted to is past the end" do + [].insert(5, 5).should == [nil, nil, nil, nil, nil, 5] + end + + it "can insert before the first element with a negative index" do + [1, 2, 3].insert(-4, -3).should == [-3, 1, 2, 3] + end + + it "raises an IndexError if the negative index is out of bounds" do + lambda { [].insert(-2, 1) }.should raise_error(IndexError) + lambda { [1].insert(-3, 2) }.should raise_error(IndexError) + end + + it "does nothing of no object is passed" do + [].insert(0).should == [] + [].insert(-1).should == [] + [].insert(10).should == [] + [].insert(-2).should == [] + end + + it "calls to_int on position argument" do + obj = mock('2') + def obj.to_int() 2 end + [].insert(obj, 'x').should == [nil, nil, 'x'] + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(2) + [].insert(obj, 'x').should == [nil, nil, 'x'] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on frozen arrays if modification takes place" do + lambda { ArraySpecs.frozen_array.insert(0, 'x') }.should raise_error(TypeError) + end + + it "does not raise on frozen arrays if no modification takes place" do + ArraySpecs.frozen_array.insert(0) # ok + end + end +end diff --git a/1.8/core/array/inspect_spec.rb b/1.8/core/array/inspect_spec.rb new file mode 100644 index 0000000000..23097fa2fe --- /dev/null +++ b/1.8/core/array/inspect_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#inspect" do + # FIX: compatibility? --rue + it "returns a string equivalent to evaluated source code representation" do + [1, 2, 3].inspect.should == '[1, 2, 3]' + [1, 2, 3 + 4].inspect.should == '[1, 2, 7]' + [1, ['a', nil, [], 5.0], [[]], -4].inspect.should == '[1, ["a", nil, [], 5.0], [[]], -4]' + end + + it "calls inspect on its arguments" do + items = Array.new(3) do |i| + obj = mock("#{i}") + obj.should_receive(:inspect).and_return("items[#{i}]") + obj + end + + items.inspect.should == '[items[0], items[1], items[2]]' + end + + it "handles recursive arrays" do + x = [1, 2] + x << x << 4 + x.inspect.should == '[1, 2, [...], 4]' + + x = [1, 2] + y = [3, 4] + x << y + y << x + x.inspect.should == '[1, 2, [3, 4, [...]]]' + y.inspect.should == '[3, 4, [1, 2, [...]]]' + end +end diff --git a/1.8/core/array/intersection_spec.rb b/1.8/core/array/intersection_spec.rb new file mode 100644 index 0000000000..d92c56fc27 --- /dev/null +++ b/1.8/core/array/intersection_spec.rb @@ -0,0 +1,53 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#&" do + it "creates an array with elements common to both arrays (intersection)" do + ([] & []).should == [] + ([1, 2] & []).should == [] + ([] & [1, 2]).should == [] + ([ 1, 3, 5 ] & [ 1, 2, 3 ]).should == [1, 3] + end + + it "creates an array with no duplicates" do + ([ 1, 1, 3, 5 ] & [ 1, 2, 3 ]).uniq!.should == nil + end + + it "creates an array with elements in order they are first encountered" do + ([ 1, 2, 3, 2, 5 ] & [ 5, 2, 3, 4 ]).should == [2, 3, 5] + end + + it "does not modify the original Array" do + a = [1, 1, 3, 5] + a & [1, 2, 3] + a.should == [1, 1, 3, 5] + end + + it "calls to_ary on its argument" do + obj = mock('[1,2,3]') + def obj.to_ary() [1, 2, 3] end + ([1, 2] & obj).should == ([1, 2]) + + obj = mock('[1,2,3]') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).and_return([1, 2, 3]) + ([1, 2] & obj).should == [1, 2] + end + + # MRI doesn't actually call eql?() however. So you can't reimplement it. + it "acts as if using eql?" do + ([5.0, 4.0] & [5, 4]).should == [] + str = "x" + ([str] & [str.dup]).should == [str] + end + + it "does return subclass instances for Array subclasses" do + (ArraySpecs::MyArray[1, 2, 3] & []).class.should == Array + (ArraySpecs::MyArray[1, 2, 3] & ArraySpecs::MyArray[1, 2, 3]).class.should == Array + ([] & ArraySpecs::MyArray[1, 2, 3]).class.should == Array + end + + it "does not call to_ary on array subclasses" do + ([5, 6] & ArraySpecs::ToAryArray[1, 2, 5, 6]).should == [5, 6] + end +end diff --git a/1.8/core/array/join_spec.rb b/1.8/core/array/join_spec.rb new file mode 100644 index 0000000000..c697316ae9 --- /dev/null +++ b/1.8/core/array/join_spec.rb @@ -0,0 +1,79 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#join" do + it "returns an empty string if the Array is empty" do + a = [] + a.join.should == '' + end + + it "returns a string formed by concatenating each element.to_s separated by separator without trailing separator" do + obj = mock('foo') + def obj.to_s() 'foo' end + [1, 2, 3, 4, obj].join(' | ').should == '1 | 2 | 3 | 4 | foo' + +# undef is not implemented -rue +# obj = mock('o') +# class << obj; undef :to_s; end +# obj.should_receive(:method_missing).with(:to_s).and_return("o") +# [1, obj].join(":").should == "1:o" + end + + it "uses the same separator with nested arrays" do + [1, [2, [3, 4], 5], 6].join(":").should == "1:2:3:4:5:6" + [1, [2, ArraySpecs::MyArray[3, 4], 5], 6].join(":").should == "1:2:3:4:5:6" + end + + it "uses $, as the default separator (which defaults to empty)" do + [1, 2, 3].join.should == '123' + old, $, = $,, '-' + [1, 2, 3].join.should == '1-2-3' + $, = old + end + + it "calls to_str on its separator argument" do + obj = mock('::') + def obj.to_str() '::' end + [1, 2, 3, 4].join(obj).should == '1::2::3::4' + + obj = mock('.') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return(".") + [1, 2].join(obj).should == "1.2" + end + + it "does not process the separator if the array is empty" do + a = [] + sep = Object.new + a.join(sep).should == "" + end + + it "handles recursive arrays" do + x = [] + x << x + x.join(":").should == '[...]' + + x = [] + y = [] + y << 9 << x << 8 << y << 7 + x << 1 << x << 2 << y << 3 + # representations when recursing from x + # these are here to make it easier to understand what is happening + y_rec = '9:[...]:8:9:[...]:8:[...]:7:7' + x_rec = '1:[...]:2:' + y_rec + ':3' + x.join(":").should == '1:' + x_rec + ':2:' + y_rec + ':3' + + x = ["one", "two"] + x << x + x.join('/').should == 'one/two/one/two/[...]' + + x << "three" + x << "four" + x.join('/').should == 'one/two/one/two/[...]/three/four/three/four' + + # nested and recursive + x = [["one", "two"], ["three", "four"]] + x << x + x.join('/').should == 'one/two/three/four/one/two/three/four/[...]' + end +end diff --git a/1.8/core/array/last_spec.rb b/1.8/core/array/last_spec.rb new file mode 100644 index 0000000000..ac3547589c --- /dev/null +++ b/1.8/core/array/last_spec.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#last" do + it "returns the last element" do + [1, 1, 1, 1, 2].last.should == 2 + end + + it "returns nil if self is empty" do + [].last.should == nil + end + + it "returns the last count elements" do + [1, 2, 3, 4, 5, 9].last(3).should == [4, 5, 9] + end + + it "returns an empty array when passed a count on an empty array" do + [].last(0).should == [] + [].last(1).should == [] + end + + it "returns an empty array when count == 0" do + [1, 2, 3, 4, 5].last(0).should == [] + end + + it "raises an ArgumentError when count is negative" do + lambda { [1, 2].last(-1) }.should raise_error(ArgumentError) + end + + it "returns the entire array when count > length" do + [1, 2, 3, 4, 5, 9].last(10).should == [1, 2, 3, 4, 5, 9] + end + + it "uses to_int to convert its argument" do + o = mock('2') + lambda { [1, 2, 3].last o }.should raise_error(TypeError) + + def o.to_int(); 2; end + + [1, 2, 3].last(o).should == [2, 3] + end + + it "does not return subclass instance on Array subclasses" do + ArraySpecs::MyArray[].last(0).class.should == Array + ArraySpecs::MyArray[].last(2).class.should == Array + ArraySpecs::MyArray[1, 2, 3].last(0).class.should == Array + ArraySpecs::MyArray[1, 2, 3].last(1).class.should == Array + ArraySpecs::MyArray[1, 2, 3].last(2).class.should == Array + end +end diff --git a/1.8/core/array/length_spec.rb b/1.8/core/array/length_spec.rb new file mode 100644 index 0000000000..7cc90a01bd --- /dev/null +++ b/1.8/core/array/length_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/length' + +describe "Array#length" do + it_behaves_like(:array_length, :length) +end diff --git a/1.8/core/array/map_spec.rb b/1.8/core/array/map_spec.rb new file mode 100644 index 0000000000..f9de06fda6 --- /dev/null +++ b/1.8/core/array/map_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/collect' + +describe "Array#map" do + it_behaves_like(:array_collect, :map) +end + +describe "Array#map!" do + it_behaves_like(:array_collect_b, :map!) +end diff --git a/1.8/core/array/minus_spec.rb b/1.8/core/array/minus_spec.rb new file mode 100644 index 0000000000..c90f8760d2 --- /dev/null +++ b/1.8/core/array/minus_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#-" do + it "creates an array minus any items from other array" do + ([] - [ 1, 2, 4 ]).should == [] + ([1, 2, 4] - []).should == [1, 2, 4] + ([ 1, 2, 3, 4, 5 ] - [ 1, 2, 4 ]).should == [3, 5] + end + + it "removes multiple items on the lhs equal to one on the rhs" do + ([1, 1, 2, 2, 3, 3, 4, 5] - [1, 2, 4]).should == [3, 3, 5] + end + + it "calls to_ary on its argument" do + obj = mock('[2,3,3,4]') + def obj.to_ary() [2, 3, 3, 4] end + ([1, 1, 2, 2, 3, 4] - obj).should == [1, 1] + + obj = mock('[2,3,4]') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).and_return([2, 3, 4]) + ([1, 1, 2, 2, 3, 4] - obj).should == [1, 1] + end + + it "does not return subclass instance for Array subclasses" do + (ArraySpecs::MyArray[1, 2, 3] - []).class.should == Array + (ArraySpecs::MyArray[1, 2, 3] - ArraySpecs::MyArray[]).class.should == Array + ([1, 2, 3] - ArraySpecs::MyArray[]).class.should == Array + end + + it "does not call to_ary on array subclasses" do + ([5, 6, 7] - ArraySpecs::ToAryArray[7]).should == [5, 6] + end +end diff --git a/1.8/core/array/multiply_spec.rb b/1.8/core/array/multiply_spec.rb new file mode 100644 index 0000000000..c94541af2a --- /dev/null +++ b/1.8/core/array/multiply_spec.rb @@ -0,0 +1,73 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#*" do + it "is equivalent to self.join(str) when passed a string" do + ([ 1, 2, 3 ] * ",").should == [1, 2, 3].join(",") + end + + it "handles recursive arrays like #join" do + x = [] + x << x + (x * ":").should == x.join(":") + + x = [] + y = [] + y << 9 << x << 8 << y << 7 + x << 1 << x << 2 << y << 3 + (x * ":").should == x.join(":") + end + + it "calls to_str on its argument" do + obj = mock('x') + def obj.to_str() "x" end + ([1, 2, 3] * obj).should == [1, 2, 3].join("x") + + obj = mock('x') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("x") + ([1, 2, 3] * obj).should == [1, 2, 3].join("x") + end + + it "concatenates n copies of the array when passed an integer" do + ([ 1, 2, 3 ] * 0).should == [] + ([ 1, 2, 3 ] * 1).should == [1, 2, 3] + ([ 1, 2, 3 ] * 3).should == [1, 2, 3, 1, 2, 3, 1, 2, 3] + ([] * 10).should == [] + end + + it "raises an ArgumentError when passed a negative integer" do + lambda { [ 1, 2, 3 ] * -1 }.should raise_error(ArgumentError) + lambda { [] * -1 }.should raise_error(ArgumentError) + end + + it "calls to_int on its argument" do + obj = mock('2') + def obj.to_int() 2 end + + ([1, 2, 3] * obj).should == [1, 2, 3] * obj.to_int + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(false) + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(2) + ([1, 2, 3] * obj).should == [1, 2, 3] * 2 + end + + it "calls to_str on its argument before to_int" do + obj = mock('2') + def obj.to_int() 2 end + def obj.to_str() "x" end + ([1, 2, 3] * obj).should == [1, 2, 3] * obj.to_str + end + + it "returns subclass instance with Array subclasses" do + (ArraySpecs::MyArray[1, 2, 3] * 0).class.should == ArraySpecs::MyArray + (ArraySpecs::MyArray[1, 2, 3] * 1).class.should == ArraySpecs::MyArray + (ArraySpecs::MyArray[1, 2, 3] * 2).class.should == ArraySpecs::MyArray + end + + it "raises a TypeError if the argument can neither be converted to a string nor an integer" do + lambda { [1, 2] * mock('str') }.should raise_error(TypeError) + end +end diff --git a/1.8/core/array/new_spec.rb b/1.8/core/array/new_spec.rb new file mode 100644 index 0000000000..0a9f3675cf --- /dev/null +++ b/1.8/core/array/new_spec.rb @@ -0,0 +1,87 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array.new" do + it "returns a new array when not passed arguments" do + a = Array.new + a.class.should == Array + b = ArraySpecs::MyArray.new + b.class.should == ArraySpecs::MyArray + end + + it "raises an ArgumentError when passed a negative size" do + lambda { Array.new(-1) }.should raise_error(ArgumentError) + end + + it "returns a new array of size with nil elements" do + Array.new(5).should == [nil, nil, nil, nil, nil] + a = ArraySpecs::MyArray.new(5) + a.class.should == ArraySpecs::MyArray + a.inspect.should == [nil, nil, nil, nil, nil].inspect + end + + it "calls to_int on size" do + obj = mock('3') + def obj.to_int() 3 end + Array.new(obj).should == [nil, nil, nil] + + obj = mock('3') + obj.should_receive(:respond_to?).with(:to_ary).and_return(false) + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(3) + Array.new(obj).should == [nil, nil, nil] + end + + it "returns a new array of size default objects" do + Array.new(4, true).should == [true, true, true, true] + + # Shouldn't copy object + str = "x" + ary = Array.new(4, str) + str << "y" + ary.should == [str, str, str, str] + + a = ArraySpecs::MyArray.new(4, true) + a.class.should == ArraySpecs::MyArray + a.inspect.should == [true, true, true, true].inspect + end + + it "returns a new array by calling to_ary on an array-like argument" do + obj = mock('[:foo]') + def obj.to_ary() [:foo] end + Array.new(obj).should == [:foo] + + a = ArraySpecs::MyArray.new(obj) + a.class.should == ArraySpecs::MyArray + a.inspect.should == [:foo].inspect + + obj = mock('[:foo]') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).any_number_of_times.and_return([:foo]) + Array.new(obj).should == [:foo] + end + + it "does not call to_ary on Array subclasses when passed an array-like argument" do + Array.new(ArraySpecs::ToAryArray[5, 6, 7]).should == [5, 6, 7] + end + + it "calls to_ary on an argument before to_int" do + obj = mock('[1,2,3]') + def obj.to_ary() [1, 2, 3] end + def obj.to_int() 3 end + + Array.new(obj).should == [1, 2, 3] + end + + it "returns an array of size elements from the result of passing each index to block" do + Array.new(5) { |i| i + 1 }.should == [1, 2, 3, 4, 5] + + a = ArraySpecs::MyArray.new(5) { |i| i + 1 } + a.class.should == ArraySpecs::MyArray + a.inspect.should == [1, 2, 3, 4, 5].inspect + end + + it "will fail if a to_ary is supplied as the first argument and a second argument is given" do + lambda { Array.new([1, 2], 1) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/array/nitems_spec.rb b/1.8/core/array/nitems_spec.rb new file mode 100644 index 0000000000..881c540c7f --- /dev/null +++ b/1.8/core/array/nitems_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#nitems" do + it "returns the number of non-nil elements" do + [nil].nitems.should == 0 + [].nitems.should == 0 + [1, 2, 3, nil].nitems.should == 3 + [1, 2, 3].nitems.should == 3 + [1, nil, 2, 3, nil, nil, 4].nitems.should == 4 + [1, nil, 2, false, 3, nil, nil, 4].nitems.should == 5 + end +end diff --git a/1.8/core/array/pack_spec.rb b/1.8/core/array/pack_spec.rb new file mode 100644 index 0000000000..1b35b6a045 --- /dev/null +++ b/1.8/core/array/pack_spec.rb @@ -0,0 +1,869 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +if ENV['MRI'] then + $: << 'kernel/core' + require 'pack' +end + +describe "Array#pack" do + it "raises an ArgumentError with ('%')" do + lambda { [].pack("%") }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError on empty array" do + ['A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', + 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', + 'I', 'i', 'L', 'l', 'M', 'm', 'N', 'n', + 'Q', 'q', 'U', 'u','w', 'Z'].each { |pat| + lambda { [].pack(pat) }.should raise_error(ArgumentError) + } + end + + it "skips everything till the end of schema string with ('#')" do + ["abc", "def"].pack("A*#A10%").should == "abc" + end + + it "skips everything till the end of schema line with ('#')" do + ["abc", "def"].pack("A*#A10%\nA*").should == "abcdef" + end + + it "returns space padded string with ('A')" do + ['abcde'].pack('A7').should == 'abcde ' + end + + it "cuts string if its size greater than directive count with ('A')" do + ['abcde'].pack('A3').should == 'abc' + end + + it "consider count = 1 if count omited with ('A')" do + ['abcde'].pack('A').should == 'a' + end + + it "returns empty string if count = 0 with ('A')" do + ['abcde'].pack('A0').should == '' + end + + it "returns the whole argument string with star parameter with ('A')" do + ['abcdef'].pack('A*').should == 'abcdef' + end + + it "raises a TypeError if array item is not String with ('A')" do + lambda { [123].pack('A5') }.should raise_error(TypeError) + lambda { [:hello].pack('A5') }.should raise_error(TypeError) + lambda { [mock('not string')].pack('A5') }.should raise_error(TypeError) + end + + it "returns null padded string with ('a')" do + ['abcdef'].pack('a7').should == "abcdef\x0" + end + + it "cuts string if its size greater than directive count with ('a')" do + ['abcde'].pack('a3').should == 'abc' + end + + it "considers count = 1 if count omited with ('a')" do + ['abcde'].pack('a').should == 'a' + end + + it "returns empty string if count = 0 with ('a')" do + ['abcde'].pack('a0').should == '' + end + + it "returns the whole argument string with star parameter with ('a')" do + ['abcdef'].pack('a*').should == 'abcdef' + end + + it "raises a TypeError if array item is not String with ('a')" do + lambda { [123].pack('a5') }.should raise_error(TypeError) + lambda { [:hello].pack('a5') }.should raise_error(TypeError) + lambda { [mock('not string')].pack('a5') }.should raise_error(TypeError) + end + + it "returns packed bit-string descending order with ('B')" do + ["011000010110001001100011"].pack('B24').should == 'abc' + end + + it "uses char codes to determine if bit is set or not with ('B')" do + ["bccddddefgghhhijjkklllmm"].pack('B24').should == ["011000010110001001100011"].pack('B24') + end + + it "conversion edge case: all zeros with ('B')" do + ["00000000"].pack('B8').should == "\000" + end + + it "conversion edge case: all ones with ('B')" do + ["11111111"].pack('B8').should == "\377" + end + + it "conversion edge case: left one with ('B')" do + ["10000000"].pack('B8').should == "\200" + end + + it "conversion edge case: right one with ('B')" do + ["00000001"].pack('B8').should == "\001" + end + + it "conversion edge case: edge sequences not in first char with ('B')" do + ["0000000010000000000000011111111100000000"].pack('B40').should == "\000\200\001\377\000" + end + + it "uses zeros if count is not multiple of 8 with ('B')" do + ["00111111"].pack('B4').should == ["00110000"].pack('B8') + end + + it "returns zero-char for each 2 of count that greater than string length with ('B')" do + [""].pack('B6').should == "\000\000\000" + end + + it "returns extra zero char if count is odd and greater than string length with ('B')" do + [""].pack('B7').should == "\000\000\000\000" + end + + it "starts new char if string is ended before char's 8 bits with ('B')" do + ["0011"].pack('B8').should == "0\000\000" + end + + it "considers count = 1 if no explicit count it given with ('B')" do + ["10000000"].pack('B').should == ["10000000"].pack('B1') + ["01000000"].pack('B').should == ["01000000"].pack('B1') + end + + it "returns empty string if count = 0 with ('B')" do + ["10101010"].pack('B0').should == "" + end + + it "uses argument string length as count if count = * with ('B')" do + ["00111111010"].pack('B*').should == ["00111111010"].pack('B11') + end + + it "consumes only one array item with ('B')" do + ["0011", "1111"].pack('B*').should == ["0011"].pack('B4') + ["0011", "1011"].pack('B*B*').should == ["0011"].pack('B4') + ["1011"].pack('B4') + end + + it "raises a TypeError if corresponding array item is not String with ('B')" do + lambda { [123].pack('B8') }.should raise_error(TypeError) + lambda { [:data].pack('B8') }.should raise_error(TypeError) + lambda { [mock('not string')].pack('B8') }.should raise_error(TypeError) + end + + it "returns packed bit-string descending order with ('b')" do + ["100001100100011011000110"].pack('b24').should == 'abc' + end + + it "conversion edge case: all zeros with ('b')" do + ["00000000"].pack('b8').should == "\000" + end + + it "conversion edge case: all ones with ('b')" do + ["11111111"].pack('b8').should == "\377" + end + + it "conversion edge case: left one with ('b')" do + ["10000000"].pack('b8').should == "\001" + end + + it "conversion edge case: right one with ('b')" do + ["00000001"].pack('b8').should == "\200" + end + + it "conversion edge case: edge sequences not in first char with ('b')" do + ["0000000010000000000000011111111100000000"].pack('b40').should == "\000\001\200\377\000" + end + + it "uses char codes to determine if bit is set or not with ('b')" do + ["abbbbccddefffgghiijjjkkl"].pack('b24').should == ["100001100100011011000110"].pack('b24') + end + + it "uses zeros if count is not multiple of 8 with ('b')" do + ["00111111"].pack('b4').should == ["00110000"].pack('b8') + end + + it "returns zero-char for each 2 of count that greater than string length with ('b')" do + [""].pack('b6').should == "\000\000\000" + end + + it "returns extra zero char if count is odd and greater than string length with ('b')" do + [""].pack('b7').should == "\000\000\000\000" + end + + it "starts new char if argument string is ended before char's 8 bits with ('b')" do + ["0011"].pack('b8').should == "\f\000\000" + end + + it "considers count = 1 if no explicit count it given with ('b')" do + ["10000000"].pack('b').should == ["10000000"].pack('b1') + ["01000000"].pack('b').should == ["01000000"].pack('b1') + end + + it "returns empty string if count = 0 with ('b')" do + ["10101010"].pack('b0').should == "" + end + + it "uses argument string length as count if count = * with ('b')" do + ["00111111010"].pack('b*').should == ["00111111010"].pack('b11') + end + + it "consumes only one array item with ('b')" do + ["0011", "1111"].pack('b*').should == ["0011"].pack('b4') + ["0011", "1011"].pack('b*b*').should == ["0011"].pack('b4') + ["1011"].pack('b4') + end + + it "raises a TypeError if corresponding array item is not String with ('b')" do + lambda { [123].pack('b8') }.should raise_error(TypeError) + lambda { [:data].pack('b8') }.should raise_error(TypeError) + lambda { [mock('not string')].pack('b8') }.should raise_error(TypeError) + end + + it "returns string with char of appropriate number with ('C')" do + [49].pack('C').should == '1' + end + + it "reduces value to fit in byte with ('C')" do + [257].pack('C').should == "\001" + end + + it "converts negative values to positive with ('C')" do + [-1].pack('C').should == [255].pack('C') + [-257].pack('C').should == [255].pack('C') + end + + it "converts float to integer and returns char with that number with ('C')" do + [5.0].pack('C').should == [5].pack('C') + end + + not_compliant_on :rubinius do + it "calls to_i on symbol and returns char with that number with ('C')" do + [:hello].pack('C').should == [:hello.to_i].pack('C') + end + end + + it "raises a TypeError if value is string with ('C')" do + lambda { ["hello"].pack('C') }.should raise_error(TypeError) + end + + it "processes count number of array elements if count given with ('C')" do + [1, 2, 3].pack('C3').should == "\001\002\003" + [1, 2, 3].pack('C2C1').should == "\001\002\003" + end + + it "returns empty string if count = 0 with ('C')" do + [1, 2, 3].pack('C0').should == '' + end + + it "with star parameter processes all remaining array items with ('C')" do + [1, 2, 3, 4, 5].pack('C*').should == "\001\002\003\004\005" + end + + it "raises an ArgumentError if count is greater than array elements left with ('C')" do + lambda { [1, 2].pack('C3') }.should raise_error(ArgumentError) + end + + it "returns string with char of appropriate number with ('c')" do + [49].pack('c').should == '1' + end + + it "reduces value to fit in byte with ('c')" do + [257].pack('c').should == "\001" + end + + it "converts negative values to positive with ('c')" do + [-1].pack('c').should == [255].pack('C') + [-257].pack('c').should == [255].pack('C') + end + + it "converts float to integer and returns char with that number with ('c')" do + [5.0].pack('c').should == [5].pack('c') + end + + not_compliant_on :rubinius do + it "calls to_i on symbol and returns char with that number with ('c')" do + [:hello].pack('c').should == [:hello.to_i].pack('c') + end + end + + it "raises a TypeError if value is string with ('c')" do + lambda { ["hello"].pack('c') }.should raise_error(TypeError) + end + + it "processes count number of array elements if count given with ('c')" do + [1, 2, 3].pack('c3').should == "\001\002\003" + end + + it "returns empty string if count = 0 with ('c')" do + [1, 2, 3].pack('c0').should == '' + end + + it "with star parameter processes all remaining array items with ('c')" do + [1, 2, 3, 4, 5].pack('c*').should == "\001\002\003\004\005" + end + + it "raises an ArgumentError if count is greater than array elements left with ('c')" do + lambda { [1, 2].pack('c3') }.should raise_error(ArgumentError) + end + + + it "encodes a high-nibble hexadecimal string with ('H')" do + ["41"].pack("H2").should == "A" + ["61"].pack("H2").should == "a" + ["7e"].pack("H2").should == "~" + + %w(41 31 2a).pack("H2H2H2").should == "A1*" + %w(41312a).pack("H6").should == "A1*" + %w(41312a).pack("H*").should == "A1*" + end + + it "encodes a low-nibble hexadecimal string with ('h')" do + ["14"].pack("h2").should == "A" + ["16"].pack("h2").should == "a" + ["e7"].pack("h2").should == "~" + + %w(14 13 a2).pack("h2h2h2").should == "A1*" + %w(1413a2).pack("h6").should == "A1*" + %w(1413a2).pack("h*").should == "A1*" + end + + + it "encodes a positive integer with ('i')" do + [0].pack('i').should == "\000\000\000\000" + [2**32-1].pack('i').should == "\377\377\377\377" + end + + little_endian do + it "encodes a positive integer in little-endian order with ('i')" do + [1].pack('i').should == "\001\000\000\000" + end + + it "encodes 4 positive integers in little-endian order with ('i4')" do + [1,1234,2,2345].pack('i4').should == "\001\000\000\000\322\004\000\000\002\000\000\000)\t\000\000" + end + + it "encodes remaining integers in little-endian order with ('i*')" do + [1,1234,2].pack('i*').should == "\001\000\000\000\322\004\000\000\002\000\000\000" + end + end + + big_endian do + it "encodes a positive integer in big-endian order with ('i')" do + [1].pack('i').should == "\000\000\000\001" + end + + it "encodes 4 positive integers in big-endian order with ('i4')" do + [1,1234,2,2345].pack('i4').should == "\000\000\000\001\000\000\004\322\000\000\000\002\000\000\t)" + end + + it "encodes remaining integers in big-endian order with ('i*')" do + [1,1234,2].pack('i*').should == "\000\000\000\001\000\000\004\322\000\000\000\002" + end + end + + it "raises a RangeError when the positive integer is too big with ('i')" do + lambda { [2**32].pack('i') }.should raise_error(RangeError) + end + + it "encodes a negative integer with ('i')" do + [-1].pack('i').should == "\377\377\377\377" + end + + little_endian do + it "encodes a negative integer in little-endian order with ('i')" do + [-2].pack('i').should == "\376\377\377\377" + end + end + + big_endian do + it "encodes a negative integer in big-endian order with ('i')" do + [-2].pack('i').should == "\377\377\377\376" + end + end + + it "raises a RangeError when the negative integer is too big with ('l')" do + lambda { [-2**32].pack('l') }.should raise_error(RangeError) + end + + it "encodes a positive integer with ('l')" do + [0].pack('l').should == "\000\000\000\000" + [2**32-1].pack('l').should == "\377\377\377\377" + end + + little_endian do + it "encodes a positive integer in little-endian order with ('l')" do + [1].pack('l').should == "\001\000\000\000" + end + end + + big_endian do + it "encodes a positive integer in big-endian order with ('l')" do + [1].pack('l').should == "\000\000\000\001" + end + end + + it "raises a RangeError when the positive integer is too big with ('l')" do + lambda { [2**32].pack('l') }.should raise_error(RangeError) + end + + it "encodes a negative integer with ('l')" do + [-1].pack('l').should == "\377\377\377\377" + end + + little_endian do + it "encodes a negative integer in little-endian order with ('l')" do + [-2].pack('l').should == "\376\377\377\377" + end + end + + big_endian do + it "encodes a negative integer in big-endian order with ('l')" do + [-2].pack('l').should == "\377\377\377\376" + end + end + + it "raises a RangeError when the negative integer is too big with ('l')" do + lambda { [-2**32].pack('l') }.should raise_error(RangeError) + end + + it "enocdes string with Qouted Printable encoding with ('M')" do + ["ABCDEF"].pack('M').should == "ABCDEF=\n" + end + + it "doesn't encode new line chars with ('M')" do + ["\nA"].pack('M').should == "\nA=\n" + end + + it "always appends soft line break at the end of encoded string with ('M')" do + ["ABC"].pack('M')[-2, 2].should == "=\n" + end + + it "appends soft line break after each 72 chars + 1 encoded char in encoded string with ('M')" do + s = ["A"*150].pack('M') + s[73, 2].should == "=\n" + s[148, 2].should == "=\n" + + s = ["A"*72+"\001"].pack('M') + s[75, 2].should == "=\n" + end + + it "doesn't quote chars 32..60 and 62..126) with ('M')" do + 32.upto(60) do |i| + [i.chr].pack('M').should == i.chr+"=\n" + end + + 62.upto(126) do |i| + [i.chr].pack('M').should == i.chr+"=\n" + end + end + + it "quotes chars by adding equal sign and char's hex value with ('M')" do + ["\001"].pack('M').should == "=01=\n" + end + + it "quotes equal sign with ('M')" do + ["="].pack('M').should == "=3D=\n" + end + + it "doesn't quote \\t char with ('M')" do + ["\t"].pack('M').should == "\t=\n" + end + + it "returns empty string if source string is empty with ('M')" do + [""].pack('M').should == "" + end + + it "calls to_s on object to convert to string with ('M')" do + class X; def to_s; "unnamed object"; end; end + + [123].pack('M').should == "123=\n" + [:hello].pack('M').should == "hello=\n" + [X.new].pack('M').should == "unnamed object=\n" + end + + it "ignores count parameter with ('M')" do + ["ABC", "DEF", "GHI"].pack('M0').should == ["ABC"].pack('M') + ["ABC", "DEF", "GHI"].pack('M3').should == ["ABC"].pack('M') + end + + it "ignores star parameter with ('M')" do + ["ABC", "DEF", "GHI"].pack('M*').should == ["ABC"].pack('M') + end + + it "encodes string with Base64 encoding with ('m')" do + ["ABCDEF"].pack('m').should == "QUJDREVG\n" + end + + it "converts series of 3-char sequences into four 4-char sequences with ('m')" do + ["ABCDEFGHI"].pack('m').size.should == 4+4+4+1 + end + + it "fills chars with non-significant bits with '=' sign with ('m')" do + ["A"].pack('m').should == "QQ==\n" + end + + it "appends newline at the end of result string with ('m')" do + ["A"].pack('m')[-1, 1].should == "\n" + end + + it "appends newline after each 60 chars in result string with ('m')" do + s = ["ABC"*31].pack('m') + s[60, 1].should == "\n" + s[121, 1].should == "\n" + end + + it "encodes 6-bit char less than 26 with capital letters with ('m')" do + [( 0*4).chr].pack('m').should == "AA==\n" + [( 1*4).chr].pack('m').should == "BA==\n" + + [(25*4).chr].pack('m').should == "ZA==\n" + end + + it "encodes 6-bit char from 26 to 51 with lowercase letters with ('m')" do + [(26*4).chr].pack('m').should == "aA==\n" + [(27*4).chr].pack('m').should == "bA==\n" + + [(51*4).chr].pack('m').should == "zA==\n" + end + + it "encodes 6-bit char 62 with '+' with ('m')" do + [(62*4).chr].pack('m').should == "+A==\n" + end + + it "encodes 6-bit char 63 with '/' with ('m')" do + [(63*4).chr].pack('m').should == "/A==\n" + end + + it "returns empty string if source string is empty with ('m')" do + [""].pack('m').should == "" + end + + it "raises a TypeError if corresponding array item is not string with ('m')" do + lambda { [123].pack('m') }.should raise_error(TypeError) + lambda { [:hello].pack('m') }.should raise_error(TypeError) + lambda { [mock('not string')].pack('m') }.should raise_error(TypeError) + end + + it "ignores count parameter with ('m')" do + ["ABC", "DEF", "GHI"].pack('m0').should == ["ABC"].pack('m') + ["ABC", "DEF", "GHI"].pack('m3').should == ["ABC"].pack('m') + end + + it "ignores star parameter with ('m')" do + ["ABC", "DEF", "GHI"].pack('m*').should == ["ABC"].pack('m') + end + + it "encodes an integer in network order with ('n')" do + [1234].pack('n').should == "\004\322" + end + + it "encodes 4 integers in network order with ('n4')" do + [1234,5678,9876,5432].pack('n4').should == "\004\322\026.&\224\0258" + end + + it "encodes a long in network-order with ('N')" do + [1000].pack('N').should == "\000\000\003\350" + [-1000].pack('N').should == "\377\377\374\030" + + [65536].pack('N').should == "\000\001\000\000" + [-65536].pack('N').should == "\377\377\000\000" + # TODO: add bigger numbers + end + +# it "encodes a long in network-order with ('N4')" do +# [1234,5678,9876,5432].pack('N4').should == "\000\000\004\322\000\000\026.\000\000&\224\000\000\0258" +# # TODO: bigger +# end + + it "encodes a long in little-endian order with ('V')" do + [1000].pack('V').should == "\350\003\000\000" + [-1000].pack('V').should == "\030\374\377\377" + + [65536].pack('V').should == "\000\000\001\000" + [-65536].pack('V').should == "\000\000\377\377" + # TODO: add bigger numbers + end + + it "encodes a short in little-endian order with ('v')" do + [1000].pack('v').should == "\350\003" + [-1000].pack('v').should == "\030\374" + + [65536].pack('v').should == "\000\000" + [-65536].pack('v').should == "\000\000" + end + + it "encodes a positive integer with ('s')" do + [0].pack('s').should == "\000\000" + [2**32-1].pack('s').should == "\377\377" + end + + little_endian do + it "encodes a positive integer in little-endian order with ('s')" do + [1].pack('s').should == "\001\000" + end + end + + big_endian do + it "encodes a positive integer in big-endian order with ('s')" do + [1].pack('s').should == "\000\001" + end + end + + it "raises a RangeError when the positive integer is too big with ('s')" do + lambda { [2**32].pack('s') }.should raise_error(RangeError) + end + + it "encodes a negative integer with ('s')" do + [-1].pack('s').should == "\377\377" + end + + little_endian do + it "encodes a negative integer in little-endian order with ('s')" do + [-2].pack('s').should == "\376\377" + end + end + + big_endian do + it "encodes a negative integer in big-endian order with ('s')" do + [-2].pack('s').should == "\377\376" + end + end + + it "raises a RangeError when the negative integer is too big with ('s')" do + lambda { [-2**32].pack('s') }.should raise_error(RangeError) + end + + it "converts integers into UTF-8 encoded byte sequences with ('U')" do + numbers = [0, 1, 15, 16, 127, + 128, 255, 256, 1024] + numbers.each do |n| + [n].pack('U').unpack('U').should == [n] + end + [0x7F, 0x7F].pack('U*').should == "\x7F\x7F" + [262193, 4736, 191, 12, 107].pack('U*').should == "\xF1\x80\x80\xB1\xE1\x8A\x80\xC2\xBF\x0C\x6B" + [2**16+1, 2**30].pack('U2').should == "\360\220\200\201\375\200\200\200\200\200" + + lambda { [].pack('U') }.should raise_error(ArgumentError) + lambda { [1].pack('UU') }.should raise_error(ArgumentError) + lambda { [2**32].pack('U') }.should raise_error(RangeError) + lambda { [-1].pack('U') }.should raise_error(RangeError) + lambda { [-5].pack('U') }.should raise_error(RangeError) + lambda { [-2**32].pack('U') }.should raise_error(RangeError) + end + + it "only takes as many elements as specified after ('U')" do + [?a,?b,?c].pack('U2').should == "ab" + end + + it "converts big integers into UTF-8 encoded byte sequences with ('U')" do + #these are actually failing on String#unpack + # they are not passing the 'utf8_regex_strict' test + compliant_on :ruby, :jruby do + numbers = [ 2048, 4096, 2**16 -1, 2**16, 2**16 + 1, 2**30] + numbers.each do |n| + [n].pack('U').unpack('U').should == [n] + end + end + end + + it "encodes string with UU-encoding with ('u')" do + ["ABCDEF"].pack('u').should == "&04)#1$5&\n" + end + + it "converts series of 3-char sequences into four 4-char sequences with ('u')" do + ["ABCDEFGHI"].pack('u').size.should == 4+4+4+1+1 + end + + it "appends zero-chars to source string if string length is not multiple of 3 with ('u')" do + ["A"].pack('u').should == "!00``\n" + end + + it "appends newline at the end of result string with ('u')" do + ["A"].pack('u')[-1, 1].should == "\n" + end + + it "splits source string into lines with no more than 45 chars with ('u')" do + s = ["A"*91].pack('u') + s[61, 1].should == "\n" + s[123, 1].should == "\n" + end + + it "prepends encoded line length to each line with ('u')" do + s = ["A"*50].pack('u') + s[ 0].should == 45+32 + s[62].should == 5+32 + end + + it "encodes 6-bit char with another char starting from char 32 with ('u')" do + [( 1 * 4).chr].pack('u').should == "!!```\n" + [(16 * 4).chr].pack('u').should == "!0```\n" + [(25 * 4).chr].pack('u').should == "!9```\n" + [(63 * 4).chr].pack('u').should == "!_```\n" + end + + it "replaces spaces in encoded string with grave accent (`) char with ('u')" do + [( 0*4).chr].pack('u').should == "!````\n" + end + + it "returns empty string if source string is empty with ('u')" do + [""].pack('u').should == "" + end + + it "raises a TypeError if corresponding array item is not string with ('u')" do + lambda { [123].pack('u') }.should raise_error(TypeError) + lambda { [:hello].pack('u') }.should raise_error(TypeError) + lambda { [mock('not string')].pack('u') }.should raise_error(TypeError) + end + + it "ignores count parameter with ('u')" do + ["ABC", "DEF", "GHI"].pack('u0').should == ["ABC"].pack('u') + ["ABC", "DEF", "GHI"].pack('u3').should == ["ABC"].pack('u') + end + + it "ignores star parameter with ('u')" do + ["ABC", "DEF", "GHI"].pack('u*').should == ["ABC"].pack('u') + end + + it "decreases result string by one char with ('X')" do + ['abcdef'].pack('A4X').should == 'abc' + end + + it "converts to BER-compressed integer with ('w')" do + [0].pack('w').should == "\000" + [1].pack('w').should == "\001" + [9999].pack('w').should == "\316\017" + [2**64].pack('w').should == "\202\200\200\200\200\200\200\200\200\000" + lambda { [-1].pack('w') }.should raise_error(ArgumentError) + lambda { [-2**256].pack('w') }.should raise_error(ArgumentError) + end + + it "with count decreases result string by count chars with ('X')" do + ['abcdef'].pack('A6X4').should == 'ab' + end + + it "with zero count doesnt change result string with ('X')" do + ['abcdef'].pack('A6X0').should == 'abcdef' + end + + it "treats start parameter as zero count with ('X')" do + ['abcdef'].pack('A6X*').should == 'abcdef' + end + + it "raises an ArgumentError if count greater than already generated string length with ('X')" do + lambda { ['abcdef'].pack('A6X7') }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError if it is first directive with ('X')" do + lambda { [].pack('X') }.should raise_error(ArgumentError) + end + + it "doesn't increment the array index count with ('X')" do + ['abcd','efgh'].pack('A4X2A4').should == 'abefgh' + end + + it "returns zero-char string with ('x')" do + [].pack('x').should == "\000" + end + + it "returns string of count zero chars with count and ('x')" do + [].pack('x5').should == "\000\000\000\000\000" + end + + it "returns empty string with count == 0 and ('x')" do + [].pack('x0').should == "" + end + + it "behaves like with count == 0 with star parameter and ('x')" do + [].pack('x*').should == "" + end + + it "doesn't increment the array index count with ('x')" do + ['abcd','efgh'].pack('A4x2A4').should == "abcd\000\000efgh" + end + + it "returns null padded string with ('Z')" do + ['abcdef'].pack('Z7').should == "abcdef\000" + end + + it "cuts string if its size greater than directive count with ('Z')" do + ['abcde'].pack('Z3').should == 'abc' + end + + it "considers count = 1 if count omited with ('Z')" do + ['abcde'].pack('Z').should == 'a' + end + + it "returns empty string if count = 0 with ('Z')" do + ['abcde'].pack('Z0').should == '' + end + + it "returns the whole argument string plus null char with star parameter with ('Z')" do + ['abcdef'].pack('Z*').should == "abcdef\000" + end + + it "raises a TypeError if array item is not String with ('Z')" do + lambda { [123].pack('Z5') }.should raise_error(TypeError) + lambda { [:hello].pack('Z5') }.should raise_error(TypeError) + lambda { [mock('not string')].pack('Z5') }.should raise_error(TypeError) + end + + # Scenario taken from Mongrel's use of the SO_ACCEPTFILTER struct + it "reuses last array element as often as needed to complete the string" do + expected = "httpready" + ("\000" * 247) + ['httpready', nil].pack('a16a240').should == expected + end +end + +# def test_pack +# $format = "c2x5CCxsdils_l_a6"; +# # Need the expression in here to force ary[5] to be numeric. This avoids +# # test2 failing because ary2 goes str->numeric->str and ary does not. +# ary = [1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,-32767,-123456,"abcdef"] +# $x = ary.pack($format) +# ary2 = $x.unpack($format) + +# assert_equal(ary.length, ary2.length) +# assert_equal(ary.join(':'), ary2.join(':')) +# assert_match(/def/, $x) + +# $x = [-1073741825] +# assert_equal($x, $x.pack("q").unpack("q")) + +# $x = [-1] +# assert_equal($x, $x.pack("l").unpack("l")) +# end + +# def test_pack_N +# assert_equal "\000\000\000\000", [0].pack('N') +# assert_equal "\000\000\000\001", [1].pack('N') +# assert_equal "\000\000\000\002", [2].pack('N') +# assert_equal "\000\000\000\003", [3].pack('N') +# assert_equal "\377\377\377\376", [4294967294].pack('N') +# assert_equal "\377\377\377\377", [4294967295].pack('N') + +# assert_equal "\200\000\000\000", [2**31].pack('N') +# assert_equal "\177\377\377\377", [-2**31-1].pack('N') +# assert_equal "\377\377\377\377", [-1].pack('N') + +# assert_equal "\000\000\000\001\000\000\000\001", [1,1].pack('N*') +# assert_equal "\000\000\000\001\000\000\000\001\000\000\000\001", [1,1,1].pack('N*') +# end + +# def test_unpack_N +# assert_equal 1, "\000\000\000\001".unpack('N')[0] +# assert_equal 2, "\000\000\000\002".unpack('N')[0] +# assert_equal 3, "\000\000\000\003".unpack('N')[0] +# assert_equal 3, "\000\000\000\003".unpack('N')[0] +# assert_equal 4294967295, "\377\377\377\377".unpack('N')[0] +# assert_equal [1,1], "\000\000\000\001\000\000\000\001".unpack('N*') +# assert_equal [1,1,1], "\000\000\000\001\000\000\000\001\000\000\000\001".unpack('N*') +# end + +# def test_pack_U +# assert_raises(RangeError) { [-0x40000001].pack("U") } +# assert_raises(RangeError) { [-0x40000000].pack("U") } +# assert_raises(RangeError) { [-1].pack("U") } +# assert_equal "\000", [0].pack("U") +# assert_equal "\374\277\277\277\277\277", [0x3fffffff].pack("U") +# assert_equal "\375\200\200\200\200\200", [0x40000000].pack("U") +# assert_equal "\375\277\277\277\277\277", [0x7fffffff].pack("U") +# assert_raises(RangeError) { [0x80000000].pack("U") } +# assert_raises(RangeError) { [0x100000000].pack("U") } +# end diff --git a/1.8/core/array/partition_spec.rb b/1.8/core/array/partition_spec.rb new file mode 100644 index 0000000000..2898763fea --- /dev/null +++ b/1.8/core/array/partition_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#partition" do + it "returns two arrays" do + [].partition {}.should == [[], []] + end + + it "returns in the left array values for which the block evaluates to true" do + ary = [0, 1, 2, 3, 4, 5] + + ary.partition { |i| true }.should == [ary, []] + ary.partition { |i| 5 }.should == [ary, []] + ary.partition { |i| false }.should == [[], ary] + ary.partition { |i| nil }.should == [[], ary] + ary.partition { |i| i % 2 == 0 }.should == [[0, 2, 4], [1, 3, 5]] + ary.partition { |i| i / 3 == 0 }.should == [[0, 1, 2], [3, 4, 5]] + end + + it "does not return subclass instances on Array subclasses" do + result = ArraySpecs::MyArray[1, 2, 3].partition { |x| x % 2 == 0 } + result.class.should == Array + result[0].class.should == Array + result[1].class.should == Array + end +end diff --git a/1.8/core/array/plus_spec.rb b/1.8/core/array/plus_spec.rb new file mode 100644 index 0000000000..440d5a247f --- /dev/null +++ b/1.8/core/array/plus_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#+" do + it "concatenates two arrays" do + ([ 1, 2, 3 ] + [ 3, 4, 5 ]).should == [1, 2, 3, 3, 4, 5] + ([ 1, 2, 3 ] + []).should == [1, 2, 3] + ([] + [ 1, 2, 3 ]).should == [1, 2, 3] + ([] + []).should == [] + end + + it "calls to_ary on its argument" do + obj = mock('["x", "y"]') + def obj.to_ary() ["x", "y"] end + ([1, 2, 3] + obj).should == [1, 2, 3] + obj.to_ary + + obj = mock('[:x]') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).and_return([:x]) + ([1, 2, 3] + obj).should == [1, 2, 3, :x] + end + + it "does return subclass instances with Array subclasses" do + (ArraySpecs::MyArray[1, 2, 3] + []).class.should == Array + (ArraySpecs::MyArray[1, 2, 3] + ArraySpecs::MyArray[]).class.should == Array + ([1, 2, 3] + ArraySpecs::MyArray[]).class.should == Array + end + + it "does not call to_ary on array subclasses" do + ([5, 6] + ArraySpecs::ToAryArray[1, 2]).should == [5, 6, 1, 2] + end +end diff --git a/1.8/core/array/pop_spec.rb b/1.8/core/array/pop_spec.rb new file mode 100644 index 0000000000..852369fab4 --- /dev/null +++ b/1.8/core/array/pop_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#pop" do + it "removes and returns the last element of the array" do + a = ["a", 1, nil, true] + + a.pop.should == true + a.should == ["a", 1, nil] + + a.pop.should == nil + a.should == ["a", 1] + + a.pop.should == 1 + a.should == ["a"] + + a.pop.should == "a" + a.should == [] + end + + it "returns nil if there are no more elements" do + [].pop.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.pop }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/push_spec.rb b/1.8/core/array/push_spec.rb new file mode 100644 index 0000000000..ff91762a04 --- /dev/null +++ b/1.8/core/array/push_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#push" do + it "appends the arguments to the array" do + a = [ "a", "b", "c" ] + a.push("d", "e", "f").equal?(a).should == true + a.push().should == ["a", "b", "c", "d", "e", "f"] + a.push(5) + a.should == ["a", "b", "c", "d", "e", "f", 5] + end + + it "isn't confused by previous shift" do + a = [ "a", "b", "c" ] + a.shift + a.push("foo") + a.should == ["b", "c", "foo"] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array if modification takes place" do + lambda { ArraySpecs.frozen_array.push(1) }.should raise_error(TypeError) + end + + it "does not raise on a frozen array if no modification is made" do + ArraySpecs.frozen_array.push() # ok + end + end +end diff --git a/1.8/core/array/rassoc_spec.rb b/1.8/core/array/rassoc_spec.rb new file mode 100644 index 0000000000..f78bda53fe --- /dev/null +++ b/1.8/core/array/rassoc_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#rassoc" do + it "returns the first contained array whose second element is == object" do + ary = [[1, "a", 0.5], [2, "b"], [3, "b"], [4, "c"], [], [5], [6, "d"]] + ary.rassoc("a").should == [1, "a", 0.5] + ary.rassoc("b").should == [2, "b"] + ary.rassoc("d").should == [6, "d"] + ary.rassoc("z").should == nil + end + + it "calls elem == obj on the second element of each contained array" do + key = 'foobar' + o = mock('foobar') + def o.==(other); other == 'foobar'; end + + [[1, :foobar], [2, o], [3, mock('foo')]].rassoc(key).should == [2, o] + end + + it "does not check the last element in each contained but speficically the second" do + key = 'foobar' + o = mock('foobar') + def o.==(other); other == 'foobar'; end + + [[1, :foobar, o], [2, o, 1], [3, mock('foo')]].rassoc(key).should == [2, o, 1] + end +end diff --git a/1.8/core/array/reject_spec.rb b/1.8/core/array/reject_spec.rb new file mode 100644 index 0000000000..456ad5f776 --- /dev/null +++ b/1.8/core/array/reject_spec.rb @@ -0,0 +1,61 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#reject" do + it "returns a new array without elements for which block is true" do + ary = [1, 2, 3, 4, 5] + ary.reject { true }.should == [] + ary.reject { false }.should == ary + ary.reject { nil }.should == ary + ary.reject { 5 }.should == [] + ary.reject { |i| i < 3 }.should == [3, 4, 5] + ary.reject { |i| i % 2 == 0 }.should == [1, 3, 5] + end + + # Returns ArraySpecs::MyArray on MRI 1.8 which is inconsistent with select. + # It has been changed on 1.9 however. + compliant_on(:ruby, :jruby) do + it "returns subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].reject { |x| x % 2 == 0 }.class.should == ArraySpecs::MyArray + end + end + + deviates_on(:r19, :rubinius) do + it "does not return subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].reject { |x| x % 2 == 0 }.class.should == Array + end + end +end + +describe "Array#reject!" do + it "removes elements for which block is true" do + a = [3, 4, 5, 6, 7, 8, 9, 10, 11] + a.reject! { |i| i % 2 == 0 }.equal?(a).should == true + a.should == [3, 5, 7, 9, 11] + a.reject! { |i| i > 8 } + a.should == [3, 5, 7] + a.reject! { |i| i < 4 } + a.should == [5, 7] + a.reject! { |i| i == 5 } + a.should == [7] + a.reject! { true } + a.should == [] + a.reject! { true } + a.should == [] + end + + it "returns nil if no changes are made" do + a = [1, 2, 3] + + a.reject! { |i| i < 0 }.should == nil + + a.reject! { true } + a.reject! { true }.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.reject! {} }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/replace_spec.rb b/1.8/core/array/replace_spec.rb new file mode 100644 index 0000000000..282e794c78 --- /dev/null +++ b/1.8/core/array/replace_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/replace' + +describe "Array#replace" do + it_behaves_like(:array_replace, :replace) +end diff --git a/1.8/core/array/reverse_each_spec.rb b/1.8/core/array/reverse_each_spec.rb new file mode 100644 index 0000000000..944a07c425 --- /dev/null +++ b/1.8/core/array/reverse_each_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#reverse_each" do + it "traverses array in reverse order and pass each element to block" do + a = [] + [1, 3, 4, 6].reverse_each { |i| a << i } + a.should == [6, 4, 3, 1] + end + +# Is this a valid requirement? -rue +compliant_on :r18, :jruby do + it "does not fail when removing elements from block" do + ary = [0, 0, 1, 1, 3, 2, 1, :x] + + count = 0 + + ary.reverse_each do |item| + count += 1 + + if item == :x then + ary.slice!(1..-1) + end + end + + count.should == 2 + end +end +end diff --git a/1.8/core/array/reverse_spec.rb b/1.8/core/array/reverse_spec.rb new file mode 100644 index 0000000000..9f723ea052 --- /dev/null +++ b/1.8/core/array/reverse_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#reverse" do + it "returns a new array with the elements in reverse order" do + [].reverse.should == [] + [1, 3, 5, 2].reverse.should == [2, 5, 3, 1] + end + + it "returns subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].reverse.class.should == ArraySpecs::MyArray + end +end + +describe "Array#reverse!" do + it "reverses the elements in place" do + a = [6, 3, 4, 2, 1] + a.reverse!.equal?(a).should == true + a.should == [1, 2, 4, 3, 6] + [].reverse!.should == [] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.reverse! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/rindex_spec.rb b/1.8/core/array/rindex_spec.rb new file mode 100644 index 0000000000..78a54dd931 --- /dev/null +++ b/1.8/core/array/rindex_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#rindex" do + it "returns the first index backwards from the end where element == to object" do + key = 3 + uno = mock('one') + dos = mock('two') + tres = mock('three') + tres.should_receive(:==).any_number_of_times.and_return(false) + dos.should_receive(:==).any_number_of_times.and_return(true) + uno.should_not_receive(:==) + ary = [uno, dos, tres] + + ary.rindex(key).should == 1 + end + + it "returns size-1 if last element == to object" do + [2, 1, 3, 2, 5].rindex(5).should == 4 + end + + it "returns 0 if only first element == to object" do + [2, 1, 3, 1, 5].rindex(2).should == 0 + end + + it "returns nil if no element == to object" do + [1, 1, 3, 2, 1, 3].rindex(4).should == nil + end + + it "does not fail when removing elements from block" do + sentinel = mock('sentinel') + ary = [0, 0, 1, 1, 3, 2, 1, sentinel] + + sentinel.instance_variable_set(:@ary, ary) + def sentinel.==(o) @ary.slice!(1..-1); false; end + + ary.rindex(0).should == 0 + end +end diff --git a/1.8/core/array/select_spec.rb b/1.8/core/array/select_spec.rb new file mode 100644 index 0000000000..4fc5c6ada5 --- /dev/null +++ b/1.8/core/array/select_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#select" do + it "returns a new array of elements for which block is true" do + [1, 3, 4, 5, 6, 9].select { |i| i % ((i + 1) / 2) == 0}.should == [1, 4, 6] + end + + it "does not return subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].select { true }.class.should == Array + end +end diff --git a/1.8/core/array/shared/clone.rb b/1.8/core/array/shared/clone.rb new file mode 100644 index 0000000000..d76ec5d826 --- /dev/null +++ b/1.8/core/array/shared/clone.rb @@ -0,0 +1,33 @@ +shared :array_clone do |cmd| + describe "Array##{cmd}" do + it "returns an Array or a subclass instance" do + [].send(cmd).class.should == Array + ArraySpecs::MyArray[1, 2].send(cmd).class.should == ArraySpecs::MyArray + end + + it "produces a shallow copy where the references are directly copied" do + a = [mock('1'), mock('2')] + b = a.send cmd + b.first.object_id.should == a.first.object_id + b.last.object_id.should == a.last.object_id + end + + it "creates a new array containing all elements or the original" do + a = [1, 2, 3, 4] + b = a.send cmd + b.should == a + b.__id__.should_not == a.__id__ + end + + it "copies taint status from the original" do + a = [1, 2, 3, 4] + b = [1, 2, 3, 4] + a.taint + aa = a.send cmd + bb = b.send cmd + + aa.tainted?.should == true + bb.tainted?.should == false + end + end +end diff --git a/1.8/core/array/shared/collect.rb b/1.8/core/array/shared/collect.rb new file mode 100644 index 0000000000..f5cddbb3a2 --- /dev/null +++ b/1.8/core/array/shared/collect.rb @@ -0,0 +1,29 @@ +shared :array_collect do |cmd| + describe "Array##{cmd}" do + it "returns a copy of array with each element replaced by the value returned by block" do + a = ['a', 'b', 'c', 'd'] + b = a.send(cmd) { |i| i + '!' } + b.should == ["a!", "b!", "c!", "d!"] + end + + it "does not return subclass instance" do + ArraySpecs::MyArray[1, 2, 3].send(cmd) { |x| x + 1 }.class.should == Array + end + end +end + +shared :array_collect_b do |cmd| + describe "Array##{cmd}" do + it "replaces each element with the value returned by block" do + a = [7, 9, 3, 5] + a.send(cmd) { |i| i - 1 }.equal?(a).should == true + a.should == [6, 8, 2, 4] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.send(cmd) {} }.should raise_error(TypeError) + end + end + end +end diff --git a/1.8/core/array/shared/equal.rb b/1.8/core/array/shared/equal.rb new file mode 100644 index 0000000000..73f6e1c9a6 --- /dev/null +++ b/1.8/core/array/shared/equal.rb @@ -0,0 +1,46 @@ +shared :array_equal do |cmd| + describe "Array##{cmd}" do + it "returns true if each element is == to the corresponding element in the other array" do + [].send(cmd, []).should == true + ["a", "c", 7].send(cmd, ["a", "c", 7]).should == true + [1, 2, [3, 4]].send(cmd, [1, 2, [3, 4]]).should == true + + obj = mock('5') + def obj.==(other) true end + [obj].send(cmd, [5]).should == true + end + + it "returns false if any element is not == to the corresponding element in the other the array" do + [ "a", "c" ].send(cmd, [ "a", "c", 7 ]).should == false + end + + it "returns false immediately when sizes of the arrays differ" do + obj = mock('1') + obj.should_not_receive(:==) + + [].send(cmd, obj).should == false + [obj].send(cmd, []).should == false + end + + # Broken in MRI as well. See MRI bug #11585: + # http://rubyforge.org/tracker/index.php?func=detail&aid=11585&group_id=426&atid=1698 + compliant_on(:r19) do + it "calls to_ary on its argument" do + obj = mock('to_ary') + obj.should_receive(:to_ary).and_return([1, 2, 3]) + + [1, 2, 3].send(cmd, obj).should == true + end + end + + it "does not call to_ary on array subclasses" do + ([5, 6, 7] == ArraySpecs::ToAryArray[5, 6, 7]).should == true + end + + it "ignores array class differences" do + ArraySpecs::MyArray[1, 2, 3].send(cmd, [1, 2, 3]).should == true + ArraySpecs::MyArray[1, 2, 3].send(cmd, ArraySpecs::MyArray[1, 2, 3]).should == true + [1, 2, 3].send(cmd, ArraySpecs::MyArray[1, 2, 3]).should == true + end + end +end \ No newline at end of file diff --git a/1.8/core/array/shared/indexes.rb b/1.8/core/array/shared/indexes.rb new file mode 100644 index 0000000000..21bf492c49 --- /dev/null +++ b/1.8/core/array/shared/indexes.rb @@ -0,0 +1,33 @@ +shared :array_indexes do |cmd| + describe "Array##{cmd}" do + it "returns elements at integer argument indexes (DEPRECATED)" do + array = [1, 2, 3, 4, 5] + + x = mock('4') + def x.to_int() 4 end + + params = [1, 0, 5, -1, -8, 10, x] + array.send(cmd, *params).should == array.values_at(*params) + end + + it "calls to_int on arguments" do + array = [1, 2, 3, 4, 5] + + x = mock('4') + def x.to_int() 4 end + array.send(cmd, x).should == [5] + + x = mock('2') + x.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + x.should_receive(:method_missing).with(:to_int).and_return(2) + array.send(cmd, x).should == [3] + end + + it "returns elements in range arguments as nested arrays (DEPRECATED)" do + array = [1, 2, 3, 4, 5] + params = [0..2, 1...3, 4..6] + array.indexes(*params).should == [[1, 2, 3], [2, 3], [5]] + array.indices(*params).should == [[1, 2, 3], [2, 3], [5]] + end + end +end diff --git a/1.8/core/array/shared/length.rb b/1.8/core/array/shared/length.rb new file mode 100644 index 0000000000..cc9e3130ed --- /dev/null +++ b/1.8/core/array/shared/length.rb @@ -0,0 +1,8 @@ +shared :array_length do |cmd| + describe "Array##{cmd}" do + it "returns the number of elements" do + [].send(cmd).should == 0 + [1, 2, 3].send(cmd).should == 3 + end + end +end diff --git a/1.8/core/array/shared/replace.rb b/1.8/core/array/shared/replace.rb new file mode 100644 index 0000000000..4e233825fc --- /dev/null +++ b/1.8/core/array/shared/replace.rb @@ -0,0 +1,45 @@ +shared :array_replace do |cmd| + describe "Array##{cmd}" do + it "replaces the elements with elements from other array" do + a = [1, 2, 3, 4, 5] + b = ['a', 'b', 'c'] + a.send(cmd, b).equal?(a).should == true + a.should == b + a.equal?(b).should == false + + a.send(cmd, [4] * 10) + a.should == [4] * 10 + + a.send(cmd, []) + a.should == [] + end + + it "calls to_ary on its argument" do + obj = mock('[1,2,3]') + def obj.to_ary() [1, 2, 3] end + + ary = [] + ary.send(cmd, obj) + ary.should == [1, 2, 3] + + obj = mock('[]') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).and_return([]) + + ary.send(cmd, obj) + ary.should == [] + end + + it "does not call to_ary on array subclasses" do + ary = [] + ary.send(cmd, ArraySpecs::ToAryArray[5, 6, 7]) + ary.should == [5, 6, 7] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.send(cmd, ArraySpecs.frozen_array) }.should raise_error(TypeError) + end + end + end +end diff --git a/1.8/core/array/shared/slice.rb b/1.8/core/array/shared/slice.rb new file mode 100644 index 0000000000..bdb0b4fb6c --- /dev/null +++ b/1.8/core/array/shared/slice.rb @@ -0,0 +1,427 @@ +shared :array_slice do |cmd| + describe "Array##{cmd}" do + it "returns the element at index with [index]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 1).should == "b" + + a = [1, 2, 3, 4] + + a.send(cmd, 0).should == 1 + a.send(cmd, 1).should == 2 + a.send(cmd, 2).should == 3 + a.send(cmd, 3).should == 4 + a.send(cmd, 4).should == nil + a.send(cmd, 10).should == nil + + a.should == [1, 2, 3, 4] + end + + it "returns the element at index from the end of the array with [-index]" do + [ "a", "b", "c", "d", "e" ].send(cmd, -2).should == "d" + + a = [1, 2, 3, 4] + + a.send(cmd, -1).should == 4 + a.send(cmd, -2).should == 3 + a.send(cmd, -3).should == 2 + a.send(cmd, -4).should == 1 + a.send(cmd, -5).should == nil + a.send(cmd, -10).should == nil + + a.should == [1, 2, 3, 4] + end + + it "return count elements starting from index with [index, count]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 2, 3).should == ["c", "d", "e"] + + a = [1, 2, 3, 4] + + a.send(cmd, 0, 0).should == [] + a.send(cmd, 0, 1).should == [1] + a.send(cmd, 0, 2).should == [1, 2] + a.send(cmd, 0, 4).should == [1, 2, 3, 4] + a.send(cmd, 0, 6).should == [1, 2, 3, 4] + a.send(cmd, 0, -1).should == nil + a.send(cmd, 0, -2).should == nil + a.send(cmd, 0, -4).should == nil + + a.send(cmd, 2, 0).should == [] + a.send(cmd, 2, 1).should == [3] + a.send(cmd, 2, 2).should == [3, 4] + a.send(cmd, 2, 4).should == [3, 4] + a.send(cmd, 2, -1).should == nil + + a.send(cmd, 4, 0).should == [] + a.send(cmd, 4, 2).should == [] + a.send(cmd, 4, -1).should == nil + + a.send(cmd, 5, 0).should == nil + a.send(cmd, 5, 2).should == nil + a.send(cmd, 5, -1).should == nil + + a.send(cmd, 6, 0).should == nil + a.send(cmd, 6, 2).should == nil + a.send(cmd, 6, -1).should == nil + + a.should == [1, 2, 3, 4] + end + + it "returns count elements starting at index from the end of array with [-index, count]" do + [ "a", "b", "c", "d", "e" ].send(cmd, -2, 2).should == ["d", "e"] + + a = [1, 2, 3, 4] + + a.send(cmd, -1, 0).should == [] + a.send(cmd, -1, 1).should == [4] + a.send(cmd, -1, 2).should == [4] + a.send(cmd, -1, -1).should == nil + + a.send(cmd, -2, 0).should == [] + a.send(cmd, -2, 1).should == [3] + a.send(cmd, -2, 2).should == [3, 4] + a.send(cmd, -2, 4).should == [3, 4] + a.send(cmd, -2, -1).should == nil + + a.send(cmd, -4, 0).should == [] + a.send(cmd, -4, 1).should == [1] + a.send(cmd, -4, 2).should == [1, 2] + a.send(cmd, -4, 4).should == [1, 2, 3, 4] + a.send(cmd, -4, 6).should == [1, 2, 3, 4] + a.send(cmd, -4, -1).should == nil + + a.send(cmd, -5, 0).should == nil + a.send(cmd, -5, 1).should == nil + a.send(cmd, -5, 10).should == nil + a.send(cmd, -5, -1).should == nil + + a.should == [1, 2, 3, 4] + end + + it "returns the first count elements with [0, count]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 0, 3).should == ["a", "b", "c"] + end + + it "calls to_int on index and count arguments with [index, count]" do + obj = mock('2') + def obj.to_int() 2 end + + a = [1, 2, 3, 4] + a.send(cmd, obj).should == 3 + a.send(cmd, obj, 1).should == [3] + a.send(cmd, obj, obj).should == [3, 4] + a.send(cmd, 0, obj).should == [1, 2] + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(2) + a.send(cmd, obj).should == 3 + end + + it "returns the elements specified by Range indexes with [m..n]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 1..3).should == ["b", "c", "d"] + [ "a", "b", "c", "d", "e" ].send(cmd, 4..-1).should == ['e'] + [ "a", "b", "c", "d", "e" ].send(cmd, 3..3).should == ['d'] + [ "a", "b", "c", "d", "e" ].send(cmd, 3..-2).should == ['d'] + ['a'].send(cmd, 0..-1).should == ['a'] + + a = [1, 2, 3, 4] + + a.send(cmd, 0..-10).should == [] + a.send(cmd, 0..0).should == [1] + a.send(cmd, 0..1).should == [1, 2] + a.send(cmd, 0..2).should == [1, 2, 3] + a.send(cmd, 0..3).should == [1, 2, 3, 4] + a.send(cmd, 0..4).should == [1, 2, 3, 4] + a.send(cmd, 0..10).should == [1, 2, 3, 4] + + a.send(cmd, 2..-10).should == [] + a.send(cmd, 2..0).should == [] + a.send(cmd, 2..2).should == [3] + a.send(cmd, 2..3).should == [3, 4] + a.send(cmd, 2..4).should == [3, 4] + + a.send(cmd, 3..0).should == [] + a.send(cmd, 3..3).should == [4] + a.send(cmd, 3..4).should == [4] + + a.send(cmd, 4..0).should == [] + a.send(cmd, 4..4).should == [] + a.send(cmd, 4..5).should == [] + + a.send(cmd, 5..0).should == nil + a.send(cmd, 5..5).should == nil + a.send(cmd, 5..6).should == nil + + a.should == [1, 2, 3, 4] + end + + it "returns elements specified by Range indexes except the element at index n with [m...n]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 1...3).should == ["b", "c"] + + a = [1, 2, 3, 4] + + a.send(cmd, 0...-10).should == [] + a.send(cmd, 0...0).should == [] + a.send(cmd, 0...1).should == [1] + a.send(cmd, 0...2).should == [1, 2] + a.send(cmd, 0...3).should == [1, 2, 3] + a.send(cmd, 0...4).should == [1, 2, 3, 4] + a.send(cmd, 0...10).should == [1, 2, 3, 4] + + a.send(cmd, 2...-10).should == [] + a.send(cmd, 2...0).should == [] + a.send(cmd, 2...2).should == [] + a.send(cmd, 2...3).should == [3] + a.send(cmd, 2...4).should == [3, 4] + + a.send(cmd, 3...0).should == [] + a.send(cmd, 3...3).should == [] + a.send(cmd, 3...4).should == [4] + + a.send(cmd, 4...0).should == [] + a.send(cmd, 4...4).should == [] + a.send(cmd, 4...5).should == [] + + a.send(cmd, 5...0).should == nil + a.send(cmd, 5...5).should == nil + a.send(cmd, 5...6).should == nil + + a.should == [1, 2, 3, 4] + end + + it "returns elements that exist if range start is in the array but range end is not with [m..n]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 4..7).should == ["e"] + end + + it "accepts Range instances having a negative m and both signs for n with [m..n] and [m...n]" do + a = [1, 2, 3, 4] + + a.send(cmd, -1..-1).should == [4] + a.send(cmd, -1...-1).should == [] + a.send(cmd, -1..3).should == [4] + a.send(cmd, -1...3).should == [] + a.send(cmd, -1..4).should == [4] + a.send(cmd, -1...4).should == [4] + a.send(cmd, -1..10).should == [4] + a.send(cmd, -1...10).should == [4] + a.send(cmd, -1..0).should == [] + a.send(cmd, -1..-4).should == [] + a.send(cmd, -1...-4).should == [] + a.send(cmd, -1..-6).should == [] + a.send(cmd, -1...-6).should == [] + + a.send(cmd, -2..-2).should == [3] + a.send(cmd, -2...-2).should == [] + a.send(cmd, -2..-1).should == [3, 4] + a.send(cmd, -2...-1).should == [3] + a.send(cmd, -2..10).should == [3, 4] + a.send(cmd, -2...10).should == [3, 4] + + a.send(cmd, -4..-4).should == [1] + a.send(cmd, -4..-2).should == [1, 2, 3] + a.send(cmd, -4...-2).should == [1, 2] + a.send(cmd, -4..-1).should == [1, 2, 3, 4] + a.send(cmd, -4...-1).should == [1, 2, 3] + a.send(cmd, -4..3).should == [1, 2, 3, 4] + a.send(cmd, -4...3).should == [1, 2, 3] + a.send(cmd, -4..4).should == [1, 2, 3, 4] + a.send(cmd, -4...4).should == [1, 2, 3, 4] + a.send(cmd, -4...4).should == [1, 2, 3, 4] + a.send(cmd, -4..0).should == [1] + a.send(cmd, -4...0).should == [] + a.send(cmd, -4..1).should == [1, 2] + a.send(cmd, -4...1).should == [1] + + a.send(cmd, -5..-5).should == nil + a.send(cmd, -5...-5).should == nil + a.send(cmd, -5..-4).should == nil + a.send(cmd, -5..-1).should == nil + a.send(cmd, -5..10).should == nil + + a.should == [1, 2, 3, 4] + end + + it "calls to_int on Range arguments with [m..n] and [m...n]" do + from = mock('from') + to = mock('to') + + # So we can construct a range out of them... + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + def from.to_int() 1 end + def to.to_int() -2 end + + a = [1, 2, 3, 4] + + a.send(cmd, from..to).should == [2, 3] + a.send(cmd, from...to).should == [2] + a.send(cmd, 1..0).should == [] + a.send(cmd, 1...0).should == [] + + lambda { a.slice("a" .. "b") }.should raise_error(TypeError) + lambda { a.slice("a" ... "b") }.should raise_error(TypeError) + lambda { a.slice(from .. "b") }.should raise_error(TypeError) + lambda { a.slice(from ... "b") }.should raise_error(TypeError) + + from = mock('from') + to = mock('to') + + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + from.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + from.should_receive(:method_missing).with(:to_int).and_return(1) + to.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + to.should_receive(:method_missing).with(:to_int).and_return(-2) + a.send(cmd, from..to).should == [2, 3] + end + + it "returns the same elements as [m..n] and [m...n] with Range subclasses" do + a = [1, 2, 3, 4] + range_incl = ArraySpecs::MyRange.new(1, 2) + range_excl = ArraySpecs::MyRange.new(-3, -1, true) + + a[range_incl].should == [2, 3] + a[range_excl].should == [2, 3] + end + + it "returns nil for a requested index not in the array with [index]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 5).should == nil + end + + it "returns [] if the index is valid but length is zero with [index, length]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 0, 0).should == [] + [ "a", "b", "c", "d", "e" ].send(cmd, 2, 0).should == [] + end + + it "returns nil if length is zero but index is invalid with [index, length]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 100, 0).should == nil + [ "a", "b", "c", "d", "e" ].send(cmd, -50, 0).should == nil + end + + # This is by design. It is in the official documentation. + it "returns [] if index == array.size with [index, length]" do + %w|a b c d e|.send(cmd, 5, 2).should == [] + end + + it "returns nil if index > array.size with [index, length]" do + %w|a b c d e|.send(cmd, 6, 2).should == nil + end + + it "returns nil if length is negative with [index, length]" do + %w|a b c d e|.send(cmd, 3, -1).should == nil + %w|a b c d e|.send(cmd, 2, -2).should == nil + %w|a b c d e|.send(cmd, 1, -100).should == nil + end + + it "returns nil if no requested index is in the array with [m..n]" do + [ "a", "b", "c", "d", "e" ].send(cmd, 6..10).should == nil + end + + it "returns nil if range start is not in the array with [m..n]" do + [ "a", "b", "c", "d", "e" ].send(cmd, -10..2).should == nil + [ "a", "b", "c", "d", "e" ].send(cmd, 10..12).should == nil + end + + it "returns an empty array when m == n with [m...n]" do + [1, 2, 3, 4, 5].send(cmd, 1...1).should == [] + end + + it "returns an empty array with [0...0]" do + [1, 2, 3, 4, 5].send(cmd, 0...0).should == [] + end + + it "returns a subarray where m, n negatives and m < n with [m..n]" do + [ "a", "b", "c", "d", "e" ].send(cmd, -3..-2).should == ["c", "d"] + end + + it "returns an array containing the first element with [0..0]" do + [1, 2, 3, 4, 5].send(cmd, 0..0).should == [1] + end + + it "returns the entire array with [0..-1]" do + [1, 2, 3, 4, 5].send(cmd, 0..-1).should == [1, 2, 3, 4, 5] + end + + it "returns all but the last element with [0...-1]" do + [1, 2, 3, 4, 5].send(cmd, 0...-1).should == [1, 2, 3, 4] + end + + it "returns [3] for [2..-1] out of [1, 2, 3] " do + [1,2,3].send(cmd, 2..-1).should == [3] + end + + it "returns an empty array when m > n and m, n are positive with [m..n]" do + [1, 2, 3, 4, 5].send(cmd, 3..2).should == [] + end + + it "returns an empty array when m > n and m, n are negative with [m..n]" do + [1, 2, 3, 4, 5].send(cmd, -2..-3).should == [] + end + + it "does not expand array when the indices are outside of the array bounds" do + a = [1, 2] + a.send(cmd, 4).should == nil + a.should == [1, 2] + a.send(cmd, 4, 0).should == nil + a.should == [1, 2] + a.send(cmd, 6, 1).should == nil + a.should == [1, 2] + a.send(cmd, 8...8).should == nil + a.should == [1, 2] + a.send(cmd, 10..10).should == nil + a.should == [1, 2] + end + + it "returns a subclass instance when called on a subclass of Array" do + ary = ArraySpecs::MyArray[1, 2, 3] + ary.send(cmd, 0, 0).class.should == ArraySpecs::MyArray + ary.send(cmd, 0, 2).class.should == ArraySpecs::MyArray + ary.send(cmd, 0..10).class.should == ArraySpecs::MyArray + end + + not_compliant_on :rubinius do + it "raises a RangeError when the start index is out of range of Fixnum" do + array = [1, 2, 3, 4, 5, 6] + obj = mock('large value') + obj.should_receive(:to_int).and_return(0x8000_0000_0000_0000_0000) + lambda { array.send(cmd, obj) }.should raise_error(RangeError) + + obj = 8e19 + lambda { array.send(cmd, obj) }.should raise_error(RangeError) + end + + it "raises a RangeError when the length is out of range of Fixnum" do + array = [1, 2, 3, 4, 5, 6] + obj = mock('large value') + obj.should_receive(:to_int).and_return(0x8000_0000_0000_0000_0000) + lambda { array.send(cmd, 1, obj) }.should raise_error(RangeError) + + obj = 8e19 + lambda { array.send(cmd, 1, obj) }.should raise_error(RangeError) + end + end + + deviates_on :rubinius do + it "raises a TypeError when the start index is out of range of Fixnum" do + array = [1, 2, 3, 4, 5, 6] + obj = mock('large value') + obj.should_receive(:to_int).and_return(0x8000_0000_0000_0000_0000) + lambda { array.send(cmd, obj) }.should raise_error(TypeError) + + obj = 8e19 + lambda { array.send(cmd, obj) }.should raise_error(TypeError) + end + + it "raises a TypeError when the length is out of range of Fixnum" do + array = [1, 2, 3, 4, 5, 6] + obj = mock('large value') + obj.should_receive(:to_int).and_return(0x8000_0000_0000_0000_0000) + lambda { array.send(cmd, 1, obj) }.should raise_error(TypeError) + + obj = 8e19 + lambda { array.send(cmd, 1, obj) }.should raise_error(TypeError) + end + end + end +end diff --git a/1.8/core/array/shift_spec.rb b/1.8/core/array/shift_spec.rb new file mode 100644 index 0000000000..de7beb1f37 --- /dev/null +++ b/1.8/core/array/shift_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#shift" do + it "removes and returns the first element" do + a = [5, 1, 1, 5, 4] + a.shift.should == 5 + a.should == [1, 1, 5, 4] + a.shift.should == 1 + a.should == [1, 5, 4] + a.shift.should == 1 + a.should == [5, 4] + a.shift.should == 5 + a.should == [4] + a.shift.should == 4 + a.should == [] + end + + it "returns nil when the array is empty" do + [].shift.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.shift }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/size_spec.rb b/1.8/core/array/size_spec.rb new file mode 100644 index 0000000000..830f18bd1f --- /dev/null +++ b/1.8/core/array/size_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/length' + +describe "Array#size" do + it_behaves_like(:array_length, :size) +end diff --git a/1.8/core/array/slice_spec.rb b/1.8/core/array/slice_spec.rb new file mode 100644 index 0000000000..e306526e01 --- /dev/null +++ b/1.8/core/array/slice_spec.rb @@ -0,0 +1,136 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/slice' + +describe "Array#slice!" do + it "removes and return the element at index" do + a = [1, 2, 3, 4] + a.slice!(10).should == nil + a.should == [1, 2, 3, 4] + a.slice!(-10).should == nil + a.should == [1, 2, 3, 4] + a.slice!(2).should == 3 + a.should == [1, 2, 4] + a.slice!(-1).should == 4 + a.should == [1, 2] + a.slice!(1).should == 2 + a.should == [1] + a.slice!(-1).should == 1 + a.should == [] + a.slice!(-1).should == nil + a.should == [] + a.slice!(0).should == nil + a.should == [] + end + + it "removes and returns length elements beginning at start" do + a = [1, 2, 3, 4, 5, 6] + a.slice!(2, 3).should == [3, 4, 5] + a.should == [1, 2, 6] + a.slice!(1, 1).should == [2] + a.should == [1, 6] + a.slice!(1, 0).should == [] + a.should == [1, 6] + a.slice!(2, 0).should == [] + a.should == [1, 6] + a.slice!(0, 4).should == [1, 6] + a.should == [] + a.slice!(0, 4).should == [] + a.should == [] + end + + it "calls to_int on start and length arguments" do + obj = mock('2') + def obj.to_int() 2 end + + a = [1, 2, 3, 4, 5] + a.slice!(obj).should == 3 + a.should == [1, 2, 4, 5] + a.slice!(obj, obj).should == [4, 5] + a.should == [1, 2] + a.slice!(0, obj).should == [1, 2] + a.should == [] + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).any_number_of_times.and_return(2) + a = [1, 2, 3, 4, 5] + a.slice!(obj).should == 3 + end + + it "removes and return elements in range" do + a = [1, 2, 3, 4, 5, 6, 7, 8] + a.slice!(1..4).should == [2, 3, 4, 5] + a.should == [1, 6, 7, 8] + a.slice!(1...3).should == [6, 7] + a.should == [1, 8] + a.slice!(-1..-1).should == [8] + a.should == [1] + a.slice!(0...0).should == [] + a.should == [1] + a.slice!(0..0).should == [1] + a.should == [] + end + + it "calls to_int on range arguments" do + from = mock('from') + to = mock('to') + + # So we can construct a range out of them... + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + def from.to_int() 1 end + def to.to_int() -2 end + + a = [1, 2, 3, 4, 5] + + a.slice!(from .. to).should == [2, 3, 4] + a.should == [1, 5] + + lambda { a.slice!("a" .. "b") }.should raise_error(TypeError) + lambda { a.slice!(from .. "b") }.should raise_error(TypeError) + + from = mock('from') + to = mock('to') + + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + from.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + from.should_receive(:method_missing).with(:to_int).any_number_of_times.and_return(1) + to.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + to.should_receive(:method_missing).with(:to_int).any_number_of_times.and_return(-2) + + a = [1, 2, 3, 4, 5] + a.slice!(from .. to).should == [2, 3, 4] + end + + # TODO: MRI behaves inconsistently here. I'm trying to find out what it should + # do at ruby-core right now. -- flgr + # See http://groups.google.com/group/ruby-core-google/t/af70e3d0e9b82f39 + it "does (not?) expand array with indices out of bounds" do + # This is the way MRI behaves -- subject to change + a = [1, 2] + a.slice!(4).should == nil + a.should == [1, 2] + a.slice!(4, 0).should == nil + a.should == [1, 2, nil, nil] + a.slice!(6, 1).should == nil + a.should == [1, 2, nil, nil, nil, nil] + a.slice!(8...8).should == nil + a.should == [1, 2, nil, nil, nil, nil, nil, nil] + a.slice!(10..10).should == nil + a.should == [1, 2, nil, nil, nil, nil, nil, nil, nil, nil] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.slice!(0, 0) }.should raise_error(TypeError) + end + end +end + +describe "Array#slice" do + it_behaves_like(:array_slice, :slice) +end diff --git a/1.8/core/array/sort_spec.rb b/1.8/core/array/sort_spec.rb new file mode 100644 index 0000000000..05ec5f5763 --- /dev/null +++ b/1.8/core/array/sort_spec.rb @@ -0,0 +1,124 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +module ArraySpecs + class SortSame + def <=>(other); 0; end + def ==(other); true; end + end + + class UFOSceptic + def <=>(other); raise "N-uh, UFO:s do not exist!"; end + end +end + + +describe "Array#sort" do + + it "returns a new array sorted based on comparing elements with <=>" do + a = [1, -2, 3, 9, 1, 5, -5, 1000, -5, 2, -10, 14, 6, 23, 0] + a.sort.should == [-10, -5, -5, -2, 0, 1, 1, 2, 3, 5, 6, 9, 14, 23, 1000] + end + + it "does not affect the original Array" do + a = [0, 15, 2, 3, 4, 6, 14, 5, 7, 12, 8, 9, 1, 10, 11, 13] + b = a.sort + a.should == [0, 15, 2, 3, 4, 6, 14, 5, 7, 12, 8, 9, 1, 10, 11, 13] + b.should == (0..15).to_a + end + + it "sorts already-sorted Arrays" do + (0..15).to_a.sort.should == (0..15).to_a + end + + it "sorts reverse-sorted Arrays" do + (0..15).to_a.reverse.sort.should == (0..15).to_a + end + + it "sorts Arrays that consist entirely of equal elements" do + a = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + a.sort.should == a + b = Array.new(15).map { ArraySpecs::SortSame.new } + b.sort.should == b + end + + it "sorts Arrays that consist mostly of equal elements" do + a = [1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1] + a.sort.should == [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + end + + it "does not deal with exceptions raised by unimplemented or incorrect #<=>" do + o = Object.new + + lambda { [o, 1].sort }.should raise_error + end + + it "may leave the Array partially sorted if the sorting fails at any point" do + true.should == true # Muhaha. + end + + it "may take a block which is used to determine the order of objects a and b described as -1, 0 or +1" do + a = [5, 1, 4, 3, 2] + a.sort.should == [1, 2, 3, 4, 5] + a.sort {|x, y| y <=> x}.should == [5, 4, 3, 2, 1] + end + + it "does not call #<=> on contained objects when invoked with a block" do + a = Array.new(25) + (0...25).each {|i| a[i] = ArraySpecs::UFOSceptic.new } + + a.sort { -1 }.class.should == Array + end + + it "does not call #<=> on elements when invoked with a block even if Array is large (Rubinius #412)" do + a = Array.new(1500) + (0...1500).each {|i| a[i] = ArraySpecs::UFOSceptic.new } + + a.sort { -1 }.class.should == Array + end + + it "completes when supplied a block that always returns the same result" do + a = [2, 3, 5, 1, 4] + a.sort { 1 }.class.should == Array + a.sort { 0 }.class.should == Array + a.sort { -1 }.class.should == Array + end + + it "returns subclass instance on Array subclasses" do + ary = ArraySpecs::MyArray[1, 2, 3] + ary.sort.class.should == ArraySpecs::MyArray + end +end + +describe "Array#sort!" do + it "sorts array in place using <=>" do + a = [1, -2, 3, 9, 1, 5, -5, 1000, -5, 2, -10, 14, 6, 23, 0] + a.sort! + a.should == [-10, -5, -5, -2, 0, 1, 1, 2, 3, 5, 6, 9, 14, 23, 1000] + end + + it "sorts array in place using block value" do + a = [0, 15, 2, 3, 4, 6, 14, 5, 7, 12, 8, 9, 1, 10, 11, 13] + a.sort! { |x, y| y <=> x }.should == (0..15).to_a.reverse + end + + it "does not call #<=> on contained objects when invoked with a block" do + a = Array.new(25) + (0...25).each {|i| a[i] = ArraySpecs::UFOSceptic.new } + + a.sort! { -1 }.class.should == Array + end + + it "does not call #<=> on elements when invoked with a block even if Array is large (Rubinius #412)" do + a = Array.new(1500) + (0...1500).each {|i| a[i] = ArraySpecs::UFOSceptic.new } + + a.sort! { -1 }.class.should == Array + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.sort! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/array/to_a_spec.rb b/1.8/core/array/to_a_spec.rb new file mode 100644 index 0000000000..0aa7b565dc --- /dev/null +++ b/1.8/core/array/to_a_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#to_a" do + it "returns self" do + a = [1, 2, 3] + a.to_a.should == [1, 2, 3] + a.equal?(a.to_a).should == true + end + + it "does not return subclass instance on Array subclasses" do + e = ArraySpecs::MyArray.new + e << 1 + e.to_a.class.should == Array + e.to_a.should == [1] + end +end diff --git a/1.8/core/array/to_ary_spec.rb b/1.8/core/array/to_ary_spec.rb new file mode 100644 index 0000000000..f47c294bcc --- /dev/null +++ b/1.8/core/array/to_ary_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#to_ary" do + it "returns self" do + a = [1, 2, 3] + a.equal?(a.to_ary).should == true + a = ArraySpecs::MyArray[1, 2, 3] + a.equal?(a.to_ary).should == true + end +end diff --git a/1.8/core/array/to_s_spec.rb b/1.8/core/array/to_s_spec.rb new file mode 100644 index 0000000000..b1400eed35 --- /dev/null +++ b/1.8/core/array/to_s_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#to_s" do + it "is equivalent to #join without a separator string" do + old = $, + a = [1, 2, 3, 4] + a.to_s.should == a.join + $, = '-' + a.to_s.should == a.join + $, = old + end +end diff --git a/1.8/core/array/transpose_spec.rb b/1.8/core/array/transpose_spec.rb new file mode 100644 index 0000000000..ab7b77589e --- /dev/null +++ b/1.8/core/array/transpose_spec.rb @@ -0,0 +1,45 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#transpose" do + it "assumes an array of arrays and returns the result of transposing rows and columns" do + [[1, 'a'], [2, 'b'], [3, 'c']].transpose.should == [[1, 2, 3], ["a", "b", "c"]] + [[1, 2, 3], ["a", "b", "c"]].transpose.should == [[1, 'a'], [2, 'b'], [3, 'c']] + [].transpose.should == [] + [[]].transpose.should == [] + [[], []].transpose.should == [] + [[0]].transpose.should == [[0]] + [[0], [1]].transpose.should == [[0, 1]] + end + + it "raises if the items aren't arrays and don't respond to to_ary" do + g = mock('[1,2]') + def g.to_a() [1, 2] end + h = mock('[1,2]') + def h.to_ary() [1, 2] end + + lambda { [g, [:a, :b]].transpose }.should raise_error(TypeError) + [h, [:a, :b]].transpose.should == [[1, :a], [2, :b]] + + h = mock('[1,2]') + h.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + h.should_receive(:method_missing).with(:to_ary).and_return([1, 2]) + [h, [:a, :b]].transpose.should == [[1, :a], [2, :b]] + end + + it "does not call to_ary on array subclass elements" do + ary = [ArraySpecs::ToAryArray[1, 2], ArraySpecs::ToAryArray[4, 6]] + ary.transpose.should == [[1, 4], [2, 6]] + end + + it "raises an IndexError if the arrays are not of the same length" do + lambda { [[1, 2], [:a]].transpose }.should raise_error(IndexError) + end + + it "does not return subclass instance on Array subclasses" do + result = ArraySpecs::MyArray[ArraySpecs::MyArray[1, 2, 3], ArraySpecs::MyArray[4, 5, 6]].transpose + result.class.should == Array + result[0].class.should == Array + result[1].class.should == Array + end +end diff --git a/1.8/core/array/union_spec.rb b/1.8/core/array/union_spec.rb new file mode 100644 index 0000000000..5560fe8f71 --- /dev/null +++ b/1.8/core/array/union_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#|" do + it "returns an array of elements that appear in either array (union)" do + ([] | []).should == [] + ([1, 2] | []).should == [1, 2] + ([] | [1, 2]).should == [1, 2] + ([ 1, 2, 3, 4 ] | [ 3, 4, 5 ]).should == [1, 2, 3, 4, 5] + end + + it "creates an array with no duplicates" do + ([ 1, 2, 3, 1, 4, 5 ] | [ 1, 3, 4, 5, 3, 6 ]).should == [1, 2, 3, 4, 5, 6] + end + + it "creates an array with elements in order they are first encountered" do + ([ 1, 2, 3, 1 ] | [ 1, 3, 4, 5 ]).should == [1, 2, 3, 4, 5] + end + + it "calls to_ary on its argument" do + obj = mock('[1,2,3]') + def obj.to_ary() [1, 2, 3] end + ([0] | obj).should == ([0] | obj.to_ary) + + obj = mock('[1,2,3]') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).and_return([1, 2, 3]) + ([0] | obj).should == [0, 1, 2, 3] + end + + # MRI doesn't actually call eql?() however. So you can't reimplement it. + it "acts as if using eql?" do + ([5.0, 4.0] | [5, 4]).should == [5.0, 4.0, 5, 4] + str = "x" + ([str] | [str.dup]).should == [str] + end + + it "does not return subclass instances for Array subclasses" do + (ArraySpecs::MyArray[1, 2, 3] | []).class.should == Array + (ArraySpecs::MyArray[1, 2, 3] | ArraySpecs::MyArray[1, 2, 3]).class.should == Array + ([] | ArraySpecs::MyArray[1, 2, 3]).class.should == Array + end + + it "does not call to_ary on array subclasses" do + ([1, 2] | ArraySpecs::ToAryArray[5, 6]).should == [1, 2, 5, 6] + end +end diff --git a/1.8/core/array/uniq_spec.rb b/1.8/core/array/uniq_spec.rb new file mode 100644 index 0000000000..06726a7df3 --- /dev/null +++ b/1.8/core/array/uniq_spec.rb @@ -0,0 +1,105 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#uniq" do + it "returns an array with no duplicates" do + ["a", "a", "b", "b", "c"].uniq.should == ["a", "b", "c"] + end + + it "uses eql? semantics" do + [1.0, 1].uniq.should == [1.0, 1] + end + + it "compares elements first with hash" do + # Can't use should_receive because it uses hash internally + x = mock('0') + def x.hash() 0 end + y = mock('0') + def y.hash() 0 end + + [x, y].uniq + end + + it "does not compare elements with different hash codes via eql?" do + # Can't use should_receive because it uses hash and eql? internally + x = mock('0') + def x.eql?(o) raise("Shouldn't receive eql?") end + y = mock('1') + def y.eql?(o) raise("Shouldn't receive eql?") end + + def x.hash() 0 end + def y.hash() 1 end + + [x, y].uniq.should == [x, y] + end + + it "compares elements with matching hash codes with #eql?" do + # Can't use should_receive because it uses hash and eql? internally + a = Array.new(2) do + obj = mock('0') + + def obj.hash() + # It's undefined whether the impl does a[0].eql?(a[1]) or + # a[1].eql?(a[0]) so we taint both. + def self.eql?(o) taint; o.taint; false; end + return 0 + end + + obj + end + + a.uniq.should == a + a[0].tainted?.should == true + a[1].tainted?.should == true + + a = Array.new(2) do + obj = mock('0') + + def obj.hash() + # It's undefined whether the impl does a[0].eql?(a[1]) or + # a[1].eql?(a[0]) so we taint both. + def self.eql?(o) taint; o.taint; true; end + return 0 + end + + obj + end + + a.uniq.size.should == 1 + a[0].tainted?.should == true + a[1].tainted?.should == true + end + + it "returns subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].uniq.class.should == ArraySpecs::MyArray + end +end + +describe "Array#uniq!" do + it "modifies the array in place" do + a = [ "a", "a", "b", "b", "c" ] + a.uniq! + a.should == ["a", "b", "c"] + end + + it "returns self" do + a = [ "a", "a", "b", "b", "c" ] + a.equal?(a.uniq!).should == true + end + + it "returns nil if no changes are made to the array" do + [ "a", "b", "c" ].uniq!.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array if modification would take place" do + dup_ary = [1, 1, 2] + dup_ary.freeze + lambda { dup_ary.uniq! }.should raise_error(TypeError) + end + + it "does not raise TypeError on a frozen array if no modification takes place" do + ArraySpecs.frozen_array.uniq! # ok, already uniq + end + end +end diff --git a/1.8/core/array/unshift_spec.rb b/1.8/core/array/unshift_spec.rb new file mode 100644 index 0000000000..daac01b1df --- /dev/null +++ b/1.8/core/array/unshift_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#unshift" do + it "prepends object to the original array" do + a = [1, 2, 3] + a.unshift("a").equal?(a).should == true + a.should == ['a', 1, 2, 3] + a.unshift().equal?(a).should == true + a.should == ['a', 1, 2, 3] + a.unshift(5, 4, 3) + a.should == [5, 4, 3, 'a', 1, 2, 3] + + # shift all but one element + a = [1, 2] + a.shift + a.unshift(3, 4) + a.should == [3, 4, 2] + + # now shift all elements + a.shift + a.shift + a.shift + a.unshift(3, 4) + a.should == [3, 4] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError on a frozen array" do + lambda { ArraySpecs.frozen_array.unshift(1) }.should raise_error(TypeError) + end + + it "does not raise TypeError on a frozen array if no modification takes place" do + ArraySpecs.frozen_array.unshift() # ok + end + end +end diff --git a/1.8/core/array/values_at_spec.rb b/1.8/core/array/values_at_spec.rb new file mode 100644 index 0000000000..1ed3a0376a --- /dev/null +++ b/1.8/core/array/values_at_spec.rb @@ -0,0 +1,56 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#values_at" do + it "returns an array of elements at the indexes when passed indexes" do + [1, 2, 3, 4, 5].values_at().should == [] + [1, 2, 3, 4, 5].values_at(1, 0, 5, -1, -8, 10).should == [2, 1, nil, 5, nil, nil] + end + + it "calls to_int on its indices" do + obj = mock('1') + def obj.to_int() 1 end + [1, 2].values_at(obj, obj, obj).should == [2, 2, 2] + + obj = mock('1') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(1) + [1, 2].values_at(obj).should == [2] + end + + it "returns an array of elements in the ranges when passes ranges" do + [1, 2, 3, 4, 5].values_at(0..2, 1...3, 4..6).should == [1, 2, 3, 2, 3, 5, nil] + [1, 2, 3, 4, 5].values_at(6..4).should == [] + end + + it "calls to_int on arguments of ranges when passes ranges" do + from = mock('from') + to = mock('to') + + # So we can construct a range out of them... + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + def from.to_int() 1 end + def to.to_int() -2 end + + ary = [1, 2, 3, 4, 5] + ary.values_at(from .. to, from ... to, to .. from).should == [2, 3, 4, 2, 3] + + from = mock('from') + to = mock('to') + + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + from.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + from.should_receive(:method_missing).with(:to_int).and_return(1) + to.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + to.should_receive(:method_missing).with(:to_int).and_return(-2) + ary.values_at(from .. to).should == [2, 3, 4] + end + + it "does not return subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].values_at(0, 1..2, 1).class.should == Array + end +end diff --git a/1.8/core/array/zip_spec.rb b/1.8/core/array/zip_spec.rb new file mode 100644 index 0000000000..7007996715 --- /dev/null +++ b/1.8/core/array/zip_spec.rb @@ -0,0 +1,51 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Array#zip" do + it "returns an array of arrays containing corresponding elements of each array" do + [1, 2, 3, 4].zip(["a", "b", "c", "d", "e"]).should == + [[1, "a"], [2, "b"], [3, "c"], [4, "d"]] + end + + it "fills in missing values with nil" do + [1, 2, 3, 4, 5].zip(["a", "b", "c", "d"]).should == + [[1, "a"], [2, "b"], [3, "c"], [4, "d"], [5, nil]] + end + + # MRI 1.8.6 uses to_ary, but it's been fixed in 1.9 + compliant_on(:ruby, :jruby) do + it "calls to_ary on its arguments" do + obj = mock('[3,4]') + obj.should_receive(:respond_to?).with(:to_ary).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_ary).and_return([3, 4]) + + [1, 2].zip(obj).should == [[1, 3], [2, 4]] + end + end + + compliant_on(:r19) do + it "calls to_a on its arguments" do + [1, 2, 3].zip("f" .. "z", 1 .. 9).should == + [[1, "f", 1], [2, "g", 2], [3, "h", 3]] + + obj = mock('[3,4]') + obj.should_receive(:respond_to?).with(:to_a).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with([:to_a]).and_return([3, 4]) + + [1, 2].zip(obj).should == [[1, 3], [2, 4]] + end + end + + it "calls block if supplied" do + values = [] + [1, 2, 3, 4].zip(["a", "b", "c", "d", "e"]) { |value| + values << value + }.should == nil + + values.should == [[1, "a"], [2, "b"], [3, "c"], [4, "d"]] + end + + it "does not return subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].zip(["a", "b"]).class.should == Array + end +end diff --git a/1.8/core/bignum/abs_spec.rb b/1.8/core/bignum/abs_spec.rb new file mode 100644 index 0000000000..8573c260be --- /dev/null +++ b/1.8/core/bignum/abs_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#abs" do + it "returns the absolute value" do + bignum_value(39).abs.should == 9223372036854775847 + (-bignum_value(18)).abs.should == 9223372036854775826 + end +end diff --git a/1.8/core/bignum/bit_and_spec.rb b/1.8/core/bignum/bit_and_spec.rb new file mode 100644 index 0000000000..a7b5e9270e --- /dev/null +++ b/1.8/core/bignum/bit_and_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#&" do + before(:each) do + @bignum = bignum_value(5) + end + + it "returns self bitwise AND other" do + @bignum = bignum_value(5) + (@bignum & 3).should == 1 + (@bignum & 52).should == 4 + (@bignum & bignum_value(9921)).should == 9223372036854775809 + + ((2*bignum_value) & 1).should == 0 + ((2*bignum_value) & -1).should == 18446744073709551616 + ((4*bignum_value) & -1).should == 36893488147419103232 + ((2*bignum_value) & (2*bignum_value)).should == 18446744073709551616 + (bignum_value & bignum_value(0xffff).to_f).should == 9223372036854775808 + end + + it "tries to convert it's argument to an Integer using to_int" do + (@bignum & 3.4).should == 1 + + (obj = mock('3')).should_receive(:to_int).and_return(3) + (@bignum & obj).should == 1 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { @bignum & obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { @bignum & obj }.should raise_error(TypeError) + end +end diff --git a/1.8/core/bignum/bit_or_spec.rb b/1.8/core/bignum/bit_or_spec.rb new file mode 100644 index 0000000000..4639d21efd --- /dev/null +++ b/1.8/core/bignum/bit_or_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#|" do + before(:each) do + @bignum = bignum_value(11) + end + + it "returns self bitwise OR other" do + (@bignum | 2).should == 9223372036854775819 + (@bignum | 9).should == 9223372036854775819 + (@bignum | bignum_value).should == 9223372036854775819 + (bignum_value | bignum_value(0xffff).to_f).should == 9223372036854841344 + end + + it "tries to convert the given argument to an Integer using to_int" do + (@bignum | 9.9).should == 9223372036854775819 + + (obj = mock('2')).should_receive(:to_int).and_return(2) + (@bignum | obj).should == 9223372036854775819 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { @bignum | obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { @bignum | obj }.should raise_error(TypeError) + end +end diff --git a/1.8/core/bignum/bit_xor_spec.rb b/1.8/core/bignum/bit_xor_spec.rb new file mode 100644 index 0000000000..786b6d5801 --- /dev/null +++ b/1.8/core/bignum/bit_xor_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#^" do + before(:each) do + @bignum = bignum_value(18) + end + + it "returns self bitwise EXCLUSIVE OR other" do + (@bignum ^ 2).should == 9223372036854775824 + (@bignum ^ @bignum).should == 0 + (@bignum ^ 14).should == 9223372036854775836 + (bignum_value ^ bignum_value(0xffff).to_f).should == 65536 + end + + it "tries to convert the given argument to an Integer using to_int" do + (@bignum ^ 14.5).should == 9223372036854775836 + + (obj = mock('2')).should_receive(:to_int).and_return(2) + (@bignum ^ obj).should == 9223372036854775824 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { @bignum ^ obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { @bignum ^ obj }.should raise_error(TypeError) + end +end diff --git a/1.8/core/bignum/coerce_spec.rb b/1.8/core/bignum/coerce_spec.rb new file mode 100644 index 0000000000..af12bac47e --- /dev/null +++ b/1.8/core/bignum/coerce_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#coerce when given a Fixnum or Bignum" do + it "returns an Array containing the given argument and self" do + a = bignum_value + a.coerce(2).should == [2, a] + + b = bignum_value(701) + a.coerce(b).should == [b, a] + end +end + +describe "Bignum#coerce" do + it "raises a TypeError when given a non Fixnum/Bignum" do + a = bignum_value + + lambda { a.coerce(nil) }.should raise_error(TypeError) + lambda { a.coerce(mock('str')) }.should raise_error(TypeError) + lambda { a.coerce(1..4) }.should raise_error(TypeError) + lambda { a.coerce(:test) }.should raise_error(TypeError) + + compliant_on :ruby do + lambda { a.coerce(12.3) }.should raise_error(TypeError) + lambda { a.coerce("123") }.should raise_error(TypeError) + end + end +end \ No newline at end of file diff --git a/1.8/core/bignum/comparison_spec.rb b/1.8/core/bignum/comparison_spec.rb new file mode 100644 index 0000000000..b355fa189d --- /dev/null +++ b/1.8/core/bignum/comparison_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#<=>" do + before(:each) do + @bignum = bignum_value(96) + end + + it "returns -1 when self is less than the given argument" do + (-@bignum <=> @bignum).should == -1 + (-@bignum <=> -1).should == -1 + (-@bignum <=> -4.5).should == -1 + end + + it "returns 0 when self is equal to the given argument" do + (@bignum <=> @bignum).should == 0 + (-@bignum <=> -@bignum).should == 0 + end + + it "returns 1 when self is greater than the given argument" do + (@bignum <=> -@bignum).should == 1 + (@bignum <=> 1).should == 1 + (@bignum <=> 4.5).should == 1 + end + + it "returns nil when the given argument is not an Integer" do + (@bignum <=> mock('str')).should == nil + (@bignum <=> 'test').should == nil + end +end diff --git a/1.8/core/bignum/complement_spec.rb b/1.8/core/bignum/complement_spec.rb new file mode 100644 index 0000000000..ac43c5d51c --- /dev/null +++ b/1.8/core/bignum/complement_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#~" do + it "returns self with each bit flipped" do + (~bignum_value(48)).should == -9223372036854775857 + (~(-bignum_value(21))).should == 9223372036854775828 + (~bignum_value(1)).should == -9223372036854775810 + end +end diff --git a/1.8/core/bignum/div_spec.rb b/1.8/core/bignum/div_spec.rb new file mode 100644 index 0000000000..ec89e898f9 --- /dev/null +++ b/1.8/core/bignum/div_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/divide' + +describe "Bignum#div" do + it_behaves_like(:bignum_divide, :div) +end diff --git a/1.8/core/bignum/divide_spec.rb b/1.8/core/bignum/divide_spec.rb new file mode 100644 index 0000000000..060bf6ac18 --- /dev/null +++ b/1.8/core/bignum/divide_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/divide' + +describe "Bignum#/" do + it_behaves_like(:bignum_divide, :/) +end diff --git a/1.8/core/bignum/divmod_spec.rb b/1.8/core/bignum/divmod_spec.rb new file mode 100644 index 0000000000..5db827f4fa --- /dev/null +++ b/1.8/core/bignum/divmod_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#divmod" do + before(:each) do + @bignum = bignum_value(55) + end + + # Based on MRI's test/test_integer.rb (test_divmod), + # MRI maintains the following property: + # if q, r = a.divmod(b) ==> + # assert(0 < b ? (0 <= r && r < b) : (b < r && r <= 0)) + # So, r is always between 0 and b. + it "returns an Array containing quotient and modulus obtained from dividing self by the given argument" do + @bignum.divmod(4).should == [2305843009213693965, 3] + @bignum.divmod(13).should == [709490156681136604, 11] + + @bignum.divmod(4.0).should == [2305843009213693952, 0.0] + @bignum.divmod(13.0).should == [709490156681136640, 8.0] + + @bignum.divmod(2.0).should == [4611686018427387904, 0.0] + @bignum.divmod(bignum_value).should == [1, 55] + + (-(10**50)).divmod(-(10**40 + 1)).should == [9999999999, -9999999999999999999999999999990000000001] + (10**50).divmod(10**40 + 1).should == [9999999999, 9999999999999999999999999999990000000001] + + (-10**50).divmod(10**40 + 1).should == [-10000000000, 10000000000] + (10**50).divmod(-(10**40 + 1)).should == [-10000000000, -10000000000] + end + + it "raises a ZeroDivisionError when the given argument is 0" do + lambda { @bignum.divmod(0) }.should raise_error(ZeroDivisionError) + lambda { (-@bignum).divmod(0) }.should raise_error(ZeroDivisionError) + end + + it "raises a FloatDomainError when the given argument is 0 and a Float" do + lambda { @bignum.divmod(0.0) }.should raise_error(FloatDomainError, "NaN") + lambda { (-@bignum).divmod(0.0) }.should raise_error(FloatDomainError, "NaN") + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + @bignum.divmod(obj) + }.should raise_error(TypeError) + lambda { @bignum.divmod("10") }.should raise_error(TypeError) + lambda { @bignum.divmod(:symbol) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/bignum/element_reference_spec.rb b/1.8/core/bignum/element_reference_spec.rb new file mode 100644 index 0000000000..efd10aa6aa --- /dev/null +++ b/1.8/core/bignum/element_reference_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#[]" do + before(:each) do + @bignum = bignum_value(4996) + end + + it "returns the nth bit in the binary representation of self" do + @bignum[2].should == 1 + @bignum[9.2].should == 1 + @bignum[21].should == 0 + @bignum[0xffffffff].should == 0 + @bignum[-0xffffffff].should == 0 + end + + it "tries to convert the given argument to an Integer using #to_int" do + @bignum[1.3].should == @bignum[1] + + (obj = mock('2')).should_receive(:to_int).at_least(1).and_return(2) + @bignum[obj].should == 1 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { @bignum[obj] }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { @bignum[obj] }.should raise_error(TypeError) + end +end diff --git a/1.8/core/bignum/eql_spec.rb b/1.8/core/bignum/eql_spec.rb new file mode 100644 index 0000000000..f2f74c8a2c --- /dev/null +++ b/1.8/core/bignum/eql_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#eql? when given a Bignum" do + it "returns true if the given argument has the same value" do + a = bignum_value(13) + a.eql?(bignum_value(13)).should == true + (-a).eql?(-bignum_value(13)).should == true + end +end + +describe "Bignum#eql? when given a non-Bignum" do + it "returns false if the given argument is not a Bignum" do + a = bignum_value(13) + a.eql?(2).should == false + a.eql?(3.14).should == false + a.eql?(:symbol).should == false + a.eql?("String").should == false + a.eql?(mock('str')).should == false + end +end diff --git a/1.8/core/bignum/equal_value_spec.rb b/1.8/core/bignum/equal_value_spec.rb new file mode 100644 index 0000000000..094e929190 --- /dev/null +++ b/1.8/core/bignum/equal_value_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#==" do + before(:each) do + @bignum = bignum_value + end + + it "returns true if self has the same value as the given argument" do + (@bignum == @bignum).should == true + (@bignum == @bignum + 1).should == false + (@bignum + 1 == @bignum).should == false + + (@bignum == 9).should == false + (@bignum == 9.01).should == false + + (@bignum == bignum_value(10)).should == false + end + + it "calls 'other == self' if the given argument is not an Integer" do + obj = mock('not integer') + obj.should_receive(:==).and_return(false) + @bignum.should_not == obj + end +end diff --git a/1.8/core/bignum/exponent_spec.rb b/1.8/core/bignum/exponent_spec.rb new file mode 100644 index 0000000000..6f977dd15f --- /dev/null +++ b/1.8/core/bignum/exponent_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#**" do + before(:each) do + @bignum = bignum_value(47) + end + + it "returns self raised to other power" do + (@bignum ** 4).should == 7237005577332262361485077344629993318496048279512298547155833600056910050625 + (@bignum ** 5.2).inspect.should == "4.14406519833189e+98" + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + @bignum ** obj + }.should raise_error + lambda { @bignum ** "10" }.should raise_error + lambda { @bignum ** :symbol }.should raise_error + end +end diff --git a/1.8/core/bignum/gt_spec.rb b/1.8/core/bignum/gt_spec.rb new file mode 100644 index 0000000000..c97301bfbe --- /dev/null +++ b/1.8/core/bignum/gt_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#>" do + before(:each) do + @bignum = bignum_value(732) + end + + it "returns true if self is greater than the given argument" do + (@bignum > (@bignum - 1)).should == true + (@bignum > 14.6).should == true + (@bignum > 10).should == true + + (@bignum > (@bignum + 500)).should == false + end + + it "raises an ArgumentError when given a non-Integer" do + lambda { @bignum > "4" }.should raise_error(ArgumentError) + lambda { @bignum > mock('str') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/bignum/gte_spec.rb b/1.8/core/bignum/gte_spec.rb new file mode 100644 index 0000000000..bf1f7f0b2a --- /dev/null +++ b/1.8/core/bignum/gte_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#>=" do + before(:each) do + @bignum = bignum_value(14) + end + + it "returns true if self is greater than or equal to other" do + (@bignum >= @bignum).should == true + (@bignum >= (@bignum + 2)).should == false + (@bignum >= 5664.2).should == true + (@bignum >= 4).should == true + end + + it "raises an ArgumentError when given a non-Integer" do + lambda { @bignum >= "4" }.should raise_error(ArgumentError) + lambda { @bignum >= mock('str') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/bignum/hash_spec.rb b/1.8/core/bignum/hash_spec.rb new file mode 100644 index 0000000000..5a8f249b84 --- /dev/null +++ b/1.8/core/bignum/hash_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#hash" do + it "is provided" do + bignum_value.respond_to?(:hash).should == true + end + + it "is stable" do + (2**100).hash.should == (2**100).hash + end + +end diff --git a/1.8/core/bignum/left_shift_spec.rb b/1.8/core/bignum/left_shift_spec.rb new file mode 100644 index 0000000000..4f7c55bf4b --- /dev/null +++ b/1.8/core/bignum/left_shift_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#<<" do + before(:each) do + @bignum = bignum_value(9) + end + + it "returns self shifted the given amount of bits to the left" do + (@bignum << 4).should == 147573952589676413072 + (@bignum << 9).should == 4722366482869645218304 + end + + it "performs a right-shift if given a negative value" do + (@bignum << -2).should == (@bignum >> 2) + (@bignum << -4).should == (@bignum >> 4) + end + + it "tries to convert its argument to an Integer using to_int" do + (@bignum << 4.5).should == 147573952589676413072 + + (obj = mock('4')).should_receive(:to_int).and_return(4) + (@bignum << obj).should == 147573952589676413072 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { @bignum << obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { @bignum << obj }.should raise_error(TypeError) + end + + it "raises a RangeError when the given argument is out of range of Integer" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + lambda { @bignum << obj }.should raise_error(RangeError) + + obj = 8e19 + lambda { @bignum << obj }.should raise_error(RangeError) + end +end diff --git a/1.8/core/bignum/lt_spec.rb b/1.8/core/bignum/lt_spec.rb new file mode 100644 index 0000000000..92862621d6 --- /dev/null +++ b/1.8/core/bignum/lt_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#<" do + before(:each) do + @bignum = bignum_value(32) + end + + it "returns true if self is less than the given argument" do + (@bignum < @bignum + 1).should == true + (-@bignum < -(@bignum - 1)).should == true + + (@bignum < 1).should == false + (@bignum < 5).should == false + + (@bignum < 4.999).should == false + end + + it "raises an ArgumentError when given a non-Integer" do + lambda { @bignum < "4" }.should raise_error(ArgumentError) + lambda { @bignum < mock('str') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/bignum/lte_spec.rb b/1.8/core/bignum/lte_spec.rb new file mode 100644 index 0000000000..42e3da89bf --- /dev/null +++ b/1.8/core/bignum/lte_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#<=" do + before(:each) do + @bignum = bignum_value(39) + end + + it "returns true if self is less than or equal to other" do + (@bignum <= @bignum).should == true + (-@bignum <= -(@bignum - 1)).should == true + + (@bignum <= (@bignum + 0.5)).should == true + (@bignum <= 4.999).should == false + end + + it "raises an ArgumentError when given a non-Integer" do + lambda { @bignum <= "4" }.should raise_error(ArgumentError) + lambda { @bignum <= mock('str') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/bignum/minus_spec.rb b/1.8/core/bignum/minus_spec.rb new file mode 100644 index 0000000000..f0d6916d50 --- /dev/null +++ b/1.8/core/bignum/minus_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#-" do + before(:each) do + @bignum = bignum_value(314) + end + + it "returns self minus the given Integer" do + (@bignum - 9).should == 9223372036854776113 + (@bignum - 12.57).to_s.should == "9.22337203685478e+18" + (@bignum - bignum_value(42)).should == 272 + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + @bignum - obj + }.should raise_error(TypeError) + lambda { @bignum - "10" }.should raise_error(TypeError) + lambda { @bignum - :symbol }.should raise_error(TypeError) + end +end diff --git a/1.8/core/bignum/modulo_spec.rb b/1.8/core/bignum/modulo_spec.rb new file mode 100644 index 0000000000..e2a8a089b5 --- /dev/null +++ b/1.8/core/bignum/modulo_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/modulo' + +describe "Bignum#%" do + it_behaves_like(:bignum_modulo, :%) +end + +describe "Bignum#modulo" do + it_behaves_like(:bignum_modulo, :modulo) +end diff --git a/1.8/core/bignum/multiply_spec.rb b/1.8/core/bignum/multiply_spec.rb new file mode 100644 index 0000000000..f8394e4f25 --- /dev/null +++ b/1.8/core/bignum/multiply_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#*" do + before(:each) do + @bignum = bignum_value(772) + end + + it "returns self multiplied by the given Integer" do + (@bignum * (1/bignum_value(0xffff).to_f)).should be_close(0.999999999999992894572642398998, 3e-29) + (@bignum * 10).should == 92233720368547765800 + (@bignum * (@bignum - 40)).should == 85070591730234629737795195287525433200 + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + @bignum * obj + }.should raise_error(TypeError) + lambda { @bignum * "10" }.should raise_error(TypeError) + lambda { @bignum * :symbol }.should raise_error(TypeError) + end +end diff --git a/1.8/core/bignum/plus_spec.rb b/1.8/core/bignum/plus_spec.rb new file mode 100644 index 0000000000..8989d1ca9b --- /dev/null +++ b/1.8/core/bignum/plus_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#+" do + before(:each) do + @bignum = bignum_value(76) + end + + it "returns self plus the given Integer" do + (@bignum + 4).should == 9223372036854775888 + (@bignum + 4.2).to_s.should == "9.22337203685478e+18" + (@bignum + bignum_value(3)).should == 18446744073709551695 + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + @bignum + obj + }.should raise_error(TypeError) + lambda { @bignum + "10" }.should raise_error(TypeError) + lambda { @bignum + :symbol}.should raise_error(TypeError) + end +end diff --git a/1.8/core/bignum/quo_spec.rb b/1.8/core/bignum/quo_spec.rb new file mode 100644 index 0000000000..44d9f22747 --- /dev/null +++ b/1.8/core/bignum/quo_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#quo" do + before(:each) do + @bignum = bignum_value(3) + end + + it "returns the result of self divided by the given Integer as a Float" do + @bignum.quo(0xffff_afed.to_f).should be_close(2147493897.54892, TOLERANCE) + @bignum.quo(0xabcd_effe).should be_close(3199892875.41007, TOLERANCE) + @bignum.quo(bignum_value).should be_close(1.00000000279397, TOLERANCE) + end + + conflicts_with :Rational do + it "does not raise a ZeroDivisionError when the given Integer is 0" do + @bignum.quo(0).to_s.should == "Infinity" + (-@bignum).quo(0).to_s.should == "-Infinity" + end + end + + it "does not raise a FloatDomainError when the given Integer is 0 and a Float" do + @bignum.quo(0.0).to_s.should == "Infinity" + (-@bignum).quo(0.0).to_s.should == "-Infinity" + end + + conflicts_with :Rational do + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('to_int')).should_not_receive(:to_int) + @bignum.quo(obj) + }.should raise_error(TypeError) + lambda { @bignum.quo("10") }.should raise_error(TypeError) + lambda { @bignum.quo(:symbol) }.should raise_error(TypeError) + end + end +end \ No newline at end of file diff --git a/1.8/core/bignum/remainder_spec.rb b/1.8/core/bignum/remainder_spec.rb new file mode 100644 index 0000000000..472c35ccc1 --- /dev/null +++ b/1.8/core/bignum/remainder_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#remainder" do + it "returns the remainder of dividing self by other" do + a = bignum_value(79) + a.remainder(2).should == 1 + a.remainder(97.345).should be_close(46.5674996147722, TOLERANCE) + a.remainder(bignum_value).should == 79 + end + + it "raises a ZeroDivisionError if other is zero and not a Float" do + lambda { bignum_value(66).remainder(0) }.should raise_error(ZeroDivisionError) + end + + it "does NOT raise ZeroDivisionError if other is zero and is a Float" do + a = bignum_value(7) + b = bignum_value(32) + a.remainder(0.0).to_s.should == 'NaN' + b.remainder(-0.0).to_s.should == 'NaN' + end +end diff --git a/1.8/core/bignum/right_shift_spec.rb b/1.8/core/bignum/right_shift_spec.rb new file mode 100644 index 0000000000..23cab4832c --- /dev/null +++ b/1.8/core/bignum/right_shift_spec.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#>>" do + before(:each) do + @bignum = bignum_value(90812) + end + + it "returns self shifted the given amount of bits to the right" do + (@bignum >> 1).should == 4611686018427433310 + (@bignum >> 3).should == 1152921504606858327 + end + + it "performs a left-shift if given a negative value" do + (@bignum >> -1).should == (@bignum << 1) + (@bignum >> -3).should == (@bignum << 3) + end + + it "tries to convert it's argument to an Integer using to_int" do + (@bignum >> 1.3).should == 4611686018427433310 + + (obj = mock('1')).should_receive(:to_int).and_return(1) + (@bignum >> obj).should == 4611686018427433310 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { @bignum >> obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { @bignum >> obj }.should raise_error(TypeError) + end + + it "does not raise RangeError when the given argument is out of range of Integer" do + (obj1 = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + (obj2 = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + (@bignum >> obj1).should == 0 + (-@bignum >> obj2).should == -1 + + obj = 8e19 + (@bignum >> obj).should == 0 + (-@bignum >> obj).should == -1 + end + + it "return the right shift alignment" do + ((1 - 2**31) >> 31).should == -1 + ((1 - 2**32) >> 32).should == -1 + ((1 - 2**63) >> 63).should == -1 + ((1 - 2**64) >> 64).should == -1 + end +end diff --git a/1.8/core/bignum/shared/divide.rb b/1.8/core/bignum/shared/divide.rb new file mode 100644 index 0000000000..3ac017ad45 --- /dev/null +++ b/1.8/core/bignum/shared/divide.rb @@ -0,0 +1,37 @@ +shared :bignum_divide do |cmd| + describe "Bignum##{cmd}" do + before(:each) do + @bignum = bignum_value(88) + end + + it "returns self divided by other" do + @bignum.send(cmd, 4).should == 2305843009213693974 + + @bignum.send(cmd, 0xffff_ffff.to_f).should be_close(2147483648.5, TOLERANCE) + @bignum.send(cmd, bignum_value(2)).should be_close(1, TOLERANCE) + + (-(10**50)).send(cmd, -(10**40 + 1)).should == 9999999999 + (10**50).send(cmd, 10**40 + 1).should == 9999999999 + + (-10**50).send(cmd, 10**40 + 1).should == -10000000000 + (10**50).send(cmd, -(10**40 + 1)).should == -10000000000 + end + + it "raises a ZeroDivisionError if other is zero and not a Float" do + lambda { @bignum.send(cmd, 0) }.should raise_error(ZeroDivisionError) + end + + it "does NOT raise ZeroDivisionError if other is zero and is a Float" do + @bignum.send(cmd, 0.0).to_s.should == 'Infinity' + @bignum.send(cmd, -0.0).to_s.should == '-Infinity' + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + @bignum.div(obj) + }.should raise_error(TypeError) + lambda { @bignum.div("2") }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/bignum/shared/modulo.rb b/1.8/core/bignum/shared/modulo.rb new file mode 100644 index 0000000000..e4204e2bc5 --- /dev/null +++ b/1.8/core/bignum/shared/modulo.rb @@ -0,0 +1,34 @@ +shared :bignum_modulo do |cmd| + describe "Bignum##{cmd}" do + before(:each) do + @bignum = bignum_value + end + + it "returns the modulus obtained from dividing self by the given argument" do + @bignum.send(cmd, 5).should == 3 + @bignum.send(cmd, -5).should == -2 + @bignum.send(cmd, -100).should == -92 + @bignum.send(cmd, 2.22).should be_close(0.780180180180252, TOLERANCE) + @bignum.send(cmd, bignum_value(10)).should == 9223372036854775808 + end + + it "raises a ZeroDivisionError when the given argument is 0" do + lambda { @bignum.send(cmd, 0) }.should raise_error(ZeroDivisionError) + lambda { (-@bignum).send(cmd, 0) }.should raise_error(ZeroDivisionError) + end + + it "does not raise a FloatDomainError when the given argument is 0 and a Float" do + @bignum.send(cmd, 0.0).to_s.should == "NaN" + (-@bignum).send(cmd, 0.0).to_s.should == "NaN" + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + @bignum.send(cmd, obj) + }.should raise_error(TypeError) + lambda { @bignum.send(cmd, "10") }.should raise_error(TypeError) + lambda { @bignum.send(cmd, :symbol) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/bignum/size_spec.rb b/1.8/core/bignum/size_spec.rb new file mode 100644 index 0000000000..573dea5fb3 --- /dev/null +++ b/1.8/core/bignum/size_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#size" do + it "returns the number of bytes in the machine representation of self" do + compliant_on(:ruby) do + (256**7).size.should == 8 + (256**8).size.should == 12 + (256**9).size.should == 12 + (256**10).size.should == 12 + (256**10-1).size.should == 12 + (256**11).size.should == 12 + (256**12).size.should == 16 + (256**20-1).size.should == 20 + (256**40-1).size.should == 40 + end + + compliant_on(:rubinius) do + (256**7).size.should == 8 + (256**8).size.should == 9 + (256**9).size.should == 10 + (256**10).size.should == 11 + (256**10-1).size.should == 10 + (256**11).size.should == 12 + (256**12).size.should == 13 + (256**20-1).size.should == 20 + (256**40-1).size.should == 40 + end + end +end diff --git a/1.8/core/bignum/to_f_spec.rb b/1.8/core/bignum/to_f_spec.rb new file mode 100644 index 0000000000..b1e4854d3a --- /dev/null +++ b/1.8/core/bignum/to_f_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#to_f" do + it "returns self converted to a Float" do + bignum_value(0x4000_0aa0_0bb0_0000).to_f.should == 13_835_069_737_789_292_544.00 + bignum_value(0x8000_0000_0000_0ccc).to_f.should == 18_446_744_073_709_555_712.00 + (-bignum_value(99)).to_f.should == -9_223_372_036_854_775_808.00 + end +end diff --git a/1.8/core/bignum/to_s_spec.rb b/1.8/core/bignum/to_s_spec.rb new file mode 100644 index 0000000000..a44796af96 --- /dev/null +++ b/1.8/core/bignum/to_s_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#to_s when given a base" do + it "returns self converted to a String in the given base" do + a = 2**64 + a.to_s(2).should == "10000000000000000000000000000000000000000000000000000000000000000" + a.to_s(8).should == "2000000000000000000000" + a.to_s(16).should == "10000000000000000" + a.to_s(32).should == "g000000000000" + end + + it "raises an ArgumentError if the base is less than 2 or higher than 36" do + lambda { 123.to_s(-1) }.should raise_error(ArgumentError) + lambda { 123.to_s(0) }.should raise_error(ArgumentError) + lambda { 123.to_s(1) }.should raise_error(ArgumentError) + lambda { 123.to_s(37) }.should raise_error(ArgumentError) + end +end + +describe "Bignum#to_s when no base given" do + it "returns self converted to a String using base 10" do + bignum_value(9).to_s.should == "9223372036854775817" + bignum_value.to_s.should == "9223372036854775808" + (-bignum_value(675)).to_s.should == "-9223372036854776483" + end +end diff --git a/1.8/core/bignum/uminus_spec.rb b/1.8/core/bignum/uminus_spec.rb new file mode 100644 index 0000000000..e57f0a627c --- /dev/null +++ b/1.8/core/bignum/uminus_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Bignum#-@" do + it "returns self as a negative value" do + bignum_value.send(:-@).should == -9223372036854775808 + (-bignum_value).send(:-@).should == 9223372036854775808 + + bignum_value(921).send(:-@).should == -9223372036854776729 + (-bignum_value(921).send(:-@)).should == 9223372036854776729 + end +end diff --git a/1.8/core/binding/clone_spec.rb b/1.8/core/binding/clone_spec.rb new file mode 100644 index 0000000000..eb4a2deacb --- /dev/null +++ b/1.8/core/binding/clone_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/clone' + +describe "Binding#clone" do + it_behaves_like(:binding_clone, :clone) +end diff --git a/1.8/core/binding/dup_spec.rb b/1.8/core/binding/dup_spec.rb new file mode 100644 index 0000000000..e0322ea0b0 --- /dev/null +++ b/1.8/core/binding/dup_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/clone' + +describe "Binding#dup" do + it_behaves_like(:binding_clone, :dup) +end diff --git a/1.8/core/binding/fixtures/classes.rb b/1.8/core/binding/fixtures/classes.rb new file mode 100644 index 0000000000..5d26d39016 --- /dev/null +++ b/1.8/core/binding/fixtures/classes.rb @@ -0,0 +1,16 @@ +module BindingSpecs + class Demo + def initialize(n) + @secret = n + end + + def square(n) + n * n + end + + def get_binding + a = true + binding + end + end +end diff --git a/1.8/core/binding/shared/clone.rb b/1.8/core/binding/shared/clone.rb new file mode 100644 index 0000000000..660d447b3f --- /dev/null +++ b/1.8/core/binding/shared/clone.rb @@ -0,0 +1,22 @@ +shared :binding_clone do |cmd| + describe "Binding##{cmd}" do + before(:each) do + @b1 = BindingSpecs::Demo.new(99).get_binding + @b2 = @b1.send(cmd) + end + + it "returns a copy of the Bind object" do + @b1.should_not == @b2 + + eval("@secret", @b1).should == eval("@secret", @b2) + eval("square(2)", @b1).should == eval("square(2)", @b2) + eval("self.square(2)", @b1).should == eval("self.square(2)", @b2) + eval("a", @b1).should == eval("a", @b2) + end + + it "is a shallow copy of the Bind object" do + eval("a = false", @b1) + eval("a", @b2).should == false + end + end +end diff --git a/1.8/core/class/allocate_spec.rb b/1.8/core/class/allocate_spec.rb new file mode 100644 index 0000000000..60e54a24bd --- /dev/null +++ b/1.8/core/class/allocate_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Class#allocate" do + it "returns an instance of self" do + klass = Class.new + klass.allocate.should be_kind_of(klass) + end + + it "returns a fully-formed instance of Module" do + klass = Class.allocate + klass.constants.should_not == nil + klass.methods.should_not == nil + end + + it "does not call initialize on the new instance" do + klass = Class.new do + def initialize(*args) + @initialized = true + end + + def initialized? + @initialized || false + end + end + + klass.allocate.initialized?.should == false + end +end \ No newline at end of file diff --git a/1.8/core/class/fixtures/classes.rb b/1.8/core/class/fixtures/classes.rb new file mode 100644 index 0000000000..cb9dbd27de --- /dev/null +++ b/1.8/core/class/fixtures/classes.rb @@ -0,0 +1,48 @@ +module ClassSpecs + class Record + def self.called(sym) + @called = sym + end + + def self.called? + @called + end + end + + module M + def inherited(klass) + ::ClassSpecs::Record.called(klass) + super + end + end + + class F; end + class << F + include M + end + + class A + def self.inherited(klass) + ::ClassSpecs::Record.called(klass) + end + end + + class H < A + def self.inherited(klass) + super + end + end + + module Inherited + class A + SUBCLASSES = [] + def self.inherited(subclass) + SUBCLASSES << [self, subclass] + end + end + + class B < A; end + class B < A; end # reopen + class C < B; end + end +end diff --git a/1.8/core/class/inherited_spec.rb b/1.8/core/class/inherited_spec.rb new file mode 100644 index 0000000000..abc0995015 --- /dev/null +++ b/1.8/core/class/inherited_spec.rb @@ -0,0 +1,88 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Class.inherited" do + + before :each do + ClassSpecs::Record.called nil + end + + it "is invoked with the child Class when self is subclassed" do + begin + top = Class.new do + def self.inherited(cls) + $child_class = cls + end + end + + child = Class.new(top) + $child_class.should == child + + other_child = Class.new(top) + $child_class.should == other_child + ensure + $child_class = nil + end + end + + it "is invoked only once per subclass" do + expected = [ + [ClassSpecs::Inherited::A, ClassSpecs::Inherited::B], + [ClassSpecs::Inherited::B, ClassSpecs::Inherited::C], + ] + + ClassSpecs::Inherited::A::SUBCLASSES.should == expected + end + + it "is called when marked as a private class method" do + ClassSpecs::A.private_class_method :inherited + ClassSpecs::Record.called?.should == nil + module ClassSpecs; class B < A; end; end + ClassSpecs::Record.called?.should == ClassSpecs::B + end + + it "is called when marked as a protected class method" do + class << ClassSpecs::A + protected :inherited + end + ClassSpecs::Record.called?.should == nil + module ClassSpecs; class C < A; end; end + ClassSpecs::Record.called?.should == ClassSpecs::C + end + + it "is called when marked as a public class method" do + ClassSpecs::A.public_class_method :inherited + ClassSpecs::Record.called?.should == nil + module ClassSpecs; class D < A; end; end + ClassSpecs::Record.called?.should == ClassSpecs::D + end + + it "is called by super from a method provided by an included module" do + ClassSpecs::Record.called?.should == nil + module ClassSpecs; class E < F; end; end + ClassSpecs::Record.called?.should == ClassSpecs::E + end + + it "is called by super even when marked as a private class method" do + ClassSpecs::Record.called?.should == nil + ClassSpecs::H.private_class_method :inherited + module ClassSpecs; class I < H; end; end + ClassSpecs::Record.called?.should == ClassSpecs::I + end + + it "will be invoked by child class regardless of visibility" do + top = Class.new do + class << self + def inherited(cls); end + end + end + + class << top; private :inherited; end + lambda { Class.new(top) }.should_not raise_error + + class << top; protected :inherited; end + lambda { Class.new(top) }.should_not raise_error + end + +end + diff --git a/1.8/core/class/initialize_copy_spec.rb b/1.8/core/class/initialize_copy_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/class/initialize_copy_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/class/initialize_spec.rb b/1.8/core/class/initialize_spec.rb new file mode 100644 index 0000000000..c20c637c6c --- /dev/null +++ b/1.8/core/class/initialize_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Class#new" do + it "returns a new instance of self" do + klass = Class.new + klass.new.is_a?(klass).should == true + end + + it "invokes #initialize on the new instance with the given args" do + klass = Class.new do + def initialize(*args) + @initialized = true + @args = args + end + + def args + @args + end + + def initialized? + @initialized || false + end + end + + klass.new.initialized?.should == true + klass.new(1, 2, 3).args.should == [1, 2, 3] + end +end \ No newline at end of file diff --git a/1.8/core/class/new_spec.rb b/1.8/core/class/new_spec.rb new file mode 100644 index 0000000000..c139014fea --- /dev/null +++ b/1.8/core/class/new_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Class.new with a block given" do + it "uses the given block as the class' body" do + klass = Class.new do + def self.hello + "hello" + end + + def hello + "hello again" + end + end + + klass.hello.should == "hello" + klass.new.hello.should == "hello again" + end +end + +describe "Class.new" do + it "creates a new anonymous class" do + klass = Class.new + klass.is_a?(Class).should == true + + klass_instance = klass.new + klass_instance.is_a?(klass).should == true + end + + it "creates a class without a name" do + Class.new.name.should == "" + end + + it "creates a class that can be given a name by assigning it to a constant" do + MyClass = Class.new + MyClass.name.should == "MyClass" + a = Class.new + MyClass::NestedClass = a + MyClass::NestedClass.name.should == "MyClass::NestedClass" + end + + it "sets the new class' superclass to the given class" do + top = Class.new + Class.new(top).superclass.should == top + end + + it "sets the new class' superclass to Object when no class given" do + Class.new.superclass.should == Object + end + + it "raises a TypeError when given a non-Class" do + lambda { Class.new("") }.should raise_error(TypeError) + lambda { Class.new(1) }.should raise_error(TypeError) + lambda { Class.new(:symbol) }.should raise_error(TypeError) + lambda { Class.new(mock('o')) }.should raise_error(TypeError) + lambda { Class.new(Module.new) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/class/superclass_spec.rb b/1.8/core/class/superclass_spec.rb new file mode 100644 index 0000000000..9e8f31def0 --- /dev/null +++ b/1.8/core/class/superclass_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Class#superclass" do + it "returns the superclass of self" do + Object.superclass.should == nil + Class.superclass.should == Module + Class.new.superclass.should == Object + Class.new(String).superclass.should == String + Class.new(Fixnum).superclass.should == Fixnum + end +end \ No newline at end of file diff --git a/1.8/core/comparable/between_spec.rb b/1.8/core/comparable/between_spec.rb new file mode 100644 index 0000000000..efd856d15e --- /dev/null +++ b/1.8/core/comparable/between_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Comparable#between?" do + it "returns true if self is greater than or equal to the first and less than or equal to the second argument" do + a = ComparableSpecs::Weird.new(-1) + b = ComparableSpecs::Weird.new(0) + c = ComparableSpecs::Weird.new(1) + d = ComparableSpecs::Weird.new(2) + + a.between?(a, a).should == true + a.between?(a, b).should == true + a.between?(a, c).should == true + a.between?(a, d).should == true + c.between?(c, d).should == true + d.between?(d, d).should == true + c.between?(a, d).should == true + + a.between?(b, b).should == false + a.between?(b, c).should == false + a.between?(b, d).should == false + c.between?(a, a).should == false + c.between?(a, b).should == false + end +end diff --git a/1.8/core/comparable/equal_value_spec.rb b/1.8/core/comparable/equal_value_spec.rb new file mode 100644 index 0000000000..216a30f234 --- /dev/null +++ b/1.8/core/comparable/equal_value_spec.rb @@ -0,0 +1,60 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Comparable#==" do + it "returns true if other is the same as self" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + (a == a).should == true + (b == b).should == true + end + + it "calls #<=> on self with other and returns true if #<=> returns 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(10) + + a.should_receive(:<=>).any_number_of_times.and_return(0) + (a == b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(0.0) + (a == b).should == true + end + + it "returns false if calling #<=> on self returns a non-zero Integer" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(10) + + a.should_receive(:<=>).any_number_of_times.and_return(1) + (a == b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(-1) + (a == b).should == false + end + + it "returns nil if calling #<=> on self returns nil or a non-Integer" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(10) + + a.should_receive(:<=>).any_number_of_times.and_return(nil) + (a == b).should == nil + + a.should_receive(:<=>).any_number_of_times.and_return("abc") + (a == b).should == nil + end + + it "returns nil if calling #<=> on self raises a StandardError" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(10) + + def a.<=>(b) raise StandardError, "test"; end + (a == b).should == nil + + # TypeError < StandardError + def a.<=>(b) raise TypeError, "test"; end + (a == b).should == nil + + def a.<=>(b) raise Exception, "test"; end + lambda { (a == b).should == nil }.should raise_error(Exception) + end +end diff --git a/1.8/core/comparable/fixtures/classes.rb b/1.8/core/comparable/fixtures/classes.rb new file mode 100644 index 0000000000..2ea1c6d565 --- /dev/null +++ b/1.8/core/comparable/fixtures/classes.rb @@ -0,0 +1,15 @@ +module ComparableSpecs + class Weird + include Comparable + + attr_reader :value + + def initialize(value) + @value = value + end + + def <=>(other) + self.value <=> other.value + end + end +end diff --git a/1.8/core/comparable/gt_spec.rb b/1.8/core/comparable/gt_spec.rb new file mode 100644 index 0000000000..83aba2e218 --- /dev/null +++ b/1.8/core/comparable/gt_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Comparable#>" do + it "calls #<=> on self with other and returns true if #<=> returns any Integer greater than 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + a.should_receive(:<=>).any_number_of_times.and_return(1) + (a > b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(0.1) + (a > b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(10000000) + (a > b).should == true + end + + it "returns false if calling #<=> on self returns 0 or any Integer less than 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(10) + + a.should_receive(:<=>).any_number_of_times.and_return(0) + (a > b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(0.0) + (a > b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(-1.0) + (a > b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(-10000000) + (a > b).should == false + end + + it "raises an ArgumentError if calling #<=> on self returns nil" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + a.should_receive(:<=>).any_number_of_times.and_return(nil) + lambda { (a > b) }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/comparable/gte_spec.rb b/1.8/core/comparable/gte_spec.rb new file mode 100644 index 0000000000..4def876fbb --- /dev/null +++ b/1.8/core/comparable/gte_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Comparable#>=" do + it "calls #<=> on self with other and returns true if #<=> returns 0 or any Integer greater than 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + a.should_receive(:<=>).any_number_of_times.and_return(0) + (a >= b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(0.0) + (a >= b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(1) + (a >= b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(0.1) + (a >= b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(10000000) + (a >= b).should == true + end + + it "returns false if calling #<=> on self returns any Integer less than 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(10) + + + a.should_receive(:<=>).any_number_of_times.and_return(-0.1) + (a >= b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(-1.0) + (a >= b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(-10000000) + (a >= b).should == false + end + + it "raises an ArgumentError if calling #<=> on self returns nil" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + a.should_receive(:<=>).any_number_of_times.and_return(nil) + lambda { (a >= b) }.should raise_error(ArgumentError) + end +end \ No newline at end of file diff --git a/1.8/core/comparable/lt_spec.rb b/1.8/core/comparable/lt_spec.rb new file mode 100644 index 0000000000..4bc713a7ef --- /dev/null +++ b/1.8/core/comparable/lt_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Comparable#<" do + it "calls #<=> on self with other and returns true if #<=> returns any Integer less than 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + a.should_receive(:<=>).any_number_of_times.and_return(-1) + (a < b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(-0.1) + (a < b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(-10000000) + (a < b).should == true + end + + it "returns false if calling #<=> on self returns 0 or any Integer greater than 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(10) + + a.should_receive(:<=>).any_number_of_times.and_return(0) + (a < b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(0.0) + (a < b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(1.0) + (a < b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(10000000) + (a < b).should == false + end + + it "raises an ArgumentError if calling #<=> on self returns nil" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + a.should_receive(:<=>).any_number_of_times.and_return(nil) + lambda { (a < b) }.should raise_error(ArgumentError) + end +end \ No newline at end of file diff --git a/1.8/core/comparable/lte_spec.rb b/1.8/core/comparable/lte_spec.rb new file mode 100644 index 0000000000..2a9a5beea9 --- /dev/null +++ b/1.8/core/comparable/lte_spec.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Comparable#<=" do + it "calls #<=> on self with other and returns true if #<=> returns 0 or any Integer less than 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + a.should_receive(:<=>).any_number_of_times.and_return(0) + (a <= b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(0.0) + (a <= b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(-1) + (a <= b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(-0.1) + (a <= b).should == true + + a.should_receive(:<=>).any_number_of_times.and_return(-10000000) + (a <= b).should == true + end + + it "returns false if calling #<=> on self returns any Integer greater than 0" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(10) + + a.should_receive(:<=>).any_number_of_times.and_return(0.1) + (a <= b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(1.0) + (a <= b).should == false + + a.should_receive(:<=>).any_number_of_times.and_return(10000000) + (a <= b).should == false + end + + it "raises an ArgumentError if calling #<=> on self returns nil" do + a = ComparableSpecs::Weird.new(0) + b = ComparableSpecs::Weird.new(20) + + a.should_receive(:<=>).any_number_of_times.and_return(nil) + lambda { (a <= b) }.should raise_error(ArgumentError) + end +end \ No newline at end of file diff --git a/1.8/core/continuation/call_spec.rb b/1.8/core/continuation/call_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/continuation/call_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/continuation/continuation_spec.rb b/1.8/core/continuation/continuation_spec.rb new file mode 100644 index 0000000000..443d4cd091 --- /dev/null +++ b/1.8/core/continuation/continuation_spec.rb @@ -0,0 +1,55 @@ +# This file specifies behaviour for the methods of +# Continuation. The mechanics thereof may be further +# examined in spec/language. +# +require File.dirname(__FILE__) + '/../../spec_helper' + +# Class methods +# - +# +# Instance methods +# #call OK +# #[] OK + + +describe "Creating a Continuation object" do + not_supported_on :jruby do + it "must be done through Kernel.callcc, no .new" do + lambda { Continuation.new }.should raise_error(NoMethodError) + + Kernel.callcc {|@cc|} + c = @cc + c.class.should == Continuation + end + end +end + + +describe "Executing a Continuation" do + not_supported_on :jruby do + it "using #call transfers execution to right after the Kernel.callcc block" do + array = [:reached, :not_reached] + + Kernel.callcc {|@cc|} + + unless array.first == :not_reached + array.shift + @cc.call + end + + array.should == [:not_reached] + end + + it "arguments given to #call (or nil) are returned by the Kernel.callcc block (as Array unless only one object)" do + Kernel.callcc {|cc| cc.call}.should == nil + Kernel.callcc {|cc| cc.call 1}.should == 1 + Kernel.callcc {|cc| cc.call 1, 2, 3}.should == [1, 2, 3] + end + + it "#[] is an alias for #call" do + Kernel.callcc {|cc| cc.call}.should == Kernel.callcc {|cc| cc[]} + Kernel.callcc {|cc| cc.call 1}.should == Kernel.callcc {|cc| cc[1]} + Kernel.callcc {|cc| cc.call 1, 2, 3}.should == Kernel.callcc {|cc| cc[1, 2, 3]} + end + end +end diff --git a/1.8/core/continuation/element_reference_spec.rb b/1.8/core/continuation/element_reference_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/continuation/element_reference_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/dir/chdir_spec.rb b/1.8/core/dir/chdir_spec.rb new file mode 100644 index 0000000000..73010a34ce --- /dev/null +++ b/1.8/core/dir/chdir_spec.rb @@ -0,0 +1,75 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "Dir.chdir" do + before(:each) do + @original = Dir.pwd + end + + after(:each) do + Dir.chdir(@original) + end + + it "defaults to $HOME with no arguments" do + Dir.chdir(ENV['HOME']) + home = Dir.pwd + + Dir.chdir + Dir.pwd.should == home + end + + it "changes to the specified directory" do + Dir.chdir DirSpecs.mock_dir + Dir.pwd.should == DirSpecs.mock_dir + end + + it "returns 0 when successfully changing directory" do + Dir.chdir(@original).should == 0 + end + + it "returns the value of the block when a block is given" do + Dir.chdir(@original) { :block_value }.should == :block_value + end + + it "changes to the specified directory for the duration of the block" do + ar = Dir.chdir(DirSpecs.mock_dir) { |dir| [dir, Dir.pwd] } + ar.should == [DirSpecs.mock_dir, DirSpecs.mock_dir] + + Dir.pwd.should == @original + end + + it "raises a SystemCallError if the directory does not exist" do + lambda { Dir.chdir DirSpecs.nonexistent }.should raise_error(SystemCallError) + lambda { Dir.chdir(DirSpecs.nonexistent) { } }.should raise_error(SystemCallError) + end + + it "raises a SystemCallError if the original directory no longer exists" do + dir1 = File.dirname(__FILE__) + '/testdir1' + dir2 = File.dirname(__FILE__) + '/testdir2' + File.exist?(dir1).should == false + File.exist?(dir2).should == false + Dir.mkdir dir1 + Dir.mkdir dir2 + begin + lambda { + Dir.chdir dir1 do + Dir.chdir(dir2) { Dir.unlink dir1 } + end + }.should raise_error(SystemCallError) + ensure + Dir.unlink dir1 if File.exist?(dir1) + Dir.unlink dir2 if File.exist?(dir2) + end + end + + it "always returns to the original directory when given a block" do + begin + Dir.chdir(DirSpecs.mock_dir) do + raise StandardError, "something bad happened" + end + rescue StandardError + end + + Dir.pwd.should == @original + end +end diff --git a/1.8/core/dir/chroot_spec.rb b/1.8/core/dir/chroot_spec.rb new file mode 100644 index 0000000000..ece565e629 --- /dev/null +++ b/1.8/core/dir/chroot_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +# Need special perms to run chroot +# describe "Dir.chroot" do +# it 'Dir.chroot can be used to change the process\' root directory, see chroot(2)' do +# example do +# Kernel.fork { +# begin +# ret = Dir.chroot mock_dir +# File.open('/root_contents.txt', 'wb') {|f| f.puts ret; f.puts Dir.entries('/').sort} +# FileUtils.chmod 0777, '/root_contents.txt' +# rescue SystemCallError +# warn '**WARN: Insufficient permissions to test Dir.chroot! (Not a huge problem.)' +# end +# } +# +# Process.waitall +# +# contents = File.read "#{mock_dir}/root_contents.txt" +# FileUtils.rm "#{mock_dir}/root_contents.txt" +# +# # Should have the return value + the filenames +# contents.split("\n").sort +# end.should == %w|0 . .. .dotfile .dotsubdir subdir_one subdir_two deeply nondotfile file_one.ext file_two.ext root_contents.txt|.sort +# end +# end diff --git a/1.8/core/dir/close_spec.rb b/1.8/core/dir/close_spec.rb new file mode 100644 index 0000000000..2ae61066aa --- /dev/null +++ b/1.8/core/dir/close_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/closed' + +describe "Dir#close" do + it "closes the stream and fd and returns nil" do + # This is a bit convoluted but we are trying to ensure the file gets closed. + # To do that, we peek to see what the next FD number is and then probe that + # to see whether it has been closed. + peek = IO.sysopen DirSpecs.mock_dir + File.for_fd(peek).close + + dir = Dir.open DirSpecs.mock_dir + File.for_fd(peek).close # Should be open here + + dir.close.should == nil + lambda { File.for_fd(peek).close }.should raise_error(SystemCallError) # And closed here + end +end + +describe "Dir#close" do + it_behaves_like :dir_closed, :close +end diff --git a/1.8/core/dir/delete_spec.rb b/1.8/core/dir/delete_spec.rb new file mode 100644 index 0000000000..7bd77af577 --- /dev/null +++ b/1.8/core/dir/delete_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/delete' + +describe "Dir.delete" do + it_behaves_like :dir_delete, :delete +end diff --git a/1.8/core/dir/dir_spec.rb b/1.8/core/dir/dir_spec.rb new file mode 100644 index 0000000000..33f598e3b8 --- /dev/null +++ b/1.8/core/dir/dir_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Dir" do + it "includes Enumerable" do + Dir.include?(Enumerable).should == true + end +end diff --git a/1.8/core/dir/each_spec.rb b/1.8/core/dir/each_spec.rb new file mode 100644 index 0000000000..022657f6bc --- /dev/null +++ b/1.8/core/dir/each_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/closed' + +describe "Dir#each" do + before(:each) do + @dir = Dir.open DirSpecs.mock_dir + end + + after(:each) do + @dir.close + end + + it "yields each directory entry in succession" do + a = [] + @dir.each {|dir| a << dir} + + a.sort.should == DirSpecs.expected_paths + end + + it "returns the directory which remains open" do + # an FS does not necessarily impose order + ls = `ls -a #{DirSpecs.mock_dir}`.split + @dir.each {}.should == @dir + @dir.read.should == nil + @dir.rewind + ls.should include(@dir.read) + end +end + +describe "Dir#each" do + it_behaves_like :dir_closed, :each +end diff --git a/1.8/core/dir/element_reference_spec.rb b/1.8/core/dir/element_reference_spec.rb new file mode 100644 index 0000000000..8e3c575f20 --- /dev/null +++ b/1.8/core/dir/element_reference_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/glob' + +describe "Dir.[]" do + it_behaves_like :dir_glob, :[] +end diff --git a/1.8/core/dir/entries_spec.rb b/1.8/core/dir/entries_spec.rb new file mode 100644 index 0000000000..5ffd16a320 --- /dev/null +++ b/1.8/core/dir/entries_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "Dir.entries" do + it "returns an Array of filenames in an existing directory including dotfiles" do + a = Dir.entries(DirSpecs.mock_dir).sort + + a.should == DirSpecs.expected_paths + + a = Dir.entries("#{DirSpecs.mock_dir}/deeply/nested").sort + a.should == %w|. .. .dotfile.ext directory| + end + + it "raises a SystemCallError if called with a nonexistent diretory" do + lambda { Dir.entries DirSpecs.nonexistent }.should raise_error(SystemCallError) + end +end diff --git a/1.8/core/dir/fixtures/common.rb b/1.8/core/dir/fixtures/common.rb new file mode 100644 index 0000000000..642523d7ef --- /dev/null +++ b/1.8/core/dir/fixtures/common.rb @@ -0,0 +1,101 @@ +require 'fileutils' + +module DirSpecs + def DirSpecs.mock_dir + unless defined? @mock_dir then + @mock_dir = File.expand_path(tmp('mock')) + end + + @mock_dir + end + + def DirSpecs.nonexistent + name = mock_dir + "/nonexistent00" + name = name.next while File.exist? name + name + end + + def DirSpecs.clear_dirs + ['nonexisting', 'default_perms','reduced', 'always_returns_0'].each do |dir| + begin + Dir.rmdir dir + rescue + end + end + end + + def DirSpecs.create_mock_dirs + mock_dir = self.mock_dir + files = %W[ #{mock_dir}/.dotfile + #{mock_dir}/.dotsubdir/.dotfile + #{mock_dir}/.dotsubdir/nondotfile + + #{mock_dir}/deeply/.dotfile + #{mock_dir}/deeply/nested/.dotfile.ext + #{mock_dir}/deeply/nested/directory/structure/.ext + #{mock_dir}/deeply/nested/directory/structure/bar + #{mock_dir}/deeply/nested/directory/structure/baz + #{mock_dir}/deeply/nested/directory/structure/file_one + #{mock_dir}/deeply/nested/directory/structure/file_one.ext + #{mock_dir}/deeply/nested/directory/structure/foo + #{mock_dir}/deeply/nondotfile + + #{mock_dir}/file_one.ext + #{mock_dir}/file_two.ext + + #{mock_dir}/nondotfile + + #{mock_dir}/subdir_one/.dotfile + #{mock_dir}/subdir_one/nondotfile + #{mock_dir}/subdir_two/nondotfile + #{mock_dir}/subdir_two/nondotfile.ext + + #{mock_dir}/special/+ + + #{mock_dir}/special/^ + #{mock_dir}/special/$ + + #{mock_dir}/special/( + #{mock_dir}/special/) + #{mock_dir}/special/[ + #{mock_dir}/special/] + #{mock_dir}/special/{ + #{mock_dir}/special/} + ] + + platform_is_not :windows do + files += %W[ #{mock_dir}/special/* + #{mock_dir}/special/? + + #{mock_dir}/special/| + ] + end + + FileUtils.rm_rf mock_dir + files.each do |file| + FileUtils.mkdir_p File.dirname(file) + # eventually will be FileUtils.touch(File.basename(dir)) + File.open(file, "w") { } + end + end + + def self.expected_paths + %w[ + . + .. + .dotfile + .dotsubdir + deeply + file_one.ext + file_two.ext + nondotfile + special + subdir_one + subdir_two + ] + end + +end + +# Create the fixture directories every time the specs are run +DirSpecs.create_mock_dirs diff --git a/1.8/core/dir/foreach_spec.rb b/1.8/core/dir/foreach_spec.rb new file mode 100644 index 0000000000..c8ec4f6530 --- /dev/null +++ b/1.8/core/dir/foreach_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "Dir.foreach" do + it "yields all names in an existing directory to the provided block" do + a, b = [], [] + + Dir.foreach(DirSpecs.mock_dir) {|f| a << f} + Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested") {|f| b << f} + + a.sort.should == DirSpecs.expected_paths + b.sort.should == %w|. .. .dotfile.ext directory| + end + + it "returns nil when successful" do + Dir.foreach(DirSpecs.mock_dir) {|f| f}.should == nil + end + + it "raises a SystemCallError if passed a nonexistent directory" do + lambda { Dir.foreach DirSpecs.nonexistent }.should raise_error(SystemCallError) + end +end diff --git a/1.8/core/dir/getwd_spec.rb b/1.8/core/dir/getwd_spec.rb new file mode 100644 index 0000000000..152a127692 --- /dev/null +++ b/1.8/core/dir/getwd_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/pwd' + +describe "Dir.pwd" do + it_behaves_like :dir_pwd, :getwd +end diff --git a/1.8/core/dir/glob_spec.rb b/1.8/core/dir/glob_spec.rb new file mode 100644 index 0000000000..3f3e738704 --- /dev/null +++ b/1.8/core/dir/glob_spec.rb @@ -0,0 +1,63 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/glob' + +describe "Dir.glob" do + it_behaves_like(:dir_glob, :glob) + + before(:all) do + @cwd = Dir.pwd + + Dir.chdir DirSpecs.mock_dir + end + + it "matches both dot and non-dotfiles with '*' and option File::FNM_DOTMATCH" do + Dir.glob('*', File::FNM_DOTMATCH).sort.should == DirSpecs.expected_paths + end + + it "matches files with any beginning with '*' and option File::FNM_DOTMATCH" do + Dir.glob('*file', File::FNM_DOTMATCH).sort.should == %w|.dotfile nondotfile|.sort + end + + it "matches any files in the current directory with '**' and option File::FNM_DOTMATCH" do + Dir.glob('**', File::FNM_DOTMATCH).sort.should == DirSpecs.expected_paths + end + + it "recursively matches any subdirectories except './' or '../' with '**/' and option File::FNM_DOTMATCH" do + expected = %w[ + .dotsubdir/ + deeply/ + deeply/nested/ + deeply/nested/directory/ + deeply/nested/directory/structure/ + special/ + subdir_one/ + subdir_two/ + ] + + Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected + end + + it "matches the literal character '\\' with option File::FNM_NOESCAPE" do + Dir.mkdir 'foo?bar' + + begin + Dir.glob('foo?bar', File::FNM_NOESCAPE).should == %w|foo?bar| + Dir.glob('foo\?bar', File::FNM_NOESCAPE).should == [] + ensure + Dir.rmdir 'foo?bar' + end + + Dir.mkdir 'foo\?bar' + + begin + Dir.glob('foo\?bar', File::FNM_NOESCAPE).should == %w|foo\\?bar| + ensure + Dir.rmdir 'foo\?bar' + end + end + + after(:all) do + Dir.chdir @cwd + end +end diff --git a/1.8/core/dir/initialize_spec.rb b/1.8/core/dir/initialize_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/core/dir/initialize_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/core/dir/mkdir_spec.rb b/1.8/core/dir/mkdir_spec.rb new file mode 100644 index 0000000000..1283082662 --- /dev/null +++ b/1.8/core/dir/mkdir_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "Dir.mkdir" do + it "creates the named directory with the given permissions" do + DirSpecs.clear_dirs + + begin + File.exist?('nonexisting').should == false + Dir.mkdir 'nonexisting' + File.exist?('nonexisting').should == true + + Dir.mkdir 'default_perms' + a = File.stat('default_perms').mode + Dir.mkdir 'reduced', (a - 1) + File.stat('reduced').mode.should_not == a + + Dir.mkdir('always_returns_0').should == 0 + + system "chmod 0777 nonexisting default_perms reduced always_returns_0" + ensure + DirSpecs.clear_dirs + end + end + + it "raises a SystemCallError when lacking adequate permissions in the parent dir" do + # In case something happened it it didn't get cleaned up. + Dir.rmdir 'noperms' if File.directory? 'noperms' + + Dir.mkdir 'noperms', 0000 + + lambda { Dir.mkdir 'noperms/subdir' }.should raise_error(SystemCallError) + + system 'chmod 0777 noperms' + Dir.rmdir 'noperms' + end + + it "raises a SystemCallError if any of the directories in the path before the last does not exist" do + lambda { Dir.mkdir "#{DirSpecs.nonexistent}/subdir" }.should raise_error(SystemCallError) + end +end diff --git a/1.8/core/dir/new_spec.rb b/1.8/core/dir/new_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/core/dir/new_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/core/dir/open_spec.rb b/1.8/core/dir/open_spec.rb new file mode 100644 index 0000000000..955a3d8273 --- /dev/null +++ b/1.8/core/dir/open_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/open' + +describe "Dir.open" do + it_behaves_like :dir_open, :open +end diff --git a/1.8/core/dir/path_spec.rb b/1.8/core/dir/path_spec.rb new file mode 100644 index 0000000000..77c0f50cfa --- /dev/null +++ b/1.8/core/dir/path_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/closed' + +describe "Dir#path" do + it "returns the path that was supplied to .new or .open" do + dir = Dir.open DirSpecs.mock_dir + dir.path.should == DirSpecs.mock_dir + dir.close rescue nil + end +end + +describe "Dir#path" do + it_behaves_like :dir_closed, :path +end diff --git a/1.8/core/dir/pos_spec.rb b/1.8/core/dir/pos_spec.rb new file mode 100644 index 0000000000..4b7ef5c35c --- /dev/null +++ b/1.8/core/dir/pos_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/closed' +require File.dirname(__FILE__) + '/shared/pos' + +describe "Dir#pos" do + it_behaves_like :dir_pos, :pos +end + +describe "Dir#pos" do + it_behaves_like :dir_closed, :pos +end + +describe "Dir#pos=" do + it_behaves_like :dir_pos_set, :pos= +end diff --git a/1.8/core/dir/pwd_spec.rb b/1.8/core/dir/pwd_spec.rb new file mode 100644 index 0000000000..19d1b5c574 --- /dev/null +++ b/1.8/core/dir/pwd_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/pwd' + +describe "Dir.pwd" do + it_behaves_like :dir_pwd, :pwd +end diff --git a/1.8/core/dir/read_spec.rb b/1.8/core/dir/read_spec.rb new file mode 100644 index 0000000000..df832f1f4f --- /dev/null +++ b/1.8/core/dir/read_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/closed' + +describe "Dir#read" do + it "returns the file name in the current seek position" do + # an FS does not necessarily impose order + ls = `ls -a #{DirSpecs.mock_dir}`.split + dir = Dir.open DirSpecs.mock_dir + ls.should include(dir.read) + dir.close + end +end + +describe "Dir#read" do + it_behaves_like :dir_closed, :read +end diff --git a/1.8/core/dir/rewind_spec.rb b/1.8/core/dir/rewind_spec.rb new file mode 100644 index 0000000000..492227fd2c --- /dev/null +++ b/1.8/core/dir/rewind_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/closed' + +describe "Dir#rewind" do + before(:each) do + @dir = Dir.open DirSpecs.mock_dir + end + + after(:each) do + @dir.close + end + + it "resets the next read to start from the first entry" do + first = @dir.pos + a = @dir.read + b = @dir.read + prejmp = @dir.pos + ret = @dir.rewind + second = @dir.pos + c = @dir.read + + a.should_not == b + b.should_not == c + c.should == a + + second.should_not == prejmp + end + + it "returns the Dir instance" do + @dir.rewind.should == @dir + end +end + +describe "Dir#rewind" do + it_behaves_like :dir_closed, :rewind +end diff --git a/1.8/core/dir/rmdir_spec.rb b/1.8/core/dir/rmdir_spec.rb new file mode 100644 index 0000000000..a428ac9703 --- /dev/null +++ b/1.8/core/dir/rmdir_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/delete' + +describe "Dir.rmdir" do + it_behaves_like :dir_delete, :rmdir +end diff --git a/1.8/core/dir/seek_spec.rb b/1.8/core/dir/seek_spec.rb new file mode 100644 index 0000000000..dad29b44f1 --- /dev/null +++ b/1.8/core/dir/seek_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/pos' + +describe "Dir#seek" do + before(:each) do + @dir = Dir.open DirSpecs.mock_dir + end + + after(:each) do + @dir.close + end + + it "returns the Dir instance" do + @dir.seek(@dir.pos).should == @dir + end + + it_behaves_like :dir_pos_set, :seek +end diff --git a/1.8/core/dir/shared/closed.rb b/1.8/core/dir/shared/closed.rb new file mode 100644 index 0000000000..5f13931f37 --- /dev/null +++ b/1.8/core/dir/shared/closed.rb @@ -0,0 +1,11 @@ +shared :dir_closed do |cmd| + describe "Dir##{cmd}" do + it "raises an IOError when called on a closed Dir instance" do + lambda { + dir = Dir.open DirSpecs.mock_dir + dir.close + dir.send cmd + }.should raise_error(IOError) + end + end +end diff --git a/1.8/core/dir/shared/delete.rb b/1.8/core/dir/shared/delete.rb new file mode 100644 index 0000000000..edce3abaf6 --- /dev/null +++ b/1.8/core/dir/shared/delete.rb @@ -0,0 +1,29 @@ +shared :dir_delete do |cmd| + describe "Dir.#{cmd}" do + it "removes empty directories" do + %w|rmdir delete unlink|.each {|cmd| + Dir.mkdir 'empty_subdir' + Dir.send(cmd, 'empty_subdir').should == 0 + } + end + + it "raises a SystemCallError when trying to remove a nonempty directory" do + %w|rmdir delete unlink|.each {|cmd| + lambda { Dir.send cmd, 'subdir_one' }.should raise_error(SystemCallError) + } + end + + it "raises a SystemCallError if lacking adequate permissions to remove the directory" do + %w|rmdir delete unlink|.each {|cmd| + system "mkdir -p noperm_#{cmd}/child" + system "chmod 0000 noperm_#{cmd}" + + lambda { Dir.send cmd, "noperm_#{cmd}/child" }.should raise_error(SystemCallError) + + system "chmod 0777 noperm_#{cmd}" + Dir.rmdir "noperm_#{cmd}/child" + Dir.rmdir "noperm_#{cmd}" + } + end + end +end diff --git a/1.8/core/dir/shared/glob.rb b/1.8/core/dir/shared/glob.rb new file mode 100644 index 0000000000..60671d9aa3 --- /dev/null +++ b/1.8/core/dir/shared/glob.rb @@ -0,0 +1,203 @@ + +shared :dir_glob do |cmd| + describe "Dir.#{cmd}" do + before(:all) do + @cwd = Dir.pwd + Dir.chdir DirSpecs.mock_dir + end + + it "matches non-dotfiles with '*'" do + expected = %w[ + deeply + file_one.ext + file_two.ext + nondotfile + special + subdir_one + subdir_two + ] + + Dir.send(cmd,'*').sort.should == expected + end + + it "returns empty array when empty pattern provided" do + Dir.send(cmd, '').should == [] + end + + it "matches regexp special +" do + Dir.send(cmd, 'special/+').should == ['special/+'] + end + + platform_is_not :windows do + it "matches regexp special *" do + Dir.send(cmd, 'special/\*').should == ['special/*'] + end + + it "matches regexp special ?" do + Dir.send(cmd, 'special/\?').should == ['special/?'] + end + + it "matches regexp special |" do + Dir.send(cmd, 'special/|').should == ['special/|'] + end + end + + it "matches regexp special ^" do + Dir.send(cmd, 'special/^').should == ['special/^'] + end + + it "matches regexp special $" do + Dir.send(cmd, 'special/$').should == ['special/$'] + end + + it "matches regexp special (" do + Dir.send(cmd, 'special/(').should == ['special/('] + end + + it "matches regexp special )" do + Dir.send(cmd, 'special/)').should == ['special/)'] + end + + it "matches regexp special [" do + Dir.send(cmd, 'special/\[').should == ['special/['] + end + + it "matches regexp special ]" do + Dir.send(cmd, 'special/]').should == ['special/]'] + end + + it "matches regexp special {" do + Dir.send(cmd, 'special/\{').should == ['special/{'] + end + + it "matches regexp special }" do + Dir.send(cmd, 'special/\}').should == ['special/}'] + end + + it "matches dotfiles with '.*'" do + Dir.send(cmd, '.*').sort.should == %w|. .. .dotfile .dotsubdir|.sort + end + + it "matches non-dotfiles with '*'" do + Dir.send(cmd, '*file').sort.should == %w|nondotfile|.sort + end + + it "matches dotfiles with '.*'" do + Dir.send(cmd, '.*file').sort.should == %w|.dotfile|.sort + end + + it "matches files with any ending with '*'" do + Dir.send(cmd, 'file*').sort.should == %w|file_one.ext file_two.ext|.sort + end + + it "matches files with any middle with '*'" do + Dir.send(cmd, 'sub*_one').sort.should == %w|subdir_one|.sort + end + + it "matches files with multiple '*' special characters" do + Dir.send(cmd, '*fi*e*').sort.should == %w|nondotfile file_one.ext file_two.ext|.sort + end + + it "matches non-dotfiles in the current directory with '**'" do + expected = %w[ + deeply + file_one.ext + file_two.ext + nondotfile + special + subdir_one + subdir_two + ] + + Dir.send(cmd, '**').sort.should == expected + end + + it "matches dotfiles in the current directory with '.**'" do + Dir.send(cmd, '.**').sort.should == %w|. .. .dotsubdir .dotfile|.sort + end + + it "recursively matches any nondot subdirectories with '**/'" do + expected = %w[ + deeply/ + deeply/nested/ + deeply/nested/directory/ + deeply/nested/directory/structure/ + special/ + subdir_one/ + subdir_two/ + ] + + Dir.send(cmd, '**/').sort.should == expected + end + + it "recursively matches any subdirectories including ./ and ../ with '.**/'" do + Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do + Dir.send(cmd, '.**/').sort.should == %w|./ ../|.sort + end + end + + it "matches a single character except leading '.' with '?'" do + Dir.send(cmd, '?ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "accepts multiple '?' characters in a pattern" do + Dir.send(cmd, 'subdir_???').sort.should == %w|subdir_one subdir_two|.sort + end + + it "matches any characters in a set with '[]'" do + Dir.send(cmd, '[stfu]ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "matches any characters in a range with '[-]'" do + Dir.send(cmd, '[a-zA-Z]ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "matches any characters except those in a set with '[^]'" do + Dir.send(cmd, '[^wtf]ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "matches any characters except those in a range with '[^-,,...}'" do + Dir.send(cmd, 'subdir_{one,two,three}').sort.should == %w|subdir_one subdir_two|.sort + end + + it "accepts string sets with empty strings with {,,}" do + a = Dir.send(cmd, 'deeply/nested/directory/structure/file_one{.ext,}').sort + a.should == %w|deeply/nested/directory/structure/file_one.ext + deeply/nested/directory/structure/file_one|.sort + end + + it "matches dot or non-dotfiles with '{,.}*'" do + Dir.send(cmd, '{,.}*').sort.should == DirSpecs.expected_paths + end + + it "matches special characters by escaping with a backslash with '\\'" do + Dir.mkdir 'foo*bar' + + begin + Dir.glob('foo?bar').should == %w|foo*bar| + Dir.glob('foo\?bar').should == [] + Dir.glob('nond\otfile').should == %w|nondotfile| + ensure + Dir.rmdir 'foo*bar' + end + end + + it "recursively matches directories with '**/'" do + %w|glob []|.each {|cmd| + Dir.send(cmd, '**/*fil?{,.}*').sort.should == %w|deeply/nested/directory/structure/file_one + deeply/nested/directory/structure/file_one.ext + deeply/nondotfile file_one.ext file_two.ext + nondotfile subdir_one/nondotfile + subdir_two/nondotfile subdir_two/nondotfile.ext + subdir_two/nondotfile.ext| + } + end + after(:all) do + Dir.chdir @cwd + end + end +end diff --git a/1.8/core/dir/shared/open.rb b/1.8/core/dir/shared/open.rb new file mode 100644 index 0000000000..54bc1bbac0 --- /dev/null +++ b/1.8/core/dir/shared/open.rb @@ -0,0 +1,35 @@ +shared :dir_open do |cmd| + describe "Dir.#{cmd}" do + it "returns a Dir instance representing the specified directory" do + dir = Dir.send(cmd, DirSpecs.mock_dir) + dir.class.should == Dir + dir.close + end + + it "raises a SystemCallError if the directory does not exist" do + lambda { Dir.send cmd, DirSpecs.nonexistent }.should raise_error(SystemCallError) + end + + it "may take a block which is yielded to with the Dir instance" do + Dir.send(cmd, DirSpecs.mock_dir) {|dir| dir.class.should == Dir } + end + + it "returns the value of the block if a block is given" do + Dir.open(DirSpecs.mock_dir) {|dir| :value }.should == :value + end + + it "closes the Dir instance when the block exits if given a block" do + closed_dir = Dir.send(cmd, DirSpecs.mock_dir) { |dir| dir } + lambda { closed_dir.close }.should raise_error(IOError, "closed directory") + end + + it "closes the Dir instance when the block exits the block even due to an exception" do + @closed_dir = nil + + l = lambda { Dir.send(cmd, DirSpecs.mock_dir) { |dir| @closed_dir = dir; raise } } + l.should raise_error + + lambda { @closed_dir.close }.should raise_error(IOError, "closed directory") + end + end +end diff --git a/1.8/core/dir/shared/pos.rb b/1.8/core/dir/shared/pos.rb new file mode 100644 index 0000000000..086a8ff934 --- /dev/null +++ b/1.8/core/dir/shared/pos.rb @@ -0,0 +1,55 @@ +shared :dir_pos do |cmd| + describe "Dir##{cmd}" do + before :each do + @dir = Dir.open DirSpecs.mock_dir + end + + after :each do + @dir.close rescue nil + end + + it "returns an Integer representing the current position in the directory" do + @dir.send(cmd).should be_kind_of(Integer) + @dir.send(cmd).should be_kind_of(Integer) + @dir.send(cmd).should be_kind_of(Integer) + end + + it "returns a different Integer if moved from previous position" do + a = @dir.send(cmd) + @dir.read + b = @dir.send(cmd) + + a.should be_kind_of(Integer) + b.should be_kind_of(Integer) + + a.should_not == b + end + end +end + +shared :dir_pos_set do |cmd| + describe "Dir##{cmd}" do + before(:each) do + @dir = Dir.open DirSpecs.mock_dir + end + + after(:each) do + @dir.close + end + + # NOTE: #seek/#pos= to a position not returned by #tell/#pos is undefined + # and should not be spec'd. + + it "moves the read position to a previously obtained position" do + pos = @dir.pos + a = @dir.read + b = @dir.read + ret = @dir.send cmd, pos + c = @dir.read + + a.should_not == b + b.should_not == c + c.should == a + end + end +end diff --git a/1.8/core/dir/shared/pwd.rb b/1.8/core/dir/shared/pwd.rb new file mode 100644 index 0000000000..129f0cc9f5 --- /dev/null +++ b/1.8/core/dir/shared/pwd.rb @@ -0,0 +1,9 @@ +shared :dir_pwd do |cmd| + describe "Dir.pwd" do + it "returns the current working directory" do + # On ubuntu gutsy, for example, /bin/pwd does not + # understand -P. With just `pwd -P`, /bin/pwd is run. + Dir.send(cmd).should == `/bin/sh -c "pwd -P"`.chomp + end + end +end diff --git a/1.8/core/dir/tell_spec.rb b/1.8/core/dir/tell_spec.rb new file mode 100644 index 0000000000..985973142f --- /dev/null +++ b/1.8/core/dir/tell_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/closed' +require File.dirname(__FILE__) + '/shared/pos' + +describe "Dir#tell" do + it_behaves_like :dir_pos, :tell +end + +describe "Dir#tell" do + it_behaves_like :dir_closed, :tell +end diff --git a/1.8/core/dir/unlink_spec.rb b/1.8/core/dir/unlink_spec.rb new file mode 100644 index 0000000000..134eda998a --- /dev/null +++ b/1.8/core/dir/unlink_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' +require File.dirname(__FILE__) + '/shared/delete' + +describe "Dir.unlink" do + it_behaves_like :dir_delete, :unlink +end diff --git a/1.8/core/enumerable/all_spec.rb b/1.8/core/enumerable/all_spec.rb new file mode 100644 index 0000000000..0c3954ec79 --- /dev/null +++ b/1.8/core/enumerable/all_spec.rb @@ -0,0 +1,51 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#all?" do + + before :each do + @enum1 = [0, 1, 2, -1] + @enum2 = [nil, false, true] + end + + it "fails when have a wrong argument" do + lambda { @enum1.all?(1) }.should raise_error(ArgumentError) + end + + it "with no block returns true if no elements are false or nil" do + EnumerableSpecs::Numerous.new.all?.should == true + EnumerableSpecs::Numerous.new(1, nil, 2).all?.should == false + EnumerableSpecs::Numerous.new(false).all?.should == false + + @enum1.all?.should == true + @enum2.all?.should == false + end + + it "returns true if the block never returns false or nil" do + EnumerableSpecs::Numerous.new.all? { true }.should == true + @enum1.all?{ |o| o < 5 }.should == true + @enum1.all?{ |o| o > 2 }.should == false + end + + it "returns false if the block ever returns false or nil" do + EnumerableSpecs::Numerous.new.all? { |i| i > 5 }.should == false + EnumerableSpecs::Numerous.new.all? { |i| i == 3 ? nil : true }.should == false + end + + it "passes each element of the collection to the given block. (Legacy form rubycon)" do + @enum1.all?{ |o| 5.times{ @enum1.shift } }.should == true + EnumerableSpecs::EachDefiner.new().all?.should == true + EnumerableSpecs::EachDefiner.new('a','b','c').all?.should == true + EnumerableSpecs::EachDefiner.new(0, "x", true).all?.should == true + EnumerableSpecs::EachDefiner.new(nil).all?.should == false + EnumerableSpecs::EachDefiner.new(nil, nil).all?.should == false + EnumerableSpecs::EachDefiner.new(false).all?.should == false + EnumerableSpecs::EachDefiner.new(false, false).all?.should == false + EnumerableSpecs::EachDefiner.new(0, "x", false, true).all?.should == false + end + + after :each do + @enum1 = nil + end + +end diff --git a/1.8/core/enumerable/any_spec.rb b/1.8/core/enumerable/any_spec.rb new file mode 100644 index 0000000000..625a03f74d --- /dev/null +++ b/1.8/core/enumerable/any_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#any?" do + it "any? with no block should return true if any element is not false or nil" do + EnumerableSpecs::Numerous.new.any?.should == true + EnumerableSpecs::Numerous.new(1, nil, 2).any?.should == true + EnumerableSpecs::Numerous.new(false).any?.should == false + end + + it "any? should return true if the block ever returns other than false or nil" do + EnumerableSpecs::Numerous.new.any? { |i| i == 5 }.should == true + end + + it "any? should return false if the block never returns other than false or nil" do + EnumerableSpecs::Numerous.new.any? { false }.should == false + EnumerableSpecs::Numerous.new.any? { nil }.should == false + end + + it "any? with no block should return true if any element is not false or nil (Legacy form rubycon)" do + EnumerableSpecs::EachDefiner.new('a','b','c').any?.should == true + EnumerableSpecs::EachDefiner.new(false, 0, nil).any?.should == true + EnumerableSpecs::EachDefiner.new().any?.should == false + EnumerableSpecs::EachDefiner.new(false, nil).any?.should == false + EnumerableSpecs::EachDefiner.new(true).any?.should == true + end +end diff --git a/1.8/core/enumerable/collect_spec.rb b/1.8/core/enumerable/collect_spec.rb new file mode 100644 index 0000000000..bf3a6d91fa --- /dev/null +++ b/1.8/core/enumerable/collect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/collect' + +describe "Enumerable#collect" do + it_behaves_like(:enumerable_collect , :collect) +end diff --git a/1.8/core/enumerable/detect_spec.rb b/1.8/core/enumerable/detect_spec.rb new file mode 100644 index 0000000000..7ade5adfd0 --- /dev/null +++ b/1.8/core/enumerable/detect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/find' + +describe "Enumerable#detect" do + it_behaves_like(:enumerable_find , :detect) +end diff --git a/1.8/core/enumerable/each_spec.rb b/1.8/core/enumerable/each_spec.rb new file mode 100644 index 0000000000..e783d306dd --- /dev/null +++ b/1.8/core/enumerable/each_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable.each" do + it "be provided" do + EnumerableSpecs::Numerous.new.respond_to?(:each).should == true + end + + it "provide each element to the block" do + @b=[] + EnumerableSpecs::Numerous.new.each { |i| @b << i } + @b.should == [2, 5, 3, 6, 1, 4] + end +end diff --git a/1.8/core/enumerable/each_with_index_spec.rb b/1.8/core/enumerable/each_with_index_spec.rb new file mode 100644 index 0000000000..1862743f34 --- /dev/null +++ b/1.8/core/enumerable/each_with_index_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#each_with_index" do + + before :each do + @b = [2, 5, 3, 6, 1, 4] + end + + it "passes each element and its index to block" do + @a = [] + EnumerableSpecs::Numerous.new.each_with_index { |o, i| @a << [o, i] } + @a.should == [[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]] + end + + it "provides each element to the block" do + acc = [] + obj = EnumerableSpecs::EachDefiner.new() + res = obj.each_with_index {|a,i| acc << [a,i]} + acc.should == [] + obj.should == res + end + + it "provides each element to the block and its index" do + acc = [] + res = @b.each_with_index {|a,i| acc << [a,i]} + [[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]].should == acc + @b.should == res + end + +end diff --git a/1.8/core/enumerable/entries_spec.rb b/1.8/core/enumerable/entries_spec.rb new file mode 100644 index 0000000000..03c3f6cb55 --- /dev/null +++ b/1.8/core/enumerable/entries_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/entries' + +describe "Enumerable#entries" do + it_behaves_like(:enumerable_entries , :entries) +end diff --git a/1.8/core/enumerable/find_all_spec.rb b/1.8/core/enumerable/find_all_spec.rb new file mode 100644 index 0000000000..bbf1cca95d --- /dev/null +++ b/1.8/core/enumerable/find_all_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/find_all' + +describe "Enumerable#find_all" do + it_behaves_like(:enumerable_find_all , :find_all) +end diff --git a/1.8/core/enumerable/find_spec.rb b/1.8/core/enumerable/find_spec.rb new file mode 100644 index 0000000000..bc313fcdfe --- /dev/null +++ b/1.8/core/enumerable/find_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/find' + +describe "Enumerable#find" do + it_behaves_like(:enumerable_find , :find) +end diff --git a/1.8/core/enumerable/fixtures/classes.rb b/1.8/core/enumerable/fixtures/classes.rb new file mode 100644 index 0000000000..b942bed753 --- /dev/null +++ b/1.8/core/enumerable/fixtures/classes.rb @@ -0,0 +1,99 @@ +module EnumerableSpecs + + class Numerous + include Enumerable + + def initialize(*list) + @list = list.empty? ? [2, 5, 3, 6, 1, 4] : list + end + + def each + @list.each { |i| yield i } + end + end + + # (Legacy form rubycon) + class EachDefiner + + include Enumerable + + attr_reader :arr + + def initialize(*arr) + @arr = arr + end + + def each + i = 0 + loop do + break if i == @arr.size + yield @arr[i] + i += 1 + end + end + + end + + class SortByDummy + def initialize(s) + @s = s + end + + def s + @s + end + end + + class ComparesByVowelCount + + attr_accessor :value, :vowels + + def self.wrap(*args) + args.map {|element| ComparesByVowelCount.new(element)} + end + + def initialize(string) + self.value = string + all_vowels = ['a', 'e' , 'i' , 'o', 'u'] + self.vowels = string.gsub(/[^aeiou]/,'').size + end + + def <=>(other) + self.vowels <=> other.vowels + end + + end + + class InvalidComparable + def <=>(other) + "Not Valid" + end + end + + class ArrayConvertable + attr_accessor :called + def initialize(*values) + @values = values; + end + + def to_a + self.called = :to_a + @values + end + + def to_arr + self.called = :to_arr + @values + end + end + + class Equals + def initialize(obj) + @obj = obj + end + def ==(other) + @obj == other + end + end + +end # EnumerableSpecs utility classes diff --git a/1.8/core/enumerable/grep_spec.rb b/1.8/core/enumerable/grep_spec.rb new file mode 100644 index 0000000000..b569ab48e1 --- /dev/null +++ b/1.8/core/enumerable/grep_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#grep" do + before(:each) do + @a = EnumerableSpecs::EachDefiner.new( 2, 4, 6, 8, 10) + end + + it "grep without a block should return an array of all elements === pattern" do + class EnumerableSpecGrep; def ===(obj); obj == '2'; end; end + + EnumerableSpecs::Numerous.new('2', 'a', 'nil', '3', false).grep(EnumerableSpecGrep.new).should == ['2'] + end + + it "grep with a block should return an array of elements === pattern passed through block" do + class EnumerableSpecGrep2; def ===(obj); /^ca/ =~ obj; end; end + + EnumerableSpecs::Numerous.new("cat", "coat", "car", "cadr", "cost").grep(EnumerableSpecGrep2.new) { |i| i.upcase }.should == ["CAT", "CAR", "CADR"] + end + + it "grep the enumerable (rubycon legacy)" do + EnumerableSpecs::EachDefiner.new().grep(1).should == [] + @a.grep(3..7).should == [4,6] + @a.grep(3..7) {|a| a+1}.should == [5,7] + end +end diff --git a/1.8/core/enumerable/include_spec.rb b/1.8/core/enumerable/include_spec.rb new file mode 100644 index 0000000000..afd6cc51af --- /dev/null +++ b/1.8/core/enumerable/include_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/include' + +describe "Enumerable#include?" do + it_behaves_like(:enumerable_include, :include?) +end diff --git a/1.8/core/enumerable/inject_spec.rb b/1.8/core/enumerable/inject_spec.rb new file mode 100644 index 0000000000..1bdcb19f87 --- /dev/null +++ b/1.8/core/enumerable/inject_spec.rb @@ -0,0 +1,58 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#inject" do + it "inject with argument takes a block with an accumulator (with argument as initial value) and the current element. Value of block becomes new accumulator" do + a = [] + EnumerableSpecs::Numerous.new.inject(0) { |memo, i| a << [memo, i]; i } + a.should == [[0, 2], [2, 5], [5, 3], [3, 6], [6, 1], [1, 4]] + EnumerableSpecs::EachDefiner.new(true, true, true).inject(nil) {|result, i| i && result}.should == nil + end + + it "produces an array of the accumulator and the argument when given a block with a *arg" do + a = [] + [1,2].inject(0) {|*args| a << args; args[0] + args[1]} + a.should == [[0, 1], [1, 2]] + end + + it "only takes one argument" do + lambda { EnumerableSpecs::Numerous.new.inject(0, 1) { |memo, i| i } }.should raise_error(ArgumentError) + end + + it "inject without argument takes a block with an accumulator (with first element as initial value) and the current element. Value of block becomes new accumulator" do + a = [] + EnumerableSpecs::Numerous.new.inject { |memo, i| a << [memo, i]; i } + a.should == [[2, 5], [5, 3], [3, 6], [6, 1], [1, 4]] + end + + it "inject with inject arguments(legacy rubycon)" do + # with inject argument + EnumerableSpecs::EachDefiner.new().inject(1) {|acc,x| 999 }.should == 1 + EnumerableSpecs::EachDefiner.new(2).inject(1) {|acc,x| 999 }.should == 999 + EnumerableSpecs::EachDefiner.new(2).inject(1) {|acc,x| acc }.should == 1 + EnumerableSpecs::EachDefiner.new(2).inject(1) {|acc,x| x }.should == 2 + + EnumerableSpecs::EachDefiner.new(1,2,3,4).inject(100) {|acc,x| acc + x }.should == 110 + EnumerableSpecs::EachDefiner.new(1,2,3,4).inject(100) {|acc,x| acc * x }.should == 2400 + + EnumerableSpecs::EachDefiner.new('a','b','c').inject("z") {|result, i| i+result}.should == "cbaz" + end + + it "inject withou inject arguments(legacy rubycon)" do + # no inject argument + EnumerableSpecs::EachDefiner.new(2).inject {|acc,x| 999 } .should == 2 + EnumerableSpecs::EachDefiner.new(2).inject {|acc,x| acc }.should == 2 + EnumerableSpecs::EachDefiner.new(2).inject {|acc,x| x }.should == 2 + + EnumerableSpecs::EachDefiner.new(1,2,3,4).inject {|acc,x| acc + x }.should == 10 + EnumerableSpecs::EachDefiner.new(1,2,3,4).inject {|acc,x| acc * x }.should == 24 + + EnumerableSpecs::EachDefiner.new('a','b','c').inject {|result, i| i+result}.should == "cba" + EnumerableSpecs::EachDefiner.new(3, 4, 5).inject {|result, i| result*i}.should == 60 + EnumerableSpecs::EachDefiner.new([1], 2, 'a','b').inject{|r,i| r< b }.should == "4" + EnumerableSpecs::EachDefiner.new( 2 , 33 , 4 , 11 ).max {|a,b| a <=> b }.should == 33 + + EnumerableSpecs::EachDefiner.new("2","33","4","11").max {|a,b| b <=> a }.should == "11" + EnumerableSpecs::EachDefiner.new( 2 , 33 , 4 , 11 ).max {|a,b| b <=> a }.should == 2 + + @e_strs.max {|a,b| a.length <=> b.length }.should == "1010101010" + + @e_strs.max {|a,b| a <=> b }.should == "666666" + @e_strs.max {|a,b| a.to_i <=> b.to_i }.should == "1010101010" + + @e_ints.max {|a,b| a <=> b }.should == 1010101010 + @e_ints.max {|a,b| a.to_s <=> b.to_s }.should == 666666 + end + + it "returns the minimum for enumerables that contain nils" do + arr = EnumerableSpecs::Numerous.new(nil, nil, true) + arr.max { |a, b| + x = a.nil? ? 1 : a ? 0 : -1 + y = b.nil? ? 1 : b ? 0 : -1 + x <=> y + }.should == nil + end +end diff --git a/1.8/core/enumerable/member_spec.rb b/1.8/core/enumerable/member_spec.rb new file mode 100644 index 0000000000..c612f2fc86 --- /dev/null +++ b/1.8/core/enumerable/member_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/include' + +describe "Enumerable#member?" do + it_behaves_like(:enumerable_include, :member?) +end diff --git a/1.8/core/enumerable/min_spec.rb b/1.8/core/enumerable/min_spec.rb new file mode 100644 index 0000000000..e223cc0ab2 --- /dev/null +++ b/1.8/core/enumerable/min_spec.rb @@ -0,0 +1,79 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#min" do + before :each do + @a = EnumerableSpecs::EachDefiner.new( 2, 4, 6, 8, 10 ) + + @e_strs = EnumerableSpecs::EachDefiner.new("333", "22", "666666", "1", "55555", "1010101010") + @e_ints = EnumerableSpecs::EachDefiner.new( 333, 22, 666666, 55555, 1010101010) + end + + it "min should return the minimum element" do + EnumerableSpecs::Numerous.new.min.should == 1 + end + + it "return the minimun (basic cases)" do + EnumerableSpecs::EachDefiner.new(55).min.should == 55 + + EnumerableSpecs::EachDefiner.new(11,99).min.should == 11 + EnumerableSpecs::EachDefiner.new(99,11).min.should == 11 + EnumerableSpecs::EachDefiner.new(2, 33, 4, 11).min.should == 2 + + EnumerableSpecs::EachDefiner.new(1,2,3,4,5).min.should == 1 + EnumerableSpecs::EachDefiner.new(5,4,3,2,1).min.should == 1 + EnumerableSpecs::EachDefiner.new(4,1,3,5,2).min.should == 1 + EnumerableSpecs::EachDefiner.new(5,5,5,5,5).min.should == 5 + + EnumerableSpecs::EachDefiner.new("aa","tt").min.should == "aa" + EnumerableSpecs::EachDefiner.new("tt","aa").min.should == "aa" + EnumerableSpecs::EachDefiner.new("2","33","4","11").min.should == "11" + + @e_strs.min.should == "1" + @e_ints.min.should == 22 + end + + it "return nil when error" do + EnumerableSpecs::EachDefiner.new().min.should == nil + lambda { + EnumerableSpecs::EachDefiner.new(Object.new, Object.new).min + }.should raise_error(NoMethodError) + lambda { + EnumerableSpecs::EachDefiner.new(11,"22").min + }.should raise_error(ArgumentError) + lambda { + EnumerableSpecs::EachDefiner.new(11,12,22,33).min{|a, b| nil} + }.should raise_error(ArgumentError) + end + + it "return the minimun when using a block rule" do + EnumerableSpecs::EachDefiner.new("2","33","4","11").min {|a,b| a <=> b }.should == "11" + EnumerableSpecs::EachDefiner.new( 2 , 33 , 4 , 11 ).min {|a,b| a <=> b }.should == 2 + + EnumerableSpecs::EachDefiner.new("2","33","4","11").min {|a,b| b <=> a }.should == "4" + EnumerableSpecs::EachDefiner.new( 2 , 33 , 4 , 11 ).min {|a,b| b <=> a }.should == 33 + + EnumerableSpecs::EachDefiner.new( 1, 2, 3, 4 ).min {|a,b| 15 }.should == 1 + + EnumerableSpecs::EachDefiner.new(11,12,22,33).min{|a, b| 2 }.should == 11 + @i = -2 + EnumerableSpecs::EachDefiner.new(11,12,22,33).min{|a, b| @i += 1 }.should == 12 + + @e_strs.min {|a,b| a.length <=> b.length }.should == "1" + + @e_strs.min {|a,b| a <=> b }.should == "1" + @e_strs.min {|a,b| a.to_i <=> b.to_i }.should == "1" + + @e_ints.min {|a,b| a <=> b }.should == 22 + @e_ints.min {|a,b| a.to_s <=> b.to_s }.should == 1010101010 + end + + it "returns the minimum for enumerables that contain nils" do + arr = EnumerableSpecs::Numerous.new(nil, nil, true) + arr.min { |a, b| + x = a.nil? ? -1 : a ? 0 : 1 + y = b.nil? ? -1 : b ? 0 : 1 + x <=> y + }.should == nil + end +end diff --git a/1.8/core/enumerable/partition_spec.rb b/1.8/core/enumerable/partition_spec.rb new file mode 100644 index 0000000000..32b1fecf75 --- /dev/null +++ b/1.8/core/enumerable/partition_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#partition" do + it "returns two arrays, the first containing elements for which the block is true, the second containing the rest" do + EnumerableSpecs::Numerous.new.partition { |i| i % 2 == 0 }.should == [[2, 6, 4], [5, 3, 1]] + end + + it "throws LocalJumpError if called without a block" do + lambda { EnumerableSpecs::Numerous.new.partition }.should raise_error(LocalJumpError) + end +end diff --git a/1.8/core/enumerable/reject_spec.rb b/1.8/core/enumerable/reject_spec.rb new file mode 100644 index 0000000000..c3541f65d4 --- /dev/null +++ b/1.8/core/enumerable/reject_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#reject" do + it "returns an array of the elements for which block is false" do + EnumerableSpecs::Numerous.new.reject { |i| i > 3 }.should == [2, 3, 1] + entries = (1..10).to_a + numerous = EnumerableSpecs::Numerous.new(*entries) + numerous.reject {|i| i % 2 == 0 }.should == [1,3,5,7,9] + numerous.reject {|i| true }.should == [] + numerous.reject {|i| false }.should == entries + end + + it "raises a LocalJumpError if no block is given" do + lambda { EnumerableSpecs::Numerous.new.reject }.should raise_error(LocalJumpError) + end +end + diff --git a/1.8/core/enumerable/select_spec.rb b/1.8/core/enumerable/select_spec.rb new file mode 100644 index 0000000000..0194ef1aab --- /dev/null +++ b/1.8/core/enumerable/select_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/find_all' + +describe "Enumerable#select" do + it_behaves_like(:enumerable_find_all , :select) +end diff --git a/1.8/core/enumerable/shared/collect.rb b/1.8/core/enumerable/shared/collect.rb new file mode 100644 index 0000000000..d2d30e89c3 --- /dev/null +++ b/1.8/core/enumerable/shared/collect.rb @@ -0,0 +1,11 @@ +shared :enumerable_collect do |cmd| + describe "Enumerable##{cmd}" do + + it "collect should return a new array with the results of passing each element to block" do + entries = [0, 1, 3, 4, 5, 6] + numerous = EnumerableSpecs::Numerous.new(*entries) + numerous.send(cmd) { |i| i % 2 }.should == [0, 1, 1, 0, 1, 0] + numerous.send(cmd) { |i| i }.should == entries + end + end +end diff --git a/1.8/core/enumerable/shared/entries.rb b/1.8/core/enumerable/shared/entries.rb new file mode 100644 index 0000000000..17094fd9bd --- /dev/null +++ b/1.8/core/enumerable/shared/entries.rb @@ -0,0 +1,16 @@ +shared :enumerable_entries do |cmd| + describe "Enumerable##{cmd}" do + before :each do + @entries = [2, 4, 6, 8, 10] + @numerous = EnumerableSpecs::Numerous.new(*@entries) + end + + it "returns an array containing the items in enum." do + @numerous.send(cmd).should == @entries + end + + it "returns an array containing the elements" do + EnumerableSpecs::Numerous.new(1, nil, 'a', 2, false, true).send(cmd).should == [1, nil, "a", 2, false, true] + end + end +end diff --git a/1.8/core/enumerable/shared/find.rb b/1.8/core/enumerable/shared/find.rb new file mode 100644 index 0000000000..e404befa1c --- /dev/null +++ b/1.8/core/enumerable/shared/find.rb @@ -0,0 +1,44 @@ +shared :enumerable_find do |cmd| + describe "Enumerable##{cmd}" do + # #detect and #find are aliases, so we only need one function + before :each do + @elements = [2, 4, 6, 8, 10] + @numerous = EnumerableSpecs::Numerous.new(*@elements) + end + + it "Passes each entry in enum to block while block when block is false" do + visited_elements = [] + @numerous.send(cmd) do |element| + visited_elements << element + false + end + visited_elements.should == @elements + end + + it "Returns nil when the block is false and there is no ifnone proc given" do + @numerous.send(cmd) {|e| false }.should == nil + end + + it "Returns the first element for which the block is not false" do + @elements.each do |element| + @numerous.send(cmd) {|e| e > element - 1 }.should == element + end + end + + it "Returns the value of the ifnone proc if the block is false" do + fail_proc = lambda { "cheeseburgers" } + @numerous.send(cmd, fail_proc) {|e| false }.should == "cheeseburgers" + end + + it "Doesn't call the ifnone proc if an element is found" do + fail_proc = lambda { raise "This shouldn't have been called" } + @numerous.send(cmd, fail_proc) {|e| e == @elements.first } + end + + it "Calls the ifnone proc only once when the block is false" do + times = 0 + fail_proc = lambda { times += 1; raise if times > 1; "cheeseburgers" } + @numerous.send(cmd, fail_proc) {|e| false }.should == "cheeseburgers" + end + end +end diff --git a/1.8/core/enumerable/shared/find_all.rb b/1.8/core/enumerable/shared/find_all.rb new file mode 100644 index 0000000000..e02270b5cf --- /dev/null +++ b/1.8/core/enumerable/shared/find_all.rb @@ -0,0 +1,11 @@ +shared :enumerable_find_all do |cmd| + describe "Enumerable##{cmd}" do + it "returns all elements for which the block is not false" do + entries = (1..10).to_a + numerous = EnumerableSpecs::Numerous.new(*entries) + numerous.send(cmd) {|i| i % 3 == 0 }.should == [3, 6, 9] + numerous.send(cmd) {|i| true }.should == (1..10).to_a + numerous.send(cmd) {|i| false }.should == [] + end + end +end diff --git a/1.8/core/enumerable/shared/include.rb b/1.8/core/enumerable/shared/include.rb new file mode 100644 index 0000000000..178ddd962d --- /dev/null +++ b/1.8/core/enumerable/shared/include.rb @@ -0,0 +1,19 @@ +shared :enumerable_include do |cmd| + describe "Enumerable##{cmd}" do + it "returns true if any element == argument" do + class EnumerableSpecIncludeP; def ==(obj) obj == 5; end; end + + elements = (0..5).to_a + EnumerableSpecs::Numerous.new(*elements).send(cmd,5).should == true + EnumerableSpecs::Numerous.new(*elements).send(cmd,10).should == false + EnumerableSpecs::Numerous.new(*elements).send(cmd,EnumerableSpecIncludeP.new).should == true + end + + it "returns true if any member of enum equals obj when == compare different classes (legacy rubycon)" do + # equality is tested with == + EnumerableSpecs::Numerous.new(2,4,6,8,10).send(cmd, 2.0).should == true + EnumerableSpecs::Numerous.new(2,4,[6,8],10).send(cmd, [6, 8]).should == true + EnumerableSpecs::Numerous.new(2,4,[6,8],10).send(cmd, [6.0, 8.0]).should == true + end + end +end diff --git a/1.8/core/enumerable/sort_by_spec.rb b/1.8/core/enumerable/sort_by_spec.rb new file mode 100644 index 0000000000..7f9f1afb81 --- /dev/null +++ b/1.8/core/enumerable/sort_by_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#sort_by" do + it "returns an array of elements ordered by the result of block" do + a = EnumerableSpecs::Numerous.new("once", "upon", "a", "time") + a.sort_by { |i| i[0] }.should == ["a", "once", "time", "upon"] + end + + it "sorts the object by the given attribute" do + a = EnumerableSpecs::SortByDummy.new("fooo") + b = EnumerableSpecs::SortByDummy.new("bar") + + ar = [a, b].sort_by { |d| d.s } + ar.should == [b, a] + end +end diff --git a/1.8/core/enumerable/sort_spec.rb b/1.8/core/enumerable/sort_spec.rb new file mode 100644 index 0000000000..3d68a62ab3 --- /dev/null +++ b/1.8/core/enumerable/sort_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#sort" do + it "sorts by the natural order as defined by <=> " do + EnumerableSpecs::Numerous.new.sort.should == [1, 2, 3, 4, 5, 6] + sorted = EnumerableSpecs::ComparesByVowelCount.wrap("a" * 1, "a" * 2, "a"*3, "a"*4, "a"*5) + EnumerableSpecs::Numerous.new(sorted[2],sorted[0],sorted[1],sorted[3],sorted[4]).sort.should == sorted + end + + it "yields elements to the provided block" do + EnumerableSpecs::Numerous.new.sort { |a, b| b <=> a }.should == [6, 5, 4, 3, 2, 1] + EnumerableSpecs::Numerous.new(2,0,1,3,4).sort { |n, m| -(n <=> m) }.should == [4,3,2,1,0] + end + + it "sort should throw a NoMethodError if elements do not define <=>" do + lambda { + EnumerableSpecs::Numerous.new(Object.new, Object.new, Object.new).sort + }.should raise_error(NoMethodError) + end + + it "sorts enumerables that contain nils" do + arr = EnumerableSpecs::Numerous.new(nil, true, nil, false, nil, true, nil, false, nil) + arr.sort { |a, b| + x = a ? -1 : a.nil? ? 0 : 1 + y = b ? -1 : b.nil? ? 0 : 1 + x <=> y + }.should == [true, true, nil, nil, nil, nil, nil, false, false] + end +end + diff --git a/1.8/core/enumerable/to_a_spec.rb b/1.8/core/enumerable/to_a_spec.rb new file mode 100644 index 0000000000..1aff9a94a7 --- /dev/null +++ b/1.8/core/enumerable/to_a_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/entries' + +describe "Enumerable#to_a" do + it_behaves_like(:enumerable_entries , :to_a) +end diff --git a/1.8/core/enumerable/zip_spec.rb b/1.8/core/enumerable/zip_spec.rb new file mode 100644 index 0000000000..e5a731c282 --- /dev/null +++ b/1.8/core/enumerable/zip_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Enumerable#zip" do + + it "combines each element of the receiver with the element of the same index in arrays given as arguments" do + EnumerableSpecs::Numerous.new(1,2,3).zip([4,5,6],[7,8,9]).should == [[1,4,7],[2,5,8],[3,6,9]] + EnumerableSpecs::Numerous.new(1,2,3).zip.should == [[1],[2],[3]] + end + + it "passes each element of the result array to a block and return nil if a block is given" do + expected = [[1,4,7],[2,5,8],[3,6,9]] + EnumerableSpecs::Numerous.new(1,2,3).zip([4,5,6],[7,8,9]) do |result_component| + result_component.should == expected.shift + end.should == nil + expected.size.should == 0 + end + + it "fills resulting array with nils if an argument array is too short" do + EnumerableSpecs::Numerous.new(1,2,3).zip([4,5,6], [7,8]).should == [[1,4,7],[2,5,8],[3,6,nil]] + end + + it "converts arguments to arrays using #to_a" do + convertable = EnumerableSpecs::ArrayConvertable.new(4,5,6) + EnumerableSpecs::Numerous.new(1,2,3).zip(convertable).should == [[1,4],[2,5],[3,6]] + convertable.called.should == :to_a + end + +end + diff --git a/1.8/core/env/clear_spec.rb b/1.8/core/env/clear_spec.rb new file mode 100644 index 0000000000..4987540b3a --- /dev/null +++ b/1.8/core/env/clear_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "ENV#clear" do + + it "deletes all environment variables" do + orig = ENV.to_hash + begin + ENV.clear + EnvSpecs.get_env.should == {} + ensure + ENV.replace orig + end + end + +end diff --git a/1.8/core/env/delete_if_spec.rb b/1.8/core/env/delete_if_spec.rb new file mode 100644 index 0000000000..5b1821c411 --- /dev/null +++ b/1.8/core/env/delete_if_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#delete_if" do + + it "deletes pairs if the block returns true" do + ENV["foo"] = "bar" + ENV.delete_if { |k, v| k == "foo" } + ENV["foo"].should == nil + end + + it "returns ENV even if nothing deleted" do + ENV.delete_if { false }.should_not == nil + end + + it "raises LocalJumpError if no block given" do + lambda { ENV.delete_if }.should raise_error(LocalJumpError) + end + +end diff --git a/1.8/core/env/delete_spec.rb b/1.8/core/env/delete_spec.rb new file mode 100644 index 0000000000..2881980455 --- /dev/null +++ b/1.8/core/env/delete_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#delete" do + it "removes the variable and return its value" do + ENV["foo"] = "bar" + ENV.delete("foo").should == "bar" + ENV["foo"].should == nil + end +end diff --git a/1.8/core/env/each_key_spec.rb b/1.8/core/env/each_key_spec.rb new file mode 100644 index 0000000000..1db2345d3d --- /dev/null +++ b/1.8/core/env/each_key_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#each_key" do + + it "returns each key" do + e = [] + orig = ENV.to_hash + begin + ENV.clear + ENV["1"] = "3" + ENV["2"] = "4" + ENV.each_key { |k| e << k } + e.should include("1") + e.should include("2") + ensure + ENV.replace orig + end + end + + it "raises LocalJumpError if no block given" do + lambda { ENV.each_key }.should raise_error(LocalJumpError) + end + +end diff --git a/1.8/core/env/each_pair_spec.rb b/1.8/core/env/each_pair_spec.rb new file mode 100644 index 0000000000..77d0531b62 --- /dev/null +++ b/1.8/core/env/each_pair_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/each.rb' + +describe "ENV#each_pair" do + it_behaves_like(:env_each, :each_pair) +end diff --git a/1.8/core/env/each_spec.rb b/1.8/core/env/each_spec.rb new file mode 100644 index 0000000000..3e6a001bf0 --- /dev/null +++ b/1.8/core/env/each_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/each.rb' + +describe "ENV#each" do + it_behaves_like(:env_each, :each) +end diff --git a/1.8/core/env/each_value_spec.rb b/1.8/core/env/each_value_spec.rb new file mode 100644 index 0000000000..f34d073be4 --- /dev/null +++ b/1.8/core/env/each_value_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#each_value" do + + it "returns each value" do + e = [] + orig = ENV.to_hash + begin + ENV.clear + ENV["1"] = "3" + ENV["2"] = "4" + ENV.each_value { |v| e << v } + e.should include("3") + e.should include("4") + ensure + ENV.replace orig + end + end + + it "raises LocalJumpError if no block given" do + lambda { ENV.each_value }.should raise_error(LocalJumpError) + end + +end diff --git a/1.8/core/env/element_reference_spec.rb b/1.8/core/env/element_reference_spec.rb new file mode 100644 index 0000000000..5cf21899f7 --- /dev/null +++ b/1.8/core/env/element_reference_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "ENV#[]" do + it "returns the specified environment variable" do + ENV["USER"].should == EnvSpecs.get_current_user + end + + it "returns nil if the variable isn't found" do + ENV["this_var_is_never_set"].should == nil + end +end diff --git a/1.8/core/env/element_set_spec.rb b/1.8/core/env/element_set_spec.rb new file mode 100644 index 0000000000..6009a2e8e0 --- /dev/null +++ b/1.8/core/env/element_set_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/store.rb' + +describe "ENV#[]=" do + it_behaves_like(:env_store, :[]=) +end diff --git a/1.8/core/env/empty_spec.rb b/1.8/core/env/empty_spec.rb new file mode 100644 index 0000000000..4e71dbef59 --- /dev/null +++ b/1.8/core/env/empty_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#empty?" do + + it "return true if the Environment is empty" do + if ENV.keys.size > 0 + ENV.empty?.should == false + end + orig = ENV.to_hash + begin + ENV.clear + ENV.empty?.should == true + ensure + ENV.replace orig + end + end + + it "returns false if not empty" do + if ENV.keys.size > 0 + ENV.empty?.should == false + end + end +end diff --git a/1.8/core/env/fetch_spec.rb b/1.8/core/env/fetch_spec.rb new file mode 100644 index 0000000000..71c477c2e5 --- /dev/null +++ b/1.8/core/env/fetch_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#fetch" do + + it "returns a value" do + ENV["foo"] = "bar" + ENV.fetch("foo").should == "bar" + ENV.delete "foo" + end + + it "raises IndexError for an invalid key" do + lambda { ENV.fetch "should_never_be_set" }.should raise_error(IndexError) + end + + it "provides the given default parameter" do + ENV.fetch("should_never_be_set", "default").should == "default" + end + + it "provides a default value from a block" do + ENV.fetch("should_never_be_set") { |k| "wanted #{k}" }.should == "wanted should_never_be_set" + end + + it "warns on block and default parameter given" do + lambda do + ENV.fetch("should_never_be_set", "default") { 1 }.should == 1 + end.should complain(/block supersedes default value argument/) + end + +end diff --git a/1.8/core/env/fixtures/classes.rb b/1.8/core/env/fixtures/classes.rb new file mode 100644 index 0000000000..a79d05dc8d --- /dev/null +++ b/1.8/core/env/fixtures/classes.rb @@ -0,0 +1,17 @@ +module EnvSpecs + def self.get_env + env = "" + platform_is_not :windows do + env = Hash[*`env`.split("\n").map { |e| e.split("=", 2) }.flatten] + end + env + end + + def self.get_current_user + user = "" + platform_is_not :windows do + user = `whoami`.strip + end + user + end +end diff --git a/1.8/core/env/has_key_spec.rb b/1.8/core/env/has_key_spec.rb new file mode 100644 index 0000000000..6a6cc806c6 --- /dev/null +++ b/1.8/core/env/has_key_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include.rb' + +describe "ENV#has_key?" do + it_behaves_like(:env_include, :has_key?) +end diff --git a/1.8/core/env/has_value_spec.rb b/1.8/core/env/has_value_spec.rb new file mode 100644 index 0000000000..6102d4517e --- /dev/null +++ b/1.8/core/env/has_value_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/value.rb' + +describe "ENV#has_value?" do + it_behaves_like(:env_value, :has_value?) +end diff --git a/1.8/core/env/include_spec.rb b/1.8/core/env/include_spec.rb new file mode 100644 index 0000000000..8d71ed04c1 --- /dev/null +++ b/1.8/core/env/include_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include.rb' + +describe "ENV#include?" do + it_behaves_like(:env_include, :include?) +end diff --git a/1.8/core/env/index_spec.rb b/1.8/core/env/index_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/env/index_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/env/indexes_spec.rb b/1.8/core/env/indexes_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/env/indexes_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/env/indices_spec.rb b/1.8/core/env/indices_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/env/indices_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/env/inspect_spec.rb b/1.8/core/env/inspect_spec.rb new file mode 100644 index 0000000000..555ae7b4d5 --- /dev/null +++ b/1.8/core/env/inspect_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#inspect" do + + it "returns a String that looks like a Hash with real data" do + ENV["foo"] = "bar" + ENV.inspect.should =~ /\{.*"foo"=>"bar".*\}/ + ENV.delete "foo" + end + +end diff --git a/1.8/core/env/invert_spec.rb b/1.8/core/env/invert_spec.rb new file mode 100644 index 0000000000..fd8cc004d2 --- /dev/null +++ b/1.8/core/env/invert_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#invert" do + + it "returns a hash with ENV.keys as the values and vice versa" do + ENV["foo"] = "bar" + ENV.delete "bar" + ENV.invert["bar"].should == "foo" + ENV["foo"].should == "bar" + ENV["bar"].should == nil + end +end diff --git a/1.8/core/env/key_spec.rb b/1.8/core/env/key_spec.rb new file mode 100644 index 0000000000..34ec089eb4 --- /dev/null +++ b/1.8/core/env/key_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include.rb' + +describe "ENV#key?" do + it_behaves_like(:env_include, :key?) +end diff --git a/1.8/core/env/keys_spec.rb b/1.8/core/env/keys_spec.rb new file mode 100644 index 0000000000..876911e04c --- /dev/null +++ b/1.8/core/env/keys_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#keys" do + + it "returns all the keys" do + ENV.keys.sort.should == ENV.to_hash.keys.sort + end +end diff --git a/1.8/core/env/length_spec.rb b/1.8/core/env/length_spec.rb new file mode 100644 index 0000000000..246baf2b8e --- /dev/null +++ b/1.8/core/env/length_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/length.rb' + +describe "ENV#length" do + it_behaves_like(:env_length, :length) +end diff --git a/1.8/core/env/member_spec.rb b/1.8/core/env/member_spec.rb new file mode 100644 index 0000000000..35be14eb8b --- /dev/null +++ b/1.8/core/env/member_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include.rb' + +describe "ENV#member?" do + it_behaves_like(:env_include, :member?) +end diff --git a/1.8/core/env/rehash_spec.rb b/1.8/core/env/rehash_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/env/rehash_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/env/reject_spec.rb b/1.8/core/env/reject_spec.rb new file mode 100644 index 0000000000..1a3cc76c68 --- /dev/null +++ b/1.8/core/env/reject_spec.rb @@ -0,0 +1,72 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#reject!" do + it "rejects entries based on key" do + ENV["foo"] = "bar" + ENV.reject! { |k, v| k == "foo" } + ENV["foo"].should == nil + end + + it "rejects entries based on value" do + ENV["foo"] = "bar" + ENV.reject! { |k, v| v == "bar" } + ENV["foo"].should == nil + end + + it "returns itself or nil" do + ENV.reject! { false }.should == nil + ENV["foo"] = "bar" + ENV.reject! { |k, v| k == "foo" }.should == ENV + ENV["foo"].should == nil + end + + it "raises on no block given" do + lambda { ENV.reject! }.should raise_error(LocalJumpError) + end + + it "doesn't raise if empty" do + orig = ENV.to_hash + begin + ENV.clear + lambda { ENV.reject! }.should_not raise_error(LocalJumpError) + ensure + ENV.replace orig + end + end +end + +describe "ENV#reject" do + it "rejects entries based on key" do + ENV["foo"] = "bar" + e = ENV.reject { |k, v| k == "foo" } + e["foo"].should == nil + ENV["foo"].should == "bar" + ENV["foo"] = nil + end + + it "rejects entries based on value" do + ENV["foo"] = "bar" + e = ENV.reject { |k, v| v == "bar" } + e["foo"].should == nil + ENV["foo"].should == "bar" + ENV["foo"] = nil + end + + it "returns a Hash" do + ENV.reject { false }.class.should == Hash + end + + it "raises on no block given" do + lambda { ENV.reject }.should raise_error(LocalJumpError) + end + + it "doesn't raise if empty" do + orig = ENV.to_hash + begin + ENV.clear + lambda { ENV.reject }.should_not raise_error(LocalJumpError) + ensure + ENV.replace orig + end + end +end diff --git a/1.8/core/env/replace_spec.rb b/1.8/core/env/replace_spec.rb new file mode 100644 index 0000000000..a4ffdcd6da --- /dev/null +++ b/1.8/core/env/replace_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#replace" do + + it "replaces ENV with a Hash" do + ENV["foo"] = "bar" + e = ENV.reject { |k, v| k == "foo" } + e["baz"] = "bam" + ENV.replace e + ENV["foo"].should == nil + ENV["baz"].should == "bam" + ENV.delete "baz" + end + +end diff --git a/1.8/core/env/select_spec.rb b/1.8/core/env/select_spec.rb new file mode 100644 index 0000000000..3327076002 --- /dev/null +++ b/1.8/core/env/select_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#select" do + + it "returns the Hash for which block return true" do + ENV["foo"] = "bar" + ENV.select { |k, v| k == "foo" }.should == [["foo", "bar"]] + ENV.delete "foo" + end + + it "raises when no block is given" do + lambda { ENV.select }.should raise_error(LocalJumpError) + end +end diff --git a/1.8/core/env/shared/each.rb b/1.8/core/env/shared/each.rb new file mode 100644 index 0000000000..0e13bd14f4 --- /dev/null +++ b/1.8/core/env/shared/each.rb @@ -0,0 +1,24 @@ +shared :env_each do |cmd| + describe "ENV##{cmd}" do + + it "returns each pair" do + orig = ENV.to_hash + e = [] + begin + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "boo" + ENV.send(cmd) { |k, v| e << [k, v] } + e.should include(["foo", "bar"]) + e.should include(["baz", "boo"]) + ensure + ENV.replace orig + end + end + + it "raises LocalJumpError if no block given" do + lambda { ENV.each_key }.should raise_error(LocalJumpError) + end + + end +end diff --git a/1.8/core/env/shared/include.rb b/1.8/core/env/shared/include.rb new file mode 100644 index 0000000000..142a4402b5 --- /dev/null +++ b/1.8/core/env/shared/include.rb @@ -0,0 +1,15 @@ +shared :env_include do |cmd| + describe "ENV##{cmd}" do + + it "returns true if ENV has the key" do + ENV["foo"] = "bar" + ENV.send(cmd, "foo").should == true + ENV.delete "foo" + end + + it "return false if ENV doesn't include the key" do + ENV.send(cmd, "should_never_be_set").should == false + end + + end +end diff --git a/1.8/core/env/shared/length.rb b/1.8/core/env/shared/length.rb new file mode 100644 index 0000000000..0f2a76e218 --- /dev/null +++ b/1.8/core/env/shared/length.rb @@ -0,0 +1,15 @@ +shared :env_length do |cmd| + describe "ENV##{cmd}" do + it "returns the number of ENV entries" do + orig = ENV.to_hash + begin + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "boo" + ENV.send(cmd).should == 2 + ensure + ENV.replace orig + end + end + end +end diff --git a/1.8/core/env/shared/store.rb b/1.8/core/env/shared/store.rb new file mode 100644 index 0000000000..4a9b7eaa1d --- /dev/null +++ b/1.8/core/env/shared/store.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../fixtures/classes' + +shared :env_store do |cmd| + describe "ENV##{cmd}" do + it "sets the environment variable to the given value" do + ENV["foo"] = "bar" + EnvSpecs.get_env.key?("foo").should == true + EnvSpecs.get_env.value?("bar").should == true + ENV.delete "foo" + ENV["foo"].should == nil + ENV.store "foo", "bar" + EnvSpecs.get_env.key?("foo").should == true + EnvSpecs.get_env.value?("bar").should == true + ENV.delete "foo" + end + end +end diff --git a/1.8/core/env/shared/value.rb b/1.8/core/env/shared/value.rb new file mode 100644 index 0000000000..36c5926a8f --- /dev/null +++ b/1.8/core/env/shared/value.rb @@ -0,0 +1,15 @@ +shared :env_value do |cmd| + describe "ENV##{cmd}" do + + it "returns true if ENV has the value" do + ENV["foo"] = "bar" + ENV.has_value?("bar").should == true + ENV["foo"] = nil + end + + it "returns false if ENV doesn't have the value" do + ENV.has_value?("this_value_should_never_exist").should == false + end + + end +end diff --git a/1.8/core/env/shift_spec.rb b/1.8/core/env/shift_spec.rb new file mode 100644 index 0000000000..91c44434b4 --- /dev/null +++ b/1.8/core/env/shift_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#shift" do + + it "returns a pair and deletes it" do + ENV.empty?.should == false + orig = ENV.to_hash + begin + pair = ENV.shift + ENV.has_key?(pair.first).should == false + ensure + ENV.replace orig + end + ENV.has_key?(pair.first).should == true + end + + it "returns nil if ENV.empty?" do + orig = ENV.to_hash + begin + ENV.clear + ENV.shift.should == nil + ensure + ENV.replace orig + end + end + +end diff --git a/1.8/core/env/size_spec.rb b/1.8/core/env/size_spec.rb new file mode 100644 index 0000000000..f96a4b4e1f --- /dev/null +++ b/1.8/core/env/size_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/length.rb' + +describe "ENV#size" do + it_behaves_like(:env_length, :size) +end diff --git a/1.8/core/env/store_spec.rb b/1.8/core/env/store_spec.rb new file mode 100644 index 0000000000..a849172a5d --- /dev/null +++ b/1.8/core/env/store_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/store.rb' + +describe "ENV#store" do + it_behaves_like(:env_store, :store) +end diff --git a/1.8/core/env/to_a_spec.rb b/1.8/core/env/to_a_spec.rb new file mode 100644 index 0000000000..733a77e0bd --- /dev/null +++ b/1.8/core/env/to_a_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#to_a" do + + it "returns the ENV as an array" do + ENV["foo"] = "bar" + a = ENV.to_a + a.is_a?(Array).should == true + a.find { |e| e.first == "foo" }.should == ["foo", "bar"] + ENV.delete "foo" + end +end diff --git a/1.8/core/env/to_hash_spec.rb b/1.8/core/env/to_hash_spec.rb new file mode 100644 index 0000000000..a7bb15b1e4 --- /dev/null +++ b/1.8/core/env/to_hash_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#to_hash" do + + it "returns the ENV as a hash" do + ENV["foo"] = "bar" + h = ENV.to_hash + h.is_a?(Hash).should == true + h["foo"].should == "bar" + ENV.delete "foo" + end +end diff --git a/1.8/core/env/to_s_spec.rb b/1.8/core/env/to_s_spec.rb new file mode 100644 index 0000000000..869d24712c --- /dev/null +++ b/1.8/core/env/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#to_s" do + it "returns \"ENV\"" do + ENV.to_s.should == "ENV" + end +end diff --git a/1.8/core/env/update_spec.rb b/1.8/core/env/update_spec.rb new file mode 100644 index 0000000000..23695c579b --- /dev/null +++ b/1.8/core/env/update_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#update" do + + it "add the parameter hash to ENV" do + ENV["foo"].should == nil + ENV.update "foo" => "bar" + ENV["foo"].should == "bar" + ENV.delete "foo" + end + + it "yields key, the old value and the new value when replacing entries" do + ENV.update "foo" => "bar" + ENV["foo"].should == "bar" + ENV.update("foo" => "boo") do |key, old, new| + key.should == "foo" + old.should == "bar" + new.should == "boo" + "rab" + end + ENV["foo"].should == "rab" + ENV.delete "foo" + end + +end diff --git a/1.8/core/env/value_spec.rb b/1.8/core/env/value_spec.rb new file mode 100644 index 0000000000..6db69a5d91 --- /dev/null +++ b/1.8/core/env/value_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/value.rb' + +describe "ENV#value?" do + it_behaves_like(:env_value, :value?) +end diff --git a/1.8/core/env/values_at_spec.rb b/1.8/core/env/values_at_spec.rb new file mode 100644 index 0000000000..d472832a1c --- /dev/null +++ b/1.8/core/env/values_at_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#values_at" do + + it "returns an array of the values referenced by the parameters as keys" do + ENV["foo"] = "oof" + ENV["bar"] = "rab" + ENV.values_at.should == [] + ENV.values_at("bar", "foo").should == ["rab", "oof"] + ENV.delete "foo" + ENV.delete "bar" + end +end diff --git a/1.8/core/env/values_spec.rb b/1.8/core/env/values_spec.rb new file mode 100644 index 0000000000..d187d17c3e --- /dev/null +++ b/1.8/core/env/values_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ENV#values" do + + it "returns an array of the values" do + orig = ENV.to_hash + begin + ENV.replace "a" => "b", "c" => "d" + a = ENV.values + a.sort.should == ["b", "d"] + ensure + ENV.replace orig + end + end +end diff --git a/1.8/core/exception/arguments_spec.rb b/1.8/core/exception/arguments_spec.rb new file mode 100644 index 0000000000..ded3b14198 --- /dev/null +++ b/1.8/core/exception/arguments_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ArgumentError" do + + it "is a subclass of StandardError" do + ArgumentError.class.superclass == StandardError + end + +end diff --git a/1.8/core/exception/backtrace_spec.rb b/1.8/core/exception/backtrace_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/backtrace_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/exception/case_compare_spec.rb b/1.8/core/exception/case_compare_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/case_compare_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/exception/errno_spec.rb b/1.8/core/exception/errno_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/errno_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/exception/exception_spec.rb b/1.8/core/exception/exception_spec.rb new file mode 100644 index 0000000000..5b97507855 --- /dev/null +++ b/1.8/core/exception/exception_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/new' + +describe "Exception.exception" do + it_behaves_like(:exception_new, :exception) +end + +describe "Exception" do + it "is a Class" do + Exception.is_a?(Class) + end + + it "is a superclass of NoMemoryError" do + Exception.should be_ancestor_of(NoMemoryError) + end + + it "is a superclass of ScriptError" do + Exception.should be_ancestor_of(ScriptError) + end + + it "is a superclass of SignalException" do + Exception.should be_ancestor_of(SignalException) + end + + it "is a superclass of Interrupt" do + SignalException.should be_ancestor_of(Interrupt) + end + + it "is a superclass of StandardError" do + Exception.should be_ancestor_of(StandardError) + end + + it "is a superclass of SystemExit" do + Exception.should be_ancestor_of(SystemExit) + end + + it "is a superclass of SystemStackError" do + Exception.should be_ancestor_of(SystemStackError) + end +end diff --git a/1.8/core/exception/exit_value_spec.rb b/1.8/core/exception/exit_value_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/exit_value_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/exception/fixtures/common.rb b/1.8/core/exception/fixtures/common.rb new file mode 100644 index 0000000000..b056acfb14 --- /dev/null +++ b/1.8/core/exception/fixtures/common.rb @@ -0,0 +1,14 @@ +module NoMethodErrorSpecs + class NoMethodErrorA; end + + class NoMethodErrorB; end + + class NoMethodErrorC; + protected + def a_protected_method;end + private + def a_private_method; end + end + + class NoMethodErrorD; end +end diff --git a/1.8/core/exception/initialize_spec.rb b/1.8/core/exception/initialize_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/initialize_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/exception/inspect_spec.rb b/1.8/core/exception/inspect_spec.rb new file mode 100644 index 0000000000..f4ddc1615a --- /dev/null +++ b/1.8/core/exception/inspect_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Exception#inspect" do + it "returns '#' when no message given" do + Exception.new.inspect.should == "#" + end + + it "includes message when given" do + [Exception.new("foobar").inspect].should == ["#"] + end +end diff --git a/1.8/core/exception/io_error_spec.rb b/1.8/core/exception/io_error_spec.rb new file mode 100644 index 0000000000..6f5673f0a7 --- /dev/null +++ b/1.8/core/exception/io_error_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IOError" do + it "is a superclass of EOFError" do + IOError.should be_ancestor_of(EOFError) + end +end diff --git a/1.8/core/exception/message_spec.rb b/1.8/core/exception/message_spec.rb new file mode 100644 index 0000000000..d57b721bce --- /dev/null +++ b/1.8/core/exception/message_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Exception#message" do + it "returns the exception message" do + [Exception.new.message, Exception.new("Ouch!").message].should == ["Exception", "Ouch!"] + end +end diff --git a/1.8/core/exception/name_error_spec.rb b/1.8/core/exception/name_error_spec.rb new file mode 100644 index 0000000000..2934f7f0f0 --- /dev/null +++ b/1.8/core/exception/name_error_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NameError" do + it "is a superclass of NoMethodError" do + NameError.should be_ancestor_of(NoMethodError) + end +end + +describe "NameError.new" do + it "NameError.new should take optional name argument" do + NameError.new("msg","name").name.should == "name" + end +end diff --git a/1.8/core/exception/name_spec.rb b/1.8/core/exception/name_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/name_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/exception/new_spec.rb b/1.8/core/exception/new_spec.rb new file mode 100644 index 0000000000..e3f610a132 --- /dev/null +++ b/1.8/core/exception/new_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/new' + +describe "Exception.new" do + it_behaves_like(:exception_new, :new) +end diff --git a/1.8/core/exception/no_method_error_spec.rb b/1.8/core/exception/no_method_error_spec.rb new file mode 100644 index 0000000000..4f7c3eff53 --- /dev/null +++ b/1.8/core/exception/no_method_error_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "NoMethodError.new" do + it "allows passing method args" do + NoMethodError.new("msg","name","args").args.should == "args" + end +end + +describe "NoMethodError#args" do + it "returns an empty array if the caller method had no arguments" do + begin + NoMethodErrorSpecs::NoMethodErrorB.new.foo + rescue Exception => e + e.args.should == [] + end + end + + it "returns an array with the same elements as passed to the method" do + begin + a = NoMethodErrorSpecs::NoMethodErrorA.new + NoMethodErrorSpecs::NoMethodErrorB.new.foo(1,a) + rescue Exception => e + e.args.should == [1,a] + e.args[1].object_id.should == a.object_id + end + end +end + +describe "NoMethodError#message" do + it "for an undefined method match /undefined method/" do + begin + NoMethodErrorSpecs::NoMethodErrorD.new.foo + rescue Exception => e + e.class.should == NoMethodError + end + end + + it "for an protected method match /protected method/" do + begin + NoMethodErrorSpecs::NoMethodErrorC.new.a_protected_method + rescue Exception => e + e.class.should == NoMethodError + end + end + + not_compliant_on :rubinius do + it "for private method match /private method/" do + begin + NoMethodErrorSpecs::NoMethodErrorC.new.a_private_method + rescue Exception => e + e.class.should == NoMethodError + e.message.match(/private method/).should_not == nil + end + end + end +end diff --git a/1.8/core/exception/range_error_spec.rb b/1.8/core/exception/range_error_spec.rb new file mode 100644 index 0000000000..c841b9c0a9 --- /dev/null +++ b/1.8/core/exception/range_error_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "RangeError" do + it "is a superclass of FloatDomainError" do + RangeError.should be_ancestor_of(FloatDomainError) + end +end diff --git a/1.8/core/exception/script_error_spec.rb b/1.8/core/exception/script_error_spec.rb new file mode 100644 index 0000000000..55e4dcff77 --- /dev/null +++ b/1.8/core/exception/script_error_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ScriptError" do + # it "is a superclass of LoadError" do + # ScriptError.should be_ancestor_of(LoadError) + # end + # + # it "is a superclass of NotImplementedError" do + # ScriptError.should be_ancestor_of(NotImplementedError) + # end + # + # it "is a superclass of SyntaxError" do + # ScriptError.should be_ancestor_of(SyntaxError) + # end +end diff --git a/1.8/core/exception/set_backtrace_spec.rb b/1.8/core/exception/set_backtrace_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/set_backtrace_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/exception/shared/new.rb b/1.8/core/exception/shared/new.rb new file mode 100644 index 0000000000..eb60ca281b --- /dev/null +++ b/1.8/core/exception/shared/new.rb @@ -0,0 +1,15 @@ +shared :exception_new do |cmd| + describe "Exception.#{cmd}" do + it "creates a new instance of Exception" do + Exception.should be_ancestor_of(Exception.send(cmd).class) + end + + it "sets the message of the Exception when passes a message" do + Exception.send(cmd, "I'm broken.").message.should == "I'm broken." + end + + it "returns 'Exception' for message when no message given" do + Exception.send(cmd).message.should == "Exception" + end + end +end diff --git a/1.8/core/exception/standard_error_spec.rb b/1.8/core/exception/standard_error_spec.rb new file mode 100644 index 0000000000..587a7136c6 --- /dev/null +++ b/1.8/core/exception/standard_error_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "StandardError" do + it "is a superclass of ArgumentError" do + StandardError.should be_ancestor_of(ArgumentError) + end + + it "is a superclass of IOError" do + StandardError.should be_ancestor_of(IOError) + end + + it "is a superclass of IndexError" do + StandardError.should be_ancestor_of(IndexError) + end + + it "is a superclass of LocalJumpError" do + StandardError.should be_ancestor_of(LocalJumpError) + end + + it "is a superclass of NameError" do + StandardError.should be_ancestor_of(NameError) + end + + it "is a superclass of RangeError" do + StandardError.should be_ancestor_of(RangeError) + end + + it "is a superclass of RegexpError" do + StandardError.should be_ancestor_of(RegexpError) + end + + it "is a superclass of RuntimeError" do + StandardError.should be_ancestor_of(RuntimeError) + end + + it "is a superclass of SecurityError" do + StandardError.should be_ancestor_of(SecurityError) + end + + it "is a superclass of SystemCallError" do + StandardError.should be_ancestor_of(SystemCallError.new("").class) + end + it "is a superclass of ThreadError" do + StandardError.should be_ancestor_of(ThreadError) + end + + it "is a superclass of TypeError" do + StandardError.should be_ancestor_of(TypeError) + end + + it "is a superclass of ZeroDivisionError" do + StandardError.should be_ancestor_of(ZeroDivisionError) + end +end diff --git a/1.8/core/exception/system_call_error_spec.rb b/1.8/core/exception/system_call_error_spec.rb new file mode 100644 index 0000000000..f457695b40 --- /dev/null +++ b/1.8/core/exception/system_call_error_spec.rb @@ -0,0 +1,45 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "SystemCallError.new" do + it "requires at least one argumentt" do + lambda { SystemCallError.new }.should raise_error(ArgumentError) + end + + it "takes an optional errno argument" do + SystemCallError.should be_ancestor_of(SystemCallError.new("message",1).class) + end + + it "accepts single Fixnum argument as errno" do + SystemCallError.new(-2**24).errno.should == -2**24 + SystemCallError.new(42).errno.should == 42 + SystemCallError.new(2**24).errno.should == 2**24 + end +end + +describe "SystemCallError#errno" do + it "returns nil when no errno given" do + SystemCallError.new("message").errno.should == nil + end + + it "returns the errno given as optional argument to new" do + SystemCallError.new("message", -2**30).errno.should == -2**30 + SystemCallError.new("message", -1).errno.should == -1 + SystemCallError.new("message", 0).errno.should == 0 + SystemCallError.new("message", 1).errno.should == 1 + SystemCallError.new("message", 42).errno.should == 42 + SystemCallError.new("message", 2**30).errno.should == 2**30 + end +end + +describe "SystemCallError#message" do + it "should return default message when no message given" do + SystemCallError.new(2**28).message.should =~ /Unknown error/ + end + + it "returns the message given as an argument to new" do + SystemCallError.new("message", 1).message.should =~ /message/ + SystemCallError.new("XXX").message.should =~ /XXX/ + end +end + + diff --git a/1.8/core/exception/to_s_spec.rb b/1.8/core/exception/to_s_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/to_s_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/exception/to_str_spec.rb b/1.8/core/exception/to_str_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/exception/to_str_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/false/and_spec.rb b/1.8/core/false/and_spec.rb new file mode 100644 index 0000000000..eb6a196a91 --- /dev/null +++ b/1.8/core/false/and_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "FalseClass#&" do + it "returns false" do + (false & false).should == false + (false & true).should == false + (false & nil).should == false + (false & "").should == false + (false & mock('x')).should == false + end +end diff --git a/1.8/core/false/inspect_spec.rb b/1.8/core/false/inspect_spec.rb new file mode 100644 index 0000000000..718b144077 --- /dev/null +++ b/1.8/core/false/inspect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "FalseClass#inspect" do + it "returns the string 'false'" do + false.inspect.should == "false" + end +end diff --git a/1.8/core/false/or_spec.rb b/1.8/core/false/or_spec.rb new file mode 100644 index 0000000000..24b898d573 --- /dev/null +++ b/1.8/core/false/or_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "FalseClass#|" do + it "return false if other is nil or false, otherwise true" do + (false | false).should == false + (false | true).should == true + (false | nil).should == false + (false | "").should == true + (false | mock('x')).should == true + end +end diff --git a/1.8/core/false/to_s_spec.rb b/1.8/core/false/to_s_spec.rb new file mode 100644 index 0000000000..0dcd71fde4 --- /dev/null +++ b/1.8/core/false/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "FalseClass#to_s" do + it "returns the string 'false'" do + false.to_s.should == "false" + end +end diff --git a/1.8/core/false/xor_spec.rb b/1.8/core/false/xor_spec.rb new file mode 100644 index 0000000000..6facdf7ad5 --- /dev/null +++ b/1.8/core/false/xor_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "FalseClass#^" do + it "returns false if other is nil or false, otherwise true" do + (false ^ false).should == false + (false ^ true).should == true + (false ^ nil).should == false + (false ^ "").should == true + (false ^ mock('x')).should == true + end +end diff --git a/1.8/core/file/atime_spec.rb b/1.8/core/file/atime_spec.rb new file mode 100644 index 0000000000..cb946cb0e9 --- /dev/null +++ b/1.8/core/file/atime_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.atime" do + before :each do + @file = File.join('test.txt') + File.open(@file, "w") {} # touch + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "returns the last access time for the named file as a Time object" do + File.atime(@file) + File.atime(@file).should be_kind_of(Time) + end + + it "raises an Errno::ENOENT exception if the file is not found" do + lambda { File.atime('a_fake_file') }.should raise_error(Errno::ENOENT) + end +end + +describe "File#atime" do + before :each do + @name = File.expand_path(__FILE__) + @file = File.open(@name) + end + + after :each do + @file.close rescue nil + end + + it "returns the last access time to self" do + @file.atime + @file.atime.should be_kind_of(Time) + end +end diff --git a/1.8/core/file/basename_spec.rb b/1.8/core/file/basename_spec.rb new file mode 100644 index 0000000000..54cb53d9cc --- /dev/null +++ b/1.8/core/file/basename_spec.rb @@ -0,0 +1,144 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.basename" do + before :each do + @name = "test.txt" + File.delete(@name) if File.exist? @name + @file = File.open(@name,"w+") + end + + after :each do + @file.close + File.delete(@name) if File.exist?(@name) + end + + it "return the basename of a path (basic cases)" do + File.basename(@name).should == "test.txt" + File.basename(File.join("/tmp")).should == "tmp" + File.basename(File.join(*%w( g f d s a b))).should == "b" + File.basename("/tmp", ".*").should == "tmp" + File.basename("/tmp", ".c").should == "tmp" + File.basename("/tmp.c", ".c").should == "tmp" + File.basename("/tmp.c", ".*").should == "tmp" + File.basename("/tmp.c", ".?").should == "tmp.c" + File.basename("/tmp.cpp", ".*").should == "tmp" + File.basename("/tmp.cpp", ".???").should == "tmp.cpp" + File.basename("/tmp.o", ".c").should == "tmp.o" + #Version.greater_or_equal("1.8.0") do + File.basename(File.join("/tmp/")).should == "tmp" + File.basename("/").should == "/" + File.basename("//").should == "/" + File.basename("dir///base", ".*").should == "base" + File.basename("dir///base", ".c").should == "base" + File.basename("dir///base.c", ".c").should == "base" + File.basename("dir///base.c", ".*").should == "base" + File.basename("dir///base.o", ".c").should == "base.o" + File.basename("dir///base///").should == "base" + File.basename("dir//base/", ".*").should == "base" + File.basename("dir//base/", ".c").should == "base" + File.basename("dir//base.c/", ".c").should == "base" + File.basename("dir//base.c/", ".*").should == "base" + #end + end + + it "return the last component of the filename" do + File.basename('a').should == 'a' + File.basename('/a').should == 'a' + File.basename('/a/b').should == 'b' + File.basename('/ab/ba/bag').should == 'bag' + File.basename('/ab/ba/bag.txt').should == 'bag.txt' + File.basename('/').should == '/' + File.basename('/foo/bar/baz.rb', '.rb').should == 'baz' + File.basename('baz.rb', 'z.rb').should == 'ba' + end + + it "return an string" do + File.basename("foo").class.should == String + end + + it "return the basename for unix format" do + File.basename("/foo/bar").should == "bar" + File.basename("/foo/bar.txt").should == "bar.txt" + File.basename("bar.c").should == "bar.c" + File.basename("/bar").should == "bar" + File.basename("/bar/").should == "bar" + + # Considered UNC paths on Windows + platform_is :windows do + File.basename("baz//foo").should =="foo" + File.basename("//foo/bar/baz").should == "baz" + end + end + + it "return the basename for edge cases" do + File.basename("").should == "" + File.basename(".").should == "." + File.basename("..").should == ".." + File.basename("//foo/").should == "foo" + File.basename("//foo//").should == "foo" + File.basename("foo/").should == "foo" + end + + it "return the basename for unix suffix" do + File.basename("bar.c", ".c").should == "bar" + File.basename("bar.txt", ".txt").should == "bar" + File.basename("/bar.txt", ".txt").should == "bar" + File.basename("/foo/bar.txt", ".txt").should == "bar" + File.basename("bar.txt", ".exe").should == "bar.txt" + File.basename("bar.txt.exe", ".exe").should == "bar.txt" + File.basename("bar.txt.exe", ".txt").should == "bar.txt.exe" + File.basename("bar.txt", ".*").should == "bar" + File.basename("bar.txt.exe", ".*").should == "bar.txt" + File.basename("bar.txt.exe", ".txt.exe").should == "bar" + deviates_on :rbx do + File.basename("bar.txt.exe", ".txt.*").should == "bar" + end + end + + it "raises a TypeError if the arguments are not String types" do + lambda { File.basename(nil) }.should raise_error(TypeError) + lambda { File.basename(1) }.should raise_error(TypeError) + lambda { File.basename("bar.txt", 1) }.should raise_error(TypeError) + lambda { File.basename(true) }.should raise_error(TypeError) + end + + it "raises an ArgumentError if passed more than two arguments" do + lambda { File.basename('bar.txt', '.txt', '.txt') }.should raise_error(ArgumentError) + end + + # specific to MS Windows + platform_is :windows do + it "return the basename for windows" do + File.basename("C:\\foo\\bar\\baz.txt").should == "baz.txt" + File.basename("C:\\foo\\bar").should == "baz" + File.basename("C:\\foo\\bar\\").should == "baz" + File.basename("C:\\foo").should == "foo" + File.basename("C:\\").should == "C:\\" + end + + it "return basename windows unc" do + File.basename("\\\\foo\\bar\\baz.txt").should == "baz.txt" + File.basename("\\\\foo\\bar\\baz").should =="baz" + File.basename("\\\\foo").should == "\\\\foo" + File.basename("\\\\foo\\bar").should == "\\\\foo\\bar" + end + + it "return basename windows forward slash" do + File.basename("C:/").should == "C:/" + File.basename("C:/foo").should == "foo" + File.basename("C:/foo/bar").should == "bar" + File.basename("C:/foo/bar/").should "bar" + File.basename("C:/foo/bar//").shouldl == "bar" + end + + it "return basename with windows suffix" do + File.basename("c:\\bar.txt", ".txt").should == "bar" + File.basename("c:\\foo\\bar.txt", ".txt").should == "bar" + File.basename("c:\\bar.txt", ".exe").should == "bar.txt" + File.basename("c:\\bar.txt.exe", ".exe").should == "bar.txt" + File.basename("c:\\bar.txt.exe", ".txt").should == "bar.txt.exe" + File.basename("c:\\bar.txt", ".*").should == "bar" + File.basename("c:\\bar.txt.exe", ".*").should == "bar.txt" + end + end +end diff --git a/1.8/core/file/blockdev_spec.rb b/1.8/core/file/blockdev_spec.rb new file mode 100644 index 0000000000..b53a0b4dfd --- /dev/null +++ b/1.8/core/file/blockdev_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/blockdev' + +describe "File.blockdev?" do + it_behaves_like :file_blockdev, :blockdev?, File +end diff --git a/1.8/core/file/chardev_spec.rb b/1.8/core/file/chardev_spec.rb new file mode 100644 index 0000000000..03fe39749e --- /dev/null +++ b/1.8/core/file/chardev_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/chardev' + +describe "File.chardev?" do + it_behaves_like :file_chardev, :chardev?, File +end diff --git a/1.8/core/file/chmod_spec.rb b/1.8/core/file/chmod_spec.rb new file mode 100644 index 0000000000..3032579c3b --- /dev/null +++ b/1.8/core/file/chmod_spec.rb @@ -0,0 +1,143 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File#chmod" do + before :each do + @filename = File.dirname(__FILE__) + '/fixtures/i_exist' + @file = File.open(@filename, 'w') + end + + after :each do + @file.close + File.delete(@filename) if File.exist?(@filename) + end + + it "returns 0 if successful" do + @file.chmod(0755).should == 0 + end + + it "always succeeds with any numeric values" do + vals = [-2**30, -2**16, -2**8, -2, -1, + -0.5, 0, 1, 2, 5.555575, 16, 32, 64, 2**8, 2**16, 2**30] + vals.each { |v| + lambda { @file.chmod(v) }.should_not raise_error + } + end + + it "invokes to_int on non-integer argument" do + mode = File.stat(@filename).mode + (obj = mock('mode')).should_receive(:to_int).and_return(mode) + @file.chmod(obj) + File.stat(@filename).mode.should == mode + end + + it "with '0222' makes file writable but not readable or executable" do + @file.chmod(0222) + File.readable?(@filename).should == false + File.writable?(@filename).should == true + File.executable?(@filename).should == false + end + + it "with '0444' makes file readable but not writable or executable" do + @file.chmod(0444) + File.readable?(@filename).should == true + File.writable?(@filename).should == false + File.executable?(@filename).should == false + end + + it "with '0666' makes file readable and writable but not executable" do + @file.chmod(0666) + File.readable?(@filename).should == true + File.writable?(@filename).should == true + File.executable?(@filename).should == false + end + + it "with '0111' makes file executable but not readable or writable" do + @file.chmod(0111) + File.readable?(@filename).should == false + File.writable?(@filename).should == false + File.executable?(@filename).should == true + end + + platform_is_not :windows do + it "modifies the permission bits of the files specified" do + @file.chmod(0755) + File.stat(@filename).mode.should == 33261 + end + end +end + +describe "File.chmod" do + before :each do + @file = File.dirname(__FILE__) + '/fixtures/i_exist' + File.open(@file, 'w') {} + @count = File.chmod(0755, @file) + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "returns the number of files modified" do + @count.should == 1 + end + + it "always succeeds with any numeric values" do + vals = [-2**30, -2**16, -2**8, -2, -1, + -0.5, 0, 1, 2, 5.555575, 16, 32, 64, 2**8, 2**16, 2**30] + vals.each { |v| + lambda { File.chmod(v, @file) }.should_not raise_error + } + end + + it "throws a TypeError if the given path is not coercable into a string" do + lambda { File.chmod(0, @file.to_sym) }.should raise_error(TypeError) + end + + it "invokes to_int on non-integer argument" do + mode = File.stat(@file).mode + (obj = mock('mode')).should_receive(:to_int).and_return(mode) + File.chmod(obj, @file) + File.stat(@file).mode.should == mode + end + + it "invokes to_str on non-string file names" do + mode = File.stat(@file).mode + (obj = mock('path')).should_receive(:to_str).and_return(@file) + File.chmod(mode, obj) + File.stat(@file).mode.should == mode + end + + it "with '0222' makes file writable but not readable or executable" do + File.chmod(0222, @file) + File.readable?(@file).should == false + File.writable?(@file).should == true + File.executable?(@file).should == false + end + + it "with '0444' makes file readable but not writable or executable" do + File.chmod(0444, @file) + File.readable?(@file).should == true + File.writable?(@file).should == false + File.executable?(@file).should == false + end + + it "with '0666' makes file readable and writable but not executable" do + File.chmod(0666, @file) + File.readable?(@file).should == true + File.writable?(@file).should == true + File.executable?(@file).should == false + end + + it "with '0111' makes file executable but not readable or writable" do + File.chmod(0111, @file) + File.readable?(@file).should == false + File.writable?(@file).should == false + File.executable?(@file).should == true + end + + platform_is_not :windows do + it "modifies the permission bits of the files specified" do + File.stat(@file).mode.should == 33261 + end + end +end diff --git a/1.8/core/file/chown_spec.rb b/1.8/core/file/chown_spec.rb new file mode 100644 index 0000000000..7bef73a6b0 --- /dev/null +++ b/1.8/core/file/chown_spec.rb @@ -0,0 +1,94 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +as_superuser do + describe "File.chown" do + before :each do + @fname = '/tmp/file_chown_test' + File.open(@fname, 'w') { } + end + + after :each do + File.delete @fname if File.exist? @fname + end + + it "changes the owner id of the file" do + File.chown 501, nil, @fname + File.stat(@fname).uid.should == 501 + File.chown 0, nil, @fname + File.stat(@fname).uid.should == 0 + end + + it "changes the group id of the file" do + File.chown nil, 501, @fname + File.stat(@fname).gid.should == 501 + File.chown nil, 0, @fname + File.stat(@fname).uid.should == 0 + end + + it "does not modify the owner id of the file if passed nil or -1" do + File.chown 501, nil, @fname + File.chown nil, nil, @fname + File.stat(@fname).uid.should == 501 + File.chown nil, -1, @fname + File.stat(@fname).uid.should == 501 + end + + it "does not modify the group id of the file if passed nil or -1" do + File.chown nil, 501, @fname + File.chown nil, nil, @fname + File.stat(@fname).gid.should == 501 + File.chown nil, -1, @fname + File.stat(@fname).gid.should == 501 + end + + it "returns the number of files processed" do + File.chown(nil, nil, @fname, @fname).should == 2 + end + end + + describe "File#chown" do + before :each do + @fname = '/tmp/file_chown_test' + @file = File.open(@fname, 'w') + end + + after :each do + @file.close unless @file.closed? + File.delete @fname if File.exist? @fname + end + + it "changes the owner id of the file" do + @file.chown 501, nil + @file.stat.uid.should == 501 + @file.chown 0, nil + @file.stat.uid.should == 0 + end + + it "changes the group id of the file" do + @file.chown nil, 501 + @file.stat.gid.should == 501 + @file.chown nil, 0 + @file.stat.uid.should == 0 + end + + it "does not modify the owner id of the file if passed nil or -1" do + @file.chown 501, nil + @file.chown nil, nil + @file.stat.uid.should == 501 + @file.chown nil, -1 + @file.stat.uid.should == 501 + end + + it "does not modify the group id of the file if passed nil or -1" do + @file.chown nil, 501 + @file.chown nil, nil + @file.stat.gid.should == 501 + @file.chown nil, -1 + @file.stat.gid.should == 501 + end + + it "returns 0" do + @file.chown(nil, nil).should == 0 + end + end +end diff --git a/1.8/core/file/constants_spec.rb b/1.8/core/file/constants_spec.rb new file mode 100644 index 0000000000..dd028d1d87 --- /dev/null +++ b/1.8/core/file/constants_spec.rb @@ -0,0 +1,139 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File::Constants" do + it "match mode constants" do + File::FNM_NOESCAPE.should_not == nil + File::FNM_PATHNAME.should_not == nil + File::FNM_DOTMATCH.should_not == nil + File::FNM_CASEFOLD.should_not == nil + File::FNM_SYSCASE.should_not == nil + + platform_is :windows do #|| VMS + File::FNM_SYSCASE.should == 8 + end + end + + # Only these constants are not inherited from the IO class + it "the separator constant" do + File::SEPARATOR.should_not == nil + File::Separator.should_not == nil + File::PATH_SEPARATOR.should_not == nil + File::SEPARATOR.should == "/" + + platform_is :windows do #|| VMS + File::ALT_SEPARATOR.should_not == nil + File::PATH_SEPARATOR.should == ";" + end + + platform_is_not :windows do + File::ALT_SEPARATOR.should == nil + File::PATH_SEPARATOR.should == ":" + end + end + + it "the open mode constants" do + File::APPEND.should_not == nil + File::CREAT.should_not == nil + File::EXCL.should_not == nil + File::NONBLOCK.should_not == nil + File::RDONLY.should_not == nil + File::RDWR.should_not == nil + File::TRUNC.should_not == nil + File::WRONLY.should_not == nil + + platform_is_not :windows do # Not sure about VMS here + File::NOCTTY.should_not == nil + end + end + + it "lock mode constants" do + File::LOCK_EX.should_not == nil + File::LOCK_NB.should_not == nil + File::LOCK_SH.should_not == nil + File::LOCK_UN.should_not == nil + end +end + +describe "File::Constants" do + # These mode and permission bits are platform dependent + it "File::RDONLY" do + defined?(File::RDONLY).should == "constant" + end + + it "File::WRONLY" do + defined?(File::WRONLY).should == "constant" + end + + it "File::CREAT" do + defined?(File::CREAT).should == "constant" + end + + it "File::RDWR" do + defined?(File::RDWR).should == "constant" + end + + it "File::APPEND" do + defined?(File::APPEND).should == "constant" + end + + it "File::TRUNC" do + defined?(File::TRUNC).should == "constant" + end + + platform_is_not :windows do # Not sure about VMS here + it "File::NOCTTY" do + defined?(File::NOCTTY).should == "constant" + end + end + + it "File::NONBLOCK" do + defined?(File::NONBLOCK).should == "constant" + end + + it "File::LOCK_EX" do + defined?(File::LOCK_EX).should == "constant" + end + + it "File::LOCK_NB" do + defined?(File::LOCK_NB).should == "constant" + end + + it "File::LOCK_SH" do + defined?(File::LOCK_SH).should == "constant" + end + + it "File::LOCK_UN" do + defined?(File::LOCK_UN).should == "constant" + end + + it "File::SEPARATOR" do + defined?(File::SEPARATOR).should == "constant" + end + it "File::Separator" do + defined?(File::Separator).should == "constant" + end + + it "File::PATH_SEPARATOR" do + defined?(File::PATH_SEPARATOR).should == "constant" + end + + it "File::SEPARATOR" do + defined?(File::SEPARATOR).should == "constant" + File::SEPARATOR.should == "/" + end + + platform_is :windows do #|| VMS + it "File::ALT_SEPARATOR" do + defined?(File::ALT_SEPARATOR).should == "constant" + File::PATH_SEPARATOR.should == ";" + end + end + + platform_is_not :windows do + it "File::PATH_SEPARATOR" do + defined?(File::PATH_SEPARATOR).should == "constant" + File::PATH_SEPARATOR.should == ":" + end + end + +end diff --git a/1.8/core/file/ctime_spec.rb b/1.8/core/file/ctime_spec.rb new file mode 100644 index 0000000000..66ca6d817f --- /dev/null +++ b/1.8/core/file/ctime_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.ctime" do + before :each do + @file = __FILE__ + end + + after :each do + @file = nil + end + + it "Returns the change time for the named file (the time at which directory information about the file was changed, not the file itself)." do + File.ctime(@file) + File.ctime(@file).class.should == Time + end + + it "raises an Errno::ENOENT exception if the file is not found" do + lambda { File.ctime('bogus') }.should raise_error(Errno::ENOENT) + end +end + +describe "File#ctime" do + before :each do + @file = File.open(__FILE__) + end + + after:each do + @file.close + @file = nil + end + + it "Returns the change time for the named file (the time at which directory information about the file was changed, not the file itself)." do + @file.ctime + @file.ctime.class.should == Time + end +end diff --git a/1.8/core/file/delete_spec.rb b/1.8/core/file/delete_spec.rb new file mode 100644 index 0000000000..29df47ef64 --- /dev/null +++ b/1.8/core/file/delete_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/unlink' + +describe "File.delete" do + it_behaves_like(:file_unlink, :delete) +end diff --git a/1.8/core/file/directory_spec.rb b/1.8/core/file/directory_spec.rb new file mode 100644 index 0000000000..e5af018271 --- /dev/null +++ b/1.8/core/file/directory_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/directory' + +describe "File.directory?" do + it_behaves_like :file_directory, :directory?, File +end diff --git a/1.8/core/file/dirname_spec.rb b/1.8/core/file/dirname_spec.rb new file mode 100644 index 0000000000..0e711641d3 --- /dev/null +++ b/1.8/core/file/dirname_spec.rb @@ -0,0 +1,89 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.dirname" do + it "dirname should return all the components of filename except the last one" do + File.dirname('/home/jason').should == '/home' + File.dirname('/home/jason/poot.txt').should == '/home/jason' + File.dirname('poot.txt').should == '.' + File.dirname('/holy///schnikies//w00t.bin').should == '/holy///schnikies' + File.dirname('').should == '.' + File.dirname('/').should == '/' + File.dirname('/////').should == '/' + end + + it "return a String" do + File.dirname("foo").class.should == String + end + + it "not modify its argument" do + x = "/usr/bin" + File.dirname(x) + x.should == "/usr/bin" + end + + it "return the return all the components of filename except the last one (unix format)" do + File.dirname("foo").should =="." + File.dirname("/foo").should =="/" + File.dirname("/foo/bar").should =="/foo" + File.dirname("/foo/bar.txt").should =="/foo" + File.dirname("/foo/bar/baz").should =="/foo/bar" + end + + platform_is_not :windows do + it "return all the components of filename except the last one (edge cases)" do + File.dirname("").should == "." + File.dirname(".").should == "." + File.dirname("./").should == "." + File.dirname("./b/./").should == "./b" + File.dirname("..").should == "." + File.dirname("../").should == "." + File.dirname("/").should == "/" + File.dirname("/.").should == "/" + File.dirname("/foo/").should == "/" + File.dirname("//foo//").should == "/" + File.dirname("/foo/.").should == "/foo" + File.dirname("/foo/./").should == "/foo" + File.dirname("/foo/../.").should == "/foo/.." + File.dirname("foo/../").should == "foo" + end + end + + platform_is :windows do + it "return all the components of filename except the last one (edge cases)" do + File.dirname("//foo").should == "/" + end + end + + it "raises a TypeError if not passed a String type" do + lambda { File.dirname(nil) }.should raise_error(TypeError) + lambda { File.dirname(0) }.should raise_error(TypeError) + lambda { File.dirname(true) }.should raise_error(TypeError) + lambda { File.dirname(false) }.should raise_error(TypeError) + end + + # Windows specific tests + platform_is :windows do + it "return the return all the components of filename except the last one (Windows format)" do + File.dirname("C:\\foo\\bar\\baz.txt").should =="C:\\foo\\bar" + File.dirname("C:\\foo\\bar").should =="C:\\foo" + File.dirname("C:\\foo\\bar\\").should == "C:\\foo" + File.dirname("C:\\foo").should == "C:\\" + File.dirname("C:\\").should =="C:\\" + end + + it "return the return all the components of filename except the last one (windows unc)" do + File.dirname("\\\\foo\\bar\\baz.txt").should == "\\\\foo\\bar" + File.dirname("\\\\foo\\bar\\baz").should == "\\\\foo\\bar" + File.dirname("\\\\foo").should =="\\\\foo" + File.dirname("\\\\foo\\bar").should =="\\\\foo\\bar" + end + + it "return the return all the components of filename except the last one (forward_slash)" do + File.dirname("C:/").should == "C:/" + File.dirname("C:/foo").should == "C:/" + File.dirname("C:/foo/bar").should == "C:/foo" + File.dirname("C:/foo/bar/").should == "C:/foo" + File.dirname("C:/foo/bar//").should == "C:/foo" + end + end +end diff --git a/1.8/core/file/executable_real_spec.rb b/1.8/core/file/executable_real_spec.rb new file mode 100644 index 0000000000..428e7872f5 --- /dev/null +++ b/1.8/core/file/executable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/executable_real' + +describe "File.executable_real?" do + it_behaves_like :file_executable_real, :executable_real?, File + it_behaves_like :file_executable_real_missing, :executable_real?, File +end diff --git a/1.8/core/file/executable_spec.rb b/1.8/core/file/executable_spec.rb new file mode 100644 index 0000000000..d1fb58cdf1 --- /dev/null +++ b/1.8/core/file/executable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/executable' + +describe "File.executable?" do + it_behaves_like :file_executable, :executable?, File + it_behaves_like :file_executable_missing, :executable?, File +end diff --git a/1.8/core/file/exist_spec.rb b/1.8/core/file/exist_spec.rb new file mode 100644 index 0000000000..387dfa6421 --- /dev/null +++ b/1.8/core/file/exist_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/exist' + +describe "File.exist?" do + it_behaves_like(:file_exist, :exist?, File) +end diff --git a/1.8/core/file/exists_spec.rb b/1.8/core/file/exists_spec.rb new file mode 100644 index 0000000000..e0bb2ff115 --- /dev/null +++ b/1.8/core/file/exists_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/exist' + +describe "File.exists?" do + it_behaves_like(:file_exist, :exists?, File) +end diff --git a/1.8/core/file/expand_path_spec.rb b/1.8/core/file/expand_path_spec.rb new file mode 100644 index 0000000000..494761320d --- /dev/null +++ b/1.8/core/file/expand_path_spec.rb @@ -0,0 +1,91 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.expand_path" do + before :each do + platform_is :windows do + @base = `cd`.chomp.tr '\\', '/' + @tmpdir = "c:/tmp" + @rootdir = "c:/" + end + + platform_is_not :windows do + @base = Dir.pwd + @tmpdir = "/tmp" + @rootdir = "/" + end + end + + it "converts a pathname to an absolute pathname" do + File.expand_path('').should == @base + File.expand_path('a').should == File.join(@base, 'a') + File.expand_path('a', nil).should == File.join(@base, 'a') + end + + it "converts a pathname to an absolute pathname, Ruby-Talk:18512 " do + # Because of Ruby-Talk:18512 + File.expand_path('a.').should == File.join(@base, 'a.') + File.expand_path('.a').should == File.join(@base, '.a') + File.expand_path('a..').should == File.join(@base, 'a..') + File.expand_path('..a').should == File.join(@base, '..a') + File.expand_path('a../b').should == File.join(@base, 'a../b') + end + + it "converts a pathname to an absolute pathname, using a complete path" do + File.expand_path("", "#{@tmpdir}").should == "#{@tmpdir}" + File.expand_path("a", "#{@tmpdir}").should =="#{@tmpdir}/a" + File.expand_path("../a", "#{@tmpdir}/xxx").should == "#{@tmpdir}/a" + File.expand_path(".", "#{@rootdir}").should == "#{@rootdir}" + end + + # FIXME: do not use conditionals like this around #it blocks + unless not home = ENV['HOME'] + it "converts a pathname to an absolute pathname, using ~ (home) as base" do + File.expand_path('~').should == home + File.expand_path('~', '/tmp/gumby/ddd').should == home + File.expand_path('~/a', '/tmp/gumby/ddd').should == File.join(home, 'a') + end + end + + platform_is_not :windows do + # FIXME: these are insane! + it "expand path with " do + File.expand_path("../../bin", "/tmp/x").should == "/bin" + File.expand_path("../../bin", "/tmp").should == "/bin" + File.expand_path("../../bin", "/").should == "/bin" + File.expand_path("../../bin", "tmp/x").should == File.join(@base, 'bin') + end + + it "expand_path for commoms unix path give a full path" do + File.expand_path('/tmp/').should =='/tmp' + File.expand_path('/tmp/../../../tmp').should == '/tmp' + File.expand_path('').should == Dir.pwd + File.expand_path('./////').should == Dir.pwd + File.expand_path('.').should == Dir.pwd + File.expand_path(Dir.pwd).should == Dir.pwd + File.expand_path('~/').should == ENV['HOME'] + File.expand_path('~/..badfilename').should == ENV['HOME'] + '/..badfilename' + File.expand_path('..').should == Dir.pwd.split('/')[0...-1].join("/") + File.expand_path('//').should == '//' + File.expand_path('~/a','~/b').should == ENV['HOME']+"/a" + end + + it "raises an ArgumentError if the path is not valid" do + lambda { File.expand_path("~a_fake_file") }.should raise_error(ArgumentError) + end + + it "expands ~ENV['USER'] to the user's home directory" do + File.expand_path("~#{ENV['USER']}").should == ENV['HOME'] + end + end + + it "raises an ArgumentError is not passed one or two arguments" do + lambda { File.expand_path }.should raise_error(ArgumentError) + lambda { File.expand_path '../', 'tmp', 'foo' }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { File.expand_path(1) }.should raise_error(TypeError) + lambda { File.expand_path(nil) }.should raise_error(TypeError) + lambda { File.expand_path(true) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/file/extname_spec.rb b/1.8/core/file/extname_spec.rb new file mode 100644 index 0000000000..b9025197e0 --- /dev/null +++ b/1.8/core/file/extname_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.extname" do + it "returns the extension (the portion of file name in path after the period)." do + File.extname("foo.rb").should == ".rb" + File.extname("/foo/bar.rb").should == ".rb" + File.extname("/foo.rb/bar.c").should == ".c" + File.extname("bar").should == "" + File.extname(".bashrc").should == "" + File.extname("/foo.bar/baz").should == "" + File.extname(".app.conf").should == ".conf" + end + + it "returns the extension (the portion of file name in path after the period).(edge cases)" do + File.extname("").should == "" + File.extname(".").should == "" + File.extname("/").should == "" + File.extname("/.").should == "" + File.extname("..").should == "" + File.extname("...").should == "" + File.extname("....").should == "" + File.extname(".foo.").should == "" + File.extname("foo.").should == "" + end + + it "returns only the last extension of a file with several dots" do + File.extname("a.b.c.d.e").should == ".e" + end + + it "raises a TypeError if not passed a String type" do + lambda { File.extname(nil) }.should raise_error(TypeError) + lambda { File.extname(0) }.should raise_error(TypeError) + lambda { File.extname(true) }.should raise_error(TypeError) + lambda { File.extname(false) }.should raise_error(TypeError) + end + + it "raises an ArgumentError if not passed one argument" do + lambda { File.extname }.should raise_error(ArgumentError) + lambda { File.extname("foo.bar", "foo.baz") }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/file/file_spec.rb b/1.8/core/file/file_spec.rb new file mode 100644 index 0000000000..0782028ed9 --- /dev/null +++ b/1.8/core/file/file_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/file' + +describe "File.file?" do + it_behaves_like :file_file, :file?, File +end diff --git a/1.8/core/file/fixtures/do_not_remove b/1.8/core/file/fixtures/do_not_remove new file mode 100644 index 0000000000..e69de29bb2 diff --git a/1.8/core/file/fixtures/file_types.rb b/1.8/core/file/fixtures/file_types.rb new file mode 100644 index 0000000000..eddd100d75 --- /dev/null +++ b/1.8/core/file/fixtures/file_types.rb @@ -0,0 +1,72 @@ +module FileSpecs + # Try to set up known locations of each filetype + def self.reconfigure() + @file = "test.txt" + @dir = Dir.pwd + @fifo = "test_fifo" + @block = `find /dev /devices -type b 2> /dev/null`.split("\n").first + @char = `find /dev /devices -type c 2> /dev/null`.split("\n").last + + %w[/dev /usr/bin /usr/local/bin].each do |dir| + links = `find #{dir} -type l 2> /dev/null`.split("\n") + next if links.empty? + @link = links.first + break + end + + @sock = nil + find_socket + end + + # TODO: This is probably too volatile + def self.find_socket() + %w[/tmp /var/run].each do |dir| + socks = `find #{dir} -type s 2> /dev/null`.split("\n") + next if socks.empty? + @sock = socks.first + break + end + end + + # TODO: Automatic reload mechanism + reconfigure + + def self.normal_file() + File.open(@file, "w") {} # 'Touch' + yield @file + ensure + File.unlink @file + end + + def self.directory() + yield @dir + end + + def self.fifo() + system "mkfifo #{@fifo} 2> /dev/null" + yield @fifo + ensure + File.unlink @fifo + end + + def self.block_device() + yield @block + end + + def self.character_device() + yield @char + end + + def self.symlink() + yield @link + end + + # This will silently not execute the block if no socket + # can be found. However, if you are running X, there is + # a good chance that if nothing else, at least the X + # Server socket exists. + def self.socket() + find_socket + yield @sock if @sock + end +end diff --git a/1.8/core/file/flock_spec.rb b/1.8/core/file/flock_spec.rb new file mode 100644 index 0000000000..e6c08926e7 --- /dev/null +++ b/1.8/core/file/flock_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File#flock" do + before :each do + system "echo 'rubinius' > flock_test" + end + + after :each do + File.delete('flock_test') if File.exist?('flock_test') + end + + it "should lock a file" do + f = File.open('flock_test', "r") + f.flock(File::LOCK_EX).should == 0 + File.open('flock_test', "w") do |f2| + f2.flock(File::LOCK_EX | File::LOCK_NB).should == false + end + f.flock(File::LOCK_UN).should == 0 + File.open('flock_test', "w") do |f2| + f2.flock(File::LOCK_EX | File::LOCK_NB).should == 0 + f2.flock(File::LOCK_UN).should == 0 + end + f.close + end +end diff --git a/1.8/core/file/fnmatch_spec.rb b/1.8/core/file/fnmatch_spec.rb new file mode 100644 index 0000000000..8350b3770d --- /dev/null +++ b/1.8/core/file/fnmatch_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/fnmatch' + +describe "File.fnmatch" do + it_behaves_like(:file_fnmatch, :fnmatch) +end + +describe "File.fnmatch?" do + it_behaves_like(:file_fnmatch, :fnmatch?) +end diff --git a/1.8/core/file/ftype_spec.rb b/1.8/core/file/ftype_spec.rb new file mode 100644 index 0000000000..2103787d99 --- /dev/null +++ b/1.8/core/file/ftype_spec.rb @@ -0,0 +1,68 @@ +require "#{File.dirname(__FILE__)}/../../spec_helper" +require "#{File.dirname(__FILE__)}/fixtures/file_types.rb" + +describe "File.ftype" do + it "raises ArgumentError if not given exactly one filename" do + lambda { File.ftype }.should raise_error(ArgumentError) + lambda { File.ftype('blah', 'bleh') }.should raise_error(ArgumentError) + end + + it "raises Errno::ENOENT if the file is not valid" do + l = lambda { File.ftype("/#{$$}#{Time.now.to_f}#{$0}") } + l.should raise_error(Errno::ENOENT) + end + + it "returns a String " do + FileSpecs.normal_file do |file| + File.ftype(file).class.should == String + end + end + + it "returns 'file' when the file is a file" do + FileSpecs.normal_file do |file| + File.ftype(file).should == 'file' + end + end + + it "returns 'directory' when the file is a dir" do + FileSpecs.directory do |dir| + File.ftype(dir).should == 'directory' + end + end + + it "returns 'characterSpecial' when the file is a char" do + FileSpecs.character_device do |char| + File.ftype(char).should == 'characterSpecial' + end + end + + platform_is_not :freebsd do # FreeBSD does not have block devices + it "returns 'blockSpecial' when the file is a block" do + FileSpecs.block_device do |block| + File.ftype(block).should == 'blockSpecial' + end + end + end + + it "returns 'link' when the file is a link" do + FileSpecs.symlink do |link| + File.ftype(link).should == 'link' + end + end + + it "returns fifo when the file is a fifo" do + FileSpecs.fifo do |fifo| + File.ftype(fifo).should == 'fifo' + end + end + + # This will silently not execute the block if no socket + # can be found. However, if you are running X, there is + # a good chance that if nothing else, at least the X + # Server socket exists. + it "returns 'socket' when the file is a socket" do + FileSpecs.socket do |socket| + File.ftype(socket).should == 'socket' + end + end +end diff --git a/1.8/core/file/grpowned_spec.rb b/1.8/core/file/grpowned_spec.rb new file mode 100644 index 0000000000..10e9861bab --- /dev/null +++ b/1.8/core/file/grpowned_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/grpowned' + +describe "File.grpowned?" do + it_behaves_like :file_grpowned, :grpowned?, File + + it "returns false if file the does not exist" do + File.grpowned?("i_am_a_bogus_file").should == false + end +end diff --git a/1.8/core/file/identical_spec.rb b/1.8/core/file/identical_spec.rb new file mode 100644 index 0000000000..0be7c1c86e --- /dev/null +++ b/1.8/core/file/identical_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/identical' + +describe "File.identical?" do + it_behaves_like :file_identical, :identical?, File +end diff --git a/1.8/core/file/initialize_spec.rb b/1.8/core/file/initialize_spec.rb new file mode 100644 index 0000000000..dc1620e865 --- /dev/null +++ b/1.8/core/file/initialize_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/inspect_spec.rb b/1.8/core/file/inspect_spec.rb new file mode 100644 index 0000000000..943c94e69b --- /dev/null +++ b/1.8/core/file/inspect_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../io/fixtures/classes' + +describe "File#inspect" do + it "returns string that contains 'closed' when invoked on closed file" do + IOSpecs.closed_file.inspect.should =~ /closed/ + end +end diff --git a/1.8/core/file/join_spec.rb b/1.8/core/file/join_spec.rb new file mode 100644 index 0000000000..ebbca17572 --- /dev/null +++ b/1.8/core/file/join_spec.rb @@ -0,0 +1,90 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.join" do + + it "does nothing to empty strings" do + File.join("").should == "" + end + + it "joins parts using File::SEPARATOR" do + File.join('usr', 'bin').should == "usr/bin" + end + + platform_is :windows do + it "joins parts using File::ALT_SEPARATOR on windows" do + File.join("C:\\", 'windows').should == "C:\\windows" + File.join("\\\\", "usr").should == "\\\\usr" + end + end + + it "handles leading parts edge cases" do + File.join("/bin") .should == "/bin" + File.join("", "bin") .should == "/bin" + File.join("/", "bin") .should == "/bin" + File.join("/", "/bin").should == "/bin" + end + + it "handles trailing parts edge cases" do + File.join("bin", "") .should == "bin/" + File.join("bin/") .should == "bin/" + File.join("bin/", "") .should == "bin/" + File.join("bin", "/") .should == "bin/" + File.join("bin/", "/").should == "bin/" + end + + it "handles middle parts edge cases" do + File.join("usr", "", "bin") .should == "usr/bin" + File.join("usr/", "", "bin") .should == "usr/bin" + File.join("usr", "", "/bin").should == "usr/bin" + File.join("usr/", "", "/bin").should == "usr/bin" + end + + it "handles recursive arrays" do + parts = [] + parts << parts + File.join(parts).should == '[...]' + + parts = ["one", "two"] + parts << parts + File.join(parts).should == 'one/two/one/two/[...]' + + parts << "three" + parts << "four" + File.join(parts).should == 'one/two/one/two/[...]/three/four/three/four' + + parts = [["one", "two"], ["three", "four"]] + parts << parts + File.join(parts).should == 'one/two/three/four/one/two/three/four/[...]' + + a = ['a'] + a << a + File.join(a).should == 'a/a/[...]' + File.join([a]).should == 'a/a/[...]' + + a = ['a'] + b = ['b'] + a << b + b << a + File.join(a).should == "a/b/[...]" + + a = [] + b = [] + a << b + b << a + File.join(a).should == '[...]' + end + + it "doesn't remove File::SEPARATOR from the middle of arguments" do + path = File.join "file://usr", "bin" + path.should == "file://usr/bin" + end + + it "raises a TypeError exception when args are nil" do + lambda { File.join nil }.should raise_error(TypeError) + end + + it "calls #to_str" do + lambda { File.join(mock('x')) }.should raise_error(TypeError) + end + +end diff --git a/1.8/core/file/lchmod_spec.rb b/1.8/core/file/lchmod_spec.rb new file mode 100644 index 0000000000..85f0ab9a09 --- /dev/null +++ b/1.8/core/file/lchmod_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.lchmod" do + before :each do + @fname = tmp('file_chmod_test') + @lname = @fname + '.lnk' + File.delete @fname rescue nil + File.delete @lname rescue nil + File.open(@fname, 'w') { |f| f.write "rubinius" } + File.symlink @fname, @lname + end + + after :each do + File.delete @fname if File.exist? @fname + File.delete @lname if File.exist? @lname + end + + it "changes the file mode of the link and not of the file" do + File.chmod(0222, @lname).should == 1 + File.lchmod(0755, @lname).should == 1 + + File.lstat(@lname).executable?.should == true + File.lstat(@lname).readable?.should == true + File.lstat(@lname).writable?.should == true + + File.stat(@lname).executable?.should == false + File.stat(@lname).readable?.should == false + File.stat(@lname).writable?.should == true + end + +end diff --git a/1.8/core/file/lchown_spec.rb b/1.8/core/file/lchown_spec.rb new file mode 100644 index 0000000000..1d4f6b4d66 --- /dev/null +++ b/1.8/core/file/lchown_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +as_superuser do + describe "File.lchown" do + before :each do + @fname = '/tmp/file_chown_test' + @lname = @fname + '.lnk' + File.delete @fname rescue nil + File.delete @lname rescue nil + File.open(@fname, 'w') { |f| f.chown 501, 501 } + File.symlink @fname, @lname + end + + after :each do + File.delete @fname if File.exist? @fname + File.delete @lname if File.exist? @lname + end + + it "changes the owner id of the file" do + File.lchown 502, nil, @lname + File.stat(@fname).uid.should == 501 + File.lstat(@lname).uid.should == 502 + File.lchown 0, nil, @lname + File.stat(@fname).uid.should == 501 + File.lstat(@lname).uid.should == 0 + end + + it "changes the group id of the file" do + File.lchown nil, 502, @lname + File.stat(@fname).gid.should == 501 + File.lstat(@lname).gid.should == 502 + File.lchown nil, 0, @lname + File.stat(@fname).uid.should == 501 + File.lstat(@lname).uid.should == 0 + end + + it "does not modify the owner id of the file if passed nil or -1" do + File.lchown 502, nil, @lname + File.lchown nil, nil, @lname + File.lstat(@lname).uid.should == 502 + File.lchown nil, -1, @lname + File.lstat(@lname).uid.should == 502 + end + + it "does not modify the group id of the file if passed nil or -1" do + File.lchown nil, 502, @lname + File.lchown nil, nil, @lname + File.lstat(@lname).gid.should == 502 + File.lchown nil, -1, @lname + File.lstat(@lname).gid.should == 502 + end + + it "returns the number of files processed" do + File.lchown(nil, nil, @lname, @lname).should == 2 + end + end +end diff --git a/1.8/core/file/link_spec.rb b/1.8/core/file/link_spec.rb new file mode 100644 index 0000000000..c9d42de05e --- /dev/null +++ b/1.8/core/file/link_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.link" do + before :each do + @file = "test.txt" + @link = "test.lnk" + File.delete(@link) if File.exist?(@link) + File.delete(@file) if File.exist?(@file) + File.open(@file,"w+") + end + + after :each do + File.unlink(@link) if File.exist?(@link) + File.delete(@file) if File.exist?(@file) + @link = nil + end + + platform_is_not :windows do + it "link a file with another" do + File.link(@file, @link).should == 0 + File.exists?(@link).should == true + File.identical?(@file, @link).should == true + end + + it "raises an Errno::EEXIST if the target already exists" do + File.link(@file, @link) + lambda { File.link(@file, @link) }.should raise_error(Errno::EEXIST) + end + + it "raises an ArgumentError if not passed two arguments" do + lambda { File.link }.should raise_error(ArgumentError) + lambda { File.link(@file) }.should raise_error(ArgumentError) + lambda { File.link(@file, @link, @file) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed String types" do + lambda { File.link(@file, nil) }.should raise_error(TypeError) + lambda { File.link(@file, 1) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/file/lstat_spec.rb b/1.8/core/file/lstat_spec.rb new file mode 100644 index 0000000000..4d7e09d7ac --- /dev/null +++ b/1.8/core/file/lstat_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/stat' + +describe "File.lstat" do + it_behaves_like :file_stat, :lstat +end + +describe "File.lstat" do + + before :each do + @file = '/tmp/i_exist' + @link = '/tmp/i_am_a_symlink' + File.open(@file,'w'){|f| f.write 'rubinius'} + File.symlink(@file, @link) + end + + after :each do + File.delete(@link) if File.exist?(@link) + File.delete(@file) if File.exist?(@file) + end + + it "returns a File::Stat object with symlink properties for a symlink" do + st = File.lstat(@link) + + st.symlink?.should == true + st.file?.should == false + end +end diff --git a/1.8/core/file/mtime_spec.rb b/1.8/core/file/mtime_spec.rb new file mode 100644 index 0000000000..a4e52729fd --- /dev/null +++ b/1.8/core/file/mtime_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.mtime" do + before :each do + @filename = '/tmp/i_exist' + File.open(@filename, 'w') { @mtime = Time.now } + end + + after :each do + File.delete(@filename) if File.exist?(@filename) + end + + it "returns the modification Time of the file" do + File.mtime(@filename).class.should == Time + File.mtime(@filename).should be_close(@mtime, 2.0) + end + + it "raises an Errno::ENOENT exception if the file is not found" do + lambda { File.mtime('bogus') }.should raise_error(Errno::ENOENT) + end +end + +describe "File#mtime" do + before :each do + @filename = '/tmp/i_exist' + @f = File.open(@filename, 'w') + end + + after :each do + File.delete(@filename) if File.exist?(@filename) + end + + it "returns the modification Time of the file" do + @f.mtime.class.should == Time + end + +end diff --git a/1.8/core/file/new_spec.rb b/1.8/core/file/new_spec.rb new file mode 100644 index 0000000000..d7e77a6b1e --- /dev/null +++ b/1.8/core/file/new_spec.rb @@ -0,0 +1,138 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.new" do + before :each do + @file = 'test.txt' + @fh = nil + @flags = File::CREAT | File::TRUNC | File::WRONLY + File.open(@file, "w") {} # touch + end + + after :each do + File.delete(@file) if File.exists?(@file) + @fh = nil + @file = nil + @flags = nil + end + + it "return a new File with mode string" do + @fh = File.new(@file, 'w') + @fh.class.should == File + File.exists?(@file).should == true + end + + it "return a new File with mode num" do + @fh = File.new(@file, @flags) + @fh.class.should == File + File.exists?(@file).should == true + end + + it "return a new File with modus num and permissions" do + File.delete(@file) + File.umask(0011) + @fh = File.new(@file, @flags, 0755) + @fh.class.should == File + File.stat(@file).mode.to_s(8).should == "100744" + File.exists?(@file).should == true + end + + it "creates the file and returns writable descriptor when called with 'w' mode and r-o permissions" do + # it should be possible to write to such a file via returned descriptior, + # even though the file permissions are r-r-r. + + File.delete(@file) if File.exists?(@file) + begin + f = File.new(@file, "w", 0444) + lambda { f.puts("test") }.should_not raise_error(IOError) + ensure + f.close + end + File.exist?(@file).should == true + File.read(@file).should == "test\n" + end + + it "opens the existing file, does not change permissions even when they are specified" do + File.chmod(0664, @file) # r-w perms + orig_perms = File.stat(@file).mode.to_s(8) + begin + f = File.new(@file, "w", 0444) # r-o perms, but they should be ignored + f.puts("test") + ensure + f.close + end + File.stat(@file).mode.to_s(8).should == orig_perms + + # it should be still possible to read from the file + File.read(@file).should == "test\n" + end + + it "return a new File with modus fd " do + @fh = File.new(@file) + @fh = File.new(@fh.fileno) + @fh.class.should == File + File.exists?(@file).should == true + end + + it "create a new file when use File::EXCL mode " do + @fh = File.new(@file, File::EXCL) + @fh.class.should == File + File.exists?(@file).should == true + end + + it "raises an Errorno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do + lambda { @fh = File.new(@file, File::CREAT|File::EXCL) }.should raise_error(Errno::EEXIST) + end + + it "create a new file when use File::WRONLY|File::APPEND mode" do + @fh = File.new(@file, File::WRONLY|File::APPEND) + @fh.class.should == File + File.exists?(@file).should == true + end + + it "raises an Errno::EINVAL error with File::APPEND" do + lambda { @fh = File.new(@file, File::APPEND) }.should raise_error(Errno::EINVAL) + end + + it "raises an Errno::EINVAL error with File::RDONLY|File::APPEND" do + lambda { @fh = File.new(@file, File::RDONLY|File::APPEND) }.should raise_error(Errno::EINVAL) + end + + it "raises an Errno::EINVAL error with File::RDONLY|File::WRONLY" do + @fh = File.new(@file, File::RDONLY|File::WRONLY) + @fh.class.should == File + File.exists?(@file).should == true + end + + + it "create a new file when use File::WRONLY|File::TRUNC mode" do + @fh = File.new(@file, File::WRONLY|File::TRUNC) + @fh.class.should == File + File.exists?(@file).should == true + end + + it "coerces filename using to_str" do + f = Object.new + def f.to_str; __FILE__; end + + begin + file = File.new(f) + ensure + file.close if file + end + end + + specify "expected errors " do + lambda { File.new(true) }.should raise_error(TypeError) + lambda { File.new(false) }.should raise_error(TypeError) + lambda { File.new(nil) }.should raise_error(TypeError) + lambda { File.new(-1) }.should raise_error(Errno::EBADF) + lambda { File.new(@file, File::CREAT, 0755, 'test') }.should raise_error(ArgumentError) + end + + # You can't alter mode or permissions when opening a file descriptor + # + it "can't alter mode or permissions when opening a file" do + @fh = File.new(@file) + lambda { File.new(@fh.fileno, @flags) }.should raise_error(Errno::EINVAL) + end +end diff --git a/1.8/core/file/open_spec.rb b/1.8/core/file/open_spec.rb new file mode 100644 index 0000000000..2331bfc562 --- /dev/null +++ b/1.8/core/file/open_spec.rb @@ -0,0 +1,523 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.open" do + before :all do + @file = "/tmp/test.txt" + File.delete(@file) if File.exist?(@file) + File.delete("fake") if File.exist?("fake") + end + + before :each do + @fh = @fd = nil + @flags = File::CREAT | File::TRUNC | File::WRONLY + File.open(@file, "w") {} # touch + end + + after :each do + File.delete(@file) if File.exist?(@file) + File.delete("fake") if File.exist?("fake") + @fh.close if @fh and not @fh.closed? + end + + it "with block does not raise error when file is closed inside the block" do + lambda { + @fh = File.open(@file) { |fh| fh.close; fh } + }.should_not raise_error + @fh.closed?.should == true + end + + it "with a block invokes close on opened file when exiting the block" do + file = File.open(@file, 'r') do |f| + class << f + @res = "close was not invoked" + alias_method(:close_orig, :close) + def close; close_orig; @res = "close was invoked"; end + def to_s; @res; end + end + f + end + file.to_s.should == "close was invoked" + end + + it "with a block propagates non-StandardErrors produced by close" do + lambda { + File.open(@file, 'r') do |f| + class << f + alias_method(:close_orig, :close) + def close + close_orig + raise Exception, "exception out of close" + end + end + end + }.should raise_error(Exception, "exception out of close") + end + + it "with a block swallows StandardErrors produced by close" do + File.open(@file, 'r') do |f| + class << f + alias_method(:close_orig, :close) + def close + raise IOError + end + end + end + end + + it "opens the file (basic case)" do + @fh = File.open(@file) + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens file when call with a block (basic case)" do + File.open(@file){ |fh| @fd = fh.fileno } + lambda { File.open(@fd) }.should raise_error(SystemCallError) # Should be closed by block + File.exist?(@file).should == true + end + + it "opens with mode string" do + @fh = File.open(@file, 'w') + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens a file with mode string and block" do + File.open(@file, 'w'){ |fh| @fd = fh.fileno } + lambda { File.open(@fd) }.should raise_error(SystemCallError) + File.exist?(@file).should == true + end + + it "opens a file with mode num" do + @fh = File.open(@file, @flags) + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens a file with mode num and block" do + File.open(@file, 'w'){ |fh| @fd = fh.fileno } + lambda { File.open(@fd) }.should raise_error(SystemCallError) + File.exist?(@file).should == true + end + + # I do not think this should be valid on MRI either--File.new yes. + compliant_on :ruby do + # For this test we delete the file first to reset the perms + it "opens the file when call with mode, num and permissions" do + File.delete(@file) + File.umask(0011) + @fh = File.open(@file, @flags, 0755) + @fh.should be_kind_of(File) + @fh.lstat.mode.to_s(8).should == "100744" + File.exist?(@file).should == true + end + + # For this test we delete the file first to reset the perms + it "opens the flie when call with mode, num, permissions and block" do + File.delete(@file) + File.umask(0022) + File.open(@file, "w", 0755){ |fh| @fd = fh.fileno } + lambda { File.open(@fd) }.should raise_error(SystemCallError) + File.stat(@file).mode.to_s(8).should == "100755" + File.exist?(@file).should == true + end + end + + it "creates the file and returns writable descriptor when called with 'w' mode and r-o permissions" do + # it should be possible to write to such a file via returned descriptior, + # even though the file permissions are r-r-r. + + File.delete(@file) if File.exists?(@file) + File.open(@file, "w", 0444){ |f| + lambda { f.puts("test") }.should_not raise_error(IOError) + } + File.exist?(@file).should == true + File.read(@file).should == "test\n" + end + + it "opens the existing file, does not change permissions even when they are specified" do + File.chmod(0664, @file) # r-w perms + orig_perms = File.stat(@file).mode.to_s(8) + File.open(@file, "w", 0444){ |f| # r-o perms, but they should be ignored + lambda { f.puts("test") }.should_not raise_error(IOError) + } + # check that original permissions preserved + File.stat(@file).mode.to_s(8).should == orig_perms + + # it should be still possible to read from the file + File.read(@file).should == "test\n" + end + + it "creates a new write-only file when invoked with 'w' and '0222'" do + File.delete(@file) if File.exists?(@file) + File.open(@file, 'w', 0222) {} + File.readable?(@file).should == false + File.writable?(@file).should == true + end + + it "opens the file when call with fd" do + @fh = File.open(@file) + @fh = File.open(@fh.fileno) + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens a file with a file descriptor d and a block" do + @fh = File.open(@file) + @fh.should be_kind_of(File) + File.open(@fh.fileno) { |fh| @fd = fh.fileno; @fh.close } + lambda { File.open(@fd) }.should raise_error(SystemCallError) + File.exist?(@file).should == true + end + + it "opens a file that no exists when use File::WRONLY mode" do + lambda { File.open("fake", File::WRONLY) }.should raise_error(Errno::ENOENT) + end + + it "opens a file that no exists when use File::RDONLY mode" do + lambda { File.open("fake", File::RDONLY) }.should raise_error(Errno::ENOENT) + end + + it "opens a file that no exists when use 'r' mode" do + lambda { File.open("fake", 'r') }.should raise_error(Errno::ENOENT) + end + + it "opens a file that no exists when use File::EXCL mode" do + lambda { File.open("fake", File::EXCL) }.should raise_error(Errno::ENOENT) + end + + it "opens a file that no exists when use File::NONBLOCK mode" do + lambda { File.open("fake", File::NONBLOCK) }.should raise_error(Errno::ENOENT) + end + + platform_is_not :openbsd do + it "opens a file that no exists when use File::TRUNC mode" do + lambda { File.open("fake", File::TRUNC) }.should raise_error(Errno::ENOENT) + end + end + + platform_is :openbsd do + it "opens a file that no exists when use File::TRUNC mode" do + lambda { File.open("fake", File::TRUNC) }.should raise_error(Errno::EINVAL) + end + end + + it "opens a file that no exists when use File::NOCTTY mode" do + lambda { File.open("fake", File::NOCTTY) }.should raise_error(Errno::ENOENT) + end + + it "opens a file that no exists when use File::CREAT mode" do + @fh = File.open("fake", File::CREAT) { |f| f } + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens a file that no exists when use 'a' mode" do + @fh = File.open("fake", 'a') { |f| f } + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens a file that no exists when use 'w' mode" do + @fh = File.open("fake", 'w') { |f| f } + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + # Check the grants associated to the differents open modes combinations. + it "raises an ArgumentError exception when call with an unknown mode" do + lambda { File.open(@file, "q") }.should raise_error(ArgumentError) + end + + it "can read in a block when call open with RDONLY mode" do + File.open(@file, File::RDONLY) do |f| + f.gets.should == nil + end + end + + it "can read in a block when call open with 'r' mode" do + File.open(@file, "r") do |f| + f.gets.should == nil + end + end + + it "raises an IO exception when write in a block opened with RDONLY mode" do + File.open(@file, File::RDONLY) do |f| + lambda { f.puts "writing ..." }.should raise_error(IOError) + end + end + + it "raises an IO exception when write in a block opened with 'r' mode" do + File.open(@file, "r") do |f| + lambda { f.puts "writing ..." }.should raise_error(IOError) + end + end + + it "can't write in a block when call open with File::WRONLY||File::RDONLY mode" do + File.open(@file, File::WRONLY|File::RDONLY ) do |f| + f.puts("writing").should == nil + end + end + + it "can't read in a block when call open with File::WRONLY||File::RDONLY mode" do + lambda { + File.open(@file, File::WRONLY|File::RDONLY ) do |f| + f.gets.should == nil + end + }.should raise_error(IOError) + end + + it "can write in a block when call open with WRONLY mode" do + File.open(@file, File::WRONLY) do |f| + f.puts("writing").should == nil + end + end + + it "can write in a block when call open with 'w' mode" do + File.open(@file, "w") do |f| + f.puts("writing").should == nil + end + end + + it "raises an IO exception when read in a block opened with WRONLY mode" do + File.open(@file, File::WRONLY) do |f| + lambda { f.gets }.should raise_error(IOError) + end + end + + it "raises an IO exception when read in a block opened with 'w' mode" do + File.open(@file, "w") do |f| + lambda { f.gets }.should raise_error(IOError) + end + end + + it "raises an IO exception when read in a block opened with 'a' mode" do + File.open(@file, "a") do |f| + lambda { f.gets }.should raise_error(IOError) + end + end + + it "raises an IO exception when read in a block opened with 'a' mode" do + File.open(@file, "a") do |f| + f.puts("writing").should == nil + lambda { f.gets }.should raise_error(IOError) + end + end + + it "raises an IO exception when read in a block opened with 'a' mode" do + File.open(@file, File::WRONLY|File::APPEND ) do |f| + lambda { f.gets }.should raise_error(IOError) + end + end + + it "raises an IO exception when read in a block opened with File::WRONLY|File::APPEND mode" do + File.open(@file, File::WRONLY|File::APPEND ) do |f| + f.puts("writing").should == nil + end + end + + it "raises an IO exception when read in a block opened with File::RDONLY|File::APPEND mode" do + lambda { + File.open(@file, File::RDONLY|File::APPEND ) do |f| + f.puts("writing") + end + }.should raise_error(Errno::EINVAL) + end + + it "can read and write in a block when call open with RDWR mode" do + File.open(@file, File::RDWR) do |f| + f.gets.should == nil + f.puts("writing").should == nil + f.rewind + f.gets.should == "writing\n" + end + end + + it "can't read in a block when call open with File::EXCL mode" do + lambda { + File.open(@file, File::EXCL) do |f| + f.puts("writing").should == nil + end + }.should raise_error(IOError) + end + + it "can read in a block when call open with File::EXCL mode" do + File.open(@file, File::EXCL) do |f| + f.gets.should == nil + end + end + + it "can read and write in a block when call open with File::RDWR|File::EXCL mode" do + File.open(@file, File::RDWR|File::EXCL) do |f| + f.gets.should == nil + f.puts("writing").should == nil + f.rewind + f.gets.should == "writing\n" + end + end + + it "raises an Errorno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do + lambda { + File.open(@file, File::CREAT|File::EXCL) do |f| + f.puts("writing") + end + }.should raise_error(Errno::EEXIST) + end + + it "create a new file when use File::WRONLY|File::APPEND mode" do + @fh = File.open(@file, File::WRONLY|File::APPEND) + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens a file when use File::WRONLY|File::APPEND mode" do + File.open(@file, File::WRONLY) do |f| + f.puts("hello file") + end + File.open(@file, File::RDWR|File::APPEND) do |f| + f.puts("bye file") + f.rewind + f.gets().should == "hello file\n" + f.gets().should == "bye file\n" + f.gets().should == nil + end + end + + it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::APPEND" do + lambda { + File.open(@file, File::RDONLY|File::APPEND) do |f| + f.puts("writing").should == nil + end + }.should raise_error(Errno::EINVAL) + end + + platform_is_not :openbsd do + + it "truncates the file when passed File::TRUNC mode" do + File.open(@file, File::RDWR) { |f| f.puts "hello file" } + @fh = File.open(@file, File::TRUNC) + @fh.gets.should == nil + end + + it "can't read in a block when call open with File::TRUNC mode" do + File.open(@file, File::TRUNC) do |f| + f.gets.should == nil + end + end + + end + + it "opens a file when use File::WRONLY|File::TRUNC mode" do + File.open(@file, "w") + @fh = File.open(@file, File::WRONLY|File::TRUNC) + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + platform_is_not :openbsd do + it "can't write in a block when call open with File::TRUNC mode" do + lambda { + File.open(@file, File::TRUNC) do |f| + f.puts("writing") + end + }.should raise_error(IOError) + end + + it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do + lambda { + File.open(@file, File::RDONLY|File::TRUNC) do |f| + f.puts("writing").should == nil + end + }.should raise_error(IOError) + end + end + + platform_is :openbsd do + it "can't write in a block when call open with File::TRUNC mode" do + lambda { + File.open(@file, File::TRUNC) do |f| + f.puts("writing") + end + }.should raise_error(Errno::EINVAL) + end + + it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do + lambda { + File.open(@file, File::RDONLY|File::TRUNC) do |f| + f.puts("writing").should == nil + end + }.should raise_error(Errno::EINVAL) + end + end + + it "raises an Errno::EACCES when opening non-permitted file" do + @fh = File.open(@file, "w") + @fh.chmod(000) + lambda { File.open(@file) }.should raise_error(Errno::EACCES) + end + + it "raises an Errno::EACCES when opening read-only file" do + @fh = File.open(@file, "w") + @fh.chmod(0444) + lambda { File.open(@file, "w") }.should raise_error(Errno::EACCES) + end + + it "opens a file for binary read" do + @fh = File.open(@file, "rb") + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens a file for binary write" do + @fh = File.open(@file, "wb") + @fh.should be_kind_of(File) + File.exist?(@file).should == true + end + + it "opens a file for read-write and truncate the file" do + File.open(@file, "w") { |f| f.puts "testing" } + File.size(@file).should > 0 + File.open(@file, "w+") do |f| + f.pos.should == 0 + f.eof?.should == true + end + File.size(@file).should == 0 + end + + it "opens a file for binary read-write starting at the beginning of the file" do + File.open(@file, "w") { |f| f.puts "testing" } + File.size(@file).should > 0 + File.open(@file, "rb+") do |f| + f.pos.should == 0 + f.eof?.should == false + end + end + + it "opens a file for binary read-write and truncate the file" do + File.open(@file, "w") { |f| f.puts "testing" } + File.size(@file).should > 0 + File.open(@file, "wb+") do |f| + f.pos.should == 0 + f.eof?.should == true + end + File.size(@file).should == 0 + end + + it "raises a TypeError if passed a filename that is not a String or Integer type" do + lambda { File.open(true) }.should raise_error(TypeError) + lambda { File.open(false) }.should raise_error(TypeError) + lambda { File.open(nil) }.should raise_error(TypeError) + end + + it "raises a SystemCallError if passed an invalid Integer type" do + lambda { File.open(-1) }.should raise_error(SystemCallError) + end + + it "raises an ArgumentError if passed the wrong number of arguments" do + lambda { File.open(@file, File::CREAT, 0755, 'test') }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError if passed an invalid string for mode" do + lambda { File.open(@file, 'fake') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/file/owned_spec.rb b/1.8/core/file/owned_spec.rb new file mode 100644 index 0000000000..ec68ce1d4a --- /dev/null +++ b/1.8/core/file/owned_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/owned' + +describe "File.owned?" do + it_behaves_like :file_owned, :owned?, File +end + +describe "File.owned?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/path_spec.rb b/1.8/core/file/path_spec.rb new file mode 100644 index 0000000000..d02381fed3 --- /dev/null +++ b/1.8/core/file/path_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File#path" do + before :each do + @file1 = "testfile" + @file2 = "/tmp/../tmp/xxx" + end + + after :each do + File.delete(@file1) if File.exist?(@file1) + File.delete(@file2) if File.exist?(@file2) + end + + it "returns the pathname used to create file as a string" do + File.open(@file1,'w'){|file| file.path.should == "testfile"} + File.open(@file2, 'w'){|file| file.path.should == "/tmp/../tmp/xxx"} + end +end diff --git a/1.8/core/file/pipe_spec.rb b/1.8/core/file/pipe_spec.rb new file mode 100644 index 0000000000..d1de18cbdc --- /dev/null +++ b/1.8/core/file/pipe_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/pipe' + +describe "File.pipe?" do + it_behaves_like :file_pipe, :pipe?, File +end + +describe "File.pipe?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/readable_real_spec.rb b/1.8/core/file/readable_real_spec.rb new file mode 100644 index 0000000000..cc627dc890 --- /dev/null +++ b/1.8/core/file/readable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/readable_real' + +describe "File.readable_real?" do + it_behaves_like :file_readable_real, :readable_real?, File + it_behaves_like :file_readable_real_missing, :readable_real?, File +end diff --git a/1.8/core/file/readable_spec.rb b/1.8/core/file/readable_spec.rb new file mode 100644 index 0000000000..3817b42c58 --- /dev/null +++ b/1.8/core/file/readable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/readable' + +describe "File.readable?" do + it_behaves_like :file_readable, :readable?, File + it_behaves_like :file_readable_missing, :readable?, File +end diff --git a/1.8/core/file/readlink_spec.rb b/1.8/core/file/readlink_spec.rb new file mode 100644 index 0000000000..7ff713d5ec --- /dev/null +++ b/1.8/core/file/readlink_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.readlink" do + + before :each do + @file1 = 'test.txt' + @file3 = 'test.lnk' + File.delete(@file3) if File.exists?(@file3) + + File.open(@file1, 'w+') { } # + File.symlink(@file1, @file3) + end + + after :each do + File.delete(@file1) if File.exists?(@file1) + File.delete(@file3) if File.symlink?(@file3) + end + + it "return the name of the file referenced by the given link" do + File.readlink(@file3).should == @file1 + end + + it "raises an Errno::ENOENT if called with an invalid argument" do + lambda { File.readlink("/this/surely/doesnt/exist") }.should raise_error(Errno::ENOENT) + end +end diff --git a/1.8/core/file/rename_spec.rb b/1.8/core/file/rename_spec.rb new file mode 100644 index 0000000000..dbeca0e2d1 --- /dev/null +++ b/1.8/core/file/rename_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.rename" do + before :each do + @old = "test.txt" + @new = "test.new" + File.delete(@old) if File.exist?(@old) + File.delete(@new) if File.exist?(@new) + File.open(@old,"w+") {|f| f.puts "hello" } + end + + after :each do + File.delete(@old) if File.exist?(@old) + File.delete(@new) if File.exist?(@new) + end + + platform_is_not :windows do + it "renames a file " do + File.exists?(@old).should == true + File.exists?(@new).should == false + File.rename(@old, @new) + File.exists?(@old).should == false + File.exists?(@new).should == true + end + + it "raises an Errno::ENOENT if the source does not exist" do + File.delete(@old) + lambda { File.rename(@old, @new) }.should raise_error(Errno::ENOENT) + end + + it "raises an ArgumentError if not passed two arguments" do + lambda { File.rename }.should raise_error(ArgumentError) + lambda { File.rename(@file) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed String types" do + lambda { File.rename(1, 2) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/file/setgid_spec.rb b/1.8/core/file/setgid_spec.rb new file mode 100644 index 0000000000..0884c52766 --- /dev/null +++ b/1.8/core/file/setgid_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/setgid' + +describe "File.setgid?" do + it_behaves_like :file_setgid, :setgid?, File +end + +describe "File.setgid?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/setuid_spec.rb b/1.8/core/file/setuid_spec.rb new file mode 100644 index 0000000000..e37261361b --- /dev/null +++ b/1.8/core/file/setuid_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/setuid' + +describe "File.setuid?" do + it_behaves_like :file_setuid, :setuid?, File +end + +describe "File.setuid?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/shared/fnmatch.rb b/1.8/core/file/shared/fnmatch.rb new file mode 100644 index 0000000000..7d350e697d --- /dev/null +++ b/1.8/core/file/shared/fnmatch.rb @@ -0,0 +1,158 @@ +shared :file_fnmatch do |cmd| + describe "File.#{cmd}" do + it "matches entire strings" do + File.send(cmd, 'cat', 'cat').should == true + end + + it "does not match partial strings" do + File.send(cmd, 'cat', 'category').should == false + end + + it "does not support { } patterns" do + File.send(cmd, 'c{at,ub}s', 'cats').should == false + File.send(cmd, 'c{at,ub}s', 'c{at,ub}s').should == true + end + + it "matches a single character for each ? character" do + File.send(cmd, 'c?t', 'cat').should == true + File.send(cmd, 'c??t', 'cat').should == false + end + + it "matches zero or more characters for each * character" do + File.send(cmd, 'c*', 'cats').should == true + File.send(cmd, 'c*t', 'c/a/b/t').should == true + end + + it "matches ranges of characters using bracket expresions (e.g. [a-z])" do + File.send(cmd, 'ca[a-z]', 'cat').should == true + end + + it "matches ranges of characters using bracket expresions, taking case into account" do + File.send(cmd, '[a-z]', 'D').should == false + File.send(cmd, '[^a-z]', 'D').should == true + File.send(cmd, '[A-Z]', 'd').should == false + File.send(cmd, '[^A-Z]', 'd').should == true + File.send(cmd, '[a-z]', 'D', File::FNM_CASEFOLD).should == true + end + + it "does not match characters outside of the range of the bracket expresion" do + File.send(cmd, 'ca[x-z]', 'cat').should == false + File.send(cmd, '/ca[s][s-t]/rul[a-b]/[z]he/[x-Z]orld', '/cats/rule/the/World').should == false + end + + it "matches ranges of characters using exclusive bracket expresions (e.g. [^t] or [!t])" do + File.send(cmd, 'ca[^t]', 'cat').should == false + File.send(cmd, 'ca[!t]', 'cat').should == false + end + + it "matches characters with a case sensitive comparison" do + File.send(cmd, 'cat', 'CAT').should == false + end + + it "matches characters with case insensitive comparison when flags includes FNM_CASEFOLD" do + File.send(cmd, 'cat', 'CAT', File::FNM_CASEFOLD).should == true + end + + it "does not match '/' characters with ? or * when flags includes FNM_PATHNAME" do + File.send(cmd, '?', '/', File::FNM_PATHNAME).should == false + File.send(cmd, '*', '/', File::FNM_PATHNAME).should == false + end + + it "does not match '/' characters inside bracket expressions when flags includes FNM_PATHNAME" do + File.send(cmd, '[/]', '/', File::FNM_PATHNAME).should == false + end + + it "matches literal ? or * in path when pattern includes \\? or \\*" do + File.send(cmd, '\?', '?').should == true + File.send(cmd, '\?', 'a').should == false + + File.send(cmd, '\*', '*').should == true + File.send(cmd, '\*', 'a').should == false + end + + it "matches literal character (e.g. 'a') in path when pattern includes escaped character (e.g. \\a)" do + File.send(cmd, '\a', 'a').should == true + File.send(cmd, 'this\b', 'thisb').should == true + end + + it "matches '\\' characters in path when flags includes FNM_NOESACPE" do + File.send(cmd, '\a', '\a', File::FNM_NOESCAPE).should == true + File.send(cmd, '\a', 'a', File::FNM_NOESCAPE).should == false + File.send(cmd, '\[foo\]\[bar\]', '[foo][bar]', File::FNM_NOESCAPE).should == false + end + + it "escapes special characters inside bracket expression" do + File.send(cmd, '[\?]', '?').should == true + File.send(cmd, '[\*]', '*').should == true + end + + it "does not match leading periods in filenames with wildcards by default" do + File.send(cmd, '*', '.profile').should == false + File.send(cmd, '*', 'home/.profile').should == true + File.send(cmd, '*/*', 'home/.profile').should == true + File.send(cmd, '*/*', 'dave/.profile', File::FNM_PATHNAME).should == false + end + + it "matches patterns with leading periods to dotfiles by default" do + File.send(cmd, '.*', '.profile').should == true + File.send(cmd, ".*file", "nondotfile").should == false + end + + it "matches leading periods in filenames when flags includes FNM_DOTMATCH" do + File.send(cmd, '*', '.profile', File::FNM_DOTMATCH).should == true + File.send(cmd, '*', 'home/.profile', File::FNM_DOTMATCH).should == true + end + + it "matches multiple directories with ** and *" do + files = '**/*.rb' + File.send(cmd, files, 'main.rb').should == false + File.send(cmd, files, './main.rb').should == false + File.send(cmd, files, 'lib/song.rb').should == true + File.send(cmd, '**.rb', 'main.rb').should == true + File.send(cmd, '**.rb', './main.rb').should == false + File.send(cmd, '**.rb', 'lib/song.rb').should == true + File.send(cmd, '*', 'dave/.profile').should == true + end + + it "matches multiple directories with ** when flags includes File::FNM_PATHNAME" do + files = '**/*.rb' + File.send(cmd, files, 'main.rb', File::FNM_PATHNAME).should == true + File.send(cmd, files, 'one/two/three/main.rb', File::FNM_PATHNAME).should == true + File.send(cmd, files, './main.rb', File::FNM_PATHNAME).should == false + File.send(cmd, files, './main.rb', File::FNM_PATHNAME| File::FNM_DOTMATCH).should == true + File.send(cmd, files, 'one/two/.main.rb', File::FNM_PATHNAME| File::FNM_DOTMATCH).should == true + File.send(cmd, "**/best/*", 'lib/my/best/song.rb').should == true + end + + it "requires that '/' characters in pattern match '/' characters in path when flags includes FNM_PATHNAME" do + pattern = '*/*' + File.send(cmd, pattern, 'dave/.profile', File::FNM_PATHNAME) + File.send(cmd, pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) + + pattern = '**/foo' + File.send(cmd, pattern, 'a/b/c/foo', File::FNM_PATHNAME) + File.send(cmd, pattern, '/a/b/c/foo', File::FNM_PATHNAME) + File.send(cmd, pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) + File.send(cmd, pattern, 'a/.b/c/foo', File::FNM_PATHNAME) + File.send(cmd, pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) + end + + it "raises a TypeError if the first and second arguments are not string-like" do + lambda { File.send(cmd, nil, nil, 0, 0) }.should raise_error(ArgumentError) + lambda { File.send(cmd, 1, 'some/thing') }.should raise_error(TypeError) + lambda { File.send(cmd, 'some/thing', 1) }.should raise_error(TypeError) + lambda { File.send(cmd, 1, 1) }.should raise_error(TypeError) + end + + it "raises a TypeError if the third argument is not an Integer" do + lambda { File.send(cmd, "*/place", "path/to/file", "flags") }.should raise_error(TypeError) + lambda { File.send(cmd, "*/place", "path/to/file", nil) }.should raise_error(TypeError) + end + + it "does not raise a TypeError if the third argument can be coerced to an Integer" do + flags = mock("flags") + flags.should_receive(:to_int).and_return(10) + lambda { File.send(cmd, "*/place", "path/to/file", flags) }.should_not raise_error + end + end +end diff --git a/1.8/core/file/shared/stat.rb b/1.8/core/file/shared/stat.rb new file mode 100644 index 0000000000..20aa565dbf --- /dev/null +++ b/1.8/core/file/shared/stat.rb @@ -0,0 +1,45 @@ +shared :file_stat do |cmd| + describe "File.#{cmd}" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "returns a File::Stat object if the given file exists" do + st = File.send(cmd, @file) + + st.file?.should == true + st.zero?.should == false + st.size.should == 8 + st.size?.should == 8 + st.blksize.should > 0 + st.atime.class.should == Time + st.ctime.class.should == Time + st.mtime.class.should == Time + end + + it "should be able to use the instance methods" do + st = File.new(@file).send(cmd) + + st.file?.should == true + st.zero?.should == false + st.size.should == 8 + st.size?.should == 8 + st.blksize.should > 0 + st.atime.class.should == Time + st.ctime.class.should == Time + st.mtime.class.should == Time + end + + + it "raises an Errno::ENOENT if the file does not exist" do + lambda { + File.send(cmd, "fake_file") + }.should raise_error(Errno::ENOENT) + end + end +end diff --git a/1.8/core/file/shared/unlink.rb b/1.8/core/file/shared/unlink.rb new file mode 100644 index 0000000000..37f5d9e7bc --- /dev/null +++ b/1.8/core/file/shared/unlink.rb @@ -0,0 +1,54 @@ +shared :file_unlink do |cmd| + describe "File.#{cmd}" do + before :each do + @file1 = 'test.txt' + @file2 = 'test2.txt' + File.send(cmd, @file1) if File.exists?(@file1) + File.send(cmd, @file2) if File.exists?(@file2) + + File.open(@file1, "w") {} # Touch + File.open(@file2, "w") {} # Touch + end + + after :each do + File.send(cmd, @file1) if File.exists?(@file1) + File.send(cmd, @file2) if File.exists?(@file2) + + @file1 = nil + @file2 = nil + end + + it "returns 0 when called without arguments" do + File.send(cmd).should == 0 + end + + it "deletes a single file" do + File.send(cmd, @file1).should == 1 + File.exists?(@file1).should == false + end + + it "deletes multiple files" do + File.send(cmd, @file1, @file2).should == 2 + File.exists?(@file1).should == false + File.exists?(@file2).should == false + end + + it "raises an TypeError if not passed a String type" do + lambda { File.send(cmd, 1) }.should raise_error(TypeError) + end + + it "raises an Errno::ENOENT when the given file doesn't exist" do + lambda { File.send(cmd, 'bogus') }.should raise_error(Errno::ENOENT) + end + + it "coerces a given parameter into a string if possible" do + class Coercable + def to_str + "test.txt" + end + end + + File.send(cmd, Coercable.new).should == 1 + end + end +end diff --git a/1.8/core/file/size_spec.rb b/1.8/core/file/size_spec.rb new file mode 100644 index 0000000000..8cc1f96d62 --- /dev/null +++ b/1.8/core/file/size_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/size' + +describe "File.size" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "returns the size of the file" do + File.size?(@file).should == 8 + end +end + +describe "File.size?" do + it_behaves_like :file_size, :size?, File + it_behaves_like :file_size_missing, :size?, File +end diff --git a/1.8/core/file/socket_spec.rb b/1.8/core/file/socket_spec.rb new file mode 100644 index 0000000000..4a0b2655ea --- /dev/null +++ b/1.8/core/file/socket_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/socket' + +describe "File.socket?" do + it_behaves_like :file_socket, :socket?, File +end + +describe "File.socket?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/split_spec.rb b/1.8/core/file/split_spec.rb new file mode 100644 index 0000000000..214abb25c1 --- /dev/null +++ b/1.8/core/file/split_spec.rb @@ -0,0 +1,55 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.split" do + before :each do + @path_unix = "/foo/bar/baz.rb" + @path_windows_backward = "C:\\foo\\bar\\baz.rb" + @path_windows_forward = "C:/foo/bar/baz.rb" + end + + it "splits the given string into a directory and a file component and returns them in a 2 element array" do + File.split("/rubinius/better/than/ruby").should == ["/rubinius/better/than", "ruby"] + end + + it "splits the given string into a directory and a file component and returns them in a two-element array. (unix)" do + File.split(@path_unix).should == ["/foo/bar","baz.rb"] + end + + it "splits the given string into a directory and a file component and returns them in a two-element array. (edge cases)" do + File.split("").should == [".", ""] + File.split("//foo////").should == ["/", "foo"] + end + + it "splits the given string into a directory and a file component and returns them in a two-element array. (windows)" do + compliant_on :ruby, :rubinius do + File.split(@path_windows_backward).should == [".", "C:\\foo\\bar\\baz.rb"] + end + + # Actually, MRI on windows behaves like this too, and that seems + # to be most proper behavior: + compliant_on :jruby do + File.split(@path_windows_backward).should == ["C:\\foo\\bar", "baz.rb"] + end + + # Note: MRI on Cygwin exhibits third type of behavior, + # different from *both* variants above... + end + + it "splits the given string into a directory and a file component and returns them in a two-element array. (forward slash)" do + File.split(@path_windows_forward).should == ["C:/foo/bar", "baz.rb"] + end + + it "raises an ArgumentError when not passed a single argument" do + lambda { File.split }.should raise_error(ArgumentError) + lambda { File.split('string', 'another string') }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is not a String type" do + lambda { File.split(1) }.should raise_error(TypeError) + end + + it "coerces the argument with to_str if it is not a String type" do + class C; def to_str; "/rubinius/better/than/ruby"; end; end + File.split(C.new).should == ["/rubinius/better/than", "ruby"] + end +end diff --git a/1.8/core/file/stat/atime_spec.rb b/1.8/core/file/stat/atime_spec.rb new file mode 100644 index 0000000000..ac870d44ed --- /dev/null +++ b/1.8/core/file/stat/atime_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#atime" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the atime on a File::Stat object" do + st = File.stat(@file) + st.atime.class.should == Time + st.atime.should <= Time.now + end +end diff --git a/1.8/core/file/stat/blksize_spec.rb b/1.8/core/file/stat/blksize_spec.rb new file mode 100644 index 0000000000..49d2325300 --- /dev/null +++ b/1.8/core/file/stat/blksize_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#blksize" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the blksize on a File::Stat object" do + st = File.stat(@file) + st.blksize.is_a?(Integer).should == true + st.blksize.should > 0 + end +end diff --git a/1.8/core/file/stat/blockdev_spec.rb b/1.8/core/file/stat/blockdev_spec.rb new file mode 100644 index 0000000000..151b903005 --- /dev/null +++ b/1.8/core/file/stat/blockdev_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/blockdev' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#blockdev?" do + it_behaves_like :file_blockdev, :blockdev?, FileStat, "File::Stat#blockdev?" +end diff --git a/1.8/core/file/stat/blocks_spec.rb b/1.8/core/file/stat/blocks_spec.rb new file mode 100644 index 0000000000..a376ea5a64 --- /dev/null +++ b/1.8/core/file/stat/blocks_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#blocks" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the blocks on a File::Stat object" do + st = File.stat(@file) + st.blocks.is_a?(Integer).should == true + st.blocks.should > 0 + end +end diff --git a/1.8/core/file/stat/chardev_spec.rb b/1.8/core/file/stat/chardev_spec.rb new file mode 100644 index 0000000000..dd9ced4b5f --- /dev/null +++ b/1.8/core/file/stat/chardev_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/chardev' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#chardev?" do + it_behaves_like :file_chardev, :chardev?, FileStat, "File::Stat#chardev?" +end diff --git a/1.8/core/file/stat/comparison_spec.rb b/1.8/core/file/stat/comparison_spec.rb new file mode 100644 index 0000000000..a97abe1839 --- /dev/null +++ b/1.8/core/file/stat/comparison_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#<=>" do + + it "is able to compare files by the same modification times" do + f1 = File.new("/tmp/i_exist", "w") + f2 = File.new("/tmp/i_exist_too", "w") + + (f1.stat <=> f2.stat).should == 0 + + File.delete("/tmp/i_exist") if File.exist?("/tmp/i_exist") + File.delete("/tmp/i_exist_too") if File.exist?("/tmp/i_exist_too") + end + + it "is able to compare files by different modification times" do + f1 = File.new("/tmp/i_exist", "w") + f2 = File.new("/tmp/i_exist_too", "w") + + File.utime(Time.now, Time.now + 100, "/tmp/i_exist_too") + (f1.stat <=> f2.stat).should == -1 + + File.utime(Time.now, Time.now - 100, "/tmp/i_exist_too") + (f1.stat <=> f2.stat).should == 1 + + File.delete("/tmp/i_exist") if File.exist?("/tmp/i_exist") + File.delete("/tmp/i_exist_too") if File.exist?("/tmp/i_exist_too") + end + + it "should also include Comparable and thus == shows mtime equality between two File::Stat objects" do + f1 = File.new("/tmp/i_exist", "w") + f2 = File.new("/tmp/i_exist_too", "w") + + (f1.stat == f2.stat).should == true + (f1.stat == f1.stat).should == true + (f2.stat == f2.stat).should == true + + File.utime(Time.now, Time.now + 100, "/tmp/i_exist_too") + + (f1.stat == f2.stat).should == false + (f1.stat == f1.stat).should == true + (f2.stat == f2.stat).should == true + end + +end diff --git a/1.8/core/file/stat/ctime_spec.rb b/1.8/core/file/stat/ctime_spec.rb new file mode 100644 index 0000000000..4c60fb5065 --- /dev/null +++ b/1.8/core/file/stat/ctime_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#ctime" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the ctime on a File::Stat object" do + st = File.stat(@file) + st.ctime.class.should == Time + st.ctime.should <= Time.now + end +end diff --git a/1.8/core/file/stat/dev_major_spec.rb b/1.8/core/file/stat/dev_major_spec.rb new file mode 100644 index 0000000000..1582b6f1df --- /dev/null +++ b/1.8/core/file/stat/dev_major_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#dev_major" do + it "returns the major part of File::Stat#dev" do + File.stat('/dev/null').dev_major.should be_kind_of(Integer) + end +end diff --git a/1.8/core/file/stat/dev_minor_spec.rb b/1.8/core/file/stat/dev_minor_spec.rb new file mode 100644 index 0000000000..28358f8423 --- /dev/null +++ b/1.8/core/file/stat/dev_minor_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#dev_minor" do + it "returns the minor part of File::Stat#dev" do + File.stat('/dev/null').dev_minor.should be_kind_of(Integer) + end +end diff --git a/1.8/core/file/stat/dev_spec.rb b/1.8/core/file/stat/dev_spec.rb new file mode 100644 index 0000000000..d7260e2130 --- /dev/null +++ b/1.8/core/file/stat/dev_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe 'File::Stat#dev' do + it "returns the number of the device on which the file exists" do + File.stat('/dev/null').dev.should be_kind_of(Integer) + end +end diff --git a/1.8/core/file/stat/directory_spec.rb b/1.8/core/file/stat/directory_spec.rb new file mode 100644 index 0000000000..c5732dab19 --- /dev/null +++ b/1.8/core/file/stat/directory_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/directory' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#directory?" do + it_behaves_like :file_directory, :directory?, FileStat, "File::Stat#directory?" +end diff --git a/1.8/core/file/stat/executable_real_spec.rb b/1.8/core/file/stat/executable_real_spec.rb new file mode 100644 index 0000000000..94b3a950a8 --- /dev/null +++ b/1.8/core/file/stat/executable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/executable_real' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#executable_real?" do + it_behaves_like :file_executable_real, :executable_real?, FileStat, "File::Stat#executable_real?" +end diff --git a/1.8/core/file/stat/executable_spec.rb b/1.8/core/file/stat/executable_spec.rb new file mode 100644 index 0000000000..63b8c6bf21 --- /dev/null +++ b/1.8/core/file/stat/executable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/executable' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#executable?" do + it_behaves_like :file_executable, :executable?, FileStat, "File::Stat#executable?" +end diff --git a/1.8/core/file/stat/file_spec.rb b/1.8/core/file/stat/file_spec.rb new file mode 100644 index 0000000000..5bfd89866f --- /dev/null +++ b/1.8/core/file/stat/file_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/file' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#file?" do + it_behaves_like :file_file, :file?, FileStat, "File::Stat#file?" +end diff --git a/1.8/core/file/stat/fixtures/classes.rb b/1.8/core/file/stat/fixtures/classes.rb new file mode 100644 index 0000000000..4fe9a2a30f --- /dev/null +++ b/1.8/core/file/stat/fixtures/classes.rb @@ -0,0 +1,5 @@ +class FileStat + def self.method_missing(meth, file) + File.lstat(file).send(meth) + end +end diff --git a/1.8/core/file/stat/ftype_spec.rb b/1.8/core/file/stat/ftype_spec.rb new file mode 100644 index 0000000000..a901cc6849 --- /dev/null +++ b/1.8/core/file/stat/ftype_spec.rb @@ -0,0 +1,59 @@ +require "#{File.dirname(__FILE__)}/../../../spec_helper" +require "#{File.dirname(__FILE__)}/../fixtures/file_types.rb" + +describe "File::Stat#ftype" do + it "returns a String " do + FileSpecs.normal_file do |file| + File.lstat(file).ftype.class.should == String + end + end + + it "returns 'file' when the file is a file" do + FileSpecs.normal_file do |file| + File.lstat(file).ftype.should == 'file' + end + end + + it "returns 'directory' when the file is a dir" do + FileSpecs.directory do |dir| + File.lstat(dir).ftype.should == 'directory' + end + end + + it "returns 'characterSpecial' when the file is a char" do + FileSpecs.character_device do |char| + File.lstat(char).ftype.should == 'characterSpecial' + end + end + + platform_is_not :freebsd do # FreeBSD does not have block devices + it "returns 'blockSpecial' when the file is a block" do + FileSpecs.block_device do |block| + File.lstat(block).ftype.should == 'blockSpecial' + end + end + end + + it "returns 'link' when the file is a link" do + FileSpecs.symlink do |link| + File.lstat(link).ftype.should == 'link' + end + end + + it "returns fifo when the file is a fifo" do + FileSpecs.fifo do |fifo| + File.lstat(fifo).ftype.should == 'fifo' + end + end + + # This will silently not execute the block if no socket + # can be found. However, if you are running X, there is + # a good chance that if nothing else, at least the X + # Server socket exists. + it "returns 'socket' when the file is a socket" do + FileSpecs.socket do |socket| + File.lstat(socket).ftype.should == 'socket' + end + end +end + diff --git a/1.8/core/file/stat/gid_spec.rb b/1.8/core/file/stat/gid_spec.rb new file mode 100644 index 0000000000..fb6a2fe15d --- /dev/null +++ b/1.8/core/file/stat/gid_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#gid" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + File.chown(nil, Process.gid, @file) + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the group owner through a File::Stat object" do + st = File.stat(@file) + st.gid.is_a?(Integer).should == true + st.gid.should == Process.gid + end +end diff --git a/1.8/core/file/stat/grpowned_spec.rb b/1.8/core/file/stat/grpowned_spec.rb new file mode 100644 index 0000000000..31000fae8c --- /dev/null +++ b/1.8/core/file/stat/grpowned_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/grpowned' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#grpowned?" do + it_behaves_like :file_grpowned, :grpowned?, FileStat, "File::Stat#grpowned?" +end diff --git a/1.8/core/file/stat/ino_spec.rb b/1.8/core/file/stat/ino_spec.rb new file mode 100644 index 0000000000..a162d1939a --- /dev/null +++ b/1.8/core/file/stat/ino_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#ino" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the ino on a File::Stat object" do + st = File.stat(@file) + st.ino.is_a?(Integer).should == true + st.ino.should > 0 + end +end diff --git a/1.8/core/file/stat/inspect_spec.rb b/1.8/core/file/stat/inspect_spec.rb new file mode 100644 index 0000000000..ea9cbfacb4 --- /dev/null +++ b/1.8/core/file/stat/inspect_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#inspect" do + + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "produces a nicely formatted description of a File::Stat object" do + st = File.stat(@file) + #p "#" + st.inspect.should == "#" + + end + + +end diff --git a/1.8/core/file/stat/mode_spec.rb b/1.8/core/file/stat/mode_spec.rb new file mode 100644 index 0000000000..fb2328f996 --- /dev/null +++ b/1.8/core/file/stat/mode_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#mode" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + File.chmod(0755, @file) + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the mode through a File::Stat object" do + st = File.stat(@file) + st.mode.is_a?(Integer).should == true + st.mode.should == 33261 + end +end diff --git a/1.8/core/file/stat/mtime_spec.rb b/1.8/core/file/stat/mtime_spec.rb new file mode 100644 index 0000000000..dde9ea4eab --- /dev/null +++ b/1.8/core/file/stat/mtime_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#mtime" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the mtime on a File::Stat object" do + st = File.stat(@file) + st.mtime.class.should == Time + st.mtime.should <= Time.now + end +end diff --git a/1.8/core/file/stat/new_spec.rb b/1.8/core/file/stat/new_spec.rb new file mode 100644 index 0000000000..26e9b9870b --- /dev/null +++ b/1.8/core/file/stat/new_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#initialize" do + + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + File.chmod(0755, @file) + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "raises an exception if the file doesn't exist" do + lambda { File::Stat.new("/tmp/i_am_a_dummy_file_that_doesnt_exist") }.should raise_error + end + + it "creates a File::Stat object for the given file" do + st = File::Stat.new(@file) + st.class.should == File::Stat + st.ftype.should == 'file' + end + +end diff --git a/1.8/core/file/stat/nlink_spec.rb b/1.8/core/file/stat/nlink_spec.rb new file mode 100644 index 0000000000..48f7184bf8 --- /dev/null +++ b/1.8/core/file/stat/nlink_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#nlink" do + before :each do + @file = "/tmp/stat_nlink" + @link = @file + ".lnk" + File.open(@file, "w") {} + end + + after :each do + File.delete(@file) rescue nil + File.delete(@link) rescue nil + end + + it "returns the number of links to a file" do + File::Stat.new(@file).nlink.should == 1 + File.link(@file, @link) + File::Stat.new(@file).nlink.should == 2 + File.delete(@link) + end +end diff --git a/1.8/core/file/stat/owned_spec.rb b/1.8/core/file/stat/owned_spec.rb new file mode 100644 index 0000000000..7831fa851c --- /dev/null +++ b/1.8/core/file/stat/owned_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/owned' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#owned?" do + it_behaves_like :file_owned, :owned?, FileStat, "File::Stat#owned?" +end + +describe "File::Stat#owned?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/stat/pipe_spec.rb b/1.8/core/file/stat/pipe_spec.rb new file mode 100644 index 0000000000..46f029346f --- /dev/null +++ b/1.8/core/file/stat/pipe_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/pipe' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#pipe?" do + it_behaves_like :file_pipe, :pipe?, FileStat, "File::Stat#pipe?" +end + +describe "File::Stat#pipe?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/stat/rdev_major_spec.rb b/1.8/core/file/stat/rdev_major_spec.rb new file mode 100644 index 0000000000..350a219c4f --- /dev/null +++ b/1.8/core/file/stat/rdev_major_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#rdev_major" do + it "returns the major part of File::Stat#rdev" do + File.stat('/dev/null').rdev_major.should be_kind_of(Integer) + end +end diff --git a/1.8/core/file/stat/rdev_minor_spec.rb b/1.8/core/file/stat/rdev_minor_spec.rb new file mode 100644 index 0000000000..f35db3fdf6 --- /dev/null +++ b/1.8/core/file/stat/rdev_minor_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#rdev_minor" do + it "returns the minor part of File::Stat#rdev" do + File.stat('/dev/null').rdev_minor.should be_kind_of(Integer) + end +end diff --git a/1.8/core/file/stat/rdev_spec.rb b/1.8/core/file/stat/rdev_spec.rb new file mode 100644 index 0000000000..4e1356aaa6 --- /dev/null +++ b/1.8/core/file/stat/rdev_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe 'File::Stat#rdev' do + it "returns the number of the device this file represents which the file exists" do + File.stat('/dev/null').rdev.should be_kind_of(Integer) + end +end diff --git a/1.8/core/file/stat/readable_real_spec.rb b/1.8/core/file/stat/readable_real_spec.rb new file mode 100644 index 0000000000..da179b8b57 --- /dev/null +++ b/1.8/core/file/stat/readable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/readable_real' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#readable_real?" do + it_behaves_like :file_readable_real, :readable_real?, FileStat, "File::Stat#readable_real?" +end diff --git a/1.8/core/file/stat/readable_spec.rb b/1.8/core/file/stat/readable_spec.rb new file mode 100644 index 0000000000..1eaf989639 --- /dev/null +++ b/1.8/core/file/stat/readable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/readable' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#readable?" do + it_behaves_like :file_readable, :readable?, FileStat, "File::Stat#readable?" +end diff --git a/1.8/core/file/stat/setgid_spec.rb b/1.8/core/file/stat/setgid_spec.rb new file mode 100644 index 0000000000..1bd23edefd --- /dev/null +++ b/1.8/core/file/stat/setgid_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/setgid' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#setgid?" do + it_behaves_like :file_setgid, :setgid?, FileStat, "File::Stat#setgid?" +end + +describe "File::Stat#setgid?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/stat/setuid_spec.rb b/1.8/core/file/stat/setuid_spec.rb new file mode 100644 index 0000000000..f4f696c82a --- /dev/null +++ b/1.8/core/file/stat/setuid_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/setuid' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#setuid?" do + it_behaves_like :file_setuid, :setuid?, FileStat, "File::Stat#setuid?" +end + +describe "File::Stat#setuid?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/stat/size_spec.rb b/1.8/core/file/stat/size_spec.rb new file mode 100644 index 0000000000..b3185f723e --- /dev/null +++ b/1.8/core/file/stat/size_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/size' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#size?" do + it_behaves_like :file_size, :size?, FileStat, "File::Stat#size?" +end diff --git a/1.8/core/file/stat/socket_spec.rb b/1.8/core/file/stat/socket_spec.rb new file mode 100644 index 0000000000..e0a5674148 --- /dev/null +++ b/1.8/core/file/stat/socket_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/socket' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#socket?" do + it_behaves_like :file_socket, :socket?, FileStat, "File::Stat#socket?" +end + +describe "File::Stat#socket?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/stat/sticky_spec.rb b/1.8/core/file/stat/sticky_spec.rb new file mode 100644 index 0000000000..a4d960d116 --- /dev/null +++ b/1.8/core/file/stat/sticky_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/sticky' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#sticky?" do + it_behaves_like :file_sticky, :sticky?, FileStat, "File::Stat#sticky?" +end + +describe "File::Stat#sticky?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/stat/symlink_spec.rb b/1.8/core/file/stat/symlink_spec.rb new file mode 100644 index 0000000000..9e28974608 --- /dev/null +++ b/1.8/core/file/stat/symlink_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/symlink' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#symlink?" do + it_behaves_like :file_symlink, :symlink?, FileStat, "File::Stat#symlink?" +end diff --git a/1.8/core/file/stat/uid_spec.rb b/1.8/core/file/stat/uid_spec.rb new file mode 100644 index 0000000000..c7150911f5 --- /dev/null +++ b/1.8/core/file/stat/uid_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "File::Stat#uid" do + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "should be able to determine the owner through a File::Stat object" do + st = File.stat(@file) + st.uid.is_a?(Integer).should == true + st.uid.should == Process.uid + end +end diff --git a/1.8/core/file/stat/writable_real_spec.rb b/1.8/core/file/stat/writable_real_spec.rb new file mode 100644 index 0000000000..e0551a94a5 --- /dev/null +++ b/1.8/core/file/stat/writable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/writable_real' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#writable_real?" do + it_behaves_like :file_writable_real, :writable_real?, FileStat, "File::Stat#writable_real?" +end diff --git a/1.8/core/file/stat/writable_spec.rb b/1.8/core/file/stat/writable_spec.rb new file mode 100644 index 0000000000..0a62e6f1a7 --- /dev/null +++ b/1.8/core/file/stat/writable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/writable' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#writable?" do + it_behaves_like :file_writable, :writable?, FileStat, "File::Stat#writable?" +end diff --git a/1.8/core/file/stat/zero_spec.rb b/1.8/core/file/stat/zero_spec.rb new file mode 100644 index 0000000000..11d2733bad --- /dev/null +++ b/1.8/core/file/stat/zero_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../../../shared/file/zero' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "File::Stat#zero?" do + it_behaves_like :file_zero, :zero?, FileStat, "File::Stat#zero?" +end diff --git a/1.8/core/file/stat_spec.rb b/1.8/core/file/stat_spec.rb new file mode 100644 index 0000000000..9f9907a039 --- /dev/null +++ b/1.8/core/file/stat_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/stat' + +describe "File.stat" do + it_behaves_like :file_stat, :stat +end + +describe "File.stat" do + + before :each do + @file = '/tmp/i_exist' + @link = '/tmp/i_am_a_symlink' + File.open(@file,'w'){|f| f.write 'rubinius'} + File.symlink(@file, @link) + end + + after :each do + File.delete(@link) if File.exist?(@link) + File.delete(@file) if File.exist?(@file) + end + + it "returns a File::Stat object with file properties for a symlink" do + st = File.stat(@link) + + st.file?.should == true + st.symlink?.should == false + end +end diff --git a/1.8/core/file/sticky_spec.rb b/1.8/core/file/sticky_spec.rb new file mode 100644 index 0000000000..4bbbe3f4b7 --- /dev/null +++ b/1.8/core/file/sticky_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/sticky' + +describe "File.sticky?" do + it_behaves_like :file_sticky, :sticky?, File +end + +describe "File.sticky?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/file/symlink_spec.rb b/1.8/core/file/symlink_spec.rb new file mode 100644 index 0000000000..a33c51ce21 --- /dev/null +++ b/1.8/core/file/symlink_spec.rb @@ -0,0 +1,51 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/symlink' + +describe "File.symlink" do + before :each do + @file = "test.txt" + @link = "test.lnk" + File.delete(@link) if File.exist?(@link) + File.delete(@file) if File.exist?(@file) + File.open(@file,"w+") + end + + after :each do + File.unlink(@link) if File.exist?(@link) + File.delete(@file) if File.exist?(@file) + @link = nil + end + + platform_is_not :windows do + it "create a symlink between a source and target file" do + File.symlink(@file, @link).should == 0 + File.exists?(@link).should == true + File.identical?(@file, @link).should == true + end + + it "create a symbolic link" do + File.symlink(@file, @link) + File.symlink?(@link).should == true + end + + it "raises an Errno::EEXIST if the target already exists" do + File.symlink(@file, @link) + lambda { File.symlink(@file, @link) }.should raise_error(Errno::EEXIST) + end + + it "raises an ArgumentError if not called with two arguments" do + lambda { File.symlink }.should raise_error(ArgumentError) + lambda { File.symlink(@file) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not called with String types" do + lambda { File.symlink(@file, nil) }.should raise_error(TypeError) + lambda { File.symlink(@file, 1) }.should raise_error(TypeError) + lambda { File.symlink(1, 1) }.should raise_error(TypeError) + end + end +end + +describe "File.symlink?" do + it_behaves_like :file_symlink, :symlink?, File +end diff --git a/1.8/core/file/truncate_spec.rb b/1.8/core/file/truncate_spec.rb new file mode 100644 index 0000000000..76bfbbab86 --- /dev/null +++ b/1.8/core/file/truncate_spec.rb @@ -0,0 +1,170 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.truncate" do + before :each do + @name = "test.txt" + @file = File.open(@name, 'w') + File.open(@name,"w") { |f| f.write("1234567890") } + end + + after :each do + @file.close + File.delete(@name) if File.exist?(@name) + @name = nil + end + + it "truncates a file" do + File.open(@name, "w") { |f| f.puts "123456789" } + platform_is :windows do + File.size(@name).should == 11 + end + + platform_is_not :windows do + File.size(@name).should == 10 + end + File.truncate(@name, 5) + File.size(@name).should == 5 + File.open(@name, "r") do |f| + f.read(99).should == "12345" + f.eof?.should == true + end + end + + it "truncate a file size to 0" do + File.truncate(@name, 0).should == 0 + IO.read(@name).should == "" + end + + it "truncate a file size to 5" do + File.size(@name).should == 10 + File.truncate(@name, 5) + File.size(@name).should == 5 + IO.read(@name).should == "12345" + end + + it "truncates to a larger file size than the original file" do + File.truncate(@name, 12) + File.size(@name).should == 12 + IO.read(@name).should == "1234567890\000\000" + end + + it "truncates to the same size as the original file" do + File.truncate(@name, File.size(@name)) + File.size(@name).should == 10 + IO.read(@name).should == "1234567890" + end + + it "raises an Errno::ENOENT if the file does not exist" do + not_existing_file = "file-does-not-exist-for-sure.txt" + + # make sure it doesn't exist for real + File.delete(not_existing_file) if File.exist?(not_existing_file) + + begin + lambda { File.truncate(not_existing_file, 5) }.should raise_error(Errno::ENOENT) + ensure + File.delete(not_existing_file) if File.exist?(not_existing_file) + end + end + + it "raises an ArgumentError if not passed two arguments" do + lambda { File.truncate }.should raise_error(ArgumentError) + lambda { File.truncate(@name) }.should raise_error(ArgumentError) + end + + platform_is_not :openbsd do + it "raises an Errno::EINVAL if the length argument is not valid" do + lambda { File.truncate(@name, -1) }.should raise_error(Errno::EINVAL) # May fail + end + end + + it "raises a TypeError if not passed a String type for the first argument" do + lambda { File.truncate(1, 1) }.should raise_error(TypeError) + end + + it "raises a TypeError if not passed an Integer type for the second argument" do + lambda { File.truncate(@name, nil) }.should raise_error(TypeError) + end +end + + +describe "File#truncate" do + before :each do + @name = "test.txt" + @file = File.open(@name, 'w') + File.open(@name,"w") { |f| f.write("1234567890") } + end + + after :each do + @file.close unless @file.closed? + File.delete(@name) if File.exist?(@name) + @name = nil + end + + it "truncates a file" do + File.open(@name, "w") { |f| f.puts "123456789" } + platform_is :windows do + File.size(@name).should == 11 + end + + platform_is_not :windows do + File.size(@name).should == 10 + end + @file.truncate(5) + File.size(@name).should == 5 + File.open(@name, "r") do |f| + f.read(99).should == "12345" + f.eof?.should == true + end + end + + it "truncates a file size to 0" do + @file.truncate(0).should == 0 + IO.read(@name).should == "" + end + + it "truncates a file size to 5" do + File.size(@name).should == 10 + @file.truncate(5) + File.size(@name).should == 5 + IO.read(@name).should == "12345" + end + + it "truncates a file to a larger size than the original file" do + @file.truncate(12) + File.size(@name).should == 12 + IO.read(@name).should == "1234567890\000\000" + end + + it "truncates a file to the same size as the original file" do + @file.truncate(File.size(@name)) + File.size(@name).should == 10 + IO.read(@name).should == "1234567890" + end + + it "raises an ArgumentError if not passed one argument" do + lambda { @file.truncate }.should raise_error(ArgumentError) + lambda { @file.truncate(1) }.should_not raise_error(ArgumentError) + end + + it "raises an Errno::EINVAL if the length argument is not valid" do + lambda { @file.truncate(-1) }.should raise_error(Errno::EINVAL) # May fail + end + + it "raises an IOError if file is closed" do + @file.close + @file.closed?.should == true + lambda { @file.truncate(42) }.should raise_error(IOError) + end + + compliant_on :ruby, :jruby do + it "raises an IOError if file is not opened for writing" do + file = File.new(@name, 'r') + lambda { file.truncate(42) }.should raise_error(IOError) + end + end + + it "raises a TypeError if not passed an Integer type for the for the argument" do + lambda { @file.truncate(nil) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/file/umask_spec.rb b/1.8/core/file/umask_spec.rb new file mode 100644 index 0000000000..f038782a9c --- /dev/null +++ b/1.8/core/file/umask_spec.rb @@ -0,0 +1,61 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.umask" do + before :each do + @orig_umask = File.umask + @file = 'test.txt' + File.open(@file, 'w') {} + end + + after :each do + File.delete(@file) if File.exists?(@file) + @file = nil + File.umask(@orig_umask) + end + + it "return a Fixnum" do + File.umask.class.should == Fixnum + end + + it "umask should return the current umask value for the process" do + File.umask(022) + File.umask(006).should == 022 + File.umask.should == 006 + end + + it "invokes to_int on non-integer argument" do + (obj = mock(022)).should_receive(:to_int).any_number_of_times.and_return(022) + File.umask(obj) + File.umask(obj).should == 022 + end + + it "always succeeds with any integer values" do + vals = [-2**30, -2**16, -2**8, -2, + -1.5, -1, 0.5, 0, 1, 2, 7.77777, 16, 32, 64, 2**8, 2**16, 2**30] + vals.each { |v| + lambda { File.umask(v) }.should_not raise_error + } + end + + it "raises ArgumentError when more than one argument is provided" do + lambda { File.umask(022, 022) }.should raise_error(ArgumentError) + end + + platform_is :windows do + it "Returns the current umask value for this process. (basic)" do + File.umask.should == 0 + end + + # The value used here is the value of _S_IWRITE. + it "Returns the current umask value for this process." do + File.umask(0000200) + File.umask.should == 0000200 + end + + # FIXME: wtf? + it "raises an exception if the arguments are wrong type or are the incorect number of arguments " do + File.umask(0006) + File.umask.should == 0 + end + end +end diff --git a/1.8/core/file/unlink_spec.rb b/1.8/core/file/unlink_spec.rb new file mode 100644 index 0000000000..4dfae740f6 --- /dev/null +++ b/1.8/core/file/unlink_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/unlink' + +describe "File.unlink" do + it_behaves_like(:file_unlink, :unlink) +end diff --git a/1.8/core/file/utime_spec.rb b/1.8/core/file/utime_spec.rb new file mode 100644 index 0000000000..11479d6539 --- /dev/null +++ b/1.8/core/file/utime_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "File.utime" do + before :each do + @atime = Time.now + @mtime = Time.now + @file1 = "/tmp/specs_file_utime1" + @file2 = "/tmp/specs_file_utime2" + File.open(@file1, "w") {} + File.open(@file2, "w") {} + end + + after :each do + File.delete(@file1) if File.exist?(@file1) + File.delete(@file2) if File.exist?(@file2) + end + + it "sets the access and modification time of each file" do + File.utime(@atime, @mtime, @file1, @file2) + File.atime(@file1).to_i.should be_close(@atime.to_i, 2) + File.mtime(@file1).to_i.should be_close(@mtime.to_i, 2) + File.atime(@file2).to_i.should be_close(@atime.to_i, 2) + File.mtime(@file2).to_i.should be_close(@mtime.to_i, 2) + end +end diff --git a/1.8/core/file/writable_real_spec.rb b/1.8/core/file/writable_real_spec.rb new file mode 100644 index 0000000000..d3c03ec16b --- /dev/null +++ b/1.8/core/file/writable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/writable_real' + +describe "File.writable_real?" do + it_behaves_like :file_writable_real, :writable_real?, File + it_behaves_like :file_writable_real_missing, :writable_real?, File +end diff --git a/1.8/core/file/writable_spec.rb b/1.8/core/file/writable_spec.rb new file mode 100644 index 0000000000..3b515527e6 --- /dev/null +++ b/1.8/core/file/writable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/writable' + +describe "File.writable?" do + it_behaves_like :file_writable, :writable?, File + it_behaves_like :file_writable_missing, :writable?, File +end diff --git a/1.8/core/file/zero_spec.rb b/1.8/core/file/zero_spec.rb new file mode 100644 index 0000000000..d0829f7e45 --- /dev/null +++ b/1.8/core/file/zero_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/zero' + +describe "File.zero?" do + it_behaves_like :file_zero, :zero?, File + it_behaves_like :file_zero_missing, :zero?, File +end diff --git a/1.8/core/filetest/blockdev_spec.rb b/1.8/core/filetest/blockdev_spec.rb new file mode 100644 index 0000000000..0031888130 --- /dev/null +++ b/1.8/core/filetest/blockdev_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/blockdev' + +describe "FileTest.blockdev?" do + it_behaves_like :file_blockdev, :blockdev?, FileTest +end diff --git a/1.8/core/filetest/chardev_spec.rb b/1.8/core/filetest/chardev_spec.rb new file mode 100644 index 0000000000..431c6c66e1 --- /dev/null +++ b/1.8/core/filetest/chardev_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/chardev' + +describe "FileTest.chardev?" do + it_behaves_like :file_chardev, :chardev?, FileTest +end diff --git a/1.8/core/filetest/directory_spec.rb b/1.8/core/filetest/directory_spec.rb new file mode 100644 index 0000000000..454143b01d --- /dev/null +++ b/1.8/core/filetest/directory_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/directory' + +describe "FileTest.directory?" do + it_behaves_like :file_directory, :directory?, FileTest +end diff --git a/1.8/core/filetest/executable_real_spec.rb b/1.8/core/filetest/executable_real_spec.rb new file mode 100644 index 0000000000..6e02dfb7c4 --- /dev/null +++ b/1.8/core/filetest/executable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/executable_real' + +describe "FileTest.executable_real?" do + it_behaves_like :file_executable_real, :executable_real?, FileTest + it_behaves_like :file_executable_real_missing, :executable_real?, FileTest +end diff --git a/1.8/core/filetest/executable_spec.rb b/1.8/core/filetest/executable_spec.rb new file mode 100644 index 0000000000..fa794bad9e --- /dev/null +++ b/1.8/core/filetest/executable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/executable' + +describe "FileTest.executable?" do + it_behaves_like :file_executable, :executable?, FileTest + it_behaves_like :file_executable_missing, :executable?, FileTest +end diff --git a/1.8/core/filetest/exist_spec.rb b/1.8/core/filetest/exist_spec.rb new file mode 100644 index 0000000000..f5fc1e9111 --- /dev/null +++ b/1.8/core/filetest/exist_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/exist' + +describe "FileTest.exist?" do + it_behaves_like :file_exist, :exist?, FileTest +end diff --git a/1.8/core/filetest/exists_spec.rb b/1.8/core/filetest/exists_spec.rb new file mode 100644 index 0000000000..57e4451635 --- /dev/null +++ b/1.8/core/filetest/exists_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/exist' + +describe "FileTest.exists?" do + it_behaves_like :file_exist, :exists?, FileTest +end diff --git a/1.8/core/filetest/file_spec.rb b/1.8/core/filetest/file_spec.rb new file mode 100644 index 0000000000..0782028ed9 --- /dev/null +++ b/1.8/core/filetest/file_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/file' + +describe "File.file?" do + it_behaves_like :file_file, :file?, File +end diff --git a/1.8/core/filetest/grpowned_spec.rb b/1.8/core/filetest/grpowned_spec.rb new file mode 100644 index 0000000000..766880c628 --- /dev/null +++ b/1.8/core/filetest/grpowned_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/grpowned' + +describe "FileTest.grpowned?" do + it_behaves_like :file_grpowned, :grpowned?, FileTest +end diff --git a/1.8/core/filetest/identical_spec.rb b/1.8/core/filetest/identical_spec.rb new file mode 100644 index 0000000000..0c1e87a7fb --- /dev/null +++ b/1.8/core/filetest/identical_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/identical' + +describe "FileTest.identical?" do + it_behaves_like :file_identical, :identical?, FileTest +end diff --git a/1.8/core/filetest/owned_spec.rb b/1.8/core/filetest/owned_spec.rb new file mode 100644 index 0000000000..e1eb15c049 --- /dev/null +++ b/1.8/core/filetest/owned_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/owned' + +describe "FileTest.owned?" do + it_behaves_like :file_owned, :owned?, FileTest +end diff --git a/1.8/core/filetest/pipe_spec.rb b/1.8/core/filetest/pipe_spec.rb new file mode 100644 index 0000000000..b73cc16daa --- /dev/null +++ b/1.8/core/filetest/pipe_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/pipe' + +describe "FileTest.pipe?" do + it_behaves_like :file_pipe, :pipe?, FileTest +end diff --git a/1.8/core/filetest/readable_real_spec.rb b/1.8/core/filetest/readable_real_spec.rb new file mode 100644 index 0000000000..5a3508d7c7 --- /dev/null +++ b/1.8/core/filetest/readable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/readable_real' + +describe "FileTest.readable_real?" do + it_behaves_like :file_readable_real, :readable_real?, FileTest + it_behaves_like :file_readable_real_missing, :readable_real?, FileTest +end diff --git a/1.8/core/filetest/readable_spec.rb b/1.8/core/filetest/readable_spec.rb new file mode 100644 index 0000000000..c55bd3ebc4 --- /dev/null +++ b/1.8/core/filetest/readable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/readable' + +describe "FileTest.readable?" do + it_behaves_like :file_readable, :readable?, FileTest + it_behaves_like :file_readable_missing, :readable?, FileTest +end diff --git a/1.8/core/filetest/setgid_spec.rb b/1.8/core/filetest/setgid_spec.rb new file mode 100644 index 0000000000..00e181aa16 --- /dev/null +++ b/1.8/core/filetest/setgid_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/setgid' + +describe "FileTest.setgid?" do + it_behaves_like :file_setgid, :setgid?, FileTest +end diff --git a/1.8/core/filetest/setuid_spec.rb b/1.8/core/filetest/setuid_spec.rb new file mode 100644 index 0000000000..31752bef4b --- /dev/null +++ b/1.8/core/filetest/setuid_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/setuid' + +describe "FileTest.setuid?" do + it_behaves_like :file_setuid, :setuid?, FileTest +end diff --git a/1.8/core/filetest/size_spec.rb b/1.8/core/filetest/size_spec.rb new file mode 100644 index 0000000000..181dd20be6 --- /dev/null +++ b/1.8/core/filetest/size_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/size' + +describe "FileTest.size?" do + it_behaves_like :file_size, :size?, FileTest + it_behaves_like :file_size_missing, :size?, FileTest +end diff --git a/1.8/core/filetest/socket_spec.rb b/1.8/core/filetest/socket_spec.rb new file mode 100644 index 0000000000..20ac7b182e --- /dev/null +++ b/1.8/core/filetest/socket_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/socket' + +describe "FileTest.socket?" do + it_behaves_like :file_socket, :socket?, FileTest +end diff --git a/1.8/core/filetest/sticky_spec.rb b/1.8/core/filetest/sticky_spec.rb new file mode 100644 index 0000000000..1027fda06e --- /dev/null +++ b/1.8/core/filetest/sticky_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/sticky' + +describe "FileTest.sticky?" do + it_behaves_like :file_sticky, :sticky?, FileTest +end diff --git a/1.8/core/filetest/symlink_spec.rb b/1.8/core/filetest/symlink_spec.rb new file mode 100644 index 0000000000..320ec1c047 --- /dev/null +++ b/1.8/core/filetest/symlink_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/symlink' + +describe "FileTest.symlink?" do + it_behaves_like :file_symlink, :symlink?, FileTest +end diff --git a/1.8/core/filetest/writable_real_spec.rb b/1.8/core/filetest/writable_real_spec.rb new file mode 100644 index 0000000000..b7aa4f5f98 --- /dev/null +++ b/1.8/core/filetest/writable_real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/writable_real' + +describe "FileTest.writable_real?" do + it_behaves_like :file_writable_real, :writable_real?, FileTest + it_behaves_like :file_writable_real_missing, :writable_real?, FileTest +end diff --git a/1.8/core/filetest/writable_spec.rb b/1.8/core/filetest/writable_spec.rb new file mode 100644 index 0000000000..225660442b --- /dev/null +++ b/1.8/core/filetest/writable_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/writable' + +describe "FileTest.writable?" do + it_behaves_like :file_writable, :writable?, FileTest + it_behaves_like :file_writable_missing, :writable?, FileTest +end diff --git a/1.8/core/filetest/zero_spec.rb b/1.8/core/filetest/zero_spec.rb new file mode 100644 index 0000000000..e225fbe15a --- /dev/null +++ b/1.8/core/filetest/zero_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../../shared/file/zero' + +describe "FileTest.zero?" do + it_behaves_like :file_zero, :zero?, FileTest + it_behaves_like :file_zero_missing, :zero?, FileTest +end diff --git a/1.8/core/fixnum/abs_spec.rb b/1.8/core/fixnum/abs_spec.rb new file mode 100644 index 0000000000..7ad9980046 --- /dev/null +++ b/1.8/core/fixnum/abs_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#abs" do + it "returns self's absolute value" do + { 0 => [0, -0, +0], 2 => [2, -2, +2], 100 => [100, -100, +100] }.each do |key, values| + values.each do |value| + value.abs.should == key + end + end + end +end diff --git a/1.8/core/fixnum/bit_and_spec.rb b/1.8/core/fixnum/bit_and_spec.rb new file mode 100644 index 0000000000..6d3d34f67a --- /dev/null +++ b/1.8/core/fixnum/bit_and_spec.rb @@ -0,0 +1,51 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#&" do + it "returns self bitwise AND other" do + (256 & 16).should == 0 + (2010 & 5).should == 0 + (65535 & 1).should == 1 + (0xffff & bignum_value + 0xffff_ffff).should == 65535 + end + + it "should be able to AND a bignum with a fixnum" do + (-1 & 2**64).should == 18446744073709551616 + end + + it "raises a RangeError if passed a Float out of Fixnum range" do + lambda { 1 & bignum_value(10000).to_f }.should raise_error(RangeError) + lambda { 1 & -bignum_value(10000).to_f }.should raise_error(RangeError) + end + + it "tries to convert it's argument to an Integer using to_int" do + (3 & 2.4).should == 2 + + (obj = mock('2')).should_receive(:to_int).and_return(2) + (3 & obj).should == 2 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { 3 & obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { 3 & obj }.should raise_error(TypeError) + end + + # On Rubinius this works ok. This failure is actually a bug in MRI, because there is + # no reason it should fail, especially because it can do & on a fixnum and bignum. + # See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/15838 + not_compliant_on :rubinius do + it "raises a RangeError when the given argument is out of range of Integer" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + lambda { 3 & obj }.should raise_error(RangeError) + end + end + + deviates_on :rubinius do + it "coerces arguments correctly even if it is a Bignum" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + (3 & obj).should == 0 + end + end +end diff --git a/1.8/core/fixnum/bit_or_spec.rb b/1.8/core/fixnum/bit_or_spec.rb new file mode 100644 index 0000000000..3b286ea586 --- /dev/null +++ b/1.8/core/fixnum/bit_or_spec.rb @@ -0,0 +1,52 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#|" do + it "returns self bitwise OR other" do + (1 | 0).should == 1 + (5 | 4).should == 5 + (5 | 6).should == 7 + (248 | 4096).should == 4344 + (0xffff | bignum_value + 0xf0f0).should == 0x8000_0000_0000_ffff + end + + it "should be able to AND a bignum with a fixnum" do + (-1 | 2**64).should == -1 + end + + it "raises a RangeError if passed a Float out of Fixnum range" do + lambda { 1 | bignum_value(10000).to_f }.should raise_error(RangeError) + lambda { 1 | -bignum_value(10000).to_f }.should raise_error(RangeError) + end + + it "tries to convert the given argument to an Integer using to_int" do + (5 | 4.3).should == 5 + + (obj = mock('4')).should_receive(:to_int).and_return(4) + (3 | obj).should == 7 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { 3 | obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { 3 | obj }.should raise_error(TypeError) + end + + # On Rubinius this works ok. This failure is actually a bug in MRI, because there is + # no reason it should fail, especially because it can do & on a fixnum and bignum. + # See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/15838 + not_compliant_on :rubinius do + it "raises a RangeError when the given argument is out of range of Integer" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + lambda { 3 | obj }.should raise_error(RangeError) + end + end + + deviates_on :rubinius do + it "coerces arguments correctly even if it is a Bignum" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + (3 | obj).should == 80000000000000000003 + end + end +end diff --git a/1.8/core/fixnum/bit_xor_spec.rb b/1.8/core/fixnum/bit_xor_spec.rb new file mode 100644 index 0000000000..4d080fca19 --- /dev/null +++ b/1.8/core/fixnum/bit_xor_spec.rb @@ -0,0 +1,51 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#^" do + it "returns self bitwise EXCLUSIVE OR other" do + (3 ^ 5).should == 6 + (-7 ^ 15.2).should == -10 + (-2 ^ -255).should == 255 + (5 ^ bignum_value + 0xffff_ffff).should == 0x8000_0000_ffff_fffa + end + + it "should be able to AND a bignum with a fixnum" do + (-1 ^ 2**64).should == -18446744073709551617 + end + + it "raises a RangeError if passed a Float out of Fixnum range" do + lambda { 1 ^ bignum_value(10000).to_f }.should raise_error(RangeError) + lambda { 1 ^ -bignum_value(10000).to_f }.should raise_error(RangeError) + end + + it "tries to convert the given argument to an Integer using to_int" do + (5 ^ 4.3).should == 1 + + (obj = mock('4')).should_receive(:to_int).and_return(4) + (3 ^ obj).should == 7 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { 3 ^ obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { 3 ^ obj }.should raise_error(TypeError) + end + + # On Rubinius this works ok. This failure is actually a bug in MRI, because there is + # no reason it should fail, especially because it can do & on a fixnum and bignum. + # See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/15838 + not_compliant_on :rubinius do + it "raises a RangeError when the given argument is out of range of Integer" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + lambda { 3 ^ obj }.should raise_error(RangeError) + end + end + + deviates_on :rubinius do + it "coerces arguments correctly even if it is a Bignum" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + (3 ^ obj).should == 80000000000000000003 + end + end +end diff --git a/1.8/core/fixnum/coerce_spec.rb b/1.8/core/fixnum/coerce_spec.rb new file mode 100644 index 0000000000..72315b7cb5 --- /dev/null +++ b/1.8/core/fixnum/coerce_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#coerce when given a Fixnum" do + it "returns an array containing two Fixnums" do + 1.coerce(2).should == [2, 1] + 1.coerce(2).map { |i| i.class }.should == [Fixnum, Fixnum] + end +end + +describe "Fixnum#coerce when given a String" do + it "raises an ArgumentError when trying to coerce with a non-number String" do + lambda { 1.coerce(":)") }.should raise_error(ArgumentError) + end + + it "returns an array containing two Floats" do + 1.coerce("2").should == [2.0, 1.0] + 1.coerce("-2").should == [-2.0, 1.0] + end +end + +describe "Fixnum#coerce" do + it "raises a TypeError when trying to coerce with nil" do + lambda { 1.coerce(nil) }.should raise_error(TypeError) + end + + it "tries to convert the given Object into a Float by using #to_f" do + (obj = mock('1.0')).should_receive(:to_f).and_return(1.0) + 2.coerce(obj).should == [1.0, 2.0] + + (obj = mock('0')).should_receive(:to_f).and_return('0') + lambda { 2.coerce(obj).should == [1.0, 2.0] }.should raise_error(TypeError) + end + + it "raises a TypeError when given an Object that does not respond to #to_f" do + lambda { 1.coerce(mock('x')) }.should raise_error(TypeError) + lambda { 1.coerce(1..4) }.should raise_error(TypeError) + lambda { 1.coerce(:test) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/fixnum/comparison_spec.rb b/1.8/core/fixnum/comparison_spec.rb new file mode 100644 index 0000000000..e73785c9b1 --- /dev/null +++ b/1.8/core/fixnum/comparison_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#<=>" do + it "returns -1 when self is less than the given argument" do + (-3 <=> -1).should == -1 + (-5 <=> 10).should == -1 + (-5 <=> -4.5).should == -1 + end + + it "returns 0 when self is equal to the given argument" do + (0 <=> 0).should == 0 + (954 <=> 954).should == 0 + (954 <=> 954.0).should == 0 + end + + it "returns 1 when self is greater than the given argument" do + (496 <=> 5).should == 1 + (200 <=> 100).should == 1 + (51 <=> 50.5).should == 1 + end + + it "returns nil when the given argument is not an Integer" do + (3 <=> mock('x')).should == nil + (3 <=> 'test').should == nil + end +end diff --git a/1.8/core/fixnum/complement_spec.rb b/1.8/core/fixnum/complement_spec.rb new file mode 100644 index 0000000000..4d19d4779f --- /dev/null +++ b/1.8/core/fixnum/complement_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#~" do + it "returns self with each bit flipped" do + (~0).should == -1 + (~1221).should == -1222 + (~-2).should == 1 + (~-599).should == 598 + end +end diff --git a/1.8/core/fixnum/div_spec.rb b/1.8/core/fixnum/div_spec.rb new file mode 100644 index 0000000000..743af42659 --- /dev/null +++ b/1.8/core/fixnum/div_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#div with a Fixnum" do + it "returns self divided by the given argument as an Integer" do + 2.div(2).should == 1 + 1.div(2).should == 0 + 5.div(2).should == 2 + end +end + +describe "Fixnum#div" do + it "rounds towards -inf" do + 8192.div(10).should == 819 + 8192.div(-10).should == -820 + (-8192).div(10).should == -820 + (-8192).div(-10).should == 819 + end + + it "coerces self and the given argument to Floats and returns self divided by other as Fixnum" do + 1.div(0.2).should == 5 + 1.div(0.16).should == 6 + 1.div(0.169).should == 5 + -1.div(50.4).should == -1 + 1.div(bignum_value).should == 0 + end + + it "raises a FloatDomainError when the given argument is 0 and a Float" do + lambda { 0.div(0.0) }.should raise_error(FloatDomainError) + lambda { 10.div(0.0) }.should raise_error(FloatDomainError) + lambda { -10.div(0.0) }.should raise_error(FloatDomainError) + end + + it "raises a ZeroDivisionError when the given argument is 0" do + lambda { 13.div(0) }.should raise_error(ZeroDivisionError) + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + 13.div(obj) + }.should raise_error(TypeError) + lambda { 5.div("2") }.should raise_error(TypeError) + end +end diff --git a/1.8/core/fixnum/divide_spec.rb b/1.8/core/fixnum/divide_spec.rb new file mode 100644 index 0000000000..7067c1ebad --- /dev/null +++ b/1.8/core/fixnum/divide_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#/" do + it "returns self divided by the given argument" do + (2 / 2).should == 1 + (3 / 2).should == 1 + end + + it "raises a ZeroDivisionError if the given argument is zero and not a Float" do + lambda { 1 / 0 }.should raise_error(ZeroDivisionError) + end + + it "does NOT raise ZeroDivisionError if the given argument is zero and is a Float" do + (1 / 0.0).to_s.should == 'Infinity' + (-1 / 0.0).to_s.should == '-Infinity' + end + + it "coerces fixnum and return self divided by other" do + (-1 / 50.4).should be_close(-0.0198412698412698, TOLERANCE) + (1 / bignum_value).should == 0 + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + 13 / obj + }.should raise_error(TypeError) + lambda { 13 / "10" }.should raise_error(TypeError) + lambda { 13 / :symbol }.should raise_error(TypeError) + end +end diff --git a/1.8/core/fixnum/divmod_spec.rb b/1.8/core/fixnum/divmod_spec.rb new file mode 100644 index 0000000000..a0857fe521 --- /dev/null +++ b/1.8/core/fixnum/divmod_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#divmod" do + it "returns an Array containing quotient and modulus obtained from dividing self by the given argument" do + 13.divmod(4).should == [3, 1] + 4.divmod(13).should == [0, 4] + + 13.divmod(4.0).should == [3, 1] + 4.divmod(13.0).should == [0, 4] + + 1.divmod(2.0).should == [0, 1.0] + 200.divmod(bignum_value).should == [0, 200] + end + + it "raises a ZeroDivisionError when the given argument is 0" do + lambda { 13.divmod(0) }.should raise_error(ZeroDivisionError) + lambda { 0.divmod(0) }.should raise_error(ZeroDivisionError) + lambda { -10.divmod(0) }.should raise_error(ZeroDivisionError) + end + + it "raises a FloatDomainError when the given argument is 0 and a Float" do + lambda { 0.divmod(0.0) }.should raise_error(FloatDomainError) + lambda { 10.divmod(0.0) }.should raise_error(FloatDomainError) + lambda { -10.divmod(0.0) }.should raise_error(FloatDomainError) + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + 13.divmod(obj) + }.should raise_error(TypeError) + lambda { 13.divmod("10") }.should raise_error(TypeError) + lambda { 13.divmod(:symbol) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/fixnum/element_reference_spec.rb b/1.8/core/fixnum/element_reference_spec.rb new file mode 100644 index 0000000000..a218c0ffb4 --- /dev/null +++ b/1.8/core/fixnum/element_reference_spec.rb @@ -0,0 +1,51 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#[]" do + it "returns the nth bit in the binary representation of self" do + 2[3].should == 0 + 15[1].should == 1 + + 2[3].should == 0 + 3[0xffffffff].should == 0 + 3[-0xffffffff].should == 0 + end + + it "tries to convert the given argument to an Integer using #to_int" do + 15[1.3].should == 15[1] + + (obj = mock('1')).should_receive(:to_int).and_return(1) + 2[obj].should == 1 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { 3[obj] }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { 3[obj] }.should raise_error(TypeError) + end + + # On Rubinius this works ok. This failure is actually a bug in MRI, because there is + # no reason it should fail, especially because it can do & on a fixnum and bignum. + # See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/15838 + not_compliant_on :rubinius do + it "raises a RangeError when the given argument is out of range of Integer" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + lambda { 3[obj] }.should raise_error(RangeError) + + obj = 8e19 + lambda { 3[obj] }.should raise_error(RangeError) + end + end + + deviates_on :rubinius do + it "coerces arguments correctly even if it is a Bignum" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + 3[obj].should == 0 + obj = 8e19 + + 3[obj].should == 0 + end + end + +end diff --git a/1.8/core/fixnum/equal_value_spec.rb b/1.8/core/fixnum/equal_value_spec.rb new file mode 100644 index 0000000000..b5e96eeb6a --- /dev/null +++ b/1.8/core/fixnum/equal_value_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#==" do + it "returns true if self has the same value as other" do + (1 == 1).should == true + (9 == 5).should == false + + # Actually, these call Float#==, Bignum#== etc. + (9 == 9.0).should == true + (9 == 9.01).should == false + + (10 == bignum_value).should == false + end + + it "calls 'other == self' if the given argument is not a Fixnum" do + (1 == '*').should == false + + obj = mock('one other') + obj.should_receive(:==).any_number_of_times.and_return(false) + 1.should_not == obj + + obj = mock('another') + obj.should_receive(:==).any_number_of_times.and_return(true) + 2.should == obj + end +end diff --git a/1.8/core/fixnum/exponent_spec.rb b/1.8/core/fixnum/exponent_spec.rb new file mode 100644 index 0000000000..e060f7fc76 --- /dev/null +++ b/1.8/core/fixnum/exponent_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#**" do + it "returns self raised to the given power" do + (2 ** 0).should == 1 + (2 ** 1).should == 2 + (2 ** 2).should == 4 + + (9 ** 0.5).to_s.should == '3.0' + (5 ** -1).to_f.to_s.should == '0.2' + + (2 ** 40).should == 1099511627776 + end + + conflicts_with :Rational do + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + 13 ** obj + }.should raise_error(TypeError) + lambda { 13 ** "10" }.should raise_error(TypeError) + lambda { 13 ** :symbol }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/fixnum/gt_spec.rb b/1.8/core/fixnum/gt_spec.rb new file mode 100644 index 0000000000..b3edb8b131 --- /dev/null +++ b/1.8/core/fixnum/gt_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#>" do + it "returns true if self is greater than the given argument" do + (13 > 2).should == true + (-500 > -600).should == true + + (1 > 5).should == false + (5 > 5).should == false + + (900 > bignum_value).should == false + (5 > 4.999).should == true + end + + it "raises an ArgumentError when given a non-Integer" do + lambda { 5 > "4" }.should raise_error(ArgumentError) + lambda { 5 > mock('x') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/fixnum/gte_spec.rb b/1.8/core/fixnum/gte_spec.rb new file mode 100644 index 0000000000..320cdf00cf --- /dev/null +++ b/1.8/core/fixnum/gte_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#>=" do + it "returns true if self is greater than or equal to the given argument" do + (13 >= 2).should == true + (-500 >= -600).should == true + + (1 >= 5).should == false + (2 >= 2).should == true + (5 >= 5).should == true + + (900 >= bignum_value).should == false + (5 >= 4.999).should == true + end + + it "raises an ArgumentError when given a non-Integer" do + lambda { 5 >= "4" }.should raise_error(ArgumentError) + lambda { 5 >= mock('x') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/fixnum/hash_spec.rb b/1.8/core/fixnum/hash_spec.rb new file mode 100644 index 0000000000..8c91e8df88 --- /dev/null +++ b/1.8/core/fixnum/hash_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#hash" do + it "is provided" do + 1.respond_to?(:hash).should == true + end + + it "is stable" do + 1.hash.should == 1.hash + end +end diff --git a/1.8/core/fixnum/id2name_spec.rb b/1.8/core/fixnum/id2name_spec.rb new file mode 100644 index 0000000000..f01b097b0d --- /dev/null +++ b/1.8/core/fixnum/id2name_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#id2name" do + + not_compliant_on :rubinius do + it "returns the string name of the object whose symbol ID is self" do + a = :@sym + b = :@ruby + c = :@rubinius + a.to_i.id2name.should == '@sym' + b.to_i.id2name.should == '@ruby' + c.to_i.id2name.should == '@rubinius' + end + + it "returns nil if there is no symbol in the symbol table with this value" do + 100000000.id2name.should == nil + end + end +end diff --git a/1.8/core/fixnum/induced_from_spec.rb b/1.8/core/fixnum/induced_from_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/fixnum/induced_from_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/fixnum/left_shift_spec.rb b/1.8/core/fixnum/left_shift_spec.rb new file mode 100644 index 0000000000..e21dedecd7 --- /dev/null +++ b/1.8/core/fixnum/left_shift_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#<<" do + it "returns self shifted the given amount of bits to the left" do + (7 << 2).should == 28 + (9 << 4).should == 144 + end + + it "performs a right-shift if given a negative value" do + (7 << -2).should == (7 >> 2) + (9 << -4).should == (9 >> 4) + end + + it "coerces result on overflow and return self shifted left other bits" do + (9 << 4.2).should == 144 + (6 << 0xff).should == 347376267711948586270712955026063723559809953996921692118372752023739388919808 + end + + it "tries to convert its argument to an Integer using to_int" do + (5 << 4.3).should == 80 + + (obj = mock('4')).should_receive(:to_int).and_return(4) + (3 << obj).should == 48 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { 3 << obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { 3 << obj }.should raise_error(TypeError) + end + + it "raises a RangeError when the given argument is out of range of Integer" do + (obj = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + lambda { 3 << obj }.should raise_error(RangeError) + + obj = 8e19 + lambda { 3 << obj }.should raise_error(RangeError) + end +end diff --git a/1.8/core/fixnum/lt_spec.rb b/1.8/core/fixnum/lt_spec.rb new file mode 100644 index 0000000000..7ee283bbec --- /dev/null +++ b/1.8/core/fixnum/lt_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#<" do + it "returns true if self is less than the given argument" do + (2 < 13).should == true + (-600 < -500).should == true + + (5 < 1).should == false + (5 < 5).should == false + + (900 < bignum_value).should == true + (5 < 4.999).should == false + end + + it "raises an ArgumentError when given a non-Integer" do + lambda { 5 < "4" }.should raise_error(ArgumentError) + lambda { 5 < mock('x') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/fixnum/lte_spec.rb b/1.8/core/fixnum/lte_spec.rb new file mode 100644 index 0000000000..b7713bc2f4 --- /dev/null +++ b/1.8/core/fixnum/lte_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#<=" do + it "returns true if self is less than or equal to other" do + (2 <= 13).should == true + (-600 <= -500).should == true + + (5 <= 1).should == false + (5 <= 5).should == true + (-2 <= -2).should == true + + (900 <= bignum_value).should == true + (5 <= 4.999).should == false + end + + it "raises an ArgumentError when given a non-Integer" do + lambda { 5 <= "4" }.should raise_error(ArgumentError) + lambda { 5 <= mock('x') }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/fixnum/minus_spec.rb b/1.8/core/fixnum/minus_spec.rb new file mode 100644 index 0000000000..694c2484a3 --- /dev/null +++ b/1.8/core/fixnum/minus_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#-" do + it "returns self minus the given Integer" do + (5 - 10).should == -5 + (9237212 - 5_280).should == 9231932 + + (781 - 0.5).should == 780.5 + (2_560_496 - bignum_value).should == -9223372036852215312 + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + 13 - obj + }.should raise_error(TypeError) + lambda { 13 - "10" }.should raise_error(TypeError) + lambda { 13 - :symbol }.should raise_error(TypeError) + end +end diff --git a/1.8/core/fixnum/modulo_spec.rb b/1.8/core/fixnum/modulo_spec.rb new file mode 100644 index 0000000000..fe5f0cbd0c --- /dev/null +++ b/1.8/core/fixnum/modulo_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/modulo' + +describe "Fixnum#%" do + it_behaves_like(:fixnum_modulo, :%) +end + +describe "Fixnum#modulo" do + it_behaves_like(:fixnum_modulo, :modulo) +end diff --git a/1.8/core/fixnum/multiply_spec.rb b/1.8/core/fixnum/multiply_spec.rb new file mode 100644 index 0000000000..fd33f61c05 --- /dev/null +++ b/1.8/core/fixnum/multiply_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#*" do + it "returns self multiplied by the given Integer" do + (4923 * 2).should == 9846 + (1342177 * 800).should == 1073741600 + (65536 * 65536).should == 4294967296 + + (256 * bignum_value).should == 2361183241434822606848 + (6712 * 0.25).should == 1678.0 + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + 13 * obj + }.should raise_error(TypeError) + lambda { 13 * "10" }.should raise_error(TypeError) + lambda { 13 * :symbol }.should raise_error(TypeError) + end +end diff --git a/1.8/core/fixnum/plus_spec.rb b/1.8/core/fixnum/plus_spec.rb new file mode 100644 index 0000000000..99ec5cd6ee --- /dev/null +++ b/1.8/core/fixnum/plus_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#+" do + it "returns self plus the given Integer" do + (491 + 2).should == 493 + (90210 + 10).should == 90220 + + (9 + bignum_value).should == 9223372036854775817 + (1001 + 5.219).should == 1006.219 + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + 13 + obj + }.should raise_error(TypeError) + lambda { 13 + "10" }.should raise_error(TypeError) + lambda { 13 + :symbol }.should raise_error(TypeError) + end +end diff --git a/1.8/core/fixnum/quo_spec.rb b/1.8/core/fixnum/quo_spec.rb new file mode 100644 index 0000000000..0c7f161578 --- /dev/null +++ b/1.8/core/fixnum/quo_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#quo" do + it "returns the result of self divided by the given Integer as a Float" do + 2.quo(2.5).should == 0.8 + 5.quo(2).should == 2.5 + 45.quo(bignum_value).should be_close(1.04773789668636e-08, TOLERANCE) + end + + conflicts_with :Rational do + it "does not raise a ZeroDivisionError when the given Integer is 0" do + 0.quo(0).to_s.should == "NaN" + 10.quo(0).to_s.should == "Infinity" + -10.quo(0).to_s.should == "-Infinity" + end + end + + it "does not raise a FloatDomainError when the given Integer is 0 and a Float" do + 0.quo(0.0).to_s.should == "NaN" + 10.quo(0.0).to_s.should == "Infinity" + -10.quo(0.0).to_s.should == "-Infinity" + end + + conflicts_with :Rational do + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('x')).should_not_receive(:to_int) + 13.quo(obj) + }.should raise_error(TypeError) + lambda { 13.quo("10") }.should raise_error(TypeError) + lambda { 13.quo(:symbol) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/fixnum/right_shift_spec.rb b/1.8/core/fixnum/right_shift_spec.rb new file mode 100644 index 0000000000..524f82bbad --- /dev/null +++ b/1.8/core/fixnum/right_shift_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#>>" do + it "returns self shifted the given amount of bits to the right" do + (7 >> 1).should == 3 + (4095 >> 3).should == 511 + (9245278 >> 1).should == 4622639 + end + + it "performs a left-shift if given a negative value" do + (7 >> -1).should == (7 << 1) + (4095 >> -3).should == (4095 << 3) + end + + it "performs a right-shift if given a negative value" do + (-7 >> 1).should == -4 + (-4095 >> 3).should == -512 + end + + it "tries to convert it's argument to an Integer using to_int" do + (7 >> 1.3).should == 3 + + (obj = mock('1')).should_receive(:to_int).and_return(1) + (7 >> obj).should == 3 + end + + it "raises a TypeError when the given argument can't be converted to Integer" do + obj = mock('asdf') + lambda { 3 >> obj }.should raise_error(TypeError) + + obj.should_receive(:to_int).and_return("asdf") + lambda { 3 >> obj }.should raise_error(TypeError) + end + + it "does not raise RangeError when the given argument is out of range of Integer" do + (obj1 = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + (obj2 = mock('large value')).should_receive(:to_int).and_return(8000_0000_0000_0000_0000) + (3 >> obj1).should == 0 + (-3 >> obj2).should == -1 + + obj = 8e19 + (3 >> obj).should == 0 + (-3 >> obj).should == -1 + end + + +end diff --git a/1.8/core/fixnum/shared/modulo.rb b/1.8/core/fixnum/shared/modulo.rb new file mode 100644 index 0000000000..9cfabde41c --- /dev/null +++ b/1.8/core/fixnum/shared/modulo.rb @@ -0,0 +1,35 @@ +shared :fixnum_modulo do |cmd| + describe "Fixnum##{cmd}" do + it "returns the modulus obtained from dividing self by the given argument" do + 13.send(cmd, 4).should == 1 + 4.send(cmd, 13).should == 4 + + 13.send(cmd, 4.0).should == 1 + 4.send(cmd, 13.0).should == 4 + + 1.send(cmd, 2.0).should == 1.0 + 200.send(cmd, bignum_value).should == 200 + end + + it "raises a ZeroDivisionError when the given argument is 0" do + lambda { 13.send(cmd, 0) }.should raise_error(ZeroDivisionError) + lambda { 0.send(cmd, 0) }.should raise_error(ZeroDivisionError) + lambda { -10.send(cmd, 0) }.should raise_error(ZeroDivisionError) + end + + it "does not raise a FloatDomainError when the given argument is 0 and a Float" do + 0.send(cmd, 0.0).to_s.should == "NaN" + 10.send(cmd, 0.0).to_s.should == "NaN" + -10.send(cmd, 0.0).to_s.should == "NaN" + end + + it "raises a TypeError when given a non-Integer" do + lambda { + (obj = mock('10')).should_receive(:to_int).any_number_of_times.and_return(10) + 13.send(cmd, obj) + }.should raise_error(TypeError) + lambda { 13.send(cmd, "10") }.should raise_error(TypeError) + lambda { 13.send(cmd, :symbol) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/fixnum/size_spec.rb b/1.8/core/fixnum/size_spec.rb new file mode 100644 index 0000000000..501a721b99 --- /dev/null +++ b/1.8/core/fixnum/size_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#size" do + platform_is :wordsize => 32 do + it "returns the number of bytes in the machine representation of self" do + -1.size.should == 4 + 0.size.should == 4 + 4091.size.should == 4 + end + end + + platform_is :wordsize => 64 do + it "returns the number of bytes in the machine representation of self" do + -1.size.should == 8 + 0.size.should == 8 + 4091.size.should == 8 + end + end +end diff --git a/1.8/core/fixnum/to_f_spec.rb b/1.8/core/fixnum/to_f_spec.rb new file mode 100644 index 0000000000..ba26681e3c --- /dev/null +++ b/1.8/core/fixnum/to_f_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#to_f" do + it "returns self converted to a Float" do + 0.to_f.should == 0.0 + -500.to_f.should == -500.0 + 9_641_278.to_f.should == 9641278.0 + end +end diff --git a/1.8/core/fixnum/to_s_spec.rb b/1.8/core/fixnum/to_s_spec.rb new file mode 100644 index 0000000000..fb9ea00091 --- /dev/null +++ b/1.8/core/fixnum/to_s_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#to_s when given a base" do + it "returns self converted to a String in the given base" do + 12345.to_s(2).should == "11000000111001" + 12345.to_s(8).should == "30071" + 12345.to_s(10).should == "12345" + 12345.to_s(16).should == "3039" + 12345.to_s(36).should == "9ix" + end + + it "raises an ArgumentError if the base is less than 2 or higher than 36" do + lambda { 123.to_s(-1) }.should raise_error(ArgumentError) + lambda { 123.to_s(0) }.should raise_error(ArgumentError) + lambda { 123.to_s(1) }.should raise_error(ArgumentError) + lambda { 123.to_s(37) }.should raise_error(ArgumentError) + end +end + +describe "Fixnum#to_s when no base given" do + it "returns self converted to a String using base 10" do + 255.to_s.should == '255' + 3.to_s.should == '3' + 0.to_s.should == '0' + -9002.to_s.should == '-9002' + end +end diff --git a/1.8/core/fixnum/to_sym_spec.rb b/1.8/core/fixnum/to_sym_spec.rb new file mode 100644 index 0000000000..465a5e869e --- /dev/null +++ b/1.8/core/fixnum/to_sym_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#to_sym" do + not_compliant_on :rubinius do + it "returns the symbol whose integer value is self" do + a = :@sym + b = :@ruby + c = :@rubinius + + a.to_i.to_sym.should == :@sym + b.to_i.to_sym.should == :@ruby + c.to_i.to_sym.should == :@rubinius + end + + it "returns nil if there is no symbol in the symbol table with this value" do + 100000000.to_sym.should == nil + end + + end +end diff --git a/1.8/core/fixnum/uminus_spec.rb b/1.8/core/fixnum/uminus_spec.rb new file mode 100644 index 0000000000..1d524ba26a --- /dev/null +++ b/1.8/core/fixnum/uminus_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#-@" do + it "returns self as a negative value" do + 2.send(:-@).should == -2 + -2.should == -2 + -268435455.should == -268435455 + (--5).should == 5 + -8.send(:-@).should == 8 + end +end diff --git a/1.8/core/fixnum/zero_spec.rb b/1.8/core/fixnum/zero_spec.rb new file mode 100644 index 0000000000..fa0850a0ac --- /dev/null +++ b/1.8/core/fixnum/zero_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Fixnum#zero?" do + it "returns true if self is 0" do + 0.zero?.should == true + -1.zero?.should == false + 1.zero?.should == false + end +end diff --git a/1.8/core/float/abs_spec.rb b/1.8/core/float/abs_spec.rb new file mode 100644 index 0000000000..32ce97a582 --- /dev/null +++ b/1.8/core/float/abs_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#abs" do + it "returns the absolute value" do + -99.1.abs.should be_close(99.1, TOLERANCE) + 4.5.abs.should be_close(4.5, TOLERANCE) + 0.0.abs.should be_close(0.0, TOLERANCE) + end +end diff --git a/1.8/core/float/ceil_spec.rb b/1.8/core/float/ceil_spec.rb new file mode 100644 index 0000000000..90e3a89628 --- /dev/null +++ b/1.8/core/float/ceil_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#ceil" do + it "returns the smallest Integer greater than or equal to self" do + -1.2.ceil.should == -1 + -1.0.ceil.should == -1 + 0.0.ceil.should == 0 + 1.3.ceil.should == 2 + 3.0.ceil.should == 3 + -9223372036854775808.1.ceil.should == -9223372036854775808 + 9223372036854775808.1.ceil.should == 9223372036854775808 + end +end diff --git a/1.8/core/float/coerce_spec.rb b/1.8/core/float/coerce_spec.rb new file mode 100644 index 0000000000..bbea40e795 --- /dev/null +++ b/1.8/core/float/coerce_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#coerce" do + it "returns [other, self] both as Floats" do + 1.2.coerce(1).should == [1.0, 1.2] + 5.28.coerce(1.0).should == [1.0, 5.28] + 1.0.coerce(1).should == [1.0, 1.0] + 1.0.coerce("2.5").should == [2.5, 1.0] + 1.0.coerce(3.14).should == [3.14, 1.0] + + a, b = -0.0.coerce(bignum_value) + a.should be_close(9223372036854775808.000, TOLERANCE) + b.should be_close(-0.0, TOLERANCE) + a, b = 1.0.coerce(bignum_value) + a.should be_close(9223372036854775808.000, TOLERANCE) + b.should be_close(1.0, TOLERANCE) + end +end diff --git a/1.8/core/float/comparison_spec.rb b/1.8/core/float/comparison_spec.rb new file mode 100644 index 0000000000..1f85dd3ee2 --- /dev/null +++ b/1.8/core/float/comparison_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#<=>" do + it "returns -1, 0, 1 when self is less than, equal, or greater than other" do + (1.5 <=> 5).should == -1 + (2.45 <=> 2.45).should == 0 + ((bignum_value*1.1) <=> bignum_value).should == 1 + end +end diff --git a/1.8/core/float/constants_spec.rb b/1.8/core/float/constants_spec.rb new file mode 100644 index 0000000000..96561564e0 --- /dev/null +++ b/1.8/core/float/constants_spec.rb @@ -0,0 +1,53 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#CONSTANTS" do + specify "the DIG value is 15" do + Float::DIG.should == 15 + end + + it "the EPSILON value is " do + Float::EPSILON.should == 0.0000000000000002220446049250313080847263336181640625 + end + + it "the MANT_DIG is 53" do + Float::MANT_DIG.should == 53 + end + + it "the MAX_10_EXP is 308" do + Float::MAX_10_EXP.should == 308 + end + + it "the MIN_10_EXP is -308" do + Float::MIN_10_EXP.should == -307 + end + + it "the MAX_EXP is 1024" do + Float::MAX_EXP.should == 1024 + end + + it "the MIN_EXP is -1021" do + Float::MIN_EXP.should == -1021 + end + + it "the MAX is 1.79769313486232e+308" do + Float::MAX.should == 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 + end + + # TODO: file a bug report for MRI + not_compliant_on :ruby, :jruby do + it "the MIN is 2.2250738585072e-308" do + Float::MIN.should == 2.225073858507201383090232717332404064219215980462331830553327416887204434813918195854283159012511020564067339731035811005152434161553460108856012385377718821130777993532002330479610147442583636071921565046942503734208375250806650616658158948720491179968591639648500635908770118304874799780887753749949451580451605050915399856582470818645113537935804992115981085766051992433352114352390148795699609591288891602992641511063466313393663477586513029371762047325631781485664350872122828637642044846811407613911477062801689853244110024161447421618567166150540154285084716752901903161322778896729707373123334086988983175067838846926092773977972858659654941091369095406136467568702398678315290680984617210924625396728515625e-308 + end + end + + # TODO: Does this actually constitute noncompliance? + deviates_on :jruby do + it "the MIN is 4.9e-324" do + Float::MIN.should == 4.9e-324 + end + end + + it "the RADIX is 2" do + Float::RADIX.should == 2 + end +end diff --git a/1.8/core/float/divide_spec.rb b/1.8/core/float/divide_spec.rb new file mode 100644 index 0000000000..6cbb2b5ba8 --- /dev/null +++ b/1.8/core/float/divide_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#/" do + it "returns self divided by other" do + (5.75 / -2).should be_close(-2.875,TOLERANCE) + (451.0 / 9.3).should be_close(48.494623655914,TOLERANCE) + (91.1 / -0xffffffff).should be_close(-2.12108716418061e-08, TOLERANCE) + end + + it "does NOT raise ZeroDivisionError if other is zero" do + (1.0 / 0.0).to_s.should == 'Infinity' + (-1.0 / 0.0).to_s.should == '-Infinity' + (1.0 / -0.0).to_s.should == '-Infinity' + (-1.0 / -0.0).to_s.should == 'Infinity' + (0.0 / 0.0).to_s.should == 'NaN' + (-0.0 / 0.0).to_s.should == 'NaN' + (-0.0 / -0.0).to_s.should == 'NaN' + end +end diff --git a/1.8/core/float/divmod_spec.rb b/1.8/core/float/divmod_spec.rb new file mode 100644 index 0000000000..4e0a6808dc --- /dev/null +++ b/1.8/core/float/divmod_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#divmod" do + it "returns an [quotient, modulus] from dividing self by other" do + values = 3.14.divmod(2) + values[0].should == 1 + values[1].should be_close(1.14, TOLERANCE) + values = 2.8284.divmod(3.1415) + values[0].should == 0 + values[1].should be_close(2.8284, TOLERANCE) + values = -1.0.divmod(bignum_value) + values[0].should == -1 + values[1].should be_close(9223372036854775808.000, TOLERANCE) + end + + it "raises FloatDomainError if other is zero" do + lambda { 1.0.divmod(0) }.should raise_error(FloatDomainError) + lambda { 1.0.divmod(0.0) }.should raise_error(FloatDomainError) + end +end diff --git a/1.8/core/float/eql_spec.rb b/1.8/core/float/eql_spec.rb new file mode 100644 index 0000000000..1b61151834 --- /dev/null +++ b/1.8/core/float/eql_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#eql?" do + it "returns true if other is a Float equal to self" do + 1.0.eql?(1).should == false + 0.0.eql?(0.0).should == true + end +end diff --git a/1.8/core/float/equal_value_spec.rb b/1.8/core/float/equal_value_spec.rb new file mode 100644 index 0000000000..893ed09cb4 --- /dev/null +++ b/1.8/core/float/equal_value_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#==" do + it "returns true if self has the same value as other" do + (1.0 == 1).should == true + (2.71828 == 1.428).should == false + (-4.2 == 4.2).should == false + end + + it "calls 'other == self' if coercion fails" do + class X; def ==(other); 2.0 == other; end; end + + (1.0 == X.new).should == false + (2.0 == X.new).should == true + end +end diff --git a/1.8/core/float/exponent_spec.rb b/1.8/core/float/exponent_spec.rb new file mode 100644 index 0000000000..78821c8819 --- /dev/null +++ b/1.8/core/float/exponent_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#**" do + it "returns self raise to the other power" do + (2.3 ** 3).should be_close(12.167,TOLERANCE) + (5.2 ** -1).should be_close(0.192307692307692,TOLERANCE) + (9.5 ** 0.5).should be_close(3.08220700148449, TOLERANCE) + (9.5 ** 0xffffffff).to_s.should == 'Infinity' + end +end diff --git a/1.8/core/float/finite_spec.rb b/1.8/core/float/finite_spec.rb new file mode 100644 index 0000000000..050125d4c0 --- /dev/null +++ b/1.8/core/float/finite_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#finite?" do + it "returns true if a valid IEEE floating-point number" do + (1.5**0xffffffff).finite?.should == false + 3.14159.finite?.should == true + (-1.0/0.0).finite?.should == false + end +end diff --git a/1.8/core/float/floor_spec.rb b/1.8/core/float/floor_spec.rb new file mode 100644 index 0000000000..7acf713632 --- /dev/null +++ b/1.8/core/float/floor_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#floor" do + it "returns the largest Integer less than or equal to self" do + -1.2.floor.should == -2 + -1.0.floor.should == -1 + 0.0.floor.should == 0 + 1.0.floor.should == 1 + 5.9.floor.should == 5 + -9223372036854775808.1.floor.should == -9223372036854775808 + 9223372036854775808.1.floor.should == 9223372036854775808 + end +end diff --git a/1.8/core/float/gt_spec.rb b/1.8/core/float/gt_spec.rb new file mode 100644 index 0000000000..f44e81c070 --- /dev/null +++ b/1.8/core/float/gt_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#>" do + it "returns true if self is greater than other" do + (1.5 > 1).should == true + (2.5 > 3).should == false + (45.91 > bignum_value).should == false + end +end diff --git a/1.8/core/float/gte_spec.rb b/1.8/core/float/gte_spec.rb new file mode 100644 index 0000000000..bf987ca07e --- /dev/null +++ b/1.8/core/float/gte_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#>=" do + it "returns true if self is greater than or equal to other" do + (5.2 >= 5.2).should == true + (9.71 >= 1).should == true + (5.55382 >= 0xfabdafbafcab).should == false + end +end diff --git a/1.8/core/float/hash_spec.rb b/1.8/core/float/hash_spec.rb new file mode 100644 index 0000000000..87a7758244 --- /dev/null +++ b/1.8/core/float/hash_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#hash" do + it "is provided" do + 0.0.respond_to?(:hash).should == true + end + + it "is stable" do + 1.0.hash.should == 1.0.hash + end +end diff --git a/1.8/core/float/induced_from_spec.rb b/1.8/core/float/induced_from_spec.rb new file mode 100644 index 0000000000..69228bd174 --- /dev/null +++ b/1.8/core/float/induced_from_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float.induced_from" do + it "returns the argument when passed a Float" do + Float.induced_from(5.5).eql?(5.5).should == true + end + + it "returns a Float of the correct value when sent a Fixnum" do + Float.induced_from(36).should == 36.0 + end + + it "returns a Float of the correct value when sent a Bignum" do + Float.induced_from(23472398472349872349872349872348972348972439423).should be_close(2.34723984723499e+46, 0.00003e+46) + end + + it "raises a TypeError if the argument is not a Float, Fixnum, or Bignum" do + class Foo + def to_f; 9.9; end + end + lambda { Float.induced_from(Foo.new) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/float/infinite_spec.rb b/1.8/core/float/infinite_spec.rb new file mode 100644 index 0000000000..6c700e6622 --- /dev/null +++ b/1.8/core/float/infinite_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#infinite?" do + it "returns nil, -1, +1 when self is finite, -Infinity, +Infinity" do + 1.0.infinite?.should == nil + (1.0/0.0).infinite?.should == 1 + (1.0/-0.0).infinite?.should == -1 + end +end diff --git a/1.8/core/float/lt_spec.rb b/1.8/core/float/lt_spec.rb new file mode 100644 index 0000000000..8ef88c1470 --- /dev/null +++ b/1.8/core/float/lt_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#<" do + it "returns true if self is less than other" do + (71.3 < 91.8).should == true + (192.6 < -500).should == false + (-0.12 < 0x4fffffff).should == true + end +end diff --git a/1.8/core/float/lte_spec.rb b/1.8/core/float/lte_spec.rb new file mode 100644 index 0000000000..5b36c687a2 --- /dev/null +++ b/1.8/core/float/lte_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#<=" do + it "returns true if self is less than or equal to other" do + (2.0 <= 3.14159).should == true + (-2.7183 <= -24).should == false + (0.0 <= 0.0).should == true + (9_235.9 <= bignum_value).should == true + end +end diff --git a/1.8/core/float/minus_spec.rb b/1.8/core/float/minus_spec.rb new file mode 100644 index 0000000000..8a3dc6fc7f --- /dev/null +++ b/1.8/core/float/minus_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#-" do + it "returns self minus other" do + (9_237_212.5280 - 5_280).should be_close(9231932.528, TOLERANCE) + (2_560_496.1691 - bignum_value).should be_close(-9223372036852215808.000, TOLERANCE) + (5.5 - 5.5).should be_close(0.0,TOLERANCE) + end +end diff --git a/1.8/core/float/modulo_spec.rb b/1.8/core/float/modulo_spec.rb new file mode 100644 index 0000000000..2a2c7ee00c --- /dev/null +++ b/1.8/core/float/modulo_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/modulo' + +describe "Float#%" do + it_behaves_like(:float_modulo, :%) +end + +describe "Float#modulo" do + it_behaves_like(:float_modulo, :modulo) +end diff --git a/1.8/core/float/multiply_spec.rb b/1.8/core/float/multiply_spec.rb new file mode 100644 index 0000000000..0f5f26264d --- /dev/null +++ b/1.8/core/float/multiply_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#*" do + it "returns self multiplied by other" do + (4923.98221 * 2).should be_close(9847.96442, TOLERANCE) + (6712.5 * 0.25).should be_close(1678.125, TOLERANCE) + (256.4096 * bignum_value).should be_close(2364961134621118431232.000, TOLERANCE) + end +end diff --git a/1.8/core/float/nan_spec.rb b/1.8/core/float/nan_spec.rb new file mode 100644 index 0000000000..49e33ca2ef --- /dev/null +++ b/1.8/core/float/nan_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#nan?" do + it "returns true if self is not a valid IEEE floating-point number" do + 0.0.nan?.should == false + -1.5.nan?.should == false + (0.0/0.0).nan?.should == true + end +end diff --git a/1.8/core/float/plus_spec.rb b/1.8/core/float/plus_spec.rb new file mode 100644 index 0000000000..e871d52723 --- /dev/null +++ b/1.8/core/float/plus_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#+" do + it "returns self plus other" do + (491.213 + 2).should be_close(493.213, TOLERANCE) + (9.99 + bignum_value).should be_close(9223372036854775808.000, TOLERANCE) + (1001.99 + 5.219).should be_close(1007.209, TOLERANCE) + end +end diff --git a/1.8/core/float/round_spec.rb b/1.8/core/float/round_spec.rb new file mode 100644 index 0000000000..2e83d4fe27 --- /dev/null +++ b/1.8/core/float/round_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#round" do + it "returns the nearest Integer" do + 5.5.round.should == 6 + 0.4.round.should == 0 + -2.8.round.should == -3 + 0.0.round.should == 0 + end +end diff --git a/1.8/core/float/shared/modulo.rb b/1.8/core/float/shared/modulo.rb new file mode 100644 index 0000000000..9e4155b6ed --- /dev/null +++ b/1.8/core/float/shared/modulo.rb @@ -0,0 +1,18 @@ +shared :float_modulo do |cmd| + describe "Float##{cmd}" do + it "returns self modulo other" do + 6543.21.send(cmd, 137).should be_close(104.21, TOLERANCE) + 5667.19.send(cmd, bignum_value).should be_close(5667.19, TOLERANCE) + 6543.21.send(cmd, 137.24).should be_close(92.9299999999996, TOLERANCE) + + 6543.21.send(cmd, 137).should be_close(6543.21.%(137), TOLERANCE) + 5667.19.send(cmd, bignum_value).should be_close(5667.19.%(0xffffffff), TOLERANCE) + 6543.21.send(cmd, 137.24).should be_close(6543.21.%(137.24), TOLERANCE) + end + + it "does NOT raise ZeroDivisionError if other is zero" do + 1.0.send(cmd, 0).to_s.should == 'NaN' + 1.0.send(cmd, 0.0).to_s.should == 'NaN' + end + end +end diff --git a/1.8/core/float/shared/to_i.rb b/1.8/core/float/shared/to_i.rb new file mode 100644 index 0000000000..81139d62bc --- /dev/null +++ b/1.8/core/float/shared/to_i.rb @@ -0,0 +1,12 @@ +shared :float_to_i do |cmd| + describe "Float##{cmd}" do + it "returns self truncated to an Integer" do + 899.2.send(cmd).should == 899 + -1.122256e-45.send(cmd).should == 0 + 5_213_451.9201.send(cmd).should == 5213451 + 1.233450999123389e+12.send(cmd).should == 1233450999123 + -9223372036854775808.1.send(cmd).should == -9223372036854775808 + 9223372036854775808.1.send(cmd).should == 9223372036854775808 + end + end +end diff --git a/1.8/core/float/to_f_spec.rb b/1.8/core/float/to_f_spec.rb new file mode 100644 index 0000000000..7351ee1159 --- /dev/null +++ b/1.8/core/float/to_f_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#to_f" do + it "returns self" do + -500.3.to_f.should == -500.3 + 267.51.to_f.should == 267.51 + 1.1412.to_f.should == 1.1412 + end +end diff --git a/1.8/core/float/to_i_spec.rb b/1.8/core/float/to_i_spec.rb new file mode 100644 index 0000000000..4f37cd3b9e --- /dev/null +++ b/1.8/core/float/to_i_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Float#to_i" do + it_behaves_like(:float_to_i, :to_i) +end diff --git a/1.8/core/float/to_int_spec.rb b/1.8/core/float/to_int_spec.rb new file mode 100644 index 0000000000..13da0fc937 --- /dev/null +++ b/1.8/core/float/to_int_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Float#" do + it_behaves_like(:float_to_i, :to_int) +end diff --git a/1.8/core/float/to_s_spec.rb b/1.8/core/float/to_s_spec.rb new file mode 100644 index 0000000000..f8e7012775 --- /dev/null +++ b/1.8/core/float/to_s_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#to_s" do + it "returns a string representation of self, possibly Nan, -Infinity, +Infinity" do + 0.551e7.to_s.should == "5510000.0" + -3.14159.to_s.should == "-3.14159" + 0.0.to_s.should == "0.0" + 1000000000000.to_f.to_s.should == "1000000000000.0" + 10000000000000.to_f.to_s.should == "10000000000000.0" + 100000000000000.to_f.to_s.should == "1.0e+14" + 1.87687113714737e-40.to_s.should == "1.87687113714737e-40" + (0.0 / 0.0).to_s.should == "NaN" + (1.0 / 0.0).to_s.should == "Infinity" + (-1.0 / 0.0).to_s.should == "-Infinity" + 1.50505000e-20.to_s.should == "1.50505e-20" + end + + platform_is_not :openbsd do + it "returns the correct values for -0.0" do + -0.0.to_s.should == "-0.0" + end + end +end diff --git a/1.8/core/float/truncate_spec.rb b/1.8/core/float/truncate_spec.rb new file mode 100644 index 0000000000..4ba9e4bc38 --- /dev/null +++ b/1.8/core/float/truncate_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Float#truncate" do + it_behaves_like(:float_to_i, :truncate) +end diff --git a/1.8/core/float/uminus_spec.rb b/1.8/core/float/uminus_spec.rb new file mode 100644 index 0000000000..93f1a36756 --- /dev/null +++ b/1.8/core/float/uminus_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#-@" do + it "negates self" do + (2.221.send(:-@)).should be_close(-2.221, TOLERANCE) + -2.01.should be_close(-2.01,TOLERANCE) + -2_455_999_221.5512.should be_close(-2455999221.5512, TOLERANCE) + (--5.5).should be_close(5.5, TOLERANCE) + -8.551.send(:-@).should be_close(8.551, TOLERANCE) + end +end diff --git a/1.8/core/float/uplus_spec.rb b/1.8/core/float/uplus_spec.rb new file mode 100644 index 0000000000..47b4cf7425 --- /dev/null +++ b/1.8/core/float/uplus_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#+@" do + it "returns the same value with same sign (twos complement)" do + 34.56.send(:+@).should == 34.56 + -34.56.send(:+@).should == -34.56 + 0.0.send(:+@).should == 0.0 + end +end diff --git a/1.8/core/float/zero_spec.rb b/1.8/core/float/zero_spec.rb new file mode 100644 index 0000000000..69e9f3da83 --- /dev/null +++ b/1.8/core/float/zero_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#zero?" do + it "returns true if self is 0.0" do + 0.0.zero?.should == true + 1.0.zero?.should == false + -1.0.zero?.should == false + end +end diff --git a/1.8/core/gc/disable_spec.rb b/1.8/core/gc/disable_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/gc/disable_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/gc/enable_spec.rb b/1.8/core/gc/enable_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/gc/enable_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/gc/garbage_collect_spec.rb b/1.8/core/gc/garbage_collect_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/gc/garbage_collect_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/gc/start_spec.rb b/1.8/core/gc/start_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/gc/start_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/hash/allocate_spec.rb b/1.8/core/hash/allocate_spec.rb new file mode 100644 index 0000000000..8863c1c47f --- /dev/null +++ b/1.8/core/hash/allocate_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Hash.allocate" do + it "returns an instance of Hash" do + hsh = Hash.allocate + hsh.should be_kind_of(Hash) + end + + it "returns a fully-formed instance of Hash" do + hsh = Hash.allocate + hsh.size.should == 0 + hsh[:a] = 1 + hsh.should == { :a => 1 } + end +end diff --git a/1.8/core/hash/clear_spec.rb b/1.8/core/hash/clear_spec.rb new file mode 100644 index 0000000000..2f11696037 --- /dev/null +++ b/1.8/core/hash/clear_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#clear" do + it "removes all key, value pairs" do + h = { 1 => 2, 3 => 4 } + h.clear.equal?(h).should == true + h.should == {} + end + + it "does not remove default values and procs" do + h = Hash.new(5) + h.clear + h.default.should == 5 + + h = Hash.new { 5 } + h.clear + h.default_proc.should_not == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + lambda { HashSpecs.frozen_hash.clear }.should raise_error(TypeError) + lambda { HashSpecs.empty_frozen_hash.clear }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/hash/clone_spec.rb b/1.8/core/hash/clone_spec.rb new file mode 100644 index 0000000000..0801e55e7c --- /dev/null +++ b/1.8/core/hash/clone_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Hash#clone" do + it "clones" do + hash = { 'key' => 'value' } + + clone = hash.clone + + clone.should == hash + clone.object_id.should_not == hash.object_id + end +end + diff --git a/1.8/core/hash/default_proc_spec.rb b/1.8/core/hash/default_proc_spec.rb new file mode 100644 index 0000000000..2dac0425ab --- /dev/null +++ b/1.8/core/hash/default_proc_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#default_proc" do + it "returns the block passed to Hash.new" do + h = Hash.new { |i| 'Paris' } + p = h.default_proc + p.call(1).should == 'Paris' + end + + it "returns nil if no block was passed to proc" do + Hash.new.default_proc.should == nil + end +end diff --git a/1.8/core/hash/default_spec.rb b/1.8/core/hash/default_spec.rb new file mode 100644 index 0000000000..62d00b032a --- /dev/null +++ b/1.8/core/hash/default_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#default" do + it "returns the default value" do + h = Hash.new(5) + h.default.should == 5 + h.default(4).should == 5 + {}.default.should == nil + {}.default(4).should == nil + end + + it "uses the default proc to compute a default value, passing given key" do + h = Hash.new { |*args| args } + h.default(nil).should == [h, nil] + h.default(5).should == [h, 5] + end + + it "calls default proc with nil arg if passed a default proc but no arg" do + h = Hash.new { |*args| args } + h.default.should == nil + end +end + +describe "Hash#default=" do + it "sets the default value" do + h = Hash.new + h.default = 99 + h.default.should == 99 + end + + it "unsets the default proc" do + [99, nil, lambda { 6 }].each do |default| + h = Hash.new { 5 } + h.default_proc.should_not == nil + h.default = default + h.default.should == default + h.default_proc.should == nil + end + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + lambda { HashSpecs.frozen_hash.default = nil }.should raise_error(TypeError) + lambda { HashSpecs.empty_frozen_hash.default = nil }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/hash/delete_if_spec.rb b/1.8/core/hash/delete_if_spec.rb new file mode 100644 index 0000000000..7c39729bf9 --- /dev/null +++ b/1.8/core/hash/delete_if_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' + +describe "Hash#delete_if" do + it "yields two arguments: key and value" do + all_args = [] + {1 => 2, 3 => 4}.delete_if { |*args| all_args << args } + all_args.should == [[1, 2], [3, 4]] + end + + it "removes every entry for which block is true and returns self" do + h = {:a => 1, :b => 2, :c => 3, :d => 4} + h.delete_if { |k,v| v % 2 == 1 }.equal?(h).should == true + h.should == {:b => 2, :d => 4} + end + + it "processes entries with the same order as each()" do + h = {:a => 1, :b => 2, :c => 3, :d => 4} + + each_pairs = [] + delete_pairs = [] + + h.each_pair { |*pair| each_pairs << pair } + h.delete_if { |*pair| delete_pairs << pair } + + each_pairs.should == delete_pairs + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + lambda { HashSpecs.frozen_hash.delete_if { false } }.should raise_error(TypeError) + lambda { HashSpecs.empty_frozen_hash.delete_if { true } }.should raise_error(TypeError) + end + end + + it_behaves_like(:hash_iteration_method, :delete_if) + it_behaves_like(:hash_iteration_no_block, :delete_if) +end diff --git a/1.8/core/hash/delete_spec.rb b/1.8/core/hash/delete_spec.rb new file mode 100644 index 0000000000..5a76289206 --- /dev/null +++ b/1.8/core/hash/delete_spec.rb @@ -0,0 +1,64 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#delete" do + it "removes the entry and returns the deleted value" do + h = {:a => 5, :b => 2} + h.delete(:b).should == 2 + h.should == {:a => 5} + end + + it "calls eql? on colliding keys it finds" do + h = Hash.new + + # a class that tracks how many times eql? is called + eql_counter = Class.new do + def eql_count; @eql_count ||= 0; end + def eql_count=(count); @eql_count = count; end + # defer to super, so both get inserted + def eql?(obj); self.eql_count += 1; super; end + end + + # two equals_counter objects with the same hash + obj1 = eql_counter.new + obj2 = eql_counter.new + def obj1.hash; 0; end + def obj2.hash; 0; end + + h[obj1] = :a + h[obj2] = :b + + # obj2 has the same hash, so eql? should have been called once + obj2.eql_count.should == 1 + + # now always return true, so first key encountered is deleted + def obj1.eql?(obj); self.eql_count += 1; true; end + def obj2.eql?(obj); self.eql_count += 1; true; end + + # delete one of them + h.delete(obj1) + + # assert that between the two objects, eql? was called twice total + # we can't assert specific counts since we shouldn't specify bucket ordering + (obj1.eql_count + obj2.eql_count).should == 2 + end + + it "calls supplied block if the key is not found" do + {:a => 1, :b => 10, :c => 100 }.delete(:d) { 5 }.should == 5 + Hash.new(:default).delete(:d) { 5 }.should == 5 + Hash.new() { :defualt }.delete(:d) { 5 }.should == 5 + end + + it "returns nil if the key is not found when no block is given" do + {:a => 1, :b => 10, :c => 100 }.delete(:d).should == nil + Hash.new(:default).delete(:d).should == nil + Hash.new() { :defualt }.delete(:d).should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + lambda { HashSpecs.frozen_hash.delete("foo") }.should raise_error(TypeError) + lambda { HashSpecs.empty_frozen_hash.delete("foo") }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/hash/each_key_spec.rb b/1.8/core/hash/each_key_spec.rb new file mode 100644 index 0000000000..66a2983a0e --- /dev/null +++ b/1.8/core/hash/each_key_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' + +describe "Hash#each_key" do + it "calls block once for each key, passing key" do + r = {} + h = {1 => -1, 2 => -2, 3 => -3, 4 => -4 } + h.each_key { |k| r[k] = k }.equal?(h).should == true + r.should == { 1 => 1, 2 => 2, 3 => 3, 4 => 4 } + end + + it "processes keys in the same order as keys()" do + keys = [] + h = {1 => -1, 2 => -2, 3 => -3, 4 => -4 } + h.each_key { |k| keys << k } + keys.should == h.keys + end + + it_behaves_like(:hash_iteration_method, :each_key) + it_behaves_like(:hash_iteration_modifying, :each_key) + it_behaves_like(:hash_iteration_no_block, :each_key) +end diff --git a/1.8/core/hash/each_pair_spec.rb b/1.8/core/hash/each_pair_spec.rb new file mode 100644 index 0000000000..4d63571551 --- /dev/null +++ b/1.8/core/hash/each_pair_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' + +describe "Hash#each_pair" do + it "processes all pairs, yielding two arguments: key and value" do + all_args = [] + + h = {1 => 2, 3 => 4} + h2 = h.each_pair { |*args| all_args << args } + h2.equal?(h).should == true + + all_args.should == [[1, 2], [3, 4]] + end + + it_behaves_like(:hash_iteration_method, :each_pair) + it_behaves_like(:hash_iteration_modifying, :each_pair) + it_behaves_like(:hash_iteration_no_block, :each_pair) +end diff --git a/1.8/core/hash/each_spec.rb b/1.8/core/hash/each_spec.rb new file mode 100644 index 0000000000..a3b7459a85 --- /dev/null +++ b/1.8/core/hash/each_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' + +describe "Hash#each" do + it "yields one argument: [key, value]" do + all_args = [] + {1 => 2, 3 => 4}.each { |*args| all_args << args } + all_args.should == [[[1, 2]], [[3, 4]]] + end + + it "calls block once for each entry, passing key, value" do + r = {} + h = {:a => 1, :b => 2, :c => 3, :d => 5} + h.each { |k,v| r[k.to_s] = v.to_s }.equal?(h).should == true + r.should == {"a" => "1", "b" => "2", "c" => "3", "d" => "5" } + end + + it "uses the same order as keys() and values()" do + h = {:a => 1, :b => 2, :c => 3, :d => 5} + keys = [] + values = [] + + h.each do |k, v| + keys << k + values << v + end + + keys.should == h.keys + values.should == h.values + end + + it_behaves_like(:hash_iteration_method, :each) + it_behaves_like(:hash_iteration_modifying, :each) + it_behaves_like(:hash_iteration_no_block, :each) +end diff --git a/1.8/core/hash/each_value_spec.rb b/1.8/core/hash/each_value_spec.rb new file mode 100644 index 0000000000..ce4b8e2155 --- /dev/null +++ b/1.8/core/hash/each_value_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' + +describe "Hash#each_value" do + it "calls block once for each key, passing value" do + r = [] + h = { :a => -5, :b => -3, :c => -2, :d => -1, :e => -1 } + h.each_value { |v| r << v }.equal?(h).should == true + r.sort.should == [-5, -3, -2, -1, -1] + end + + it "processes values in the same order as values()" do + values = [] + h = { :a => -5, :b => -3, :c => -2, :d => -1, :e => -1 } + h.each_value { |v| values << v } + values.should == h.values + end + + it_behaves_like(:hash_iteration_method, :each_value) + it_behaves_like(:hash_iteration_modifying, :each_value) + it_behaves_like(:hash_iteration_no_block, :each_value) +end diff --git a/1.8/core/hash/element_reference_spec.rb b/1.8/core/hash/element_reference_spec.rb new file mode 100644 index 0000000000..3cc5be0adc --- /dev/null +++ b/1.8/core/hash/element_reference_spec.rb @@ -0,0 +1,149 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash.[]" do + it "creates a Hash; values can be provided as the argument list" do + Hash[:a, 1, :b, 2].should == {:a => 1, :b => 2} + Hash[].should == {} + end + + it "creates a Hash; values can be provided as one single hash" do + Hash[:a => 1, :b => 2].should == {:a => 1, :b => 2} + Hash[{1 => 2, 3 => 4}].should == {1 => 2, 3 => 4} + Hash[{}].should == {} + end + + it "raises an ArgumentError when passed an odd number of arguments" do + lambda { Hash[1, 2, 3] }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when mixing argument styles" do + lambda { Hash[1, 2, {3 => 4}] }.should raise_error(ArgumentError) + Hash[1, 2, 3, {3 => 4}].should == {1 => 2, 3 => {3 => 4}} + end + + it "does not call to_hash" do + obj = mock('x') + def obj.to_hash() { 1 => 2, 3 => 4 } end + lambda { Hash[obj] }.should raise_error(ArgumentError) + end + + it "returns an instance of the class it's called on" do + Hash[MyHash[1, 2]].class.should == Hash + MyHash[Hash[1, 2]].class.should == MyHash + end +end + +describe "Hash#[]" do + it "returns the value for key" do + obj = mock('x') + h = { 1 => 2, 3 => 4, "foo" => "bar", obj => obj, [] => "baz" } + h[1].should == 2 + h[3].should == 4 + h["foo"].should == "bar" + h[obj].should == obj + h[[]].should == "baz" + end + + it "returns the default (immediate) value for missing keys" do + h = Hash.new(5) + h[:a].should == 5 + h[:a] = 0 + h[:a].should == 0 + h[:b].should == 5 + + # The default default is nil + { 0 => 0 }[5].should == nil + end + + it "calls subclass implementations of default" do + h = DefaultHash.new + h[:nothing].should == 100 + end + + it "does not create copies of the immediate default value" do + str = "foo" + h = Hash.new(str) + a = h[:a] + b = h[:b] + a << "bar" + + a.equal?(b).should == true + a.should == "foobar" + b.should == "foobar" + end + + it "returns the default (dynamic) value for missing keys" do + h = Hash.new { |hsh, k| k.kind_of?(Numeric) ? hsh[k] = k + 2 : hsh[k] = k } + h[1].should == 3 + h['this'].should == 'this' + h.should == {1 => 3, 'this' => 'this'} + + i = 0 + h = Hash.new { |hsh, key| i += 1 } + h[:foo].should == 1 + h[:foo].should == 2 + h[:bar].should == 3 + end + + it "does not return default values for keys with nil values" do + h = Hash.new(5) + h[:a] = nil + h[:a].should == nil + + h = Hash.new() { 5 } + h[:a] = nil + h[:a].should == nil + end + + it "compares keys with eql? semantics" do + { 1.0 => "x" }[1].should == nil + { 1.0 => "x" }[1.0].should == "x" + { 1 => "x" }[1.0].should == nil + { 1 => "x" }[1].should == "x" + end + + it "compares key via hash" do + # Can't use should_receive because it uses hash internally + x = mock('0') + def x.hash() 0 end + + { }[x].should == nil + end + + it "does not compare key with unknown hash codes via eql?" do + # Can't use should_receive because it uses hash and eql? internally + x = mock('x') + y = mock('y') + def x.eql?(o) raise("Shouldn't receive eql?") end + + def x.hash() 0 end + def y.hash() 1 end + + { y => 1 }[x].should == nil + end + + it "compares key with found hash code via eql?" do + # Can't use should_receive because it uses hash and eql? internally + y = mock('0') + def y.hash() 0 end + + x = mock('0') + def x.hash() + def self.eql?(o) taint; false; end + return 0 + end + + { y => 1 }[x].should == nil + x.tainted?.should == true + + x = mock('0') + def x.hash() + def self.eql?(o) taint; true; end + return 0 + end + + { y => 1 }[x].should == 1 + x.tainted?.should == true + end +end diff --git a/1.8/core/hash/element_set_spec.rb b/1.8/core/hash/element_set_spec.rb new file mode 100644 index 0000000000..6af7bf4d53 --- /dev/null +++ b/1.8/core/hash/element_set_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/store' + +describe "Hash#[]=" do + it_behaves_like(:hash_store, :[]=) +end diff --git a/1.8/core/hash/empty_spec.rb b/1.8/core/hash/empty_spec.rb new file mode 100644 index 0000000000..acab48314d --- /dev/null +++ b/1.8/core/hash/empty_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#empty?" do + it "returns true if the hash has no entries" do + {}.empty?.should == true + {1 => 1}.empty?.should == false + Hash.new(5).empty?.should == true + Hash.new { 5 }.empty?.should == true + end +end diff --git a/1.8/core/hash/equal_value_spec.rb b/1.8/core/hash/equal_value_spec.rb new file mode 100644 index 0000000000..244e1dba52 --- /dev/null +++ b/1.8/core/hash/equal_value_spec.rb @@ -0,0 +1,148 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#==" do + it "returns true if other Hash has the same number of keys and each key-value pair matches" do + Hash.new(5).should == Hash.new(1) + Hash.new {|h, k| 1}.should == Hash.new {} + Hash.new {|h, k| 1}.should == Hash.new(2) + + a = {:a => 5} + b = {} + + a.should_not == b + + b[:a] = 5 + + a.should == b + + c = Hash.new {|h, k| 1} + d = Hash.new {} + c[1] = 2 + d[1] = 2 + c.should == d + end + + it "does not call to_hash on hash subclasses" do + {5 => 6}.should == ToHashHash[5 => 6] + end + + it "returns false when the numbers of keys differ without comparing any elements" do + obj = mock('x') + obj.should_not_receive(:==) + obj.should_not_receive(:eql?) + + {}.should_not == { obj => obj } + { obj => obj }.should_not == {} + end + + it "compares keys with eql? semantics" do + { 1.0 => "x" }.should == { 1.0 => "x" } + { 1 => "x" }.should_not == { 1.0 => "x" } + { 1.0 => "x" }.should_not == { 1 => "x" } + end + + it "first compares keys via hash" do + # Can't use should_receive because it uses hash internally + x = mock('x') + def x.hash() 0 end + y = mock('y') + def y.hash() 0 end + + { x => 1 }.should_not == { y => 1 } + end + + it "does not compare keys with different hash codes via eql?" do + # Can't use should_receive because it uses hash and eql? internally + x = mock('x') + y = mock('y') + x.instance_variable_set(:@other, y) + y.instance_variable_set(:@other, x) + def x.eql?(o) + raise("x Shouldn't receive eql?") if o == @other + self == o + end + def y.eql?(o) + raise("y Shouldn't receive eql?") if o == @other + self == o + end + + def x.hash() 0 end + def y.hash() 1 end + + { x => 1 }.should_not == { y => 1 } + end + + it "compares keys with matching hash codes via eql?" do + # Can't use should_receive because it uses hash and eql? internally + a = Array.new(2) do + obj = mock('0') + + def obj.hash() + return 0 + end + # It's undefined whether the impl does a[0].eql?(a[1]) or + # a[1].eql?(a[0]) so we taint both. + def obj.eql?(o) + return true if self == o + taint + o.taint + false + end + + obj + end + + { a[0] => 1 }.should_not == { a[1] => 1 } + a[0].tainted?.should == true + a[1].tainted?.should == true + + a = Array.new(2) do + obj = mock('0') + + def obj.hash() + # It's undefined whether the impl does a[0].eql?(a[1]) or + # a[1].eql?(a[0]) so we taint both. + def self.eql?(o) taint; o.taint; true; end + return 0 + end + + obj + end + + { a[0] => 1 }.should == { a[1] => 1 } + a[0].tainted?.should == true + a[1].tainted?.should == true + end + + it "compares values with == semantics" do + { "x" => 1.0 }.should == { "x" => 1 } + end + + it "does not compare values when keys don't match" do + value = mock('x') + value.should_not_receive(:==) + { 1 => value }.should_not == { 2 => value } + end + + it "compares values when keys match" do + x = mock('x') + y = mock('y') + def x.==(o) false end + def y.==(o) false end + { 1 => x }.should_not == { 1 => y } + + x = mock('x') + y = mock('y') + def x.==(o) true end + def y.==(o) true end + { 1 => x }.should == { 1 => y } + end + + it "ignores hash class differences" do + h = { 1 => 2, 3 => 4 } + MyHash[h].should == h + MyHash[h].should == MyHash[h] + h.should == MyHash[h] + end +end diff --git a/1.8/core/hash/fetch_spec.rb b/1.8/core/hash/fetch_spec.rb new file mode 100644 index 0000000000..277e2227fd --- /dev/null +++ b/1.8/core/hash/fetch_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#fetch" do + it "returns the value for key" do + { :a => 1, :b => -1 }.fetch(:b).should == -1 + end + + it "raises an IndexError if key is not found" do + lambda { {}.fetch(:a) }.should raise_error(IndexError) + lambda { Hash.new(5).fetch(:a) }.should raise_error(IndexError) + lambda { Hash.new { 5 }.fetch(:a) }.should raise_error(IndexError) + end + + it "returns default if key is not found when passed a default" do + {}.fetch(:a, nil).should == nil + {}.fetch(:a, 'not here!').should == "not here!" + { :a => nil }.fetch(:a, 'not here!').should == nil + end + + it "returns value of block if key is not found when passed a block" do + {}.fetch('a') { |k| k + '!' }.should == "a!" + end + + it "gives precedence to the default block over the default argument when passed both" do + old, $VERBOSE = $VERBOSE, nil + {}.fetch(9, :foo) { |i| i * i }.should == 81 + $VERBOSE = old + end + + it "raises an ArgumentError when not passed one or two arguments" do + lambda { {}.fetch() }.should raise_error(ArgumentError) + lambda { {}.fetch(1, 2, 3) }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/hash/fixtures/classes.rb b/1.8/core/hash/fixtures/classes.rb new file mode 100644 index 0000000000..fac6c399cf --- /dev/null +++ b/1.8/core/hash/fixtures/classes.rb @@ -0,0 +1,33 @@ +class MyHash < Hash; end + +class NewHash < Hash + def initialize(*args) + args.each_with_index do |val, index| + self[index] = val + end + end +end + +class DefaultHash < Hash + def default(key) + 100 + end +end + +class ToHashHash < Hash + def to_hash() { "to_hash" => "was", "called!" => "duh." } end +end + +module HashSpecs + def self.empty_frozen_hash + @empty ||= {} + @empty.freeze + @empty + end + + def self.frozen_hash + @hash ||= {1 => 2, 3 => 4} + @hash.freeze + @hash + end +end diff --git a/1.8/core/hash/has_key_spec.rb b/1.8/core/hash/has_key_spec.rb new file mode 100644 index 0000000000..227a39c1d4 --- /dev/null +++ b/1.8/core/hash/has_key_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/key' + +describe "Hash#has_key?" do + it_behaves_like(:hash_key_p, :has_key?) +end + diff --git a/1.8/core/hash/has_value_spec.rb b/1.8/core/hash/has_value_spec.rb new file mode 100644 index 0000000000..ba75725c60 --- /dev/null +++ b/1.8/core/hash/has_value_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/value' + +describe "Hash#has_value?" do + it_behaves_like(:hash_value_p, :has_value?) +end + diff --git a/1.8/core/hash/hash_spec.rb b/1.8/core/hash/hash_spec.rb new file mode 100644 index 0000000000..17889ce4c6 --- /dev/null +++ b/1.8/core/hash/hash_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Hash" do + it "includes Enumerable" do + Hash.include?(Enumerable).should == true + end +end diff --git a/1.8/core/hash/include_spec.rb b/1.8/core/hash/include_spec.rb new file mode 100644 index 0000000000..62a9ce8b98 --- /dev/null +++ b/1.8/core/hash/include_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/key' + +describe "Hash#include?" do + it_behaves_like(:hash_key_p, :include?) +end diff --git a/1.8/core/hash/index_spec.rb b/1.8/core/hash/index_spec.rb new file mode 100644 index 0000000000..ee603231b6 --- /dev/null +++ b/1.8/core/hash/index_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#index" do + it "returns the corresponding key for value" do + {2 => 'a', 1 => 'b'}.index('b').should == 1 + end + + it "returns nil if the value is not found" do + {:a => -1, :b => 3.14, :c => 2.718}.index(1).should == nil + Hash.new(5).index(5).should == nil + end + + it "compares values using ==" do + {1 => 0}.index(0.0).should == 1 + {1 => 0.0}.index(0).should == 1 + + needle = mock('needle') + inhash = mock('inhash') + inhash.should_receive(:==).with(needle).and_return(true) + + {1 => inhash}.index(needle).should == 1 + end +end diff --git a/1.8/core/hash/indexes_spec.rb b/1.8/core/hash/indexes_spec.rb new file mode 100644 index 0000000000..fdff49f8b1 --- /dev/null +++ b/1.8/core/hash/indexes_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/values_at_spec' + +describe "Hash#indexes" do + old, $VERBOSE = $VERBOSE, nil + it_behaves_like(:hash_values_at, :indexes) + $VERBOSE = old +end diff --git a/1.8/core/hash/indices_spec.rb b/1.8/core/hash/indices_spec.rb new file mode 100644 index 0000000000..a3eace87c4 --- /dev/null +++ b/1.8/core/hash/indices_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/values_at_spec' + +describe "Hash#indices" do + old, $VERBOSE = $VERBOSE, nil + it_behaves_like(:hash_values_at, :indices) + $VERBOSE = old +end diff --git a/1.8/core/hash/initialize_copy_spec.rb b/1.8/core/hash/initialize_copy_spec.rb new file mode 100644 index 0000000000..605111d813 --- /dev/null +++ b/1.8/core/hash/initialize_copy_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/replace' + +describe "Hash#initialize_copy" do + it "is private" do + {}.private_methods.map { |m| m.to_s }.include?("initialize_copy").should == true + end + + it_behaves_like(:hash_replace, :initialize_copy) +end diff --git a/1.8/core/hash/initialize_spec.rb b/1.8/core/hash/initialize_spec.rb new file mode 100644 index 0000000000..de28498e16 --- /dev/null +++ b/1.8/core/hash/initialize_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#initialize" do + it "is private" do + {}.private_methods.map { |m| m.to_s }.include?("initialize").should == true + end + + it "can be used to reset default_proc" do + h = { "foo" => 1, "bar" => 2 } + h.default_proc.should == nil + h.instance_eval { initialize { |h, k| k * 2 } } + h.default_proc.should_not == nil + h["a"].should == "aa" + end + + it "should get passed whatever args were passed to Hash#new" do + NewHash.new(:one, :two)[0].should == :one + NewHash.new(:one, :two)[1].should == :two + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + block = lambda { HashSpecs.frozen_hash.instance_eval { initialize() }} + block.should raise_error(TypeError) + + block = lambda { HashSpecs.frozen_hash.instance_eval { initialize(nil) } } + block.should raise_error(TypeError) + + block = lambda { HashSpecs.frozen_hash.instance_eval { initialize(5) } } + block.should raise_error(TypeError) + + block = lambda { HashSpecs.frozen_hash.instance_eval { initialize { 5 } } } + block.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/hash/inspect_spec.rb b/1.8/core/hash/inspect_spec.rb new file mode 100644 index 0000000000..c72ddea08e --- /dev/null +++ b/1.8/core/hash/inspect_spec.rb @@ -0,0 +1,60 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#inspect" do + it "returns a string representation with same order as each()" do + h = {:a => [1, 2], :b => -2, :d => -6, nil => nil} + + pairs = [] + h.each do |key, value| + pairs << key.inspect + "=>" + value.inspect + end + + str = '{' + pairs.join(', ') + '}' + h.inspect.should == str + end + + it "calls inspect on keys and values" do + key = mock('key') + val = mock('val') + key.should_receive(:inspect).and_return('key') + val.should_receive(:inspect).and_return('val') + + { key => val }.inspect.should == '{key=>val}' + end + + it "handles recursive hashes" do + x = {} + x[0] = x + x.inspect.should == '{0=>{...}}' + + x = {} + x[x] = 0 + x.inspect.should == '{{...}=>0}' + + x = {} + x[x] = x + x.inspect.should == '{{...}=>{...}}' + + x = {} + y = {} + x[0] = y + y[1] = x + x.inspect.should == "{0=>{1=>{...}}}" + y.inspect.should == "{1=>{0=>{...}}}" + + x = {} + y = {} + x[y] = 0 + y[x] = 1 + x.inspect.should == "{{{...}=>1}=>0}" + y.inspect.should == "{{{...}=>0}=>1}" + + x = {} + y = {} + x[y] = x + y[x] = y + x.inspect.should == "{{{...}=>{...}}=>{...}}" + y.inspect.should == "{{{...}=>{...}}=>{...}}" + end +end diff --git a/1.8/core/hash/invert_spec.rb b/1.8/core/hash/invert_spec.rb new file mode 100644 index 0000000000..d776e18f52 --- /dev/null +++ b/1.8/core/hash/invert_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#invert" do + it "returns a new hash where keys are values and vice versa" do + { 1 => 'a', 2 => 'b', 3 => 'c' }.invert.should == { 'a' => 1, 'b' => 2, 'c' => 3 } + end + + it "handles collisions by overriding with the key coming later in keys()" do + h = { :a => 1, :b => 1 } + override_key = h.keys.last + h.invert[1].should == override_key + end + + it "compares new keys with eql? semantics" do + h = { :a => 1.0, :b => 1 } + i = h.invert + i[1.0].should == :a + i[1].should == :b + end + + it "does not return subclass instances for subclasses" do + MyHash[1 => 2, 3 => 4].invert.class.should == Hash + MyHash[].invert.class.should == Hash + end +end diff --git a/1.8/core/hash/key_spec.rb b/1.8/core/hash/key_spec.rb new file mode 100644 index 0000000000..3fb7952f74 --- /dev/null +++ b/1.8/core/hash/key_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/key' + +describe "Hash#key?" do + it_behaves_like(:hash_key_p, :key?) +end diff --git a/1.8/core/hash/keys_spec.rb b/1.8/core/hash/keys_spec.rb new file mode 100644 index 0000000000..dbf4efe96c --- /dev/null +++ b/1.8/core/hash/keys_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#keys" do + it "returns an array populated with keys" do + {}.keys.should == [] + {}.keys.class.should == Array + Hash.new(5).keys.should == [] + Hash.new { 5 }.keys.should == [] + { 1 => 2, 2 => 4, 4 => 8 }.keys.should == [1, 2, 4] + { 1 => 2, 2 => 4, 4 => 8 }.keys.class.should == Array + { nil => nil }.keys.should == [nil] + end + + it "it uses the same order as #values" do + h = { 1 => "1", 2 => "2", 3 => "3", 4 => "4" } + + h.size.times do |i| + h[h.keys[i]].should == h.values[i] + end + end +end diff --git a/1.8/core/hash/length_spec.rb b/1.8/core/hash/length_spec.rb new file mode 100644 index 0000000000..6ab8328c3e --- /dev/null +++ b/1.8/core/hash/length_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/length' + +describe "Hash#length" do + it_behaves_like(:hash_length, :length) +end diff --git a/1.8/core/hash/member_spec.rb b/1.8/core/hash/member_spec.rb new file mode 100644 index 0000000000..0568d0aba3 --- /dev/null +++ b/1.8/core/hash/member_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/key' + +describe "Hash#member?" do + it_behaves_like(:hash_key_p, :member?) +end diff --git a/1.8/core/hash/merge_spec.rb b/1.8/core/hash/merge_spec.rb new file mode 100644 index 0000000000..dfdb5885a5 --- /dev/null +++ b/1.8/core/hash/merge_spec.rb @@ -0,0 +1,72 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' +require File.dirname(__FILE__) + '/shared/update' + +describe "Hash#merge" do + it "returns a new hash by combining self with the contents of other" do + { 1 => :a, 2 => :b, 3 => :c }.merge(:a => 1, :c => 2).should == { :c => 2, 1 => :a, 2 => :b, :a => 1, 3 => :c } + end + + it "sets any duplicate key to the value of block if passed a block" do + h1 = { :a => 2, :b => 1, :d => 5} + h2 = { :a => -2, :b => 4, :c => -3 } + r = h1.merge(h2) { |k,x,y| nil } + r.should == { :a => nil, :b => nil, :c => -3, :d => 5 } + + r = h1.merge(h2) { |k,x,y| "#{k}:#{x+2*y}" } + r.should == { :a => "a:-2", :b => "b:9", :c => -3, :d => 5 } + + lambda { + h1.merge(h2) { |k, x, y| raise(IndexError) } + }.should raise_error(IndexError) + + r = h1.merge(h1) { |k,x,y| :x } + r.should == { :a => :x, :b => :x, :d => :x } + end + + it "calls to_hash on its argument" do + obj = mock('{1=>2}') + obj.should_receive(:to_hash).and_return({1 => 2}) + {3 => 4}.merge(obj).should == {1 => 2, 3 => 4} + + obj = mock('{1=>2}') + obj.should_receive(:respond_to?).with(:to_hash).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_hash).and_return({ 1 => 2}) + {3 => 4}.merge(obj).should == {1 => 2, 3 => 4} + end + + it "does not call to_hash on hash subclasses" do + {3 => 4}.merge(ToHashHash[1 => 2]).should == {1 => 2, 3 => 4} + end + + it "returns subclass instance for subclasses" do + MyHash[1 => 2, 3 => 4].merge({1 => 2}).class.should == MyHash + MyHash[].merge({1 => 2}).class.should == MyHash + + {1 => 2, 3 => 4}.merge(MyHash[1 => 2]).class.should == Hash + {}.merge(MyHash[1 => 2]).class.should == Hash + end + + it "processes entries with same order as each()" do + h = {1 => 2, 3 => 4, 5 => 6, "x" => nil, nil => 5, [] => []} + merge_pairs = [] + each_pairs = [] + h.each_pair { |*pair| each_pairs << pair } + h.merge(h) { |k, v1, v2| merge_pairs << [k, v1] } + merge_pairs.should == each_pairs + end + + it_behaves_like(:hash_iteration_method, :merge) + it_behaves_like(:hash_iteration_modifying, :merge) +end + +describe "Hash#merge!" do + it_behaves_like(:hash_update, :merge!) + + it_behaves_like(:hash_iteration_method, :merge!) + + compliant_on :ruby, :rubinius do + it_behaves_like(:hash_iteration_modifying, :merge!) + end +end diff --git a/1.8/core/hash/new_spec.rb b/1.8/core/hash/new_spec.rb new file mode 100644 index 0000000000..235fa11e12 --- /dev/null +++ b/1.8/core/hash/new_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash.new" do + it "creates a new Hash with default object if pass a default argument " do + Hash.new(5).default.should == 5 + Hash.new({}).default.should == {} + end + + it "does not create a copy of the default argument" do + str = "foo" + Hash.new(str).default.equal?(str).should == true + end + + it "creates a Hash with a default_proc if passed a block" do + Hash.new.default_proc.should == nil + + h = Hash.new { |x| "Answer to #{x}" } + h.default_proc.call(5).should == "Answer to 5" + h.default_proc.call("x").should == "Answer to x" + end + + it "raises an ArgumentError if more than one argument is passed" do + lambda { Hash.new(5,6) }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError if passed both default argument and default block" do + lambda { Hash.new(5) { 0 } }.should raise_error(ArgumentError) + lambda { Hash.new(nil) { 0 } }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/hash/rehash_spec.rb b/1.8/core/hash/rehash_spec.rb new file mode 100644 index 0000000000..98aeb4a357 --- /dev/null +++ b/1.8/core/hash/rehash_spec.rb @@ -0,0 +1,60 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#rehash" do + it "reorganizes the hash by recomputing all key hash codes" do + k1 = [1] + k2 = [2] + h = {} + h[k1] = 0 + h[k2] = 1 + + k1 << 2 + h.key?(k1).should == false + h.keys.include?(k1).should == true + + h.rehash.equal?(h).should == true + h.key?(k1).should == true + h[k1].should == 0 + + k1 = mock('k1') + k2 = mock('k2') + v1 = mock('v1') + v2 = mock('v2') + + # Can't use should_receive here because it uses hash() internally + def v1.hash() raise("values shouldn't be rehashed"); end + def v2.hash() raise("values shouldn't be rehashed"); end + + h = { k1 => v1, k2 => v2 } + + def k1.hash() 0 end + def k2.hash() 0 end + + h.rehash + h[k1].should == v1 + h[k2].should == v2 + end + + compliant_on :ruby, :rubinius do + it "gives precedence to keys coming later in keys() on collisions" do + k1 = [1] + k2 = [2] + h = {} + h[k1] = 0 + h[k2] = 1 + + k1.replace(k2) + override_val = h[h.keys.last] + h.rehash + h[k1].should == override_val + end + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + lambda { HashSpecs.frozen_hash.rehash }.should raise_error(TypeError) + lambda { HashSpecs.empty_frozen_hash.rehash }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/hash/reject_spec.rb b/1.8/core/hash/reject_spec.rb new file mode 100644 index 0000000000..b7fa94d40a --- /dev/null +++ b/1.8/core/hash/reject_spec.rb @@ -0,0 +1,78 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' + +describe "Hash#reject" do + it "is equivalent to hsh.dup.delete_if" do + h = { :a => 'a', :b => 'b', :c => 'd' } + h.reject { |k,v| k == 'd' }.should == (h.dup.delete_if { |k, v| k == 'd' }) + + all_args_reject = [] + all_args_delete_if = [] + h = {1 => 2, 3 => 4} + h.reject { |*args| all_args_reject << args } + h.delete_if { |*args| all_args_delete_if << args } + all_args_reject.should == all_args_delete_if + + h = { 1 => 2 } + # dup doesn't copy singleton methods + def h.to_a() end + h.reject { false }.to_a.should == [[1, 2]] + end + + it "returns subclass instance for subclasses" do + MyHash[1 => 2, 3 => 4].reject { false }.class.should == MyHash + MyHash[1 => 2, 3 => 4].reject { true }.class.should == MyHash + end + + it "processes entries with the same order as reject!" do + h = {:a => 1, :b => 2, :c => 3, :d => 4} + + reject_pairs = [] + reject_bang_pairs = [] + h.dup.reject { |*pair| reject_pairs << pair } + h.reject! { |*pair| reject_bang_pairs << pair } + + reject_pairs.should == reject_bang_pairs + end + + it_behaves_like(:hash_iteration_no_block, :reject) +end + +describe "Hash#reject!" do + it "is equivalent to delete_if if changes are made" do + {:a => 2}.reject! { |k,v| v > 1 }.should == ({:a => 2}.delete_if { |k, v| v > 1 }) + + h = {1 => 2, 3 => 4} + all_args_reject = [] + all_args_delete_if = [] + h.dup.reject! { |*args| all_args_reject << args } + h.dup.delete_if { |*args| all_args_delete_if << args } + all_args_reject.should == all_args_delete_if + end + + it "returns nil if no changes were made" do + { :a => 1 }.reject! { |k,v| v > 1 }.should == nil + end + + it "processes entries with the same order as delete_if" do + h = {:a => 1, :b => 2, :c => 3, :d => 4} + + reject_bang_pairs = [] + delete_if_pairs = [] + h.dup.reject! { |*pair| reject_bang_pairs << pair } + h.dup.delete_if { |*pair| delete_if_pairs << pair } + + reject_bang_pairs.should == delete_if_pairs + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + lambda { HashSpecs.frozen_hash.reject! { false } }.should raise_error(TypeError) + lambda { HashSpecs.empty_frozen_hash.reject! { true } }.should raise_error(TypeError) + end + end + + it_behaves_like(:hash_iteration_method, :reject!) + it_behaves_like(:hash_iteration_no_block, :reject!) +end diff --git a/1.8/core/hash/replace_spec.rb b/1.8/core/hash/replace_spec.rb new file mode 100644 index 0000000000..c42d73922b --- /dev/null +++ b/1.8/core/hash/replace_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/replace' + +describe "Hash#replace" do + it_behaves_like(:hash_replace, :replace) +end diff --git a/1.8/core/hash/select_spec.rb b/1.8/core/hash/select_spec.rb new file mode 100644 index 0000000000..8ac7177f8f --- /dev/null +++ b/1.8/core/hash/select_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' + +describe "Hash#select" do + it "yields two arguments: key and value" do + all_args = [] + {1 => 2, 3 => 4}.select { |*args| all_args << args } + all_args.should == [[1, 2], [3, 4]] + end + + it "returns an array of entries for which block is true" do + { :a => 9, :c => 4, :b => 5, :d => 2 }.select { |k,v| v % 2 == 0 } + end + + it "processes entries with the same order as reject" do + h = { :a => 9, :c => 4, :b => 5, :d => 2 } + + select_pairs = [] + reject_pairs = [] + h.dup.select { |*pair| select_pairs << pair } + h.reject { |*pair| reject_pairs << pair } + + select_pairs.should == reject_pairs + end + + it_behaves_like(:hash_iteration_method, :select) + it_behaves_like(:hash_iteration_modifying, :select) + it_behaves_like(:hash_iteration_no_block, :select) +end diff --git a/1.8/core/hash/shared/iteration.rb b/1.8/core/hash/shared/iteration.rb new file mode 100644 index 0000000000..625df029df --- /dev/null +++ b/1.8/core/hash/shared/iteration.rb @@ -0,0 +1,72 @@ +shared :hash_iteration_method do |cmd| + # These are the only ones that actually have the exceptions on MRI 1.8. + # sort and reject don't raise! + # + # delete_if each each_key each_pair each_value merge merge! reject! + # select update + # + describe "Hash##{cmd}" do + hsh = {1 => 2, 3 => 4, 5 => 6} + big_hash = {} + 64.times { |k| big_hash[k.to_s] = k } + + # it "raises a RuntimeError if #rehash is called from block" do + # h = hsh.dup + # args = cmd.to_s[/merge|update/] ? [h] : [] + # + # lambda { + # h.send(cmd, *args) { h.rehash } + # }.should raise_error(RuntimeError) + # end + # + # # This specification seems arbitrary, but describes the behavior of MRI + # it "raises if more than 63 new entries are added from block" do + # h = hsh.dup + # args = cmd.to_s[/merge|update/] ? [h] : [] + # + # lambda { + # h.send(cmd, *args) { |*x| h.merge!(big_hash) } + # }.should raise_error(RuntimeError) + # end + + end +end + +shared :hash_iteration_modifying do |cmd| + describe "Hash##{cmd}" do + hsh = {1 => 2, 3 => 4, 5 => 6} + big_hash = {} + 100.times { |k| big_hash[k.to_s] = k } + + it "does not affect yielded items by removing the current element" do + n = 3 + + h = Array.new(n) { hsh.dup } + args = Array.new(n) { |i| cmd.to_s[/merge|update/] ? [h[i]] : [] } + r = Array.new(n) { [] } + + h[0].send(cmd, *args[0]) { |*x| r[0] << x; true } + h[1].send(cmd, *args[1]) { |*x| r[1] << x; h[1].shift; true } + h[2].send(cmd, *args[2]) { |*x| r[2] << x; h[2].delete(h[2].keys.first); true } + + r[1..-1].each do |yielded| + yielded.should == r[0] + end + end + end +end + +shared :hash_iteration_no_block do |cmd| + describe "Hash##{cmd}" do + hsh = {1 => 2, 3 => 4, 5 => 6} + empty = {} + + it "raises a LocalJumpError when called on a non-empty hash without a block" do + lambda { hsh.delete_if }.should raise_error(LocalJumpError) + end + + it "does not raise a LocalJumpError when called on an empty hash without a block" do + empty.delete_if.should == empty + end + end +end \ No newline at end of file diff --git a/1.8/core/hash/shared/key.rb b/1.8/core/hash/shared/key.rb new file mode 100644 index 0000000000..3db3e76cfa --- /dev/null +++ b/1.8/core/hash/shared/key.rb @@ -0,0 +1,31 @@ +shared :hash_key_p do |cmd| + describe "Hash##{cmd}" do + it "returns true if argument is a key" do + h = { :a => 1, :b => 2, :c => 3, 4 => 0 } + h.send(cmd, :a).should == true + h.send(cmd, :b).should == true + h.send(cmd, 'b').should == false + h.send(cmd, 2).should == false + h.send(cmd, 4).should == true + h.send(cmd, 4.0).should == false + end + + it "returns true if the key's matching value was nil" do + { :xyz => nil }.send(cmd, :xyz).should == true + end + + it "returns true if the key's matching value was false" do + { :xyz => false }.send(cmd, :xyz).should == true + end + + it "returns false for objects with the same hash" do + o1 = Object.new + def o1.hash() 0 end + + o2 = Object.new + def o2.hash() 0 end + + { o1 => nil }.send(cmd, o2).should == false + end + end +end diff --git a/1.8/core/hash/shared/length.rb b/1.8/core/hash/shared/length.rb new file mode 100644 index 0000000000..3a5e13e783 --- /dev/null +++ b/1.8/core/hash/shared/length.rb @@ -0,0 +1,12 @@ +shared :hash_length do |cmd| + describe "Hash##{cmd}" do + it "returns the number of entries" do + {:a => 1, :b => 'c'}.send(cmd).should == 2 + {:a => 1, :b => 2, :a => 2}.send(cmd).should == 2 + {:a => 1, :b => 1, :c => 1}.send(cmd).should == 3 + {}.send(cmd).should == 0 + Hash.new(5).send(cmd).should == 0 + Hash.new { 5 }.send(cmd).should == 0 + end + end +end diff --git a/1.8/core/hash/shared/replace.rb b/1.8/core/hash/shared/replace.rb new file mode 100644 index 0000000000..b7c680adda --- /dev/null +++ b/1.8/core/hash/shared/replace.rb @@ -0,0 +1,56 @@ +shared :hash_replace do |cmd| + describe "Hash##{cmd}" do + it "replaces the contents of self with other" do + h = { :a => 1, :b => 2 } + h.send(cmd, :c => -1, :d => -2).equal?(h).should == true + h.should == { :c => -1, :d => -2 } + end + + it "calls to_hash on its argument" do + obj = mock('{1=>2,3=>4}') + obj.should_receive(:to_hash).and_return({1 => 2, 3 => 4}) + + h = {} + h.send(cmd, obj) + h.should == {1 => 2, 3 => 4} + + obj = mock('{}') + obj.should_receive(:respond_to?).with(:to_hash).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_hash).and_return({}) + + h.send(cmd, obj) + h.should == {} + end + + it "calls to_hash on hash subclasses" do + h = {} + h.send(cmd, ToHashHash[1 => 2]) + h.should == {1 => 2} + end + + it "does not transfer default values" do + hash_a = {} + hash_b = Hash.new(5) + hash_a.send(cmd, hash_b) + hash_a.default.should == 5 + + hash_a = {} + hash_b = Hash.new { |h, k| k * 2 } + hash_a.send(cmd, hash_b) + hash_a.default(5).should == 10 + + hash_a = Hash.new { |h, k| k * 5 } + hash_b = Hash.new(lambda { raise "Should not invoke lambda" }) + hash_a.send(cmd, hash_b) + hash_a.default.should == hash_b.default + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + HashSpecs.frozen_hash.send(cmd, HashSpecs.frozen_hash) # ok, nothing changed + block = lambda { HashSpecs.frozen_hash.send(cmd, HashSpecs.empty_frozen_hash) } + block.should raise_error(TypeError) + end + end + end +end diff --git a/1.8/core/hash/shared/store.rb b/1.8/core/hash/shared/store.rb new file mode 100644 index 0000000000..7831c36842 --- /dev/null +++ b/1.8/core/hash/shared/store.rb @@ -0,0 +1,47 @@ +shared :hash_store do |cmd| + describe "Hash##{cmd}" do + it "associates the key with the value and return the value" do + h = { :a => 1 } + h.send(cmd, :b, 2).should == 2 + h.should == {:b=>2, :a=>1} + end + + it "duplicates string keys using dup semantics" do + # dup doesn't copy singleton methods + key = "foo" + def key.reverse() "bar" end + h = {} + h.send(cmd, key, 0) + h.keys[0].reverse.should == "oof" + end + + it "stores unequal keys that hash to the same value" do + h = {} + k1 = ["x"] + k2 = ["y"] + # So they end up in the same bucket + def k1.hash() 0 end + def k2.hash() 0 end + + h[k1] = 1 + h[k2] = 2 + h.size.should == 2 + end + + compliant_on :ruby, :jruby do + it "duplicates and freezes string keys" do + key = "foo" + h = {} + h.send(cmd, key, 0) + key << "bar" + + h.should == { "foo" => 0 } + h.keys[0].frozen?.should == true + end + + it "raises a TypeError if called on a frozen instance" do + lambda { HashSpecs.frozen_hash.send(cmd, 1, 2) }.should raise_error(TypeError) + end + end + end +end diff --git a/1.8/core/hash/shared/update.rb b/1.8/core/hash/shared/update.rb new file mode 100644 index 0000000000..015ffc9e18 --- /dev/null +++ b/1.8/core/hash/shared/update.rb @@ -0,0 +1,50 @@ +shared :hash_update do |cmd| + describe "Hash##{cmd}" do + it "adds the entries from other, overwriting duplicate keys. Returns self" do + h = { :_1 => 'a', :_2 => '3' } + h.send(cmd, :_1 => '9', :_9 => 2).equal?(h).should == true + h.should == {:_1 => "9", :_2 => "3", :_9 => 2} + end + + it "sets any duplicate key to the value of block if passed a block" do + h1 = { :a => 2, :b => -1 } + h2 = { :a => -2, :c => 1 } + h1.send(cmd, h2) { |k,x,y| 3.14 }.equal?(h1).should == true + h1.should == {:c => 1, :b => -1, :a => 3.14} + + h1.send(cmd, h1) { nil } + h1.should == { :a => nil, :b => nil, :c => nil } + end + + it "calls to_hash on its argument" do + obj = mock('{1=>2}') + obj.should_receive(:to_hash).and_return({1 => 2}) + {3 => 4}.send(cmd, obj).should == {1 => 2, 3 => 4} + + obj = mock('{1=>2}') + obj.should_receive(:respond_to?).with(:to_hash).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_hash).and_return({ 1 => 2}) + {3 => 4}.send(cmd, obj).should == {1 => 2, 3 => 4} + end + + it "does not call to_hash on hash subclasses" do + {3 => 4}.send(cmd, ToHashHash[1 => 2]).should == {1 => 2, 3 => 4} + end + + it "processes entries with same order as merge()" do + h = {1 => 2, 3 => 4, 5 => 6, "x" => nil, nil => 5, [] => []} + merge_bang_pairs = [] + merge_pairs = [] + h.merge(h) { |*arg| merge_pairs << arg } + h.send(cmd, h) { |*arg| merge_bang_pairs << arg } + merge_bang_pairs.should == merge_pairs + end + + compliant_on :ruby do + it "raises a TypeError if called on a non-empty, frozen instance" do + HashSpecs.frozen_hash.send(cmd, HashSpecs.empty_frozen_hash) # ok, empty + lambda { HashSpecs.frozen_hash.send(cmd, 1 => 2) }.should raise_error(TypeError) + end + end + end +end diff --git a/1.8/core/hash/shared/value.rb b/1.8/core/hash/shared/value.rb new file mode 100644 index 0000000000..36e93eab44 --- /dev/null +++ b/1.8/core/hash/shared/value.rb @@ -0,0 +1,16 @@ +shared :hash_value_p do |cmd| + describe "Hash##{cmd}" do + it "returns true if the value exists in the hash" do + {:a => :b}.send(cmd, :a).should == false + {1 => 2}.send(cmd, 2).should == true + h = Hash.new(5) + h.send(cmd, 5).should == false + h = Hash.new { 5 } + h.send(cmd, 5).should == false + end + + it "uses == semantics for comparing values" do + { 5 => 2.0 }.send(cmd, 2).should == true + end + end +end diff --git a/1.8/core/hash/shift_spec.rb b/1.8/core/hash/shift_spec.rb new file mode 100644 index 0000000000..11d6365191 --- /dev/null +++ b/1.8/core/hash/shift_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#shift" do + it "removes a pair from hash and return it (same order as to_a)" do + h = { :a => 1, :b => 2, "c" => 3, nil => 4, [] => 5 } + pairs = h.to_a + + h.size.times do + r = h.shift + r.class.should == Array + r.should == pairs.shift + h.size.should == pairs.size + end + + h.should == {} + h.shift.should == nil + end + + it "returns (computed) default for empty hashes" do + Hash.new(5).shift.should == 5 + h = Hash.new { |*args| args } + h.shift.should == [h, nil] + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if called on a frozen instance" do + lambda { HashSpecs.frozen_hash.shift }.should raise_error(TypeError) + lambda { HashSpecs.empty_frozen_hash.shift }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/hash/size_spec.rb b/1.8/core/hash/size_spec.rb new file mode 100644 index 0000000000..22a2a1fd4e --- /dev/null +++ b/1.8/core/hash/size_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/length' + +describe "Hash#size" do + it_behaves_like(:hash_length, :size) +end diff --git a/1.8/core/hash/sort_spec.rb b/1.8/core/hash/sort_spec.rb new file mode 100644 index 0000000000..d395b70313 --- /dev/null +++ b/1.8/core/hash/sort_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#sort" do + it "converts self to a nested array of [key, value] arrays and sort with Array#sort" do + { 'a' => 'b', '1' => '2', 'b' => 'a' }.sort.should == [["1", "2"], ["a", "b"], ["b", "a"]] + end + + it "works when some of the keys are themselves arrays" do + { [1,2] => 5, [1,1] => 5 }.sort.should == [[[1,1],5], [[1,2],5]] + end + + it "uses block to sort array if passed a block" do + { 1 => 2, 2 => 9, 3 => 4 }.sort { |a,b| b <=> a }.should == [[3, 4], [2, 9], [1, 2]] + end +end diff --git a/1.8/core/hash/store_spec.rb b/1.8/core/hash/store_spec.rb new file mode 100644 index 0000000000..8ef87e4bc3 --- /dev/null +++ b/1.8/core/hash/store_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/store' + +describe "Hash#store" do + it_behaves_like(:hash_store, :store) +end diff --git a/1.8/core/hash/to_a_spec.rb b/1.8/core/hash/to_a_spec.rb new file mode 100644 index 0000000000..01a1e8caea --- /dev/null +++ b/1.8/core/hash/to_a_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#to_a" do + it "returns a list of [key, value] pairs with same order as each()" do + h = {:a => 1, 1 => :a, 3 => :b, :b => 5} + pairs = [] + + h.each_pair do |*pair| + pairs << pair + end + + h.to_a.class.should == Array + h.to_a.should == pairs + end +end diff --git a/1.8/core/hash/to_hash_spec.rb b/1.8/core/hash/to_hash_spec.rb new file mode 100644 index 0000000000..34871b91b4 --- /dev/null +++ b/1.8/core/hash/to_hash_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#to_hash" do + it "returns self" do + h = {} + h.to_hash.equal?(h).should == true + end +end diff --git a/1.8/core/hash/to_s_spec.rb b/1.8/core/hash/to_s_spec.rb new file mode 100644 index 0000000000..beaaec0cea --- /dev/null +++ b/1.8/core/hash/to_s_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#to_s" do + it "returns a string by calling Hash#to_a and using Array#join with default separator" do + h = { :fun => 'x', 1 => 3, nil => "ok", [] => :y } + h.to_a.to_s.should == h.to_s + old, $, = $,, ':' + h.to_a.to_s.should == h.to_s + $, = old + end +end diff --git a/1.8/core/hash/update_spec.rb b/1.8/core/hash/update_spec.rb new file mode 100644 index 0000000000..11d5ef6af8 --- /dev/null +++ b/1.8/core/hash/update_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/iteration' +require File.dirname(__FILE__) + '/shared/update' + +describe "Hash#update" do + it_behaves_like(:hash_update, :update) + + it_behaves_like(:hash_iteration_method, :update) + + compliant_on :ruby, :rubinius do + it_behaves_like(:hash_iteration_modifying, :update) + end +end diff --git a/1.8/core/hash/value_spec.rb b/1.8/core/hash/value_spec.rb new file mode 100644 index 0000000000..f4846d2af9 --- /dev/null +++ b/1.8/core/hash/value_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/value' + +describe "Hash#value?" do + it_behaves_like(:hash_value_p, :value?) +end + diff --git a/1.8/core/hash/values_at_spec.rb b/1.8/core/hash/values_at_spec.rb new file mode 100644 index 0000000000..18f0641a37 --- /dev/null +++ b/1.8/core/hash/values_at_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +shared :hash_values_at do |cmd| + describe "Hash##{cmd}" do + it "returns an array of values for the given keys" do + h = {:a => 9, :b => 'a', :c => -10, :d => nil} + h.send(cmd).class.should == Array + h.send(cmd).should == [] + h.send(cmd, :a, :d, :b).class.should == Array + h.send(cmd, :a, :d, :b).should == [9, nil, 'a'] + end + end +end + +describe "Hash#values_at" do + it_behaves_like(:hash_values_at, :values_at) +end \ No newline at end of file diff --git a/1.8/core/hash/values_spec.rb b/1.8/core/hash/values_spec.rb new file mode 100644 index 0000000000..54da8a91ad --- /dev/null +++ b/1.8/core/hash/values_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Hash#values" do + it "returns an array of values" do + h = { 1 => :a, 'a' => :a, 'the' => 'lang'} + h.values.class.should == Array + h.values.sort {|a, b| a.to_s <=> b.to_s}.should == [:a, :a, 'lang'] + end +end diff --git a/1.8/core/integer/ceil_spec.rb b/1.8/core/integer/ceil_spec.rb new file mode 100644 index 0000000000..551288d943 --- /dev/null +++ b/1.8/core/integer/ceil_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Integer#ceil" do + it_behaves_like(:integer_to_i, :ceil) +end diff --git a/1.8/core/integer/chr_spec.rb b/1.8/core/integer/chr_spec.rb new file mode 100644 index 0000000000..25aa47b922 --- /dev/null +++ b/1.8/core/integer/chr_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Integer#chr" do + it "returns a string containing the ASCII character represented by self" do + [82.chr, 117.chr, 98.chr, 105.chr, 110.chr, 105.chr, 117.chr, 115.chr, + 32.chr, + 114.chr, 111.chr, 99.chr, 107.chr, 115.chr].should == + ["R", "u", "b", "i", "n", "i", "u", "s", " ", "r", "o", "c", "k", "s"] + end + + it "returns a new string" do + 82.chr.equal?(82.chr).should == false + end +end diff --git a/1.8/core/integer/downto_spec.rb b/1.8/core/integer/downto_spec.rb new file mode 100644 index 0000000000..4b1896f74d --- /dev/null +++ b/1.8/core/integer/downto_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Integer#downto" do + it "passes block decreasing values from self down to and including other Integer" do + a = [] + 3.downto(-1) { |i| a << i } + -1.downto(3) { |i| a << i } + a.should == [3, 2, 1, 0, -1] + end +end diff --git a/1.8/core/integer/floor_spec.rb b/1.8/core/integer/floor_spec.rb new file mode 100644 index 0000000000..764d73c9bf --- /dev/null +++ b/1.8/core/integer/floor_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Integer#floor" do + it_behaves_like(:integer_to_i, :floor) +end diff --git a/1.8/core/integer/induced_from_spec.rb b/1.8/core/integer/induced_from_spec.rb new file mode 100644 index 0000000000..10ddee0749 --- /dev/null +++ b/1.8/core/integer/induced_from_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Integer.induced_from" do + it "converts other to Integer" do + Integer.induced_from(2.5).should == 2 + Integer.induced_from(-3.14).should == -3 + Integer.induced_from(1.233450999123389e+12).should == 1233450999123 + end +end diff --git a/1.8/core/integer/integer_spec.rb b/1.8/core/integer/integer_spec.rb new file mode 100644 index 0000000000..03260605d0 --- /dev/null +++ b/1.8/core/integer/integer_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Integer#integer?" do + it "returns true" do + 0.integer?.should == true + bignum_value.integer?.should == true + -1.integer?.should == true + end +end diff --git a/1.8/core/integer/next_spec.rb b/1.8/core/integer/next_spec.rb new file mode 100644 index 0000000000..665c0ab92d --- /dev/null +++ b/1.8/core/integer/next_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/next' + +describe "Integer#next" do + it_behaves_like(:integer_next, :next) +end diff --git a/1.8/core/integer/round_spec.rb b/1.8/core/integer/round_spec.rb new file mode 100644 index 0000000000..2858016307 --- /dev/null +++ b/1.8/core/integer/round_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Integer#round" do + it_behaves_like(:integer_to_i, :round) +end diff --git a/1.8/core/integer/shared/next.rb b/1.8/core/integer/shared/next.rb new file mode 100644 index 0000000000..b4109914fb --- /dev/null +++ b/1.8/core/integer/shared/next.rb @@ -0,0 +1,10 @@ +shared :integer_next do |cmd| + describe "Integer##{cmd}" do + it "returns the Integer equal to self + 1" do + 0.send(cmd).should == 1 + -1.send(cmd).should == 0 + bignum_value.send(cmd).should == 9223372036854775809 + 20.send(cmd).should == 21 + end + end +end diff --git a/1.8/core/integer/shared/to_i.rb b/1.8/core/integer/shared/to_i.rb new file mode 100644 index 0000000000..0b9e90656a --- /dev/null +++ b/1.8/core/integer/shared/to_i.rb @@ -0,0 +1,9 @@ +shared :integer_to_i do |cmd| + describe "Integer##{cmd}" do + it "returns self" do + a = 1 + a.send(cmd).should == 1 + a.send(cmd).eql?(a).should == true + end + end +end diff --git a/1.8/core/integer/succ_spec.rb b/1.8/core/integer/succ_spec.rb new file mode 100644 index 0000000000..807632de17 --- /dev/null +++ b/1.8/core/integer/succ_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/next' + +describe "Integer#succ" do + it_behaves_like(:integer_next, :succ) +end diff --git a/1.8/core/integer/times_spec.rb b/1.8/core/integer/times_spec.rb new file mode 100644 index 0000000000..93243a3299 --- /dev/null +++ b/1.8/core/integer/times_spec.rb @@ -0,0 +1,188 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Integer#times with block argument" do + it "passes block values from 0 to self - 1" do + a = [] + 9.times { |i| a << i } + -2.times { |i| a << i } + a.should == [0, 1, 2, 3, 4, 5, 6, 7, 8] + end + + it "executes a simple expression" do + a = 0 + b = 3.times do |i| + a += 1 + end + a.should == 3 + b.should == 3 + end + + it "skips the current iteration of the block from 'next' to the end" do + a = 0 + b = 3.times do |i| + next if a == 2 + a += 1 + end + a.should == 2 + b.should == 3 + end + + it "stops executing the block when it contains a break expression" do + a = 0 + b = 3.times do |i| + a += 1 + break + end + a.should == 1 + b.should == nil + end + + it "stops executing the block when it contains a break expression with argument" do + a = 0 + b = 3.times do |i| + a += 1 + break 9 + end + a.should == 1 + b.should == 9 + end + + it "stops executing the block when it contains an expression containing break" do + a = [false] + b = 1.times do |i| + a.shift or break + end + a.should == [] + b.should == nil + end + + it "stops executing the block when it contains a complex break expression" do + a = [false] + b = 2.times do |i| + (a.shift or break) << 'x' + end + a.should == [] + b.should == nil + end + + it "executes a nested while loop containing a break expression" do + a = [false] + b = 1.times do |i| + while true + a.shift or break + end + end + a.should == [] + b.should == 1 + end + + it "executes a nested while loop containing a complex break expression" do + a = [nil, nil] + b = 3.times do |i| + while true + (a.shift or break) << 'x' + end + end + a.should == [] + b.should == 3 + end + + it "executes a nested #times" do + a = 0 + b = 3.times do |i| + 2.times { a += 1 } + end + a.should == 6 + b.should == 3 + end +end + +describe "Integer#times without block argument" do + it "executes a simple expression" do + a = 0 + b = 3.times do + a += 1 + end + a.should == 3 + b.should == 3 + end + + it "skips the current iteration of the block from 'next' to the end" do + a = 0 + b = 3.times do + next if a == 2 + a += 1 + end + a.should == 2 + b.should == 3 + end + + it "stops executing the block when it contains a break expression" do + a = 0 + b = 3.times do + a += 1 + break + end + a.should == 1 + b.should == nil + end + + it "stops executing the block when it contains a break expression with argument" do + a = 0 + b = 3.times do + a += 1 + break 9 + end + a.should == 1 + b.should == 9 + end + + it "stops executing the block when it contains an expression containing break" do + a = [false] + b = 1.times do + a.shift or break + end + a.should == [] + b.should == nil + end + + it "stops executing the block when it contains a complex break expression" do + a = [false] + b = 2.times do + (a.shift or break) << 'x' + end + a.should == [] + b.should == nil + end + + it "executes a nested while loop containing a break expression" do + a = [false] + b = 1.times do + while true + a.shift or break + end + end + a.should == [] + b.should == 1 + end + + it "executes a nested while loop containing a complex break expression" do + a = [nil, nil] + b = 3.times do + while true + (a.shift or break) << 'x' + end + end + a.should == [] + b.should == 3 + end + + it "executes a nested #times" do + a = 0 + b = 3.times do + 2.times { a += 1 } + end + a.should == 6 + b.should == 3 + end +end diff --git a/1.8/core/integer/to_i_spec.rb b/1.8/core/integer/to_i_spec.rb new file mode 100644 index 0000000000..61292b081f --- /dev/null +++ b/1.8/core/integer/to_i_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Integer#to_i" do + it_behaves_like(:integer_to_i, :to_i) +end diff --git a/1.8/core/integer/to_int_spec.rb b/1.8/core/integer/to_int_spec.rb new file mode 100644 index 0000000000..3c45b65751 --- /dev/null +++ b/1.8/core/integer/to_int_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Integer#to_int" do + it_behaves_like(:integer_to_i, :to_int) +end diff --git a/1.8/core/integer/truncate_spec.rb b/1.8/core/integer/truncate_spec.rb new file mode 100644 index 0000000000..021d6bb498 --- /dev/null +++ b/1.8/core/integer/truncate_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Integer#truncate" do + it_behaves_like(:integer_to_i, :truncate) +end diff --git a/1.8/core/integer/upto_spec.rb b/1.8/core/integer/upto_spec.rb new file mode 100644 index 0000000000..588a08e78d --- /dev/null +++ b/1.8/core/integer/upto_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Integer#upto" do + it "passes block values from self up to and including other Integer" do + a = [] + 9.upto(13) { |i| a << i } + 2.upto(-1) { |i| a << i } + a.should == [9, 10, 11, 12, 13] + end +end diff --git a/1.8/core/io/binmode_spec.rb b/1.8/core/io/binmode_spec.rb new file mode 100644 index 0000000000..44d4109de0 --- /dev/null +++ b/1.8/core/io/binmode_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#binmode" do + it "does not raise any errors on closed stream" do + lambda { IOSpecs.closed_file.binmode }.should_not raise_error() + end +end diff --git a/1.8/core/io/close_read_spec.rb b/1.8/core/io/close_read_spec.rb new file mode 100644 index 0000000000..a2f9da9a21 --- /dev/null +++ b/1.8/core/io/close_read_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#close_read" do + before :each do + @io = IO.popen(RUBY_NAME, "r+") + end + after :each do + @io.close unless @io.closed? + end + + it "closes the read end of a duplex I/O stream" do + @io.close_read + lambda { @io.read() }.should raise_error(IOError) + lambda { @io.sysread(1) }.should raise_error(IOError) + end + + it "raises an IOError on subsequent invocations" do + @io.close_read + lambda { @io.close_read }.should raise_error(IOError) + lambda { @io.close_read }.should raise_error(IOError) + end + + it "allows subsequent invocation of close" do + @io.close_read + lambda { @io.close }.should_not raise_error + end + + it "raises an IOError if the stream is not duplexed." do + begin + io_w = IO.popen(RUBY_NAME, "w") + lambda { io_w.close_read }.should raise_error(IOError) + ensure + io_w.close + end + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.close_read }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/close_spec.rb b/1.8/core/io/close_spec.rb new file mode 100644 index 0000000000..03832e27d3 --- /dev/null +++ b/1.8/core/io/close_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO#close" do + before :each do + @io = IO.popen(RUBY_NAME, "r+") + end + after :each do + @io.close unless @io.closed? + end + + it "closes the stream" do + lambda { @io.close }.should_not raise_error + @io.closed?.should == true + end + + it "returns nil" do + @io.close.should == nil + end + + it "makes the stream unavailable for any further data operations" do + @io.close + lambda { @io.print "attempt to write" }.should raise_error(IOError) + lambda { @io.syswrite "attempt to write" }.should raise_error(IOError) + lambda { @io.read }.should raise_error(IOError) + lambda { @io.sysread(1) }.should raise_error(IOError) + end + + it "raises an IOError on subsequent invocations" do + @io.close + lambda { @io.close }.should raise_error(IOError) + lambda { @io.close }.should raise_error(IOError) + end + + it "sets $? if the stream is opened by IO.popen" do + @io.close + $?.should == 0 + + old_stderr = $stderr.dup + $stderr.reopen("/dev/null") + begin + @io = IO.popen("does-not-exist-for-sure", "r+") + @io.close + $?.exitstatus.should == 127 + ensure + $stderr.reopen(old_stderr) + end + end +end diff --git a/1.8/core/io/close_write_spec.rb b/1.8/core/io/close_write_spec.rb new file mode 100644 index 0000000000..6e8d867ae4 --- /dev/null +++ b/1.8/core/io/close_write_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#close_write" do + before :each do + @io = IO.popen(RUBY_NAME, "r+") + end + after :each do + @io.close unless @io.closed? + end + + it "closes the write end of a duplex I/O stream" do + @io.close_write + lambda { @io.print("attempt to write") }.should raise_error(IOError) + lambda { @io.syswrite("attempt to write") }.should raise_error(IOError) + end + + it "raises an IOError on subsequent invocations" do + @io.close_write + lambda { @io.close_write }.should raise_error(IOError) + lambda { @io.close_write }.should raise_error(IOError) + end + + it "allows subsequent invocation of close" do + @io.close_write + lambda { @io.close }.should_not raise_error + end + + it "raises an IOError if the stream is not duplexed." do + begin + io_r = IO.popen("ls", "r") + lambda { io_r.close_write }.should raise_error(IOError) + ensure + io_r.close + end + end + + it "flushes and closes the write stream" do + @io.print("p 12345") + @io.close_write + @io.read.should == "12345\n" + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.close_write }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/closed_spec.rb b/1.8/core/io/closed_spec.rb new file mode 100644 index 0000000000..5114e5807a --- /dev/null +++ b/1.8/core/io/closed_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO##{}closed?" do + it "returns true on closed stream" do + IOSpecs.closed_file.closed?.should == true + end + + it "returns false on open stream" do + File.open(File.dirname(__FILE__) + '/fixtures/gets.txt', 'r') { |io| + io.closed?.should == false + } + end +end diff --git a/1.8/core/io/constants_spec.rb b/1.8/core/io/constants_spec.rb new file mode 100644 index 0000000000..d8b49769cc --- /dev/null +++ b/1.8/core/io/constants_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO::SEEK_SET" do + it "is defined" do + IO.const_defined?(:SEEK_SET).should == true + end +end + +describe "IO::SEEK_CUR" do + it "is defined" do + IO.const_defined?(:SEEK_CUR).should == true + end +end + +describe "IO::SEEK_END" do + it "is defined" do + IO.const_defined?(:SEEK_END).should == true + end +end diff --git a/1.8/core/io/dup_spec.rb b/1.8/core/io/dup_spec.rb new file mode 100644 index 0000000000..ff9eaa4c85 --- /dev/null +++ b/1.8/core/io/dup_spec.rb @@ -0,0 +1,75 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#dup" do + before :all do + @file = "/tmp/rubinius_spec_io_dup_#{$$}_#{Time.now.to_f}" + end + + before :each do + @f = File.open @file, 'w+' + @i = @f.dup + + @f.sync = true + @i.sync = true + end + + after :each do + @i.close unless @i.closed? + @f.close unless @f.closed? + end + + after :all do + File.unlink @file if File.exists?(@file) + end + + it "returns a new IO instance" do + @i.class.should == @f.class + end + + it "sets a new descriptor on the returned object" do + @i.fileno.should_not == @f.fileno + end + +quarantine! do # This does not appear to be consistent across platforms + it "shares the original stream between the two IOs" do + start = @f.pos + @i.pos.should == start + + s = "Hello, wo.. wait, where am I?\n" + s2 = " Muhahahaa!" + + @f.write s + @i.pos.should == @f.pos + + @i.rewind + @i.gets.should == s + + @i.rewind + @i.write s2 + + @f.rewind + @f.gets.should == "#{s2}\n" + end +end + + it "allows closing the new IO without affecting the original" do + @i.close + lambda { @f.gets }.should_not raise_error(Exception) + + @i.closed?.should == true + @f.closed?.should == false + end + + it "allows closing the original IO without affecting the new one" do + @f.close + lambda { @i.gets }.should_not raise_error(Exception) + + @i.closed?.should == false + @f.closed?.should == true + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.dup }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/each_byte_spec.rb b/1.8/core/io/each_byte_spec.rb new file mode 100644 index 0000000000..88a48a21b5 --- /dev/null +++ b/1.8/core/io/each_byte_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#each_byte" do + it "raises IOError on closed stream" do + # each_byte must have a block in order to raise the Error. + # MRI 1.8.7 returns enumerator if block is not provided. + # See [ruby-core:16557]. + lambda { IOSpecs.closed_file.each_byte{} }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/each_line_spec.rb b/1.8/core/io/each_line_spec.rb new file mode 100644 index 0000000000..4aa0b1c83f --- /dev/null +++ b/1.8/core/io/each_line_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/each' + +describe "IO#each_line" do + it_behaves_like(:io_each, :each_line) +end diff --git a/1.8/core/io/each_spec.rb b/1.8/core/io/each_spec.rb new file mode 100644 index 0000000000..63cf9da1c2 --- /dev/null +++ b/1.8/core/io/each_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/each' + +describe "IO#each" do + it_behaves_like(:io_each, :each) +end diff --git a/1.8/core/io/eof_spec.rb b/1.8/core/io/eof_spec.rb new file mode 100644 index 0000000000..045878a2c6 --- /dev/null +++ b/1.8/core/io/eof_spec.rb @@ -0,0 +1,96 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#eof?" do + before :each do + @file_name = File.dirname(__FILE__) + '/fixtures/readlines.txt' + @file = File.open(@file_name, 'r') + end + + after :each do + @file.close unless @file.closed? + end + + it "returns false when not at end of file" do + @file.read 1 + @file.eof?.should == false + end + + it "returns true after reading with read with no parameters" do + @file.read() + @file.eof?.should == true + end + + it "returns true after reading with read" do + @file.read(File.size(@file_name)) + @file.eof?.should == true + end + + it "returns true after reading with sysread" do + @file.sysread(File.size(@file_name)) + @file.eof?.should == true + end + + it "returns true after reading with readlines" do + @file.readlines + @file.eof?.should == true + end + + it "returns true on just opened empty stream" do + File.open('/tmp/empty.txt', "w") { |empty| } # ensure it exists + File.open('/tmp/empty.txt') { |empty| + empty.eof?.should == true + } + end + + it "returns false on just opened non-empty stream" do + @file.eof?.should == false + end + + it "should not consume the data from the stream" do + @file.eof?.should == false + @file.getc.should == 86 + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.eof? }.should raise_error(IOError) + end + + it "raises IOError on stream not opened for reading" do + lambda { + File.open('/tmp/empty.txt', "w") { |empty| + empty.eof? + } + }.should raise_error(IOError) + end + + it "raises IOError on stream closed for reading by close_read" do + @file.close_read + lambda { @file.eof? }.should raise_error(IOError) + end + + it "returns true on one-byte stream after single-byte read" do + File.open(File.dirname(__FILE__) + '/fixtures/one_byte.txt') { |one_byte| + one_byte.read(1) + one_byte.eof?.should == true + } + end + + it "returns true on receiving side of Pipe when writing side is closed" do + r, w = IO.pipe + w.close + r.eof?.should == true + r.close + end + + it "returns false on receiving side of Pipe when writing side wrote some data" do + r, w = IO.pipe + w.puts "hello" + r.eof?.should == false + w.close + r.eof?.should == false + r.read + r.eof?.should == true + r.close + end +end diff --git a/1.8/core/io/fcntl_spec.rb b/1.8/core/io/fcntl_spec.rb new file mode 100644 index 0000000000..0d2ca85643 --- /dev/null +++ b/1.8/core/io/fcntl_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#fcntl" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.fcntl(5, 5) }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/fileno_spec.rb b/1.8/core/io/fileno_spec.rb new file mode 100644 index 0000000000..ecd49891ff --- /dev/null +++ b/1.8/core/io/fileno_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#fileno" do + it "returns the numeric file descriptor of the given IO object" do + $stdout.fileno.should == 1 + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.fileno }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/fixtures/classes.rb b/1.8/core/io/fixtures/classes.rb new file mode 100644 index 0000000000..2d1b03a683 --- /dev/null +++ b/1.8/core/io/fixtures/classes.rb @@ -0,0 +1,34 @@ +module IOSpecs + def self.lines + [ "Voici la ligne une.\n", + "Qui \303\250 la linea due.\n", + "\n", + "\n", + "Aqu\303\255 est\303\241 la l\303\255nea tres.\n", + "Ist hier Linie vier.\n", + "\n", + "Est\303\241 aqui a linha cinco.\n", + "Here is line six.\n" ] + end + + def self.gets_fixtures + File.dirname(__FILE__) + '/gets.txt' + end + + def self.gets_output + File.dirname(__FILE__) + '/gets_output.txt' + end + + def self.closed_file + File.open(File.dirname(__FILE__) + '/gets.txt', 'r') { |f| f } + end + + def self.closed_io + File.open(gets_fixtures, 'r') { |file| + IO.open(file.fileno, 'r') { |io| + io + } + } + end + +end diff --git a/1.8/core/io/fixtures/gets.txt b/1.8/core/io/fixtures/gets.txt new file mode 100644 index 0000000000..a64d8ff6bb --- /dev/null +++ b/1.8/core/io/fixtures/gets.txt @@ -0,0 +1,9 @@ +Voici la ligne une. +Qui è la linea due. + + +Aquí está la línea tres. +Ist hier Linie vier. + +Está aqui a linha cinco. +Here is line six. diff --git a/1.8/core/io/fixtures/numbered_lines.txt b/1.8/core/io/fixtures/numbered_lines.txt new file mode 100644 index 0000000000..70e49a3d98 --- /dev/null +++ b/1.8/core/io/fixtures/numbered_lines.txt @@ -0,0 +1,5 @@ +Line 1: One +Line 2: Two +Line 3: Three +Line 4: Four +Line 5: Five diff --git a/1.8/core/io/fixtures/one_byte.txt b/1.8/core/io/fixtures/one_byte.txt new file mode 100644 index 0000000000..56a6051ca2 --- /dev/null +++ b/1.8/core/io/fixtures/one_byte.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/1.8/core/io/fixtures/readlines.txt b/1.8/core/io/fixtures/readlines.txt new file mode 100644 index 0000000000..d01869936f --- /dev/null +++ b/1.8/core/io/fixtures/readlines.txt @@ -0,0 +1,6 @@ +Voici la ligne une. +Qui è la linea due. +Aquí está la línea tres. +Ist hier Linie vier. +Está aqui a linha cinco. +Here is line six. diff --git a/1.8/core/io/flush_spec.rb b/1.8/core/io/flush_spec.rb new file mode 100644 index 0000000000..4e92317574 --- /dev/null +++ b/1.8/core/io/flush_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#flush" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.flush }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/for_fd_spec.rb b/1.8/core/io/for_fd_spec.rb new file mode 100644 index 0000000000..4ad583061f --- /dev/null +++ b/1.8/core/io/for_fd_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#for_fd" do + it "raises IOError on closed stream" do + lambda { IO.for_fd(IOSpecs.closed_file.fileno) }.should raise_error(IOError) + end +end + +describe "IO.for_fd" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/foreach_spec.rb b/1.8/core/io/foreach_spec.rb new file mode 100644 index 0000000000..35ba393775 --- /dev/null +++ b/1.8/core/io/foreach_spec.rb @@ -0,0 +1,116 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO::foreach" do + before :all do + @file = File.dirname(__FILE__) + '/fixtures/readlines.txt' + @content = ["Voici la ligne une.\n", "Qui \303\250 la linea due.\n", + "Aqu\303\255 est\303\241 la l\303\255nea tres.\n", "Ist hier Linie vier.\n", + "Est\303\241 aqui a linha cinco.\n", "Here is line six.\n"] + @content_with_r = ["Voici la ligne une.\nQui \303\250 la linea due.\nAqu\303\255 est\303\241 la l\303\255nea tr", + "es.\nIst hier", " Linie vier", + ".\nEst\303\241 aqui a linha cinco.\nHer","e is line six.\n"] + end + after :all do + @file = nil + @content = nil + end + + it "yields a sequence of Strings that were separated by $/" do + lines = [] + IO::foreach(@file) do |line| + lines << line + end + lines.should == @content + end + + it "yields a sequence of Strings that were separated by r" do + lines = [] + IO::foreach(File.dirname(__FILE__) + '/fixtures/readlines.txt','r') do |line| + lines << line + end + lines.should == @content_with_r + end + + it "yields a single string with entire content when the separator is nil" do + lines = [] + IO::foreach(@file, nil) do |line| + lines << line + end + lines.should == [@content.join] + end + + it "yields a sequence of paragraphs when the separator is an empty string" do + lines = [] + IO::foreach(File.dirname(__FILE__) + '/fixtures/gets.txt', "") do |line| + lines << line + end + lines.should == [ + "Voici la ligne une.\nQui \303\250 la linea due.\n\n", + "Aqu\303\255 est\303\241 la l\303\255nea tres.\nIst hier Linie vier.\n\n", + "Est\303\241 aqui a linha cinco.\nHere is line six.\n"] + end + + it "updates $. with each yield" do + count = 1 + IO::foreach(@file, nil) do + $..should == count + count += 1 + end + + count = 1 + IO::foreach(@file, "") do + $..should == count + count += 1 + end + + count = 1 + IO::foreach(@file) do + $..should == count + count += 1 + end + + count = 1 + IO::foreach(@file, "la") do + $..should == count + count += 1 + end + end + + it "can handle non-ASCII data as separator" do + lines = [] + IO::foreach(@file, "\303\250") do |line| + lines << line + end + lines.should == ["Voici la ligne une.\nQui \303\250", + " la linea due.\nAqu\303\255 est\303\241 la l\303\255nea tres.\nIst hier Linie vier.\nEst\303\241 aqui a linha cinco.\nHere is line six.\n"] + end + + it "raises TypeError if the first parameter is nil" do + lambda { + IO::foreach(nil) {} + }.should raise_error(TypeError) + end + + it "converts first parameter to string and uses as file name" do + (obj = mock('readlines.txt')).should_receive(:to_str).and_return(@file) + lines = [] + IO::foreach(obj) do |line| + lines << line + end + lines.should == @content + end + + it "converts second parameter to string and uses as separator" do + (obj = mock('r')).should_receive(:to_str).and_return('r') + lines = [] + IO::foreach(@file, obj) do |line| + lines << line + end + lines.should == @content_with_r + end +end + +describe "IO.foreach" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/fsync_spec.rb b/1.8/core/io/fsync_spec.rb new file mode 100644 index 0000000000..33e5beaf94 --- /dev/null +++ b/1.8/core/io/fsync_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#fsync" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.fsync }.should raise_error(IOError) + end +end \ No newline at end of file diff --git a/1.8/core/io/getc_spec.rb b/1.8/core/io/getc_spec.rb new file mode 100644 index 0000000000..c1791602fd --- /dev/null +++ b/1.8/core/io/getc_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#getc" do + before :each do + @file_name = File.dirname(__FILE__) + '/fixtures/readlines.txt' + @file = File.open(@file_name, 'r') + end + + after :each do + @file.close unless @file.closed? + end + + it "returns the next byte from the stream" do + @file.getc.should == 86 + @file.getc.should == 111 + @file.getc.should == 105 + # read the rest of line + @file.readline.should == "ci la ligne une.\n" + @file.getc.should == 81 + end + + it "returns nil when invoked at the end of the stream" do + # read entire content + @file.read + @file.getc.should == nil + end + + it "returns nil on empty stream" do + File.open('/tmp/empty.txt') { |empty| + empty.getc.should == nil + } + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.getc }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/gets_spec.rb b/1.8/core/io/gets_spec.rb new file mode 100644 index 0000000000..327ae6bdd5 --- /dev/null +++ b/1.8/core/io/gets_spec.rb @@ -0,0 +1,166 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#gets" do + after :each do + File.delete IOSpecs.gets_output if File.exists?(IOSpecs.gets_output) + end + + it "returns the next line of string that were separated by $/" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + IOSpecs.lines.each {|line| line.should == f.gets} + end + end + + it "returns tainted strings" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets(nil)) + line.tainted?.should == true + end + end + + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets("")) + line.tainted?.should == true + end + end + + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets) + line.tainted?.should == true + end + end + + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets("la")) + line.tainted?.should == true + end + end + end + + it "updates lineno with each invocation" do + count = 1 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets(nil)) + f.lineno.should == count + count += 1 + end + end + + count = 1 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets("")) + f.lineno.should == count + count += 1 + end + end + + count = 1 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets) + f.lineno.should == count + count += 1 + end + end + + count = 1 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets("la")) + f.lineno.should == count + count += 1 + end + end + end + + it "updates $. with each invocation" do + count = 1 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets(nil)) + $..should == count + count += 1 + end + end + + count = 1 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets("")) + $..should == count + count += 1 + end + end + + count = 1 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets) + $..should == count + count += 1 + end + end + + count = 1 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + while (line = f.gets("la")) + $..should == count + count += 1 + end + end + end + + it "assigns the returned line to $_" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + IOSpecs.lines.each do |line| + f.gets + $_.should == line + end + end + end + + it "returns nil if called at the end of the stream" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + IOSpecs.lines.length.times { f.gets } + f.gets.should == nil + end + end + + it "returns the entire content if the separator is nil" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + f.gets(nil).should == IOSpecs.lines.join('') + end + end + + # Two successive newlines in the input separate paragraphs. + # When there are more than two successive newlines, only two are kept. + it "returns the next paragraph if the separator's length is 0" do + a = "Voici la ligne une.\nQui \303\250 la linea due.\n\n" + b = "Aqu\303\255 est\303\241 la l\303\255nea tres.\nIst hier Linie vier.\n\n" + c = "Est\303\241 aqui a linha cinco.\nHere is line six.\n" + + File.open(IOSpecs.gets_fixtures, 'r') do |f| + f.gets("").should == a + f.gets("").should == b + f.gets("").should == c + end + end + + # This could probably be added to the previous test using pos, but right now + # this doesn't pass and the previous test does. + it "reads until the beginning of the next paragraph when the separator's length is 0" do + # Leverage the fact that there are three newlines between the first + # and second paragraph + File.open(IOSpecs.gets_fixtures, 'r') do |f| + f.gets('') + + # This should return 'A', the first character of the next paragraph, not $/ + f.read(1).should == 'A' + end + end + + it "raises an IOError if the stream is not opened for reading" do + lambda { File.open(IOSpecs.gets_output, 'a') {|f| f.gets} }.should raise_error(IOError) + lambda { File.open(IOSpecs.gets_output, 'w') {|f| f.gets} }.should raise_error(IOError) + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.gets }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/initialize_copy_spec.rb b/1.8/core/io/initialize_copy_spec.rb new file mode 100644 index 0000000000..2756be047b --- /dev/null +++ b/1.8/core/io/initialize_copy_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO#initialize_copy" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/initialize_spec.rb b/1.8/core/io/initialize_spec.rb new file mode 100644 index 0000000000..6af87f59b1 --- /dev/null +++ b/1.8/core/io/initialize_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#initialize" do + before :each do + @io = IO.allocate + end + + it "succeeds when fd is a Fixnum" do + lambda { @io.send :initialize, $stdout.fileno, 'w' }.should_not raise_error(TypeError) + end + + it "succeeds when fd responds to #to_int" do + obj = mock('fileno') + def obj.to_int() $stdout.fileno end + + lambda { @io.send :initialize, obj, 'w' }.should_not raise_error(TypeError) + end + + it "raises a TypeError when fd is an IO" do + lambda { @io.send :initialize, $stdout, 'w' }.should raise_error(TypeError) + end + + it "raises a TypeError when given a non-integer" do + lambda { @io.send :initialize, @fname, 'w' }.should raise_error(TypeError) + end + + it "raises IOError on closed stream" do + lambda { @io.send :initialize, IOSpecs.closed_file.fileno }.should raise_error(IOError) + end + + it "raises an Errno::EBADF when given an invalid file descriptor" do + lambda { @io.send :initialize, -1, 'w' }.should raise_error(Errno::EBADF) + end +end diff --git a/1.8/core/io/inspect_spec.rb b/1.8/core/io/inspect_spec.rb new file mode 100644 index 0000000000..fb03eb1d2e --- /dev/null +++ b/1.8/core/io/inspect_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#inspect" do + it "does not raise anything when invoked on closed stream" do + lambda { IOSpecs.closed_file.inspect }.should_not raise_error + lambda { IOSpecs.closed_io.inspect }.should_not raise_error + end +end diff --git a/1.8/core/io/ioctl_spec.rb b/1.8/core/io/ioctl_spec.rb new file mode 100644 index 0000000000..bdcb53849c --- /dev/null +++ b/1.8/core/io/ioctl_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#ioctl" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.ioctl(5, 5) }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/isatty_spec.rb b/1.8/core/io/isatty_spec.rb new file mode 100644 index 0000000000..a82dd0d804 --- /dev/null +++ b/1.8/core/io/isatty_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/tty_shared.rb' + +describe "IO#isatty" do + it_behaves_like :io_tty, :isatty +end diff --git a/1.8/core/io/lineno_spec.rb b/1.8/core/io/lineno_spec.rb new file mode 100644 index 0000000000..402d5ab8d8 --- /dev/null +++ b/1.8/core/io/lineno_spec.rb @@ -0,0 +1,84 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#lineno" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.lineno }.should raise_error(IOError) + end + + it "returns the current line number" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + f.lineno.should == 0 + while (f.gets) + f.lineno.should > 0 + end + f.rewind + f.lineno.should == 0 + end + end +end + +describe "IO#lineno=" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.lineno = 5 }.should raise_error(IOError) + end + + it "invokes to_int on non-numeric arguments" do + (obj = mock('123')).should_receive(:to_int).and_return(123) + File.open(IOSpecs.gets_fixtures, 'r') do |f| + f.lineno = obj + f.lineno.should == 123 + + f.lineno = 1.5 + f.lineno.should == 1 + + f.lineno = 92233.72036854775808 + f.lineno.should == 92233 + end + end + + it "raises TypeError on nil argument" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + lambda { f.lineno = nil }.should raise_error(TypeError) + end + end + + it "sets the current line number to the given value" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + count = 500 + f.lineno = count - 1 + while (f.gets) + f.lineno.should == count + count += 1 + end + f.rewind + f.lineno.should == 0 + end + end + + it "does not change $." do + orig_value = $. + File.open(IOSpecs.gets_fixtures, 'r') do |f| + numbers = [-2**30, -2**16, -2**8, -100, -10, -1, 0, 1, 10, 2**8, 2**16, 2**30] + numbers.each { |num| + f.lineno = num + f.lineno.should == num + $..should == orig_value + } + end + end + + it "does not change $. until next read" do + $. = 0 + File.open(IOSpecs.gets_fixtures, 'r') do |f| + $..should == 0 + count = 500 + f.lineno = count - 1 + $..should == 0 + while (f.gets) + $..should == count + count += 1 + end + end + end +end diff --git a/1.8/core/io/new_spec.rb b/1.8/core/io/new_spec.rb new file mode 100644 index 0000000000..34b8959b68 --- /dev/null +++ b/1.8/core/io/new_spec.rb @@ -0,0 +1,66 @@ +require "#{File.dirname __FILE__}/../../spec_helper" +require "#{File.dirname __FILE__}/shared/new_shared" +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO.new" do + it_behaves_like :io_new, :new +end + +describe "IO.new" do + before :all do + @filename = "/tmp/rubinius-spec-io-new-#{$$}.txt" + end + + after :all do + File.unlink @filename + end + + before :each do + @file = File.open @filename, "w" + end + + after :each do + @file.close unless @file.closed? rescue Errno::EBADF + end + + it "does not execute a block if given one" do + l = lambda { + io = IO.new(@file.fileno, 'w') {|io| raise Exception, "N-uh" } + io.close + } + l.should_not raise_error(Exception, "N-uh") + end + + it "raises IOError on closed stream" do + lambda { IO.new(IOSpecs.closed_file.fileno, 'w') }.should raise_error(IOError) + end + + it "does not close the stream automatically if given a block" do + begin + io = IO.new(@file.fileno, 'w') {|f| puts f.read } + io.closed?.should == false + @file.closed?.should == false + ensure + io.close + end + end + + it "emits a warning if given a block" do + lambda { + io = IO.new(@file.fileno, 'w') {|io| puts io.read } + io.close + }.should complain(/IO::new.*does not take block.*IO::open.*instead/) + end + + it "accepts only one argument" do + # By default, IO.new without an arg assumes RO + @file.close + @file = File.open @filename, 'r' + lambda { IO.new(@file.fileno) }.should_not raise_error() + end +end + +describe "IO#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/open_spec.rb b/1.8/core/io/open_spec.rb new file mode 100644 index 0000000000..a9fbc31603 --- /dev/null +++ b/1.8/core/io/open_spec.rb @@ -0,0 +1,79 @@ +require "#{File.dirname __FILE__}/../../spec_helper" +require "#{File.dirname __FILE__}/shared/new_shared" +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO.open" do + it_behaves_like :io_new, :open +end + +describe "IO.open" do + before :all do + @file_name = File.dirname(__FILE__) + '/fixtures/gets.txt' + end + + it "raises IOError on closed stream" do + lambda { IO.open(IOSpecs.closed_file.fileno, 'w') }.should raise_error(IOError) + end + + it "with a block invokes close on opened IO object when exiting the block" do + File.open(@file_name, 'r') do |f| + io = IO.open(f.fileno, 'r') do |io| + class << io + @res = "close was not invoked" + alias_method(:close_orig, :close) + def close; close_orig; @res = "close was invoked"; end + def to_s; @res; end + end + io + end + io.to_s.should == "close was invoked" + end + end + + it "with a block propagates non-StandardErrors produced by close" do + lambda { + File.open(@file_name, 'r') do |f| + IO.open(f.fileno, 'r') do |io| + class << io + alias_method(:close_orig, :close) + def close + close_orig + raise Exception, "exception out of close" + end + end + end + end + }.should raise_error(Exception, "exception out of close") + end + + it "with a block swallows StandardErrors produced by close" do + File.open(@file_name, 'r') do |f| + IO.open(f.fileno, 'r') do |io| + class << io + alias_method(:close_orig, :close) + def close + close_orig + raise IOError + end + end + end + end + end + +# before :all do +# @filename = "/tmp/rubinius-spec-io-new-#{$$}.txt" +# end +# +# after :all do +# File.unlink @filename +# end +# +# before :each do +# @file = File.open @filename, "w" +# end +# +# after :each do +# # This should normally NOT be rescued +# @file.close unless @file.closed? rescue nil +# end +end diff --git a/1.8/core/io/output_spec.rb b/1.8/core/io/output_spec.rb new file mode 100644 index 0000000000..f54a933b65 --- /dev/null +++ b/1.8/core/io/output_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO#<<" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/pid_spec.rb b/1.8/core/io/pid_spec.rb new file mode 100644 index 0000000000..38f0d9a6ab --- /dev/null +++ b/1.8/core/io/pid_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO#pid" do + before :each do + @file = File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r') + @io = IO.open @file.fileno, 'r' + end + + after :each do + # we *must* close both in order to not leak descriptors + @io.close unless @io.closed? + @file.close unless @file.closed? rescue Errno::EBADF + end + + it "returns nil for IO not associated with a process" do + @io.pid.should == nil + end + + it "returns the ID of a process associated with stream" do + IO.popen(RUBY_NAME, "r+") { |io| + io.pid.should_not == nil + } + end + + it "raises IOError on closed stream" do + process_io = IO.popen(RUBY_NAME, "r+") { |io| io } + lambda { process_io.pid }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/pipe_spec.rb b/1.8/core/io/pipe_spec.rb new file mode 100644 index 0000000000..d3a7999a38 --- /dev/null +++ b/1.8/core/io/pipe_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO.pipe" do + it "creates a two-ended pipe" do + r, w = IO.pipe + w.puts "test_create_pipe\\n" + w.close + r.read(16).should == "test_create_pipe" + r.close + end +end diff --git a/1.8/core/io/popen_spec.rb b/1.8/core/io/popen_spec.rb new file mode 100644 index 0000000000..9121e48e35 --- /dev/null +++ b/1.8/core/io/popen_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO#popen" do + it "reads from a read-only pipe" do + IO.popen("echo foo", "r") do |pipe| + pipe.read.should == "foo\n" + end + end + + platform_is_not :windows do + it "writes to a read/write pipe" do + IO.popen("cat", "r+") do |pipe| + pipe.write("bar") + pipe.read 3 + end.should == "bar" + end + end + + it "with block does not raise error when io closed inside the block" do + lambda { + @io = IO.popen(RUBY_NAME, "r+") { |io| io.close; io } + }.should_not raise_error + @io.closed?.should == true + end +end + +describe "IO.popen" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/pos_spec.rb b/1.8/core/io/pos_spec.rb new file mode 100644 index 0000000000..e0a6be2435 --- /dev/null +++ b/1.8/core/io/pos_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/pos' + +describe "IO#pos" do + it_behaves_like(:io_pos, :pos) +end + +describe "IO#pos=" do + + before :each do + @fname = 'test.txt' + File.open @fname, 'w' do |f| f.write "123" end + end + + after :each do + File.unlink @fname + end + + it "sets the offset" do + File.open @fname do |f| + val1 = f.read 1 + f.pos = 0 + f.read(1).should == val1 + end + end + + it "can handle any numerical argument without breaking" do + File.open @fname do |f| + f.seek(1.2).should == 0 + f.seek(2**32).should == 0 + f.seek(1.23423423432e12).should == 0 + f.seek(0.00000000000000000000001).should == 0 + lambda { f.seek(2**128) }.should raise_error(RangeError) + end + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.pos = 0 }.should raise_error(IOError) + end + +end + diff --git a/1.8/core/io/print_spec.rb b/1.8/core/io/print_spec.rb new file mode 100644 index 0000000000..22f25f660f --- /dev/null +++ b/1.8/core/io/print_spec.rb @@ -0,0 +1,59 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe IO, "#print" do + class IOSpecPrint + attr_accessor :message + def to_s; @message; end + end + + before :each do + @old_separator = $\ + $\ = '->' + end + + after :each do + $\ = @old_separator + end + + it "writes $_.to_s followed by $\\ (if any) to the stream if no arguments given" do + o = IOSpecPrint.new + o.message = 'I know what you did last line!' + $_ = o + l = lambda { $stdout.print }.should output_to_fd("#{o.message}#{$\}", STDOUT) + + string = File.open(__FILE__) {|f| f.gets } # Set $_ to something known + lambda { $stdout.print }.should output_to_fd("#{string}#{$\}", STDOUT) + end + + it "writes obj.to_s followed by $\\ (if any) to the stream when given one object" do + o = Object.new + def o.to_s(); 'I am an object'; end + + lambda { $stdout.print(o) }.should output("#{o.to_s}#{$\}") + end + + it "does not call obj.to_str" do + o = Object.new + def o.to_str(); 'Haha!'; end + + lambda { $stdout.print(o) }.should output("#{o.to_s}#{$\}") + end + + it "writes each obj.to_s to the stream and appends $\\ (if any) given multiple objects" do + o, o2 = Object.new, Object.new + def o.to_s(); 'o'; end + def o2.to_s(); 'o2'; end + + lambda { $stdout.print(o, o2) }.should output("#{o.to_s}#{o2.to_s}#{$\}") + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.print("stuff") }.should raise_error(IOError) + end +end + +describe "IO#print" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/printf_spec.rb b/1.8/core/io/printf_spec.rb new file mode 100644 index 0000000000..355a0a617d --- /dev/null +++ b/1.8/core/io/printf_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#printf" do + before :each do + @io = IO.new STDOUT.fileno, 'w' + end + + it "writes the #sprintf formatted string to the file descriptor" do + lambda { + @io.printf "%s\n", "look ma, no hands" + }.should output_to_fd("look ma, no hands\n", @io) + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.printf("stuff") }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/putc_spec.rb b/1.8/core/io/putc_spec.rb new file mode 100644 index 0000000000..ac2698d992 --- /dev/null +++ b/1.8/core/io/putc_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#putc" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.putc('a') }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/puts_spec.rb b/1.8/core/io/puts_spec.rb new file mode 100644 index 0000000000..2d195e9b7e --- /dev/null +++ b/1.8/core/io/puts_spec.rb @@ -0,0 +1,84 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# TODO: need to find a better way to test this. Too fragile to set expectations +# to each write call. Only care that all the characters are sent not the number +# or write calls. Also, these tests do not make sure the ordering of the write calls +# are correct. +describe "IO#puts" do + before(:each) do + @io = IO.new(2, 'w') + end + + it "writes just a newline when given no args" do + @io.should_receive(:write).with("\n") + @io.puts.should == nil + end + + it "writes just a newline when given just a newline" do + lambda { $stdout.puts "\n" }.should output_to_fd("\n", STDOUT) + end + + it "writes nil with a newline when given nil as an arg" do + @io.should_receive(:write).with("nil") + @io.should_receive(:write).with("\n") + @io.puts(nil).should == nil + end + + it "calls to_s before writing non-string objects" do + object = mock('hola') + object.should_receive(:to_s).and_return("hola") + + @io.should_receive(:write).with("hola") + @io.should_receive(:write).with("\n") + @io.puts(object).should == nil + end + + it "writes each arg if given several" do + @io.should_receive(:write).with("1") + @io.should_receive(:write).with("two") + @io.should_receive(:write).with("3") + @io.should_receive(:write).with("\n").exactly(3).times + @io.puts(1, "two", 3).should == nil + end + + it "flattens a nested array before writing it" do + @io.should_receive(:write).with("1") + @io.should_receive(:write).with("2") + @io.should_receive(:write).with("3") + @io.should_receive(:write).with("\n").exactly(3).times + @io.puts([1, 2, [3]]).should == nil + end + + it "writes [...] for a recursive array arg" do + x = [] + x << 2 << x + @io.should_receive(:write).with("2") + @io.should_receive(:write).with("[...]") + @io.should_receive(:write).with("\n").exactly(2).times + @io.puts(x).should == nil + end + + it "writes a newline after objects that do not end in newlines" do + @io.should_receive(:write).with("5") + @io.should_receive(:write).with("\n") + @io.puts(5).should == nil + end + + it "does not write a newline after objects that end in newlines" do + @io.should_receive(:write).with("5\n") + @io.puts("5\n").should == nil + end + + it "ignores the $/ separator global" do + $/ = ":" + @io.should_receive(:write).with("5") + @io.should_receive(:write).with("\n") + @io.puts(5).should == nil + $/ = "\n" + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.puts("stuff") }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/read_nonblock_spec.rb b/1.8/core/io/read_nonblock_spec.rb new file mode 100644 index 0000000000..c70fe9da16 --- /dev/null +++ b/1.8/core/io/read_nonblock_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#read_nonblock" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.read_nonblock(5) }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/read_spec.rb b/1.8/core/io/read_spec.rb new file mode 100644 index 0000000000..88fe4a1057 --- /dev/null +++ b/1.8/core/io/read_spec.rb @@ -0,0 +1,222 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO.read" do + before :each do + @fname = "test.txt" + @contents = "1234567890" + File.open(@fname, "w") { |f| f.write(@contents) } + end + + after :each do + File.delete(@fname) if File.exists?(@fname) + end + + it "reads the contents of a file" do + IO.read(@fname).should == @contents + end + + it "treats second nil argument as no length limit" do + IO.read(@fname, nil).should == @contents + IO.read(@fname, nil, 5).should == IO.read(@fname, @contents.length, 5) + end + + it "treats third nil argument as 0" do + IO.read(@fname, nil, nil).should == @contents + IO.read(@fname, 5, nil).should == IO.read(@fname, 5, 0) + end + + it "reads the contents of a file up to a certain size when specified" do + IO.read(@fname, 5).should == @contents.slice(0..4) + end + + it "reads the contents of a file from an offset of a specific size when specified" do + IO.read(@fname, 5, 3).should == @contents.slice(3, 5) + end + + it "returns nil at end-of-file with a length" do + IO.read(@fname, 1, 10).should == nil + end + + describe "on empty file" do + + before :each do + @fname = 'empty_test.txt' + File.open(@fname, 'w') {|f| 1 } + end + + it "returns nil when length provided" do + IO.read(@fname, 1).should == nil + end + + it "returns empty string when no length provided" do + IO.read(@fname).should == "" + end + + after :each do + File.delete(@fname) if File.exists?(@fname) + end + + end + + it "raises an Errno::ENOENT when the requested file does not exist" do + File.delete(@fname) if File.exists?(@fname) + lambda { IO.read @fname }.should raise_error(Errno::ENOENT) + end + + it "raises a TypeError when not passed a String type" do + lambda { IO.read nil }.should raise_error(TypeError) + end + + it "raises an ArgumentError when not passed a valid length" do + lambda { IO.read @fname, -1 }.should raise_error(ArgumentError) + end + + it "raises an Errno::EINVAL when not passed a valid offset" do + lambda { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL) + lambda { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL) + end +end + +describe "IO#read" do + + before :each do + @fname = "test.txt" + @contents = "1234567890" + open @fname, "w" do |io| io.write @contents end + + @io = open @fname, "r+" + end + + after :each do + @io.close + File.delete(@fname) if File.exists?(@fname) + end + + it "can be read from consecutively" do + @io.read(1).should == '1' + @io.read(2).should == '23' + @io.read(3).should == '456' + @io.read(4).should == '7890' + end + + it "can read lots of data" do + data = "\xaa" * (8096 * 2 + 1024) # HACK IO::BufferSize + + File.open @fname, 'w' do |io| io.write data end + + actual = nil + + File.open @fname, 'r' do |io| + actual = io.read + end + + actual.length.should == data.length + actual.split('').all? { |c| c == "\xaa" }.should == true + end + + it "can read lots of data with length" do + read_length = 8096 * 2 + 1024 # HACK IO::BufferSize + data = "\xaa" * (read_length + 8096) # HACK same + + File.open @fname, 'w' do |io| io.write data end + + actual = nil + + File.open @fname, 'r' do |io| + actual = io.read read_length + end + + actual.length.should == read_length + actual.split('').all? { |c| c == "\xaa" }.should == true + end + + it "consumes zero bytes when reading zero bytes" do + pre_pos = @io.pos + + @io.read(0).should == '' + + @io.getc.chr.should == '1' + end + + it "is at end-of-file when everything has been read" do + @io.read + @io.eof?.should == true + end + + it "reads the contents of a file" do + @io.read.should == @contents + end + + it "places the specified number of bytes in the buffer" do + buf = "" + @io.read 5, buf + + buf.should == "12345" + end + + it "expands the buffer when too small" do + buf = "ABCDE" + @io.read nil, buf + + buf.should == @contents + end + + it "overwrites the buffer" do + buf = "ABCDEFGHIJ" + @io.read nil, buf + + buf.should == @contents + end + + it "truncates the buffer when too big" do + buf = "ABCDEFGHIJKLMNO" + @io.read nil, buf + buf.should == @contents + + @io.rewind + + buf = "ABCDEFGHIJKLMNO" + @io.read 5, buf + buf.should == @contents[0..4] + end + + it "returns the given buffer" do + buf = "" + + @io.read(nil, buf).object_id.should == buf.object_id + end + + it "coerces the second argument to string and uses it as a buffer" do + buf = "ABCDE" + obj = mock("buff") + obj.should_receive(:to_str).any_number_of_times.and_return(buf) + + @io.read(15, obj).object_id.should_not == obj.object_id + buf.should == @contents + end + + it "returns an empty string at end-of-file" do + @io.read + @io.read.should == '' + end + + it "reads the contents of a file when more bytes are specified" do + @io.read(@contents.length + 1).should == @contents + end + + it "returns an empty string at end-of-file" do + @io.read + @io.read.should == '' + end + + it "returns nil at end-of-file with a length" do + @io.read + @io.read(1).should == nil + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.read }.should raise_error(IOError) + end +end + diff --git a/1.8/core/io/readchar_spec.rb b/1.8/core/io/readchar_spec.rb new file mode 100644 index 0000000000..28d8203303 --- /dev/null +++ b/1.8/core/io/readchar_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#readchar" do + before :each do + @file_name = File.dirname(__FILE__) + '/fixtures/readlines.txt' + @file = File.open(@file_name, 'r') + end + + after :each do + @file.close unless @file.closed? + end + + it "returns the next byte from the stream" do + @file.readchar.should == 86 + @file.readchar.should == 111 + @file.readchar.should == 105 + # read the rest of line + @file.readline.should == "ci la ligne une.\n" + @file.readchar.should == 81 + end + + it "raises EOFError when invoked at the end of the stream" do + # read entire content + @file.read + lambda { @file.readchar }.should raise_error(EOFError) + end + + it "raises EOFError when reaches the end of the stream" do + lambda { loop { @file.readchar } }.should raise_error(EOFError) + end + + it "raises EOFError on empty stream" do + lambda { + File.open('/tmp/empty.txt') { |empty| + empty.readchar + } + }.should raise_error(EOFError) + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.readchar }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/readline_spec.rb b/1.8/core/io/readline_spec.rb new file mode 100644 index 0000000000..6e0ec70add --- /dev/null +++ b/1.8/core/io/readline_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#readline" do + @testfile = File.dirname(__FILE__) + '/fixtures/gets.txt' + + it "raises EOFError on end of stream" do + File.open(@testfile, 'r') do |f| + lambda { loop { f.readline } }.should raise_error(EOFError) + end + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.readline }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/readlines_spec.rb b/1.8/core/io/readlines_spec.rb new file mode 100644 index 0000000000..ab64f50a68 --- /dev/null +++ b/1.8/core/io/readlines_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#readlines" do + it "returns an Array of Strings that were separated by $/" do + File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r') do |f| + f.readlines.should == ["Voici la ligne une.\n", "Qui \303\250 la linea due.\n", + "Aqu\303\255 est\303\241 la l\303\255nea tres.\n", "Ist hier Linie vier.\n", + "Est\303\241 aqui a linha cinco.\n", "Here is line six.\n"] + end + end + it "returns an Array of Strings that were separated by r" do + File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r') do |f| + f.readlines('r').should == ["Voici la ligne une.\nQui \303\250 la linea due.\nAqu\303\255 est\303\241 la l\303\255nea tr", + "es.\nIst hier"," Linie vier",".\nEst\303\241 aqui a linha cinco.\nHer","e is line six.\n"] + end + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.readlines }.should raise_error(IOError) + end +end + +describe "IO::readlines" do + it "returns an Array of Strings that were separated by $/" do + lines = IO::readlines(File.dirname(__FILE__) + '/fixtures/readlines.txt') + lines.should == ["Voici la ligne une.\n", "Qui \303\250 la linea due.\n", + "Aqu\303\255 est\303\241 la l\303\255nea tres.\n", "Ist hier Linie vier.\n", + "Est\303\241 aqui a linha cinco.\n", "Here is line six.\n"] + end + it "returns an Array of Strings that were separated by r" do + lines = IO::readlines(File.dirname(__FILE__) + '/fixtures/readlines.txt','r') + lines.should == ["Voici la ligne une.\nQui \303\250 la linea due.\nAqu\303\255 est\303\241 la l\303\255nea tr", + "es.\nIst hier"," Linie vier",".\nEst\303\241 aqui a linha cinco.\nHer","e is line six.\n"] + end +end + +describe "IO.readlines" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/readpartial_spec.rb b/1.8/core/io/readpartial_spec.rb new file mode 100644 index 0000000000..72a83569e0 --- /dev/null +++ b/1.8/core/io/readpartial_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#readpartial" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.readpartial(10) }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/reopen_spec.rb b/1.8/core/io/reopen_spec.rb new file mode 100644 index 0000000000..f0ee271706 --- /dev/null +++ b/1.8/core/io/reopen_spec.rb @@ -0,0 +1,109 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#reopen" do + before :each do + # for reading + @name1 = IOSpecs.gets_fixtures + @name2 = File.dirname(__FILE__) + '/fixtures/numbered_lines.txt' + @file1 = File.new(@name1) + @file2 = File.new(@name2) + + # for writing + @name1_w = "/tmp/IO_reopen_file1" + $$.to_s + @name2_w = "/tmp/IO_reopen_file2" + $$.to_s + @file1_w = File.new(@name1_w, "w+") + @file2_w = File.new(@name2_w, "w+") + end + + after :each do + @file1.close unless @file1.closed? + @file2.close unless @file2.closed? + @file1_w.close unless @file1_w.closed? + @file2_w.close unless @file2_w.closed? + File.delete(@name1_w) + File.delete(@name2_w) + end + + it "raises IOError on closed stream" do + File.open(File.dirname(__FILE__) + '/fixtures/gets.txt', 'r') { |f| + lambda { f.reopen(IOSpecs.closed_file) }.should raise_error(IOError) + } + end + + it "reassociates self to another file/descriptor but returns self" do + @file1.reopen(@file2).should == @file1 + @file2.reopen(@file1).should == @file2 + @file1.reopen(@name2).should == @file1 + @file2.reopen(@name2).should == @file2 + end + + it "reassociates self with a new stream opened on path, when self in initial state" do + @file1.reopen(@name2) + @file1.gets.should == "Line 1: One\n" + end + + it "reassociates self with a new stream opened on path, after some reads" do + # reade some first + 4.times {@file1.gets; @file2.gets} + + @file1.reopen(@name2) + @file1.gets.should == "Line 1: One\n" + end + + it "reassociates self with a new stream opened on path, after some writes" do + @file1_w.puts("line1-F1") + @file2_w.puts("line1-F2") + @file2_w.reopen(@name1_w) + @file1_w.puts("line2-F1") + @file2_w.puts("line2-F2") + @file1_w.close + @file2_w.close + File.readlines(@name1_w).should == ["line2-F2\n", "line2-F1\n"] + File.readlines(@name2_w).should == ["line1-F2\n"] + end + + # JRUBY-2071: File#reopen blows with IllegalArgumentException in some cases + it "reassociates self with the I/O stream specified as an argument, after some reads" do + length = 12 # length of first lines in numbered_lines.txt + + # reade some first + @file1.gets + @file2.gets + + pos = @file2.pos + @file1.reopen(@file2) + @file1.pos.should == pos + + # MRI behavior: after reopen the buffers are not corrected, + # so we need the following line, or next gets wourd return nil. + @file1.pos = pos + + @file1.gets.should == "Line 2: Two\n" + end + + platform_is_not :darwin do + it "reassociates self with the I/O stream specified as an argument, after some sysreads" do + length = 12 # length of first lines in numbered_lines.txt + + # reade some first + @file1.sysread(length) + @file2.sysread(length) + + @file1.reopen(@file2) + @file1.sysread(length).should == "Line 2: Two\n" + end + end + + it "reassociates self with the I/O stream specified as an argument, after some writes" do + @file1_w.puts("line1-F1") + @file2_w.puts("line1-F2") + @file2_w.reopen(@file1_w) + @file1_w.puts("line2-F1") + @file2_w.puts("line2-F2") + @file1_w.close + @file2_w.close + File.readlines(@name1_w).should == ["line1-F1\n", "line2-F1\n", "line2-F2\n"] + File.readlines(@name2_w).should == ["line1-F2\n"] + end +end diff --git a/1.8/core/io/rewind_spec.rb b/1.8/core/io/rewind_spec.rb new file mode 100644 index 0000000000..c01940b419 --- /dev/null +++ b/1.8/core/io/rewind_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#rewind" do + before :each do + @file = File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r') + @io = IO.open @file.fileno, 'r' + end + + after :each do + # we *must* close both in order to not leak descriptors + @io.close unless @io.closed? + @file.close unless @file.closed? rescue Errno::EBADF + end + + it "positions the instance to the beginning of input" do + @io.readline.should == "Voici la ligne une.\n" + @io.readline.should == "Qui è la linea due.\n" + @io.rewind + @io.readline.should == "Voici la ligne une.\n" + end + + it "sets lineno to 0" do + @io.readline.should == "Voici la ligne une.\n" + @io.lineno.should == 1 + @io.rewind + @io.lineno.should == 0 + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.rewind }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/seek_spec.rb b/1.8/core/io/seek_spec.rb new file mode 100644 index 0000000000..a62c343f5e --- /dev/null +++ b/1.8/core/io/seek_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#seek" do + before :each do + @file = File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r') + @io = IO.open @file.fileno, 'r' + end + + after :each do + # we *must* close both in order to not leak descriptors + @io.close unless @io.closed? + @file.close unless @file.closed? rescue Errno::EBADF + end + + it "moves the read position relative to the current position with SEEK_CUR" do + @io.seek(10, IO::SEEK_CUR) + @io.readline.should == "igne une.\n" + @io.seek(-5, IO::SEEK_CUR) + @io.readline.should == "une.\n" + end + + it "moves the read position relative to the start with SEEK_SET" do + @io.seek(42, IO::SEEK_SET) + @io.readline.should == "quí está la línea tres.\n" + @io.seek(5, IO::SEEK_SET) + @io.readline.should == " la ligne une.\n" + end + + it "moves the read position relative to the end with SEEK_END" do + @io.seek(0, IO::SEEK_END) + @io.tell.should == 134 + @io.seek(-25, IO::SEEK_END) + @io.readline.should == "cinco.\n" + end + + it "can handle any numerical argument without breaking" do + @io.seek(1.2).should == 0 + @io.seek(2**32).should == 0 + @io.seek(1.23423423432e12).should == 0 + @io.seek(0.00000000000000000000001).should == 0 + lambda { @io.seek(2**128) }.should raise_error(RangeError) + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.seek(0) }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/select_spec.rb b/1.8/core/io/select_spec.rb new file mode 100644 index 0000000000..73f13e9515 --- /dev/null +++ b/1.8/core/io/select_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO.select" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/shared/each.rb b/1.8/core/io/shared/each.rb new file mode 100644 index 0000000000..2938b8a67a --- /dev/null +++ b/1.8/core/io/shared/each.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/../fixtures/classes' + +shared :io_each do |cmd| + describe "IO##{cmd}" do + it "yields the next line of string that is separated by $/" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + i = 0 + f.send(cmd) do |line| + line.should == IOSpecs.lines[i]; + i += 1 + end + end + end + + it "yields the entire content if the separator is nil" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + f.send(cmd, nil) { |line| line.should == IOSpecs.lines.join('') } + end + end + + # Two successive newlines in the input separate paragraphs. + # When there are more than two successive newlines, only two are kept. + it "yields the next paragraph if the separator's length is 0" do + pars = ["Voici la ligne une.\nQui \303\250 la linea due.\n\n", + "Aqu\303\255 est\303\241 la l\303\255nea tres.\nIst hier Linie vier.\n\n", + "Est\303\241 aqui a linha cinco.\nHere is line six.\n"] + + File.open(IOSpecs.gets_fixtures, 'r') do |f| + i = 0 + f.send(cmd, '') { |par| par.should == pars[i]; i += 1 } + end + end + + it "does not change $_" do + File.open(IOSpecs.gets_fixtures, 'r') do |f| + val = "Should not change" + $_ = val + f.send(cmd) { |line| } + $_.should == val + end + end + + it "raises IOError on closed stream" do + # method must have a block in order to raise the IOError. + # MRI 1.8.7 returns enumerator if block is not provided. + # See [ruby-core:16557]. + lambda { IOSpecs.closed_file.send(cmd){} }.should raise_error(IOError) + end + end +end diff --git a/1.8/core/io/shared/new_shared.rb b/1.8/core/io/shared/new_shared.rb new file mode 100644 index 0000000000..9d6f677e6a --- /dev/null +++ b/1.8/core/io/shared/new_shared.rb @@ -0,0 +1,75 @@ +shared :io_new do |cmd| + describe "IO##{cmd}" do + before :all do + @filename = "/tmp/rubinius-spec-io-new-#{$$}.txt" + end + + after :all do + File.unlink @filename + end + + before :each do + @file = File.open @filename, "w" + end + + after :each do + @file.close unless @file.closed? rescue Errno::EBADF + end + + it "returns a new IO object" do + begin + io = IO.send(cmd, @file.fileno, 'w') + ensure + io.close + end + io.class.should == IO + end + + it "takes an Integer or #to_int argument as the descriptor to open" do + o = mock('descriptor') + o.should_receive(:to_int).any_number_of_times.and_return(@file.fileno) + + begin + io = IO.send(cmd, @file.fileno, 'w') + io.fileno.should == @file.fileno + + io2 = IO.send(cmd, o, 'w') + io2.fileno.should == @file.fileno + ensure + io.close unless io.closed? rescue Errno::EBADF + io2.close unless io2.closed? rescue Errno::EBADF + end + end + + it "associates new IO with the old descriptor so each IO directly affects the other" do + io = IO.send cmd, @file.fileno, 'w' + + @file.syswrite "Hello " + @file.closed?.should == false + + io.close + io.closed?.should == true + + # Using #syswrite to force no Ruby buffering which could mask this error + lambda { @file.syswrite "there\n" }.should raise_error(Errno::EBADF) + end + + it "raises TypeError if not given an Integer or #to_int" do + lambda { IO.send(cmd, nil, 'r') }.should raise_error(TypeError) + lambda { IO.send(cmd, Object.new, 'r') }.should raise_error(TypeError) + end + + it "raises EBADF if the file descriptor given is not a valid and open one" do + lambda { IO.send(cmd, -2, 'r') }.should raise_error(Errno::EBADF) + + fd = @file.fileno + @file.close + lambda { IO.send(cmd, fd, 'w') }.should raise_error(Errno::EBADF) + end + + it "raises EINVAL if mode is not compatible with the descriptor's current mode" do + lambda { IO.send(cmd, @file.fileno, 'r') }.should raise_error(Errno::EINVAL) + lambda { io = IO.send(cmd, @file.fileno, 'w'); io.close }.should_not raise_error + end + end +end diff --git a/1.8/core/io/shared/pos.rb b/1.8/core/io/shared/pos.rb new file mode 100644 index 0000000000..48fdae00cf --- /dev/null +++ b/1.8/core/io/shared/pos.rb @@ -0,0 +1,35 @@ +shared :io_pos do |cmd| + describe "IO##{cmd}" do + before :each do + @fname = 'test.txt' + File.open @fname, 'w' do |f| f.write "123" end + end + + after :each do + File.unlink @fname + end + + it "gets the offset" do + File.open @fname do |f| + f.send(cmd).should == 0 + f.read 1 + f.send(cmd).should == 1 + f.read 2 + f.send(cmd).should == 3 + end + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.send(cmd) }.should raise_error(IOError) + end + + it "resets #eof?" do + open @fname do |io| + io.read 1 + io.read 1 + io.send(cmd) + io.eof?.should == false + end + end + end +end diff --git a/1.8/core/io/shared/tty_shared.rb b/1.8/core/io/shared/tty_shared.rb new file mode 100644 index 0000000000..f029780ed4 --- /dev/null +++ b/1.8/core/io/shared/tty_shared.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../fixtures/classes' + +shared :io_tty do |cmd| + describe "IO##{cmd}" do + # Yeah, this will probably break. + it "returns true if this stream is a terminal device (TTY)" do + File.open('/dev/tty') {|f| f.send cmd }.should == true + end + + it "returns false if this stream is not a terminal device (TTY)" do + File.open(__FILE__) {|f| f.send cmd }.should == false + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.send cmd }.should raise_error(IOError) + end + end +end diff --git a/1.8/core/io/shared/write.rb b/1.8/core/io/shared/write.rb new file mode 100644 index 0000000000..922b55176e --- /dev/null +++ b/1.8/core/io/shared/write.rb @@ -0,0 +1,65 @@ +require File.dirname(__FILE__) + '/../fixtures/classes' + +shared :io_write do |cmd| + describe "IO##{cmd} on a file" do + before :each do + @filename = "/tmp/IO_syswrite_file" + $$.to_s + File.open(@filename, "w") do |file| + file.send(cmd, "012345678901234567890123456789") + end + @file = File.open(@filename, "r+") + @readonly_file = File.open(@filename) + end + + after :each do + @file.close + @readonly_file.close + File.delete(@filename) + end + + it "coerces the argument to a string using to_s" do + (obj = mock('test')).should_receive(:to_s).and_return('a string') + @file.send(cmd, obj) + end + + it "checks if the file is writable if writing more than zero bytes" do + lambda { @readonly_file.send(cmd, "abcde") }.should raise_error(IOError) + end + + it "returns the number of bytes written" do + written = @file.send(cmd, "abcde") + written.should == 5 + end + + it "invokes to_s on non-String argument" do + data = "abcdefgh9876" + (obj = mock(data)).should_receive(:to_s).and_return(data) + @file.send(cmd, obj) + @file.seek(0) + @file.read(data.length).should == data + end + + it "writes all of the string's bytes without buffering if mode is sync" do + @file.sync = true + written = @file.send(cmd, "abcde") + written.should == 5 + File.open(@filename) do |file| + file.read(10).should == "abcde56789" + end + end + + it "does not warn if called after IO#read" do + @file.read(5) + lambda { @file.send(cmd, "fghij") }.should_not complain + end + + it "advances the file position by the count of given bytes" do + @file.send(cmd, "abcde") + @file.read(10).should == "5678901234" + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.send(cmd, "hello") }.should raise_error(IOError) + end + end +end diff --git a/1.8/core/io/stat_spec.rb b/1.8/core/io/stat_spec.rb new file mode 100644 index 0000000000..ae16a9918b --- /dev/null +++ b/1.8/core/io/stat_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#stat" do + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_io.stat }.should raise_error(IOError) + lambda { IOSpecs.closed_file.stat }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/sync_spec.rb b/1.8/core/io/sync_spec.rb new file mode 100644 index 0000000000..b4a4504228 --- /dev/null +++ b/1.8/core/io/sync_spec.rb @@ -0,0 +1,56 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#sync=" do + before :each do + @file = File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r') + @io = IO.open @file.fileno, 'r' + end + + after :each do + # we *must* close both in order to not leak descriptors + @io.close unless @io.closed? + @file.close unless @file.closed? rescue Errno::EBADF + end + + it "sets the sync mode to true or false" do + @io.sync = true + @io.sync.should == true + @io.sync = false + @io.sync.should == false + end + + it "accepts non-boolean arguments" do + @io.sync = 10 + @io.sync.should == true + @io.sync = nil + @io.sync.should == false + @io.sync = Object.new + @io.sync.should == true + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.sync = true }.should raise_error(IOError) + end +end + +describe "IO#sync" do + before :each do + @file = File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r') + @io = IO.open @file.fileno, 'r' + end + + after :each do + # we *must* close both in order to not leak descriptors + @io.close unless @io.closed? + @file.close unless @file.closed? rescue Errno::EBADF + end + + it "returns the current sync mode" do + @io.sync.should == false + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.sync }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/sysopen_spec.rb b/1.8/core/io/sysopen_spec.rb new file mode 100644 index 0000000000..5fcd18aa72 --- /dev/null +++ b/1.8/core/io/sysopen_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO.sysopen" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/io/sysread_spec.rb b/1.8/core/io/sysread_spec.rb new file mode 100644 index 0000000000..b6667ce8ec --- /dev/null +++ b/1.8/core/io/sysread_spec.rb @@ -0,0 +1,81 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#sysread on a file" do + before :each do + @file_name = "/tmp/IO_sysread_file" + $$.to_s + File.open(@file_name, "w") do |f| + # write some stuff + f.write("012345678901234567890123456789") + end + @file = File.open(@file_name, "r+") + end + + after :each do + @file.close + File.delete(@file_name) + end + + it "reads the specified number of bytes from the file" do + @file.sysread(15).should == "012345678901234" + end + + it "reads the specified number of bytes from the file to the buffer" do + buf = "" # empty buffer + @file.sysread(15, buf).should == buf + buf.should == "012345678901234" + + @file.rewind + + buf = "ABCDE" # small buffer + @file.sysread(15, buf).should == buf + buf.should == "012345678901234" + + @file.rewind + + buf = "ABCDE" * 5 # large buffer + @file.sysread(15, buf).should == buf + buf.should == "012345678901234" + end + + it "coerces the second argument to string and uses it as a buffer" do + buf = "ABCDE" + (obj = mock("buff")).should_receive(:to_str).any_number_of_times.and_return(buf) + @file.sysread(15, obj).should == buf + buf.should == "012345678901234" + end + + it "advances the position of the file by the specified number of bytes" do + @file.sysread(15) + @file.sysread(5).should == "56789" + end + + it "throws IOError when called immediately after a buffered IO#read" do + @file.read(15) + lambda { @file.sysread(5) }.should raise_error(IOError) + end + + it "does not raise error if called after IO#read followed by IO#write" do + @file.read(5) + @file.write("abcde") + lambda { @file.sysread(5) }.should_not raise_error(IOError) + end + + it "does not raise error if called after IO#read followed by IO#syswrite" do + @file.read(5) + @file.syswrite("abcde") + lambda { @file.sysread(5) }.should_not raise_error(IOError) + end + + it "flushes write buffer when called immediately after a buffered IO#write" do + @file.write("abcde") + @file.sysread(5).should == "56789" + File.open(@file_name) do |f| + f.sysread(10).should == "abcde56789" + end + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.sysread(5) }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/sysseek_spec.rb b/1.8/core/io/sysseek_spec.rb new file mode 100644 index 0000000000..f7a388a81e --- /dev/null +++ b/1.8/core/io/sysseek_spec.rb @@ -0,0 +1,64 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#sysseek on a file" do + # TODO: This should be made more generic with seek spec + before :each do + @file = File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r+') + @io = IO.open @file.fileno, 'r' + end + + after :each do + # we *must* close both in order to not leak descriptors + @io.close unless @io.closed? + @file.close unless @file.closed? rescue Errno::EBADF + end + + it "moves the read position relative to the current position with SEEK_CUR" do + @io.sysseek(10, IO::SEEK_CUR) + @io.readline.should == "igne une.\n" + end + + it "raises an error when called after buffered reads" do + @io.readline + lambda { @io.sysseek(-5, IO::SEEK_CUR) }.should raise_error(IOError) + end + + it "warns if called immediately after a buffered IO#write" do + begin + # copy contents to a separate file + tmpfile = File.open("/tmp/tmp_IO_sysseek", "w") + tmpfile.write(@file.read) + tmpfile.seek(0, File::SEEK_SET) + + tmpfile.write("abcde") + lambda { tmpfile.sysseek(10) }.should complain(/sysseek/) + ensure + tmpfile.close + File.unlink(tmpfile.path) + end + end + + it "moves the read position relative to the start with SEEK_SET" do + @io.sysseek(42, IO::SEEK_SET) + @io.readline.should == "quí está la línea tres.\n" + end + + it "moves the read position relative to the end with SEEK_END" do + @io.sysseek(0, IO::SEEK_END) + @io.tell.should == 134 + @io.sysseek(-25, IO::SEEK_END) + @io.readline.should == "cinco.\n" + end + + it "can handle any numerical argument without breaking and can seek past EOF" do + @io.sysseek(1.2).should == 1 + @io.sysseek(2**10).should == 1024 + @io.sysseek(2**32).should == 4294967296 + lambda { @io.sysseek(2**128) }.should raise_error(RangeError) + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.sysseek(0) }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/syswrite_spec.rb b/1.8/core/io/syswrite_spec.rb new file mode 100644 index 0000000000..d73cd40b6a --- /dev/null +++ b/1.8/core/io/syswrite_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/write' + +describe "IO#syswrite on a file" do + before :each do + @filename = "/tmp/IO_syswrite_file" + $$.to_s + File.open(@filename, "w") do |file| + file.syswrite("012345678901234567890123456789") + end + @file = File.open(@filename, "r+") + @readonly_file = File.open(@filename) + end + + after :each do + @file.close + @readonly_file.close + File.delete(@filename) + end + + it "writes all of the string's bytes but does not buffer them" do + written = @file.syswrite("abcde") + written.should == 5 + File.open(@filename) do |file| + file.sysread(10).should == "abcde56789" + file.seek(0) + @file.fsync + file.sysread(10).should == "abcde56789" + end + end + + not_compliant_on :rubinius do + it "warns if called immediately after a buffered IO#write" do + @file.write("abcde") + lambda { @file.syswrite("fghij") }.should complain(/syswrite/) + end + end + + it "does not warn if called after IO#write with intervening IO#sysread" do + @file.syswrite("abcde") + @file.sysread(5) + lambda { @file.syswrite("fghij") }.should_not complain + end + + it "writes to the actual file position when called after buffered IO#read" do + @file.read(5) + @file.syswrite("abcde") + File.open(@filename) do |file| + file.sysread(10).should == "01234abcde" + end + end + + it_behaves_like(:io_write, :syswrite) +end diff --git a/1.8/core/io/tell_spec.rb b/1.8/core/io/tell_spec.rb new file mode 100644 index 0000000000..60cfd31037 --- /dev/null +++ b/1.8/core/io/tell_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/pos' + +describe "IO#tell" do + it_behaves_like(:io_pos, :tell) +end diff --git a/1.8/core/io/to_i_spec.rb b/1.8/core/io/to_i_spec.rb new file mode 100644 index 0000000000..4238922124 --- /dev/null +++ b/1.8/core/io/to_i_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#to_i" do + it "return the numeric file descriptor of the given IO object" do + $stdout.to_i.should == 1 + end + + it "raises IOError on closed stream" do + lambda { IOSpecs.closed_file.to_i }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/to_io_spec.rb b/1.8/core/io/to_io_spec.rb new file mode 100644 index 0000000000..7233c6b6f6 --- /dev/null +++ b/1.8/core/io/to_io_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "IO#to_io" do + it "returns self for open stream" do + io = IO.new(2, 'w') + io.to_io.should == io + + File.open(File.dirname(__FILE__) + '/fixtures/readlines.txt', 'r') { |io| + io.to_io.should == io + } + end + + it "returns self for closed stream" do + io = IOSpecs.closed_file + io.to_io.should == io + end +end diff --git a/1.8/core/io/tty_spec.rb b/1.8/core/io/tty_spec.rb new file mode 100644 index 0000000000..4dc2aa5669 --- /dev/null +++ b/1.8/core/io/tty_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/tty_shared.rb' + +describe "IO#tty?" do + it_behaves_like :io_tty, :tty? +end diff --git a/1.8/core/io/ungetc_spec.rb b/1.8/core/io/ungetc_spec.rb new file mode 100644 index 0000000000..d753a90149 --- /dev/null +++ b/1.8/core/io/ungetc_spec.rb @@ -0,0 +1,119 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "IO#ungetc" do + before :each do + @file_name = File.dirname(__FILE__) + '/fixtures/readlines.txt' + @file = File.open(@file_name, 'r') + end + + after :each do + @file.close unless @file.closed? + end + + it "pushes back one character onto stream" do + @file.getc.should == 86 + @file.ungetc(86) + @file.getc.should == 86 + + @file.ungetc(10) + @file.getc.should == 10 + + @file.getc.should == 111 + @file.getc.should == 105 + # read the rest of line + @file.readline.should == "ci la ligne une.\n" + @file.getc.should == 81 + @file.ungetc(99) + @file.getc.should == 99 + end + + it "pushes back one character when invoked at the end of the stream" do + # read entire content + @file.read + @file.ungetc(100) + @file.getc.should == 100 + end + + it "pushes back one character when invoked at the start of the stream" do + @file.read(0) + @file.ungetc(100) + @file.getc.should == 100 + end + + it "pushes back one character when invoked on empty stream" do + File.open('/tmp/empty.txt') { |empty| + empty.getc().should == nil + empty.ungetc(10) + empty.getc.should == 10 + } + end + + it "affects EOF state" do + File.open('/tmp/empty.txt') { |empty| + empty.eof?.should == true + empty.getc.should == nil + empty.ungetc(100) + empty.eof?.should == false + } + end + + it "adjusts the stream position" do + @file.pos.should == 0 + + # read one char + c = @file.getc + @file.pos.should == 1 + @file.ungetc(c) + @file.pos.should == 0 + + # read all + @file.read + pos = @file.pos + @file.ungetc(98) + @file.pos.should == pos - 1 + end + + # TODO: file MRI bug + # Even though this behavior is clearly stated in ruby-doc + # for IO#ungetc, MRI doesn't follow it: + # + # "Only one character may be pushed back before a subsequent + # read operation (that is, you will be able to read only the + # last of several characters that have been pushed back)." + # + #it "pushing back only one character" do + # @file.getc + # 10.times { @file.ungetc(90) } + # @file.ungetc(80) + # @file.read(1).should == "P" + # @file.readline.should == "oici la ligne une.\n" + #end + + # TODO: file MRI bug + # Another specified behavior that MRI doesn't follow: + # "Has no effect with unbuffered reads (such as IO#sysread)." + # + #it "has no effect with unbuffered reads" do + # length = File.size(@file_name) + # content = @file.sysread(length) + # @file.rewind + # @file.ungetc(100) + # @file.sysread(length).should == content + #end + + it "makes subsequent unbuffered operations to raise IOError" do + @file.getc + @file.ungetc(100) + lambda { @file.sysread(1) }.should raise_error(IOError) + end + + it "raises IOError when invoked on stream that was not yet read" do + lambda { @file.ungetc(100) }.should raise_error(IOError) + end + + it "raises IOError on closed stream" do + @file.getc + @file.close + lambda { @file.ungetc(100) }.should raise_error(IOError) + end +end diff --git a/1.8/core/io/write_nonblock_spec.rb b/1.8/core/io/write_nonblock_spec.rb new file mode 100644 index 0000000000..cf2b3bf06f --- /dev/null +++ b/1.8/core/io/write_nonblock_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/write' + +describe "IO#write_nonblock on a file" do + before :each do + @filename = "/tmp/IO_syswrite_file" + $$.to_s + File.open(@filename, "w") do |file| + file.write_nonblock("012345678901234567890123456789") + end + @file = File.open(@filename, "r+") + @readonly_file = File.open(@filename) + end + + after :each do + @file.close + @readonly_file.close + File.delete(@filename) + end + + it "writes all of the string's bytes but does not buffer them" do + written = @file.write_nonblock("abcde") + written.should == 5 + File.open(@filename) do |file| + file.sysread(10).should == "abcde56789" + file.seek(0) + @file.fsync + file.sysread(10).should == "abcde56789" + end + end + + it "checks if the file is writable if writing zero bytes" do + lambda { @readonly_file.write_nonblock("") }.should raise_error + end + + it_behaves_like(:io_write, :write_nonblock) +end diff --git a/1.8/core/io/write_spec.rb b/1.8/core/io/write_spec.rb new file mode 100644 index 0000000000..8f6a2045e7 --- /dev/null +++ b/1.8/core/io/write_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/write' + +describe "IO#write on a file" do + before :each do + @filename = "/tmp/IO_syswrite_file" + $$.to_s + File.open(@filename, "w") do |file| + file.write("012345678901234567890123456789") + end + @file = File.open(@filename, "r+") + @readonly_file = File.open(@filename) + end + + after :each do + @file.close + @readonly_file.close + File.delete(@filename) + end + + it "writes all of the string's bytes but buffers them" do + written = @file.write("abcde") + written.should == 5 + File.open(@filename) do |file| + file.sysread(10).should_not == "abcde56789" + file.seek(0) + @file.fsync + file.sysread(10).should == "abcde56789" + end + end + + it "does not check if the file is writable if writing zero bytes" do + lambda { @readonly_file.write("") }.should_not raise_error + end + + it "returns a length of 0 when writing a blank string" do + @file.write('').should == 0 + end + + it_behaves_like(:io_write, :write) +end diff --git a/1.8/core/kernel/Array_spec.rb b/1.8/core/kernel/Array_spec.rb new file mode 100644 index 0000000000..3297f7dd12 --- /dev/null +++ b/1.8/core/kernel/Array_spec.rb @@ -0,0 +1,42 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#Array" do + it "is a private method" do + Kernel.private_instance_methods.should include("Array") + end + + it "first tries to call #to_ary on the given argument" do + (obj = mock('[1,2,3]')).should_receive(:to_ary).and_return([1, 2, 3]) + obj.should_not_receive(:to_a) + + Array(obj).should == [1, 2, 3] + end + + it "tries to call #to_a on the given argument if #to_ary is not provided" do + (obj = mock('[4,5,6]')).should_receive(:to_a).and_return([4, 5, 6]) + Array(obj).should == [4, 5, 6] + end + + it "returns an array with the given argument if neither #to_ary nor #to_a are provided" do + obj = mock('x') + Array(obj).should == [obj] + end + + it "returns an empty array if the given argument is nil" do + Array(nil).should == [] + end + + it "raises a TypeError if #to_ary / #to_a do not return an array" do + (obj = mock('ha!')).should_receive(:to_a).and_return("ha!") + lambda { Array(obj) }.should raise_error(TypeError) + + obj.should_receive(:to_ary).and_return("ha!") + lambda { Array(obj) }.should raise_error(TypeError) + end +end + +describe "Kernel.Array" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/Float_spec.rb b/1.8/core/kernel/Float_spec.rb new file mode 100644 index 0000000000..01e8935b28 --- /dev/null +++ b/1.8/core/kernel/Float_spec.rb @@ -0,0 +1,45 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.Float when passed a String" do + it "raises a TypeError when the given String can't be fully converted to a Float" do + lambda { Float('0.0.0') }.should raise_error(ArgumentError) + lambda { Float('float') }.should raise_error(ArgumentError) + lambda { Float('10.0:D') }.should raise_error(ArgumentError) + lambda { Float('D10') }.should raise_error(ArgumentError) + end +end + +describe "Kernel.Float" do + it "is a private method" do + Kernel.private_instance_methods.should include("Float") + end + + it "converts the given argument to a Float by calling #to_f" do + Kernel.Float(1).should == 1.0 + Kernel.Float(1.12).should == 1.12 + Kernel.Float(1000000000000).should == 1000000000000.0 + Kernel.Float("10").should == 10.0 + + (obj = mock('1.2')).should_receive(:to_f).any_number_of_times.and_return(1.2) + obj.should_not_receive(:to_i) + Kernel.Float(obj).should == 1.2 + end + + it "raises a TypeError of #to_f is not provided" do + lambda { Kernel.Float(mock('x')) }.should raise_error(TypeError) + end + + it "raises a TypeError if #to_f does not return a Float" do + (obj = mock('ha!')).should_receive(:to_f).any_number_of_times.and_return('ha!') + lambda { Kernel.Float(obj) }.should raise_error(TypeError) + + (obj = mock('123')).should_receive(:to_f).any_number_of_times.and_return(123) + lambda { Kernel.Float(obj) }.should raise_error(TypeError) + end +end + +describe "Kernel#Float" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/Integer_spec.rb b/1.8/core/kernel/Integer_spec.rb new file mode 100644 index 0000000000..569acb3aa8 --- /dev/null +++ b/1.8/core/kernel/Integer_spec.rb @@ -0,0 +1,53 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.Integer when given a String" do + it "does not call #to_i on the given String" do + (obj = "2").should_not_receive(:to_i) + Integer(obj).should == 2 + end + + it "ignores whitespaces" do + Integer(" 2 ").should == 2 + Integer(" 22222 ").should == 22222 + end + + it "raises an ArgumentError if the given String has no valid Integer representation" do + [ "", "--2", "-+2", "++2", "a2", "2a", "__2", " _2", "2__", "2 _", "2 a"].each do |str| + lambda { Integer(str) }.should raise_error(ArgumentError) + end + end +end + +describe "Kernel.Integer" do + it "is a private method" do + Kernel.private_instance_methods.should include("Integer") + end + + it "calls #to_int if the given object responds to it" do + obj = mock('1') + obj.should_receive(:to_int).and_return(1) + obj.should_not_receive(:to_i) + + Integer(obj).should == 1 + end + + it "calls to_i to convert any arbitrary argument to an Integer" do + (obj = mock('7')).should_receive(:to_i).and_return(7) + Integer(obj).should == 7 + end + + it "raises a TypeError if there is no to_i method on an object" do + lambda { Integer(mock('x')) }.should raise_error(TypeError) + end + + it "raises a TypeError if to_i doesn't return an Integer" do + (obj = mock('ha!')).should_receive(:to_i).and_return("ha!") + lambda { Integer(obj) }.should raise_error(TypeError) + end +end + +describe "Kernel#Integer" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/String_spec.rb b/1.8/core/kernel/String_spec.rb new file mode 100644 index 0000000000..f4cba34ebf --- /dev/null +++ b/1.8/core/kernel/String_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.String" do + it "is a private method" do + Kernel.private_instance_methods.should include("String") + end + + it "converts the given argument to a String by calling #to_s" do + Kernel.String(nil).should == "" + Kernel.String("10").should == "10" + Kernel.String(1.12).should == "1.12" + Kernel.String(false).should == "false" + Kernel.String(Object).should == "Object" + + (obj = mock('test')).should_receive(:to_s).and_return("test") + Kernel.String(obj).should == "test" + end + +# TODO: does not work yet because of undef_method +# +# it "raises a TypeError of #to_s is not provided" do +# class << (obj = mock('to_s')) +# undef_method :to_s +# end +# +# lambda { +# Kernel.String(obj) +# }.should raise_error(TypeError) +# end + + it "raises a TypeError if #to_s does not return a String" do + (obj = mock('123')).should_receive(:to_s).and_return(123) + lambda { Kernel.String(obj) }.should raise_error(TypeError) + end +end + +describe "Kernel#String" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/__id___spec.rb b/1.8/core/kernel/__id___spec.rb new file mode 100644 index 0000000000..343a1296ee --- /dev/null +++ b/1.8/core/kernel/__id___spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/object_id' + +describe "Kernel#__id__" do + it_behaves_like(:kernel_object_id, :__id__) +end + +describe "Kernel#__id__" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/__send___spec.rb b/1.8/core/kernel/__send___spec.rb new file mode 100644 index 0000000000..adc766a94a --- /dev/null +++ b/1.8/core/kernel/__send___spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#__send__" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/abort_spec.rb b/1.8/core/kernel/abort_spec.rb new file mode 100644 index 0000000000..5e528b93f6 --- /dev/null +++ b/1.8/core/kernel/abort_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#abort" do + it "is a private method" do + Kernel.private_instance_methods.should include("abort") + end +end + +describe "Kernel.abort" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/at_exit_spec.rb b/1.8/core/kernel/at_exit_spec.rb new file mode 100644 index 0000000000..73359b91be --- /dev/null +++ b/1.8/core/kernel/at_exit_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.at_exit" do + it "is a private method" do + Kernel.private_instance_methods.should include("at_exit") + end + + it "runs after all other code" do + #result = `#{RUBY_CLI} -e "at_exit {print 5}; print 6"` + #result.should == "65" + end + + it "runs in reverse order of registration" do + #result = `#{RUBY_CLI} -e "at_exit {print 4};at_exit {print 5}; print 6; at_exit {print 7}"` + #result.should == '6754' + end +end + +describe "Kernel#at_exit" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/autoload_spec.rb b/1.8/core/kernel/autoload_spec.rb new file mode 100644 index 0000000000..e1c2262181 --- /dev/null +++ b/1.8/core/kernel/autoload_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#autoload" do + it "is a private method" do + Kernel.private_instance_methods.should include("autoload") + end +end + +describe "Kernel#autoload?" do + it "is a private method" do + Kernel.private_instance_methods.should include("autoload?") + end +end + +describe "Kernel.autoload" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "Kernel.autoload?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/backtick_spec.rb b/1.8/core/kernel/backtick_spec.rb new file mode 100644 index 0000000000..2c6e9ffe02 --- /dev/null +++ b/1.8/core/kernel/backtick_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#`" do + it "is a private method" do + Kernel.private_instance_methods.should include("`") + end + + it "returns the standard output of the executed sub-process" do + ip = 'world' + `echo disc #{ip}`.should == "disc world\n" + end + + it "tries to convert the given argument to String using to_str" do + (obj = mock('echo test')).should_receive(:to_str).and_return("echo test") + Kernel.`(obj).should == "test\n" + + obj = mock('echo another test') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("echo another test") + Kernel.`(obj).should == "another test\n" + end + + it "sets $? to the exit status of the executed sub-process" do + ip = 'world' + `echo disc #{ip}` + $?.class.should == Process::Status + $?.stopped?.should == false + $?.exited?.should == true + $?.exitstatus.should == 0 + $?.success?.should == true + `echo disc #{ip}; exit 99` + $?.class.should == Process::Status + $?.stopped?.should == false + $?.exited?.should == true + $?.exitstatus.should == 99 + $?.success?.should == false + end +end + +describe "Kernel.`" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/binding_spec.rb b/1.8/core/kernel/binding_spec.rb new file mode 100644 index 0000000000..a282929383 --- /dev/null +++ b/1.8/core/kernel/binding_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#binding" do + it "is a private method" do + Kernel.private_instance_methods.should include("binding") + end + + before(:each) do + @b1 = KernelSpecs::Binding.new(99).get_binding + end + + it "returns a Binding object" do + @b1.kind_of?(Binding).should == true + end + + it "encapsulates the execution context properly" do + eval("@secret", @b1).should == 100 + eval("a", @b1).should == true + eval("b", @b1).should == true + eval("@@super_secret", @b1).should == "password" + + eval("square(2)", @b1).should == 4 + eval("self.square(2)", @b1).should == 4 + + eval("a = false", @b1) + eval("a", @b1).should == false + end + + it "raises a NameError on undefined variable" do + lambda { eval("a_fake_variable", @b1) }.should raise_error(NameError) + end +end + +describe "Kernel.binding" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/block_given_spec.rb b/1.8/core/kernel/block_given_spec.rb new file mode 100644 index 0000000000..75e3e8ef75 --- /dev/null +++ b/1.8/core/kernel/block_given_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#block_given?" do + it "is a private method" do + Kernel.private_instance_methods.should include("block_given?") + end + + it "returns true if and only if a block is supplied" do + KernelSpecs::BlockGiven::accept_block {}.should_not == false + KernelSpecs::BlockGiven::accept_block_as_argument {}.should_not == false + KernelSpecs::BlockGiven::accept_block.should_not == true + KernelSpecs::BlockGiven::accept_block_as_argument.should_not == true + end +end + +describe "Kernel.block_given?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/callcc_spec.rb b/1.8/core/kernel/callcc_spec.rb new file mode 100644 index 0000000000..a96255d599 --- /dev/null +++ b/1.8/core/kernel/callcc_spec.rb @@ -0,0 +1,69 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#callcc" do + not_supported_on(:jruby) do + it "is a private method" do + Kernel.private_instance_methods.should include("callcc") + end + + it "is possible to exit a loop like a break" do + i = 0 + Kernel.callcc do |x| + loop do + i += 1 + x.call() if i == 5 + end + end.should == nil + i.should == 5 + end + + it "is possible to call a continuation multiple times" do + i = 0 + cont = nil + Kernel.callcc {|cont|} + i += 1 + cont.call() if i < 5 + i.should == 5 + end + + it "returns the results of a block if block is not called" do + cont = nil + a = callcc {|cont| 0} + cont.call(1) if a == 0 + a.should == 1 + end + + it "returns the arguments to call" do + callcc {|cont| cont.call }.should == nil + callcc {|cont| cont.call 1 }.should == 1 + callcc {|cont| cont.call 1,2,3 }.should == [1,2,3] + end + + it "preserves changes to block-local scope" do + i = "before" + cont = callcc { |c| c } + if cont # nil the second time + i = "after" + cont.call + end + i.should == "after" + end + + it "preserves changes to method-local scope" do + # This spec tests that a continuation shares the same locals + # tuple as the scope that created it. + KernelSpecs.before_and_after.should == "after" + end + + it "raises a LocalJumpError if callcc is not given a block" do + lambda { Kernel.callcc }.should raise_error(LocalJumpError) + end + + end +end + +describe "Kernel.callcc" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/caller_spec.rb b/1.8/core/kernel/caller_spec.rb new file mode 100644 index 0000000000..42eeea6a6e --- /dev/null +++ b/1.8/core/kernel/caller_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# DO NOT PUT ANYTHING ABOVE THIS +describe "Kernel#caller" do + before :each do + def a(skip) + caller(skip) + end + def b(skip) + a(skip) + end + def c(skip) + b(skip) + end + end + + it "is a private method" do + Kernel.private_instance_methods.should include("caller") + end + + it "returns the current call stack" do + stack = c 0 + stack[0].should =~ /caller_spec.rb.*?8.*?`a'/ + stack[1].should =~ /caller_spec.rb.*?11.*?`b'/ + stack[2].should =~ /caller_spec.rb.*?14.*?`c'/ + end + + it "omits a number of frames corresponding to the parameter" do + c(0)[1..-1].should == c(1) + c(0)[2..-1].should == c(2) + c(0)[3..-1].should == c(3) + end + + it "defaults to omitting one frame" do + caller.should == caller(1) + end + + # The contents of the array returned by #caller depends on whether + # the call is made from an instance_eval block or a #call. + # We purposely do not spec what happens if you request to omit + # more entries than exist in the array returned. +end + +describe "Kernel.caller" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/case_compare_spec.rb b/1.8/core/kernel/case_compare_spec.rb new file mode 100644 index 0000000000..14b5bf1329 --- /dev/null +++ b/1.8/core/kernel/case_compare_spec.rb @@ -0,0 +1,174 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + + +module Specs + module Kernel + + class HasNone + end + + class HasOpEqual + def ==(other) + other.kind_of? HasOpEqual + end + end + + class HasEqual + def equal?(other) + false + end + end + + class HasOppoOpEqual + def ==(other) + false + end + + def equal?(other) + false + end + end + + class RandomID + def ==(other) + true + end + + def equal?(other) + true + end + + def object_id() + @ids ||= [] + + loop { + candidate = rand + next if @ids.include? candidate + @ids << candidate + return candidate + } + end + end + + end +end + + +describe "Kernel#=== for a class with default #== and #equal?" do + before :each do + @o1 = Specs::Kernel::HasNone.new + @o2 = @o1.dup + end + + it "returns true if other object has same object id" do + @o1.object_id.should == @o1.object_id + (@o1 === @o1).should == true + end + + it "returns false if other object does not have same object id" do + @o1.object_id.should_not == @o2.object_id + (@o1 === @o2).should == false + end +end + +describe "Kernel#=== for a class with #== overridden to consider other object's class" do + before :each do + @o = Object.new + @o1 = Specs::Kernel::HasOpEqual.new + @o2 = @o1.dup + end + + it "returns true if #== returns true even if #equal? is false" do + @o1.equal?(@o2).should == false + (@o1 == @o2).should == true + (@o1 === @o2).should == true + end + + it "returns true if #equal? returns true" do + @o1.equal?(@o1).should == true + (@o1 === @o1).should == true + end + + it "returns false if neither #== nor #equal? returns true" do + @o1.equal?(@o).should == false + (@o1 == @o).should == false + (@o1 === @o).should == false + end +end + +describe "Kernel#=== for a class with #equal? overridden to always be false" do + before :each do + @o = Object.new + @o1 = Specs::Kernel::HasEqual.new + @o2 = @o1.dup + end + + it "returns true if #== returns true even if #equal? is false" do + @o1.equal?(@o1).should == false + (@o1 == @o1).should == true + (@o1 === @o1).should == true + end + + it "returns false if neither #== nor #equal? returns true" do + @o1.equal?(@o).should == false + (@o1 == @o).should == false + (@o1 === @o).should == false + end +end + +describe "Kernel#=== for a class with #== and #equal? overridden to always be false" do + before :each do + @o = Object.new + @o1 = Specs::Kernel::HasOppoOpEqual.new + @o2 = @o1.dup + end + + not_compliant_on :rubinius do + it "returns true if the object id is the same even if both #== and #equal? return false" do + @o1.object_id.should == @o1.object_id + + @o1.equal?(@o1).should == false + (@o1 == @o1).should == false + + (@o1 === @o1).should == true + end + end + + deviates_on :rubinius do + it "returns false if both #== and #equal? return false even if object id is same" do + @o1.object_id.should == @o1.object_id + + @o1.equal?(@o1).should == false + (@o1 == @o1).should == false + + (@o1 === @o1).should == false + end + end + + it "returns false if the object id is not the same and both #== and #equal? return false" do + @o1.object_id.should_not == @o2.object_id + + @o1.equal?(@o2).should == false + (@o1 == @o2).should == false + + (@o1 === @o2).should == false + end +end + +describe "Kernel#=== for a class with #object_id overridden to always be different #== and #equal? overridden to always be true" do + before :each do + @o = Object.new + @o1 = Specs::Kernel::RandomID.new + @o2 = @o1.dup + end + + it "returns true if #== or #equal? is true even if object id is different" do + @o1.object_id.should_not == @o1.object_id + + @o1.equal?(@o1).should == true + (@o1 == @o1).should == true + + (@o1 === @o1).should == true + end +end diff --git a/1.8/core/kernel/catch_spec.rb b/1.8/core/kernel/catch_spec.rb new file mode 100644 index 0000000000..841213b3b2 --- /dev/null +++ b/1.8/core/kernel/catch_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#catch" do + + it "throws the given name and is caught by matching catch block" do + bad = false + catch :blah do + throw :blah + bad = true + end + bad.should == false + end + + it "raises unless the thrown name is known" do + proc { + throw :blah + }.should raise_error(NameError, "uncaught throw `blah'") { |error| + # The ruby docs are not clear whether NameError#name should + # retrun String or Symbol. Well, the docs state the *String* + # should be returned, but the actual MRI behavior is to return Symbol. + # And in MRI 1.9, even different Exception raised altogether. + + # So, instead of checking that error.name == :blah, we perform + # more generic test, suitable for different implementations + # (like JRuby, since JRuby follows the ruby-doc, and returns String). + error.name.to_s.should == "blah" + } + end + + it "is a private method" do + Kernel.private_instance_methods.should include("catch") + end +end + +describe "Kernel.catch" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/chomp_spec.rb b/1.8/core/kernel/chomp_spec.rb new file mode 100644 index 0000000000..bb06190778 --- /dev/null +++ b/1.8/core/kernel/chomp_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#chomp" do + it "is a private method" do + Kernel.private_instance_methods.should include("chomp") + end +end + +describe "Kernel#chomp!" do + it "is a private method" do + Kernel.private_instance_methods.should include("chomp!") + end +end + +describe "Kernel.chomp" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "Kernel.chomp!" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/chop_spec.rb b/1.8/core/kernel/chop_spec.rb new file mode 100644 index 0000000000..433e9b30b5 --- /dev/null +++ b/1.8/core/kernel/chop_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#chop" do + it "is a private method" do + Kernel.private_instance_methods.should include("chop") + end +end + +describe "Kernel#chop!" do + it "is a private method" do + Kernel.private_instance_methods.should include("chop!") + end +end + +describe "Kernel.chop" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "Kernel.chop!" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/class_spec.rb b/1.8/core/kernel/class_spec.rb new file mode 100644 index 0000000000..7f669d40ef --- /dev/null +++ b/1.8/core/kernel/class_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#class" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/clone_spec.rb b/1.8/core/kernel/clone_spec.rb new file mode 100644 index 0000000000..360f6149dc --- /dev/null +++ b/1.8/core/kernel/clone_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#clone" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/display_spec.rb b/1.8/core/kernel/display_spec.rb new file mode 100644 index 0000000000..4f08a83598 --- /dev/null +++ b/1.8/core/kernel/display_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#display" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/dup_spec.rb b/1.8/core/kernel/dup_spec.rb new file mode 100644 index 0000000000..96cc12e429 --- /dev/null +++ b/1.8/core/kernel/dup_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#dup" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/eql_spec.rb b/1.8/core/kernel/eql_spec.rb new file mode 100644 index 0000000000..36b6ca96e1 --- /dev/null +++ b/1.8/core/kernel/eql_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#eql?" do + it "returns true if obj and anObject are the same object." do + o1 = mock('o1') + o2 = mock('o2') + (o1.eql?(o1)).should == true + (o2.eql?(o2)).should == true + (o1.eql?(o2)).should == false + end + + it "returns true if obj and anObject have the same value." do + o1 = 1 + o2 = :hola + (:hola.eql? o1).should == false + (1.eql? o1).should == true + (:hola.eql? o2).should == true + end +end + diff --git a/1.8/core/kernel/equal_spec.rb b/1.8/core/kernel/equal_spec.rb new file mode 100644 index 0000000000..47fee6dbd7 --- /dev/null +++ b/1.8/core/kernel/equal_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#equal?" do + it "returns true only if obj and other are the same object" do + o1 = mock('o1') + o2 = mock('o2') + (o1.equal? o1).should == true + (o2.equal? o2).should == true + (o1.equal? o2).should== false + (nil.equal? nil).should == true + (o1.equal? nil).should== false + (nil.equal? o2).should== false + end + + it "returns true if obj and anObject have the same value." do + o1 = 1 + o2 = :hola + (:hola.equal? o1).should == false + (1.equal? o1).should == true + (:hola.equal? o2).should == true + end +end diff --git a/1.8/core/kernel/equal_value_spec.rb b/1.8/core/kernel/equal_value_spec.rb new file mode 100644 index 0000000000..e6142f610a --- /dev/null +++ b/1.8/core/kernel/equal_value_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#==" do + it "returns true only if obj and other are the same object" do + o1 = mock('o1') + o2 = mock('o2') + (o1 == o1).should == true + (o2 == o2).should == true + (o1 == o2).should== false + (nil == nil).should == true + (o1 == nil).should== false + (nil == o2).should== false + end +end diff --git a/1.8/core/kernel/eval_spec.rb b/1.8/core/kernel/eval_spec.rb new file mode 100644 index 0000000000..3fc8a58f8c --- /dev/null +++ b/1.8/core/kernel/eval_spec.rb @@ -0,0 +1,148 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +class A + eval "class B; end" + def c + eval "class C; end" + end +end + +A.new.c + +describe "Kernel#eval" do + it "is a private method" do + Kernel.private_instance_methods.should include("eval") + end + + it "is a module function" do + Kernel.respond_to?(:eval).should == true + end + + it "evaluates the code within" do + eval("2 + 3").should == 5 + end + + it "evaluates within the scope of the eval" do + A::B.name.should == "A::B" + end + + it "evaluates such that consts are scoped to the class of the eval" do + A::C.name.should == "A::C" + end + + it "accepts a Proc object as a binding" do + x = 1 + bind = proc {} + + eval("x", bind).should == 1 + eval("y = 2", bind).should == 2 + eval("y", bind).should == 2 + + eval("z = 3").should == 3 + eval("z", bind).should == 3 + end + + it "does not make Proc locals visible to evaluated code" do + bind = proc { inner = 4 } + lambda { eval("inner", bind) }.should raise_error(NameError) + end + + it "allows a binding to be captured inside an eval" do + outer_binding = binding + level1 = eval("binding", outer_binding) + level2 = eval("binding", level1) + + eval("w = 1") + eval("x = 2", outer_binding) + eval("y = 3", level1) + + eval("w").should == 1 + eval("w", outer_binding).should == 1 + eval("w", level1).should == 1 + eval("w", level2).should == 1 + + eval("x").should == 2 + eval("x", outer_binding).should == 2 + eval("x", level1).should == 2 + eval("x", level2).should == 2 + + eval("y").should == 3 + eval("y", outer_binding).should == 3 + eval("y", level1).should == 3 + eval("y", level2).should == 3 + end + + it "allows Proc and binding to be nested in horrible ways" do + outer_binding = binding + proc_binding = eval("proc {l = 5; binding}.call", outer_binding) + inner_binding = eval("proc {k = 6; binding}.call", proc_binding) + + eval("w = 1") + eval("x = 2", outer_binding) + eval("yy = 3", proc_binding) + eval("z = 4", inner_binding) + + eval("w").should == 1 + eval("w", outer_binding).should == 1 + eval("w", proc_binding).should == 1 + eval("w", inner_binding).should == 1 + + eval("x").should == 2 + eval("x", outer_binding).should == 2 + eval("x", proc_binding).should == 2 + eval("x", inner_binding).should == 2 + + lambda { eval("yy") }.should raise_error(NameError) + lambda { eval("yy", outer_binding) }.should raise_error(NameError) + eval("yy", proc_binding).should == 3 + eval("yy", inner_binding).should == 3 + + lambda { eval("z") }.should raise_error(NameError) + lambda { eval("z", outer_binding) }.should raise_error(NameError) + lambda { eval("z", proc_binding) }.should raise_error(NameError) + eval("z", inner_binding).should == 4 + + lambda { eval("l") }.should raise_error(NameError) + lambda { eval("l", outer_binding) }.should raise_error(NameError) + eval("l", proc_binding).should == 5 + eval("l", inner_binding).should == 5 + + lambda { eval("k") }.should raise_error(NameError) + lambda { eval("k", outer_binding) }.should raise_error(NameError) + lambda { eval("k", proc_binding) }.should raise_error(NameError) + eval("k", inner_binding).should == 6 + end + + it "allows creating a new class in a binding" do + bind = proc {} + eval "class A; end", bind + eval("A.name", bind).should == "A" + end + + it "allows creating a new class in a binding created by #eval" do + bind = eval "binding" + eval "class A; end", bind + eval("A.name").should == "A" + end + + it "allows creating a new class in a binding returned by a method defined with #eval" do + bind = eval "def spec_binding; binding; end; spec_binding" + eval "class A; end", bind + eval("A.name").should == "A" + end + + it "includes file and line information in syntax error" do + expected = 'speccing.rb' + lambda { + eval('if true',TOPLEVEL_BINDING,expected) + }.should raise_error(SyntaxError) { |e| + e.message.should =~ /^#{expected}:1:.+/ + } + end +end + +describe "Kernel.eval" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/exec_spec.rb b/1.8/core/kernel/exec_spec.rb new file mode 100644 index 0000000000..d2a01b8e3f --- /dev/null +++ b/1.8/core/kernel/exec_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#exec" do + it "is a private method" do + Kernel.private_instance_methods.should include("exec") + end + + it "raises a SystemCallError if cmd cannot execute" do + lambda { exec "" }.should raise_error(SystemCallError) + end +end + +describe "Kernel.exec" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/exit_spec.rb b/1.8/core/kernel/exit_spec.rb new file mode 100644 index 0000000000..128bc444ad --- /dev/null +++ b/1.8/core/kernel/exit_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#exit" do + it "is a private method" do + Kernel.private_instance_methods.should include("exit") + end +end + +describe "Kernel#exit!" do + it "is a private method" do + Kernel.private_instance_methods.should include("exit!") + end +end + + +describe "Kernel.exit" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "Kernel.exit!" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/extend_spec.rb b/1.8/core/kernel/extend_spec.rb new file mode 100644 index 0000000000..a8eff1b1c0 --- /dev/null +++ b/1.8/core/kernel/extend_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +compliant_on :ruby, :jruby do + describe "Object#extend" do + it "raises a TypeError if self is frozen" do + module Mod; end + o = mock('o') + o.freeze + lambda { o.extend Mod }.should raise_error(TypeError) + end + end +end + +describe "Kernel#extend" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/fail_spec.rb b/1.8/core/kernel/fail_spec.rb new file mode 100644 index 0000000000..235d5898a9 --- /dev/null +++ b/1.8/core/kernel/fail_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.fail" do + it "is a private method" do + Kernel.private_instance_methods.should include("fail") + end + + it "raises a RuntimeError" do + lambda { fail }.should raise_error(RuntimeError) + end + + it "accepts an Object with an exception method returning an Exception" do + class Boring + def self.exception(msg) + StandardError.new msg + end + end + lambda { fail Boring, "..." }.should raise_error(StandardError) + end + + it "instantiates the specified exception class" do + class LittleBunnyFooFoo < RuntimeError; end + lambda { fail LittleBunnyFooFoo }.should raise_error(LittleBunnyFooFoo) + end + + it "uses the specified message" do + lambda { + begin + fail "the duck is not irish." + rescue => e + e.message.should == "the duck is not irish." + raise + else + raise Exception + end + }.should raise_error(RuntimeError) + end +end + +describe "Kernel#fail" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/fixtures/.gitignore b/1.8/core/kernel/fixtures/.gitignore new file mode 100644 index 0000000000..fe17774732 --- /dev/null +++ b/1.8/core/kernel/fixtures/.gitignore @@ -0,0 +1,4 @@ +load_spec_dynamic.rb +load_spec_dynamic.rbc +*.rbc +*.old diff --git a/1.8/core/kernel/fixtures/classes.rb b/1.8/core/kernel/fixtures/classes.rb new file mode 100644 index 0000000000..50fd59de00 --- /dev/null +++ b/1.8/core/kernel/fixtures/classes.rb @@ -0,0 +1,175 @@ +module KernelSpecs + class Methods + def self.ichi; end + def ni; end + class << self + def san; end + end + + private + + def self.shi; end + def juu_shi; end + + class << self + def roku; end + + private + + def shichi; end + end + + protected + + def self.hachi; end + def ku; end + + class << self + def juu; end + + protected + + def juu_ichi; end + end + + public + + def self.juu_ni; end + def juu_san; end + end + + class A + def public_method; :public_method; end + + def undefed_method; :undefed_method; end + undef_method :undefed_method + + protected + def protected_method; :protected_method; end + + private + def private_method; :private_method; end + end + + class Binding + @@super_secret = "password" + + def initialize(n) + @secret = n + end + + def square(n) + n * n + end + + def get_binding + a = true + @bind = binding + + # Add/Change stuff + b = true + @secret += 1 + + @bind + end + end + + module MethodMissing + def self.method_missing(*args) :method_missing end + def self.existing() :existing end + + def self.private_method() :private_method end + private_class_method :private_method + end + + class MethodMissingC + def self.method_missing(*args) :method_missing end + def method_missing(*args) :instance_method_missing end + + def self.existing() :existing end + def existing() :instance_existing end + + def self.private_method() :private_method end + def self.protected_method() :protected_method end + class << self + private :private_method + protected :protected_method + end + + def private_method() :private_instance_method end + private :private_method + + def protected_method() :protected_instance_method end + protected :protected_method + end + + module NoMethodMissing + def self.existing() :existing end + + def self.private_method() :private_method end + private_class_method :private_method + end + + class NoMethodMissingC + def self.existing() :existing end + def existing() :instance_existing end + + def self.private_method() :private_method end + def self.protected_method() :protected_method end + class << self + private :private_method + protected :protected_method + end + + def private_method() :private_instance_method end + private :private_method + + def protected_method() :protected_instance_method end + protected :protected_method + end + + module BlockGiven + def self.accept_block + block_given? + end + + def self.accept_block_as_argument(&block) + block_given? + end + end + + def self.before_and_after + i = "before" + cont = callcc { |c| c } + if cont # nil the second time + i = "after" + cont.call + end + i + end + + class IVars + def initialize + @secret = 99 + end + end + + module InstEval + def self.included(base) + base.instance_eval { @@count = 2 } + end + end + + class IncludesInstEval + include InstEval + end +end + +# for Kernel#sleep to have Channel in it's specs +# TODO: switch directly to queue for both Kernel#sleep and Thread specs? +unless defined? Channel + require 'thread' + class Channel < Queue + alias receive shift + end +end diff --git a/1.8/core/kernel/fork_spec.rb b/1.8/core/kernel/fork_spec.rb new file mode 100644 index 0000000000..ed05f53929 --- /dev/null +++ b/1.8/core/kernel/fork_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#fork" do + it "is a private method" do + Kernel.private_instance_methods.should include("fork") + end +end + +describe "Kernel.fork" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/format_spec.rb b/1.8/core/kernel/format_spec.rb new file mode 100644 index 0000000000..16c797deeb --- /dev/null +++ b/1.8/core/kernel/format_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#format" do + it "is a private method" do + Kernel.private_instance_methods.should include("format") + end +end + +describe "Kernel.format" do + it "is accessible as a module function" do + Kernel.format("%s", "hello").should == "hello" + end +end diff --git a/1.8/core/kernel/freeze_spec.rb b/1.8/core/kernel/freeze_spec.rb new file mode 100644 index 0000000000..f88fe223b3 --- /dev/null +++ b/1.8/core/kernel/freeze_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +compliant_on :ruby, :jruby do + describe "Kernel#freeze" do + it "prevents self from being further modified" do + o = mock('o') + o.frozen?.should == false + o.freeze + o.frozen?.should == true + end + + it "has no effect on immediate values" do + a = nil + b = true + c = false + d = 1 + a.freeze + b.freeze + c.freeze + d.freeze + a.frozen?.should == false + b.frozen?.should == false + c.frozen?.should == false + d.frozen?.should == false + end + end +end diff --git a/1.8/core/kernel/frozen_spec.rb b/1.8/core/kernel/frozen_spec.rb new file mode 100644 index 0000000000..9e3e6dda8f --- /dev/null +++ b/1.8/core/kernel/frozen_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +compliant_on :ruby, :jruby do + describe "Kernel#frozen?" do + it "returns true if self is frozen" do + o = mock('o') + p = mock('p') + p.freeze + o.frozen?.should == false + p.frozen?.should == true + end + end +end diff --git a/1.8/core/kernel/getc_spec.rb b/1.8/core/kernel/getc_spec.rb new file mode 100644 index 0000000000..380b2f5cdc --- /dev/null +++ b/1.8/core/kernel/getc_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#getc" do + it "is a private method" do + Kernel.private_instance_methods.should include("getc") + end +end + +describe "Kernel.getc" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/gets_spec.rb b/1.8/core/kernel/gets_spec.rb new file mode 100644 index 0000000000..fce6324ef4 --- /dev/null +++ b/1.8/core/kernel/gets_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#gets" do + it "is a private method" do + Kernel.private_instance_methods.should include("gets") + end +end + +describe "Kernel.gets" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/global_variables_spec.rb b/1.8/core/kernel/global_variables_spec.rb new file mode 100644 index 0000000000..e1de7d99d3 --- /dev/null +++ b/1.8/core/kernel/global_variables_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.global_variables" do + it "is a private method" do + Kernel.private_instance_methods.should include("global_variables") + end + + it "finds subset starting with std" do + global_variables.grep(/std/).should include("$stderr", "$stdin", "$stdout") + a = global_variables.size + global_variables.include?("$foolish_global_var").should == false + eval("$foolish_global_var = 1") + global_variables.size.should == a+1 + global_variables.should include("$foolish_global_var") + end +end + +describe "Kernel#global_variables" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/gsub_spec.rb b/1.8/core/kernel/gsub_spec.rb new file mode 100644 index 0000000000..341b6fe2f8 --- /dev/null +++ b/1.8/core/kernel/gsub_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#gsub" do + it "is a private method" do + Kernel.private_instance_methods.should include("gsub") + end +end + +describe "Kernel#gsub!" do + it "is a private method" do + Kernel.private_instance_methods.should include("gsub!") + end +end + +describe "Kernel.gsub" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "Kernel.gsub!" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/hash_spec.rb b/1.8/core/kernel/hash_spec.rb new file mode 100644 index 0000000000..6738b854e9 --- /dev/null +++ b/1.8/core/kernel/hash_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#hash" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/id_spec.rb b/1.8/core/kernel/id_spec.rb new file mode 100644 index 0000000000..4c60c48e68 --- /dev/null +++ b/1.8/core/kernel/id_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#id" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/initialize_copy_spec.rb b/1.8/core/kernel/initialize_copy_spec.rb new file mode 100644 index 0000000000..a0aab59552 --- /dev/null +++ b/1.8/core/kernel/initialize_copy_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#initialize_copy" do + it "is a private method" do + Kernel.private_instance_methods.should include("initialize_copy") + end +end diff --git a/1.8/core/kernel/inspect_spec.rb b/1.8/core/kernel/inspect_spec.rb new file mode 100644 index 0000000000..1f1a33163b --- /dev/null +++ b/1.8/core/kernel/inspect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#inspect" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/instance_eval_spec.rb b/1.8/core/kernel/instance_eval_spec.rb new file mode 100644 index 0000000000..e9c33e5a2c --- /dev/null +++ b/1.8/core/kernel/instance_eval_spec.rb @@ -0,0 +1,68 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#instance_eval" do + it "expects a block with no arguments" do + lambda { "hola".instance_eval }.should raise_error(ArgumentError) + end + + it "takes no arguments with a block" do + lambda { "hola".instance_eval(4, 5) { |a,b| a + b } }.should raise_error(ArgumentError) + end + + it "passes the object to the block" do + "hola".instance_eval { |o| o.size }.should == 4 + end + + it "binds self to the receiver" do + s = "hola" + (s == s.instance_eval { self }).should == true + o = mock('o') + (o == o.instance_eval("self")).should == true + end + + it "executes in the context of the receiver" do + "Ruby-fu".instance_eval { size }.should == 7 + "hola".instance_eval("size").should == 4 + end + + it "has access to receiver's instance variables" do + KernelSpecs::IVars.new.instance_eval { @secret }.should == 99 + KernelSpecs::IVars.new.instance_eval("@secret").should == 99 + end + + it "sets class variables in the receiver" do + KernelSpecs::IncludesInstEval.class_variables.should include("@@count") + KernelSpecs::IncludesInstEval.send(:class_variable_get, :@@count).should == 2 + end + + it "raises a TypeError when defining methods on an immediate" do + lambda do + 1.instance_eval { def foo; end } + end.should raise_error(TypeError) + lambda do + :foo.instance_eval { def foo; end } + end.should raise_error(TypeError) + end + +quarantine! do # Not clean, leaves cvars lying around to break other specs + it "scopes class var accesses in the caller when called on a Fixnum" do + # Fixnum can take instance vars + Fixnum.class_eval "@@__tmp_instance_eval_spec = 1" + (defined? @@__tmp_instance_eval_spec).should == nil + + @@__tmp_instance_eval_spec = 2 + 1.instance_eval { @@__tmp_instance_eval_spec }.should == 2 + Fixnum.__send__(:remove_class_variable, :@@__tmp_instance_eval_spec) + end +end + + it "raises a TypeError when defining methods on numerics" do + lambda do + (1.0).instance_eval { def foo; end } + end.should raise_error(TypeError) + lambda do + (1 << 64).instance_eval { def foo; end } + end.should raise_error(TypeError) + end +end diff --git a/1.8/core/kernel/instance_of_spec.rb b/1.8/core/kernel/instance_of_spec.rb new file mode 100644 index 0000000000..c6d755001f --- /dev/null +++ b/1.8/core/kernel/instance_of_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Kernel#instance_of?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/instance_variable_defined_spec.rb b/1.8/core/kernel/instance_variable_defined_spec.rb new file mode 100644 index 0000000000..a83d394599 --- /dev/null +++ b/1.8/core/kernel/instance_variable_defined_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Kernel#instance_variable_defined?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/instance_variable_get_spec.rb b/1.8/core/kernel/instance_variable_get_spec.rb new file mode 100644 index 0000000000..f75e4bed17 --- /dev/null +++ b/1.8/core/kernel/instance_variable_get_spec.rb @@ -0,0 +1,63 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#instance_variable_get" do + it "returns the value of the instance variable" do + class Fred + def initialize(p1, p2) + @a, @b = p1, p2 + end + end + fred = Fred.new('cat', 99) + fred.instance_variable_get(:@a).should == "cat" + fred.instance_variable_get("@b").should == 99 + + a = [] + a.instance_variable_set(:@c, 1) + a.instance_variable_get(:@c).should == 1 + end + + it "returns nil if the instance variable does not exist" do + [].instance_variable_get(:@c).should == nil + end + + it "raises a NameError exception if the argument is not of form '@x'" do + class NoFred; end + lambda { NoFred.new.instance_variable_get(:c) }.should raise_error(NameError) + lambda { [].instance_variable_get(:c) }.should raise_error(NameError) + end + + it "raises an ArgumentError if the instance variable name is a Fixnum" do + lambda { "".instance_variable_get(1) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the instance variable name is an object that does not respond to to_str" do + class KernelSpecs::A; end + lambda { "".instance_variable_get(KernelSpecs::A.new) }.should raise_error(TypeError) + end + + it "raises a NameError if the passed object, when coerced with to_str, does not start with @" do + class KernelSpecs::B + def to_str + ":c" + end + end + lambda { "".instance_variable_get(KernelSpecs::B.new) }.should raise_error(NameError) + end + + it "raises a NameError if pass an object that cannot be a symbol" do + lambda { "".instance_variable_get(:c) }.should raise_error(NameError) + end + + it "accepts as instance variable name any instance of a class that responds to to_str" do + class KernelSpecs::C + def initialize + @a = 1 + end + def to_str + "@a" + end + end + KernelSpecs::C.new.instance_variable_get(KernelSpecs::C.new).should == 1 + end +end diff --git a/1.8/core/kernel/instance_variable_set_spec.rb b/1.8/core/kernel/instance_variable_set_spec.rb new file mode 100644 index 0000000000..5ff56a9db5 --- /dev/null +++ b/1.8/core/kernel/instance_variable_set_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#instance_variable_set" do + it "sets the value of the specified instance variable" do + class Dog + def initialize(p1, p2) + @a, @b = p1, p2 + end + end + Dog.new('cat', 99).instance_variable_set(:@a, 'dog').should == "dog" + end + + it "sets the value of the instance variable when no instance variables exist yet" do + class NoVariables; end + NoVariables.new.instance_variable_set(:@a, "new").should == "new" + end + + it "raises a NameError exception if the argument is not of form '@x'" do + class NoDog; end + lambda { NoDog.new.instance_variable_set(:c, "cat") }.should raise_error(NameError) + end + + it "raises an ArgumentError if the instance variable name is a Fixnum" do + lambda { "".instance_variable_set(1, 2) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the instance variable name is an object that does not respond to to_str" do + class KernelSpecs::A; end + lambda { "".instance_variable_set(KernelSpecs::A.new, 3) }.should raise_error(TypeError) + end + + it "raises a NameError if the passed object, when coerced with to_str, does not start with @" do + class KernelSpecs::B + def to_str + ":c" + end + end + lambda { "".instance_variable_set(KernelSpecs::B.new, 4) }.should raise_error(NameError) + end + + it "raises a NameError if pass an object that cannot be a symbol" do + lambda { "".instance_variable_set(:c, 1) }.should raise_error(NameError) + end + + it "accepts as instance variable name any instance of a class that responds to to_str" do + class KernelSpecs::C + def initialize + @a = 1 + end + def to_str + "@a" + end + end + KernelSpecs::C.new.instance_variable_set(KernelSpecs::C.new, 2).should == 2 + end +end diff --git a/1.8/core/kernel/instance_variables_spec.rb b/1.8/core/kernel/instance_variables_spec.rb new file mode 100644 index 0000000000..080d87ccd2 --- /dev/null +++ b/1.8/core/kernel/instance_variables_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#instance_variables" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/is_a_spec.rb b/1.8/core/kernel/is_a_spec.rb new file mode 100644 index 0000000000..a03fd150fc --- /dev/null +++ b/1.8/core/kernel/is_a_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Kernel#is_a?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/iterator_spec.rb b/1.8/core/kernel/iterator_spec.rb new file mode 100644 index 0000000000..4249fe5ba4 --- /dev/null +++ b/1.8/core/kernel/iterator_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#iterator?" do + it "is a private method" do + Kernel.private_instance_methods.should include("iterator?") + end +end + +describe "Kernel.iterator?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/kind_of_spec.rb b/1.8/core/kernel/kind_of_spec.rb new file mode 100644 index 0000000000..ee09abc020 --- /dev/null +++ b/1.8/core/kernel/kind_of_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Kernel#kind_of?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/lambda_spec.rb b/1.8/core/kernel/lambda_spec.rb new file mode 100644 index 0000000000..b8623974a1 --- /dev/null +++ b/1.8/core/kernel/lambda_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/lambda' + +describe "Kernel.lambda" do + it "is a private method" do + Kernel.private_instance_methods.should include("lambda") + end + + it_behaves_like(:kernel_lambda, :lambda) +end + +describe "Kernel#lambda" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/load_spec.rb b/1.8/core/kernel/load_spec.rb new file mode 100644 index 0000000000..506be4acca --- /dev/null +++ b/1.8/core/kernel/load_spec.rb @@ -0,0 +1,234 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +$load_fixture_dir = (File.dirname(__FILE__) + '/../../fixtures/load') +$LOAD_PATH << $load_fixture_dir + +$load_spec_1 = nil +$load_spec_2 = nil +$load_spec_3 = nil +$load_spec_4 = nil +$load_spec_5 = nil +$load_spec_6 = nil +$load_spec_7 = nil +$load_spec_8 = nil +$load_spec_9 = nil +$load_spec_10 = nil +$load_spec_wrap = nil +$load_spec_wrap2 = nil +$load_spec = nil +$load_spec_rooby = nil + +require 'rbconfig' + +# The files used below just contain code that assigns +# Time.now to the respective global variable. +# +# The only exception are the _wrap files which contain +# similarly named classes. The class definitions, in +# addition, contain another global timestamp assignment. +describe "Kernel#load" do + it "is a private method" do + Kernel.private_instance_methods.should include("load") + end + + # Avoid storing .rbc in repo + before :all do + Dir.chdir($load_fixture_dir) do |dir| + `rm -f ./*.rbc` + end + end + + it "loads a .rb from an absolute path and returns true" do + path = File.expand_path(File.dirname(__FILE__) + '/../../fixtures/load/load_spec_1.rb') + + load(path).should == true + $load_spec_1.nil?.should == false + end + + it "loads a .rb from a relative path and returns true" do + Dir.chdir($load_fixture_dir) do |dir| + $load_spec_1 = nil + load('../../fixtures/load/load_spec_1.rb').should == true + $load_spec_1.nil?.should == false + + $load_spec_1 = nil + load('./../load/load_spec_1.rb').should == true + $load_spec_1.nil?.should == false + end + end + + it "loads extension files" do + # Not sure how to spec this yet because it needs an extension file + end + + it "loads an unqualified .rb by looking in $LOAD_PATH and returns true" do + load('load_spec_2.rb').should == true + $load_spec_2.nil?.should == false + end + + it "does not expand/resolve qualified files against $LOAD_PATH" do + Dir.chdir($load_fixture_dir + '/../') do |dir| + # This would be a valid path if expanded against the fixture dir + lambda { load '../load/load_spec_2.rb' }.should raise_error LoadError + end + end + + it "allows unqualified files to contain path information (just not in the beginning)" do + name = (File.dirname(__FILE__) + '/../../fixtures') + $LOAD_PATH << name + + $load_spec_2 = nil + load('load/../load/load_spec_2.rb').should == true + $load_spec_2.nil?.should == false + + $LOAD_PATH.delete name + end + + it "loads a file with no extension as a ruby source file" do + load('load_spec').should == true + $load_spec.nil?.should == false + end + + it "loads a file with any extension as a ruby source file" do + load('load_spec.rooby').should == true + $load_spec_rooby.nil?.should == false + end + + it "does not create a .rb file for the non-.rb files" do + load('load_spec').should == true + load('load_spec.rooby').should == true + + File.exist?("#{$load_fixture_dir}/load_spec.rb").should == false + File.exist?("#{$load_fixture_dir}/load_spec.rooby.rb").should == false + end + + it "does not add the loaded file to $LOADED_FEATURES" do + $LOADED_FEATURES.grep(/load_spec_3.rb/).should == [] + load('load_spec_3.rb').should == true + $load_spec_3.nil?.should == false + $LOADED_FEATURES.grep(/load_spec_3.rb/).should == [] + end + + it "produces __FILE__ as the given filename and __LINE__ as the source line number" do + Dir.chdir($load_fixture_dir) do |dir| + load('load_spec_4.rb').should == true + $load_spec_4.should == [['./load_spec_4.rb', 1], ['./load_spec_4.rb', 10]] + + extended_on :rubinius do + `rm load_spec_4.rbc` + end + end + + load("#{$load_fixture_dir}/load_spec_4.rb").should == true + $load_spec_4[0][0].should =~ %r[^.*/fixtures/load/load_spec_4.rb] + $load_spec_4[0][1].should == 1 + $load_spec_4[1][0].should =~ %r[^.*/fixtures/load/load_spec_4.rb] + $load_spec_4[1][1].should == 10 + end + + it "reloads the file if invoked on the same filename again, returning true" do + load('load_spec_4.rb').should == true + load('load_spec_4.rb').should == true + end + + it "re-evaluates the file each time it is loaded" do + load('load_spec_5.rb').should == true + a = $load_spec_5 + load('load_spec_5.rb').should == true + b = $load_spec_5 + + a.eql?(b).should == false + end + + it "loads the file even if it has already been #required" do + require('load_spec_6.rb').should == true + a = $load_spec_6 + + require('load_spec_6.rb').should == false + b = $load_spec_6 + + load('load_spec_6.rb').should == true + c = $load_spec_6 + + a.eql?(b).should == true + c.eql?(a).should == false + end + + it "does not cause #require on the same filename to fail" do + load('load_spec_7.rb').should == true + a = $load_spec_7 + + require('load_spec_7.rb').should == true + b = $load_spec_7 + + load('load_spec_7.rb').should == true + c = $load_spec_7 + + a.eql?(b).should == false + b.eql?(c).should == false + c.eql?(a).should == false + end + + it "raises a LoadError if the file can't be found" do + lambda { load("./nonexistent#{Time.now.to_f}#{$$}") }.should raise_error LoadError + end + + # TODO: This currently fails on Rubinius because the #load logic + # will take 'load_spec_1' and try 'load_spec_1.rbc' since + # that is the logic for .rb files. + it "raises a LoadError if filename given without its extension" do + lambda { load('load_spec_1') }.should raise_error LoadError + load('load_spec_1.rb').should == true + lambda { load('load_spec_1') }.should raise_error LoadError + end + + it "only accepts strings as the filename argument" do + lambda { load(nil) }.should raise_error TypeError + lambda { load(42) }.should raise_error TypeError + lambda { load([]) }.should raise_error TypeError + end + + runner_is_not :rspec do + it "allows wrapping the code in the file in an anonymous module" do + !!defined?(LoadSpecWrap).should == false + !!defined?(LoadSpecWrapTwo).should == false + + load('load_spec_wrap.rb').should == true + $load_spec_wrap.nil?.should == false + LoadSpecWrap.lsw.should == :lsw + + load('load_spec_wrap2.rb', true).should == true + $load_spec_wrap2.nil?.should == false + !!defined?(LoadSpecWrapTwo).should == false + end + end +end + +describe "Shell expansion in Kernel#load" do + before :all do + @rs_home = ENV["HOME"] + ENV["HOME"] = $load_fixture_dir + @rs_short = "~/load_spec_1.rb" + @rs_long = "#{$load_fixture_dir}/load_spec_1.rb" + end + + after :all do + ENV["HOME"] = @rs_home + end + + before :each do + $LOADED_FEATURES.delete @rs_long + $LOADED_FEATURES.delete @rs_short + end + + it "expands a preceding ~/ to the user's home directory to use as path" do + $load_spec_1 = nil + load(@rs_short).should == true + $load_spec_1.nil?.should == false + end +end + +describe "Kernel.load" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/local_variables_spec.rb b/1.8/core/kernel/local_variables_spec.rb new file mode 100644 index 0000000000..5ba1187bd5 --- /dev/null +++ b/1.8/core/kernel/local_variables_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.local_variables" do + it "is a private method" do + Kernel.private_instance_methods.should include("local_variables") + end + + it "contains locals as they are added" do + a = 1 + b = 2 + local_variables.should include("a", "b") + end + + it "is accessable from bindings" do + def local_var_foo + a = 1 + b = 2 + binding + end + foo_binding = local_var_foo() + res = eval("local_variables",foo_binding) + res.should include("a", "b") + end +end + +describe "Kernel#local_variables" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/loop_spec.rb b/1.8/core/kernel/loop_spec.rb new file mode 100644 index 0000000000..54d832b964 --- /dev/null +++ b/1.8/core/kernel/loop_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.loop" do + it "is a private method" do + Kernel.private_instance_methods.should include("loop") + end + + it "calls block until it is terminated by a break" do + i = 0 + loop do + i += 1 + break if i == 10 + end + + i.should == 10 + end + + it "returns value passed to break" do + loop do + break 123 + end.should == 123 + end + + it "returns nil if no value passed to break" do + loop do + break + end.should == nil + end + + it "raises a LocalJumpError if no block given" do + lambda { loop }.should raise_error(LocalJumpError) + end +end + +describe "Kernel#loop" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/match_spec.rb b/1.8/core/kernel/match_spec.rb new file mode 100644 index 0000000000..37ae0621bc --- /dev/null +++ b/1.8/core/kernel/match_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#=~" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/method_missing_spec.rb b/1.8/core/kernel/method_missing_spec.rb new file mode 100644 index 0000000000..4c7b6129d2 --- /dev/null +++ b/1.8/core/kernel/method_missing_spec.rb @@ -0,0 +1,61 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#method_missing" do + it "is a private method" do + Kernel.private_instance_methods.should include("method_missing") + end + + it "is not called when a defined method is called" do + KernelSpecs::MethodMissing.should_not_receive(:method_missing) + KernelSpecs::MethodMissingC.should_not_receive(:method_missing) + obj = KernelSpecs::MethodMissingC.new + obj.should_not_receive(:method_missing) + + KernelSpecs::MethodMissing.existing.should == :existing + KernelSpecs::MethodMissingC.existing.should == :existing + obj.existing.should == :instance_existing + end + + it "is called when an undefined method is called" do + KernelSpecs::MethodMissing.nonexistent.should == :method_missing + KernelSpecs::MethodMissingC.nonexistent.should == :method_missing + KernelSpecs::MethodMissingC.new.nonexistent.should == :instance_method_missing + end + + it "is called when a private method is called" do + KernelSpecs::MethodMissing.private_method.should == :method_missing + KernelSpecs::MethodMissingC.private_method.should == :method_missing + KernelSpecs::MethodMissingC.new.private_method.should == :instance_method_missing + end + + it "is called when a protected method is called" do + KernelSpecs::MethodMissingC.protected_method.should == :method_missing + KernelSpecs::MethodMissingC.new.protected_method.should == :instance_method_missing + end +end + +describe "When Kernel#method_missing is undefined" do + it "a NoMethodError is raised when an undefined method is called" do + lambda { KernelSpecs::NoMethodMissing.nonexistent }.should raise_error(NoMethodError) + lambda { KernelSpecs::NoMethodMissingC.nonexistent }.should raise_error(NoMethodError) + lambda { KernelSpecs::NoMethodMissingC.new.nonexistent }.should raise_error(NoMethodError) + end + + it "a NoMethodError is raised when a private method is called" do + lambda { KernelSpecs::NoMethodMissing.nonexistent }.should raise_error(NoMethodError) + lambda { KernelSpecs::NoMethodMissingC.nonexistent }.should raise_error(NoMethodError) + lambda { KernelSpecs::NoMethodMissingC.new.nonexistent }.should raise_error(NoMethodError) + end + + it "a NoMethodError is raised when a protected method is called" do + lambda { KernelSpecs::NoMethodMissing.nonexistent }.should raise_error(NoMethodError) + lambda { KernelSpecs::NoMethodMissingC.nonexistent }.should raise_error(NoMethodError) + lambda { KernelSpecs::NoMethodMissingC.new.nonexistent }.should raise_error(NoMethodError) + end +end + +describe "Kernel.method_missing" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/method_spec.rb b/1.8/core/kernel/method_spec.rb new file mode 100644 index 0000000000..7511b48720 --- /dev/null +++ b/1.8/core/kernel/method_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#method" do + it "returns a method object for a valid method" do + class KernelSpecs::Foo; def bar; 'done'; end; end + KernelSpecs::Foo.new.method(:bar).class.should == Method + end + + it "returns a method object for a valid singleton method" do + class KernelSpecs::Foo; def self.bar; 'done'; end; end + KernelSpecs::Foo.method(:bar).class.should == Method + end + + it "raises a NameError for an invalid method name" do + class KernelSpecs::Foo; def bar; 'done'; end; end + lambda { + KernelSpecs::Foo.new.method(:invalid_and_silly_method_name) + }.should raise_error(NameError) + end + + it "raises a NameError for an invalid singleton method name" do + class KernelSpecs::Foo; def self.bar; 'done'; end; end + lambda { KernelSpecs::Foo.method(:baz) }.should raise_error(NameError) + end +end diff --git a/1.8/core/kernel/methods_spec.rb b/1.8/core/kernel/methods_spec.rb new file mode 100644 index 0000000000..900b3c5ce6 --- /dev/null +++ b/1.8/core/kernel/methods_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#methods" do + + it "picks up methods added via self.meth" do + KernelSpecs::Methods.methods(false).should include("ichi") + end + + it "picks up methods added inside 'class << self'" do + KernelSpecs::Methods.methods(false).should include("san") + end + + it "picks up private methods added via self.meth" do + KernelSpecs::Methods.methods(false).should include("shi") + end + + it "picks up methods added inside 'class << self' after private" do + KernelSpecs::Methods.methods(false).should include("roku") + end + + it "doesn't picks up methods added inside 'class << self; private'" do + KernelSpecs::Methods.methods(false).should_not include("shichi") + end + + it "returns a list of the names of publicly accessible methods in the object" do + meths = KernelSpecs::Methods.methods(false) + + ["hachi", "ichi", "juu", "juu_ichi", "juu_ni", "roku", "san", "shi"].each do|m| + meths.should include(m) + end + + KernelSpecs::Methods.new.methods(false).should == [] + end + + it "returns a list of the names of publicly accessible methods in the object and its ancestors and mixed-in modules" do + meths = KernelSpecs::Methods.methods(false) & KernelSpecs::Methods.methods + ["hachi", "ichi", "juu", "juu_ichi", "juu_ni", "roku", "san", "shi"].each do |m| + meths.should include(m) + end + + m = KernelSpecs::Methods.new.methods + m.should include('ku') + m.should include('ni') + m.should include('juu_san') + end +end diff --git a/1.8/core/kernel/nil_spec.rb b/1.8/core/kernel/nil_spec.rb new file mode 100644 index 0000000000..c1c099bb02 --- /dev/null +++ b/1.8/core/kernel/nil_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#nil?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/object_id_spec.rb b/1.8/core/kernel/object_id_spec.rb new file mode 100644 index 0000000000..914164760d --- /dev/null +++ b/1.8/core/kernel/object_id_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/object_id' + +describe "Object.object_id" do + it_behaves_like(:kernel_object_id, :object_id) +end + +describe "Kernel#object_id" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/open_spec.rb b/1.8/core/kernel/open_spec.rb new file mode 100644 index 0000000000..2f12d08c92 --- /dev/null +++ b/1.8/core/kernel/open_spec.rb @@ -0,0 +1,52 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#open" do + it "is a private method" do + Kernel.private_instance_methods.should include("open") + end + + before :each do + @file = "test.txt" + File.open(@file, "w"){ |f| f.puts "This is a test" } + end + + after :each do + File.delete(@file) rescue nil + end + + it "opens a file when given a valid filename" do + @file = open("test.txt") + @file.class.should == File + end + + it "opens a file when called with a block" do + @output = open("test.txt", "r") { |f| f.gets } + @output.should == "This is a test\n" + end + + it "opens an io when path starts with a pipe" do + @io = open("|date") + @io.should be_kind_of(IO) + end + + it "opens an io when called with a block" do + @output = open("|date") { |f| f.gets } + @output.should_not == '' + end + + it "raises an ArgumentError if not passed one argument" do + lambda { open }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { open(nil) }.should raise_error(TypeError) + lambda { open(7) }.should raise_error(TypeError) + lambda { open(mock('x')) }.should raise_error(TypeError) + end +end + +describe "Kernel.open" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/p_spec.rb b/1.8/core/kernel/p_spec.rb new file mode 100644 index 0000000000..1ce72fc9fe --- /dev/null +++ b/1.8/core/kernel/p_spec.rb @@ -0,0 +1,79 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#p" do + before :all do + @rs_f, @rs_b, @rs_c = $/, $\, $, + end + + after :each do + $/, $\, $, = @rs_f, @rs_b, @rs_c + end + + it "is a private method" do + Kernel.private_instance_methods.should include("p") + end + + it "flushes output if receiver is a File" do + filename = "/tmp/Kernel_p_flush" + $$.to_s + begin + File.open(filename, "w") do |f| + begin + old_stdout = $stdout + $stdout = f + p("abcde") + ensure + $stdout = old_stdout + end + + File.open(filename) do |f2| + f2.read(7).should == "\"abcde\"" + end + end + ensure + File.delete(filename) rescue nil + end + end + + it "prints obj.inspect followed by system record separator (usually \\n) for each argument given" do + o = mock("Inspector Gadget") + o.should_receive(:inspect).any_number_of_times.and_return "Next time, Gadget, NEXT TIME!" + + lambda { p(o) }.should output("Next time, Gadget, NEXT TIME!\n") + lambda { p(*[o]) }.should output("Next time, Gadget, NEXT TIME!\n") + lambda { p(*[o, o]) }.should output("Next time, Gadget, NEXT TIME!\nNext time, Gadget, NEXT TIME!\n") + lambda { p([o])}.should output("[#{o.inspect}]\n") + end + + it "is not affected by setting $\\, $/ or $," do + o = mock("Inspector Gadget") + o.should_receive(:inspect).any_number_of_times.and_return "Next time, Gadget, NEXT TIME!" + + $, = " *helicopter sound*\n" + lambda { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n") + + $\ = " *helicopter sound*\n" + lambda { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n") + + $/ = " *helicopter sound*\n" + lambda { p(o) }.should output_to_fd("Next time, Gadget, NEXT TIME!\n") + end + + it "prints nothing if no argument is given" do + lambda { p }.should output("") + end + + it "prints nothing if called splatting an empty Array" do + lambda { p(*[]) }.should output("") + end + +=begin Not sure how to spec this, but wanted to note the behavior here + it "does not flush if receiver is not a TTY or a File" do + end +=end +end + +describe "Kernel.p" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/print_spec.rb b/1.8/core/kernel/print_spec.rb new file mode 100644 index 0000000000..15f473b3d2 --- /dev/null +++ b/1.8/core/kernel/print_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#print" do + it "is a private method" do + Kernel.private_instance_methods.should include("print") + end +end + +describe "Kernel.print" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/printf_spec.rb b/1.8/core/kernel/printf_spec.rb new file mode 100644 index 0000000000..833e272bfe --- /dev/null +++ b/1.8/core/kernel/printf_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#printf" do + it "is a private method" do + Kernel.private_instance_methods.should include("printf") + end +end + +describe "Kernel.printf" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/private_methods_spec.rb b/1.8/core/kernel/private_methods_spec.rb new file mode 100644 index 0000000000..0494d3c05d --- /dev/null +++ b/1.8/core/kernel/private_methods_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#private_methods" do + it "returns a list of the names of privately accessible methods in the object" do + m = KernelSpecs::Methods.private_methods(false) + m.should include("shichi") + m = KernelSpecs::Methods.new.private_methods(false) + m.should include("juu_shi") + end + + it "returns a list of the names of privately accessible methods in the object and its ancestors and mixed-in modules" do + m = (KernelSpecs::Methods.private_methods(false) & KernelSpecs::Methods.private_methods) + + m.should include("shichi") + m = KernelSpecs::Methods.new.private_methods + m.should include('juu_shi') + end +end diff --git a/1.8/core/kernel/proc_spec.rb b/1.8/core/kernel/proc_spec.rb new file mode 100644 index 0000000000..d0e5f14451 --- /dev/null +++ b/1.8/core/kernel/proc_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/lambda' + +describe "Kernel.proc" do + it "is a private method" do + Kernel.private_instance_methods.should include("proc") + end + + it_behaves_like(:kernel_lambda, :proc) +end + +describe "Kernel#proc" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/protected_methods_spec.rb b/1.8/core/kernel/protected_methods_spec.rb new file mode 100644 index 0000000000..1e86771455 --- /dev/null +++ b/1.8/core/kernel/protected_methods_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#protected_methods" do + it "returns a list of the names of protected methods accessible in the object" do + KernelSpecs::Methods.protected_methods(false).sort.should include("juu_ichi") + KernelSpecs::Methods.new.protected_methods(false).should include("ku") + end + + it "returns a list of the names of protected methods accessible in the object and from its ancestors and mixed-in modules" do + l1 = KernelSpecs::Methods.protected_methods(false) + l2 = KernelSpecs::Methods.protected_methods + (l1 & l2).should include("juu_ichi") + KernelSpecs::Methods.new.protected_methods.should include('ku') + end +end diff --git a/1.8/core/kernel/public_methods_spec.rb b/1.8/core/kernel/public_methods_spec.rb new file mode 100644 index 0000000000..ddfaf63c9a --- /dev/null +++ b/1.8/core/kernel/public_methods_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#public_methods" do + it "returns a list of the names of publicly accessible methods in the object" do + KernelSpecs::Methods.public_methods(false).sort.should include("allocate", "hachi", + "ichi", "juu", "juu_ni", "new", "roku", "san", "shi", "superclass") + KernelSpecs::Methods.new.public_methods(false).sort.should include("juu_san", "ni") + end + + it "returns a list of the names of publicly accessible methods in the object and its ancestors and mixed-in modules" do + (KernelSpecs::Methods.public_methods(false) & KernelSpecs::Methods.public_methods).sort.should include( + "allocate", "hachi", "ichi", "juu", "juu_ni", "new", "roku", "san", "shi", "superclass") + m = KernelSpecs::Methods.new.public_methods + m.should include('ni', 'juu_san') + end +end diff --git a/1.8/core/kernel/putc_spec.rb b/1.8/core/kernel/putc_spec.rb new file mode 100644 index 0000000000..4905da766f --- /dev/null +++ b/1.8/core/kernel/putc_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#putc" do + it "is a private method" do + Kernel.private_instance_methods.should include("putc") + end +end + +describe "Kernel.putc" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/puts_spec.rb b/1.8/core/kernel/puts_spec.rb new file mode 100644 index 0000000000..4bdbd12a93 --- /dev/null +++ b/1.8/core/kernel/puts_spec.rb @@ -0,0 +1,86 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#puts" do + it "is a private method" do + Kernel.private_instance_methods.should include("puts") + end + + before(:each) do + @old_stdout = $stdout + $stdout = IO.new(2, 'w') + end + + after(:each) do + $stdout = @old_stdout + end + + it "writes just a newline when given no args" do + $stdout.should_receive(:write).with("\n") + Kernel.puts.should == nil + end + + it "writes nil with a newline when given nil as an arg" do + $stdout.should_receive(:write).with("nil") + $stdout.should_receive(:write).with("\n") + Kernel.puts(nil).should == nil + end + + it "calls to_s before writing non-string objects" do + object = mock('hola') + object.should_receive(:to_s).and_return("hola") + + $stdout.should_receive(:write).with("hola") + $stdout.should_receive(:write).with("\n") + Kernel.puts(object).should == nil + end + + it "writes each arg if given several" do + $stdout.should_receive(:write).with("1") + $stdout.should_receive(:write).with("two") + $stdout.should_receive(:write).with("3") + $stdout.should_receive(:write).with("\n").exactly(3).times + Kernel.puts(1, "two", 3).should == nil + end + + it "flattens a nested array before writing it" do + $stdout.should_receive(:write).with("1") + $stdout.should_receive(:write).with("2") + $stdout.should_receive(:write).with("3") + $stdout.should_receive(:write).with("\n").exactly(3).times + Kernel.puts([1, 2, [3]]).should == nil + end + + it "writes [...] for a recursive array arg" do + x = [] + x << 2 << x + $stdout.should_receive(:write).with("2") + $stdout.should_receive(:write).with("[...]") + $stdout.should_receive(:write).with("\n").exactly(2).times + Kernel.puts(x).should == nil + end + + it "writes a newline after objects that do not end in newlines" do + $stdout.should_receive(:write).with("5") + $stdout.should_receive(:write).with("\n") + Kernel.puts(5).should == nil + end + + it "does not write a newline after objects that end in newlines" do + $stdout.should_receive(:write).with("5\n") + Kernel.puts("5\n").should == nil + end + + it "ignores the $/ separator global" do + $/ = ":" + $stdout.should_receive(:write).with("5") + $stdout.should_receive(:write).with("\n") + Kernel.puts(5).should == nil + $/ = "\n" + end +end + +describe "Kernel.puts" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/raise_spec.rb b/1.8/core/kernel/raise_spec.rb new file mode 100644 index 0000000000..4e9d1f7ad7 --- /dev/null +++ b/1.8/core/kernel/raise_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#raise" do + it "is a private method" do + Kernel.private_instance_methods.should include("raise") + end +end + +describe "Kernel.raise" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/rand_spec.rb b/1.8/core/kernel/rand_spec.rb new file mode 100644 index 0000000000..9c332bf1bc --- /dev/null +++ b/1.8/core/kernel/rand_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.rand" do + it "is a private method" do + Kernel.private_instance_methods.should include("rand") + end + + it "returns a random float less than 1 if no max argument is passed" do + rand.kind_of?(Float).should == true + end + + it "returns a random int or bigint less than the argument for an integer argument" do + rand(77).kind_of?(Integer).should == true + end + + it "returns a random integer less than the argument casted to an int for a float argument greater than 1" do + rand(1.3).kind_of?(Integer).should == true + end + + it "returns a random float less than 1 for float arguments less than 1" do + rand(0.01).kind_of?(Float).should == true + end + + it "never returns a value greater or equal to 1.0 with no arguments" do + 1000.times do + (rand < 1.0).should == true + end + end + + it "never returns a value greater or equal to any passed in max argument" do + 1000.times do + (rand(100) < 100).should == true + end + end +end + +describe "Kernel#rand" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/readline_spec.rb b/1.8/core/kernel/readline_spec.rb new file mode 100644 index 0000000000..a78ea2684f --- /dev/null +++ b/1.8/core/kernel/readline_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#readline" do + it "is a private method" do + Kernel.private_instance_methods.should include("readline") + end +end + +describe "Kernel.readline" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/readlines_spec.rb b/1.8/core/kernel/readlines_spec.rb new file mode 100644 index 0000000000..e797e89c08 --- /dev/null +++ b/1.8/core/kernel/readlines_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#readlines" do + it "is a private method" do + Kernel.private_instance_methods.should include("readlines") + end +end + +describe "Kernel.readlines" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/remove_instance_variable_spec.rb b/1.8/core/kernel/remove_instance_variable_spec.rb new file mode 100644 index 0000000000..f7c2a4098f --- /dev/null +++ b/1.8/core/kernel/remove_instance_variable_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#remove_instance_variable" do + it "is a private method" do + Kernel.private_instance_methods.should include("remove_instance_variable") + end +end diff --git a/1.8/core/kernel/require_spec.rb b/1.8/core/kernel/require_spec.rb new file mode 100644 index 0000000000..703015e3f6 --- /dev/null +++ b/1.8/core/kernel/require_spec.rb @@ -0,0 +1,282 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +$require_fixture_dir = (File.dirname(__FILE__) + '/../../fixtures/require') +$LOAD_PATH << $require_fixture_dir + +$require_spec = nil +$require_spec_1 = nil +$require_spec_2 = nil +$require_spec_3 = nil +$require_spec_4 = nil +$require_spec_5 = nil +$require_spec_6 = nil +$require_spec_7 = nil +$require_spec_8 = nil +$require_spec_9 = nil +$require_spec_10 = nil +$require_spec_rooby = nil +$require_spec_recursive = nil + +require 'rbconfig' + +describe "Kernel#require" do + runner_is_not :rspec do + # RSpec requires rubygems, which redefines #require without setting + # it's visibility back to module_function or private + it "is a private method" do + Kernel.private_instance_methods.should include("require") + end + end + + # Avoid storing .rbc in repo + before :all do + Dir.chdir($require_fixture_dir) { + `rm -f ./*.rbc` + `touch require_spec_dummy.#{Config::CONFIG['DLEXT']}` + `touch require_spec_dummy.rb` + } + end + + # The files used below just contain code that assigns + # Time.now to the respective global variable so that + # reloads can easily be verified. + + # CAUTION: Some of these work because a different path is used to + # load the same file. Be careful if you change the order + # or add items. + + it "loads a .rb from an absolute path and returns true" do + path = File.expand_path(File.dirname(__FILE__) + '/../../fixtures/require/require_spec_1.rb') + + require(path).should == true + $require_spec_1.nil?.should == false + end + + it "loads a .rb from a relative path and returns true" do + Dir.chdir($require_fixture_dir) do |dir| + $require_spec_1 = nil + require('../../fixtures/require/require_spec_1.rb').should == true + $require_spec_1.nil?.should == false + + $require_spec_1 = nil + require('./../require/require_spec_1.rb').should == true + $require_spec_1.nil?.should == false + end + end + + it "loads an unqualified .rb by looking in $LOAD_PATH and returns true" do + require('require_spec_2.rb').should == true + $require_spec_2.nil?.should == false + end + + it "loads extension files" do + # TODO: Not sure how to spec this yet since it needs an extfile + end + + it "does not expand/resolve qualified files against $LOAD_PATH" do + num_features = $LOADED_FEATURES.size + Dir.chdir($require_fixture_dir + '/../') do |dir| + # This would be a valid path if expanded against the fixture dir + lambda { require '../require/require_spec_2.rb' }.should raise_error LoadError + end + $LOADED_FEATURES.size.should == num_features + end + + it "allows unqualified files to contain path information (just not in the beginning)" do + name = (File.dirname(__FILE__) + '/../../fixtures') + $LOAD_PATH << name + + $require_spec2 = nil + require('require/../require/require_spec_2.rb').should == true + $require_spec_2.nil?.should == false + + $LOAD_PATH.delete name + end + + it "appends a file with no extension with .rb/. in that order to locate file" do + load('require_spec') + $require_spec.should == :noext + load('require_spec.rb') + $require_spec.should == :rb + + $require_spec = nil + + require('require_spec') + $require_spec.should == :rb + end + + it "prefers to use .rb over . if given non-extensioned file and both exist" do + require('require_spec_dummy').should == true + $LOADED_FEATURES.include?('require_spec_dummy.rb').should == true + $LOADED_FEATURES.include?("require_spec_dummy.#{Config::CONFIG['DLEXT']}").should == false + end + + runner_is_not :rspec do + it "will not add a bad load to LOADED_FEATURES" do + lambda { require('require_spec_raises') }.should raise_error(RuntimeError) + + $LOADED_FEATURES.include?('require_spec_raises.rb').should == false + end + end + + it "will load file.rb when given 'file' if it exists even if file. is loaded" do + $LOADED_FEATURES << "require_spec_3.#{Config::CONFIG['DLEXT']}" + require('require_spec_3.rb').should == true + $LOADED_FEATURES.include?('require_spec_3.rb').should == true + end + + it "will not load file. when given 'file' if file.rb already loaded" do + unless $LOADED_FEATURES.include?('require_spec_dummy.rb') + require('require_spec_dummy.rb') + end + + require('require_spec_dummy').should == false + end + + it "will load explicit file. even if file.rb already loaded and vice versa" do + # Not sure how to spec this yet because it needs an extfile. + end + + it "appends any non-ruby extensioned file with .rb/. in that order to locate file" do + load('require_spec.rooby') + $require_spec_rooby.should == :rooby + load('require_spec.rooby.rb') + $require_spec_rooby.should == :rb + + $require_spec_rooby = nil + + require('require_spec.rooby') + $require_spec_rooby.should == :rb + end + + it "produces __FILE__ as the given filename and __LINE__ as the source line number" do + Dir.chdir($require_fixture_dir) do |dir| + require('require_spec_4').should == true + $require_spec_4.should == [['./require_spec_4.rb', 1], ['./require_spec_4.rb', 10]] + + extended_on :rubinius do + `rm require_spec_4.rbc` + end + end + + $require_spec_4 = nil + + require("#{$require_fixture_dir}/require_spec_4").should == true + $require_spec_4[0][0].should =~ %r[^.*/fixtures/require/require_spec_4.rb] + $require_spec_4[0][1].should == 1 + $require_spec_4[1][0].should =~ %r[^.*/fixtures/require/require_spec_4.rb] + $require_spec_4[1][1].should == 10 + end + + it "stores the loaded file in $LOADED_FEATURES" do + $LOADED_FEATURES.include?('require_spec_6.rb').should == false + require('require_spec_6.rb').should == true + $LOADED_FEATURES.include?('require_spec_6.rb').should == true + end + + it "stores a non-extensioned file with its located suffix" do + $LOADED_FEATURES.delete 'require_spec_6.rb' + + require('require_spec_6').should == true + + $LOADED_FEATURES.include?('require_spec_6.rb').should == true + end + + it "bases the filename in $LOADED_FEATURES on the path given, not just basename" do + $LOADED_FEATURES.include?('require_spec_6.rb').should == true + + Dir.chdir($require_fixture_dir) do |dir| + require('../../fixtures/require/require_spec_6.rb').should == true + end + + $LOADED_FEATURES.include?('require_spec_6.rb').should == true + $LOADED_FEATURES.include?('../../fixtures/require/require_spec_6.rb').should == true + end + + it "will not load the same file twice, returns false instead" do + $LOADED_FEATURES.include?('require_spec_7.rb').should == false + + require('require_spec_7.rb').should == true + a = $require_spec_7 + a.nil?.should == false + + $LOADED_FEATURES.include?('require_spec_7.rb').should == true + + require('require_spec_7.rb').should == false + b = $require_spec_7 + b.nil?.should == false + + # Timestamps should not differ + a.eql?(b).should == true + + $LOADED_FEATURES.include?('require_spec_7.rb').should == true + end + + it "checks $LOADED_FEATURES to see whether file is already loaded" do + $LOADED_FEATURES.include?('require_spec_7.rb').should == true + require('require_spec_7.rb').should == false + + $LOADED_FEATURES.delete 'require_spec_7.rb' + require('require_spec_7.rb').should == true + require('require_spec_7.rb').should == false + + $LOADED_FEATURES.include?('require_spec_7.rb').should == true + end + + it "raises a LoadError if the file can't be found" do + lambda { require "nonesuch#{$$}#{Time.now.to_f}" }.should raise_error LoadError + end + + it "only accepts strings" do + lambda { require(nil) }.should raise_error(TypeError) + lambda { require(42) }.should raise_error(TypeError) + lambda { require([]) }.should raise_error(TypeError) + end + + it "does not infinite loop on an rb file that requires itself" do + $require_spec_recursive = nil + $LOADED_FEATURES.delete 'require_spec_recursive.rb' + + $LOADED_FEATURES.include?('require_spec_recursive.rb').should == false + require('require_spec_recursive').should == true + $LOADED_FEATURES.include?('require_spec_recursive.rb').should == true + $require_spec_recursive.nil?.should == false + end +end + +describe "Shell expansion in Kernel#require" do + before :all do + @rs_home = ENV["HOME"] + ENV["HOME"] = $require_fixture_dir + @rs_short = "~/require_spec_1.rb" + @rs_long = "#{$require_fixture_dir}/require_spec_1.rb" + end + + after :all do + ENV["HOME"] = @rs_home + end + + before :each do + $LOADED_FEATURES.delete @rs_long + $LOADED_FEATURES.delete @rs_short + end + + it "expands a preceding ~/ to the user's home directory for building the path to search" do + $require_spec_1 = nil + require(@rs_short).should == true + $require_spec_1.nil?.should == false + end + + it "adds the path to $LOADED_FEATURES" do + $require_spec_1 = nil + require(@rs_short).should == true + $require_spec_1.nil?.should == false + + $LOADED_FEATURES.find {|f| f == @rs_short || f == @rs_long }.nil?.should == false + end +end + +describe "Kernel.require" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/respond_to_spec.rb b/1.8/core/kernel/respond_to_spec.rb new file mode 100644 index 0000000000..ecf222f956 --- /dev/null +++ b/1.8/core/kernel/respond_to_spec.rb @@ -0,0 +1,63 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.respond_to?" do + it "indicates if a singleton object responds to a particular message" do + class KernelSpecs::Foo; def self.bar; 'done'; end; end + KernelSpecs::Foo.respond_to?(:bar).should == true + KernelSpecs::Foo.respond_to?(:baz).should == false + end +end + +describe "Kernel#respond_to?" do + before :each do + @a = KernelSpecs::A.new + end + + it "returns false if the given method was undefined" do + @a.respond_to?(:undefed_method).should == false + @a.respond_to?("undefed_method").should == false + end + + it "returns true if obj responds to the given public method" do + @a.respond_to?("five").should == false + @a.respond_to?(:public_method).should == true + @a.respond_to?("public_method").should == true + end + + it "returns true if obj responds to the given protected method" do + @a.respond_to?("five", true).should == false + @a.respond_to?(:protected_method, false).should == true + @a.respond_to?("protected_method", false).should == true + end + + it "returns true if obj responds to the given protected method, include_private = true" do + @a.respond_to?("seven").should == false + @a.respond_to?(:protected_method).should == true + @a.respond_to?("protected_method").should == true + end + + it "returns true if obj responds to the given protected method" do + @a.respond_to?("seven", true).should == false + @a.respond_to?(:protected_method, false).should == true + @a.respond_to?("protected_method", false).should == true + end + + it "returns true if obj responds to the given private method, include_private = true" do + @a.respond_to?("six").should == false + @a.respond_to?(:private_method).should == false + @a.respond_to?("private_method").should == false + end + + it "returns true if obj responds to the given private method" do + @a.respond_to?("six", true).should == false + @a.respond_to?(:private_method, true).should == true + @a.respond_to?("private_method", true).should == true + end + + it "indicates if an object responds to a particular message" do + class KernelSpecs::Foo; def bar; 'done'; end; end + KernelSpecs::Foo.new.respond_to?(:bar).should == true + KernelSpecs::Foo.new.respond_to?(:invalid_and_silly_method_name).should == false + end +end diff --git a/1.8/core/kernel/scan_spec.rb b/1.8/core/kernel/scan_spec.rb new file mode 100644 index 0000000000..5450683f4c --- /dev/null +++ b/1.8/core/kernel/scan_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#scan" do + it "is a private method" do + Kernel.private_instance_methods.should include("scan") + end +end + +describe "Kernel.scan" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/select_spec.rb b/1.8/core/kernel/select_spec.rb new file mode 100644 index 0000000000..60be75a5a5 --- /dev/null +++ b/1.8/core/kernel/select_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#select" do + it "is a private method" do + Kernel.private_instance_methods.should include("select") + end +end + +describe "Kernel.select" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/send_spec.rb b/1.8/core/kernel/send_spec.rb new file mode 100644 index 0000000000..95c3b4eedb --- /dev/null +++ b/1.8/core/kernel/send_spec.rb @@ -0,0 +1,122 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#send" do + it "invokes the named method" do + class KernelSpecs::Foo + def bar + 'done' + end + + private + def bar2 + 'done2' + end + end + KernelSpecs::Foo.new.send(:bar).should == 'done' + KernelSpecs::Foo.new.send(:bar2).should == 'done2' + end + + it "invokes a class method if called on a class" do + class KernelSpecs::Foo + def self.bar + 'done' + end + end + KernelSpecs::Foo.send(:bar).should == 'done' + end + + it "raises a NoMethodError if the corresponding method can't be found" do + class KernelSpecs::Foo + def bar + 'done' + end + end + lambda { KernelSpecs::Foo.new.send(:baz) }.should raise_error(NameError) + end + + it "raises a NoMethodError if the corresponding singleton method can't be found" do + class KernelSpecs::Foo + def self.bar + 'done' + end + end + lambda { KernelSpecs::Foo.send(:baz) }.should raise_error(NameError) + end + + it "raises an ArgumentError if called with more arguments than available parameters" do + class KernelSpecs::Foo + def bar; end + end + + lambda { KernelSpecs::Foo.new.send(:bar, :arg) }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError if called with fewer arguments than required parameters" do + class KernelSpecs::Foo + def foo(arg); end + end + + lambda { KernelSpecs::Foo.new.send(:foo) }.should raise_error(ArgumentError) + end + + it "succeeds if passed an arbitrary number of arguments as a splat parameter" do + class KernelSpecs::Foo + def baz(*args); end + end + + begin + KernelSpecs::Foo.new.send(:baz) + rescue + fail + end + + begin + KernelSpecs::Foo.new.send(:baz, :quux) + rescue + fail + end + + begin + KernelSpecs::Foo.new.send(:baz, :quux, :foo) + rescue + fail + end + end + + it "succeeds when passing 1 or more arguments as a required and a splat parameter" do + class KernelSpecs::Foo + def foo(first, *rest); end + end + + begin + KernelSpecs::Foo.new.send(:baz, :quux) + rescue + fail + end + + begin + KernelSpecs::Foo.new.send(:baz, :quux, :foo) + rescue + fail + end + end + + it "succeeds when passing 0 arguments to a method with one parameter with a default" do + class KernelSpecs::Foo + def foo(first = true); end + end + + begin + KernelSpecs::Foo.new.send(:foo) + rescue + fail + end + + begin + KernelSpecs::Foo.new.send(:foo, :arg) + rescue + fail + end + end +end diff --git a/1.8/core/kernel/set_trace_func_spec.rb b/1.8/core/kernel/set_trace_func_spec.rb new file mode 100644 index 0000000000..137a1981ff --- /dev/null +++ b/1.8/core/kernel/set_trace_func_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#set_trace_func" do + it "is a private method" do + Kernel.private_instance_methods.should include("set_trace_func") + end +end + +describe "Kernel.set_trace_func" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/shared/lambda.rb b/1.8/core/kernel/shared/lambda.rb new file mode 100644 index 0000000000..6987f79f6c --- /dev/null +++ b/1.8/core/kernel/shared/lambda.rb @@ -0,0 +1,35 @@ +shared :kernel_lambda do |cmd| + describe "Kernel.#{cmd}" do + it "returns a Proc object" do + send(cmd) { true }.kind_of?(Proc).should == true + end + + it "raises an ArgumentError when no block is given" do + lambda { send(cmd) }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when given too many arguments" do + lambda { + send(cmd) { |a, b| a + b}.call(1,2,5).should == 3 + }.should raise_error(ArgumentError) + end + + it "returns from block into caller block" do + # More info in the pickaxe book pg. 359 + def some_method(cmd) + p = send(cmd) { return 99 } + res = p.call + "returned #{res}" + end + + # Have to pass in the cmd errors otherwise + some_method(cmd).should == "returned 99" + + def some_method2(&b) b end + a_proc = send(cmd) { return true } + res = some_method2(&a_proc) + + res.call.should == true + end + end +end diff --git a/1.8/core/kernel/shared/object_id.rb b/1.8/core/kernel/shared/object_id.rb new file mode 100644 index 0000000000..e50b2c0835 --- /dev/null +++ b/1.8/core/kernel/shared/object_id.rb @@ -0,0 +1,21 @@ +shared :kernel_object_id do |cmd| + describe "Object##{cmd}" do + # #object_id and #__id__ are aliases, so we only need one function + # that tests both methods + it "returns an integer" do + mock('fixnum').send(cmd).class.should == Fixnum + nil.send(cmd).class.should == Fixnum + end + + it "returns the same value on all calls to id for a given object" do + o1 = mock('x') + o1.send(cmd).should == o1.send(cmd) + end + + it "returns different values for different objects" do + o1 = mock('o1') + o2 = mock('o2') + o1.send(cmd).should_not == o2.send(cmd) + end + end +end diff --git a/1.8/core/kernel/singleton_method_added_spec.rb b/1.8/core/kernel/singleton_method_added_spec.rb new file mode 100644 index 0000000000..9a3556e0ed --- /dev/null +++ b/1.8/core/kernel/singleton_method_added_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#singleton_method_added" do + it "is a private method" do + Kernel.private_instance_methods.should include("singleton_method_added") + end +end diff --git a/1.8/core/kernel/singleton_method_removed_spec.rb b/1.8/core/kernel/singleton_method_removed_spec.rb new file mode 100644 index 0000000000..a8075c8966 --- /dev/null +++ b/1.8/core/kernel/singleton_method_removed_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#singleton_method_removed" do + it "is a private method" do + Kernel.private_instance_methods.should include("singleton_method_removed") + end +end diff --git a/1.8/core/kernel/singleton_method_undefined_spec.rb b/1.8/core/kernel/singleton_method_undefined_spec.rb new file mode 100644 index 0000000000..9237604e2f --- /dev/null +++ b/1.8/core/kernel/singleton_method_undefined_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#singleton_method_undefined" do + it "is a private method" do + Kernel.private_instance_methods.should include("singleton_method_undefined") + end +end diff --git a/1.8/core/kernel/singleton_methods_spec.rb b/1.8/core/kernel/singleton_methods_spec.rb new file mode 100644 index 0000000000..b19cdc1d4a --- /dev/null +++ b/1.8/core/kernel/singleton_methods_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#singleton_methods" do + it "returns a list of the names of singleton methods in the object" do + m = KernelSpecs::Methods.singleton_methods(false) + ["hachi", "ichi", "juu", "juu_ichi", "juu_ni", "roku", "san", "shi"].each do |e| + m.should include(e) + end + + KernelSpecs::Methods.new.singleton_methods(false).should == [] + end + + it "should handle singleton_methods call with and without argument" do + [1, "string", :symbol, [], {} ].each do |e| + lambda {e.singleton_methods}.should_not raise_error + lambda {e.singleton_methods(true)}.should_not raise_error + lambda {e.singleton_methods(false)}.should_not raise_error + end + + end + + it "returns a list of the names of singleton methods in the object and its ancestors and mixed-in modules" do + m = (KernelSpecs::Methods.singleton_methods(false) & KernelSpecs::Methods.singleton_methods) + ["hachi", "ichi", "juu", "juu_ichi", "juu_ni", "roku", "san", "shi"].each do |e| + m.should include(e) + end + + KernelSpecs::Methods.new.singleton_methods.should == [] + end +end diff --git a/1.8/core/kernel/sleep_spec.rb b/1.8/core/kernel/sleep_spec.rb new file mode 100644 index 0000000000..3bec799532 --- /dev/null +++ b/1.8/core/kernel/sleep_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#sleep" do + it "is a private method" do + Kernel.private_instance_methods.should include("sleep") + end + + it "pauses execution for approximately the duration requested" do + duration = 0.01 + start = Time.now + sleep duration + (Time.now - start).should be_close(duration, duration) + end + + it "returns the rounded number of seconds asleep" do + sleep(0.01).should be_kind_of(Integer) + end + + it "raises a TypeError when passed a non-numeric duration" do + lambda { sleep(nil) }.should raise_error(TypeError) + lambda { sleep('now') }.should raise_error(TypeError) + lambda { sleep('2') }.should raise_error(TypeError) + end + + it "pauses execution indefinitely if not given a duration" do + lock = Channel.new + t = Thread.new do + lock << :ready + sleep + 5 + end + lock.receive.should == :ready + Thread.pass unless t.status == "sleep" + t.run + t.value.should == 5 + end +end + +describe "Kernel.sleep" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/split_spec.rb b/1.8/core/kernel/split_spec.rb new file mode 100644 index 0000000000..b99181d379 --- /dev/null +++ b/1.8/core/kernel/split_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#split" do + it "is a private method" do + Kernel.private_instance_methods.should include("split") + end +end + +describe "Kernel.split" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/sprintf_spec.rb b/1.8/core/kernel/sprintf_spec.rb new file mode 100644 index 0000000000..1396782f02 --- /dev/null +++ b/1.8/core/kernel/sprintf_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#sprintf" do + it "is a private method" do + Kernel.private_instance_methods.should include("sprintf") + end + + it "treats nil arguments as zero-width strings in %s slots" do + sprintf("%s%d%s%s", nil, 4, 'a', 'b').should == '4ab' + end + + it "treats nil arguments as zeroes in %d slots" do + sprintf("%d%d%s%s", nil, 4, 'a', 'b').should == '04ab' + end +end + +describe "Kernel.sprintf" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/srand_spec.rb b/1.8/core/kernel/srand_spec.rb new file mode 100644 index 0000000000..807b378e3b --- /dev/null +++ b/1.8/core/kernel/srand_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.srand" do + it "is a private method" do + Kernel.private_instance_methods.should include("srand") + end + + it "srand should return the previous seed value" do + srand(10) + srand(20).should == 10 + end + + it "srand should seed the RNG correctly and repeatably" do + srand(10) + x = rand + srand(10) + rand.should == x + end +end + +describe "Kernel#srand" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/sub_spec.rb b/1.8/core/kernel/sub_spec.rb new file mode 100644 index 0000000000..b642edf17d --- /dev/null +++ b/1.8/core/kernel/sub_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#sub" do + it "is a private method" do + Kernel.private_instance_methods.should include("sub") + end +end + +describe "Kernel#sub!" do + it "is a private method" do + Kernel.private_instance_methods.should include("sub!") + end +end + +describe "Kernel.sub" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "Kernel.sub!" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/syscall_spec.rb b/1.8/core/kernel/syscall_spec.rb new file mode 100644 index 0000000000..489a531788 --- /dev/null +++ b/1.8/core/kernel/syscall_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#syscall" do + it "is a private method" do + Kernel.private_instance_methods.should include("syscall") + end +end + +describe "Kernel.syscall" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/system_spec.rb b/1.8/core/kernel/system_spec.rb new file mode 100644 index 0000000000..4311532700 --- /dev/null +++ b/1.8/core/kernel/system_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#system" do + it "can run basic things that exist" do + begin + result = false + + File.exist?("happy").should == false + result = system("touch happy") + result.should == true + File.exist?("happy").should == true + ensure + File.unlink "happy" + end + end + + it "returns false when it can't" do + result = system("sad") + result.should == false + end + + it "uses /bin/sh if freaky shit is in the command" do + begin + result = false + + File.exist?("happy").should == false + result = system("echo woot > happy") + result.should == true + File.exist?("happy").should == true + ensure + File.unlink "happy" + end + end + + it "is a private method" do + Kernel.private_instance_methods.should include("system") + end +end + +describe "Kernel.system" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/taint_spec.rb b/1.8/core/kernel/taint_spec.rb new file mode 100644 index 0000000000..4ffbee9ae0 --- /dev/null +++ b/1.8/core/kernel/taint_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#taint" do + it "sets self to be tainted" do + mock('tainted?').taint.tainted?.should == true + end + + it "has no effect on immediate values" do + a = nil + b = true + c = false + d = 1 + a.tainted?.should == false + b.tainted?.should == false + c.tainted?.should == false + d.tainted?.should == false + end +end diff --git a/1.8/core/kernel/tainted_spec.rb b/1.8/core/kernel/tainted_spec.rb new file mode 100644 index 0000000000..ae28b5650a --- /dev/null +++ b/1.8/core/kernel/tainted_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#tainted?" do + it "returns true if Object is tainted" do + o = mock('o') + p = mock('p') + p.taint + o.tainted?.should == false + p.tainted?.should == true + end +end \ No newline at end of file diff --git a/1.8/core/kernel/test_spec.rb b/1.8/core/kernel/test_spec.rb new file mode 100644 index 0000000000..e0f75951fc --- /dev/null +++ b/1.8/core/kernel/test_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#test" do + before :all do + @file = File.dirname(__FILE__) + '/fixtures/classes.rb' + @dir = File.dirname(__FILE__) + '/fixtures' + end + + it "is a private method" do + Kernel.private_instance_methods.should include("test") + end + + it "returns true when passed ?f if the argument is a regular file" do + Kernel.test(?f, @file).should == true + end + + it "returns true when passed ?e if the argument is a file" do + Kernel.test(?e, @file).should == true + end + + it "returns true when passed ?d if the argument is a directory" do + Kernel.test(?d, @dir).should == true + end +end + +describe "Kernel.test" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/throw_spec.rb b/1.8/core/kernel/throw_spec.rb new file mode 100644 index 0000000000..f3e86e2453 --- /dev/null +++ b/1.8/core/kernel/throw_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#throw" do + it "is a private method" do + Kernel.private_instance_methods.should include("throw") + end +end + +describe "Kernel.throw" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/to_a_spec.rb b/1.8/core/kernel/to_a_spec.rb new file mode 100644 index 0000000000..b4a67a0059 --- /dev/null +++ b/1.8/core/kernel/to_a_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#to_a" do + it "is defined on Kernel" do + Kernel.instance_methods.should include('to_a') + end +end + +describe "Kernel#to_a when the receiver is an Array" do + it "returns self" do + array = [1, 2] + array.to_a.equal?(array).should == true + end +end + +describe "Kernel#to_a when the receiver is not an Array" do + it "returns an Array containing self" do + object = "I am not an array" + object.to_a.should == [object] + end +end \ No newline at end of file diff --git a/1.8/core/kernel/to_s_spec.rb b/1.8/core/kernel/to_s_spec.rb new file mode 100644 index 0000000000..a5a95bfe7a --- /dev/null +++ b/1.8/core/kernel/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#to_s" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/trace_var_spec.rb b/1.8/core/kernel/trace_var_spec.rb new file mode 100644 index 0000000000..c00ebbdeae --- /dev/null +++ b/1.8/core/kernel/trace_var_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#trace_var" do + it "is a private method" do + Kernel.private_instance_methods.should include("trace_var") + end +end + +describe "Kernel.trace_var" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/trap_spec.rb b/1.8/core/kernel/trap_spec.rb new file mode 100644 index 0000000000..34890091b5 --- /dev/null +++ b/1.8/core/kernel/trap_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#trap" do + it "is a private method" do + Kernel.private_instance_methods.should include("trap") + end +end + +describe "Kernel.trap" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/type_spec.rb b/1.8/core/kernel/type_spec.rb new file mode 100644 index 0000000000..165649da18 --- /dev/null +++ b/1.8/core/kernel/type_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#type" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/untaint_spec.rb b/1.8/core/kernel/untaint_spec.rb new file mode 100644 index 0000000000..9040814f96 --- /dev/null +++ b/1.8/core/kernel/untaint_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#untaint" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/untrace_var_spec.rb b/1.8/core/kernel/untrace_var_spec.rb new file mode 100644 index 0000000000..07def043d5 --- /dev/null +++ b/1.8/core/kernel/untrace_var_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel#untrace_var" do + it "is a private method" do + Kernel.private_instance_methods.should include("untrace_var") + end +end + +describe "Kernel.untrace_var" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/kernel/warn_spec.rb b/1.8/core/kernel/warn_spec.rb new file mode 100644 index 0000000000..f5123d2a89 --- /dev/null +++ b/1.8/core/kernel/warn_spec.rb @@ -0,0 +1,49 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Kernel.warn" do + it "is a private method" do + Kernel.private_instance_methods.should include("warn") + end + + it "calls #write on $stderr" do + lambda { + v = $VERBOSE + $VERBOSE = true + + warn("Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn") + + $VERBOSE = v + }.should output(nil, /Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn\n/) + end + + it "writes the default record seperator (\\n) and NOT $/ to $stderr after the warning message" do + lambda { + v = $VERBOSE + rs = $/ + $VERBOSE = true + $/ = 'rs' + + warn("") + + $VERBOSE = v + $/ = rs + }.should output(nil, /\n/) + end + + it "does not call #write on $stderr if $VERBOSE is nil" do + lambda { + v = $VERBOSE + $VERBOSE = nil + + warn("Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn") + + $VERBOSE = v + }.should output(nil, "") + end +end + +describe "Kernel#warn" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/core/marshal/dump_spec.rb b/1.8/core/marshal/dump_spec.rb new file mode 100644 index 0000000000..b06266f723 --- /dev/null +++ b/1.8/core/marshal/dump_spec.rb @@ -0,0 +1,170 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/marshal_data' + +mv = [Marshal::MAJOR_VERSION].pack 'C' +nv = [Marshal::MINOR_VERSION].pack 'C' + +class UserDefinedBad + def _dump(depth); 10; end +end + +# TODO: these need to be reviewed and cleaned up +describe "Marshal.dump" do + it "raises an ArgumentError when the recursion limit is exceeded" do + lambda { Marshal.dump([], 1) }.should_not raise_error(ArgumentError) + lambda { Marshal.dump([[]], 2) }.should_not raise_error(ArgumentError) + lambda { Marshal.dump([[[]]], 3) }.should_not raise_error(ArgumentError) + + h = {'one' => {'two' => {'three' => 0}}} + lambda { Marshal.dump(h, 3) }.should raise_error(ArgumentError) + lambda { Marshal.dump([h], 4) }.should raise_error(ArgumentError) + lambda { Marshal.dump({}, 1) }.should_not raise_error(ArgumentError) + lambda { Marshal.dump(h, 4) }.should_not raise_error(ArgumentError) + + lambda { Marshal.dump([], 0) }.should raise_error(ArgumentError) + lambda { Marshal.dump([[[]]], 1) }.should raise_error(ArgumentError) + end + + it "ignores the recursion limit if the limit is negative" do + Marshal.dump([], -1) + Marshal.dump([[]], -1) + Marshal.dump([[[]]], -1) + end + + it "writes the serialized data to the IO-Object" do + (obj = mock('test')).should_receive(:write).at_least(1) + Marshal.dump("test", obj) + end + + it "returns the IO-Object" do + (obj = mock('test')).should_receive(:write).at_least(1) + Marshal.dump("test", obj).should == obj + end + + it "raises an Error when the IO-Object does not respond to #write" do + obj = mock('test') + lambda { Marshal.dump("test", obj) }.should raise_error(TypeError) + end + + it "raises an ArgumentError when given more than three arguments" do + lambda { Marshal.dump(nil, nil, nil, nil) }.should raise_error(ArgumentError) + end + + it "raises an Error when trying to dump an anonymous class/module" do + klass = Class.new + mod = Module.new + + lambda { Marshal.dump(klass) }.should raise_error(TypeError) + lambda { Marshal.dump(mod) }.should raise_error(TypeError) + end + + it "raises a TypeError if _dump returns a non-string" do + lambda { Marshal.dump(UserDefinedBad.new) }.should raise_error(TypeError) + end + + it "dumps an Object" do + Marshal.dump(Object.new).should == "#{mv+nv}o:\x0BObject\x00" + end + + it "dumps an extended_object" do + Marshal.dump(Object.new.extend(Meths)).should == "#{mv+nv}e:\x0AMethso:\x0BObject\x00" + end + + it "dumps an object having ivar" do + s = 'hi' + obj = Object.new + obj.instance_variable_set(:@str, [:so, :so, s, s]) + Marshal.dump(obj).should == "#{mv+nv}o:\x0BObject\x06:\x09@str[\x09:\x07so;\x07\"\x07hi@\x07" + end + + it "dumps an extended_user_regexp having ivar" do + r = UserRegexp.new('').extend(Meths) + r.instance_variable_set(:@noise, 'much') + Marshal.dump(r).should == "#{mv+nv}Ie:\x0AMethsC:\x0FUserRegexp/\x00\x00\x06:\x0B@noise\"\x09much" + end + + it "raises a TypeError with hash having default proc" do + lambda { Marshal.dump(Hash.new {}) }.should raise_error(TypeError) + end + + it "dumps an extended_user_hash_default" do + h = UserHash.new(:Meths).extend(Meths) + h['three'] = 3 + Marshal.dump(h).should == "#{mv+nv}e:\x0AMethsC:\x0DUserHash}\x06\"\x0Athreei\x08;\x00" + end + + it "dumps an extended_user_hash with a parameter to initialize" do + h = UserHashInitParams.new(:abc).extend(Meths) + h['three'] = 3 + Marshal.dump(h).should == "\004\bIe:\nMethsC:\027UserHashInitParams{\006\"\nthreei\b\006:\a@a:\babc" + end + + it "dumps an array containing objects having _dump method" do + o1 = UserDefined.new + o2 = UserDefinedWithIvar.new + a = [o1, o2, o1, o2] + Marshal.dump(a).should == + "#{mv+nv}[\tu:\020UserDefined\022\004\b[\a\"\nstuff@\006u:\030UserDefinedWithIvar5\004\b[\bI\"\nstuff\006:\t@foo:\030UserDefinedWithIvar\"\tmore@\a@\006@\a" + end + + it "dumps an array containing objects having marshal_dump method" do + o1 = UserMarshal.new + o2 = UserMarshalWithIvar.new + a = [o1, o2, o1, o2] + Marshal.dump(a).should == + "#{mv+nv}[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b" + end + + it "dumps an array containing the same objects" do + s = 'oh'; b = 'hi'; r = //; d = [b, :no, s, :go]; c = String + a = [:so, 'hello', 100, :so, :so, d, :so, :so, :no, :go, c, nil, + :go, :no, s, b, r, :so, 'huh', true, b, b, 99, r, b, s, :so, c, :no, d] + Marshal.dump(a).should == + "#{mv+nv}[\x23:\x07so\"\x0Ahelloi\x69;\x00;\x00[\x09\"\x07hi:\x07no\"\x07oh:\x07go;\x00;\x00;\x06;\x07c\x0BString0;\x07;\x06@\x09@\x08/\x00\x00;\x00\"\x08huhT@\x08@\x08i\x68@\x0B@\x08@\x09;\x00@\x0A;\x06@\x07" + end + + it "dumps an extended_array having ivar" do + s = 'well' + s.instance_variable_set(:@foo, 10) + a = ['5', s, 'hi'].extend(Meths, MethsMore) + a.instance_variable_set(:@mix, s) + Marshal.dump(a).should == + "#{mv+nv}Ie:\x0AMethse:\x0EMethsMore[\x08\"\x065I\"\x09well\x06:\x09@fooi\x0F\"\x07hi\x06:\x09@mix@\x07" + end + + it "dumps a struct having ivar" do + st = Struct.new("Thick").new + st.instance_variable_set(:@foo, 5) + Marshal.dump(st).should == "#{mv+nv}IS:\x12Struct::Thick\x00\x06:\x09@fooi\x0A" + end + + it "dumps a struct having fields" do + Marshal.dump(Struct.new("Ure1", :a, :b).new).should == "#{mv+nv}S:\x11Struct::Ure1\x07:\x06a0:\x06b0" + end + + it "dumps an extended_struct having fields with same objects" do + s = 'hi' + st = Struct.new("Ure2", :a, :b).new.extend(Meths) + st.a = [:a, s]; st.b = [:Meths, s] + Marshal.dump(st).should == + "#{mv+nv}e:\x0AMethsS:\x11Struct::Ure2\x07:\x06a[\x07;\x07\"\x07hi:\x06b[\x07;\x00@\x07" + end +end + +describe "Marshal.dump" do + MarshalSpec::DATA.each do |description, (object, marshal, attributes)| + it "dumps a #{description}" do + unless attributes then + Marshal.dump(object).should == marshal + else + # these objects have non-deterministic field order in the + # marshal stream, so they need a round trip and independent + # verification. + object = Marshal.load(Marshal.dump(object)) + attributes.each do |attr, val| + object.send(attr).should == val + end + end + end + end +end diff --git a/1.8/core/marshal/fixtures/marshal_data.rb b/1.8/core/marshal/fixtures/marshal_data.rb new file mode 100644 index 0000000000..d0a9e0b981 --- /dev/null +++ b/1.8/core/marshal/fixtures/marshal_data.rb @@ -0,0 +1,236 @@ +class UserDefined + + class Nested + def ==(other) + other.kind_of? self.class + end + end + + attr_reader :a, :b + + def initialize + @a = 'stuff' + @b = @a + end + + def _dump(depth) + Marshal.dump [@a, @b] + end + + def self._load(data) + a, b = Marshal.load data + + obj = allocate + obj.instance_variable_set :@a, a + obj.instance_variable_set :@b, b + + obj + end + + def ==(other) + self.class === other and + @a == other.a and + @b == other.b + end + +end + +class UserDefinedWithIvar + attr_reader :a, :b, :c + + def initialize + @a = 'stuff' + @a.instance_variable_set :@foo, :UserDefinedWithIvar + @b = 'more' + @c = @b + end + + def _dump(depth) + Marshal.dump [@a, @b, @c] + end + + def self._load(data) + a, b, c = Marshal.load data + + obj = allocate + obj.instance_variable_set :@a, a + obj.instance_variable_set :@b, b + obj.instance_variable_set :@c, c + + obj + end + + def ==(other) + self.class === other and + @a == other.a and + @b == other.b and + @c == other.c and + @a.instance_variable_get(:@foo) == other.a.instance_variable_get(:@foo) + end +end + +class UserMarshal + attr_reader :data + + def initialize + @data = 'stuff' + end + def marshal_dump() @data end + def marshal_load(data) @data = data end + def ==(other) self.class === other and @data == other.data end +end + +class UserMarshalWithIvar + attr_reader :data + + def initialize + @data = 'my data' + end + + def marshal_dump + [@data] + end + + def marshal_load(o) + @data = o.first + end + + def ==(other) + self.class === other and + @data = other.data + end +end + +class UserArray < Array +end + +class UserHash < Hash +end + +class UserHashInitParams < Hash + def initialize(a) + @a = a + end +end + +class UserObject +end + +class UserRegexp < Regexp +end + +class UserString < String +end + +module Meths + def meths_method() end +end + +module MethsMore + def meths_more_method() end +end + +Struct.new "Pyramid" +Struct.new "Useful", :a, :b + +module MarshalSpec + DATA = { + "nil" => [nil, "\004\b0"], + "1..2" => [(1..2), + "\004\bo:\nRange\b:\nbegini\006:\texclF:\bendi\a", + { :begin => 1, :end => 2, :exclude_end? => false }], + "1...2" => [(1...2), + "\004\bo:\nRange\b:\nbegini\006:\texclT:\bendi\a", + { :begin => 1, :end => 2, :exclude_end? => true }], + "'a'..'b'" => [('a'..'b'), + "\004\bo:\nRange\b:\nbegin\"\006a:\texclF:\bend\"\006b", + { :begin => 'a', :end => 'b', :exclude_end? => false }], + "Struct" => [Struct::Useful.new(1, 2), + "\004\bS:\023Struct::Useful\a:\006ai\006:\006bi\a"], + "Symbol" => [:symbol, + "\004\b:\vsymbol"], + "true" => [true, + "\004\bT"], + "false" => [false, + "\004\bF"], + "String empty" => ['', + "\004\b\"\000"], + "String small" => ['small', + "\004\b\"\012small"], + "String big" => ['big' * 100, + "\004\b\"\002,\001#{'big' * 100}"], + "String extended" => [''.extend(Meths), # TODO: check for module on load + "\004\be:\nMeths\"\000"], + "String subclass" => [UserString.new, + "\004\bC:\017UserString\"\000"], + "String subclass extended" => [UserString.new.extend(Meths), + "\004\be:\nMethsC:\017UserString\"\000"], + "Symbol small" => [:big, + "\004\b:\010big"], + "Symbol big" => [('big' * 100).to_sym, + "\004\b:\002,\001#{'big' * 100}"], + "Bignum -2**64" => [-2**64, + "\004\bl-\n\000\000\000\000\000\000\000\000\001\000"], + "Bignum -2**63" => [-2**63, + "\004\bl-\t\000\000\000\000\000\000\000\200"], + "Fixnum -2**24" => [-2**24, + "\004\bi\375\000\000\000"], + "Fixnum -2**16" => [-2**16, + "\004\bi\376\000\000"], + "Fixnum -2**8" => [-2**8, + "\004\bi\377\000"], + "Fixnum -123" => [-123, + "\004\bi\200"], + "Fixnum 0" => [0, + "\004\bi\000"], + "Fixnum 5" => [5, + "\004\bi\n"], + "Fixnum 2**8" => [2**8, + "\004\bi\002\000\001"], + "Fixnum 2**16" => [2**16, + "\004\bi\003\000\000\001"], + "Fixnum 2**24" => [2**24, + "\004\bi\004\000\000\000\001"], + "Bignum 2**64" => [2**64, + "\004\bl+\n\000\000\000\000\000\000\000\000\001\000"], + "Bignum 2**90" => [2**90, + "\004\bl+\v#{"\000" * 11}\004"], + "Class String" => [String, + "\004\bc\vString"], + "Module Marshal" => [Marshal, + "\004\bm\fMarshal"], + "Module nested" => [UserDefined::Nested.new, + "\004\bo:\030UserDefined::Nested\000"], + "_dump object" => [UserDefinedWithIvar.new, + "\004\bu:\030UserDefinedWithIvar5\004\b[\bI\"\nstuff\006:\t@foo:\030UserDefinedWithIvar\"\tmore@\a"], + "_dump object extended" => [UserDefined.new.extend(Meths), + "\004\bu:\020UserDefined\022\004\b[\a\"\nstuff@\006"], + "marshal_dump object" => [UserMarshalWithIvar.new, + "\004\bU:\030UserMarshalWithIvar[\006\"\fmy data"], + "Regexp" => [/\A.\Z/, + "\004\b/\n\\A.\\Z\000"], + "Regexp subclass /i" => [UserRegexp.new('', Regexp::IGNORECASE), + "\004\bC:\017UserRegexp/\000\001"], + "Float 0.0" => [0.0, + "\004\bf\0060"], + "Float -0.0" => [-0.0, + "\004\bf\a-0"], + "Float Infinity" => [(1.0 / 0.0), + "\004\bf\binf"], + "Float -Infinity" => [(-1.0 / 0.0), + "\004\bf\t-inf"], + "Float 1.0" => [1.0, + "\004\bf\0061"], + "Hash" => [Hash.new, + "\004\b{\000"], + "Hash subclass" => [UserHash.new, + "\004\bC:\rUserHash{\000"], + "Array" => [Array.new, + "\004\b[\000"], + "Array subclass" => [UserArray.new, + "\004\bC:\016UserArray[\000"], + "Struct" => [Struct::Pyramid.new, + "\004\bS:\024Struct::Pyramid\000"], + } +end + diff --git a/1.8/core/marshal/load_spec.rb b/1.8/core/marshal/load_spec.rb new file mode 100644 index 0000000000..aaa18e1110 --- /dev/null +++ b/1.8/core/marshal/load_spec.rb @@ -0,0 +1,228 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/marshal_data' + +describe "Marshal::load" do + it "loads a extended_struct having fields with same objects" do + s = 'hi' + obj = Struct.new("Ure2", :a, :b).new.extend(Meths) + obj.a = [:a, s]; obj.b = [:Meths, s] + + Marshal.load("\004\be:\nMethsS:\021Struct::Ure2\a:\006a[\a;\a\"\ahi:\006b[\a;\000@\a").should == + obj + end + + it "loads a string having ivar with ref to self" do + obj = 'hi' + obj.instance_variable_set(:@self, obj) + Marshal.load("\004\bI\"\ahi\006:\n@self@\000").should == obj + end + + it "loads an extended_user_hash with a parameter to initialize" do + obj = UserHashInitParams.new(:abc).extend(Meths) + + new_obj = Marshal.load "\004\bIe:\nMethsC:\027UserHashInitParams{\000\006:\a@a:\babc" + + new_obj.should == obj + new_obj_metaclass_ancestors = class << new_obj; ancestors; end + new_obj_metaclass_ancestors[0].should == Meths + new_obj_metaclass_ancestors[1].should == UserHashInitParams + end + + it "loads a user-marshaled extended object" do + obj = UserMarshal.new.extend(Meths) + + new_obj = Marshal.load "\004\bU:\020UserMarshal\"\nstuff" + + new_obj.should == obj + new_obj_metaclass_ancestors = class << new_obj; ancestors; end + new_obj_metaclass_ancestors.first.should == UserMarshal + end + + it "loads a user_object" do + obj = UserObject.new + Marshal.load("\004\bo:\017UserObject\000").class.should == UserObject + end + + it "loads a object" do + Marshal.load("\004\bo:\vObject\000").class.should == Object + end + + it "loads an extended Object" do + obj = Object.new.extend(Meths) + + new_obj = Marshal.load "\004\be:\nMethso:\vObject\000" + + new_obj.class.should == obj.class + new_obj_metaclass_ancestors = class << new_obj; ancestors; end + new_obj_metaclass_ancestors.first(2).should == [Meths, Object] + end + + it "loads a object having ivar" do + s = 'hi' + arr = [:so, :so, s, s] + obj = Object.new + obj.instance_variable_set :@str, arr + + new_obj = Marshal.load "\004\bo:\vObject\006:\t@str[\t:\aso;\a\"\ahi@\a" + new_str = new_obj.instance_variable_get :@str + + new_str.should == arr + end + + it "loads an extended Regexp" do + obj = /[a-z]/.extend(Meths, MethsMore) + new_obj = Marshal.load "\004\be:\nMethse:\016MethsMore/\n[a-z]\000" + + new_obj.should == obj + new_obj_metaclass_ancestors = class << new_obj; ancestors; end + new_obj_metaclass_ancestors.first(3).should == + [Meths, MethsMore, Regexp] + end + + it "loads a extended_user_regexp having ivar" do + obj = UserRegexp.new('').extend(Meths) + obj.instance_variable_set(:@noise, 'much') + + new_obj = Marshal.load "\004\bIe:\nMethsC:\017UserRegexp/\000\000\006:\v@noise\"\tmuch" + + new_obj.should == obj + new_obj.instance_variable_get(:@noise).should == 'much' + new_obj_metaclass_ancestors = class << new_obj; ancestors; end + new_obj_metaclass_ancestors.first(3).should == + [Meths, UserRegexp, Regexp] + end + + it "loads a Float NaN" do + obj = 0.0 / 0.0 + Marshal.load("\004\bf\bnan").to_s.should == obj.to_s + end + + it "loads a Float 1.3" do + Marshal.load("\004\bf\v1.3\000\314\315").should == 1.3 + end + + it "loads a Float -5.1867345e-22" do + obj = -5.1867345e-22 + Marshal.load("\004\bf\037-5.1867345000000008e-22\000\203_").should be_close(obj, 1e-30) + end + + it "loads a Float 1.1867345e+22" do + obj = 1.1867345e+22 + Marshal.load("\004\bf\0361.1867344999999999e+22\000\344@").should == + obj + end + + it "loads a array containing objects having _dump method, and with proc" do + arr = [] + proc = Proc.new { |o| arr << o } + o1 = UserDefined.new; o2 = UserDefinedWithIvar.new + obj = [o1, o2, o1, o2] + + Marshal.load "\004\b[\tu:\020UserDefined\022\004\b[\a\"\nstuff@\006u:\030UserDefinedWithIvar5\004\b[\bI\"\nstuff\006:\t@foo:\030UserDefinedWithIvar\"\tmore@\a@\006@\a", proc + + arr.should == [o1, o2, obj] + end + + it "loads an array containing objects having marshal_dump method, and with proc" do + arr = [] + proc = Proc.new { |o| arr << o } + o1 = UserMarshal.new + o2 = UserMarshalWithIvar.new + obj = [o1, o2, o1, o2] + + Marshal.load "\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc + + arr.should == ['stuff', o1, 'my data', ['my data'], o2, obj] + end + + it "loads an Array with proc" do + arr = [] + s = 'hi' + s.instance_variable_set(:@foo, 5) + st = Struct.new("Brittle", :a).new + st.instance_variable_set(:@clue, 'none') + st.a = 0.0 + h = Hash.new('def') + h['nine'] = 9 + a = [:a, :b, :c] + a.instance_variable_set(:@two, 2) + obj = [s, 10, s, s, st, h, a] + obj.instance_variable_set(:@zoo, 'ant') + + proc = Proc.new { |o| arr << o } + new_obj = Marshal.load "\004\bI[\fI\"\ahi\006:\t@fooi\ni\017@\006@\006IS:\024Struct::Brittle\006:\006af\0060\006:\n@clue\"\tnone}\006\"\tninei\016\"\bdefI[\b;\a:\006b:\006c\006:\t@twoi\a\006:\t@zoo\"\bant", proc + + new_obj.should == obj + new_obj.instance_variable_get(:@zoo).should == 'ant' + + arr.should == + [5, s, 10, 0.0, 'none', st, 'nine', 9, 'def', h, :b, :c, 2, a, 'ant', obj] + end + + it "loads a array containing the same objects" do + s = 'oh'; b = 'hi'; r = //; d = [b, :no, s, :go]; c = String; f = 1.0 + o1 = UserMarshalWithIvar.new; o2 = UserMarshal.new + obj = [:so, 'hello', 100, :so, :so, d, :so, o2, :so, :no, o2, + :go, c, nil, Struct::Pyramid.new, f, :go, :no, s, b, r, + :so, 'huh', o1, true, b, b, 99, r, b, s, :so, f, c, :no, o1, d] + + Marshal.load("\004\b[*:\aso\"\nhelloii;\000;\000[\t\"\ahi:\ano\"\aoh:\ago;\000U:\020UserMarshal\"\nstuff;\000;\006@\n;\ac\vString0S:\024Struct::Pyramid\000f\0061;\a;\006@\t@\b/\000\000;\000\"\bhuhU:\030UserMarshalWithIvar[\006\"\fmy dataT@\b@\bih@\017@\b@\t;\000@\016@\f;\006@\021@\a").should == + obj + end + + it "loads an array having ivar" do + s = 'well' + s.instance_variable_set(:@foo, 10) + obj = ['5', s, 'hi'].extend(Meths, MethsMore) + obj.instance_variable_set(:@mix, s) + Marshal.load("\004\bI[\b\"\0065I\"\twell\006:\t@fooi\017\"\ahi\006:\t@mix@\a").should == + obj + end + + it "loads a struct having ivar" do + obj = Struct.new("Thick").new + obj.instance_variable_set(:@foo, 5) + Marshal.load("\004\bIS:\022Struct::Thick\000\006:\t@fooi\n").should == + obj + end + + it "loads a struct having fields" do + obj = Struct.new("Ure1", :a, :b).new + Marshal.load("\004\bS:\021Struct::Ure1\a:\006a0:\006b0").should == + obj + end + + it "raises a TypeError with bad Marshal version" do + marshal_data = '\xff\xff' + marshal_data[0] = (Marshal::MAJOR_VERSION).chr + marshal_data[1] = (Marshal::MINOR_VERSION + 1).chr + + lambda { Marshal.load marshal_data }.should raise_error(TypeError) + + marshal_data = '\xff\xff' + marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr + marshal_data[1] = (Marshal::MINOR_VERSION).chr + + lambda { Marshal.load marshal_data }.should raise_error(TypeError) + end + + it "raises EOFError on loading an empty file" do + temp_file = "marshal.rubinius.tmp.#{Process.pid}" + file = File.new(temp_file, "w+") + begin + # TODO: This should be in an ensure block, but because of a bug in + # Rubinius that can't be done yet. + File.unlink(temp_file) + + lambda { Marshal.load(file) }.should raise_error(EOFError) + ensure + file.close + end + end + + MarshalSpec::DATA.each do |description, (object, marshal, attributes)| + it "loads a #{description}" do + Marshal.load(marshal).should == object + end + end +end diff --git a/1.8/core/marshal/restore_spec.rb b/1.8/core/marshal/restore_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/marshal/restore_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/matchdata/begin_spec.rb b/1.8/core/matchdata/begin_spec.rb new file mode 100644 index 0000000000..a263db86cd --- /dev/null +++ b/1.8/core/matchdata/begin_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#begin" do + it "returns the offset of the start of the nth element" do + /(.)(.)(\d+)(\d)/.match("THX1138.").begin(0).should == 1 + /(.)(.)(\d+)(\d)/.match("THX1138.").begin(2).should == 2 + end +end diff --git a/1.8/core/matchdata/captures_spec.rb b/1.8/core/matchdata/captures_spec.rb new file mode 100644 index 0000000000..76ad88f62d --- /dev/null +++ b/1.8/core/matchdata/captures_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#captures" do + it "returns an array of the match captures" do + /(.)(.)(\d+)(\d)/.match("THX1138.").captures.should == ["H","X","113","8"] + end +end diff --git a/1.8/core/matchdata/element_reference_spec.rb b/1.8/core/matchdata/element_reference_spec.rb new file mode 100644 index 0000000000..1b75f2d4b0 --- /dev/null +++ b/1.8/core/matchdata/element_reference_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#[]" do + it "acts as normal array indexing [index]" do + /(.)(.)(\d+)(\d)/.match("THX1138.")[0].should == 'HX1138' + /(.)(.)(\d+)(\d)/.match("THX1138.")[1].should == 'H' + /(.)(.)(\d+)(\d)/.match("THX1138.")[2].should == 'X' + end + + it "supports accessors [start, length]" do + /(.)(.)(\d+)(\d)/.match("THX1138.")[1, 2].should == %w|H X| + /(.)(.)(\d+)(\d)/.match("THX1138.")[-3, 2].should == %w|X 113| + end + + it "supports ranges [start..end]" do + /(.)(.)(\d+)(\d)/.match("THX1138.")[1..3].should == %w|H X 113| + end +end diff --git a/1.8/core/matchdata/end_spec.rb b/1.8/core/matchdata/end_spec.rb new file mode 100644 index 0000000000..02245c2f40 --- /dev/null +++ b/1.8/core/matchdata/end_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#end" do + it "returns the offset of the end of the nth element" do + /(.)(.)(\d+)(\d)/.match("THX1138.").end(0).should == 7 + /(.)(.)(\d+)(\d)/.match("THX1138.").end(2).should == 3 + end +end diff --git a/1.8/core/matchdata/initialize_copy_spec.rb b/1.8/core/matchdata/initialize_copy_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/matchdata/initialize_copy_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/matchdata/inspect_spec.rb b/1.8/core/matchdata/inspect_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/matchdata/inspect_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/matchdata/length_spec.rb b/1.8/core/matchdata/length_spec.rb new file mode 100644 index 0000000000..6555dff62b --- /dev/null +++ b/1.8/core/matchdata/length_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/length' + +describe "MatchData#length" do + it_behaves_like(:matchdata_length, :length) +end diff --git a/1.8/core/matchdata/offset_spec.rb b/1.8/core/matchdata/offset_spec.rb new file mode 100644 index 0000000000..636cd7ce24 --- /dev/null +++ b/1.8/core/matchdata/offset_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#offset" do + it "returns a two element array with the begin and end of the nth match" do + /(.)(.)(\d+)(\d)/.match("THX1138.").offset(0).should == [1, 7] + /(.)(.)(\d+)(\d)/.match("THX1138.").offset(4).should == [6, 7] + end +end diff --git a/1.8/core/matchdata/post_match_spec.rb b/1.8/core/matchdata/post_match_spec.rb new file mode 100644 index 0000000000..dddc3c4e37 --- /dev/null +++ b/1.8/core/matchdata/post_match_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#post_match" do + it "returns the string after the match equiv. special var $'" do + /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").post_match.should == ': The Movie' + $'.should == ': The Movie' + end +end diff --git a/1.8/core/matchdata/pre_match_spec.rb b/1.8/core/matchdata/pre_match_spec.rb new file mode 100644 index 0000000000..62d060902c --- /dev/null +++ b/1.8/core/matchdata/pre_match_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#pre_match" do + it "returns the string before the match, equiv. special var $`" do + /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").pre_match.should == 'T' + $`.should == 'T' + end +end diff --git a/1.8/core/matchdata/select_spec.rb b/1.8/core/matchdata/select_spec.rb new file mode 100644 index 0000000000..019d70fcbd --- /dev/null +++ b/1.8/core/matchdata/select_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#select" do + it "yields the contents of the match array to a block" do + /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").select { |x| x }.should == ["HX1138", "H", "X", "113", "8"] + end +end diff --git a/1.8/core/matchdata/shared/length.rb b/1.8/core/matchdata/shared/length.rb new file mode 100644 index 0000000000..7adbfbf6f4 --- /dev/null +++ b/1.8/core/matchdata/shared/length.rb @@ -0,0 +1,7 @@ +shared :matchdata_length do |cmd| + describe "MatchData##{cmd}" do + it "length should return the number of elements in the match array" do + /(.)(.)(\d+)(\d)/.match("THX1138.").send(cmd).should == 5 + end + end +end diff --git a/1.8/core/matchdata/size_spec.rb b/1.8/core/matchdata/size_spec.rb new file mode 100644 index 0000000000..cb6280ee24 --- /dev/null +++ b/1.8/core/matchdata/size_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/length' + +describe "MatchData#size" do + it_behaves_like(:matchdata_length, :size) +end diff --git a/1.8/core/matchdata/string_spec.rb b/1.8/core/matchdata/string_spec.rb new file mode 100644 index 0000000000..0f32529871 --- /dev/null +++ b/1.8/core/matchdata/string_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#string" do + it "returns a copy of the match string" do + str = /(.)(.)(\d+)(\d)/.match("THX1138.").string + str.should == "THX1138." + end + + compliant_on :ruby, :jruby do + it "returns a frozen copy of the match string" do + str = /(.)(.)(\d+)(\d)/.match("THX1138.").string + str.should == "THX1138." + str.frozen?.should == true + end + end +end diff --git a/1.8/core/matchdata/to_a_spec.rb b/1.8/core/matchdata/to_a_spec.rb new file mode 100644 index 0000000000..773d1caf69 --- /dev/null +++ b/1.8/core/matchdata/to_a_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#to_a" do + it "returns an array of matches" do + /(.)(.)(\d+)(\d)/.match("THX1138.").to_a.should == ["HX1138", "H", "X", "113", "8"] + end +end diff --git a/1.8/core/matchdata/to_s_spec.rb b/1.8/core/matchdata/to_s_spec.rb new file mode 100644 index 0000000000..f23197e738 --- /dev/null +++ b/1.8/core/matchdata/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#to_s" do + it "returns the entire matched string" do + /(.)(.)(\d+)(\d)/.match("THX1138.").to_s.should == "HX1138" + end +end diff --git a/1.8/core/matchdata/values_at_spec.rb b/1.8/core/matchdata/values_at_spec.rb new file mode 100644 index 0000000000..8f8aea00e1 --- /dev/null +++ b/1.8/core/matchdata/values_at_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "MatchData#values_at" do + it "returns an array of the matching value" do + /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0, 2, -2).should == ["HX1138", "X", "113"] + end +end diff --git a/1.8/core/math/acos_spec.rb b/1.8/core/math/acos_spec.rb new file mode 100644 index 0000000000..b043d09911 --- /dev/null +++ b/1.8/core/math/acos_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# arccosine : (-1.0, 1.0) --> (0, PI) +describe "Math.acos" do + it "returns a float" do + Math.acos(1).class.should == Float + end + + it "returns the arccosine of the argument" do + Math.acos(1).should be_close(0.0, TOLERANCE) + Math.acos(0).should be_close(1.5707963267949, TOLERANCE) + Math.acos(-1).should be_close(Math::PI,TOLERANCE) + Math.acos(0.25).should be_close(1.31811607165282, TOLERANCE) + Math.acos(0.50).should be_close(1.0471975511966 , TOLERANCE) + Math.acos(0.75).should be_close(0.722734247813416, TOLERANCE) + end + + it "raises an Errno::EDOM if the argument is greater than 1.0" do + lambda { Math.acos(1.0001) }.should raise_error(Errno::EDOM) + end + + it "raises an Errno::EDOM if the argument is less than -1.0" do + lambda { Math.acos(-1.0001) }.should raise_error(Errno::EDOM) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.acos("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.acos(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.acos(MathSpecs::Float.new).should == 0.0 + end +end + +describe "Math#acos" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:acos, 0).should be_close(1.5707963267949, TOLERANCE) + end +end diff --git a/1.8/core/math/acosh_spec.rb b/1.8/core/math/acosh_spec.rb new file mode 100644 index 0000000000..403541ecb7 --- /dev/null +++ b/1.8/core/math/acosh_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.acosh" do + it "returns a float" do + Math.acosh(1.0).class.should == Float + end + + it "returns the principle value of the inverse hyperbolic cosine of the argument" do + Math.acosh(14.2).should be_close(3.345146999647, TOLERANCE) + Math.acosh(1.0).should be_close(0.0, TOLERANCE) + end + + it "it raises Errno::EDOM if x < 1" do + lambda { Math.acosh(1.0 - TOLERANCE) }.should raise_error(Errno::EDOM) + lambda { Math.acosh(0) }.should raise_error(Errno::EDOM) + lambda { Math.acosh(-1.0) }.should raise_error(Errno::EDOM) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.acosh("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.acosh(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.acosh(MathSpecs::Float.new).should == 0.0 + end +end + +describe "Math#acosh" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:acosh, 1.0).should be_close(0.0, TOLERANCE) + end +end diff --git a/1.8/core/math/asin_spec.rb b/1.8/core/math/asin_spec.rb new file mode 100644 index 0000000000..884889702a --- /dev/null +++ b/1.8/core/math/asin_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# arcsine : (-1.0, 1.0) --> (-PI/2, PI/2) +describe "Math.asin" do + it "return a float" do + Math.asin(1).class.should == Float + end + + it "returns the arcsine of the argument" do + Math.asin(1).should be_close(Math::PI/2, TOLERANCE) + Math.asin(0).should be_close(0.0, TOLERANCE) + Math.asin(-1).should be_close(-Math::PI/2, TOLERANCE) + Math.asin(0.25).should be_close(0.252680255142079, TOLERANCE) + Math.asin(0.50).should be_close(0.523598775598299, TOLERANCE) + Math.asin(0.75).should be_close(0.8480620789814816,TOLERANCE) + end + + it "raises an Errno::EDOM if the argument is greater than 1.0" do + lambda { Math.asin(1.0001) }.should raise_error( Errno::EDOM) + end + + it "raises an Errno::EDOM if the argument is less than -1.0" do + lambda { Math.asin(-1.0001) }.should raise_error( Errno::EDOM) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.asin("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.asin(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.asin(MathSpecs::Float.new).should be_close(1.5707963267949, TOLERANCE) + end +end + +describe "Math#asin" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:asin, 0.5).should be_close(0.523598775598299, TOLERANCE) + end +end diff --git a/1.8/core/math/asinh_spec.rb b/1.8/core/math/asinh_spec.rb new file mode 100644 index 0000000000..75739c208c --- /dev/null +++ b/1.8/core/math/asinh_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.asinh" do + it "returns a float" do + Math.asinh(1.5).class.should == Float + end + + it "returns the inverse hyperbolic sin of the argument" do + Math.asinh(1.5).should be_close(1.19476321728711, TOLERANCE) + Math.asinh(-2.97).should be_close(-1.8089166921397, TOLERANCE) + Math.asinh(0.0).should == 0.0 + Math.asinh(-0.0).should == -0.0 + Math.asinh(1.05367e-08).should be_close(1.05367e-08, TOLERANCE) + Math.asinh(-1.05367e-08).should be_close(-1.05367e-08, TOLERANCE) + # Default tolerance does not scale right for these... + #Math.asinh(94906265.62).should be_close(19.0615, TOLERANCE) + #Math.asinh(-94906265.62).should be_close(-19.0615, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.asinh("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.asinh(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.asinh(MathSpecs::Float.new).should be_close(0.881373587019543, TOLERANCE) + end +end + +describe "Math#asinh" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:asinh, 19.275).should be_close(3.65262832292466, TOLERANCE) + end +end diff --git a/1.8/core/math/atan2_spec.rb b/1.8/core/math/atan2_spec.rb new file mode 100644 index 0000000000..c16d97512c --- /dev/null +++ b/1.8/core/math/atan2_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.atan2" do + it "returns a float" do + Math.atan2(1.2, 0.5).class.should == Float + end + + it "returns the arc tangent of y, x" do + Math.atan2(4.2, 0.3).should be_close(1.49948886200961, TOLERANCE) + Math.atan2(0.0, 1.0).should be_close(0.0, TOLERANCE) + Math.atan2(-9.1, 3.2).should be_close(-1.23265379809025, TOLERANCE) + Math.atan2(7.22, -3.3).should be_close(1.99950888779256, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.atan2(1.0, "test") }.should raise_error(ArgumentError) + lambda { Math.atan2("test", 0.0) }.should raise_error(ArgumentError) + lambda { Math.atan2("test", "this") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.atan2(nil, 1.0) }.should raise_error(TypeError) + lambda { Math.atan2(-1.0, nil) }.should raise_error(TypeError) + lambda { Math.atan2(nil, nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.atan2(MathSpecs::Float.new, MathSpecs::Float.new).should be_close(0.785398163397448, TOLERANCE) + end +end + +describe "Math#atan2" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:atan2, 1.1, 2.2).should be_close(0.463647609000806, TOLERANCE) + end +end diff --git a/1.8/core/math/atan_spec.rb b/1.8/core/math/atan_spec.rb new file mode 100644 index 0000000000..17fc086e08 --- /dev/null +++ b/1.8/core/math/atan_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# arctangent : (-Inf, Inf) --> (-PI/2, PI/2) +describe "Math.atan" do + it "returns a float" do + Math.atan(1).class.should == Float + end + + it "return the arctangent of the argument" do + Math.atan(1).should be_close(Math::PI/4, TOLERANCE) + Math.atan(0).should be_close(0.0, TOLERANCE) + Math.atan(-1).should be_close(-Math::PI/4, TOLERANCE) + Math.atan(0.25).should be_close(0.244978663126864, TOLERANCE) + Math.atan(0.50).should be_close(0.463647609000806, TOLERANCE) + Math.atan(0.75).should be_close(0.643501108793284, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.atan("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.atan(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.atan(MathSpecs::Float.new).should be_close(0.785398163397448, TOLERANCE) + end +end + +describe "Math#atan" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:atan, 3.1415).should be_close(1.2626187313511, TOLERANCE) + end +end diff --git a/1.8/core/math/atanh_spec.rb b/1.8/core/math/atanh_spec.rb new file mode 100644 index 0000000000..52475d3948 --- /dev/null +++ b/1.8/core/math/atanh_spec.rb @@ -0,0 +1,58 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.atanh" do + it "returns a float" do + Math.atanh(0.5).class.should == Float + end + + it "returns the inverse hyperbolic tangent of the argument" do + Math.atanh(0.0).should == 0.0 + Math.atanh(-0.0).should == -0.0 + Math.atanh(0.5).should be_close(0.549306144334055, TOLERANCE) + Math.atanh(-0.2).should be_close(-0.202732554054082, TOLERANCE) + end + + platform_is :darwin, :freebsd do + it "returns Infinity for 1.0" do + Math.atanh(1.0).infinite?.should == 1 + end + + it "returns -Infinity for -1.0" do + Math.atanh(-1.0).infinite?.should == -1 + end + end + + platform_is :windows, :linux, :openbsd do + it "raises an Errno::EDOM if x = 1.0" do + lambda { Math.atanh(1.0) }.should raise_error(Errno::EDOM) + end + + it "raises an Errno::EDOM if x = -1.0" do + lambda { Math.atanh(-1.0) }.should raise_error(Errno::EDOM) + end + end + + it "raises an Errno::EDOM if x > 1.0" do + lambda { Math.atanh(1.0 + TOLERANCE) }.should raise_error(Errno::EDOM) + lambda { Math.atanh(-1.0 - TOLERANCE) }.should raise_error(Errno::EDOM) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.atanh("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.atanh(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.atanh(MathSpecs::Float.new(0.5)).infinite?.should == nil + end +end + +describe "Math#atanh" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:atanh, 0.1415).should be_close(0.14245589281616, TOLERANCE) + end +end diff --git a/1.8/core/math/constants_spec.rb b/1.8/core/math/constants_spec.rb new file mode 100644 index 0000000000..eef531a4f7 --- /dev/null +++ b/1.8/core/math/constants_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math::PI" do + it "approximates the value of pi" do + Math::PI.should be_close(3.14159_26535_89793_23846, TOLERANCE) + end + + it "is accessible to a class that includes Math" do + IncludesMath::PI.should == Math::PI + end +end + +describe "Math::E" do + it "approximates the value of Napier's constant" do + Math::E.should be_close(2.71828_18284_59045_23536, TOLERANCE) + end + + it "is accessible to a class that includes Math" do + IncludesMath::E.should == Math::E + end +end diff --git a/1.8/core/math/cos_spec.rb b/1.8/core/math/cos_spec.rb new file mode 100644 index 0000000000..579191df21 --- /dev/null +++ b/1.8/core/math/cos_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# cosine : (-Inf, Inf) --> (-1.0, 1.0) +describe "Math.cos" do + it "returns a float" do + Math.cos(Math::PI).class.should == Float + end + + it "returns the cosine of the argument expressed in radians" do + Math.cos(Math::PI).should be_close(-1.0, TOLERANCE) + Math.cos(0).should be_close(1.0, TOLERANCE) + Math.cos(Math::PI/2).should be_close(0.0, TOLERANCE) + Math.cos(3*Math::PI/2).should be_close(0.0, TOLERANCE) + Math.cos(2*Math::PI).should be_close(1.0, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.cos("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.cos(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.cos(MathSpecs::Float.new).should be_close(0.54030230586814, TOLERANCE) + end +end + +describe "Math#cos" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:cos, 3.1415).should be_close(-0.999999995707656, TOLERANCE) + end +end diff --git a/1.8/core/math/cosh_spec.rb b/1.8/core/math/cosh_spec.rb new file mode 100644 index 0000000000..f950cea303 --- /dev/null +++ b/1.8/core/math/cosh_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.cosh" do + it "returns a float" do + Math.cosh(1.0).class.should == Float + end + + it "returns the hyperbolic cosine of the argument" do + Math.cosh(0.0).should == 1.0 + Math.cosh(-0.0).should == 1.0 + Math.cosh(1.5).should be_close(2.35240961524325, TOLERANCE) + Math.cosh(-2.99).should be_close(9.96798496414416, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.cosh("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.cosh(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.cosh(MathSpecs::Float.new).should be_close(1.54308063481524, TOLERANCE) + end +end + +describe "Math#cosh" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:cos, 3.1415).should be_close(-0.999999995707656, TOLERANCE) + end +end diff --git a/1.8/core/math/erf_spec.rb b/1.8/core/math/erf_spec.rb new file mode 100644 index 0000000000..dcef38af38 --- /dev/null +++ b/1.8/core/math/erf_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# erf method is the "error function" encountered in integrating the normal +# distribution (which is a normalized form of the Gaussian function). +describe "Math.erf" do + it "returns a float" do + Math.erf(1).class.should == Float + end + + it "returns the error function of the argument" do + Math.erf(0).should be_close(0.0, TOLERANCE) + Math.erf(1).should be_close(0.842700792949715, TOLERANCE) + Math.erf(-1).should be_close(-0.842700792949715, TOLERANCE) + Math.erf(0.5).should be_close(0.520499877813047, TOLERANCE) + Math.erf(-0.5).should be_close(-0.520499877813047, TOLERANCE) + Math.erf(10000).should be_close(1.0, TOLERANCE) + Math.erf(-10000).should be_close(-1.0, TOLERANCE) + Math.erf(0.00000000000001).should be_close(0.0, TOLERANCE) + Math.erf(-0.00000000000001).should be_close(0.0, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.erf("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.erf(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.erf(MathSpecs::Float.new).should be_close(0.842700792949715, TOLERANCE) + end +end + +describe "Math#erf" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:erf, 3.1415).should be_close(0.999991118444483, TOLERANCE) + end +end diff --git a/1.8/core/math/erfc_spec.rb b/1.8/core/math/erfc_spec.rb new file mode 100644 index 0000000000..65ada95762 --- /dev/null +++ b/1.8/core/math/erfc_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# erfc is the complementary error function +describe "Math.erfc" do + it "returns a float" do + Math.erf(1).class.should == Float + end + + it "returns the complimentary error function of the argument" do + Math.erfc(0).should be_close(1.0, TOLERANCE) + Math.erfc(1).should be_close(0.157299207050285, TOLERANCE) + Math.erfc(-1).should be_close(1.84270079294971, TOLERANCE) + Math.erfc(0.5).should be_close(0.479500122186953, TOLERANCE) + Math.erfc(-0.5).should be_close(1.52049987781305, TOLERANCE) + Math.erfc(10000).should be_close(0.0, TOLERANCE) + Math.erfc(-10000).should be_close(2.0, TOLERANCE) + Math.erfc(0.00000000000001).should be_close(0.999999999999989, TOLERANCE) + Math.erfc(-0.00000000000001).should be_close(1.00000000000001, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.erfc("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.erfc(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.erfc(MathSpecs::Float.new).should be_close(0.157299207050285, TOLERANCE) + end +end + +describe "Math#erfc" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:erf, 3.1415).should be_close(0.999991118444483, TOLERANCE) + end +end diff --git a/1.8/core/math/exp_spec.rb b/1.8/core/math/exp_spec.rb new file mode 100644 index 0000000000..4bf3a3af61 --- /dev/null +++ b/1.8/core/math/exp_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.exp" do + it "returns a float" do + Math.exp(1.0).class.should == Float + end + + it "returns the base-e exponential of the argument" do + Math.exp(0.0).should == 1.0 + Math.exp(-0.0).should == 1.0 + Math.exp(-1.8).should be_close(0.165298888221587, TOLERANCE) + Math.exp(1.25).should be_close(3.49034295746184, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.exp("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.exp(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.exp(MathSpecs::Float.new).should be_close(Math::E, TOLERANCE) + end +end + +describe "Math#exp" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:exp, 23.1415).should be_close(11226018484.0012, TOLERANCE) + end +end diff --git a/1.8/core/math/fixtures/classes.rb b/1.8/core/math/fixtures/classes.rb new file mode 100644 index 0000000000..bd5cf12273 --- /dev/null +++ b/1.8/core/math/fixtures/classes.rb @@ -0,0 +1,21 @@ +class IncludesMath + include Math +end + +module MathSpecs + class Float + def initialize(value=1.0) + @value = value + end + + def to_f + @value + end + end + + class Integer + def to_int + 2 + end + end +end diff --git a/1.8/core/math/frexp_spec.rb b/1.8/core/math/frexp_spec.rb new file mode 100644 index 0000000000..52efa48816 --- /dev/null +++ b/1.8/core/math/frexp_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.frexp" do + it "returns the normalized fraction and exponent" do + frac, exp = Math.frexp(102.83) + frac.should be_close(0.803359375, TOLERANCE) + exp.should == 7 + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.frexp("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.frexp(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + frac, exp = Math.frexp(MathSpecs::Float.new) + frac.should be_close(0.5, TOLERANCE) + exp.should == 1 + end +end + +describe "Math#frexp" do + it "is accessible as a private instance method" do + frac, exp = IncludesMath.new.send(:frexp, 2.1415) + frac.should be_close(0.535375, TOLERANCE) + exp.should == 2 + end +end diff --git a/1.8/core/math/hypot_spec.rb b/1.8/core/math/hypot_spec.rb new file mode 100644 index 0000000000..eb1e54e4bf --- /dev/null +++ b/1.8/core/math/hypot_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.hypot" do + it "returns a float" do + Math.hypot(3, 4).class.should == Float + end + + it "returns the length of the hypotenuse of a right triangle with legs given by the arguments" do + Math.hypot(0, 0).should be_close(0.0, TOLERANCE) + Math.hypot(2, 10).should be_close( 10.1980390271856, TOLERANCE) + Math.hypot(5000, 5000).should be_close(7071.06781186548, TOLERANCE) + Math.hypot(0.0001, 0.0002).should be_close(0.000223606797749979, TOLERANCE) + Math.hypot(-2, -10).should be_close(10.1980390271856, TOLERANCE) + Math.hypot(2, 10).should be_close(10.1980390271856, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.hypot("test", "this") }.should raise_error(ArgumentError) + end + + it "raises a ArgumentError if the argument is nil" do + lambda { Math.hypot(nil) }.should raise_error(ArgumentError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.hypot(MathSpecs::Float.new, MathSpecs::Float.new).should be_close(1.4142135623731, TOLERANCE) + end +end + +describe "Math#hypot" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:hypot, 2, 3.1415).should be_close(3.72411361937307, TOLERANCE) + end +end diff --git a/1.8/core/math/ldexp_spec.rb b/1.8/core/math/ldexp_spec.rb new file mode 100644 index 0000000000..ed10f27489 --- /dev/null +++ b/1.8/core/math/ldexp_spec.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.ldexp" do + it "returns a float" do + Math.ldexp(1.0, 2).class.should == Float + end + + it "returns the argument multiplied by 2**n" do + Math.ldexp(0.0, 0.0).should == 0.0 + Math.ldexp(0.0, 1.0).should == 0.0 + Math.ldexp(-1.25, 2).should be_close(-5.0, TOLERANCE) + Math.ldexp(2.1, -3).should be_close(0.2625, TOLERANCE) + Math.ldexp(5.7, 4).should be_close(91.2, TOLERANCE) + end + + it "raises an ArgumentError if the first argument cannot be coerced with Float()" do + lambda { Math.ldexp("test", 2) }.should raise_error(ArgumentError) + end + + it "raises an TypeError if the second argument cannot be coerced with Integer()" do + lambda { Math.ldexp(3.2, "this") }.should raise_error(TypeError) + end + + it "raises a TypeError if the first argument is nil" do + lambda { Math.ldexp(nil, 2) }.should raise_error(TypeError) + end + + it "raises a TypeError if the second argument is nil" do + lambda { Math.ldexp(3.1, nil) }.should raise_error(TypeError) + end + + it "accepts any first argument that can be coerced with Float()" do + Math.ldexp(MathSpecs::Float.new, 2).should be_close(4.0, TOLERANCE) + end + + it "accepts any second argument that can be coerced with Integer()" do + Math.ldexp(3.23, MathSpecs::Integer.new).should be_close(12.92, TOLERANCE) + end +end + +describe "Math#ldexp" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:ldexp, 3.1415, 2).should be_close(12.566, TOLERANCE) + end +end diff --git a/1.8/core/math/log10_spec.rb b/1.8/core/math/log10_spec.rb new file mode 100644 index 0000000000..c0dfc104db --- /dev/null +++ b/1.8/core/math/log10_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# The common logarithm, having base 10 +describe "Math.log10" do + it "returns a float" do + Math.log10(1).class.should == Float + end + + it "return the base-10 logarithm of the argument" do + Math.log10(0.0001).should be_close(-4.0, TOLERANCE) + Math.log10(0.000000000001e-15).should be_close(-27.0, TOLERANCE) + Math.log10(1).should be_close(0.0, TOLERANCE) + Math.log10(10).should be_close(1.0, TOLERANCE) + Math.log10(10e15).should be_close(16.0, TOLERANCE) + end + + it "raises an Errno::EDOM if the argument is less than 0" do + lambda { Math.log10(-1e-15) }.should raise_error( Errno::EDOM) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.log10("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.log10(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.log10(MathSpecs::Float.new).should be_close(0.0, TOLERANCE) + end +end + +describe "Math#log10" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:log10, 4.15).should be_close(0.618048096712093, TOLERANCE) + end +end diff --git a/1.8/core/math/log2_spec.rb b/1.8/core/math/log2_spec.rb new file mode 100644 index 0000000000..6ad979879e --- /dev/null +++ b/1.8/core/math/log2_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/log2' + +extended_on :rubinius do + describe "Math.log2" do + it_behaves_like(:math_log2, :log2) + end +end + \ No newline at end of file diff --git a/1.8/core/math/log_spec.rb b/1.8/core/math/log_spec.rb new file mode 100644 index 0000000000..0daed1d722 --- /dev/null +++ b/1.8/core/math/log_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# The natural logarithm, having base Math::E +describe "Math.log" do + it "returns a float" do + Math.log(1).class.should == Float + end + + it "returns the natural logarithm of the argument" do + Math.log(0.0001).should be_close(-9.21034037197618, TOLERANCE) + Math.log(0.000000000001e-15).should be_close(-62.1697975108392, TOLERANCE) + Math.log(1).should be_close(0.0, TOLERANCE) + Math.log(10).should be_close( 2.30258509299405, TOLERANCE) + Math.log(10e15).should be_close(36.8413614879047, TOLERANCE) + end + + it "raises an Errno::EDOM if the argument is less than 0" do + lambda { Math.log(-1e-15) }.should raise_error(Errno::EDOM) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.log("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.log(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.log(MathSpecs::Float.new).should be_close(0.0, TOLERANCE) + end +end + +describe "Math#log" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:log, 5.21).should be_close(1.65057985576528, TOLERANCE) + end +end diff --git a/1.8/core/math/shared/log2.rb b/1.8/core/math/shared/log2.rb new file mode 100644 index 0000000000..f35fc8a184 --- /dev/null +++ b/1.8/core/math/shared/log2.rb @@ -0,0 +1,28 @@ +shared :math_log2 do + describe "Math.log2" do + it "returns a float" do + Math.log2(5.79).should be_close(2.53356334821451, TOLERANCE) + end + + it "returns the natural logarithm of the argument" do + Math.log2(1.1).should be_close(0.137503523749935, TOLERANCE) + Math.log2(3.14).should be_close(1.6507645591169, TOLERANCE) + end + + it "raises an Errno::EDOM if the argument is less than 0" do + lambda { Math.log2(-1e-15) }.should raise_error( Errno::EDOM) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.log2("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.log2(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.log2(MathSpecs::Float.new).should be_close(0.0, TOLERANCE) + end + end +end diff --git a/1.8/core/math/sin_spec.rb b/1.8/core/math/sin_spec.rb new file mode 100644 index 0000000000..7100b36dc7 --- /dev/null +++ b/1.8/core/math/sin_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# sine : (-Inf, Inf) --> (-1.0, 1.0) +describe "Math.sin" do + it "returns a float" do + Math.sin(Math::PI).class.should == Float + end + + it "returns the sine of the argument expressed in radians" do + Math.sin(Math::PI).should be_close(0.0, TOLERANCE) + Math.sin(0).should be_close(0.0, TOLERANCE) + Math.sin(Math::PI/2).should be_close(1.0, TOLERANCE) + Math.sin(3*Math::PI/2).should be_close(-1.0, TOLERANCE) + Math.sin(2*Math::PI).should be_close(0.0, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.sin("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.sin(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.sin(MathSpecs::Float.new).should be_close(0.841470984807897, TOLERANCE) + end +end + +describe "Math#sin" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:sin, 1.21).should be_close(0.935616001553386, TOLERANCE) + end +end diff --git a/1.8/core/math/sinh_spec.rb b/1.8/core/math/sinh_spec.rb new file mode 100644 index 0000000000..36d4665af6 --- /dev/null +++ b/1.8/core/math/sinh_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.sinh" do + it "returns a float" do + Math.sinh(1.2).class.should == Float + end + + it "returns the hyperbolic sin of the argument" do + Math.sinh(0.0).should == 0.0 + Math.sinh(-0.0).should == 0.0 + Math.sinh(1.5).should be_close(2.12927945509482, TOLERANCE) + Math.sinh(-2.8).should be_close(-8.19191835423591, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.sinh("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.sinh(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.sinh(MathSpecs::Float.new).should be_close(1.1752011936438, TOLERANCE) + end +end + +describe "Math#sinh" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:sinh, 1.99).should be_close(3.58941916843202, TOLERANCE) + end +end diff --git a/1.8/core/math/sqrt_spec.rb b/1.8/core/math/sqrt_spec.rb new file mode 100644 index 0000000000..1f7bbcdedf --- /dev/null +++ b/1.8/core/math/sqrt_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.sqrt" do + it "returns a float" do + Math.sqrt(1).class.should == Float + end + + it "returns the square root of the argument" do + Math.sqrt(1).should == 1.0 + Math.sqrt(4.0).should == 2.0 + Math.sqrt(15241578780673814.441547445).to_s.should == '123456789.123457' + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.sqrt("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.sqrt(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.sqrt(MathSpecs::Float.new).should be_close(1.0, TOLERANCE) + end +end + +describe "Math#sqrt" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:sqrt, 2.23).should be_close(1.49331845230681, TOLERANCE) + end +end diff --git a/1.8/core/math/tan_spec.rb b/1.8/core/math/tan_spec.rb new file mode 100644 index 0000000000..be6de37f43 --- /dev/null +++ b/1.8/core/math/tan_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.tan" do + it "returns a float" do + Math.tan(1.35).class.should == Float + end + + it "returns the tangent of the argument" do + Math.tan(0.0).should == 0.0 + Math.tan(-0.0).should == -0.0 + Math.tan(4.22).should be_close(1.86406937682395, TOLERANCE) + Math.tan(-9.65).should be_close(-0.229109052606441, TOLERANCE) + end + + it "returns NaN if called with +-Infinitty" do + Math.tan(1.0/0.0).nan?.should == true + Math.tan(1.0/-0.0).nan?.should == true + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.tan("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.tan(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.tan(MathSpecs::Float.new).should be_close(1.5574077246549, TOLERANCE) + end +end + +describe "Math#tan" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:tan, 1.0).should be_close(1.5574077246549, TOLERANCE) + end +end diff --git a/1.8/core/math/tanh_spec.rb b/1.8/core/math/tanh_spec.rb new file mode 100644 index 0000000000..1388a7153c --- /dev/null +++ b/1.8/core/math/tanh_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Math.tanh" do + it "returns a float" do + Math.tanh(0.5).class.should == Float + end + + it "returns the hyperbolic tangent of the argument" do + Math.tanh(0.0).should == 0.0 + Math.tanh(-0.0).should == -0.0 + Math.tanh(1.0/0.0).should == 1.0 + Math.tanh(1.0/-0.0).should == -1.0 + Math.tanh(2.5).should be_close(0.98661429815143, TOLERANCE) + Math.tanh(-4.892).should be_close(-0.999887314427707, TOLERANCE) + end + + it "raises an ArgumentError if the argument cannot be coerced with Float()" do + lambda { Math.tanh("test") }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the argument is nil" do + lambda { Math.tanh(nil) }.should raise_error(TypeError) + end + + it "accepts any argument that can be coerced with Float()" do + Math.tanh(MathSpecs::Float.new).should be_close(0.761594155955765, TOLERANCE) + end +end + +describe "Math#tanh" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:tanh, 5.21).should be_close(0.99994034202065, TOLERANCE) + end +end diff --git a/1.8/core/method/arity_spec.rb b/1.8/core/method/arity_spec.rb new file mode 100644 index 0000000000..758c75c246 --- /dev/null +++ b/1.8/core/method/arity_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Method#arity" do + before(:each) do + @m = MethodSpecs::Methods.new + end + + it "returns n, where n is the number of required arguments, when there are zero or more required arguments only" do + @m.method(:zero).arity.should == 0 + @m.method(:one_req).arity.should == 1 + @m.method(:two_req).arity.should == 2 + end + + it "returns -(n+1), where n is the number of required arguments, when there is at least one optional argument" do + @m.method(:one_opt).arity.should == -1 + @m.method(:one_req_one_opt).arity.should == -2 + @m.method(:one_req_two_opt).arity.should == -2 + @m.method(:two_req_one_opt).arity.should == -3 + end + + it "returns -(n+1), where n is the number of required arguments, when there is a splat argument, regardless of optional arguments" do + @m.method(:zero_with_splat).arity.should == -1 + @m.method(:one_req_with_splat).arity.should == -2 + @m.method(:one_req_one_opt_with_splat).arity.should == -2 + @m.method(:one_req_two_opt_with_splat).arity.should == -2 + @m.method(:two_req_with_splat).arity.should == -3 + @m.method(:two_req_one_opt_with_splat).arity.should == -3 + end + + it "returns the same value regardless of the presence of a block" do + @m.method(:zero_with_block).arity.should == @m.method(:zero).arity + @m.method(:one_req_with_block).arity.should == @m.method(:one_req).arity + @m.method(:two_req_with_block).arity.should == @m.method(:two_req).arity + + @m.method(:one_opt_with_block).arity.should == @m.method(:one_opt).arity + @m.method(:one_req_one_opt_with_block).arity.should == @m.method(:one_req_one_opt).arity + @m.method(:one_req_two_opt_with_block).arity.should == @m.method(:one_req_two_opt).arity + @m.method(:two_req_one_opt_with_block).arity.should == @m.method(:two_req_one_opt).arity + + @m.method(:zero_with_splat_and_block).arity.should == @m.method(:zero_with_splat).arity + @m.method(:one_req_with_splat_and_block).arity.should == @m.method(:one_req_with_splat).arity + @m.method(:one_req_one_opt_with_splat_and_block).arity.should == @m.method(:one_req_one_opt_with_splat).arity + @m.method(:one_req_two_opt_with_splat_and_block).arity.should == @m.method(:one_req_two_opt_with_splat).arity + @m.method(:two_req_with_splat_and_block).arity.should == @m.method(:two_req_with_splat).arity + @m.method(:two_req_one_opt_with_splat_and_block).arity.should == @m.method(:two_req_one_opt_with_splat).arity + end +end diff --git a/1.8/core/method/call_spec.rb b/1.8/core/method/call_spec.rb new file mode 100644 index 0000000000..1012877124 --- /dev/null +++ b/1.8/core/method/call_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/call' + +describe "Method#call" do + it_behaves_like(:method_call, :call) +end diff --git a/1.8/core/method/clone_spec.rb b/1.8/core/method/clone_spec.rb new file mode 100644 index 0000000000..2642c36ef4 --- /dev/null +++ b/1.8/core/method/clone_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Method#clone" do + it "returns a copy of the method" do + m1 = MethodSpecs::Methods.new.method(:foo) + m2 = m1.clone + + (m1 == m2).should == true + m1.eql?(m2).should == false + + m1.call.should == m2.call + end +end diff --git a/1.8/core/method/element_reference_spec.rb b/1.8/core/method/element_reference_spec.rb new file mode 100644 index 0000000000..176abffc6e --- /dev/null +++ b/1.8/core/method/element_reference_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/call' + +describe "Method#[]" do + it_behaves_like(:method_call, :[]) +end diff --git a/1.8/core/method/equal_value_spec.rb b/1.8/core/method/equal_value_spec.rb new file mode 100644 index 0000000000..39bde4b239 --- /dev/null +++ b/1.8/core/method/equal_value_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Method#==" do + before(:each) do + @m = MethodSpecs::Methods.new + @m2 = MethodSpecs::Methods.new + @a = MethodSpecs::A.new + end + + it "returns true if methods are the same" do + m1 = @m.method(:foo) + m2 = @m.method(:foo) + + (m1 == m1).should == true + (m1 == m2).should == true + end + + it "returns true on aliased methods" do + m1 = @m.method(:foo) + m2 = @m.method(:bar) + + (m1 == m2).should == true + end + + it "returns false on a method which is neither aliases nor the same method" do + m1 = @m.method(:foo) + m2 = @m.method(:zero) + + (m1 == m2).should == false + end + + it "returns false for a method which is not bound to the same object" do + m1 = @m.method(:foo) + m2 = @m2.method(:foo) + + a = @a.method(:baz) + + (m1 == m2).should == false + (m1 == a).should == false + (m2 == a).should == false + end +end diff --git a/1.8/core/method/fixtures/classes.rb b/1.8/core/method/fixtures/classes.rb new file mode 100644 index 0000000000..5b78bb77ce --- /dev/null +++ b/1.8/core/method/fixtures/classes.rb @@ -0,0 +1,66 @@ +module MethodSpecs + class Methods + def foo + true + end + alias bar foo + + def zero; end + def one_req(a); end + def two_req(a, b); end + + def zero_with_block(&block); end + def one_req_with_block(a, &block); end + def two_req_with_block(a, b, &block); end + + def one_opt(a=nil); end + def one_req_one_opt(a, b=nil); end + def one_req_two_opt(a, b=nil, c=nil); end + def two_req_one_opt(a, b, c=nil); end + + def one_opt_with_block(a=nil, &block); end + def one_req_one_opt_with_block(a, b=nil, &block); end + def one_req_two_opt_with_block(a, b=nil, c=nil, &block); end + def two_req_one_opt_with_block(a, b, c=nil, &block); end + + def zero_with_splat(*a); end + def one_req_with_splat(a, *b); end + def two_req_with_splat(a, b, *c); end + def one_req_one_opt_with_splat(a, b=nil, *c); end + def two_req_one_opt_with_splat(a, b, c=nil, *d); end + def one_req_two_opt_with_splat(a, b=nil, c=nil, *d); end + + def zero_with_splat_and_block(*a, &block); end + def one_req_with_splat_and_block(a, *b, &block); end + def two_req_with_splat_and_block(a, b, *c, &block); end + def one_req_one_opt_with_splat_and_block(a, b=nil, *c, &block); end + def two_req_one_opt_with_splat_and_block(a, b, c=nil, *d, &block); end + def one_req_two_opt_with_splat_and_block(a, b=nil, c=nil, *d, &block); end + end + + module MyMod + def bar; :bar; end + end + + class MySuper + include MyMod + end + + class MySub < MySuper; end + + class A + def baz(a, b) + self.class + end + end + + class B < A + end + + class C < B + end + + class D + def bar() 'done' end + end +end diff --git a/1.8/core/method/inspect_spec.rb b/1.8/core/method/inspect_spec.rb new file mode 100644 index 0000000000..ce3164c7bd --- /dev/null +++ b/1.8/core/method/inspect_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_s' + +describe "Method#inspect" do + it_behaves_like(:method_to_s, :inspect) +end diff --git a/1.8/core/method/shared/call.rb b/1.8/core/method/shared/call.rb new file mode 100644 index 0000000000..8eccbbb347 --- /dev/null +++ b/1.8/core/method/shared/call.rb @@ -0,0 +1,18 @@ +shared :method_call do |cmd| + describe "Method##{cmd}" do + it "invokes the method with the specified arguments, returning the method's return value" do + m = 12.method("+") + m.send(cmd, 3).should == 15 + m.send(cmd, 20).should == 32 + end + + it "raises an ArgumentError when given incorrect number of arguments" do + lambda { + MethodSpecs::Methods.new.method(:two_req).send(cmd, 1, 2, 3) + }.should raise_error(ArgumentError) + lambda { + MethodSpecs::Methods.new.method(:two_req).send(cmd, 1) + }.should raise_error(ArgumentError) + end + end +end diff --git a/1.8/core/method/shared/to_s.rb b/1.8/core/method/shared/to_s.rb new file mode 100644 index 0000000000..dd2c8536b8 --- /dev/null +++ b/1.8/core/method/shared/to_s.rb @@ -0,0 +1,29 @@ +require "#{File.dirname __FILE__}/../../../spec_helper" +require "#{File.dirname __FILE__}/../fixtures/classes" + +shared :method_to_s do |cmd| + describe "Method##{cmd}" do + before :each do + @method = MethodSpecs::MySub.new.method :bar + end + + it "returns a String" do + @method.send(cmd).class.should == String + end + + it "the String reflects that this is a Method object" do + @method.send(cmd).should =~ /\bMethod\b/ + end + + it "the String shows the method name, Module defined in and Module extracted from" do + name = @method.send(cmd).sub(/0x\w+/, '0xXXXXXX') + + deviates_on(:rubinius) do + name.should == "#" + end + deviates_on(:ruby) do + name.should == "#" + end + end + end +end diff --git a/1.8/core/method/to_proc_spec.rb b/1.8/core/method/to_proc_spec.rb new file mode 100644 index 0000000000..e968ff74bb --- /dev/null +++ b/1.8/core/method/to_proc_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Method#to_proc" do + before(:each) do + @m = MethodSpecs::Methods.new + @meth = @m.method(:foo) + end + + it "returns a Proc object corresponding to the method" do + @meth.to_proc.kind_of?(Proc).should == true + end + + it "Proc object should have the correct arity" do + # This may seem redundant but this bug has cropped up in jruby, mri and yarv. + # http://jira.codehaus.org/browse/JRUBY-124 + [ :zero, :one_req, :two_req, + :zero_with_block, :one_req_with_block, :two_req_with_block, + :one_opt, :one_req_one_opt, :one_req_two_opt, :two_req_one_opt, + :one_opt_with_block, :one_req_one_opt_with_block, :one_req_two_opt_with_block, :two_req_one_opt_with_block, + :zero_with_splat, :one_req_with_splat, :two_req_with_splat, + :one_req_one_opt_with_splat, :one_req_two_opt_with_splat, :two_req_one_opt_with_splat, + :zero_with_splat_and_block, :one_req_with_splat_and_block, :two_req_with_splat_and_block, + :one_req_one_opt_with_splat_and_block, :one_req_two_opt_with_splat_and_block, :two_req_one_opt_with_splat_and_block + ].each do |m| + @m.method(m).to_proc.arity.should == @m.method(m).arity + end + end + + it "returns a proc that can be used by define_method" do + x = 'test' + to_s = class << x + define_method :foo, method(:to_s).to_proc + to_s + end + + x.foo.should == to_s + end +end diff --git a/1.8/core/method/to_s_spec.rb b/1.8/core/method/to_s_spec.rb new file mode 100644 index 0000000000..cd9f1b12a7 --- /dev/null +++ b/1.8/core/method/to_s_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_s' + +describe "Method#to_s" do + it_behaves_like(:method_to_s, :to_s) +end diff --git a/1.8/core/method/unbind_spec.rb b/1.8/core/method/unbind_spec.rb new file mode 100644 index 0000000000..c7b9f89f1c --- /dev/null +++ b/1.8/core/method/unbind_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Method#unbind" do + before(:each) do + @normal = MethodSpecs::Methods.new + @normal_m = @normal.method :foo + @normal_um = @normal_m.unbind + @pop_um = MethodSpecs::MySub.new.method(:bar).unbind + end + + it "returns an UnboundMethod" do + @normal_um.class.should == UnboundMethod + end + + it "gives UnboundMethod method name, Module defined in and Module extracted from" do + name = @pop_um.inspect.sub(/0x\w+/, '0xXXXXXX') + deviates_on(:rubinius) do + name.should == "#" + end + deviates_on(:ruby) do + name.should == "#" + end + end + + specify "rebinding UnboundMethod to Method's obj produces exactly equivalent Methods" do + @normal_um.bind(@normal).should == @normal_m + @normal_m.should == @normal_um.bind(@normal) + end +end diff --git a/1.8/core/module/alias_method_spec.rb b/1.8/core/module/alias_method_spec.rb new file mode 100644 index 0000000000..53d79db3a7 --- /dev/null +++ b/1.8/core/module/alias_method_spec.rb @@ -0,0 +1,61 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#alias_method" do + before(:each) do + @class = Class.new(ModuleSpecs::Aliasing) + @object = @class.new + end + + it "makes a copy of the method" do + @class.make_alias :uno, :public_one + @class.make_alias :double, :public_two + @object.uno.should == @object.public_one + @object.double(12).should == @object.public_two(12) + end + + it "retains method visibility" do + @class.make_alias :private_ichi, :private_one + lambda { @object.private_one }.should raise_error(NameError) + lambda { @object.private_ichi }.should raise_error(NameError) + @class.make_alias :public_ichi, :public_one + @object.public_ichi.should == @object.public_one + @class.make_alias :protected_ichi, :protected_one + lambda { @object.protected_ichi }.should raise_error(NameError) + end + + it "fails if origin method not found" do + lambda { @class.make_alias :ni, :san }.should raise_error(NameError) + end + + it "converts a non string/symbol/fixnum name to string using to_str" do + @class.make_alias "un", "public_one" + @class.make_alias :deux, "public_one" + @class.make_alias "trois", :public_one + @class.make_alias :quatre, :public_one + name = mock('cinq') + name.should_receive(:to_str).any_number_of_times.and_return("cinq") + @class.make_alias name, "public_one" + @class.make_alias "cinq", name + end + + it "raises a TypeError when the given name can't be converted using to_str" do + lambda { @class.make_alias mock('x'), :public_one }.should raise_error(TypeError) + end + + it "is a private method" do + lambda { @class.alias_method :ichi, :public_one }.should raise_error(NoMethodError) + end + + it "works in module" do + module Exception2MessageMapper + alias fail! fail + end + end + + it "works on private module methods in a module that has been reopened" do + ModuleSpecs::ReopeningModule.foo.should == true + lambda { ModuleSpecs::ReopeningModule.foo2 }.should_not raise_error(NoMethodError) + end + +end diff --git a/1.8/core/module/allocate_spec.rb b/1.8/core/module/allocate_spec.rb new file mode 100644 index 0000000000..54dc1e3211 --- /dev/null +++ b/1.8/core/module/allocate_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Module.allocate" do + it "returns an instance of Module" do + mod = Module.allocate + mod.should be_kind_of(Module) + end + + it "returns a fully-formed instance of Module" do + mod = Module.allocate + mod.constants.should_not == nil + mod.methods.should_not == nil + end +end diff --git a/1.8/core/module/ancestors_spec.rb b/1.8/core/module/ancestors_spec.rb new file mode 100644 index 0000000000..c2caec958a --- /dev/null +++ b/1.8/core/module/ancestors_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#ancestors" do + it "returns a list of modules included in self (including self)" do + ModuleSpecs.ancestors.should include(ModuleSpecs) + ModuleSpecs::Basic.ancestors.should include(ModuleSpecs::Basic) + ModuleSpecs::Super.ancestors.should include(ModuleSpecs::Super, ModuleSpecs::Basic) + ModuleSpecs::Parent.ancestors.should include(ModuleSpecs::Parent, Object, Kernel) + ModuleSpecs::Child.ancestors.should include(ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Kernel) + end + + it "returns only modules and classes" do + class << ModuleSpecs::Child; self; end.ancestors.should include(ModuleSpecs::Internal, Class, Module, Object, Kernel) + end +end diff --git a/1.8/core/module/append_features_spec.rb b/1.8/core/module/append_features_spec.rb new file mode 100644 index 0000000000..67bfa57f02 --- /dev/null +++ b/1.8/core/module/append_features_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#append_features" do + it "gets called when self is included in another module/class" do + begin + m = Module.new do + def self.append_features(mod) + $appended_to = mod + end + end + + c = Class.new do + include m + end + + $appended_to.should == c + ensure + $appended_to = nil + end + end +end diff --git a/1.8/core/module/attr_accessor_spec.rb b/1.8/core/module/attr_accessor_spec.rb new file mode 100644 index 0000000000..82014c26d3 --- /dev/null +++ b/1.8/core/module/attr_accessor_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#attr_accessor" do + it "creates a getter and setter for each given attribute name" do + c = Class.new do + attr_accessor :a, "b" + end + + o = c.new + + ['a','b'].each do |x| + o.respond_to?(x).should == true + o.respond_to?("#{x}=").should == true + end + + o.a = "a" + o.a.should == "a" + + o.b = "b" + o.b.should == "b" + end + + it "converts non string/symbol/fixnum names to strings using to_str" do + (o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test") + c = Class.new do + attr_accessor o + end + + c.new.respond_to?("test").should == true + c.new.respond_to?("test=").should == true + end + + it "raises a TypeError when the given names can't be converted to strings using to_str" do + o = mock('o') + lambda { Class.new { attr_accessor o } }.should raise_error(TypeError) + (o = mock('123')).should_receive(:to_str).and_return(123) + lambda { Class.new { attr_accessor o } }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/attr_reader_spec.rb b/1.8/core/module/attr_reader_spec.rb new file mode 100644 index 0000000000..beec35b4b6 --- /dev/null +++ b/1.8/core/module/attr_reader_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#attr_reader" do + it "creates a getter for each given attribute name" do + c = Class.new do + attr_reader :a, "b" + + def initialize + @a = "test" + @b = "test2" + end + end + + o = c.new + %w{a b}.each do |x| + o.respond_to?(x).should == true + o.respond_to?("#{x}=").should == false + end + + o.a.should == "test" + o.b.should == "test2" + end + + it "converts non string/symbol/fixnum names to strings using to_str" do + (o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test") + c = Class.new do + attr_reader o + end + + c.new.respond_to?("test").should == true + c.new.respond_to?("test=").should == false + end + + it "raises a TypeError when the given names can't be converted to strings using to_str" do + o = mock('o') + lambda { Class.new { attr_reader o } }.should raise_error(TypeError) + (o = mock('123')).should_receive(:to_str).and_return(123) + lambda { Class.new { attr_reader o } }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/attr_spec.rb b/1.8/core/module/attr_spec.rb new file mode 100644 index 0000000000..bc2e4b0bb9 --- /dev/null +++ b/1.8/core/module/attr_spec.rb @@ -0,0 +1,87 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#attr" do + it "creates a getter for the given attribute name" do + c = Class.new do + attr :attr + attr "attr3" + + def initialize + @attr, @attr2, @attr3 = "test", "test2", "test3" + end + end + + o = c.new + + %w{attr attr3}.each do |a| + o.respond_to?(a).should == true + o.respond_to?("#{a}=").should == false + end + + o.attr.should == "test" + o.attr3.should == "test3" + end + + it "creates a setter for the given attribute name if writable is true" do + c = Class.new do + attr :attr, true + attr "attr3", true + + def initialize + @attr, @attr2, @attr3 = "test", "test2", "test3" + end + end + + o = c.new + + %w{attr attr3}.each do |a| + o.respond_to?(a).should == true + o.respond_to?("#{a}=").should == true + end + + o.attr = "test updated" + o.attr3 = "test3 updated" + end + + it "creates a getter and setter for the given attribute name if called with and without writeable is true" do + c = Class.new do + attr :attr, true + attr :attr + + attr "attr3", true + attr "attr3" + + def initialize + @attr, @attr2, @attr3 = "test", "test2", "test3" + end + end + + o = c.new + + %w{attr attr3}.each do |a| + o.respond_to?(a).should == true + o.respond_to?("#{a}=").should == true + end + + o.attr.should == "test" + o.attr = "test updated" + o.attr.should == "test updated" + + o.attr3.should == "test3" + o.attr3 = "test3 updated" + o.attr3.should == "test3 updated" + end + + it "converts non string/symbol/fixnum names to strings using to_str" do + (o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test") + Class.new { attr o }.new.respond_to?("test").should == true + end + + it "raises a TypeError when the given names can't be converted to strings using to_str" do + o = mock('o') + lambda { Class.new { attr o } }.should raise_error(TypeError) + (o = mock('123')).should_receive(:to_str).and_return(123) + lambda { Class.new { attr o } }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/attr_writer_spec.rb b/1.8/core/module/attr_writer_spec.rb new file mode 100644 index 0000000000..9157178589 --- /dev/null +++ b/1.8/core/module/attr_writer_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#attr_writer" do + it "creates a setter for each given attribute name" do + c = Class.new do + attr_writer :test1, "test2" + end + o = c.new + + o.respond_to?("test1").should == false + o.respond_to?("test2").should == false + + o.respond_to?("test1=").should == true + o.test1 = "test_1" + o.instance_variable_get(:@test1).should == "test_1" + + o.respond_to?("test2=").should == true + o.test2 = "test_2" + o.instance_variable_get(:@test2).should == "test_2" + end + + not_compliant_on :rubinius do + it "creates a setter for an attribute name given as a Fixnum" do + c = Class.new do + attr_writer :test1.to_i + end + + o = c.new + o.respond_to?("test1").should == false + o.respond_to?("test1=").should == true + + o.test1 = "test_1" + o.instance_variable_get(:@test1).should == "test_1" + end + end + + it "converts non string/symbol/fixnum names to strings using to_str" do + (o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test") + c = Class.new do + attr_writer o + end + + c.new.respond_to?("test").should == false + c.new.respond_to?("test=").should == true + end + + it "raises a TypeError when the given names can't be converted to strings using to_str" do + o = mock('test1') + lambda { Class.new { attr_writer o } }.should raise_error(TypeError) + (o = mock('123')).should_receive(:to_str).and_return(123) + lambda { Class.new { attr_writer o } }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/autoload_spec.rb b/1.8/core/module/autoload_spec.rb new file mode 100644 index 0000000000..947b526a43 --- /dev/null +++ b/1.8/core/module/autoload_spec.rb @@ -0,0 +1,95 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#autoload" do + it "registers the given filename to be loaded the first time that the Module with the given name is accessed" do + begin + $m = Module.new { autoload(:AAA, File.dirname(__FILE__) + "/fixtures/autoload.rb") } + + # $m::AAA is set in module_spec.autoload.rb + $m.const_get(:AAA).should == "test" + + # I know this is bad... + $m = Module.new { autoload(:AAA, File.dirname(__FILE__) + "/../module/fixtures/autoload.rb") } + $m.const_get(:AAA).should == "test" + + # And this is no better... + $m = Module.new { autoload(:AAA, File.dirname(__FILE__) + "/../module/../module/fixtures/autoload.rb") } + $m.const_get(:AAA).should == "test" + ensure + $m = nil + end + end + + it "does not autoload when the specified constant was already set" do + begin + $m = Module.new { autoload(:AAA, File.dirname(__FILE__) + "/../core/../core/../core/fixtures/autoload.rb") } + $m.const_set(:AAA, "testing!") + $m.const_get(:AAA).should == "testing!" + ensure + $m = nil + end + end + + it "raises a NameError when an invalid constant name is given" do + lambda { + Module.new { autoload("no_constant", File.dirname(__FILE__) + "/fixtures/autoload.rb") } + }.should raise_error(NameError) + + lambda { + Module.new { autoload("123invalid", File.dirname(__FILE__) + "/fixtures/autoload.rb") } + }.should raise_error(NameError) + + lambda { + Module.new { autoload("This One is invalid, too!", File.dirname(__FILE__) + "/fixtures/autoload.rb") } + }.should raise_error(NameError) + end + + it "raises an ArgumentError when an empty filename is given" do + lambda { Module.new { autoload("A", "") } }.should raise_error(ArgumentError) + end + + it "loads constants that are registered at toplevel" do + ModuleSpecAutoloadToplevel.message.should == "success" + end + + it "triggers an autoload before using a toplevel constant" do + class ModuleSpecs::AutoLoadParent + autoload(:AutoLoadSubject, File.dirname(__FILE__) + "/fixtures/autoload_nested.rb") + end + + class ModuleSpecs::AutoLoadChild < ModuleSpecs::AutoLoadParent + ModuleSpecs::AutoLoadParent::AutoLoadSubject.message.should == "success" + end + end + + it "should not fail when the load path is manually required" do + module ModuleSpecs::AutoloadRequire + fixture = File.dirname(__FILE__) + "/fixtures/autoload_require.rb" + + autoload(:ModuleSpecAutoloadRequire, fixture) + require fixture + end + + ModuleSpecs::AutoloadRequire::ModuleSpecAutoloadRequire.hello.should == "Hello, World!" + end + + it "should correctly match paths with and without ruby file extensions" do + module ModuleSpecs::AutoloadExtension + with_rb = File.dirname(__FILE__) + "/fixtures/autoload_extension.rb" + without_rb = with_rb[0..-4] + + autoload(:Constant, without_rb) + require with_rb + end + ModuleSpecs::AutoloadExtension::Constant.message.should == "success" + end +end + +describe "Module#autoload?" do + it "returns the name of the file that will be autoloaded" do + m = Module.new { autoload :AAA, "module_a" } + m.autoload?(:AAA).should == "module_a" + m.autoload?(:B).should == nil + end +end diff --git a/1.8/core/module/case_compare_spec.rb b/1.8/core/module/case_compare_spec.rb new file mode 100644 index 0000000000..dc6973b37e --- /dev/null +++ b/1.8/core/module/case_compare_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#===" do + it "returns true when the given Object is an instance of self or of self's descendants" do + (ModuleSpecs::Child === ModuleSpecs::Child.new).should == true + (ModuleSpecs::Parent === ModuleSpecs::Parent.new).should == true + + (ModuleSpecs::Parent === ModuleSpecs::Child.new).should == true + (Object === ModuleSpecs::Child.new).should == true + + (ModuleSpecs::Child === String.new).should == false + (ModuleSpecs::Child === mock('x')).should == false + end + + it "returns true when the given Object's class includes self or when the given Object is extended by self" do + (ModuleSpecs::Basic === ModuleSpecs::Child.new).should == true + (ModuleSpecs::Super === ModuleSpecs::Child.new).should == true + (ModuleSpecs::Basic === mock('x').extend(ModuleSpecs::Super)).should == true + (ModuleSpecs::Super === mock('y').extend(ModuleSpecs::Super)).should == true + + (ModuleSpecs::Basic === ModuleSpecs::Parent.new).should == false + (ModuleSpecs::Super === ModuleSpecs::Parent.new).should == false + (ModuleSpecs::Basic === mock('z')).should == false + (ModuleSpecs::Super === mock('a')).should == false + end +end diff --git a/1.8/core/module/class_eval_spec.rb b/1.8/core/module/class_eval_spec.rb new file mode 100644 index 0000000000..04bf1f612b --- /dev/null +++ b/1.8/core/module/class_eval_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/class_eval' + +describe "Module#class_eval" do + it_behaves_like :module_class_eval, :class_eval +end diff --git a/1.8/core/module/class_variable_defined_spec.rb b/1.8/core/module/class_variable_defined_spec.rb new file mode 100644 index 0000000000..8aedd5d89f --- /dev/null +++ b/1.8/core/module/class_variable_defined_spec.rb @@ -0,0 +1,67 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#class_variable_defined?" do + it "returns true if a class variable with the given name is defined in self" do + c = Class.new { class_variable_set :@@class_var, "test" } + c.class_variable_defined?(:@@class_var).should == true + c.class_variable_defined?("@@class_var").should == true + c.class_variable_defined?(:@@no_class_var).should == false + c.class_variable_defined?("@@no_class_var").should == false + ModuleSpecs::CVars.class_variable_defined?("@@cls").should == true + end + + it "returns true if a class variable with the given name is defined in the metaclass" do + ModuleSpecs::CVars.class_variable_defined?("@@meta").should == true + end + + it "returns true if a class variables with the given name is defined in an included module" do + c = Class.new { include ModuleSpecs::MVars } + c.class_variable_defined?("@@mvar").should == true + end + + it "returns false if a class variables with the given name is defined in an extended module" do + c = Class.new + c.extend ModuleSpecs::MVars + c.class_variable_defined?("@@mvar").should == false + end + + not_compliant_on :rubinius do + it "accepts Fixnums for class variables" do + c = Class.new { class_variable_set :@@class_var, "test" } + c.class_variable_defined?(:@@class_var.to_i).should == true + c.class_variable_defined?(:@@no_class_var.to_i).should == false + end + end + + it "raises a NameError when the given name is not allowed" do + c = Class.new + + lambda { + c.class_variable_defined?(:invalid_name) + }.should raise_error(NameError) + + lambda { + c.class_variable_defined?("@invalid_name") + }.should raise_error(NameError) + end + + it "converts a non string/symbol/fixnum name to string using to_str" do + c = Class.new { class_variable_set :@@class_var, "test" } + (o = mock('@@class_var')).should_receive(:to_str).and_return("@@class_var") + c.class_variable_defined?(o).should == true + end + + it "raises a TypeError when the given names can't be converted to strings using to_str" do + c = Class.new { class_variable_set :@@class_var, "test" } + o = mock('123') + lambda { + c.class_variable_defined?(o) + }.should raise_error(TypeError) + + o.should_receive(:to_str).and_return(123) + lambda { + c.class_variable_defined?(o) + }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/class_variable_get_spec.rb b/1.8/core/module/class_variable_get_spec.rb new file mode 100644 index 0000000000..3678addc5a --- /dev/null +++ b/1.8/core/module/class_variable_get_spec.rb @@ -0,0 +1,77 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#class_variable_get" do + it "returns the value of the class variable with the given name" do + c = Class.new { class_variable_set :@@class_var, "test" } + c.send(:class_variable_get, :@@class_var).should == "test" + c.send(:class_variable_get, "@@class_var").should == "test" + end + + it "returns the value of a class variable with the given name defined in an included module" do + c = Class.new { include ModuleSpecs::MVars } + c.send(:class_variable_get, "@@mvar").should == :mvar + end + + it "raises a NameError for a class variables with the given name defined in an extended module" do + c = Class.new + c.extend ModuleSpecs::MVars + lambda { + c.send(:class_variable_get, "@@mvar") + }.should raise_error(NameError) + end + + it "returns class variables defined in the class body and accessed in the metaclass" do + ModuleSpecs::CVars.cls.should == :class + end + + it "returns class variables defined in the metaclass and accessed by class methods" do + ModuleSpecs::CVars.meta.should == :meta + end + + it "returns class variables defined in the metaclass and accessed by instance methods" do + ModuleSpecs::CVars.new.meta.should == :meta + end + + not_compliant_on :rubinius do + it "accepts Fixnums for class variables" do + c = Class.new { class_variable_set :@@class_var, "test" } + c.send(:class_variable_get, :@@class_var.to_i).should == "test" + end + + it "raises a NameError when a Fixnum for an uninitialized class variable is given" do + c = Class.new + lambda { + c.send :class_variable_get, :@@no_class_var.to_i + }.should raise_error(NameError) + end + end + + it "raises a NameError when an uninitialized class variable is accessed" do + c = Class.new + [:@@no_class_var, "@@no_class_var"].each do |cvar| + lambda { c.send(:class_variable_get, cvar) }.should raise_error(NameError) + end + end + + it "raises a NameError when the given name is not allowed" do + c = Class.new + + lambda { c.send(:class_variable_get, :invalid_name) }.should raise_error(NameError) + lambda { c.send(:class_variable_get, "@invalid_name") }.should raise_error(NameError) + end + + it "converts a non string/symbol/fixnum name to string using to_str" do + c = Class.new { class_variable_set :@@class_var, "test" } + (o = mock('@@class_var')).should_receive(:to_str).and_return("@@class_var") + c.send(:class_variable_get, o).should == "test" + end + + it "raises a TypeError when the given names can't be converted to strings using to_str" do + c = Class.new { class_variable_set :@@class_var, "test" } + o = mock('123') + lambda { c.send(:class_variable_get, o) }.should raise_error(TypeError) + o.should_receive(:to_str).and_return(123) + lambda { c.send(:class_variable_get, o) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/class_variable_set_spec.rb b/1.8/core/module/class_variable_set_spec.rb new file mode 100644 index 0000000000..7d6bc659e1 --- /dev/null +++ b/1.8/core/module/class_variable_set_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#class_variable_set" do + it "sets the class variable with the given name to the given value" do + c = Class.new + + c.send(:class_variable_set, :@@test, "test") + c.send(:class_variable_set, "@@test3", "test3") + + c.send(:class_variable_get, :@@test).should == "test" + c.send(:class_variable_get, :@@test3).should == "test3" + end + + it "sets the value of a class variable with the given name defined in an included module" do + c = Class.new { include ModuleSpecs::MVars } + c.send(:class_variable_set, "@@mvar", :new_mvar).should == :new_mvar + c.send(:class_variable_get, "@@mvar").should == :new_mvar + end + + not_compliant_on :rubinius do + it "accepts Fixnums for class variables" do + c = Class.new + c.send(:class_variable_set, :@@test2.to_i, "test2") + c.send(:class_variable_get, :@@test2).should == "test2" + end + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + lambda { Class.new.freeze.send(:class_variable_set, :@@test, "test") }.should raise_error(TypeError) + lambda { Module.new.freeze.send(:class_variable_set, :@@test, "test") }.should raise_error(TypeError) + end + end + + it "raises a NameError when the given name is not allowed" do + c = Class.new + + lambda { c.send(:class_variable_set, :invalid_name, "test") }.should raise_error(NameError) + lambda { c.send(:class_variable_set, "@invalid_name", "test") }.should raise_error(NameError) + end + + it "converts a non string/symbol/fixnum name to string using to_str" do + (o = mock('@@class_var')).should_receive(:to_str).and_return("@@class_var") + c = Class.new + c.send(:class_variable_set, o, "test") + c.send(:class_variable_get, :@@class_var).should == "test" + end + + it "raises a TypeError when the given names can't be converted to strings using to_str" do + c = Class.new { class_variable_set :@@class_var, "test" } + o = mock('123') + lambda { c.send(:class_variable_set, o, "test") }.should raise_error(TypeError) + o.should_receive(:to_str).and_return(123) + lambda { c.send(:class_variable_set, o, "test") }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/class_variables_spec.rb b/1.8/core/module/class_variables_spec.rb new file mode 100644 index 0000000000..ff81ec505d --- /dev/null +++ b/1.8/core/module/class_variables_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#class_variables" do + it "returns an Array with the names of class variables of self and self's ancestors" do + ModuleSpecs::ClassVars::A.class_variables.should include("@@a_cvar") + ModuleSpecs::ClassVars::M.class_variables.should include("@@m_cvar") + ModuleSpecs::ClassVars::B.class_variables.should include("@@a_cvar", "@@b_cvar", "@@m_cvar") + end + + it "returns an Array with names of class variables defined in metaclasses" do + ModuleSpecs::CVars.class_variables.should include("@@cls", "@@meta") + end + + it "returns an Array with names of class variables defined in included modules" do + c = Class.new { include ModuleSpecs::MVars } + c.class_variables.should include("@@mvar") + end + + it "does not return class variables defined in extended modules" do + c = Class.new + c.extend ModuleSpecs::MVars + c.class_variables.should_not include("@@mvar") + end +end diff --git a/1.8/core/module/comparison_spec.rb b/1.8/core/module/comparison_spec.rb new file mode 100644 index 0000000000..bdd6cc15c1 --- /dev/null +++ b/1.8/core/module/comparison_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#<=>" do + it "returns -1 if self is a subclass of or includes the given module" do + (ModuleSpecs::Child <=> ModuleSpecs::Parent).should == -1 + (ModuleSpecs::Child <=> ModuleSpecs::Basic).should == -1 + (ModuleSpecs::Child <=> ModuleSpecs::Super).should == -1 + (ModuleSpecs::Super <=> ModuleSpecs::Basic).should == -1 + end + + it "returns 0 if self is the same as the given module" do + (ModuleSpecs::Child <=> ModuleSpecs::Child).should == 0 + (ModuleSpecs::Parent <=> ModuleSpecs::Parent).should == 0 + (ModuleSpecs::Basic <=> ModuleSpecs::Basic).should == 0 + (ModuleSpecs::Super <=> ModuleSpecs::Super).should == 0 + end + + it "returns +1 if self is a superclas of or included by the given module" do + (ModuleSpecs::Parent <=> ModuleSpecs::Child).should == +1 + (ModuleSpecs::Basic <=> ModuleSpecs::Child).should == +1 + (ModuleSpecs::Super <=> ModuleSpecs::Child).should == +1 + (ModuleSpecs::Basic <=> ModuleSpecs::Super).should == +1 + end + + it "returns nil if self and the given module are not related" do + (ModuleSpecs::Parent <=> ModuleSpecs::Basic).should == nil + (ModuleSpecs::Parent <=> ModuleSpecs::Super).should == nil + (ModuleSpecs::Basic <=> ModuleSpecs::Parent).should == nil + (ModuleSpecs::Super <=> ModuleSpecs::Parent).should == nil + end + + it "returns nil if the argument is not a class/module" do + (ModuleSpecs::Parent <=> mock('x')).should == nil + end +end diff --git a/1.8/core/module/const_defined_spec.rb b/1.8/core/module/const_defined_spec.rb new file mode 100644 index 0000000000..27d9817df6 --- /dev/null +++ b/1.8/core/module/const_defined_spec.rb @@ -0,0 +1,53 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#const_defined?" do + extended_on :rubinius do + it "returns true if constant with the given String is defined in its parent" do + ModuleSpecs.const_defined?("Super::SuperChild").should == true + ModuleSpecs.const_defined?("Super::Something").should == false + # Object first and "" first + end + end + + it "returns true if constant with the given Symbol is defined in self" do + ModuleSpecs.const_defined?(:Child).should == true + ModuleSpecs.const_defined?(:SomeThing).should == false + end + + it "returns true if a constant with the given String is defined in self" do + ModuleSpecs.const_defined?("Child").should == true + ModuleSpecs.const_defined?("SomeThing").should == false + end + + not_compliant_on :rubinius do + it "returns true if a constant with the given FixNum is defined in self" do + ModuleSpecs.const_defined?(:Child.to_i).should == true + ModuleSpecs.const_defined?(:SomeThing.to_i).should == false + end + end + + it "tries to convert the given name to a string using to_str" do + (o = mock('Child')).should_receive(:to_str).and_return("Child") + o.respond_to?(:to_str).should == true + ModuleSpecs.const_defined?(o).should == true + end + + it "raises a NameError when the given constant name is not allowed" do + lambda { + ModuleSpecs.const_defined?("invalid_name") + }.should raise_error(NameError) + + lambda { + ModuleSpecs.const_defined?("@invalid_name") + }.should raise_error(NameError) + end + + it "raises a TypeError when the given names can't be converted to strings using to_str" do + o = mock('123') + lambda { ModuleSpecs.const_defined?(o) }.should raise_error(TypeError) + + o.should_receive(:to_str).and_return(123) + lambda { ModuleSpecs.const_defined?(o) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/const_get_spec.rb b/1.8/core/module/const_get_spec.rb new file mode 100644 index 0000000000..12dc4b5154 --- /dev/null +++ b/1.8/core/module/const_get_spec.rb @@ -0,0 +1,59 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#const_get" do + it "returns the named constant in the receiver module when name given as String" do + ModuleSpecs.const_get("Lookup").should == ModuleSpecs::Lookup + end + + it "returns the named constant in the receiver module when name given as Symbol" do + ModuleSpecs::Lookup.const_get(:LOOKIE).should == ModuleSpecs::Lookup::LOOKIE + end + + it "returns the named constant in any superclass of a receiver Class" do + ModuleSpecs::LookupChild.const_get(:LOOKIE).should == ModuleSpecs::Lookup::LOOKIE + ModuleSpecs::LookupChild.const_get(:MODS).should == ModuleSpecs::LookupMod::MODS + end + + it "returns the named constant in any included module in receiver's ancestry" do + ModuleSpecs::LookupMod.const_get(:INCS).should == ModuleSpecs::LookupModInMod::INCS + ModuleSpecs::LookupChild.const_get(:INCS).should == ModuleSpecs::LookupModInMod::INCS + end + + it "returns the named top-level constant for a receiver Class (since it is < Object)" do + Object.const_get(:TopLevelConst).should == TopLevelConst + ModuleSpecs::LookupChild.const_get(:TopLevelConst).should == TopLevelConst + end + + it "returns the named top-level constant for a receiver Module" do + Object.const_get(:TopLevelConst).should == TopLevelConst + ModuleSpecs::LookupMod.const_get(:TopLevelConst).should == TopLevelConst + end + + extended_on :rubinius do + it "returns the value of the constant when a scoped constant name" do + ModuleSpecs.const_get("Super::SuperChild").should == ModuleSpecs::Super::SuperChild + + lambda { + ModuleSpecs.const_get("Super::NonExistingConstantName") + }.should raise_error(NameError) + end + end + + it "raises a NameError when there is no constant with the given name" do + lambda { ModuleSpecs.const_get("NotExistant") }.should raise_error(NameError) + end + + it "tries to convert any non-String/Symbol 'name' with #to_str" do + (o = mock('Parent')).should_receive(:to_str).and_return("Parent") + ModuleSpecs.const_get(o).should == ModuleSpecs::Parent + end + + it "raises a TypeError when the given object does not respond to or fails #to_str" do + o = mock('123') + lambda { ModuleSpecs.const_get(o) }.should raise_error(TypeError) + + o.should_receive(:to_str).and_return(123) + lambda { ModuleSpecs.const_get(o) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/const_missing_spec.rb b/1.8/core/module/const_missing_spec.rb new file mode 100644 index 0000000000..4f7b54eb46 --- /dev/null +++ b/1.8/core/module/const_missing_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#const_missing" do + it "is invoked when an undefined constant is referenced in the scope of self" do + begin + A = Module.new do + const_set(:A, "test") + + def self.const_missing(mod) + $missing_const = mod + return 123 + end + end + + A::NotExistant.should == 123 + $missing_const.should == :NotExistant + + A.const_get(:NotExistantToo).should == 123 + $missing_const.should == :NotExistantToo + + A::A.should == "test" + A.const_get(:A).should == "test" + + $missing_const.should == :NotExistantToo + ensure + $missing_const = nil + end + end +end diff --git a/1.8/core/module/const_set_spec.rb b/1.8/core/module/const_set_spec.rb new file mode 100644 index 0000000000..4043cbea83 --- /dev/null +++ b/1.8/core/module/const_set_spec.rb @@ -0,0 +1,52 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#const_set" do + it "sets the constant with the given name to the given value" do + Module.const_set :A, "A" + Module.const_set "C", "C" + + Module.const_get("A").should == "A" + Module.const_get("C").should == "C" + end + + it "raises a NameError when the given name is no valid constant name" do + lambda { + Module.const_set "invalid", "some value" + }.should raise_error(NameError) + + lambda { + Module.const_set "Dup Dup", "some value" + }.should raise_error(NameError) + + lambda { + Module.const_set "123", "some value" + }.should raise_error(NameError) + end + + it "raises a NameError when there is no constant with the given name" do + lambda { + ModuleSpecs.const_get("NotExistant") + }.should raise_error(NameError) + end + + it "tries to convert the given name to a string using to_str" do + (o = mock('A')).should_receive(:to_str).and_return("A") + Module.const_set o, "test" + Module.const_get(:A).should == "test" + end + + it "raises a TypeError when the given name can't be converted to string using to_str" do + o = mock('123') + lambda { Module.const_set(o, "test") }.should raise_error(TypeError) + + o.should_receive(:to_str).and_return(123) + lambda { Module.const_set(o, "Test") }.should raise_error(TypeError) + end + + it "works in e2mmap.rb" do + # Sorry this test is so inspecific, but I felt it important to note before + # I understand the root cause, which could very well be never. :-) + require 'e2mmap' + end +end diff --git a/1.8/core/module/constants_spec.rb b/1.8/core/module/constants_spec.rb new file mode 100644 index 0000000000..f399ee7906 --- /dev/null +++ b/1.8/core/module/constants_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module.constants" do + it "returns an array of the names of all constants defined" do + a = ModuleSpecs::AddConstant.constants.size + ModuleSpecs::AddConstant::ABC = "" + b = ModuleSpecs::AddConstant.constants.size.should == a + 1 + end +end + +describe "Module#constants" do + it "returns an array with the names of all accessible constants" do + ModuleSpecs.constants.sort.should include("Basic", "Child", "CountsChild", + "CountsMixin", "CountsParent", "Parent", "Super") + + Module.new { const_set :A, "test" }.constants.should == [ "A" ] + Class.new { const_set :A, "test" }.constants.should == [ "A" ] + end +end diff --git a/1.8/core/module/define_method_spec.rb b/1.8/core/module/define_method_spec.rb new file mode 100644 index 0000000000..7498185533 --- /dev/null +++ b/1.8/core/module/define_method_spec.rb @@ -0,0 +1,76 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +class DefineMethodSpecClass +end + +describe "Module#define_method when given an UnboundMethod" do + it "correctly passes given arguments to the new method" do + klass = Class.new do + def test_method(arg1, arg2) + [arg1, arg2] + end + define_method(:another_test_method, instance_method(:test_method)) + end + + klass.new.another_test_method(1, 2).should == [1, 2] + end + + it "adds the new method to the methods list" do + klass = Class.new do + def test_method(arg1, arg2) + [arg1, arg2] + end + define_method(:another_test_method, instance_method(:test_method)) + end + + klass.new.methods.should include("another_test_method") + end +end + +describe "Module#define_method" do + it "defines the given method as an instance method with the given name in self" do + class DefineMethodSpecClass + def test1 + "test" + end + define_method(:another_test, instance_method(:test1)) + end + + o = DefineMethodSpecClass.new + o.test1.should == o.another_test + end + + it "defines a new method with the given name and the given block as body in self" do + class DefineMethodSpecClass + define_method(:block_test1) { self } + define_method(:block_test2, &lambda { self }) + end + + o = DefineMethodSpecClass.new + o.block_test1.should == o + o.block_test2.should == o + end + + it "raises a TypeError when the given method is no Method/Proc" do + lambda { + Class.new { define_method(:test, "self") } + }.should raise_error(TypeError) + + lambda { + Class.new { define_method(:test, 1234) } + }.should raise_error(TypeError) + end + + it "should maintain the Proc's scope" do + class DefineMethodByProcClass + in_scope = true + method_proc = proc { in_scope } + + define_method(:proc_test, &method_proc) + end + + o = DefineMethodByProcClass.new + o.proc_test.should == true + end +end diff --git a/1.8/core/module/eql_spec.rb b/1.8/core/module/eql_spec.rb new file mode 100644 index 0000000000..39327d9fea --- /dev/null +++ b/1.8/core/module/eql_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Module#eql?" do + it_behaves_like(:module_equal, :eql?) +end diff --git a/1.8/core/module/equal_spec.rb b/1.8/core/module/equal_spec.rb new file mode 100644 index 0000000000..6025b23d06 --- /dev/null +++ b/1.8/core/module/equal_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Module#equal?" do + it_behaves_like(:module_equal, :equal?) +end diff --git a/1.8/core/module/equal_value_spec.rb b/1.8/core/module/equal_value_spec.rb new file mode 100644 index 0000000000..edee663791 --- /dev/null +++ b/1.8/core/module/equal_value_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Module#==" do + it_behaves_like(:module_equal, :==) +end diff --git a/1.8/core/module/extend_object_spec.rb b/1.8/core/module/extend_object_spec.rb new file mode 100644 index 0000000000..c01dd6517f --- /dev/null +++ b/1.8/core/module/extend_object_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#extend_object" do + it "extends the given object with constants and methods of self" do + m = Module.new do + const_set :C, "test" + def test() "hello" end + end + + o = mock('test') + m.send(:extend_object, o) + + o.test.should == "hello" + (class << o; C; end).should == "test" + end + + it "is called when an object gets extended with self" do + begin + m = Module.new do + def self.extend_object(o) + $extended_object = o + end + end + + (o = mock('x')).extend(m) + + $extended_object.should == o + ensure + $extended_object = nil + end + end +end diff --git a/1.8/core/module/extended_spec.rb b/1.8/core/module/extended_spec.rb new file mode 100644 index 0000000000..f43e620a7c --- /dev/null +++ b/1.8/core/module/extended_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#extended" do + it "is called when an object gets extended with self" do + begin + m = Module.new do + def self.extended(o) + $extended_object = o + end + end + + (o = mock('x')).extend(m) + + $extended_object.should == o + ensure + $extended_object = nil + end + end + + it "is called after Module#extend_object" do + begin + m = Module.new do + def self.extend_object(o) + $extended_object = nil + end + + def self.extended(o) + $extended_object = o + end + end + + (o = mock('x')).extend(m) + + $extended_object.should == o + ensure + $extended_object = nil + end + end +end diff --git a/1.8/core/module/fixtures/autoload.rb b/1.8/core/module/fixtures/autoload.rb new file mode 100644 index 0000000000..286c5a68a1 --- /dev/null +++ b/1.8/core/module/fixtures/autoload.rb @@ -0,0 +1 @@ +$m.const_set(:AAA, "test") unless $m.nil? \ No newline at end of file diff --git a/1.8/core/module/fixtures/autoload_extension.rb b/1.8/core/module/fixtures/autoload_extension.rb new file mode 100644 index 0000000000..f1474f6979 --- /dev/null +++ b/1.8/core/module/fixtures/autoload_extension.rb @@ -0,0 +1,9 @@ +module ModuleSpecs + module AutoloadExtension + module Constant + class << self + def message; 'success';end + end + end + end +end diff --git a/1.8/core/module/fixtures/autoload_nested.rb b/1.8/core/module/fixtures/autoload_nested.rb new file mode 100644 index 0000000000..d1d6e3dd02 --- /dev/null +++ b/1.8/core/module/fixtures/autoload_nested.rb @@ -0,0 +1,4 @@ +module ModuleSpecs::AutoLoadParent::AutoLoadSubject + def self.message; "success"; end +end + diff --git a/1.8/core/module/fixtures/autoload_require.rb b/1.8/core/module/fixtures/autoload_require.rb new file mode 100644 index 0000000000..e93abafe53 --- /dev/null +++ b/1.8/core/module/fixtures/autoload_require.rb @@ -0,0 +1,9 @@ +module ModuleSpecs::AutoloadRequire + module ModuleSpecAutoloadRequire + def hello + "Hello, World!" + end + + module_function :hello + end +end diff --git a/1.8/core/module/fixtures/autoload_toplevel.rb b/1.8/core/module/fixtures/autoload_toplevel.rb new file mode 100644 index 0000000000..ce777ab5c6 --- /dev/null +++ b/1.8/core/module/fixtures/autoload_toplevel.rb @@ -0,0 +1,3 @@ +module ModuleSpecAutoloadToplevel + def self.message; "success";end +end diff --git a/1.8/core/module/fixtures/classes.rb b/1.8/core/module/fixtures/classes.rb new file mode 100644 index 0000000000..6094bf0013 --- /dev/null +++ b/1.8/core/module/fixtures/classes.rb @@ -0,0 +1,292 @@ +module ModuleSpecs + CONST = :plain_constant + + class Subclass < Module + end + + class SubclassSpec + end + + module LookupModInMod + INCS = :ethereal + end + + module LookupMod + include LookupModInMod + + MODS = :rockers + end + + class Lookup + include LookupMod + LOOKIE = :lookie + end + + class LookupChild < Lookup + end + + class Parent + # For private_class_method spec + def self.private_method; end + private_class_method :private_method + + def undefed_method() end + undef_method :undefed_method + + # For public_class_method spec + private + def self.public_method; end + public_class_method :public_method + + public + def public_parent() end + + protected + def protected_parent() end + + private + def private_parent() end + end + + module Basic + def public_module() end + + protected + def protected_module() end + + private + def private_module() end + end + + module Super + include Basic + + def public_super_module() end + + protected + def protected_super_module() end + + private + def private_super_module() end + + class SuperChild + end + end + + module Internal + end + + class Child < Parent + include Super + + class << self + include Internal + end + attr_accessor :accessor_method + + def public_child() end + + protected + def protected_child() end + + private + def private_child() end + end + + class Child2 < Parent + attr_reader :foo + end + + # Be careful touching the Counts* classes as there used for testing + # private_instance_methods, public_instance_methods, etc. So adding, removing + # a method will break those tests. + module CountsMixin + def public_3; end + public :public_3 + + def private_3; end + private :private_3 + + def protected_3; end + protected :protected_3 + end + + class CountsParent + include CountsMixin + + def public_2; end + + private + def private_2; end + + protected + def protected_2; end + end + + class CountsChild < CountsParent + def public_1; end + + private + def private_1; end + + protected + def protected_1; end + end + + module AddConstant + end + + module A + CONSTANT_A = :a + OVERRIDE = :a + def ma(); :a; end + def self.cma(); :a; end + end + + module B + CONSTANT_B = :b + OVERRIDE = :b + include A + def mb(); :b; end + def self.cmb(); :b; end + end + + class C + OVERRIDE = :c + include B + end + + class Aliasing + def self.make_alias(*a) + alias_method(*a) + end + + def public_one; 1; end + + def public_two(n); n * 2; end + + private + def private_one; 1; end + + protected + def protected_one; 1; end + end + + module ReopeningModule + def foo; true; end + module_function :foo + private :foo + end + + # Yes, we want to re-open the module + module ReopeningModule + alias :foo2 :foo + module_function :foo2 + end + + module Nesting + @tests = {} + def self.[](name); @tests[name]; end + def self.[]=(name, val); @tests[name] = val; end + def self.meta; class << self; self; end; end + + Nesting[:basic] = Module.nesting + + module ::ModuleSpecs + Nesting[:open_first_level] = Module.nesting + end + + class << self + Nesting[:open_meta] = Module.nesting + end + + def self.called_from_module_method + Module.nesting + end + + class NestedClass + Nesting[:nest_class] = Module.nesting + + def self.called_from_class_method + Module.nesting + end + + def called_from_inst_method + Module.nesting + end + end + + end + + Nesting[:first_level] = Module.nesting + + module InstanceMethMod + def bar(); :bar; end + end + + class InstanceMeth + include InstanceMethMod + def foo(); :foo; end + end + + class InstanceMethChild < InstanceMeth + end + + module ClassVars + class A + @@a_cvar = :a_cvar + end + + module M + @@m_cvar = :m_cvar + end + + class B < A + include M + + @@b_cvar = :b_cvar + end + end + + class CVars + @@cls = :class + + class << self + def cls + @@cls + end + @@meta = :meta + end + + def self.meta + @@meta + end + + def meta + @@meta + end + end + + module MVars + @@mvar = :mvar + end + + class SubModule < Module + attr_reader :special + def initialize + @special = 10 + end + end + +end + +ModuleSpecs::Nesting[:root_level] = Module.nesting + +class TopLevelConst +end + +module AutoLoadSubject + def self.message; "failure"; end +end + +autoload :ModuleSpecAutoloadToplevel, File.join(File.dirname(__FILE__), "autoload_toplevel.rb") diff --git a/1.8/core/module/freeze_spec.rb b/1.8/core/module/freeze_spec.rb new file mode 100644 index 0000000000..45734d1c0d --- /dev/null +++ b/1.8/core/module/freeze_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +compliant_on :ruby, :jruby do + describe "Module#freeze" do + it "prevents further modifications to self" do + m = Module.new.freeze + m.frozen?.should == true + + # Does not raise + class << m; end + + lambda { + class << m + def test() "test" end + end + }.should raise_error(TypeError) + + lambda { def m.test() "test" end }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/module/gt_spec.rb b/1.8/core/module/gt_spec.rb new file mode 100644 index 0000000000..12a5ff4862 --- /dev/null +++ b/1.8/core/module/gt_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#>" do + it "returns true if self is a superclass of or included by the given module" do + (ModuleSpecs::Parent > ModuleSpecs::Child).should == true + (ModuleSpecs::Basic > ModuleSpecs::Child).should == true + (ModuleSpecs::Super > ModuleSpecs::Child).should == true + (ModuleSpecs::Basic > ModuleSpecs::Super).should == true + end + + it "returns false if self is the same as the given module" do + (ModuleSpecs::Child > ModuleSpecs::Child).should == false + (ModuleSpecs::Parent > ModuleSpecs::Parent).should == false + (ModuleSpecs::Basic > ModuleSpecs::Basic).should == false + (ModuleSpecs::Super > ModuleSpecs::Super).should == false + end + + it "returns nil if self is not related to the given module" do + (ModuleSpecs::Parent > ModuleSpecs::Basic).should == nil + (ModuleSpecs::Parent > ModuleSpecs::Super).should == nil + (ModuleSpecs::Basic > ModuleSpecs::Parent).should == nil + (ModuleSpecs::Super > ModuleSpecs::Parent).should == nil + end + + it "raises a TypeError if the argument is not a class/module" do + lambda { ModuleSpecs::Parent > mock('x') }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/gte_spec.rb b/1.8/core/module/gte_spec.rb new file mode 100644 index 0000000000..5b669e7445 --- /dev/null +++ b/1.8/core/module/gte_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#>=" do + it "returns true if self is a superclass of, the same as or included by given module" do + (ModuleSpecs::Parent >= ModuleSpecs::Child).should == true + (ModuleSpecs::Basic >= ModuleSpecs::Child).should == true + (ModuleSpecs::Super >= ModuleSpecs::Child).should == true + (ModuleSpecs::Basic >= ModuleSpecs::Super).should == true + (ModuleSpecs::Child >= ModuleSpecs::Child).should == true + (ModuleSpecs::Parent >= ModuleSpecs::Parent).should == true + (ModuleSpecs::Basic >= ModuleSpecs::Basic).should == true + (ModuleSpecs::Super >= ModuleSpecs::Super).should == true + end + + it "returns nil if self is not related to the given module" do + (ModuleSpecs::Parent >= ModuleSpecs::Basic).should == nil + (ModuleSpecs::Parent >= ModuleSpecs::Super).should == nil + (ModuleSpecs::Basic >= ModuleSpecs::Parent).should == nil + (ModuleSpecs::Super >= ModuleSpecs::Parent).should == nil + end + + it "returns false if self is a subclass of or includes the given module" do + (ModuleSpecs::Child >= ModuleSpecs::Parent).should == false + (ModuleSpecs::Child >= ModuleSpecs::Basic).should == false + (ModuleSpecs::Child >= ModuleSpecs::Super).should == false + (ModuleSpecs::Super >= ModuleSpecs::Basic).should == false + end + + it "raises a TypeError if the argument is not a class/module" do + lambda { ModuleSpecs::Parent >= mock('x') }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/include_spec.rb b/1.8/core/module/include_spec.rb new file mode 100644 index 0000000000..55398a95ed --- /dev/null +++ b/1.8/core/module/include_spec.rb @@ -0,0 +1,98 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#include" do + it "calls #append_features(self) in reversed order on each module" do + $appended_modules = [] + + m = Module.new do + def self.append_features(mod) + $appended_modules << [ self, mod ] + end + end + + m2 = Module.new do + def self.append_features(mod) + $appended_modules << [ self, mod ] + end + end + + m3 = Module.new do + def self.append_features(mod) + $appended_modules << [ self, mod ] + end + end + + c = Class.new { include(m, m2, m3) } + + $appended_modules.should == [ [ m3, c], [ m2, c ], [ m, c ] ] + end + + it "raises a TypeError when the argument is not a Module" do + lambda { ModuleSpecs::Basic.send(:include, Class.new) }.should raise_error(TypeError) + end + + it "does not raise a TypeError when the argument is an instance of a subclass of Module" do + lambda { ModuleSpecs::SubclassSpec.send(:include, ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError) + end + + it "imports constants to modules and classes" do + ModuleSpecs::A.constants.should include("CONSTANT_A") + ModuleSpecs::B.constants.should include("CONSTANT_A","CONSTANT_B") + ModuleSpecs::C.constants.should include("CONSTANT_A","CONSTANT_B") + end + + it "does not override existing constants in modules and classes" do + ModuleSpecs::A::OVERRIDE.should == :a + ModuleSpecs::B::OVERRIDE.should == :b + ModuleSpecs::C::OVERRIDE.should == :c + end + + it "imports instance methods to modules and classes" do + ModuleSpecs::A.instance_methods.should include("ma") + ModuleSpecs::B.instance_methods.should include("ma","mb") + ModuleSpecs::C.instance_methods.should include("ma","mb") + end + + it "does not import methods to modules and classes" do + ModuleSpecs::A.methods.include?("cma").should == true + ModuleSpecs::B.methods.include?("cma").should == false + ModuleSpecs::B.methods.include?("cmb").should == true + ModuleSpecs::C.methods.include?("cma").should == false + ModuleSpecs::C.methods.include?("cmb").should == false + end + + it "attaches the module as the caller's immediate ancestor" do + module IncludeSpecsTop + def value; 5; end + end + + module IncludeSpecsMiddle + include IncludeSpecsTop + def value; 6; end + end + + class IncludeSpecsClass + include IncludeSpecsMiddle + end + + IncludeSpecsClass.new.value.should == 6 + end +end + +describe "Module#include?" do + it "returns true if the given module is included by self or one of it's ancestors" do + ModuleSpecs::Super.include?(ModuleSpecs::Basic).should == true + ModuleSpecs::Child.include?(ModuleSpecs::Basic).should == true + ModuleSpecs::Child.include?(ModuleSpecs::Super).should == true + ModuleSpecs::Child.include?(Kernel).should == true + + ModuleSpecs::Parent.include?(ModuleSpecs::Basic).should == false + ModuleSpecs::Basic.include?(ModuleSpecs::Super).should == false + end + + it "raises a TypeError when no module was given" do + lambda { ModuleSpecs::Child.include?("Test") }.should raise_error(TypeError) + lambda { ModuleSpecs::Child.include?(ModuleSpecs::Parent) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/included_modules_spec.rb b/1.8/core/module/included_modules_spec.rb new file mode 100644 index 0000000000..bcded32b2c --- /dev/null +++ b/1.8/core/module/included_modules_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#included_modules" do + it "returns a list of modules included in self" do + ModuleSpecs.included_modules.should == [] + ModuleSpecs::Child.included_modules.should include(ModuleSpecs::Super, ModuleSpecs::Basic, Kernel) + ModuleSpecs::Parent.included_modules.should include(Kernel) + ModuleSpecs::Basic.included_modules.should == [] + ModuleSpecs::Super.included_modules.should include(ModuleSpecs::Basic) + end +end diff --git a/1.8/core/module/included_spec.rb b/1.8/core/module/included_spec.rb new file mode 100644 index 0000000000..e2f8d62a38 --- /dev/null +++ b/1.8/core/module/included_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#included" do + it "is invoked when self is included in another module or class" do + begin + m = Module.new do + def self.included(o) + $included_by = o + end + end + + c = Class.new { include m } + + $included_by.should == c + ensure + $included_by = nil + end + end + + it "allows extending self with the object into which it is being included" do + m = Module.new do + def self.included(o) + o.extend(self) + end + + def test + :passed + end + end + + c = Class.new{ include(m) } + c.test.should == :passed + end +end diff --git a/1.8/core/module/initialize_copy_spec.rb b/1.8/core/module/initialize_copy_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/core/module/initialize_copy_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/core/module/initialize_spec.rb b/1.8/core/module/initialize_spec.rb new file mode 100644 index 0000000000..0b9c72acd2 --- /dev/null +++ b/1.8/core/module/initialize_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#initialize" do + it "accepts a block" do + m = Module.new do + const_set :A, "A" + end + m.const_get("A").should == "A" + end + + it "is called on subclasses" do + m = ModuleSpecs::SubModule.new + m.special.should == 10 + m.methods.should_not == nil + m.constants.should_not == nil + end +end diff --git a/1.8/core/module/instance_method_spec.rb b/1.8/core/module/instance_method_spec.rb new file mode 100644 index 0000000000..4fbe0edae8 --- /dev/null +++ b/1.8/core/module/instance_method_spec.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#instance_method" do + before :all do + @parent_um = ModuleSpecs::InstanceMeth.instance_method(:foo) + @child_um = ModuleSpecs::InstanceMethChild.instance_method(:foo) + @mod_um = ModuleSpecs::InstanceMethChild.instance_method(:bar) + end + + it "returns an UnboundMethod corresponding to the given name" do + @parent_um.class.should == UnboundMethod + @parent_um.bind(ModuleSpecs::InstanceMeth.new).call.should == :foo + end + + it "returns an UnboundMethod corresponding to the given name from a superclass" do + @child_um.class.should == UnboundMethod + @child_um.bind(ModuleSpecs::InstanceMethChild.new).call.should == :foo + end + + it "returns an UnboundMethod corresponding to the given name from an included Module" do + @mod_um.class.should == UnboundMethod + @mod_um.bind(ModuleSpecs::InstanceMethChild.new).call.should == :bar + end + + it "gives UnboundMethod method name, Module defined in and Module extracted from" do + @parent_um.inspect.should =~ /\bfoo\b/ + @parent_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/ + @parent_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/ + @child_um.inspect.should =~ /\bfoo\b/ + @child_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/ + @child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/ + @mod_um.inspect.should =~ /\bbar\b/ + @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethMod\b/ + @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/ + end + + it "raises a TypeError if the given name is not a string/symbol" do + lambda { Object.instance_method(nil) }.should raise_error(TypeError) + lambda { Object.instance_method(mock('x')) }.should raise_error(TypeError) + end + + it "raises a NameError if the given method doesn't exist" do + lambda { Object.instance_method(:missing) }.should raise_error(NameError) + end +end diff --git a/1.8/core/module/instance_methods_spec.rb b/1.8/core/module/instance_methods_spec.rb new file mode 100644 index 0000000000..0124737b9a --- /dev/null +++ b/1.8/core/module/instance_methods_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#instance_methods" do + it "does not return undefined methods" do + methods = ModuleSpecs::Parent.instance_methods(false) + methods.should_not include("undefed_method") + + methods = ModuleSpecs::Child.instance_methods + methods.should_not include("undefed_method") + end + + it "returns an array containing the public and protected methods of self if include_super is false" do + methods = ModuleSpecs::Parent.instance_methods(false) + methods.should include("protected_parent", "public_parent") + + methods = ModuleSpecs::Child.instance_methods(false) + methods.should include("protected_child", "public_child") + end + + it "returns an array containing the public and protected methods of self and it's ancestors" do + methods = ModuleSpecs::Basic.instance_methods + methods.should include("protected_module", "public_module") + + methods = ModuleSpecs::Super.instance_methods + methods.should include("protected_module", "protected_super_module", + "public_module", "public_super_module") + end +end diff --git a/1.8/core/module/lt_spec.rb b/1.8/core/module/lt_spec.rb new file mode 100644 index 0000000000..85c7b56f91 --- /dev/null +++ b/1.8/core/module/lt_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#<" do + it "returns true if self is a subclass of or includes the given module" do + (ModuleSpecs::Child < ModuleSpecs::Parent).should == true + (ModuleSpecs::Child < ModuleSpecs::Basic).should == true + (ModuleSpecs::Child < ModuleSpecs::Super).should == true + (ModuleSpecs::Super < ModuleSpecs::Basic).should == true + end + + it "returns false if self is the same as the given module" do + (ModuleSpecs::Child < ModuleSpecs::Child).should == false + (ModuleSpecs::Parent < ModuleSpecs::Parent).should == false + (ModuleSpecs::Basic < ModuleSpecs::Basic).should == false + (ModuleSpecs::Super < ModuleSpecs::Super).should == false + end + + it "returns nil if self is not related to the given module" do + (ModuleSpecs::Parent < ModuleSpecs::Basic).should == nil + (ModuleSpecs::Parent < ModuleSpecs::Super).should == nil + (ModuleSpecs::Basic < ModuleSpecs::Parent).should == nil + (ModuleSpecs::Super < ModuleSpecs::Parent).should == nil + end + + it "raises a TypeError if the argument is not a class/module" do + lambda { ModuleSpecs::Parent < mock('x') }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/lte_spec.rb b/1.8/core/module/lte_spec.rb new file mode 100644 index 0000000000..a4d4212fae --- /dev/null +++ b/1.8/core/module/lte_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#<=" do + it "returns true if self is a subclass of, the same as or includes the given module" do + (ModuleSpecs::Child <= ModuleSpecs::Parent).should == true + (ModuleSpecs::Child <= ModuleSpecs::Basic).should == true + (ModuleSpecs::Child <= ModuleSpecs::Super).should == true + (ModuleSpecs::Super <= ModuleSpecs::Basic).should == true + (ModuleSpecs::Child <= ModuleSpecs::Child).should == true + (ModuleSpecs::Parent <= ModuleSpecs::Parent).should == true + (ModuleSpecs::Basic <= ModuleSpecs::Basic).should == true + (ModuleSpecs::Super <= ModuleSpecs::Super).should == true + end + + it "returns nil if self is not related to the given module" do + (ModuleSpecs::Parent <= ModuleSpecs::Basic).should == nil + (ModuleSpecs::Parent <= ModuleSpecs::Super).should == nil + (ModuleSpecs::Basic <= ModuleSpecs::Parent).should == nil + (ModuleSpecs::Super <= ModuleSpecs::Parent).should == nil + end + + it "returns false if self is a superclass of or is included by the given module" do + (ModuleSpecs::Parent <= ModuleSpecs::Child).should == false + (ModuleSpecs::Basic <= ModuleSpecs::Child).should == false + (ModuleSpecs::Super <= ModuleSpecs::Child).should == false + (ModuleSpecs::Basic <= ModuleSpecs::Super).should == false + end + + it "raises a TypeError if the argument is not a class/module" do + lambda { ModuleSpecs::Parent <= mock('x') }.should raise_error(TypeError) + end +end diff --git a/1.8/core/module/method_added_spec.rb b/1.8/core/module/method_added_spec.rb new file mode 100644 index 0000000000..5308d406cc --- /dev/null +++ b/1.8/core/module/method_added_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#method_added" do + it "is a private instance method" do + Module.private_instance_methods.should include("method_added") + end + + it "returns nil in the default implementation" do + Module.new do + method_added(:test).should == nil + end + end + + it "is called when a new method is defined in self" do + begin + $methods_added = [] + + m = Module.new do + def self.method_added(name) + $methods_added << name + end + + def test() end + def test2() end + def test() end + end + + $methods_added.should == [:test,:test2, :test] + ensure + $methods_added = nil + end + end +end diff --git a/1.8/core/module/method_defined_spec.rb b/1.8/core/module/method_defined_spec.rb new file mode 100644 index 0000000000..636634e9c4 --- /dev/null +++ b/1.8/core/module/method_defined_spec.rb @@ -0,0 +1,42 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#method_defined?" do + it "returns true if a public or private method with the given name is defined in self, self's ancestors or one of self's included modules" do + # Defined in Child + ModuleSpecs::Child.method_defined?(:public_child).should == true + ModuleSpecs::Child.method_defined?("private_child").should == false + ModuleSpecs::Child.method_defined?(:accessor_method).should == true + + # Defined in Parent + ModuleSpecs::Child.method_defined?("public_parent").should == true + ModuleSpecs::Child.method_defined?(:private_parent).should == false + + # Defined in Module + ModuleSpecs::Child.method_defined?(:public_module).should == true + ModuleSpecs::Child.method_defined?(:protected_module).should == true + ModuleSpecs::Child.method_defined?(:private_module).should == false + + # Defined in SuperModule + ModuleSpecs::Child.method_defined?(:public_super_module).should == true + ModuleSpecs::Child.method_defined?(:protected_super_module).should == true + ModuleSpecs::Child.method_defined?(:private_super_module).should == false + end + + it "raises a TypeError when the given object is not a string/symbol/fixnum" do + c = Class.new + o = mock('123') + + lambda { c.method_defined?(o) }.should raise_error(TypeError) + + o.should_receive(:to_str).and_return(123) + lambda { c.method_defined?(o) }.should raise_error(TypeError) + end + + it "converts the given name to a string using to_str" do + c = Class.new { def test(); end } + (o = mock('test')).should_receive(:to_str).and_return("test") + + c.method_defined?(o).should == true + end +end diff --git a/1.8/core/module/method_removed_spec.rb b/1.8/core/module/method_removed_spec.rb new file mode 100644 index 0000000000..4124187c35 --- /dev/null +++ b/1.8/core/module/method_removed_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#method_removed" do + it "is called when a method is removed from self" do + begin + Module.new do + def self.method_removed(name) + $method_removed = name + end + + def test + "test" + end + remove_method :test + end + + $method_removed.should == :test + ensure + $method_removed = nil + end + end +end diff --git a/1.8/core/module/method_undefined_spec.rb b/1.8/core/module/method_undefined_spec.rb new file mode 100644 index 0000000000..86dd68fe2d --- /dev/null +++ b/1.8/core/module/method_undefined_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#method_undefined" do + it "is called when a method is undefined from self" do + begin + Module.new do + def self.method_undefined(name) + $method_undefined = name + end + + def test + "test" + end + undef_method :test + end + + $method_undefined.should == :test + ensure + $method_undefined = nil + end + end +end diff --git a/1.8/core/module/module_eval_spec.rb b/1.8/core/module/module_eval_spec.rb new file mode 100644 index 0000000000..96e5992562 --- /dev/null +++ b/1.8/core/module/module_eval_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/class_eval' + +describe "Module#module_eval" do + it_behaves_like :module_class_eval, :module_eval +end diff --git a/1.8/core/module/module_function_spec.rb b/1.8/core/module/module_function_spec.rb new file mode 100644 index 0000000000..fb3a40e0e2 --- /dev/null +++ b/1.8/core/module/module_function_spec.rb @@ -0,0 +1,213 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#module_function with specific method names" do + it "creates duplicates of the given instance methods on the Module object" do + m = Module.new do + def test() end + def test2() end + def test3() end + + module_function :test, :test2 + end + + m.respond_to?(:test).should == true + m.respond_to?(:test2).should == true + m.respond_to?(:test3).should == false + end + + it "creates an independent copy of the method, not a redirect" do + module Mixin + def test + "hello" + end + module_function :test + end + + class BaseClass + include Mixin + def call_test + test + end + end + + Mixin.test.should == "hello" + c = BaseClass.new + c.call_test.should == "hello" + + module Mixin + def test + "goodbye" + end + end + + Mixin.test.should == "hello" + c.call_test.should == "goodbye" + end + + it "makes the instance methods private" do + m = Module.new do + def test() "hello" end + module_function :test + end + + (o = mock('x')).extend(m) + o.respond_to?(:test).should == false + m.private_instance_methods.map {|m| m.to_s }.include?('test').should == true + o.private_methods.map {|m| m.to_s }.include?('test').should == true + o.send(:test).should == "hello" + end + + it "makes the new Module methods public" do + m = Module.new do + def test() "hello" end + module_function :test + end + + m.public_methods.map {|m| m.to_s }.include?('test').should == true + end + + it "tries to convert the given names to strings using to_str" do + (o = mock('test')).should_receive(:to_str).any_number_of_times.and_return("test") + (o2 = mock('test2')).should_receive(:to_str).any_number_of_times.and_return("test2") + + m = Module.new do + def test() end + def test2() end + module_function o, o2 + end + + m.respond_to?(:test).should == true + m.respond_to?(:test2).should == true + end + + it "raises a TypeError when the given names can't be converted to string using to_str" do + o = mock('123') + + lambda { Module.new { module_function(o) } }.should raise_error(TypeError) + + o.should_receive(:to_str).and_return(123) + lambda { Module.new { module_function(o) } }.should raise_error(TypeError) + end +end + +describe "Module#module_function as a toggle (no arguments) in a Module body" do + it "makes any subsequently defined methods module functions with the normal semantics" do + m = Module.new { + module_function + def test1() end + def test2() end + } + + m.respond_to?(:test1).should == true + m.respond_to?(:test2).should == true + end + + it "stops creating module functions if the body encounters another toggle " \ + "like public/protected/private without arguments" do + m = Module.new { + module_function + def test1() end + def test2() end + public + def test3() end + } + + m.respond_to?(:test1).should == true + m.respond_to?(:test2).should == true + m.respond_to?(:test3).should == false + end + + it "does not stop creating module functions if the body encounters " \ + "public/protected/private WITH arguments" do + m = Module.new { + def foo() end + + module_function + def test1() end + def test2() end + + public :foo + + def test3() end + } + + m.respond_to?(:test1).should == true + m.respond_to?(:test2).should == true + m.respond_to?(:test3).should == true + end + + it "does not affect module_evaled method definitions also if outside the eval itself" do + m = Module.new { + module_function + + module_eval { def test1() end } + module_eval " def test2() end " + } + + c = Class.new { include m } + + m.respond_to?(:test1).should == false + m.respond_to?(:test2).should == false + end + + it "has no effect if inside a module_eval if the definitions are outside of it" do + m = Module.new { + module_eval { module_function } + + def test1() end + def test2() end + } + + m.respond_to?(:test1).should == false + m.respond_to?(:test2).should == false + end + + it "functions normally if both toggle and definitions inside a module_eval" do + m = Module.new { + module_eval { + module_function + + def test1() end + def test2() end + } + } + + m.respond_to?(:test1).should == true + m.respond_to?(:test2).should == true + end + + it "affects evaled method definitions also even when outside the eval itself" do + m = Module.new { + module_function + + eval "def test1() end" + } + + m.respond_to?(:test1).should == true + end + + it "affects definitions when inside an eval even if the definitions are outside of it" do + m = Module.new { + eval "module_function" + + def test1() end + } + + m.respond_to?(:test1).should == true + end + + it "functions normally if both toggle and definitions inside a module_eval" do + m = Module.new { + eval <<-CODE + module_function + + def test1() end + def test2() end + CODE + } + + m.respond_to?(:test1).should == true + m.respond_to?(:test2).should == true + end +end diff --git a/1.8/core/module/name_spec.rb b/1.8/core/module/name_spec.rb new file mode 100644 index 0000000000..e820b12b1c --- /dev/null +++ b/1.8/core/module/name_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#name" do + it "returns the name of self" do + Module.new.name.should == "" + Class.new.name.should == "" + + ModuleSpecs.name.should == "ModuleSpecs" + ModuleSpecs::Child.name.should == "ModuleSpecs::Child" + ModuleSpecs::Parent.name.should == "ModuleSpecs::Parent" + ModuleSpecs::Basic.name.should == "ModuleSpecs::Basic" + ModuleSpecs::Super.name.should == "ModuleSpecs::Super" + + begin + (ModuleSpecs::X = Module.new).name.should == "ModuleSpecs::X" + ensure + ModuleSpecs.send :remove_const, :X + end + end +end diff --git a/1.8/core/module/nesting_spec.rb b/1.8/core/module/nesting_spec.rb new file mode 100644 index 0000000000..2d74a39596 --- /dev/null +++ b/1.8/core/module/nesting_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module::Nesting" do + + it "returns the list of Modules nested at the point of call" do + ModuleSpecs::Nesting[:root_level].should == [] + ModuleSpecs::Nesting[:first_level].should == [ModuleSpecs] + ModuleSpecs::Nesting[:basic].should == [ModuleSpecs::Nesting, ModuleSpecs] + ModuleSpecs::Nesting[:open_first_level].should == + [ModuleSpecs, ModuleSpecs::Nesting, ModuleSpecs] + ModuleSpecs::Nesting[:open_meta].should == + [ModuleSpecs::Nesting.meta, ModuleSpecs::Nesting, ModuleSpecs] + ModuleSpecs::Nesting[:nest_class].should == + [ModuleSpecs::Nesting::NestedClass, ModuleSpecs::Nesting, ModuleSpecs] + end + + it "returns the nesting for module/class declaring the called method" do + ModuleSpecs::Nesting.called_from_module_method.should == + [ModuleSpecs::Nesting, ModuleSpecs] + ModuleSpecs::Nesting::NestedClass.called_from_class_method.should == + [ModuleSpecs::Nesting::NestedClass, ModuleSpecs::Nesting, ModuleSpecs] + ModuleSpecs::Nesting::NestedClass.new.called_from_inst_method.should == + [ModuleSpecs::Nesting::NestedClass, ModuleSpecs::Nesting, ModuleSpecs] + end + +end diff --git a/1.8/core/module/new_spec.rb b/1.8/core/module/new_spec.rb new file mode 100644 index 0000000000..be5ecc7895 --- /dev/null +++ b/1.8/core/module/new_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module.new" do + it "creates a new anonymous Module" do + Module.new.is_a?(Module).should == true + end + + it "creates a new Module and passes it to the provided block" do + test_mod = nil + m = Module.new do |mod| + mod.should_not == nil + self.should == mod + test_mod = mod + mod.is_a?(Module).should == true + Object.new # trying to return something + end + test_mod.should == m + end + + it "evaluates a passed block in the context of the module" do + fred = Module.new do + def hello() "hello" end + def bye() "bye" end + end + + (o = mock('x')).extend(fred) + o.hello.should == "hello" + o.bye.should == "bye" + end +end diff --git a/1.8/core/module/private_class_method_spec.rb b/1.8/core/module/private_class_method_spec.rb new file mode 100644 index 0000000000..50bffce04e --- /dev/null +++ b/1.8/core/module/private_class_method_spec.rb @@ -0,0 +1,73 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#private_class_method" do + before(:each) do + # This is not in classes.rb because after marking a class method private it + # will stay private. + class << ModuleSpecs::Parent + def private_method_1; end + def private_method_2; end + def private_method_3; end + end + end + + it "makes an existing class method private" do + ModuleSpecs::Parent.private_method_1.should == nil + ModuleSpecs::Parent.private_class_method :private_method_1 + lambda { ModuleSpecs::Parent.private_method_1 }.should raise_error(NoMethodError) + + # Technically above we're testing the Singleton classes, class method(right?). + # Try a "real" class method set private. + lambda { ModuleSpecs::Parent.private_method }.should raise_error(NoMethodError) + end + + it "makes an existing class method private up the inheritance tree" do + ModuleSpecs::Child.private_method_1.should == nil + ModuleSpecs::Child.private_class_method :private_method_1 + + lambda { ModuleSpecs::Child.private_method_1 }.should raise_error(NoMethodError) + lambda { ModuleSpecs::Child.private_method }.should raise_error(NoMethodError) + end + + it "accepts more than one method at a time" do + ModuleSpecs::Parent.private_method_1.should == nil + ModuleSpecs::Parent.private_method_2.should == nil + ModuleSpecs::Parent.private_method_3.should == nil + + ModuleSpecs::Child.private_class_method :private_method_1, :private_method_2, :private_method_3 + + lambda { ModuleSpecs::Child.private_method_1 }.should raise_error(NoMethodError) + lambda { ModuleSpecs::Child.private_method_2 }.should raise_error(NoMethodError) + lambda { ModuleSpecs::Child.private_method_3 }.should raise_error(NoMethodError) + end + + it "raises a NameError if class method doesn't exist" do + lambda { ModuleSpecs.private_class_method :no_method_here }.should raise_error(NameError) + end + + it "makes a class method private" do + c = Class.new do + def self.foo() "foo" end + private_class_method :foo + end + lambda { c.foo }.should raise_error(NoMethodError) + end + + it "raises a NameError when the given name is not a method" do + lambda { + c = Class.new do + private_class_method :foo + end + }.should raise_error(NameError) + end + + it "raises a NameError when the given name is an instance method" do + lambda { + c = Class.new do + def foo() "foo" end + private_class_method :foo + end + }.should raise_error(NameError) + end +end diff --git a/1.8/core/module/private_instance_methods_spec.rb b/1.8/core/module/private_instance_methods_spec.rb new file mode 100644 index 0000000000..e68e56522c --- /dev/null +++ b/1.8/core/module/private_instance_methods_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#private_instance_methods" do + it "returns a list of private methods in module and its ancestors" do + methods = ModuleSpecs::CountsMixin.private_instance_methods + methods.should include('private_3') + + methods = ModuleSpecs::CountsParent.private_instance_methods + methods.should include('private_3') + methods.should include('private_2') + + methods = ModuleSpecs::CountsChild.private_instance_methods + methods.should include('private_3') + methods.should include('private_2') + methods.should include('private_1') + end + + it "when passed false as a parameter, should return only methods defined in that module" do + ModuleSpecs::CountsMixin.private_instance_methods(false).should == ['private_3'] + ModuleSpecs::CountsParent.private_instance_methods(false).should == ['private_2'] + ModuleSpecs::CountsChild.private_instance_methods(false).should == ['private_1'] + end + + it "default list should be the same as passing true as an argument" do + ModuleSpecs::CountsMixin.private_instance_methods(true).should == + ModuleSpecs::CountsMixin.private_instance_methods + ModuleSpecs::CountsParent.private_instance_methods(true).should == + ModuleSpecs::CountsParent.private_instance_methods + ModuleSpecs::CountsChild.private_instance_methods(true).should == + ModuleSpecs::CountsChild.private_instance_methods + end +end diff --git a/1.8/core/module/private_method_defined_spec.rb b/1.8/core/module/private_method_defined_spec.rb new file mode 100644 index 0000000000..e0d1283500 --- /dev/null +++ b/1.8/core/module/private_method_defined_spec.rb @@ -0,0 +1,64 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#private_method_defined?" do + it "returns true if the named private method is defined by module or its ancestors" do + ModuleSpecs::CountsMixin.private_method_defined?("private_3").should == true + + ModuleSpecs::CountsParent.private_method_defined?("private_3").should == true + ModuleSpecs::CountsParent.private_method_defined?("private_2").should == true + + ModuleSpecs::CountsChild.private_method_defined?("private_3").should == true + ModuleSpecs::CountsChild.private_method_defined?("private_2").should == true + ModuleSpecs::CountsChild.private_method_defined?("private_1").should == true + end + + it "returns false if method is not a private method" do + ModuleSpecs::CountsChild.private_method_defined?("public_3").should == false + ModuleSpecs::CountsChild.private_method_defined?("public_2").should == false + ModuleSpecs::CountsChild.private_method_defined?("public_1").should == false + + ModuleSpecs::CountsChild.private_method_defined?("protected_3").should == false + ModuleSpecs::CountsChild.private_method_defined?("protected_2").should == false + ModuleSpecs::CountsChild.private_method_defined?("protected_1").should == false + end + + it "returns false if the named method is not defined by the module or its ancestors" do + ModuleSpecs::CountsMixin.private_method_defined?(:private_10).should == false + end + + it "accepts symbols for the method name" do + ModuleSpecs::CountsMixin.private_method_defined?(:private_3).should == true + end + + compliant_on :ruby, :jruby do + it "raises an ArgumentError if passed a Fixnum" do + lambda { ModuleSpecs::CountsMixin.private_method_defined?(1) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a Symbol" do + lambda { ModuleSpecs::CountsMixin.private_method_defined?(nil) }.should raise_error(TypeError) + lambda { ModuleSpecs::CountsMixin.private_method_defined?(false) }.should raise_error(TypeError) + lambda { ModuleSpecs::CountsMixin.private_method_defined?(mock('x')) }.should raise_error(TypeError) + + sym = mock('symbol') + def sym.to_sym() :private_3 end + lambda { ModuleSpecs::CountsMixin.private_method_defined?(sym) }.should raise_error(TypeError) + end + end + + it "accepts any argument that is a String type" do + str = mock('string') + def str.to_str() 'private_3' end + ModuleSpecs::CountsMixin.private_method_defined?(str).should == true + end + + deviates_on :rubinius do + it "raises a TypeError if not passed a String type" do + lambda { ModuleSpecs::CountsMixin.private_method_defined?(1) }.should raise_error(TypeError) + lambda { ModuleSpecs::CountsMixin.private_method_defined?(nil) }.should raise_error(TypeError) + lambda { ModuleSpecs::CountsMixin.private_method_defined?(false) }.should raise_error(TypeError) + lambda { ModuleSpecs::CountsMixin.private_method_defined?(mock('x')) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/module/private_spec.rb b/1.8/core/module/private_spec.rb new file mode 100644 index 0000000000..2346dcbc29 --- /dev/null +++ b/1.8/core/module/private_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#private" do + it "should make the target method uncallable from other types" do + obj = Object.new + class << obj + def foo; true; end + end + + obj.foo.should == true + + class << obj + private :foo + end + + lambda { obj.foo }.should raise_error(NoMethodError) + end +end diff --git a/1.8/core/module/protected_instance_methods_spec.rb b/1.8/core/module/protected_instance_methods_spec.rb new file mode 100644 index 0000000000..554baef86e --- /dev/null +++ b/1.8/core/module/protected_instance_methods_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#protected_instance_methods" do + it "returns a list of protected methods in module and its ancestors" do + methods = ModuleSpecs::CountsMixin.protected_instance_methods + methods.should include('protected_3') + + methods = ModuleSpecs::CountsParent.protected_instance_methods + methods.should include('protected_3') + methods.should include('protected_2') + + methods = ModuleSpecs::CountsChild.protected_instance_methods + methods.should include('protected_3') + methods.should include('protected_2') + methods.should include('protected_1') + end + + it "when passed false as a parameter, should return only methods defined in that module" do + ModuleSpecs::CountsMixin.protected_instance_methods(false).should == ['protected_3'] + ModuleSpecs::CountsParent.protected_instance_methods(false).should == ['protected_2'] + ModuleSpecs::CountsChild.protected_instance_methods(false).should == ['protected_1'] + end + + it "default list should be the same as passing true as an argument" do + ModuleSpecs::CountsMixin.protected_instance_methods(true).should == + ModuleSpecs::CountsMixin.protected_instance_methods + ModuleSpecs::CountsParent.protected_instance_methods(true).should == + ModuleSpecs::CountsParent.protected_instance_methods + ModuleSpecs::CountsChild.protected_instance_methods(true).should == + ModuleSpecs::CountsChild.protected_instance_methods + end +end diff --git a/1.8/core/module/protected_method_defined_spec.rb b/1.8/core/module/protected_method_defined_spec.rb new file mode 100644 index 0000000000..792cf53201 --- /dev/null +++ b/1.8/core/module/protected_method_defined_spec.rb @@ -0,0 +1,60 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#protected_method_defined?" do + it "returns true if the named protected method is defined by module or its ancestors" do + ModuleSpecs::CountsMixin.protected_method_defined?("protected_3").should == true + + ModuleSpecs::CountsParent.protected_method_defined?("protected_3").should == true + ModuleSpecs::CountsParent.protected_method_defined?("protected_2").should == true + + ModuleSpecs::CountsChild.protected_method_defined?("protected_3").should == true + ModuleSpecs::CountsChild.protected_method_defined?("protected_2").should == true + ModuleSpecs::CountsChild.protected_method_defined?("protected_1").should == true + end + + it "returns false if method is not a protected method" do + ModuleSpecs::CountsChild.protected_method_defined?("public_3").should == false + ModuleSpecs::CountsChild.protected_method_defined?("public_2").should == false + ModuleSpecs::CountsChild.protected_method_defined?("public_1").should == false + + ModuleSpecs::CountsChild.protected_method_defined?("private_3").should == false + ModuleSpecs::CountsChild.protected_method_defined?("private_2").should == false + ModuleSpecs::CountsChild.protected_method_defined?("private_1").should == false + end + + it "returns false if the named method is not defined by the module or its ancestors" do + ModuleSpecs::CountsMixin.protected_method_defined?(:protected_10).should == false + end + + it "accepts symbols for the method name" do + ModuleSpecs::CountsMixin.protected_method_defined?(:protected_3).should == true + end + + compliant_on :ruby, :jruby do + it "raises an ArgumentError if passed a Fixnum" do + lambda { ModuleSpecs::CountsMixin.protected_method_defined?(1) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a Symbol" do + lambda { ModuleSpecs::CountsMixin.protected_method_defined?(nil) }.should raise_error(TypeError) + lambda { ModuleSpecs::CountsMixin.protected_method_defined?(false) }.should raise_error(TypeError) + + sym = mock('symbol') + def sym.to_sym() :protected_3 end + lambda { ModuleSpecs::CountsMixin.protected_method_defined?(sym) }.should raise_error(TypeError) + end + end + + it "accepts any object that is a String type" do + str = mock('protected_3') + def str.to_str() 'protected_3' end + ModuleSpecs::CountsMixin.protected_method_defined?(str).should == true + end + + deviates_on :rubinius do + it "raises a TypeError if not passed a String type" do + lambda { ModuleSpecs::CountsMixin.protected_method_defined?(mock('x')) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/module/protected_spec.rb b/1.8/core/module/protected_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/core/module/protected_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/core/module/public_class_method_spec.rb b/1.8/core/module/public_class_method_spec.rb new file mode 100644 index 0000000000..95a6167496 --- /dev/null +++ b/1.8/core/module/public_class_method_spec.rb @@ -0,0 +1,73 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#public_class_method" do + before(:each) do + class << ModuleSpecs::Parent + private + def public_method_1; end + def public_method_2; end + def public_method_3; end + end + end + + it "makes an existing class method public" do + lambda { ModuleSpecs::Parent.public_method_1 }.should raise_error(NoMethodError) + ModuleSpecs::Parent.public_class_method :public_method_1 + ModuleSpecs::Parent.public_method_1.should == nil + + # Technically above we're testing the Singleton classes, class method(right?). + # Try a "real" class method set public. + ModuleSpecs::Parent.public_method.should == nil + end + + it "makes an existing class method public up the inheritance tree" do + lambda { ModuleSpecs::Child.public_method_1 }.should raise_error(NoMethodError) + ModuleSpecs::Child.public_class_method :public_method_1 + + ModuleSpecs::Child.public_method_1.should == nil + ModuleSpecs::Child.public_method.should == nil + end + + it "accepts more than one method at a time" do + lambda { ModuleSpecs::Parent.public_method_1 }.should raise_error(NameError) + lambda { ModuleSpecs::Parent.public_method_2 }.should raise_error(NameError) + lambda { ModuleSpecs::Parent.public_method_3 }.should raise_error(NameError) + + ModuleSpecs::Child.public_class_method :public_method_1, :public_method_2, :public_method_3 + + ModuleSpecs::Child.public_method_1.should == nil + ModuleSpecs::Child.public_method_2.should == nil + ModuleSpecs::Child.public_method_3.should == nil + end + + it "raises a NameError if class method doesn't exist" do + lambda { ModuleSpecs.public_class_method :no_method_here }.should raise_error(NameError) + end + + it "makes a class method public" do + c = Class.new do + def self.foo() "foo" end + public_class_method :foo + end + + c.foo.should == "foo" + end + + it "raises a NameError when the given name is not a method" do + lambda { + c = Class.new do + public_class_method :foo + end + }.should raise_error(NameError) + end + + it "raises a NameError when the given name is an instance method" do + lambda { + c = Class.new do + def foo() "foo" end + public_class_method :foo + end + }.should raise_error(NameError) + end +end diff --git a/1.8/core/module/public_instance_methods_spec.rb b/1.8/core/module/public_instance_methods_spec.rb new file mode 100644 index 0000000000..afb7992f25 --- /dev/null +++ b/1.8/core/module/public_instance_methods_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#public_instance_methods" do + it "returns a list of public methods in module and its ancestors" do + methods = ModuleSpecs::CountsMixin.public_instance_methods + methods.should include('public_3') + + methods = ModuleSpecs::CountsParent.public_instance_methods + methods.should include('public_3') + methods.should include('public_2') + + methods = ModuleSpecs::CountsChild.public_instance_methods + methods.should include('public_3') + methods.should include('public_2') + methods.should include('public_1') + + methods = ModuleSpecs::Child2.public_instance_methods + methods.should include('foo') + end + + it "when passed false as a parameter, should return only methods defined in that module" do + ModuleSpecs::CountsMixin.public_instance_methods(false).should == ['public_3'] + ModuleSpecs::CountsParent.public_instance_methods(false).should == ['public_2'] + ModuleSpecs::CountsChild.public_instance_methods(false).should == ['public_1'] + end + + it "default list should be the same as passing true as an argument" do + ModuleSpecs::CountsMixin.public_instance_methods(true).should == + ModuleSpecs::CountsMixin.public_instance_methods + ModuleSpecs::CountsParent.public_instance_methods(true).should == + ModuleSpecs::CountsParent.public_instance_methods + ModuleSpecs::CountsChild.public_instance_methods(true).should == + ModuleSpecs::CountsChild.public_instance_methods + end +end diff --git a/1.8/core/module/public_method_defined_spec.rb b/1.8/core/module/public_method_defined_spec.rb new file mode 100644 index 0000000000..1a022b3916 --- /dev/null +++ b/1.8/core/module/public_method_defined_spec.rb @@ -0,0 +1,60 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#public_method_defined?" do + it "returns true if the named public method is defined by module or its ancestors" do + ModuleSpecs::CountsMixin.public_method_defined?("public_3").should == true + + ModuleSpecs::CountsParent.public_method_defined?("public_3").should == true + ModuleSpecs::CountsParent.public_method_defined?("public_2").should == true + + ModuleSpecs::CountsChild.public_method_defined?("public_3").should == true + ModuleSpecs::CountsChild.public_method_defined?("public_2").should == true + ModuleSpecs::CountsChild.public_method_defined?("public_1").should == true + end + + it "returns false if method is not a public method" do + ModuleSpecs::CountsChild.public_method_defined?("private_3").should == false + ModuleSpecs::CountsChild.public_method_defined?("private_2").should == false + ModuleSpecs::CountsChild.public_method_defined?("private_1").should == false + + ModuleSpecs::CountsChild.public_method_defined?("protected_3").should == false + ModuleSpecs::CountsChild.public_method_defined?("protected_2").should == false + ModuleSpecs::CountsChild.public_method_defined?("protected_1").should == false + end + + it "returns false if the named method is not defined by the module or its ancestors" do + ModuleSpecs::CountsMixin.public_method_defined?(:public_10).should == false + end + + it "accepts symbols for the method name" do + ModuleSpecs::CountsMixin.public_method_defined?(:public_3).should == true + end + + compliant_on :ruby, :jruby do + it "raises an ArgumentError if called with a Fixnum" do + lambda { ModuleSpecs::CountsMixin.public_method_defined?(1) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a Symbol" do + lambda { ModuleSpecs::CountsMixin.public_method_defined?(nil) }.should raise_error(TypeError) + lambda { ModuleSpecs::CountsMixin.public_method_defined?(false) }.should raise_error(TypeError) + + sym = mock('symbol') + def sym.to_sym() :public_3 end + lambda { ModuleSpecs::CountsMixin.public_method_defined?(sym) }.should raise_error(TypeError) + end + end + + it "accepts any object that is a String type" do + str = mock('public_3') + def str.to_str() 'public_3' end + ModuleSpecs::CountsMixin.public_method_defined?(str).should == true + end + + deviates_on :rubinius do + it "raises a TypeError if not passed a String type" do + lambda { ModuleSpecs::CountsMixin.public_method_defined?(mock('x')) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/module/public_spec.rb b/1.8/core/module/public_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/core/module/public_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/core/module/remove_class_variable_spec.rb b/1.8/core/module/remove_class_variable_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/core/module/remove_class_variable_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/core/module/remove_const_spec.rb b/1.8/core/module/remove_const_spec.rb new file mode 100644 index 0000000000..4d232990d5 --- /dev/null +++ b/1.8/core/module/remove_const_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Module#remove_const" do + it "returns the value of the removed constant" do + ModuleSpecs::Internal::ONE = 1 + ModuleSpecs::Internal.send(:remove_const, :ONE).should == 1 + lambda { ModuleSpecs::Internal.send(:remove_const, :ONE) }.should raise_error(NameError) + end + + it "is a private method" do + ModuleSpecs::Internal::TWO = 2 + lambda { ModuleSpecs::Internal.remove_const(:TWO) }.should raise_error(NameError) + ModuleSpecs::Internal.send(:remove_const, :TWO).should == 2 + end +end + diff --git a/1.8/core/module/remove_method_spec.rb b/1.8/core/module/remove_method_spec.rb new file mode 100644 index 0000000000..358877984c --- /dev/null +++ b/1.8/core/module/remove_method_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +module ModuleSpecs + class NoInheritance + def method_to_remove; 1; end + + remove_method :method_to_remove + end + + class Parent + def method_to_remove; 1; end + end + + class Child < Parent + def method_to_remove; 2; end + + remove_method :method_to_remove + end + + class First + def method_to_remove; 1; end + end + + class Second < First + def method_to_remove; 2; end + end +end + +describe "Module#remove_method" do + it "removes the method from a class" do + x = ModuleSpecs::NoInheritance.new + x.respond_to?(:method_to_remove).should == false + end + + it "removes method from subclass, but not parent" do + x = ModuleSpecs::Child.new + x.respond_to?(:method_to_remove).should == true + x.method_to_remove.should == 1 + end + + it "raises a NameError when attempting to remove method further up the inheritance tree" do + lambda { + class Third < ModuleSpecs::Second + remove_method :method_to_remove + end + }.should raise_error(NameError) + end + + it "raises a NameError when attempting to remove a missing method" do + lambda { + class Third < ModuleSpecs::Second + remove_method :blah + end + }.should raise_error(NameError) + end +end diff --git a/1.8/core/module/shared/class_eval.rb b/1.8/core/module/shared/class_eval.rb new file mode 100644 index 0000000000..3f8b541cf4 --- /dev/null +++ b/1.8/core/module/shared/class_eval.rb @@ -0,0 +1,46 @@ +shared :module_class_eval do |cmd| + describe "Module##{cmd}" do + it "evaluates a given string in the context of self" do + ModuleSpecs.send(cmd, "self").should == ModuleSpecs + ModuleSpecs.send(cmd, "1 + 1").should == 2 + end + + it "evaluates a given block in the context of self" do + ModuleSpecs.send(cmd) { self }.should == ModuleSpecs + ModuleSpecs.send(cmd) { 1 + 1 }.should == 2 + end + + it "uses the optional filename and lineno parameters for error messages" do + ModuleSpecs.send(cmd, "[__FILE__, __LINE__]", "test", 102).should == ["test", 102] + end + + it "converts non string eval-string to string using to_str" do + (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1") + ModuleSpecs.send(cmd, o).should == 2 + end + + it "raises a TypeError when the given eval-string can't be converted to string using to_str" do + o = mock('x') + lambda { ModuleSpecs.send(cmd, o) }.should raise_error(TypeError) + + (o = mock('123')).should_receive(:to_str).and_return(123) + lambda { ModuleSpecs.send(cmd, o) }.should raise_error(TypeError) + end + + it "raises an ArgumentError when no arguments and no block are given" do + lambda { ModuleSpecs.send(cmd) }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when more than 3 arguments are given" do + lambda { + ModuleSpecs.send(cmd, "1 + 1", "some file", 0, "bogus") + }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when a block and normal arguments are given" do + lambda { + ModuleSpecs.send(cmd, "1 + 1") { 1 + 1 } + }.should raise_error(ArgumentError) + end + end +end diff --git a/1.8/core/module/shared/equal_value.rb b/1.8/core/module/shared/equal_value.rb new file mode 100644 index 0000000000..8366e0f2f9 --- /dev/null +++ b/1.8/core/module/shared/equal_value.rb @@ -0,0 +1,16 @@ +shared :module_equal do |cmd| + describe "Module##{cmd}(other)" do + it "returns true if self and the given module are the same" do + ModuleSpecs.send(cmd, ModuleSpecs).should == true + ModuleSpecs::Child.send(cmd, ModuleSpecs::Child).should == true + ModuleSpecs::Parent.send(cmd, ModuleSpecs::Parent).should == true + ModuleSpecs::Basic.send(cmd, ModuleSpecs::Basic).should == true + ModuleSpecs::Super.send(cmd, ModuleSpecs::Super).should == true + + ModuleSpecs::Child.send(cmd, ModuleSpecs).should == false + ModuleSpecs::Child.send(cmd, ModuleSpecs::Parent).should == false + ModuleSpecs::Child.send(cmd, ModuleSpecs::Basic).should == false + ModuleSpecs::Child.send(cmd, ModuleSpecs::Super).should == false + end + end +end diff --git a/1.8/core/module/to_s_spec.rb b/1.8/core/module/to_s_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/core/module/to_s_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/core/module/undef_method_spec.rb b/1.8/core/module/undef_method_spec.rb new file mode 100644 index 0000000000..96d45f2fbb --- /dev/null +++ b/1.8/core/module/undef_method_spec.rb @@ -0,0 +1,85 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +module ModuleSpecs + class NoInheritance + def method_to_undef() 1 end + def another_method_to_undef() 1 end + end + + class Parent + def method_to_undef() 1 end + def another_method_to_undef() 1 end + end + + class Child < Parent + end + + class Ancestor + def method_to_undef() 1 end + def another_method_to_undef() 1 end + end + + class Descendant < Ancestor + end +end + +describe "Module#undef_method with symbol" do + it "removes a method defined in a class" do + x = ModuleSpecs::NoInheritance.new + + x.method_to_undef.should == 1 + + ModuleSpecs::NoInheritance.send :undef_method, :method_to_undef + + lambda { x.method_to_undef }.should raise_error(NoMethodError) + end + + it "removes a method defined in a super class" do + child = ModuleSpecs::Child.new + child.method_to_undef.should == 1 + + ModuleSpecs::Child.send :undef_method, :method_to_undef + + lambda { child.method_to_undef }.should raise_error(NoMethodError) + end + + it "does not remove a method defined in a super class when removed from a subclass" do + ancestor = ModuleSpecs::Ancestor.new + ancestor.method_to_undef.should == 1 + + ModuleSpecs::Descendant.send :undef_method, :method_to_undef + + ancestor.method_to_undef.should == 1 + end +end + +describe "Module#undef_method with string" do + it "removes a method defined in a class" do + x = ModuleSpecs::NoInheritance.new + + x.another_method_to_undef.should == 1 + + ModuleSpecs::NoInheritance.send :undef_method, 'another_method_to_undef' + + lambda { x.another_method_to_undef }.should raise_error(NoMethodError) + end + + it "removes a method defined in a super class" do + child = ModuleSpecs::Child.new + child.another_method_to_undef.should == 1 + + ModuleSpecs::Child.send :undef_method, 'another_method_to_undef' + + lambda { child.another_method_to_undef }.should raise_error(NoMethodError) + end + + it "does not remove a method defined in a super class when removed from a subclass" do + ancestor = ModuleSpecs::Ancestor.new + ancestor.another_method_to_undef.should == 1 + + ModuleSpecs::Descendant.send :undef_method, 'another_method_to_undef' + + ancestor.another_method_to_undef.should == 1 + end +end diff --git a/1.8/core/nil/and_spec.rb b/1.8/core/nil/and_spec.rb new file mode 100644 index 0000000000..6fddbae7ba --- /dev/null +++ b/1.8/core/nil/and_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#&" do + it "returns false" do + (nil & nil).should == false + (nil & true).should == false + (nil & false).should == false + (nil & "").should == false + (nil & mock('x')).should == false + end +end diff --git a/1.8/core/nil/dup_spec.rb b/1.8/core/nil/dup_spec.rb new file mode 100644 index 0000000000..abeb31be72 --- /dev/null +++ b/1.8/core/nil/dup_spec.rb @@ -0,0 +1,5 @@ +describe "NilClass#dup" do + it "raises a TypeError" do + lambda { nil.dup }.should raise_error(TypeError) + end +end diff --git a/1.8/core/nil/inspect_spec.rb b/1.8/core/nil/inspect_spec.rb new file mode 100644 index 0000000000..c5c3b9ae41 --- /dev/null +++ b/1.8/core/nil/inspect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#inspect" do + it "returns the string 'nil'" do + nil.inspect.should == "nil" + end +end diff --git a/1.8/core/nil/nil_spec.rb b/1.8/core/nil/nil_spec.rb new file mode 100644 index 0000000000..b81a509d8e --- /dev/null +++ b/1.8/core/nil/nil_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#nil?" do + it "returns true" do + nil.nil?.should == true + end +end diff --git a/1.8/core/nil/or_spec.rb b/1.8/core/nil/or_spec.rb new file mode 100644 index 0000000000..4eaccd6b5c --- /dev/null +++ b/1.8/core/nil/or_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#|" do + it "returns false if other is nil or false, otherwise true" do + (nil | nil).should == false + (nil | true).should == true + (nil | false).should == false + (nil | "").should == true + (nil | mock('x')).should == true + end +end diff --git a/1.8/core/nil/to_a_spec.rb b/1.8/core/nil/to_a_spec.rb new file mode 100644 index 0000000000..e2519ffe46 --- /dev/null +++ b/1.8/core/nil/to_a_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#to_a" do + it "returns an empty array" do + nil.to_a.should == [] + end +end diff --git a/1.8/core/nil/to_f_spec.rb b/1.8/core/nil/to_f_spec.rb new file mode 100644 index 0000000000..4ab6c097f1 --- /dev/null +++ b/1.8/core/nil/to_f_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#to_f" do + it "returns 0.0" do + nil.to_f.should == 0.0 + end + + it "does not cause NilClass to be coerced to Float" do + (0.0 == nil).should == false + end +end diff --git a/1.8/core/nil/to_i_spec.rb b/1.8/core/nil/to_i_spec.rb new file mode 100644 index 0000000000..2d08b18965 --- /dev/null +++ b/1.8/core/nil/to_i_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#to_i" do + it "returns 0" do + nil.to_i.should == 0 + end + + it "does not cause NilClass to be coerced to Fixnum" do + (0 == nil).should == false + end +end diff --git a/1.8/core/nil/to_s_spec.rb b/1.8/core/nil/to_s_spec.rb new file mode 100644 index 0000000000..3269afb07f --- /dev/null +++ b/1.8/core/nil/to_s_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#to_s" do + it "returns the string ''" do + nil.to_s.should == "" + end + + it "does not cause NilClass to be coerced to Fixnum" do + ("" == nil).should == false + end +end diff --git a/1.8/core/nil/xor_spec.rb b/1.8/core/nil/xor_spec.rb new file mode 100644 index 0000000000..84bbc8c23f --- /dev/null +++ b/1.8/core/nil/xor_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "NilClass#^" do + it "returns false if other is nil or false, otherwise true" do + (nil ^ nil).should == false + (nil ^ true).should == true + (nil ^ false).should == false + (nil ^ "").should == true + (nil ^ mock('x')).should == true + end +end diff --git a/1.8/core/numeric/abs_spec.rb b/1.8/core/numeric/abs_spec.rb new file mode 100644 index 0000000000..6b1db24dd1 --- /dev/null +++ b/1.8/core/numeric/abs_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# Returns the absolute value of num. +describe "Numeric#abs" do + it "return the abs (integers) " do + 0.abs.should == 0 + 100.abs.should == 100 + -100.abs.should == 100 + end + + it "return the abs (floats) " do + 0.0.abs.should == 0.0 + 34.56.abs.should == 34.56 + -34.56.abs.should == 34.56 + end + + it "return the abs (two complement)" do + 2147483648.abs.should == 2147483648 + -2147483648.abs.should == 2147483648 + 9223372036854775808.abs.should == 9223372036854775808 + -9223372036854775808.abs.should == 9223372036854775808 + end +end diff --git a/1.8/core/numeric/ceil_spec.rb b/1.8/core/numeric/ceil_spec.rb new file mode 100644 index 0000000000..ce92f1d1c7 --- /dev/null +++ b/1.8/core/numeric/ceil_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#ceil" do + it "returns the smallest Integer greater than or equal to self when passed a Fixnum" do + 0.ceil.should == 0 + 100.ceil.should == 100 + -100.ceil.should == -100 + end + + it "returns the smallest Integer greater than or equal to self when passed a Float" do + 0.ceil.should == 0.0 + 34.56.ceil.should == 35 + -34.56.ceil.should == -34 + end + + it "returns the smallest Integer greater than or equal to self when passed a Bignum" do + # FIXME: use bignum_value helper + 2147483648.ceil.should == 2147483648 + -2147483648.ceil.should == -2147483648 + 9223372036854775808.ceil.should == 9223372036854775808 + -9223372036854775808.ceil.should == -9223372036854775808 + end +end diff --git a/1.8/core/numeric/coerce_spec.rb b/1.8/core/numeric/coerce_spec.rb new file mode 100644 index 0000000000..38c7f8935f --- /dev/null +++ b/1.8/core/numeric/coerce_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# FIXME: this awful wording +describe "Numeric#coerce" do + before(:each) do + @integer = 1 + @float = 2.5 + end + + it "coerce integers" do + @integer.coerce(@integer).should == [1,1] + @integer.coerce(@float).should ==[2.5,1] + end + + it "coerce floats" do + @float.coerce(@float).should == [2.5,2.5] + @float.coerce(@integer).should == [1,2.5] + end + + it "coerce with 0" do + @integer.coerce(0).should == [0,1] + @float.coerce(0).should == [0,2.5] + end + + it "coerce with bignums" do + @integer.coerce(4294967296).should == [4294967296, 1] + @float.coerce(4294967296).should == [4294967296.0, 2.5] + end + + it "coerces strings to numerics" do + @integer.coerce("1").should == [1.0, 1.0] + @integer.coerce("3.32").should == [3.32, 1.0] + @float.coerce("1").should == [1.0, 2.5] + @float.coerce("3.32").should == [3.32, 2.5] + end + + it "return the vaule if number is different to 0" do + lambda { @integer.coerce("test") }.should raise_error(ArgumentError) + lambda { @integer.coerce }.should raise_error(ArgumentError) + lambda { @integer.coerce(nil) }.should raise_error(TypeError) + lambda { @integer.coerce(false) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/numeric/comparison_spec.rb b/1.8/core/numeric/comparison_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/numeric/comparison_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/numeric/div_spec.rb b/1.8/core/numeric/div_spec.rb new file mode 100644 index 0000000000..2a429a6489 --- /dev/null +++ b/1.8/core/numeric/div_spec.rb @@ -0,0 +1,42 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#div" do + it "returns the integer quotient of two Integers" do + 13.div(4).should == 3 + 4.div(13).should == 0 + end + + it "returns the integer quotient of an Integer and a Float" do + 13.div(4.0).should == 3 + 4.div(13.0).should == 0 + end + + it "returns the integer quotient of a Float and an Integer" do + (13.0).div(4).should == 3 + (4.0).div(13).should == 0 + end + + it "returns the integer quotient of two Floats" do + (13.0).div(4.0).should == 3 + (4.0).div(13.0).should == 0 + end + + it "returns the integer quotient of a Bignum and an Integer" do + bignum_value(0).div(100).should == 92233720368547758 + end + + it "raises an ArgumentError if not passed one argument" do + lambda { 13.div }.should raise_error(ArgumentError) + lambda { 13.div(1, 2) }.should raise_error(ArgumentError) + end + + it "raises a ZeroDivisionError if passed 0" do + lambda { 13.div(0) }.should raise_error(ZeroDivisionError) + end + + it "raises a TypeError if not passed a Numeric type" do + lambda { 13.div(nil) }.should raise_error(TypeError) + lambda { 13.div('test') }.should raise_error(TypeError) + lambda { 13.div(true) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/numeric/divmod_spec.rb b/1.8/core/numeric/divmod_spec.rb new file mode 100644 index 0000000000..1714ec752d --- /dev/null +++ b/1.8/core/numeric/divmod_spec.rb @@ -0,0 +1,59 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# Returns an array containing the quotient and modulus obtained +# by dividing num by aNumeric. If q, r = x.divmod(y), then +# q = floor(float(x)/float(y)) +# x = q*y + r + +describe "Numeric#divmod" do + it "returns self divmod other" do + (3**33).divmod(100).should == [55590605665555, 23] + end + + it "returns an Integer [quotient, modulus] when operating with Integers" do + 13.divmod(4).should == [3,1] + 4.divmod(13).should == [0,4] + end + + it "returns [quotent, modulus] where modulus may be Float or Integer when operating with Integers and Floats" do + 13.divmod(4.0).should == [3,1] + 4.divmod(13.0).should == [0,4] + a, b = 13.divmod(4.6) + a.should == 2 + b.should be_close(3.8, TOLERANCE) + end + + it "returns a Float [quotient, modulus] when operating with Floats" do + 13.0.divmod(4.0).should == [3.0,1.0] + 4.0.divmod(13).should == [0.0,4.0] + y = 1 / 12.0 + 0.58.divmod(y).first.should == 6 + 0.67.divmod(y).first.should == 8 + end + + ruby_bug do + # MRI 1.8.6 bug Numeric#divmod bug + # http://rubyforge.org/tracker/?func=detail&atid=1698&aid=14540&group_id=426 + it "returns a Float [quotient, modulus] when operating with Floats" do + y = 1 / 12.0 + 0.59.divmod(y).first.should == 7 + 0.63.divmod(y).first.should == 7 + 0.66.divmod(y).first.should == 7 + end + end + + it "raises an ArgumentError when not passed one argument" do + lambda { 13.divmod }.should raise_error(ArgumentError) + lambda { 13.divmod(1, 2) }.should raise_error(ArgumentError) + end + + it "raises a ZeroDivisionError when passed 0" do + lambda { 13.divmod(0) }.should raise_error(ZeroDivisionError) + end + + it "raises a TypeError when not passed a Numeric type" do + lambda { 13.divmod(nil) }.should raise_error(TypeError) + lambda { 13.divmod('test') }.should raise_error(TypeError) + lambda { 13.divmod(true) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/numeric/eql_spec.rb b/1.8/core/numeric/eql_spec.rb new file mode 100644 index 0000000000..13bbee118d --- /dev/null +++ b/1.8/core/numeric/eql_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#eql?" do + before(:each) do + @integer = 1 + @float = 1.0 + @bignum = 4294967296 + @bigfloat = 4294967296.0 + @numeric = Numeric.new + end + + after(:each) do + @integer = nil + @float = nil + @bignum = nil + @bigfloat = nil + @numeric = nil + end + + it "be equal (integers and floats)" do + @integer.eql?(@integer).should == true + @integer.eql?(@float).should == false + @float.eql?(@float).should == true + @float.eql?(@integer).should == false + end + + it " should be equal (bignums and floats " do + @bignum.eql?(@bignum).should == true + @bignum.eql?(@bigfloat).should == false + end + + it "be equal (edge cases)" do + 0.eql?(0).should == true + 1.0.eql?(1.00000000000000000000).should == true + 0.eql?(0.0).should == false + 000000.eql?(0.0).should == false + 000000.eql?(000) .should == true + @numeric.eql?(@numeric).should == true + @numeric.eql?(Numeric.new).should == false + end +end diff --git a/1.8/core/numeric/floor_spec.rb b/1.8/core/numeric/floor_spec.rb new file mode 100644 index 0000000000..5c8a21ac17 --- /dev/null +++ b/1.8/core/numeric/floor_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# Returns the largest integer less than or equal to num. Numeric implements +# this by converting anInteger to a Float and invoking Float#floor. +describe "Numeric#floor" do + it "return the largest integer less than or equal to num (integer)" do + 0.floor.should == 0 + 100.floor.should == 100 + -100.floor.should == -100 + end + + it "return the largest integer less than or equal to num (two complement)" do + 2147483648.floor.should == 2147483648 + -2147483648.floor.should == -2147483648 + 9223372036854775808.floor.should == 9223372036854775808 + -9223372036854775808.floor.should == -9223372036854775808 + end +end diff --git a/1.8/core/numeric/initialize_copy_spec.rb b/1.8/core/numeric/initialize_copy_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/numeric/initialize_copy_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/numeric/integer_spec.rb b/1.8/core/numeric/integer_spec.rb new file mode 100644 index 0000000000..543488ec47 --- /dev/null +++ b/1.8/core/numeric/integer_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# Returns true if num is an Integer (including Fixnum and Bignum). +describe "Numeric#integer?" do + it "retrun true if the num is an integer?" do + 0.integer?.should == true + 100.integer?.should == true + -100.integer?.should == true + 34.56.integer?.should == false + -34.56.integer?.should == false + 2147483648.integer?.should == true + -2147483648.integer?.should == true + 9223372036854775808.integer?.should == true + -9223372036854775808.integer?.should == true + end +end diff --git a/1.8/core/numeric/modulo_spec.rb b/1.8/core/numeric/modulo_spec.rb new file mode 100644 index 0000000000..fa7baee139 --- /dev/null +++ b/1.8/core/numeric/modulo_spec.rb @@ -0,0 +1,89 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#modulo" do + it " zero modulo x should be 0 (integer) " do + 0.modulo(100).should == 0 + 0.modulo(-100).should == 0 + end + + it " zero modulo x should be 0 (float) " do + 0.modulo(34.56).should == 0 + 0.modulo(-34.56).should == 0 + end + + it " zero modulo x should be 0 (bignum) " do + 0.modulo(2147483648).should == 0 + 0.modulo(-2147483648).should == 0 + end + + it "y modulo x should be z (integer - integer) " do + 100.modulo(100).should == 0 + 100.modulo(-100).should == 0 + -100.modulo(100).should == 0 + -100.modulo(-100).should == 0 + end + + it "y modulo x should be z (integer - float) " do + 100.modulo(34.56).should be_close(30.88,TOLERANCE) + 100.modulo(-34.56).should be_close(-3.68000000000001,TOLERANCE) + -100.modulo(34.56).should be_close(3.68000000000001 ,TOLERANCE) + -100.modulo(-34.56).should be_close(-30.88,TOLERANCE) + end + + it "y modulo x should be z (integer - bignum) " do + 100.modulo(2147483648).should == 100 + 100.modulo(-2147483648).should == -2147483548 + -100.modulo(-2147483648).should == -100 + -100.modulo(2147483648).should == 2147483548 + end + + it "modulo x should be z (floats and integers)"do + 34.56.modulo(100).should be_close(34.56,TOLERANCE) + 34.56.modulo(-100).should be_close(-65.44,TOLERANCE) + -34.56.modulo(-100).should be_close(-34.56,TOLERANCE) + -34.56.modulo(100).should be_close(65.44,TOLERANCE) + end + + it "modulo x should be z (float - float)"do + 34.56.modulo(34.56).should be_close(0.0,TOLERANCE) + 34.56.modulo(-34.56).should be_close(0.0,TOLERANCE) + -34.56.modulo(-34.56).should be_close(0.0,TOLERANCE) + -34.56.modulo(34.56).should be_close(0.0,TOLERANCE) + end + + it "modulo x should be z (float - bignum)"do + 34.56.modulo(2147483648).should be_close(34.56,TOLERANCE) + 34.56.modulo(-2147483648).should be_close(-2147483613.44 ,TOLERANCE) + -34.56.modulo(2147483648).should be_close(2147483613.44 ,TOLERANCE) + end + + it "y modulo x should be z (bignum -integer) "do + 2147483648.modulo(100).should == 48 + 2147483648.modulo(-100).should == -52 + -2147483648.modulo(100).should == 52 + -2147483648.modulo(-100).should == -48 + end + + it "y modulo x should be z (bignum - float) "do + 2147483648.modulo(34.56).should be_close(1.27999985871492, TOLERANCE) + -2147483648.modulo(34.56).should be_close(33.2800001412851 , TOLERANCE) + 2147483648.modulo(-34.56).should be_close(-33.2800001412851 , TOLERANCE) + -2147483648.modulo(-34.56).should be_close(-1.27999985871492, TOLERANCE) + end + + it "y modulo x should be z (bignum - bignum) "do + 2147483648.modulo(2147483648).should == 0 + -2147483648.modulo(2147483648).should == 0 + 2147483648.modulo(-2147483648).should == 0 + -2147483648.modulo(-2147483648).should == 0 + end + + it " should NOT raise ZeroDivisionError if other is zero and is a Float" do + 1.modulo(0.0).to_s.should == 'NaN' + 1.modulo(0.0).to_s.should == 'NaN' + end + + it " should raise an Exception when divide by 0 (non float)" do + lambda { 13.modulo(0) }.should raise_error(ZeroDivisionError) + end +end diff --git a/1.8/core/numeric/nonzero_spec.rb b/1.8/core/numeric/nonzero_spec.rb new file mode 100644 index 0000000000..0b210cd5f2 --- /dev/null +++ b/1.8/core/numeric/nonzero_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# Returns num if num is not zero, nil otherwise. +# This behavior is useful when chaining comparisons: +describe "Numeric#nonzero?" do + it "returns nil if the number is zero" do + 0.nonzero?.should == nil + end + + it "returns the value if number is different to 0" do + 1.nonzero?.should == 1 + 2.nonzero?.should == 2 + end +end diff --git a/1.8/core/numeric/quo_spec.rb b/1.8/core/numeric/quo_spec.rb new file mode 100644 index 0000000000..43c42b259f --- /dev/null +++ b/1.8/core/numeric/quo_spec.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# Equivalent to Numeric#/, but overridden in subclasses. +describe "Numeric#quo" do + it "returns the floating-point result of self divided by other" do + # the to_f is required because RSpec (I'm assuming) requires 'rational' + 2.quo(2.5).to_s.should == '0.8' + 5.quo(2).to_f.to_s.should == '2.5' + end + + it "does not raise an exception when other is zero" do + # 1.quo(0) should also not raise (i.e works in irb and from a file), + # but fails here. + 1.quo(0.0).to_s.should == 'Infinity' + 1.quo(-0.0).to_s.should == '-Infinity' + bignum_value.quo(0.0).to_s.should == 'Infinity' + end + + it "returns the floating-point result of dividing two Fixnums" do + 13.quo(4).should be_close(3.25, TOLERANCE) + 4.quo(13).should be_close( 0.307692307692308, TOLERANCE) + end + + it "returns the floating-point result of dividing a Fixnum by a Float" do + 13.quo(4.0).should be_close(3.25, TOLERANCE) + 4.quo(13.0).should be_close(0.307692307692308, TOLERANCE) + end + + it "returns the floating-point result of dividing two Floats" do + 13.0.quo(4.0).should be_close(3.25, TOLERANCE) + 4.0.quo(13.0).should be_close(0.307692307692308, TOLERANCE) + end + + it "returns the floating_point result of dividing a Bignum by a Fixnum" do + bignum_value.quo(100).should == 92233720368547760.0 + end + + it "raises an ArgumentError when not passed one argument" do + lambda { 13.quo }.should raise_error(ArgumentError) + lambda { 13.quo(1, 2) }.should raise_error(ArgumentError) + end + + conflicts_with :Rational do + it "raises a TypeError when not passed a Numeric type" do + lambda { 13.quo(nil) }.should raise_error(TypeError) + lambda { 13.quo('test') }.should raise_error(TypeError) + lambda { 13.quo(true) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/numeric/remainder_spec.rb b/1.8/core/numeric/remainder_spec.rb new file mode 100644 index 0000000000..0bb7d2c64d --- /dev/null +++ b/1.8/core/numeric/remainder_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# If num and numeric have different signs, returns mod-numeric; +# otherwise, returns mod. In both cases mod is the value num.modulo(numeric) +describe "Numeric#remainder" do + it "remainder the right integers" do + 13.remainder(4).should == 1 + 13.remainder(-4).should == 1 + -13.remainder(4).should == -1 + -13.remainder(-4).should == -1 + end + + it "remainder right integers and floats" do + 13.remainder(4.0).should == 1.0 + 13.remainder(-4.0).should == 1.0 + -13.remainder(4.0).should == -1.0 + -13.remainder(-4.0).should == -1.0 + end + + it "remainder right the integers and floats" do + 11.5.remainder(4.0).should == 3.5 + 11.5.remainder(-4.0).should == 3.5 + -11.5.remainder(4.0).should == -3.5 + -11.5.remainder(-4.0).should == -3.5 + end + + it " should remainder right with bignums and integers" do + (3**33).remainder(-100).should == 23 + (3**33).remainder(100).should == 23 + (-2**31).remainder(2**31).should == 0 + (-2**31).remainder(2**31).should == 0 + end + + it "raises an ArgumentError when not passed one argument" do + lambda { 13.remainder }.should raise_error(ArgumentError) + lambda { 13.remainder(1, 2) }.should raise_error(ArgumentError) + end + + it "raises a ZeroDivisionError when passed 0" do + lambda { 13.remainder(0) }.should raise_error(ZeroDivisionError) + end + + it "raises a TypeError when not passed a Numeric type" do + lambda { 13.remainder(nil) }.should raise_error(TypeError) + lambda { 13.remainder('test') }.should raise_error(TypeError) + lambda { 13.remainder(true) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/numeric/round_spec.rb b/1.8/core/numeric/round_spec.rb new file mode 100644 index 0000000000..e50888c973 --- /dev/null +++ b/1.8/core/numeric/round_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# Rounds num to the nearest integer +describe "Numeric#round" do + it " round (down) " do + 0.round.should == 0.0 + 100.round.should == 100 + -100.round.should == -100 + end + + it " round (up) " do + 34.56.round.should == 35 + -34.56.round.should == -35 + end + + it " round twos complement " do + 9223372036854775808.round.should == 9223372036854775808 + -9223372036854775808.round.should == -9223372036854775808 + end +end diff --git a/1.8/core/numeric/singleton_method_added_spec.rb b/1.8/core/numeric/singleton_method_added_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/numeric/singleton_method_added_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/numeric/step_spec.rb b/1.8/core/numeric/step_spec.rb new file mode 100644 index 0000000000..f7f2941b8b --- /dev/null +++ b/1.8/core/numeric/step_spec.rb @@ -0,0 +1,115 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# Invokes block with the sequence of numbers starting at num, incremented by +# step on each call. The loop finishes when the value to be passed to the block +# is greater than limit (if step is positive) or less than limit (if step is negative). +# If all the arguments are integers, the loop operates using an integer counter. +describe "Numeric#step" do + before(:each) do + @step = 2 + @stepn = -2 + @stepnf = -2 + @stepf = 2.0 + @limitf = 10.0 + @limit = 10 + @base = 1 + @basef = 5.4 + end + + it "if base < limit > step then it should iterate (base-limit)/step times (integers)" do + x = [] + @base.step(@limit, @step) { |i| x << i } + x.should == [1, 3, 5, 7, 9] + end + + it "iterate one time if step is bigger than base-limit (integers)" do + x = [] + @base.step(@limit, 11) { |i| x<< i } + x.should == [1] + end + + it "not iterate if base is bigger than limit and step >0 (integers)" do + x = [] + 12.step(@limit, @step) { |i| x<< i } + x.should == [] + end + + it "iterate backward if base is bigger than limit (integers)" do + x = [] + 10.step(1, @stepn) { |i| x << i} + x.should == [10, 8, 6, 4, 2] + end + + it "not iterate if base is minor than limit and step <0 (integers)" do + x = [] + res = @base.step(@limit, @stepn) { |i| x<< i } + x.should == [] + res.should == @base + end + + it "if base < limit > step then it should iterate (base-limit)/step times (integers)" do + x = [] + @base.step(@limit, @step) { |i| x << i } + x.should == [1, 3, 5, 7, 9] + end + + it "iterate one time if step is bigger than base-limit (integers)" do + x = [] + @base.step(@limit, 11) { |i| x<< i } + x.should == [1] + end + + it "if base < limit > step then it should iterate (base-limit)/step times (floats)" do + x = [] + @basef.step(@limitf, @stepf) { |i| x << i } + x.should == [5.4, 7.4, 9.4] + end + + it "iterate one time if step is bigger than base-limit (floats)" do + x = [] + @basef.step(@limitf, 11) { |i| x<< i } + x.should == [5.4] + end + + it "not iterate if base is bigger than limit and step >0 (floats)" do + x = [] + res = 12.0.step(@limitf, @stepf) { |i| x<< i } + x.should == [] + res.should == 12.0 + end + + it "iterate backward if base is bigger than limit (floats)" do + x = [] + res = 10.0.step(1.0, @stepnf) { |i| x << i} + x.should == [10, 8, 6, 4, 2] + res.should == 10.0 + end + + it "not iterate if base is minor than limit and step <0 (floats)" do + x = [] + res = @basef.step(@limitf, @stepnf) { |i| x<< i } + x.should == [] + res.should == @basef + end + + it "if base < limit > step then iterate (base-limit)/step times (floats)" do + x = [] + @basef.step(@limitf, @stepf) { |i| x << i } + x.should == [5.4, 7.4, 9.4] + end + + it "raises an ArgumentError if not passed not passed Numeric types in the correct range" do + lambda { @base.step }.should raise_error(ArgumentError) + lambda { @base.step(100,0) }.should raise_error(ArgumentError) + lambda { @base.step(nil) }.should raise_error(ArgumentError) + lambda { @base.step('test') }.should raise_error(ArgumentError) + lambda { @base.step(true, 123) }.should raise_error(ArgumentError) + end + + it "raises a LocalJumpError if not provided a block" do + lambda { @base.step(5, 5) }.should raise_error(LocalJumpError) + lambda { @base.step(5, 3.4) }.should raise_error(LocalJumpError) + lambda { @base.step(5.0, 2) }.should raise_error(LocalJumpError) + lambda { @base.step(5.0, 1.0) }.should raise_error(LocalJumpError) + end +end diff --git a/1.8/core/numeric/to_int_spec.rb b/1.8/core/numeric/to_int_spec.rb new file mode 100644 index 0000000000..45e37f1494 --- /dev/null +++ b/1.8/core/numeric/to_int_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#to_int" do + it "return the integer (integers)" do + 0.to_int.should == 0 + 100.to_int.should == 100 + -100.to_int.should == -100 + end + + it "return the integer part (float)" do + 34.56.to_int.should == 34 + -34.56.to_int.should == -34 + end + + it "return the integer part (two complement)" do + 2147483648.to_int.should == 2147483648 + -2147483648.to_int.should == -2147483648 + 9223372036854775808.to_int.should == 9223372036854775808 + -9223372036854775808.to_int.should == -9223372036854775808 + end +end diff --git a/1.8/core/numeric/truncate_spec.rb b/1.8/core/numeric/truncate_spec.rb new file mode 100644 index 0000000000..467c051b01 --- /dev/null +++ b/1.8/core/numeric/truncate_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#truncate" do + it " truncate integers " do + 0.truncate.should == 0.0 + 100.truncate.should == 100 + -100.truncate.should == -100 + end + + it " truncate floats " do + 34.56.truncate.should == 34 + -34.56.truncate.should == -34 + end + + it " truncate two complement " do + 2147483648.truncate.should == 2147483648 + -2147483648.truncate.should == -2147483648 + 9223372036854775808.truncate.should == 9223372036854775808 + -9223372036854775808.truncate.should == -9223372036854775808 + end +end diff --git a/1.8/core/numeric/uminus_spec.rb b/1.8/core/numeric/uminus_spec.rb new file mode 100644 index 0000000000..05ab633943 --- /dev/null +++ b/1.8/core/numeric/uminus_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#-@" do + it " should return the same value with opposite sign (integers)" do + 0.send(:-@).should == 0 + 100.send(:-@).should == -100 + -100.send(:-@).should == 100 + end + + it " should return the same value with opposite sign (floats)" do + 34.56.send(:-@).should == -34.56 + -34.56.send(:-@).should == 34.56 + end + + it " should return the same value with opposite sign (two complement)" do + 2147483648.send(:-@).should == -2147483648 + -2147483648.send(:-@).should == 2147483648 + 9223372036854775808.send(:-@).should == -9223372036854775808 + -9223372036854775808.send(:-@).should == 9223372036854775808 + end +end diff --git a/1.8/core/numeric/uplus_spec.rb b/1.8/core/numeric/uplus_spec.rb new file mode 100644 index 0000000000..15a9ff7c96 --- /dev/null +++ b/1.8/core/numeric/uplus_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#+@" do + it " should return the same value with opposite sign (integers)" do + 0.send(:+@).should == 0 + 100.send(:+@).should == 100 + -100.send(:+@).should == -100 + + end + + it " should return the same value with opposite sign (floats)" do + 34.56.send(:+@).should == 34.56 + -34.56.send(:+@).should == -34.56 + end + + it " should return the same value with opposite sign (floats)" do + (2**31).send(:+@).should == 2**31 + (-2**31).send(:+@).should == -2**31 + end + + it " should return the same value with opposite sign (two complement)" do + 2147483648.send(:+@).should == 2147483648 + -2147483648.send(:+@).should == -2147483648 + 9223372036854775808.send(:+@).should == 9223372036854775808 + -9223372036854775808.send(:+@).should == -9223372036854775808 + end +end diff --git a/1.8/core/numeric/zero_spec.rb b/1.8/core/numeric/zero_spec.rb new file mode 100644 index 0000000000..1331cbf037 --- /dev/null +++ b/1.8/core/numeric/zero_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Numeric#zero?" do + it "return the vaule if number is different to 0" do + 0.zero?.should == true + 1.zero?.should == false + end +end diff --git a/1.8/core/object/clone_spec.rb b/1.8/core/object/clone_spec.rb new file mode 100644 index 0000000000..fa2bc263e1 --- /dev/null +++ b/1.8/core/object/clone_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/dup_clone' + +describe "Object#clone" do + it_behaves_like :object_dup_clone, :clone +end + diff --git a/1.8/core/object/dup_spec.rb b/1.8/core/object/dup_spec.rb new file mode 100644 index 0000000000..a5245c8bc5 --- /dev/null +++ b/1.8/core/object/dup_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/dup_clone' + +describe "Object#dup" do + it_behaves_like :object_dup_clone, :dup +end diff --git a/1.8/core/object/initialize_spec.rb b/1.8/core/object/initialize_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/object/initialize_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/object/instance_of_P_spec.rb b/1.8/core/object/instance_of_P_spec.rb new file mode 100644 index 0000000000..6e25906d91 --- /dev/null +++ b/1.8/core/object/instance_of_P_spec.rb @@ -0,0 +1,53 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +module ObjectSpecs + module SomeOtherModule; end + module AncestorModule; end + module MyModule; end + + class AncestorClass < String + include AncestorModule + end + + class InstanceClass < AncestorClass + include MyModule + end +end + +describe Object, "#instance_of?" do + before(:each) do + @o = ObjectSpecs::InstanceClass.new + end + + it "returns true if given class is object's class" do + @o.instance_of?(ObjectSpecs::InstanceClass).should == true + [].instance_of?(Array).should == true + ''.instance_of?(String).should == true + end + + it "returns false if given class is object's ancestor class" do + @o.instance_of?(ObjectSpecs::AncestorClass).should == false + end + + it "returns false if given class is not object's class nor object's ancestor class" do + @o.instance_of?(Array).should == false + end + + it "returns false if given a Module that is included in object's class" do + @o.instance_of?(ObjectSpecs::MyModule).should == false + end + + it "returns false if given a Module that is included one of object's ancestors only" do + @o.instance_of?(ObjectSpecs::AncestorModule).should == false + end + + it "returns false if given a Module that is not included in object's class" do + @o.instance_of?(ObjectSpecs::SomeOtherModule).should == false + end + + it "raises a TypeError if given an object that is not a Class nor a Module" do + lambda { @o.instance_of?(Object.new) }.should raise_error(TypeError) + lambda { @o.instance_of?('ObjectSpecs::InstanceClass') }.should raise_error(TypeError) + lambda { @o.instance_of?(1) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/object/is_a_P_spec.rb b/1.8/core/object/is_a_P_spec.rb new file mode 100644 index 0000000000..c8bdee09fd --- /dev/null +++ b/1.8/core/object/is_a_P_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/kind_of' + +describe "Object#is_a?" do + it_behaves_like(:object_kind_of , :is_a?) +end diff --git a/1.8/core/object/kind_of_P_spec.rb b/1.8/core/object/kind_of_P_spec.rb new file mode 100644 index 0000000000..9afee91e27 --- /dev/null +++ b/1.8/core/object/kind_of_P_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/kind_of' + +describe "Object#kind_of?" do + it_behaves_like(:object_kind_of , :kind_of?) +end diff --git a/1.8/core/object/match_spec.rb b/1.8/core/object/match_spec.rb new file mode 100644 index 0000000000..2c772405da --- /dev/null +++ b/1.8/core/object/match_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Object, '=~' do + it 'returns false matching any object' do + o = Object.new + + (o =~ /Object/).should == false + (o =~ 'Object').should == false + (o =~ Object).should == false + (o =~ Object.new).should == false + (o =~ nil).should == false + (o =~ true).should == false + end +end diff --git a/1.8/core/object/metaclass_spec.rb b/1.8/core/object/metaclass_spec.rb new file mode 100644 index 0000000000..43bdb37f87 --- /dev/null +++ b/1.8/core/object/metaclass_spec.rb @@ -0,0 +1,9 @@ + +describe "Object#metaclass" do + it "returns the object's metaclass" do + foo = "foo" + foo.instance_eval "class << self; def meta_test_method; 5; end; end" + foo.respond_to?(:meta_test_method).should == true + lambda { "hello".metaclass.method(:meta_test_method) }.should raise_error(NameError) + end +end diff --git a/1.8/core/object/new_spec.rb b/1.8/core/object/new_spec.rb new file mode 100644 index 0000000000..21c512625d --- /dev/null +++ b/1.8/core/object/new_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Object.new" do + it "creates a new Object" do + Object.new.class.should == Object + end +end + diff --git a/1.8/core/object/shared/dup_clone.rb b/1.8/core/object/shared/dup_clone.rb new file mode 100644 index 0000000000..6a406d0bf9 --- /dev/null +++ b/1.8/core/object/shared/dup_clone.rb @@ -0,0 +1,56 @@ +class ObjectSpecDup + def initialize() + @obj = :original + end + + attr_accessor :obj +end + +class ObjectSpecDupInitCopy + def initialize() + @obj = :original + end + + attr_accessor :obj, :original + + def initialize_copy(original) + @obj = :init_copy + @original = original + end + + private :initialize_copy +end + +shared :object_dup_clone do |cmd| + describe "Object##{cmd}" do + it "returns a new object duplicated from the original" do + o = ObjectSpecDup.new + o2 = ObjectSpecDup.new + + o.obj = 10 + + o3 = o.send(cmd) + + o3.obj.should == 10 + o2.obj.should == :original + end + + it "produces a shallow copy, contained objects are not recursively dupped" do + o = ObjectSpecDup.new + array = [1, 2] + o.obj = array + + o2 = o.send(cmd) + o2.obj.equal?(o.obj).should == true + end + + it "calls #initialize_copy on the NEW object if available, passing in original object" do + o = ObjectSpecDupInitCopy.new + o2 = o.send(cmd) + + o.obj.should == :original + o2.obj.should == :init_copy + o2.original.equal?(o).should == true + end + end +end diff --git a/1.8/core/object/shared/kind_of.rb b/1.8/core/object/shared/kind_of.rb new file mode 100644 index 0000000000..92502ff386 --- /dev/null +++ b/1.8/core/object/shared/kind_of.rb @@ -0,0 +1,62 @@ +module ObjectSpecs + module SomeOtherModule; end + module AncestorModule; end + module MyModule; end + module MyExtensionModule; end + + class AncestorClass < String + include AncestorModule + end + + class KindaClass < AncestorClass + include MyModule + def initialize + self.extend MyExtensionModule + end + end +end + +shared :object_kind_of do |cmd| + describe "Object##{cmd}" do + before(:each) do + @o = ObjectSpecs::KindaClass.new + end + + it "returns true if given class is the object's class" do + @o.send(cmd, ObjectSpecs::KindaClass).should == true + end + + it "returns true if given class is an ancestor of the object's class" do + @o.send(cmd, ObjectSpecs::AncestorClass).should == true + @o.send(cmd, String).should == true + @o.send(cmd, Object).should == true + end + + it "returns false if the given class is not object's class nor an ancestor" do + @o.send(cmd, Array).should == false + end + + it "returns true if given a Module that is included in object's class" do + @o.send(cmd, ObjectSpecs::MyModule).should == true + end + + it "returns true if given a Module that is included one of object's ancestors only" do + @o.send(cmd, ObjectSpecs::AncestorModule).should == true + end + + it "returns true if given a Module that object has been extended with" do + @o.send(cmd, ObjectSpecs::MyExtensionModule).should == true + end + + it "returns false if given a Module not included in object's class nor ancestors" do + @o.send(cmd, ObjectSpecs::SomeOtherModule).should == false + end + + it "raises a TypeError if given an object that is not a Class nor a Module" do + lambda { @o.send(cmd, 1) }.should raise_error(TypeError) + lambda { @o.send(cmd, 'KindaClass') }.should raise_error(TypeError) + lambda { @o.send(cmd, :KindaClass) }.should raise_error(TypeError) + lambda { @o.send(cmd, Object.new) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/objectspace/_id2ref_spec.rb b/1.8/core/objectspace/_id2ref_spec.rb new file mode 100644 index 0000000000..8a3ff1e1fc --- /dev/null +++ b/1.8/core/objectspace/_id2ref_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ObjectSpace._id2ref" do + it "converts an object id to a reference to the object" do + s = "I am a string" + r = ObjectSpace._id2ref(s.object_id) + r.should == s + end +end diff --git a/1.8/core/objectspace/add_finalizer_spec.rb b/1.8/core/objectspace/add_finalizer_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/objectspace/add_finalizer_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/objectspace/call_finalizer_spec.rb b/1.8/core/objectspace/call_finalizer_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/objectspace/call_finalizer_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/objectspace/define_finalizer_spec.rb b/1.8/core/objectspace/define_finalizer_spec.rb new file mode 100644 index 0000000000..e11901152f --- /dev/null +++ b/1.8/core/objectspace/define_finalizer_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures' + +describe "ObjectSpace#define_finalizer" do + it "takes a proc and ignores the block" do + lambda { + ObjectSpace.define_finalizer("", proc { 1 }) do + 2 + end + }.should_not raise_error(ArgumentError) + end + + it "complains if the action doesn't respond to call" do + lambda { + ObjectSpace.define_finalizer("", 3) + }.should raise_error(ArgumentError) + end + + it "causes calls with the object_id when the object is dead" do + handler = ObjectSpaceFixtures.make_finalizer + ObjectSpace.define_finalizer ObjectSpaceFixtures.garbage, handler + 3.times { GC.start } + + ObjectSpaceFixtures.last_objid == ObjectSpaceFixtures.garbage_objid + end +end diff --git a/1.8/core/objectspace/each_object_spec.rb b/1.8/core/objectspace/each_object_spec.rb new file mode 100644 index 0000000000..054fca5ee5 --- /dev/null +++ b/1.8/core/objectspace/each_object_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ObjectSpace.each_object" do + it "calls the block once for each living, nonimmediate object in the Ruby process" do + class ObjectSpaceSpecEachObject; end + new_obj = ObjectSpaceSpecEachObject.new + + count = ObjectSpace.each_object(ObjectSpaceSpecEachObject) {} + count.should == 1 + # this is needed to prevent the new_obj from being GC'd too early + new_obj.should_not == nil + end +end diff --git a/1.8/core/objectspace/finalizers_spec.rb b/1.8/core/objectspace/finalizers_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/objectspace/finalizers_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/objectspace/fixtures.rb b/1.8/core/objectspace/fixtures.rb new file mode 100644 index 0000000000..ba76bd0a0f --- /dev/null +++ b/1.8/core/objectspace/fixtures.rb @@ -0,0 +1,25 @@ +module ObjectSpaceFixtures + def self.garbage + blah + end + + def self.blah + o = "hello" + @garbage_objid = o.object_id + return o + end + + @last_objid = nil + + def self.last_objid + @last_objid + end + + def self.garbage_objid + @garbage_objid + end + + def self.make_finalizer + proc { |obj_id| @last_objid = obj_id } + end +end diff --git a/1.8/core/objectspace/garbage_collect_spec.rb b/1.8/core/objectspace/garbage_collect_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/objectspace/garbage_collect_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/objectspace/remove_finalizer_spec.rb b/1.8/core/objectspace/remove_finalizer_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/objectspace/remove_finalizer_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/objectspace/undefine_finalizer_spec.rb b/1.8/core/objectspace/undefine_finalizer_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/objectspace/undefine_finalizer_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/precision/included_spec.rb b/1.8/core/precision/included_spec.rb new file mode 100644 index 0000000000..5077c894db --- /dev/null +++ b/1.8/core/precision/included_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Precision.included" do + it "raises a TypeError when a class mixed with Precision does not specify induced_from" do + class Foo ;include Precision ;end + lambda { Foo.induced_from(1) }.should raise_error(TypeError) + end + + it "doesn't raise a TypeError when a class mixed with Precision specifies induced_from" do + class Foo + include Precision + def self.induced_from(obj) + # nothing + end + end + lambda { Foo.induced_from(1) }.should_not raise_error(TypeError) + end +end diff --git a/1.8/core/precision/prec_f_spec.rb b/1.8/core/precision/prec_f_spec.rb new file mode 100644 index 0000000000..84d1f47a95 --- /dev/null +++ b/1.8/core/precision/prec_f_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Precision#prec_f" do + it "converts a Integer to Float when called on an Integer" do + 1.prec_f.should==1.0 + end + + it "returns the same Float when called on a Float" do + 1.9.prec_f.should==1.9 + end +end + diff --git a/1.8/core/precision/prec_i_spec.rb b/1.8/core/precision/prec_i_spec.rb new file mode 100644 index 0000000000..7018d7bb29 --- /dev/null +++ b/1.8/core/precision/prec_i_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Precision#prec_i" do + it "returns the same Integer when called on an Integer" do + 1.prec_i.should == 1 + end + + it "converts Float to an Integer when called on an Integer" do + 1.9.prec_i.should == 1 + end +end \ No newline at end of file diff --git a/1.8/core/precision/prec_spec.rb b/1.8/core/precision/prec_spec.rb new file mode 100644 index 0000000000..1164f1975e --- /dev/null +++ b/1.8/core/precision/prec_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Float#prec" do + it "returns the same Float when given the class Float" do + 1.4.prec(Float).should == 1.4 + end + + it "converts the Float to an Integer when given the class Integer" do + 1.4.prec(Integer).should == 1 + end +end + +describe "Integer#prec" do + it "returns the same Integer when given the class Integer" do + 1.prec(Integer).should == 1 + end + + it "converts the Integer to Float when given the class Float" do + 1.prec(Float).should == 1.0 + end +end + diff --git a/1.8/core/proc/arity_spec.rb b/1.8/core/proc/arity_spec.rb new file mode 100644 index 0000000000..58cde74021 --- /dev/null +++ b/1.8/core/proc/arity_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Proc#arity" do + it "returns the number of arguments, using Proc.new" do + Proc.new { || }.arity.should == 0 + Proc.new { |a| }.arity.should == 1 + Proc.new { |_| }.arity.should == 1 + Proc.new { |a, b| }.arity.should == 2 + Proc.new { |a, b, c| }.arity.should == 3 + end + + it "returns the number of arguments, using Kernel#lambda" do + lambda { || }.arity.should == 0 + lambda { |a| }.arity.should == 1 + lambda { |_| }.arity.should == 1 + lambda { |a, b| }.arity.should == 2 + lambda { |a, b, c| }.arity.should == 3 + end + + it "return the number of arguments, using Kernel#proc" do + proc { || }.arity.should == 0 + proc { |a| }.arity.should == 1 + proc { |_| }.arity.should == 1 + proc { |a, b| }.arity.should == 2 + proc { |a, b, c| }.arity.should == 3 + end + + it "if optional arguments, return the negative number of mandatory arguments using Proc.new " do + Proc.new { |*a| }.arity.should == -1 + Proc.new { |a, *b| }.arity.should == -2 + Proc.new { |a, b, *c| }.arity.should == -3 + end + + it "if optional arguments, return the negative number of mandatory arguments using Kernel#lambda" do + lambda { |*a| }.arity.should == -1 + lambda { |a, *b| }.arity.should == -2 + lambda { |a, b, *c| }.arity.should == -3 + end + + it "if optional arguments, return the negative number of mandatory arguments using Kernel#proc" do + proc { |*a| }.arity.should == -1 + proc { |a, *b| }.arity.should == -2 + proc { |a, b, *c| }.arity.should == -3 + end + + it "returns -1 if no argument declaration is made, using Proc.new" do + Proc.new { }.arity.should == -1 + end + + it "returns -1 if no argument declaration is made, using Kernel#lambda" do + lambda { }.arity.should == -1 + end + + it "returns -1 if no argument declaration is made, using Kernel#proc" do + proc { }.arity.should == -1 + end +end diff --git a/1.8/core/proc/binding_spec.rb b/1.8/core/proc/binding_spec.rb new file mode 100644 index 0000000000..14e1d45562 --- /dev/null +++ b/1.8/core/proc/binding_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Proc#binding" do + it "returns the binding associated wiht self" do + obj = mock('binding') + def obj.test_binding(some, params) + lambda {} + end + + binding = obj.test_binding(1, 2) + + eval("some", binding).should == 1 + eval("params", binding).should == 2 + end +end \ No newline at end of file diff --git a/1.8/core/proc/block_pass_spec.rb b/1.8/core/proc/block_pass_spec.rb new file mode 100644 index 0000000000..51a5a91f15 --- /dev/null +++ b/1.8/core/proc/block_pass_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Proc as a block pass argument" do + def revivify(&b) + b + end + + it "remains the same object if re-vivified by the target method" do + p = Proc.new {} + p2 = revivify(&p) + p.object_id.should == p2.object_id + p.should == p2 + end + + it "remains the same object if reconstructed with Proc.new" do + p = Proc.new {} + p2 = Proc.new(&p) + p.object_id.should == p2.object_id + p.should == p2 + end +end diff --git a/1.8/core/proc/call_spec.rb b/1.8/core/proc/call_spec.rb new file mode 100644 index 0000000000..cd4e91422c --- /dev/null +++ b/1.8/core/proc/call_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/call' + +describe "Proc#call" do + it_behaves_like(:proc_call, :call) +end diff --git a/1.8/core/proc/clone_spec.rb b/1.8/core/proc/clone_spec.rb new file mode 100644 index 0000000000..82549d3085 --- /dev/null +++ b/1.8/core/proc/clone_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/dup' + +describe "Proc#clone" do + it_behaves_like(:proc_dup, :clone) +end \ No newline at end of file diff --git a/1.8/core/proc/dup_spec.rb b/1.8/core/proc/dup_spec.rb new file mode 100644 index 0000000000..899110c23a --- /dev/null +++ b/1.8/core/proc/dup_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/dup' + +describe "Proc#dup" do + it_behaves_like(:proc_dup, :dup) +end \ No newline at end of file diff --git a/1.8/core/proc/element_reference_spec.rb b/1.8/core/proc/element_reference_spec.rb new file mode 100644 index 0000000000..81c450b08d --- /dev/null +++ b/1.8/core/proc/element_reference_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/call' + +describe "Proc#[]" do + it_behaves_like(:proc_call, :[]) +end \ No newline at end of file diff --git a/1.8/core/proc/equal_value_spec.rb b/1.8/core/proc/equal_value_spec.rb new file mode 100644 index 0000000000..269fe0a992 --- /dev/null +++ b/1.8/core/proc/equal_value_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Proc#==" do + it "returns true when the given value is self or a copy of self" do + a = lambda { "hello" } + + a.should == a + a.should == a.dup + + a.should_not == lambda { "hello" } + a.should_not == Proc.new {} + a.should_not == nil + end +end \ No newline at end of file diff --git a/1.8/core/proc/fixtures/procs.rb b/1.8/core/proc/fixtures/procs.rb new file mode 100644 index 0000000000..91139119ea --- /dev/null +++ b/1.8/core/proc/fixtures/procs.rb @@ -0,0 +1,5 @@ +module ProcSpecs + def self.returner + Proc.new { return }.call + end +end diff --git a/1.8/core/proc/new_spec.rb b/1.8/core/proc/new_spec.rb new file mode 100644 index 0000000000..42fb03ff4d --- /dev/null +++ b/1.8/core/proc/new_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/fixtures/procs.rb' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Proc.new" do + it "returns a new Proc instance from the passed block" do + Proc.new { }.call.should == nil + Proc.new { "hello" }.call.should == "hello" + end + + it "raises an ArgumentError when no block was passed" do + raise_error(ArgumentError, "tried to create Proc object without a block") do + Proc.new + end + end + + it "raises a LocalJumpError when context of block no longer exists" do + def some_method(&b) b end + a_proc = Proc.new { return } + res = some_method(&a_proc) + + raise_error(LocalJumpError) { res.call } + end + + it "returns from within a method" do + ProcSpecs.returner + end + + it "raises an ArgumentError when called without a block inside a method without an attached block" do + def some_method() Proc.new end + lambda { some_method }.should raise_error(ArgumentError) + end + + it "returns a new Proc instance from the block passed to the containing method" do + def some_method() Proc.new end + some_method { "hello" }.call.should == "hello" + end +end diff --git a/1.8/core/proc/shared/call.rb b/1.8/core/proc/shared/call.rb new file mode 100644 index 0000000000..b57c7332b8 --- /dev/null +++ b/1.8/core/proc/shared/call.rb @@ -0,0 +1,79 @@ +shared :proc_call do |cmd| + describe "Proc##{cmd}" do + it "invokes self" do + Proc.new { "test!" }.send(cmd).should == "test!" + lambda { "test!" }.send(cmd).should == "test!" + proc { "test!" }.send(cmd).should == "test!" + end + + it "sets self's parameters to the given values" do + Proc.new { |a, b| a + b }.send(cmd, 1, 2).should == 3 + Proc.new { |*args| args }.send(cmd, 1, 2, 3, 4).should == [1, 2, 3, 4] + Proc.new { |_, *args| args }.send(cmd, 1, 2, 3).should == [2, 3] + + lambda { |a, b| a + b }.send(cmd, 1, 2).should == 3 + lambda { |*args| args }.send(cmd, 1, 2, 3, 4).should == [1, 2, 3, 4] + lambda { |_, *args| args }.send(cmd, 1, 2, 3).should == [2, 3] + + proc { |a, b| a + b }.send(cmd, 1, 2).should == 3 + proc { |*args| args }.send(cmd, 1, 2, 3, 4).should == [1, 2, 3, 4] + proc { |_, *args| args }.send(cmd, 1, 2, 3).should == [2, 3] + end + + it "sets self's single parameter to an Array of all given values" do + [Proc.new { |x| [x] }, lambda { |x| [x] }, proc { |x| [x] }].each do |p| + a = p.send(cmd) + a.class.should == Array + a.should == [nil] + + a = p.send(cmd, 1) + a.class.should == Array + a.should == [1] + + a = p.send(cmd, 1, 2) + a.class.should == Array + a.should == [[1, 2]] + + a = p.send(cmd, 1, 2, 3) + a.class.should == Array + a.should == [[1, 2, 3]] + end + end + + it "replaces missing arguments with nil when called on a Proc created with Proc.new" do + Proc.new { |a, b| [a, b] }.send(cmd).should == [nil, nil] + Proc.new { |a, b| [a, b] }.send(cmd, 1).should == [1, nil] + end + + it "silently ignores extra arguments when called on a Proc created with Proc.new" do + Proc.new { |a, b| a + b }.send(cmd, 1, 2, 5).should == 3 + end + + it "auto-explodes a single Array argument when called on a Proc created with Proc.new" do + p = Proc.new { |a, b| [a, b] } + p.send(cmd, 1, 2).should == [1, 2] + p.send(cmd, [1, 2]).should == [1, 2] + p.send(cmd, [1, 2, 3]).should == [1, 2] + p.send(cmd, [1, 2, 3], 4).should == [[1, 2, 3], 4] + end + + it "raises an ArgumentError when called with too few arguments on a Proc created with Kernel#lambda or Kernel#proc" do + lambda { lambda { |a, b| [a, b] }.send(cmd) }.should raise_error(ArgumentError) + lambda { lambda { |a, b| [a, b] }.send(cmd, 1) }.should raise_error(ArgumentError) + lambda { proc { |a, b| [a, b] }.send(cmd) }.should raise_error(ArgumentError) + lambda { proc { |a, b| [a, b] }.send(cmd, 1) }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when called with too many arguments on a Proc created with Kernel#lambda or Kernel#proc" do + lambda { lambda { |a, b| [a, b] }.send(cmd, 1, 2, 3) }.should raise_error(ArgumentError) + lambda { proc { |a, b| [a, b] }.send(cmd, 1, 2, 3) }.should raise_error(ArgumentError) + end + + it "treats a single Array argument as a single argument when called on a Proc created with Kernel#lambda or Kernel#proc" do + lambda { |a| [a] }.send(cmd, [1, 2]).should == [[1, 2]] + lambda { lambda { |a, b| [a, b] }.send(cmd, [1, 2]) }.should raise_error(ArgumentError) + proc { |a| [a] }.send(cmd, [1, 2]).should == [[1, 2]] + lambda { proc { |a, b| [a, b] }.send(cmd, [1, 2]) }.should raise_error(ArgumentError) + end + end +end diff --git a/1.8/core/proc/shared/dup.rb b/1.8/core/proc/shared/dup.rb new file mode 100644 index 0000000000..fa03ad98cb --- /dev/null +++ b/1.8/core/proc/shared/dup.rb @@ -0,0 +1,12 @@ +shared :proc_dup do |cmd| + describe "Proc##{cmd}" do + it "returns a copy of self" do + a = lambda { "hello" } + b = a.send(cmd) + + a.equal?(b).should == false + + a.call.should == b.call + end + end +end diff --git a/1.8/core/proc/to_proc_spec.rb b/1.8/core/proc/to_proc_spec.rb new file mode 100644 index 0000000000..cf6916dd26 --- /dev/null +++ b/1.8/core/proc/to_proc_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Proc#to_proc" do + it "returns self" do + a = lambda {} + a.to_proc.equal?(a).should == true + end +end \ No newline at end of file diff --git a/1.8/core/proc/to_s_spec.rb b/1.8/core/proc/to_s_spec.rb new file mode 100644 index 0000000000..716d891e93 --- /dev/null +++ b/1.8/core/proc/to_s_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Proc#to_s" do + it "returns a description of self" do + Proc.new { "hello" }.to_s.should =~ /^#$/ + lambda { "hello" }.to_s.should =~ /^#$/ + proc { "hello" }.to_s.should =~ /^#$/ + end +end diff --git a/1.8/core/process/abort_spec.rb b/1.8/core/process/abort_spec.rb new file mode 100644 index 0000000000..f90e5f2540 --- /dev/null +++ b/1.8/core/process/abort_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# TODO: share with Kernel.abort, abort. +describe "Process.abort" do + it "terminates execution immediately" do + @file = '/tmp/i_exist' + File.delete(@file) if File.exist?(@file) + pid = Process.fork { + Process.abort + File.open(@file,'w'){|f| f.write 'rubinius'} + } + File.exist?(@file).should == false + end +end diff --git a/1.8/core/process/constants_spec.rb b/1.8/core/process/constants_spec.rb new file mode 100644 index 0000000000..fec532171c --- /dev/null +++ b/1.8/core/process/constants_spec.rb @@ -0,0 +1,60 @@ + +describe "Process::Constants" do + platform_is :os => [:darwin, :netbsd, :freebsd] do + it "should have the correct constant values on BSD-like systems" do + Process::WNOHANG.should == 1 + Process::WUNTRACED.should == 2 + Process::PRIO_PROCESS.should == 0 + Process::PRIO_PGRP.should == 1 + Process::PRIO_USER.should == 2 + Process::RLIM_INFINITY.should == 9223372036854775807 + Process::RLIMIT_CPU.should == 0 + Process::RLIMIT_FSIZE.should == 1 + Process::RLIMIT_DATA.should == 2 + Process::RLIMIT_STACK.should == 3 + Process::RLIMIT_CORE.should == 4 + Process::RLIMIT_RSS.should == 5 + Process::RLIMIT_MEMLOCK.should == 6 + Process::RLIMIT_NPROC.should == 7 + Process::RLIMIT_NOFILE.should == 8 + end + end + + platform_is :os => [:darwin] do + it "should have the correct constant values on Darwin" do + Process::RLIM_SAVED_MAX.should == 9223372036854775807 + Process::RLIM_SAVED_CUR.should == 9223372036854775807 + Process::RLIMIT_AS.should == 5 + end + end + + platform_is :os => [:linux] do + it "should have the correct constant values on Linux" do + Process::WNOHANG.should == 1 + Process::WUNTRACED.should == 2 + Process::PRIO_PROCESS.should == 0 + Process::PRIO_PGRP.should == 1 + Process::PRIO_USER.should == 2 + Process::RLIM_INFINITY.should == 9223372036854775807 + Process::RLIM_SAVED_MAX.should == 9223372036854775807 + Process::RLIM_SAVED_CUR.should == 9223372036854775807 + Process::RLIMIT_CPU.should == 0 + Process::RLIMIT_FSIZE.should == 1 + Process::RLIMIT_DATA.should == 2 + Process::RLIMIT_STACK.should == 3 + Process::RLIMIT_CORE.should == 4 + Process::RLIMIT_RSS.should == 5 + Process::RLIMIT_NPROC.should == 6 + Process::RLIMIT_NOFILE.should == 7 + Process::RLIMIT_MEMLOCK.should == 8 + Process::RLIMIT_AS.should == 9 + end + end + + platform_is :os => [:netbsd, :freebsd] do + it "Process::RLIMIT_SBSIZE" do + Process::RLIMIT_SBSIZE.should == 9 # FIXME: what's it equal? + Process::RLIMIT_AS.should == 10 + end + end +end diff --git a/1.8/core/process/detach_spec.rb b/1.8/core/process/detach_spec.rb new file mode 100644 index 0000000000..ac77fd3dbe --- /dev/null +++ b/1.8/core/process/detach_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process#detach" do + it "requires one argument" do + lambda { Process.detach }.should raise_error(ArgumentError) + end + + it "returns a thread" do + p1 = Process.fork { Process.exit! } + Process.detach(p1).class.should == Thread + end + + platform_is_not :openbsd do + it "reaps the child process's status automatically" do + p1 = Process.fork { Process.exit! } + Process.detach(p1) + + t = Time.now + while true + alive = Process.kill(0, p1) rescue nil + break unless alive && (Time.now - t < 5) # fail safe + end + lambda { Process.waitpid(p1) }.should raise_error(Errno::ECHILD) + end + end +end diff --git a/1.8/core/process/egid_spec.rb b/1.8/core/process/egid_spec.rb new file mode 100644 index 0000000000..55ebb316ef --- /dev/null +++ b/1.8/core/process/egid_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.egid" do + it "returns the effective group ID for this process" do + Process.egid.class.should == Fixnum + end + + it "also goes by Process::GID.eid" do + Process::GID.eid.should == Process.egid + end + + it "also goes by Process::Sys.getegid" do + Process::Sys.getegid.should == Process.egid + end +end diff --git a/1.8/core/process/euid_spec.rb b/1.8/core/process/euid_spec.rb new file mode 100644 index 0000000000..ac076127cc --- /dev/null +++ b/1.8/core/process/euid_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.euid" do + it "returns the effective user ID for this process" do + Process.euid.class.should == Fixnum + end + + it "also goes by Process::UID.eid" do + Process::UID.eid.should == Process.euid + end + + it "also goes by Process::Sys.geteuid" do + Process::Sys.geteuid.should == Process.euid + end +end diff --git a/1.8/core/process/exit_spec.rb b/1.8/core/process/exit_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/process/exit_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/process/fork_spec.rb b/1.8/core/process/fork_spec.rb new file mode 100644 index 0000000000..cb434d1357 --- /dev/null +++ b/1.8/core/process/fork_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.fork" do + not_supported_on :jruby do + before :each do + @file = '/tmp/i_exist' + File.delete(@file) if File.exist?(@file) + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "return nil for the child process" do + child_id = Process.fork + if child_id == nil + File.open(@file,'w'){|f| f.write 'rubinius'} + Process.exit! + else + Process.waitpid(child_id) + end + File.exist?(@file).should == true + end + + it "runs a block in a child process" do + pid = Process.fork { + File.open(@file,'w'){|f| f.write 'rubinius'} + Process.exit! + } + Process.waitpid(pid) + File.exist?(@file).should == true + end + end +end diff --git a/1.8/core/process/getpgid_spec.rb b/1.8/core/process/getpgid_spec.rb new file mode 100644 index 0000000000..d52eb6ab34 --- /dev/null +++ b/1.8/core/process/getpgid_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.getpgid" do + it "requires one argument" do + lambda { Process.getpgid }.should raise_error(ArgumentError) + end + + it "returns the process group ID for the given process id" do + Process.getpgid(Process.pid).should == Process.getpgrp + end + + it "returns the process group ID for the calling process id when passed 0" do + Process.getpgid(0).should == Process.getpgrp + end +end diff --git a/1.8/core/process/getpgrp_spec.rb b/1.8/core/process/getpgrp_spec.rb new file mode 100644 index 0000000000..730b735f4f --- /dev/null +++ b/1.8/core/process/getpgrp_spec.rb @@ -0,0 +1,3 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# see setpgrp_spec.rb diff --git a/1.8/core/process/getpriority_spec.rb b/1.8/core/process/getpriority_spec.rb new file mode 100644 index 0000000000..a99c6d835a --- /dev/null +++ b/1.8/core/process/getpriority_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.getpriority" do + it "takes two arguments" do + lambda { Process.getpriority }.should raise_error(ArgumentError) + lambda { + Process.getpriority(Process::PRIO_PROCESS) + }.should raise_error(ArgumentError) + end + + it "gets the scheduling priority for a specified process" do + Process.getpriority(Process::PRIO_PROCESS, 0).class.should == Fixnum + end + + it "gets the scheduling priority for a specified process group" do + Process.getpriority(Process::PRIO_PGRP, 0).class.should == Fixnum + end + + it "gets the scheduling priority for a specified user" do + Process.getpriority(Process::PRIO_USER, 0).class.should == Fixnum + end +end diff --git a/1.8/core/process/getrlimit_spec.rb b/1.8/core/process/getrlimit_spec.rb new file mode 100644 index 0000000000..fe330245d9 --- /dev/null +++ b/1.8/core/process/getrlimit_spec.rb @@ -0,0 +1,3 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +# see setrlimit_spec.rb diff --git a/1.8/core/process/gid_spec.rb b/1.8/core/process/gid_spec.rb new file mode 100644 index 0000000000..29997f8620 --- /dev/null +++ b/1.8/core/process/gid_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.gid" do + it "returns the correct gid for the user executing this process" do + current_gid_according_to_unix = `id -gr`.to_i + Process.gid.should == current_gid_according_to_unix + end + + it "also goes by Process::GID.rid" do + Process::GID.rid.should == Process.gid + end + + it "also goes by Process::Sys.getgid" do + Process::Sys.getgid.should == Process.gid + end +end diff --git a/1.8/core/process/groups_spec.rb b/1.8/core/process/groups_spec.rb new file mode 100644 index 0000000000..52cfc1faaa --- /dev/null +++ b/1.8/core/process/groups_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.groups" do + it "takes no arguments" do + lambda { Process.groups(1) }.should raise_error(ArgumentError) + end + + it "gets an Array of the gids of groups in the supplemental group access list" do + groups = `id -G`.scan(/\d+/).map {|i| i.to_i} + + # NOTE: if/when this fails, make sure you are running in the most + # basic environment you have available. This spec fails + # consistently on me (Ryan Davis) when I'm running the specs + # inside a shell inside emacs that was launched by OSX's + # windowserver (double click in finder or quicksilver/launchbar + # etc). When run any other way the spec passes. + Process.groups.uniq.sort.should == groups.uniq.sort + end + + # NOTE: This is kind of sketchy. + it "sets the list of gids of groups in the supplemental group access list" do + groups = Process.groups + if Process.uid == 0 + Process.groups = [] + Process.groups.should == [] + Process.groups = groups + Process.groups.sort.should == groups.sort + else + lambda { Process.groups = [] }.should raise_error(Errno::EPERM) + end + end +end diff --git a/1.8/core/process/initgroups_spec.rb b/1.8/core/process/initgroups_spec.rb new file mode 100644 index 0000000000..cf911ad216 --- /dev/null +++ b/1.8/core/process/initgroups_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.initgroups" do + it "requires two arguments" do + lambda { Process.initgroups }.should raise_error(ArgumentError) + lambda { Process.initgroups("root") }.should raise_error(ArgumentError) + end + + it "initializes the supplemental group access list" do + name = `id -un`.strip + groups = Process.groups + gid = groups.max.to_i + 1 + augmented_groups = `id -G`.scan(/\d+/).map {|i| i.to_i} << gid + if Process.uid == 0 + Process.groups = [] + Process.initgroups(name, gid).sort.should == augmented_groups.sort + Process.groups.sort.should == augmented_groups.sort + Process.groups = groups + else + lambda { Process.initgroups(name, gid) }.should raise_error(Errno::EPERM) + end + end +end diff --git a/1.8/core/process/kill_spec.rb b/1.8/core/process/kill_spec.rb new file mode 100644 index 0000000000..58ed80e993 --- /dev/null +++ b/1.8/core/process/kill_spec.rb @@ -0,0 +1,127 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.kill" do + it "requires at least two arguments" do + lambda { Process.kill }.should raise_error(ArgumentError) + lambda { Process.kill(0) }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError for unknown signals" do + lambda { Process.kill("FOO", 0) }.should raise_error(ArgumentError) + end + + it "doesn't accept lowercase signal names" do + lambda { Process.kill("hup", 0) }.should raise_error(ArgumentError) + end + + it "doesn't tolerate leading or trailing spaces in signal names" do + lambda { Process.kill(" HUP", 0) }.should raise_error(ArgumentError) + lambda { Process.kill("HUP ", 0) }.should raise_error(ArgumentError) + end + + it "tests for the existence of a process without sending a signal" do + Process.kill(0, 0).should == 1 + pid = Process.fork { + begin + Signal.trap("HUP") { Process.exit! 99 } + sleep(2) # only so that failures are cleaned up + ensure + Process.exit! + end + } + Process.kill(0, pid).should == 1 + Process.kill(1, pid).should == 1 + Process.waitpid(pid) + lambda { Process.kill(0, pid) }.should raise_error(Errno::ESRCH) + end + + it "raises an EPERM if permission is denied" do + if Process.uid != 0 + lambda { Process.kill(1, 1) }.should raise_error(Errno::EPERM) + end + end +end + +describe "Process.kill" do + before :all do + @saved_trap = Signal.trap("HUP") {} + end + + before :each do + @foo = 0 + @read, @write = IO.pipe + Signal.trap("HUP") { + @foo = 42 + @write << "1" + @write.close + } + end + + after :each do + @read.gets # the signal handler has run + @read.close + @foo.should == 42 + end + + after :all do + Signal.trap("HUP", @saved_trap) + end + + it "sends the given signal to the current process if pid is zero" do + Process.kill("HUP", 0).should == 1 + end + + it "accepts integer signal numbers" do + Process.kill(1, 0).should == 1 + end + + it "accepts POSIX signal names without 'SIG' prefix" do + Process.kill("HUP", 0).should == 1 + end + + it "accepts POSIX signal names with 'SIG' prefix" do + Process.kill("SIGHUP", 0).should == 1 + end +end + +describe "Process.kill" do + before :each do + @read, @write = IO.pipe + @pid = Process.fork { + begin + @read.close + Process.setpgid(0, 0) + Signal.trap("HUP") { Process.exit! 99 } + @write << "1" + @write.close + sleep(2) # only so that failures are cleaned up + ensure + Process.exit! 42 + end + } + @write.close + @read.gets # the child has changed process groups + @read.close + end + + after :each do + Process.waitpid(@pid).should == @pid + $?.exitstatus.should == 99 + end + + it "sends the given signal to the specified process" do + Process.kill("HUP", @pid).should == 1 + end + + it "kills process groups if signal is negative" do + Process.kill(-1, Process.getpgid(@pid)).should == 1 + end + + it "kills process groups if signal starts with a minus sign" do + Process.kill("-HUP", Process.getpgid(@pid)).should == 1 + end + + it "kills process groups if signal starts with a minus sign and 'SIG'" do + Process.kill("-SIGHUP", Process.getpgid(@pid)).should == 1 + end +end diff --git a/1.8/core/process/maxgroups_spec.rb b/1.8/core/process/maxgroups_spec.rb new file mode 100644 index 0000000000..f66fdc3629 --- /dev/null +++ b/1.8/core/process/maxgroups_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.maxgroups" do + it "returns the maximum number of gids allowed in the supplemental group access list" do + Process.maxgroups.class.should == Fixnum + end + + it "sets the maximum number of gids allowed in the supplemental group access list" do + n = Process.maxgroups + Process.maxgroups = n + 1 + Process.maxgroups.should == n + 1 + Process.maxgroups = n + end +end diff --git a/1.8/core/process/pid_spec.rb b/1.8/core/process/pid_spec.rb new file mode 100644 index 0000000000..99433b2fb2 --- /dev/null +++ b/1.8/core/process/pid_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.pid" do + it "returns the process id of this process" do + pid = Process.pid + pid.class.should == Fixnum + Process.pid.should == pid + end +end diff --git a/1.8/core/process/ppid_spec.rb b/1.8/core/process/ppid_spec.rb new file mode 100644 index 0000000000..947b787aa1 --- /dev/null +++ b/1.8/core/process/ppid_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.ppid" do + it "returns the process id of the parent of this process" do + + read, write = IO.pipe + + child_pid = Process.fork { + read.close + write << "#{Process.ppid}\n" + write.close + exit! + } + write.close + pid = read.gets + read.close + Process.wait(child_pid) + pid.to_i.should == Process.pid + end +end diff --git a/1.8/core/process/setpgid_spec.rb b/1.8/core/process/setpgid_spec.rb new file mode 100644 index 0000000000..1b544b329c --- /dev/null +++ b/1.8/core/process/setpgid_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.setpgid" do + it "requires two arguments" do + lambda { Process.setpgid }.should raise_error(ArgumentError) + lambda { Process.setpgid(0) }.should raise_error(ArgumentError) + end + + it "sets the process group id of the specified process" do + rd, wr = IO.pipe + + pid = Process.fork do + wr.close + rd.read + rd.close + Process.exit! + end + + rd.close + + Process.getpgid(pid).should == Process.getpgrp + Process.setpgid(pid, pid).should == 0 + Process.getpgid(pid).should == pid + + wr.write ' ' + wr.close + end +end diff --git a/1.8/core/process/setpgrp_spec.rb b/1.8/core/process/setpgrp_spec.rb new file mode 100644 index 0000000000..17439a5006 --- /dev/null +++ b/1.8/core/process/setpgrp_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.setpgrp and Process.getpgrp" do + it "take no arguments" do + lambda { Process.setpgrp(0) }.should raise_error(ArgumentError) + lambda { Process.getpgrp(1) }.should raise_error(ArgumentError) + end + + it "set and get the process group ID of the calling process" do + # there are two synchronization points here: + # One for the child to let the parent know that it has finished + # setting its process group; + # and another for the parent to let the child know that it's ok to die. + read1, write1 = IO.pipe + read2, write2 = IO.pipe + pid = Process.fork do + read1.close + write2.close + Process.setpgrp + write1 << Process.getpgrp + write1.close + read2.read(1) + read2.close + Process.exit! + end + write1.close + read2.close + pgid = read1.read # wait for child to change process groups + read1.close + + Process.getpgid(pid).should == pgid.to_i + + write2 << "!" + write2.close + end + +end + +describe "Process.setpgrp" do + it "returns zero" do + Process.setpgrp.should == 0 + end +end diff --git a/1.8/core/process/setpriority_spec.rb b/1.8/core/process/setpriority_spec.rb new file mode 100644 index 0000000000..5a90475b35 --- /dev/null +++ b/1.8/core/process/setpriority_spec.rb @@ -0,0 +1,79 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.setpriority" do + it "takes three arguments" do + lambda { Process.setpriority }.should raise_error(ArgumentError) + lambda { + Process.setpriority(Process::PRIO_PROCESS) + }.should raise_error(ArgumentError) + lambda { + Process.setpriority(Process::PRIO_PROCESS, 0) + }.should raise_error(ArgumentError) + end + + # Needs a valid version written for Linux + platform_is :os => :darwin do + it "sets the scheduling priority for a specified process" do + p = Process.getpriority(Process::PRIO_PROCESS, 0) + Process.setpriority(Process::PRIO_PROCESS, 0, p + 1).should == 0 + Process.getpriority(Process::PRIO_PROCESS, 0).should == (p + 1) + if Process.uid == 0 + Process.setpriority(Process::PRIO_PROCESS, 0, p).should == 0 + else + lambda { + Process.setpriority(Process::PRIO_PROCESS, 0, p) + }.should raise_error(Errno::EACCES) + end + end + end + + # Darwin and FreeBSD don't seem to handle these at all, getting all out of + # whack with either permission errors or just the wrong value + platform_is_not :os => [:darwin, :freebsd] do + it "sets the scheduling priority for a specified process group" do + pr = Process.getpriority(Process::PRIO_PGRP, 0) + + Process.setpriority(Process::PRIO_PGRP, 0, pr + 1).should == 0 + Process.getpriority(Process::PRIO_PGRP, 0).should == (pr + 1) + if Process.uid == 0 + Process.setpriority(Process::PRIO_PGRP, 0, pr).should == 0 + else + # EACCESS is not always raised. It's a stupid OS behavior. + ok = false + begin + Process.setpriority(Process::PRIO_PGRP, 0, pr) + ok = true + rescue Errno::EACCES + ok = true + rescue Object + ok = false + end + + ok.should == true + end + end + end + + it "sets the scheduling priority for a specified user" do + p = Process.getpriority(Process::PRIO_USER, 0) + if Process.uid == 0 + Process.setpriority(Process::PRIO_USER, 0, p + 1).should == 0 + Process.getpriority(Process::PRIO_USER, 0).should == (p + 1) + Process.setpriority(Process::PRIO_USER, 0, p).should == 0 + else + # EACCESS is not always raised. It's a stupid OS behavior. + ok = false + begin + Process.setpriority(Process::PRIO_USER, 0, p - 1) + ok = true + rescue Errno::EACCES + ok = true + rescue Object + ok = false + end + + ok.should == true + end + end + +end diff --git a/1.8/core/process/setrlimit_spec.rb b/1.8/core/process/setrlimit_spec.rb new file mode 100644 index 0000000000..be0c049fb5 --- /dev/null +++ b/1.8/core/process/setrlimit_spec.rb @@ -0,0 +1,100 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.setrlimit" do + it "requires at least two arguments" do + lambda { + Process.setrlimit(Process::RLIMIT_CORE) + }.should raise_error(ArgumentError) + end +end + +describe "Process.getrlimit" do + it "requires one argument" do + lambda { Process.getrlimit }.should raise_error(ArgumentError) + end +end + +describe "Process.setrlimit and Process.getrlimit" do + it "limit and get core size (bytes)" do + lim, max = Process.getrlimit(Process::RLIMIT_CORE) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_CORE, lim, max).should == nil + end + + it "limit and get CPU time (seconds)" do + lim, max = Process.getrlimit(Process::RLIMIT_CPU) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_CPU, lim, max).should == nil + end + + it "limit and get data segment (bytes)" do + lim, max = Process.getrlimit(Process::RLIMIT_DATA) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_DATA, lim, max).should == nil + end + + it "limit and get file size (bytes)" do + lim, max = Process.getrlimit(Process::RLIMIT_FSIZE) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_FSIZE, lim, max).should == nil + end + + it "limit and get file descriptors (number)" do + lim, max = Process.getrlimit(Process::RLIMIT_NOFILE) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_NOFILE, lim, max).should == nil + end + + it "limit and get stack size (bytes)" do + lim, max = Process.getrlimit(Process::RLIMIT_STACK) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_STACK, lim, max).should == nil + end + + platform_is_not :openbsd do + it "limit and get total available memory (bytes)" do + lim, max = Process.getrlimit(Process::RLIMIT_AS) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_AS, lim, max).should == nil + end + end + + it "limit and get total size for mlock(2) (bytes)" do + lim, max = Process.getrlimit(Process::RLIMIT_MEMLOCK) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + max = lim if lim > max # EINVAL is raised if this invariant is violated + Process.setrlimit(Process::RLIMIT_MEMLOCK, lim, max).should == nil + end + + it "limit and get number of processes for the user (number)" do + lim, max = Process.getrlimit(Process::RLIMIT_NPROC) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_NPROC, lim, max).should == nil + end + + it "limit and get resident memory size (bytes)" do + lim, max = Process.getrlimit(Process::RLIMIT_RSS) + lim.kind_of?(Integer).should == true + max.kind_of?(Integer).should == true + Process.setrlimit(Process::RLIMIT_RSS, lim, max).should == nil + end + + platform_is :os => [:netbsd, :freebsd] do + it "limit and get all socket buffers (bytes)" do + #TODO + # lim = Process.setrlimit(Process::RLIMIT_SBSIZE, ) + # lim.kind_of?(Integer).should == true + # max.kind_of?(Integer).should == true + # Process.setrlimit(Process::RLIMIT_SBSIZE , ).should == nil + end + end +end diff --git a/1.8/core/process/setsid_spec.rb b/1.8/core/process/setsid_spec.rb new file mode 100644 index 0000000000..dccdb0e989 --- /dev/null +++ b/1.8/core/process/setsid_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.setsid" do + it "takes no arguments" do + lambda { Process.setsid(0) }.should raise_error(ArgumentError) + end + + it "establishes this process as a new session and process group leader" do + read, write = IO.pipe + pid = Process.fork { + begin + read.close + pgid = Process.setsid + write << pgid.class.to_s + write.close + rescue Exception => e + write << e << e.backtrace + end + Process.exit! + } + write.close + klass = read.gets + read.close + klass.should == "Fixnum" + end +end diff --git a/1.8/core/process/times_spec.rb b/1.8/core/process/times_spec.rb new file mode 100644 index 0000000000..4bdc96e143 --- /dev/null +++ b/1.8/core/process/times_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.times" do + it "returns current cpu times" do + + t = Process::times + t.class.should == Struct::Tms + + # stall for 1 second, but do work instead of sleeping because process + # times won't increase + start = Time.now + 1 while (Time.now - start) < 1.1 + + # ensure times is at least one second larger + t2 = Process::times + diff = (t2.utime + t2.stime) - (t.utime + t.stime) + (diff > 1).should == true + end +end diff --git a/1.8/core/process/uid_spec.rb b/1.8/core/process/uid_spec.rb new file mode 100644 index 0000000000..3d3484779e --- /dev/null +++ b/1.8/core/process/uid_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.uid" do + it "returns the correct uid for the user executing this process" do + current_uid_according_to_unix = `id -ur`.to_i + Process.uid.should == current_uid_according_to_unix + end + + it "also goes by Process::UID.rid" do + Process::UID.rid.should == Process.uid + end + + it "also goes by Process::Sys.getuid" do + Process::Sys.getuid.should == Process.uid + end +end diff --git a/1.8/core/process/wait2_spec.rb b/1.8/core/process/wait2_spec.rb new file mode 100644 index 0000000000..17143b6ba7 --- /dev/null +++ b/1.8/core/process/wait2_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.wait2" do + before :all do + # HACK: this kludge is temporarily necessary because some + # misbehaving spec somewhere else does not clear processes + Process.waitall + end + + it "returns the pid and status of child process" do + pidf = Process.fork { Process.exit! 99 } + results = Process.wait2 + results.size.should == 2 + pidw, status = results + pidf.should == pidw + status.exitstatus.should == 99 + end + + it "raises a StandardError if no child processes exist" do + lambda { Process.wait2 }.should raise_error(Errno::ECHILD) + lambda { Process.wait2 }.should raise_error(StandardError) + end +end diff --git a/1.8/core/process/wait_spec.rb b/1.8/core/process/wait_spec.rb new file mode 100644 index 0000000000..015c66b5ea --- /dev/null +++ b/1.8/core/process/wait_spec.rb @@ -0,0 +1,80 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.wait" do + before :all do + Process.waitall + end + + it "raises a Errno::ECHILD if there are no child processes" do + lambda { Process.wait }.should raise_error(Errno::ECHILD) + end + + it "returns its childs pid" do + pid = Process.fork { Process.exit! } + Process.wait.should == pid + end + + it "sets $? to a Process::Status" do + pid = Process.fork { Process.exit! } + Process.wait + $?.class.should == Process::Status + $?.pid.should == pid + end + + it "waits for any child process if no pid is given" do + pid = Process.fork { Process.exit! } + Process.wait.should == pid + lambda { Process.kill(0, pid) }.should raise_error(Errno::ESRCH) + end + + it "waits for a specific child if a pid is given" do + pid1 = Process.fork { Process.exit! } + pid2 = Process.fork { Process.exit! } + Process.wait(pid2).should == pid2 + Process.wait(pid1).should == pid1 + lambda { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH) + lambda { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH) + end + + # This spec is probably system-dependent. + it "waits for a child whose process group ID is that of the calling process" do + read, write = IO.pipe + pid1 = Process.fork { + read.close + Process.setpgid(0, 0) + write << 1 + write.close + Process.exit! + } + Process.setpgid(0, 0) + ppid = Process.pid + pid2 = Process.fork { + read.close + Process.setpgid(0, ppid); + write << 2 + write.close + Process.exit! + } + + write.close + read.read(1) + read.read(1) # to give children a chance to set their process groups + read.close + Process.wait(0).should == pid2 + Process.wait.should == pid1 + end + + # This spec is probably system-dependent. + it "doesn't block if no child is available when WNOHANG is used" do + pid = Process.fork { 10.times { sleep(1) }; Process.exit! } + Process.wait(pid, Process::WNOHANG).should == nil + Process.kill("TERM", pid) + Process.wait.should == pid + end + + it "always accepts flags=0" do + pid = Process.fork { Process.exit! } + Process.wait(-1, 0).should == pid + lambda { Process.kill(0, pid) }.should raise_error(Errno::ESRCH) + end +end diff --git a/1.8/core/process/waitall_spec.rb b/1.8/core/process/waitall_spec.rb new file mode 100644 index 0000000000..7ba212e21d --- /dev/null +++ b/1.8/core/process/waitall_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Process.waitall" do + before :all do + Process.waitall + end + + it "returns an empty array when there are no children" do + Process.waitall.should == [] + end + + it "takes no arguments" do + lambda { Process.waitall(0) }.should raise_error(ArgumentError) + end + + it "waits for all children" do + pids = [] + pids << Process.fork { Process.exit! 2 } + pids << Process.fork { Process.exit! 1 } + pids << Process.fork { Process.exit! 0 } + Process.waitall + pids.each { |pid| + lambda { Process.kill(0, pid) }.should raise_error(Errno::ESRCH) + } + end + + it "returns an array of pid/status pairs" do + pids = [] + pids << Process.fork { Process.exit! 2 } + pids << Process.fork { Process.exit! 1 } + pids << Process.fork { Process.exit! 0 } + a = Process.waitall + a.class.should == Array + a.size.should == 3 + pids.each { |pid| + pid_status = a.assoc(pid) + pid_status.class.should == Array + pid_status.size.should == 2 + pid_status.first.should == pid + pid_status.last.class.should == Process::Status + } + end +end diff --git a/1.8/core/process/waitpid2_spec.rb b/1.8/core/process/waitpid2_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/process/waitpid2_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/process/waitpid_spec.rb b/1.8/core/process/waitpid_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/process/waitpid_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/range/begin_spec.rb b/1.8/core/range/begin_spec.rb new file mode 100644 index 0000000000..5d57b30404 --- /dev/null +++ b/1.8/core/range/begin_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/begin' + +describe "Range#begin" do + it_behaves_like(:range_begin, :begin) +end diff --git a/1.8/core/range/case_compare_spec.rb b/1.8/core/range/case_compare_spec.rb new file mode 100644 index 0000000000..8bef9585ae --- /dev/null +++ b/1.8/core/range/case_compare_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include' + +describe "Range#===" do + it_behaves_like(:range_include, :===) +end diff --git a/1.8/core/range/each_spec.rb b/1.8/core/range/each_spec.rb new file mode 100644 index 0000000000..6f26cc5e53 --- /dev/null +++ b/1.8/core/range/each_spec.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range#each" do + it "passes each element to the given block by using #succ" do + a = [] + (-5..5).each { |i| a << i } + a.should == [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5] + + a = [] + ('A'..'D').each { |i| a << i } + a.should == ['A','B','C','D'] + + a = [] + ('A'...'D').each { |i| a << i } + a.should == ['A','B','C'] + + a = [] + (0xfffd...0xffff).each { |i| a << i } + a.should == [0xfffd, 0xfffe] + + y = mock('y') + x = mock('x') + x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1) + x.should_receive(:<=>).with(x).any_number_of_times.and_return(0) + x.should_receive(:succ).any_number_of_times.and_return(y) + y.should_receive(:<=>).with(x).any_number_of_times.and_return(1) + y.should_receive(:<=>).with(y).any_number_of_times.and_return(0) + + a = [] + (x..y).each { |i| a << i } + a.should == [x, y] + end + + it "raises a TypeError if the first element does not respond to #succ" do + lambda { (0.5..2.4).each { |i| i } }.should raise_error(TypeError) + + b = mock('x') + (a = mock('1')).should_receive(:method_missing).with(:<=>, b).and_return(1) + + lambda { (a..b).each { |i| i } }.should raise_error(TypeError) + end + + it "returns self" do + (1..10).each {}.should == (1..10) + end +end diff --git a/1.8/core/range/end_spec.rb b/1.8/core/range/end_spec.rb new file mode 100644 index 0000000000..1408acb786 --- /dev/null +++ b/1.8/core/range/end_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/end' + +describe "Range#end" do + it_behaves_like(:range_end, :end) +end diff --git a/1.8/core/range/eql_spec.rb b/1.8/core/range/eql_spec.rb new file mode 100644 index 0000000000..a1646f2b0f --- /dev/null +++ b/1.8/core/range/eql_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Range#eql?" do + it_behaves_like(:range_eql, :eql?) +end diff --git a/1.8/core/range/equal_value_spec.rb b/1.8/core/range/equal_value_spec.rb new file mode 100644 index 0000000000..275bfbf7d4 --- /dev/null +++ b/1.8/core/range/equal_value_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Range#==" do + it_behaves_like(:range_eql, :==) +end diff --git a/1.8/core/range/exclude_end_spec.rb b/1.8/core/range/exclude_end_spec.rb new file mode 100644 index 0000000000..2abcccc39e --- /dev/null +++ b/1.8/core/range/exclude_end_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range#exclude_end?" do + it "returns true if the range exludes the end value" do + (-2..2).exclude_end?.should == false + ('A'..'B').exclude_end?.should == false + (0.5..2.4).exclude_end?.should == false + (0xfffd..0xffff).exclude_end?.should == false + + (0...5).exclude_end?.should == true + ('A'...'B').exclude_end?.should == true + (0.5...2.4).exclude_end?.should == true + (0xfffd...0xffff).exclude_end?.should == true + end +end diff --git a/1.8/core/range/first_spec.rb b/1.8/core/range/first_spec.rb new file mode 100644 index 0000000000..6100f421c3 --- /dev/null +++ b/1.8/core/range/first_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/begin' + +describe "Range#first" do + it_behaves_like(:range_begin, :first) +end diff --git a/1.8/core/range/hash_spec.rb b/1.8/core/range/hash_spec.rb new file mode 100644 index 0000000000..d9b46d1819 --- /dev/null +++ b/1.8/core/range/hash_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range#hash" do + it "is provided" do + (0..1).respond_to?(:hash).should == true + ('A'..'Z').respond_to?(:hash).should == true + (0xfffd..0xffff).respond_to?(:hash).should == true + (0.5..2.4).respond_to?(:hash).should == true + end + + it "generates the same hash values for Ranges with the same start, end and exclude_end? values" do + (0..1).hash.should == (0..1).hash + (0...10).hash.should == (0...10).hash + (0..10).hash.should_not == (0...10).hash + end +end diff --git a/1.8/core/range/include_spec.rb b/1.8/core/range/include_spec.rb new file mode 100644 index 0000000000..34839de715 --- /dev/null +++ b/1.8/core/range/include_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include' + +describe "Range#include?" do + it_behaves_like(:range_include, :include?) +end diff --git a/1.8/core/range/initialize_spec.rb b/1.8/core/range/initialize_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/range/initialize_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/range/inspect_spec.rb b/1.8/core/range/inspect_spec.rb new file mode 100644 index 0000000000..160c00d3d5 --- /dev/null +++ b/1.8/core/range/inspect_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range#inspect" do + it "provides a printable form, using #inspect to convert the start and end objects" do + ('A'..'Z').inspect.should == '"A".."Z"' + ('A'...'Z').inspect.should == '"A"..."Z"' + + (0..21).inspect.should == "0..21" + (-8..0).inspect.should == "-8..0" + (-411..959).inspect.should == "-411..959" + (0xfff..0xfffff).inspect.should == "4095..1048575" + (0.5..2.4).inspect.should == "0.5..2.4" + end +end diff --git a/1.8/core/range/last_spec.rb b/1.8/core/range/last_spec.rb new file mode 100644 index 0000000000..7c1e6a8b74 --- /dev/null +++ b/1.8/core/range/last_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/end' + +describe "Range#last" do + it_behaves_like(:range_end, :last) +end diff --git a/1.8/core/range/member_spec.rb b/1.8/core/range/member_spec.rb new file mode 100644 index 0000000000..89e7b2ef09 --- /dev/null +++ b/1.8/core/range/member_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include' + +describe "Range#member?" do + it_behaves_like(:range_include, :member?) +end diff --git a/1.8/core/range/new_spec.rb b/1.8/core/range/new_spec.rb new file mode 100644 index 0000000000..a76b252c44 --- /dev/null +++ b/1.8/core/range/new_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range.new" do + it "constructs a range using the given start and end" do + range = Range.new('a', 'c') + range.should == ('a'..'c') + + range.first.should == 'a' + range.last.should == 'c' + end + + it "includes the end object when the third parameter is omitted or false" do + Range.new('a', 'c').to_a.should == ['a', 'b', 'c'] + Range.new(1, 3).to_a.should == [1, 2, 3] + + Range.new('a', 'c', false).to_a.should == ['a', 'b', 'c'] + Range.new(1, 3, false).to_a.should == [1, 2, 3] + + Range.new('a', 'c', true).to_a.should == ['a', 'b'] + Range.new(1, 3, 1).to_a.should == [1, 2] + + Range.new(1, 3, mock('[1,2]')).to_a.should == [1, 2] + Range.new(1, 3, :test).to_a.should == [1, 2] + end + + it "raises an ArgumentError when the given start and end can't be compared by using #<=>" do + lambda { Range.new(1, mock('x')) }.should raise_error(ArgumentError) + lambda { Range.new(mock('x'), mock('y')) }.should raise_error(ArgumentError) + + b = mock('x') + (a = mock('nil')).should_receive(:method_missing).with(:<=>, b).and_return(nil) + lambda { Range.new(a, b) }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/range/shared/begin.rb b/1.8/core/range/shared/begin.rb new file mode 100644 index 0000000000..faeb6a89be --- /dev/null +++ b/1.8/core/range/shared/begin.rb @@ -0,0 +1,12 @@ +shared :range_begin do |cmd| + describe "Range##{cmd}" do + it "returns the first element of self" do + (-1..1).send(cmd).should == -1 + (0..1).send(cmd).should == 0 + (0xffff...0xfffff).send(cmd).should == 65535 + ('Q'..'T').send(cmd).should == 'Q' + ('Q'...'T').send(cmd).should == 'Q' + (0.5..2.4).send(cmd).should == 0.5 + end + end +end diff --git a/1.8/core/range/shared/end.rb b/1.8/core/range/shared/end.rb new file mode 100644 index 0000000000..4f50ad3d5f --- /dev/null +++ b/1.8/core/range/shared/end.rb @@ -0,0 +1,12 @@ +shared :range_end do |cmd| + describe "Range##{cmd}" do + it "end returns the last element of self" do + (-1..1).send(cmd).should == 1 + (0..1).send(cmd).should == 1 + ("A".."Q").send(cmd).should == "Q" + ("A"..."Q").send(cmd).should == "Q" + (0xffff...0xfffff).send(cmd).should == 1048575 + (0.5..2.4).send(cmd).should == 2.4 + end + end +end diff --git a/1.8/core/range/shared/equal_value.rb b/1.8/core/range/shared/equal_value.rb new file mode 100644 index 0000000000..a73def0f1a --- /dev/null +++ b/1.8/core/range/shared/equal_value.rb @@ -0,0 +1,28 @@ +shared :range_eql do |cmd| + describe "Range##{cmd}" do + it "returns true if other has same begin, end, and exclude_end? values" do + (0..2).send(cmd, 0..2).should == true + ('G'..'M').send(cmd,'G'..'M').should == true + (0.5..2.4).send(cmd, 0.5..2.4).should == true + (5..10).send(cmd, Range.new(5,10)).should == true + ('D'..'V').send(cmd, Range.new('D','V')).should == true + (0.5..2.4).send(cmd, Range.new(0.5, 2.4)).should == true + (0xffff..0xfffff).send(cmd, 0xffff..0xfffff).should == true + (0xffff..0xfffff).send(cmd, Range.new(0xffff,0xfffff)).should == true + + + ('Q'..'X').send(cmd, 'A'..'C').should == false + ('Q'...'X').send(cmd, 'Q'..'W').should == false + ('Q'..'X').send(cmd, 'Q'...'X').should == false + (0.5..2.4).send(cmd, 0.5...2.4).should == false + (1482..1911).send(cmd, 1482...1911).should == false + (0xffff..0xfffff).send(cmd, 0xffff...0xfffff).should == false + end + + it "returns false if other is no Range" do + (1..10).send(cmd, 1).should == false + (1..10).send(cmd, 'a').should == false + (1..10).send(cmd, mock('x')).should == false + end + end +end diff --git a/1.8/core/range/shared/include.rb b/1.8/core/range/shared/include.rb new file mode 100644 index 0000000000..1486cdb2c6 --- /dev/null +++ b/1.8/core/range/shared/include.rb @@ -0,0 +1,20 @@ +shared :range_include do |cmd| + describe "Range##{cmd}" do + it "returns true if other is an element of self" do + (0..5).send(cmd, 2).should == true + (-5..5).send(cmd, 0).should == true + (-1...1).send(cmd, 10.5).should == false + (-10..-2).send(cmd, -2.5).should == true + ('C'..'X').send(cmd, 'M').should == true + ('C'..'X').send(cmd, 'A').should == false + ('B'...'W').send(cmd, 'W').should == false + ('B'...'W').send(cmd, 'Q').should == true + (0xffff..0xfffff).send(cmd, 0xffffd).should == true + (0xffff..0xfffff).send(cmd, 0xfffd).should == false + (0.5..2.4).send(cmd, 2).should == true + (0.5..2.4).send(cmd, 2.5).should == false + (0.5..2.4).send(cmd, 2.4).should == true + (0.5...2.4).send(cmd, 2.4).should == false + end + end +end diff --git a/1.8/core/range/step_spec.rb b/1.8/core/range/step_spec.rb new file mode 100644 index 0000000000..ccb6715d34 --- /dev/null +++ b/1.8/core/range/step_spec.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range#step" do + it "passes each nth element to the block" do + a = [] + (-5..5).step(2) { |x| a << x } + a.should == [-5, -3, -1, 1, 3, 5] + + a = [] + ("A".."F").step(2) { |x| a << x } + a.should == ["A", "C", "E"] + + a = [] + ("A"..."G").step(2) { |x| a << x } + a.should == ["A", "C", "E"] + + a = [] + (0.5..2.4).step(0.5) { |x| a << x } + a.should == [0.5, 1, 1.5, 2] + end + + it "raises an ArgumentError if stepsize is 0 or negative" do + lambda { (-5..5).step(0) { |x| x } }.should raise_error(ArgumentError) + lambda { (-5.5..5.7).step(0.0) { |x| x } }.should raise_error(ArgumentError) + lambda { (-5..5).step(-2) { |x| x } }.should raise_error(ArgumentError) + end + + it "raises a TypeError if the first element does not respond to #succ" do + b = mock('x') + (a = mock('1')).should_receive(:method_missing).with(:<=>, b).and_return(1) + + lambda { (a..b).step(1) { |i| i } }.should raise_error(TypeError) + end + + it "returns self" do + (1..10).step(1) {}.should == (1..10) + end + + it "raises TypeError if the argument is non-numeric" do + obj = mock("mock") + lambda { (1..10).step(obj) }.should raise_error(TypeError) + end + + it "coerces the argument to intger by invoking to_int" do + (obj = mock("2")).should_receive(:to_int).and_return(2) + res = [] + (1..10).step(obj) {|x| res << x} + res.should == [1, 3, 5, 7, 9] + end +end diff --git a/1.8/core/range/to_a_spec.rb b/1.8/core/range/to_a_spec.rb new file mode 100644 index 0000000000..1511b7dc93 --- /dev/null +++ b/1.8/core/range/to_a_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range#to_a" do + it "converts self to an array" do + (-5..5).to_a.should == [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5] + ('A'..'D').to_a.should == ['A','B','C','D'] + ('A'...'D').to_a.should == ['A','B','C'] + (0xfffd...0xffff).to_a.should == [0xfffd,0xfffe] + lambda { (0.5..2.4).to_a }.should raise_error(TypeError) + end +end \ No newline at end of file diff --git a/1.8/core/range/to_s_spec.rb b/1.8/core/range/to_s_spec.rb new file mode 100644 index 0000000000..9779fa3a9e --- /dev/null +++ b/1.8/core/range/to_s_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range#to_s" do + it "provides a printable form of self" do + (0..21).to_s.should == "0..21" + (-8..0).to_s.should == "-8..0" + (-411..959).to_s.should == "-411..959" + ('A'..'Z').to_s.should == 'A..Z' + ('A'...'Z').to_s.should == 'A...Z' + (0xfff..0xfffff).to_s.should == "4095..1048575" + (0.5..2.4).inspect.should == "0.5..2.4" + end +end diff --git a/1.8/core/regexp/case_compare_spec.rb b/1.8/core/regexp/case_compare_spec.rb new file mode 100644 index 0000000000..b685ffc284 --- /dev/null +++ b/1.8/core/regexp/case_compare_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp#===" do + it "is true if there is a match" do + (/abc/ === "aabcc").should == true + end + + it "is false if there is no match" do + (/abc/ === "xyz").should == false + end +end diff --git a/1.8/core/regexp/casefold_spec.rb b/1.8/core/regexp/casefold_spec.rb new file mode 100644 index 0000000000..3f6ff74c57 --- /dev/null +++ b/1.8/core/regexp/casefold_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp#casefold?" do + it "returns the value of the case-insensitive flag" do + /abc/i.casefold?.should == true + /xyz/.casefold?.should == false + end +end diff --git a/1.8/core/regexp/compile_spec.rb b/1.8/core/regexp/compile_spec.rb new file mode 100644 index 0000000000..e8efdfdf1b --- /dev/null +++ b/1.8/core/regexp/compile_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/new' + +describe "Range.compile" do + it_behaves_like(:regexp_new, :compile) +end diff --git a/1.8/core/regexp/eql_spec.rb b/1.8/core/regexp/eql_spec.rb new file mode 100644 index 0000000000..07278da83e --- /dev/null +++ b/1.8/core/regexp/eql_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Regexp#eql?" do + it_behaves_like(:regexp_eql, :eql?) +end diff --git a/1.8/core/regexp/equal_value_spec.rb b/1.8/core/regexp/equal_value_spec.rb new file mode 100644 index 0000000000..b741f157bf --- /dev/null +++ b/1.8/core/regexp/equal_value_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Regexp#==" do + it_behaves_like(:regexp_eql, :==) +end diff --git a/1.8/core/regexp/escape_spec.rb b/1.8/core/regexp/escape_spec.rb new file mode 100644 index 0000000000..a94b283c5b --- /dev/null +++ b/1.8/core/regexp/escape_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/quote' + +describe "Range.escape" do + it_behaves_like(:regexp_quote, :escape) +end diff --git a/1.8/core/regexp/hash_spec.rb b/1.8/core/regexp/hash_spec.rb new file mode 100644 index 0000000000..e4781dc590 --- /dev/null +++ b/1.8/core/regexp/hash_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp#hash" do + it "is provided" do + Regexp.new('').respond_to?(:hash).should == true + end + + it "is based on the text and options of Regexp" do + (/cat/ix.hash == /cat/ixn.hash).should == true + (/dog/m.hash == /dog/m.hash).should == true + (/cat/.hash == /cat/ix.hash).should == false + (/cat/.hash == /dog/.hash).should == false + end +end diff --git a/1.8/core/regexp/initialize_copy_spec.rb b/1.8/core/regexp/initialize_copy_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/regexp/initialize_copy_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/regexp/initialize_spec.rb b/1.8/core/regexp/initialize_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/regexp/initialize_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/regexp/inspect_spec.rb b/1.8/core/regexp/inspect_spec.rb new file mode 100644 index 0000000000..6df05a6360 --- /dev/null +++ b/1.8/core/regexp/inspect_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp#inspect" do + it "returns a formatted string that would eval to the same regexp" do + /ab+c/ix.inspect.should == "/ab+c/ix" + /a(.)+s/n.inspect.should =~ %r|/a(.)+s/n?| # Default 'n' may not appear + /a(.)+s/u.inspect.should == "/a(.)+s/u" # But a specified one does + end + + it "correctly escapes forward slashes /" do + Regexp.new("/foo/bar").inspect.should == "/\\/foo\\/bar/" + Regexp.new("/foo/bar[/]").inspect.should == "/\\/foo\\/bar[\\/]/" + end +end diff --git a/1.8/core/regexp/kcode_spec.rb b/1.8/core/regexp/kcode_spec.rb new file mode 100644 index 0000000000..cf762a2ec2 --- /dev/null +++ b/1.8/core/regexp/kcode_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp#kcode" do + it "returns the character set code" do + default = /f.(o)/.kcode + default.should_not == 'sjis' + default.should_not == 'euc' + default.should_not == 'utf8' + + /ab+c/s.kcode.should == "sjis" + /a(.)+s/n.kcode.should == "none" + /xyz/e.kcode.should == "euc" + /cars/u.kcode.should == "utf8" + end +end diff --git a/1.8/core/regexp/last_match_spec.rb b/1.8/core/regexp/last_match_spec.rb new file mode 100644 index 0000000000..6071ef6a99 --- /dev/null +++ b/1.8/core/regexp/last_match_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Range.last_match" do + it "returns MatchData instance when not passed arguments" do + /c(.)t/ =~ 'cat' + + Regexp.last_match.should be_kind_of(MatchData) + end + + it "returns the nth field in this MatchData when passed a Fixnum" do + /c(.)t/ =~ 'cat' + Regexp.last_match(1).should == 'a' + end +end diff --git a/1.8/core/regexp/match_spec.rb b/1.8/core/regexp/match_spec.rb new file mode 100644 index 0000000000..067b47f6b4 --- /dev/null +++ b/1.8/core/regexp/match_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/match' + +describe "Regexp#=~" do + it_behaves_like(:regexp_match, :=~) +end + +describe "Regexp#match" do + it_behaves_like(:regexp_match, :match) +end + +describe "Regexp#~" do + it "matches against the contents of $_" do + $_ = "input data" + (~ /at/).should == 7 + end +end + +describe "Regexp#=~ on a successful match" do + it "returns the index of the first character of the matching region" do + (/(.)(.)(.)/ =~ "abc").should == 0 + end +end + +describe "Regexp#match on a successful match" do + it "returns a MatchData object" do + (/(.)(.)(.)/.match "abc").class.should == MatchData + end +end diff --git a/1.8/core/regexp/new_spec.rb b/1.8/core/regexp/new_spec.rb new file mode 100644 index 0000000000..cd0038c421 --- /dev/null +++ b/1.8/core/regexp/new_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/new' + +describe "Regexp.new" do + it_behaves_like(:regexp_new, :new) +end diff --git a/1.8/core/regexp/options_spec.rb b/1.8/core/regexp/options_spec.rb new file mode 100644 index 0000000000..1b56512409 --- /dev/null +++ b/1.8/core/regexp/options_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp#options" do + it "returns a Fixnum bitvector of regexp options for the Regexp object" do + /cat/.options.class.should == Fixnum + /cat/ix.options.class.should == Fixnum + end + + it "allows checking for presence of a certain option with bitwise &" do + (/cat/.options & Regexp::IGNORECASE).should == 0 + (/cat/i.options & Regexp::IGNORECASE).should_not == 0 + (/cat/.options & Regexp::MULTILINE).should == 0 + (/cat/m.options & Regexp::MULTILINE).should_not == 0 + (/cat/.options & Regexp::EXTENDED).should == 0 + (/cat/x.options & Regexp::EXTENDED).should_not == 0 + (/cat/mx.options & Regexp::MULTILINE).should_not == 0 + (/cat/mx.options & Regexp::EXTENDED).should_not == 0 + (/cat/xi.options & Regexp::IGNORECASE).should_not == 0 + (/cat/xi.options & Regexp::EXTENDED).should_not == 0 + end +end diff --git a/1.8/core/regexp/quote_spec.rb b/1.8/core/regexp/quote_spec.rb new file mode 100644 index 0000000000..37964e7073 --- /dev/null +++ b/1.8/core/regexp/quote_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/quote' + +describe "Range.quote" do + it_behaves_like(:regexp_quote, :quote) +end diff --git a/1.8/core/regexp/shared/equal_value.rb b/1.8/core/regexp/shared/equal_value.rb new file mode 100644 index 0000000000..93c8c58b42 --- /dev/null +++ b/1.8/core/regexp/shared/equal_value.rb @@ -0,0 +1,21 @@ +shared :regexp_eql do |cmd| + describe "Regexp##{cmd}" do + it "is true if self and other have the same pattern" do + /abc/.send(cmd, /abc/).should == true + /abc/.send(cmd, /abd/).should == false + end + + it "is true if self and other have the same character set code" do + /abc/.send(cmd, /abc/x).should == false + /abc/x.send(cmd, /abc/x).should == true + /abc/u.send(cmd, /abc/n).should == false + /abc/u.send(cmd, /abc/u).should == true + /abc/n.send(cmd, /abc/n).should == true + end + + it "is true if other has the same #casefold? values" do + /abc/.send(cmd, /abc/i).should == false + /abc/i.send(cmd, /abc/i).should == true + end + end +end diff --git a/1.8/core/regexp/shared/match.rb b/1.8/core/regexp/shared/match.rb new file mode 100644 index 0000000000..e0af093f94 --- /dev/null +++ b/1.8/core/regexp/shared/match.rb @@ -0,0 +1,11 @@ +shared :regexp_match do |cmd| + describe "Regexp##{cmd}" do + it "returns nil if there is no match" do + /xyz/.send(cmd,"abxyc").should == nil + end + + it "returns nil if the object is nil" do + /\w+/.send(cmd, nil).should == nil + end + end +end diff --git a/1.8/core/regexp/shared/new.rb b/1.8/core/regexp/shared/new.rb new file mode 100644 index 0000000000..0f95ce315d --- /dev/null +++ b/1.8/core/regexp/shared/new.rb @@ -0,0 +1,163 @@ +shared :regexp_new do |cmd| + describe "Regexp.#{cmd}" do + it "requires one argument and creates a new regular expression object" do + Regexp.send(cmd, '').is_a?(Regexp).should == true + end + + it "works by default for subclasses with overridden #initialize" do + class RegexpSpecsSubclass < Regexp + def initialize(*args) + super + @args = args + end + + attr_accessor :args + end + + class RegexpSpecsSubclassTwo < Regexp; end + + RegexpSpecsSubclass.send(cmd, "hi").class.should == RegexpSpecsSubclass + RegexpSpecsSubclass.send(cmd, "hi").args.first.should == "hi" + + RegexpSpecsSubclassTwo.send(cmd, "hi").class.should == RegexpSpecsSubclassTwo + end + end + + describe "Regexp.#{cmd} given a String" do + it "uses the String argument as an unescaped literal to construct a Regexp object" do + Regexp.send(cmd, "^hi{2,3}fo.o$").should == /^hi{2,3}fo.o$/ + end + + it "should throw regexp error with incorrect regexp" do + lambda { Regexp.send(cmd, "^[$", 0) }.should raise_error(RegexpError) + end + + it "does not set Regexp options if only given one argument" do + r = Regexp.send(cmd, 'Hi') + (r.options & Regexp::IGNORECASE).should == 0 + (r.options & Regexp::MULTILINE).should == 0 + (r.options & Regexp::EXTENDED).should == 0 + end + + it "does not set Regexp options if second argument is nil or false" do + r = Regexp.send(cmd, 'Hi', nil) + (r.options & Regexp::IGNORECASE).should == 0 + (r.options & Regexp::MULTILINE).should == 0 + (r.options & Regexp::EXTENDED).should == 0 + + r = Regexp.send(cmd, 'Hi', false) + (r.options & Regexp::IGNORECASE).should == 0 + (r.options & Regexp::MULTILINE).should == 0 + (r.options & Regexp::EXTENDED).should == 0 + end + + it "sets options from second argument if it is one of the Fixnum option constants" do + r = Regexp.send(cmd, 'Hi', Regexp::IGNORECASE) + (r.options & Regexp::IGNORECASE).should_not == 0 + (r.options & Regexp::MULTILINE).should == 0 + (r.options & Regexp::EXTENDED).should == 0 + + r = Regexp.send(cmd, 'Hi', Regexp::MULTILINE) + (r.options & Regexp::IGNORECASE).should == 0 + (r.options & Regexp::MULTILINE).should_not == 0 + (r.options & Regexp::EXTENDED).should == 0 + + r = Regexp.send(cmd, 'Hi', Regexp::EXTENDED) + (r.options & Regexp::IGNORECASE).should == 0 + (r.options & Regexp::MULTILINE).should == 0 + (r.options & Regexp::EXTENDED).should_not == 1 + end + + it "accepts a Fixnum of two or more options ORed together as the second argument" do + r = Regexp.send(cmd, 'Hi', Regexp::IGNORECASE | Regexp::EXTENDED) + (r.options & Regexp::IGNORECASE).should_not == 0 + (r.options & Regexp::MULTILINE).should == 0 + (r.options & Regexp::EXTENDED).should_not == 0 + end + + it "treats any non-Fixnum, non-nil, non-false second argument as IGNORECASE" do + r = Regexp.send(cmd, 'Hi', Object.new) + (r.options & Regexp::IGNORECASE).should_not == 0 + (r.options & Regexp::MULTILINE).should == 0 + (r.options & Regexp::EXTENDED).should == 0 + end + + it "does not enable multibyte support by default" do + r = Regexp.send cmd, 'Hi', true + r.kcode.should_not == 'euc' + r.kcode.should_not == 'sjis' + r.kcode.should_not == 'utf8' + end + + it "enables EUC encoding if third argument is 'e' or 'euc' (case-insensitive)" do + Regexp.send(cmd, 'Hi', nil, 'e').kcode.should == 'euc' + Regexp.send(cmd, 'Hi', nil, 'E').kcode.should == 'euc' + Regexp.send(cmd, 'Hi', nil, 'euc').kcode.should == 'euc' + Regexp.send(cmd, 'Hi', nil, 'EUC').kcode.should == 'euc' + Regexp.send(cmd, 'Hi', nil, 'EuC').kcode.should == 'euc' + end + + it "enables SJIS encoding if third argument is 's' or 'sjis' (case-insensitive)" do + Regexp.send(cmd, 'Hi', nil, 's').kcode.should == 'sjis' + Regexp.send(cmd, 'Hi', nil, 'S').kcode.should == 'sjis' + Regexp.send(cmd, 'Hi', nil, 'sjis').kcode.should == 'sjis' + Regexp.send(cmd, 'Hi', nil, 'SJIS').kcode.should == 'sjis' + Regexp.send(cmd, 'Hi', nil, 'sJiS').kcode.should == 'sjis' + end + + it "enables UTF-8 encoding if third argument is 'u' or 'utf8' (case-insensitive)" do + Regexp.send(cmd, 'Hi', nil, 'u').kcode.should == 'utf8' + Regexp.send(cmd, 'Hi', nil, 'U').kcode.should == 'utf8' + Regexp.send(cmd, 'Hi', nil, 'utf8').kcode.should == 'utf8' + Regexp.send(cmd, 'Hi', nil, 'UTF8').kcode.should == 'utf8' + Regexp.send(cmd, 'Hi', nil, 'uTf8').kcode.should == 'utf8' + end + + it "disables multibyte support if third argument is 'n' or 'none' (case insensitive)" do + Regexp.send(cmd, 'Hi', nil, 'N').kcode.should == 'none' + Regexp.send(cmd, 'Hi', nil, 'n').kcode.should == 'none' + Regexp.send(cmd, 'Hi', nil, 'nONE').kcode.should == 'none' + end + end + + describe "Regexp.#{cmd} given a Regexp" do + it "uses the argument as a literal to construct a Regexp object" do + Regexp.send(cmd, /^hi{2,3}fo.o$/).should == /^hi{2,3}fo.o$/ + end + + it "preserves any options given in the Regexp literal" do + (Regexp.send(cmd, /Hi/i).options & Regexp::IGNORECASE).should_not == 0 + (Regexp.send(cmd, /Hi/m).options & Regexp::MULTILINE).should_not == 0 + (Regexp.send(cmd, /Hi/x).options & Regexp::EXTENDED).should_not == 0 + + r = Regexp.send cmd, /Hi/imx + (r.options & Regexp::IGNORECASE).should_not == 0 + (r.options & Regexp::MULTILINE).should_not == 0 + (r.options & Regexp::EXTENDED).should_not == 0 + + r = Regexp.send cmd, /Hi/ + (r.options & Regexp::IGNORECASE).should == 0 + (r.options & Regexp::MULTILINE).should == 0 + (r.options & Regexp::EXTENDED).should == 0 + end + + it "does not honour options given as additional arguments" do + r = Regexp.send cmd, /hi/, Regexp::IGNORECASE + (r.options & Regexp::IGNORECASE).should == 0 + end + + it "does not enable multibyte support by default" do + r = Regexp.send cmd, /Hi/ + r.kcode.should_not == 'euc' + r.kcode.should_not == 'sjis' + r.kcode.should_not == 'utf8' + end + + it "enables multibyte support if given in the literal" do + Regexp.send(cmd, /Hi/u).kcode.should == 'utf8' + Regexp.send(cmd, /Hi/e).kcode.should == 'euc' + Regexp.send(cmd, /Hi/s).kcode.should == 'sjis' + Regexp.send(cmd, /Hi/n).kcode.should == 'none' + end + end +end diff --git a/1.8/core/regexp/shared/quote.rb b/1.8/core/regexp/shared/quote.rb new file mode 100644 index 0000000000..c13a79e272 --- /dev/null +++ b/1.8/core/regexp/shared/quote.rb @@ -0,0 +1,10 @@ +shared :regexp_quote do |cmd| + describe "Regexp.#{cmd}" do + it "escapes any characters with special meaning in a regular expression" do + Regexp.send(cmd, '\*?{}.+^[]()- ').should == '\\\\\*\?\{\}\.\+\^\[\]\(\)\-\\ ' + Regexp.send(cmd, "\*?{}.+^[]()- ").should == '\\*\\?\\{\\}\\.\\+\\^\\[\\]\\(\\)\\-\\ ' + Regexp.send(cmd, '\n\r\f\t').should == '\\\\n\\\\r\\\\f\\\\t' + Regexp.send(cmd, "\n\r\f\t").should == '\\n\\r\\f\\t' + end + end +end diff --git a/1.8/core/regexp/source_spec.rb b/1.8/core/regexp/source_spec.rb new file mode 100644 index 0000000000..7382059d50 --- /dev/null +++ b/1.8/core/regexp/source_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp#source" do + it "returns the original string of the pattern" do + /ab+c/ix.source.should == "ab+c" + /x(.)xz/.source.should == "x(.)xz" + end +end diff --git a/1.8/core/regexp/to_s_spec.rb b/1.8/core/regexp/to_s_spec.rb new file mode 100644 index 0000000000..126cfae4b9 --- /dev/null +++ b/1.8/core/regexp/to_s_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp#to_s" do + it "returns a string in (?xxx:yyy) notation" do + /ab+c/ix.to_s.should == "(?ix-m:ab+c)" + /xyz/.to_s.should == "(?-mix:xyz)" + /jis/s.to_s.should == "(?-mix:jis)" + end +end diff --git a/1.8/core/regexp/union_spec.rb b/1.8/core/regexp/union_spec.rb new file mode 100644 index 0000000000..b9f1cd6a85 --- /dev/null +++ b/1.8/core/regexp/union_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Regexp.union" do + it "returns /(?!)/ when passed no arguments" do + Regexp.union.should == /(?!)/ + end + + it "returns a regular expression that will match passed arguments" do + Regexp.union("penzance").should == /penzance/ + Regexp.union("skiing", "sledding").should == /skiing|sledding/ + Regexp.union(/dogs/, /cats/i).should == /(?-mix:dogs)|(?i-mx:cats)/ + end +end diff --git a/1.8/core/signal/list_spec.rb b/1.8/core/signal/list_spec.rb new file mode 100644 index 0000000000..2d80fa4805 --- /dev/null +++ b/1.8/core/signal/list_spec.rb @@ -0,0 +1,64 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Signal.list" do + RUBY18_SIGNALS = %w{ + EXIT + HUP + INT + QUIT + ILL + TRAP + IOT + ABRT + EMT + FPE + KILL + BUS + SEGV + SYS + PIPE + ALRM + TERM + URG + STOP + TSTP + CONT + CHLD + CLD + TTIN + TTOU + IO + XCPU + XFSZ + VTALRM + PROF + WINCH + USR1 + USR2 + LOST + MSG + PWR + POLL + DANGER + MIGRATE + PRE + GRANT + RETRACT + SOUND + INFO + } + + it "doesn't contain other signals than in 1.8" do + (Signal.list.keys - RUBY18_SIGNALS).should == [] + end + + if Signal.list["CHLD"] + it "should redefine CLD with CHLD if defined" do + Signal.list["CLD"].should == Signal.list["CHLD"] + end + end + + it "should contain the EXIT key with a value of zero" do + Signal.list["EXIT"].should == 0 + end +end diff --git a/1.8/core/signal/trap_spec.rb b/1.8/core/signal/trap_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/signal/trap_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/string/allocate_spec.rb b/1.8/core/string/allocate_spec.rb new file mode 100644 index 0000000000..f056c0149c --- /dev/null +++ b/1.8/core/string/allocate_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "String.allocate" do + it "returns an instance of String" do + str = String.allocate + str.should be_kind_of(String) + end + + it "returns a fully-formed String" do + str = String.allocate + str.size.should == 0 + str << "more" + str.should == "more" + end +end diff --git a/1.8/core/string/append_spec.rb b/1.8/core/string/append_spec.rb new file mode 100644 index 0000000000..028a235a79 --- /dev/null +++ b/1.8/core/string/append_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/concat.rb' + +describe "String#<<" do + it_behaves_like(:string_concat, :<<) +end \ No newline at end of file diff --git a/1.8/core/string/capitalize_spec.rb b/1.8/core/string/capitalize_spec.rb new file mode 100644 index 0000000000..34fbda2135 --- /dev/null +++ b/1.8/core/string/capitalize_spec.rb @@ -0,0 +1,55 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#capitalize" do + it "returns a copy of self with the first character converted to uppercase and the remainder to lowercase" do + "".capitalize.should == "" + "h".capitalize.should == "H" + "H".capitalize.should == "H" + "hello".capitalize.should == "Hello" + "HELLO".capitalize.should == "Hello" + "123ABC".capitalize.should == "123abc" + end + + it "taints resulting string when self is tainted" do + "".taint.capitalize.tainted?.should == true + "hello".taint.capitalize.tainted?.should == true + end + + it "is locale insensitive (only upcases a-z and only downcases A-Z)" do + "ÄÖÜ".capitalize.should == "ÄÖÜ" + "ärger".capitalize.should == "ärger" + "BÄR".capitalize.should == "BÄr" + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").capitalize.class.should == StringSpecs::MyString + StringSpecs::MyString.new("Hello").capitalize.class.should == StringSpecs::MyString + end +end + +describe "String#capitalize!" do + it "capitalizes self in place" do + a = "hello" + a.capitalize!.equal?(a).should == true + a.should == "Hello" + end + + it "returns nil when no changes are made" do + a = "Hello" + a.capitalize!.should == nil + a.should == "Hello" + + "".capitalize!.should == nil + "H".capitalize!.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + ["", "Hello", "hello"].each do |a| + a.freeze + lambda { a.capitalize! }.should raise_error(TypeError) + end + end + end +end diff --git a/1.8/core/string/casecmp_spec.rb b/1.8/core/string/casecmp_spec.rb new file mode 100644 index 0000000000..f57ba7d50c --- /dev/null +++ b/1.8/core/string/casecmp_spec.rb @@ -0,0 +1,69 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#casecmp" do + it "is a case-insensitive version of String#<=>" do + "abcdef".casecmp("abcde").should == 1 + "aBcDeF".casecmp("abcdef").should == 0 + "abcdef".casecmp("abcdefg").should == -1 + "abcdef".casecmp("ABCDEF").should == 0 + end + + # Broken in MRI 1.8.4 + it "doesn't consider non-ascii characters equal that aren't" do + # -- Latin-1 -- + upper_a_tilde = "\xC3" + upper_a_umlaut = "\xC4" + lower_a_tilde = "\xE3" + lower_a_umlaut = "\xE4" + + lower_a_tilde.casecmp(lower_a_umlaut).should_not == 0 + lower_a_umlaut.casecmp(lower_a_tilde).should_not == 0 + upper_a_tilde.casecmp(upper_a_umlaut).should_not == 0 + upper_a_umlaut.casecmp(upper_a_tilde).should_not == 0 + + # -- UTF-8 -- + upper_a_tilde = "\xC3\x83" + upper_a_umlaut = "\xC3\x84" + lower_a_tilde = "\xC3\xA3" + lower_a_umlaut = "\xC3\xA4" + + lower_a_tilde.casecmp(lower_a_umlaut).should_not == 0 + lower_a_umlaut.casecmp(lower_a_tilde).should_not == 0 + upper_a_tilde.casecmp(upper_a_umlaut).should_not == 0 + upper_a_umlaut.casecmp(upper_a_tilde).should_not == 0 + end + + it "doesn't do case mapping for non-ascii characters" do + # -- Latin-1 -- + upper_a_tilde = "\xC3" + upper_a_umlaut = "\xC4" + lower_a_tilde = "\xE3" + lower_a_umlaut = "\xE4" + + upper_a_tilde.casecmp(lower_a_tilde).should == -1 + upper_a_umlaut.casecmp(lower_a_umlaut).should == -1 + lower_a_tilde.casecmp(upper_a_tilde).should == 1 + lower_a_umlaut.casecmp(upper_a_umlaut).should == 1 + + # -- UTF-8 -- + upper_a_tilde = "\xC3\x83" + upper_a_umlaut = "\xC3\x84" + lower_a_tilde = "\xC3\xA3" + lower_a_umlaut = "\xC3\xA4" + + upper_a_tilde.casecmp(lower_a_tilde).should == -1 + upper_a_umlaut.casecmp(lower_a_umlaut).should == -1 + lower_a_tilde.casecmp(upper_a_tilde).should == 1 + lower_a_umlaut.casecmp(upper_a_umlaut).should == 1 + end + + it "ignores subclass differences" do + str = "abcdef" + my_str = StringSpecs::MyString.new(str) + + str.casecmp(my_str).should == 0 + my_str.casecmp(str).should == 0 + my_str.casecmp(my_str).should == 0 + end +end diff --git a/1.8/core/string/center_spec.rb b/1.8/core/string/center_spec.rb new file mode 100644 index 0000000000..402e294b7d --- /dev/null +++ b/1.8/core/string/center_spec.rb @@ -0,0 +1,110 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#center with length, padding" do + it "returns a new string of specified length with self centered and padded with padstr" do + "one".center(9, '.').should == "...one..." + "hello".center(20, '123').should == "1231231hello12312312" + "middle".center(13, '-').should == "---middle----" + + "".center(1, "abcd").should == "a" + "".center(2, "abcd").should == "aa" + "".center(3, "abcd").should == "aab" + "".center(4, "abcd").should == "abab" + "".center(6, "xy").should == "xyxxyx" + "".center(11, "12345").should == "12345123451" + + "|".center(2, "abcd").should == "|a" + "|".center(3, "abcd").should == "a|a" + "|".center(4, "abcd").should == "a|ab" + "|".center(5, "abcd").should == "ab|ab" + "|".center(6, "xy").should == "xy|xyx" + "|".center(7, "xy").should == "xyx|xyx" + "|".center(11, "12345").should == "12345|12345" + "|".center(12, "12345").should == "12345|123451" + + "||".center(3, "abcd").should == "||a" + "||".center(4, "abcd").should == "a||a" + "||".center(5, "abcd").should == "a||ab" + "||".center(6, "abcd").should == "ab||ab" + "||".center(8, "xy").should == "xyx||xyx" + "||".center(12, "12345").should == "12345||12345" + "||".center(13, "12345").should == "12345||123451" + end + + it "pads with whitespace if no padstr is given" do + "two".center(5).should == " two " + "hello".center(20).should == " hello " + end + + it "returns self if it's longer than or as long as the specified length" do + "".center(0).should == "" + "".center(-1).should == "" + "hello".center(4).should == "hello" + "hello".center(-1).should == "hello" + "this".center(3).should == "this" + "radiology".center(8, '-').should == "radiology" + end + + it "taints result when self or padstr is tainted" do + "x".taint.center(4).tainted?.should == true + "x".taint.center(0).tainted?.should == true + "".taint.center(0).tainted?.should == true + "x".taint.center(4, "*").tainted?.should == true + "x".center(4, "*".taint).tainted?.should == true + end + + it "tries to convert length to an integer using to_int" do + "_".center(3.8, "^").should == "^_^" + + obj = mock('3') + def obj.to_int() 3 end + + "_".center(obj, "o").should == "o_o" + + obj = mock('true') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(3) + "_".center(obj, "~").should == "~_~" + end + + it "raises a TypeError when length can't be converted to an integer" do + lambda { "hello".center("x") }.should raise_error(TypeError) + lambda { "hello".center("x", "y") }.should raise_error(TypeError) + lambda { "hello".center([]) }.should raise_error(TypeError) + lambda { "hello".center(mock('x')) }.should raise_error(TypeError) + end + + it "tries to convert padstr to a string using to_str" do + padstr = mock('123') + def padstr.to_str() "123" end + + "hello".center(20, padstr).should == "1231231hello12312312" + + obj = mock('x') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("k") + + "hello".center(7, obj).should == "khellok" + end + + it "raises a TypeError when padstr can't be converted to a string" do + lambda { "hello".center(20, ?o) }.should raise_error(TypeError) + lambda { "hello".center(20, :llo) }.should raise_error(TypeError) + lambda { "hello".center(20, mock('x')) }.should raise_error(TypeError) + end + + it "raises an ArgumentError if padstr is empty" do + lambda { "hello".center(10, "") }.should raise_error(ArgumentError) + lambda { "hello".center(0, "") }.should raise_error(ArgumentError) + end + + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").center(10).class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").center(10).class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).class.should == StringSpecs::MyString + + "".center(10, StringSpecs::MyString.new("x")).class.should == String + "foo".center(10, StringSpecs::MyString.new("x")).class.should == String + end +end diff --git a/1.8/core/string/chomp_spec.rb b/1.8/core/string/chomp_spec.rb new file mode 100644 index 0000000000..0b55cd74c2 --- /dev/null +++ b/1.8/core/string/chomp_spec.rb @@ -0,0 +1,154 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#chomp with separator" do + it "returns a new string with the given record separator removed" do + "hello".chomp("llo").should == "he" + "hellollo".chomp("llo").should == "hello" + end + + it "removes carriage return (except \\r) chars multiple times when separator is an empty string" do + "".chomp("").should == "" + "hello".chomp("").should == "hello" + "hello\n".chomp("").should == "hello" + "hello\nx".chomp("").should == "hello\nx" + "hello\r\n".chomp("").should == "hello" + "hello\r\n\r\n\n\n\r\n".chomp("").should == "hello" + + "hello\r".chomp("").should == "hello\r" + "hello\n\r".chomp("").should == "hello\n\r" + "hello\r\r\r\n".chomp("").should == "hello\r\r" + end + + it "removes carriage return chars (\\n, \\r, \\r\\n) when separator is \\n" do + "hello".chomp("\n").should == "hello" + "hello\n".chomp("\n").should == "hello" + "hello\r\n".chomp("\n").should == "hello" + "hello\n\r".chomp("\n").should == "hello\n" + "hello\r".chomp("\n").should == "hello" + "hello \n there".chomp("\n").should == "hello \n there" + "hello\r\n\r\n\n\n\r\n".chomp("\n").should == "hello\r\n\r\n\n\n" + + "hello\n\r".chomp("\r").should == "hello\n" + "hello\n\r\n".chomp("\r\n").should == "hello\n" + end + + it "returns self if the separator is nil" do + "hello\n\n".chomp(nil).should == "hello\n\n" + end + + it "returns an empty string when called on an empty string" do + "".chomp("\n").should == "" + "".chomp("\r").should == "" + "".chomp("").should == "" + "".chomp(nil).should == "" + end + + it "uses $/ as the separator when none is given" do + ["", "x", "x\n", "x\r", "x\r\n", "x\n\r\r\n", "hello"].each do |str| + ["", "llo", "\n", "\r", nil].each do |sep| + begin + expected = str.chomp(sep) + + old_rec_sep, $/ = $/, sep + + str.chomp.should == expected + ensure + $/ = old_rec_sep + end + end + end + end + + it "taints result when self is tainted" do + "hello".taint.chomp("llo").tainted?.should == true + "hello".taint.chomp("").tainted?.should == true + "hello".taint.chomp(nil).tainted?.should == true + "hello".taint.chomp.tainted?.should == true + "hello\n".taint.chomp.tainted?.should == true + + "hello".chomp("llo".taint).tainted?.should == false + end + + it "tries to convert separator to a string using to_str" do + separator = mock('llo') + def separator.to_str() "llo" end + + "hello".chomp(separator).should == "he" + + obj = mock('x') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("k") + + "hark".chomp(obj).should == "har" + end + + it "raises a TypeError if separator can't be converted to a string" do + lambda { "hello".chomp(?o) }.should raise_error(TypeError) + lambda { "hello".chomp(:llo) }.should raise_error(TypeError) + lambda { "hello".chomp(mock('x')) }.should raise_error(TypeError) + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello\n").chomp.class.should == StringSpecs::MyString + StringSpecs::MyString.new("hello").chomp.class.should == StringSpecs::MyString + StringSpecs::MyString.new("").chomp.class.should == StringSpecs::MyString + end +end + +describe "String#chomp! with seperator" do + it "modifies self in place and returns self" do + s = "one\n" + s.chomp!.equal?(s).should == true + s.should == "one" + + t = "two\r\n" + t.chomp!.equal?(t).should == true + t.should == "two" + + u = "three\r" + u.chomp! + u.should == "three" + + v = "four\n\r" + v.chomp! + v.should == "four\n" + + w = "five\n\n" + w.chomp!(nil) + w.should == "five\n\n" + + x = "six" + x.chomp!("ix") + x.should == "s" + + y = "seven\n\n\n\n" + y.chomp!("") + y.should == "seven" + end + + it "returns nil if no modifications were made" do + v = "four" + v.chomp!.should == nil + v.should == "four" + + "".chomp!.should == nil + "line".chomp!.should == nil + + "hello\n".chomp!("x").should == nil + "hello".chomp!("").should == nil + "hello".chomp!(nil).should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + a = "string\n\r" + a.freeze + + lambda { a.chomp! }.should raise_error(TypeError) + + a.chomp!(nil) # ok, no change + a.chomp!("x") # ok, no change + end + end +end diff --git a/1.8/core/string/chop_spec.rb b/1.8/core/string/chop_spec.rb new file mode 100644 index 0000000000..8f21c5f6a2 --- /dev/null +++ b/1.8/core/string/chop_spec.rb @@ -0,0 +1,77 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#chop" do + it "returns a new string with the last character removed" do + "hello\n".chop.should == "hello" + "hello\x00".chop.should == "hello" + "hello".chop.should == "hell" + + ori_str = "" + 256.times { |i| ori_str << i } + + str = ori_str + 256.times do |i| + str = str.chop + str.should == ori_str[0, 255 - i] + end + end + + it "removes both characters if the string ends with \\r\\n" do + "hello\r\n".chop.should == "hello" + "hello\r\n\r\n".chop.should == "hello\r\n" + "hello\n\r".chop.should == "hello\n" + "hello\n\n".chop.should == "hello\n" + "hello\r\r".chop.should == "hello\r" + + "\r\n".chop.should == "" + end + + it "returns an empty string when applied to an empty string" do + "".chop.should == "" + end + + it "taints result when self is tainted" do + "hello".taint.chop.tainted?.should == true + "".taint.chop.tainted?.should == true + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello\n").chop.class.should == StringSpecs::MyString + StringSpecs::MyString.new("hello").chop.class.should == StringSpecs::MyString + StringSpecs::MyString.new("").chop.class.should == StringSpecs::MyString + end +end + +describe "String#chop!" do + it "behaves just like chop, but in-place" do + ["hello\n", "hello\r\n", "hello", ""].each do |base| + str = base.dup + str.chop! + + str.should == base.chop + end + end + + it "returns self if modifications were made" do + ["hello", "hello\r\n"].each do |s| + s.chop!.equal?(s).should == true + end + end + + it "returns nil when called on an empty string" do + "".chop!.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + a = "string\n\r" + a.freeze + lambda { a.chop! }.should raise_error(TypeError) + + a = "" + a.freeze + a.chop! # ok, no change + end + end +end diff --git a/1.8/core/string/comparison_spec.rb b/1.8/core/string/comparison_spec.rb new file mode 100644 index 0000000000..084d162b19 --- /dev/null +++ b/1.8/core/string/comparison_spec.rb @@ -0,0 +1,78 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#<=> with String" do + it "compares individual characters based on their ascii value" do + ascii_order = Array.new(256) { |x| x.chr } + sort_order = ascii_order.sort + sort_order.should == ascii_order + end + + it "returns -1 when self is less than other" do + ("this" <=> "those").should == -1 + end + + it "returns 0 when self is equal to other" do + ("yep" <=> "yep").should == 0 + end + + it "returns 1 when self is greater than other" do + ("yoddle" <=> "griddle").should == 1 + end + + it "considers string that comes lexicographically first to be less if strings have same size" do + ("aba" <=> "abc").should == -1 + ("abc" <=> "aba").should == 1 + end + + it "doesn't consider shorter string to be less if longer string starts with shorter one" do + ("abc" <=> "abcd").should == -1 + ("abcd" <=> "abc").should == 1 + end + + it "compares shorter string with corresponding number of first chars of longer string" do + ("abx" <=> "abcd").should == 1 + ("abcd" <=> "abx").should == -1 + end + + it "ignores subclass differences" do + a = "hello" + b = StringSpecs::MyString.new("hello") + + (a <=> b).should == 0 + (b <=> a).should == 0 + end +end + +# Note: This is inconsistent with Array#<=> which calls to_str instead of +# just using it as an indicator. +describe "String#<=>" do + it "returns nil if its argument does not respond to to_str" do + ("abc" <=> 1).should == nil + ("abc" <=> :abc).should == nil + ("abc" <=> mock('x')).should == nil + end + + it "returns nil if its argument does not respond to <=>" do + obj = mock('x') + def obj.to_str() "" end + + ("abc" <=> obj).should == nil + end + + it "compares its argument and self by calling <=> on obj and turning the result around if obj responds to to_str" do + obj = mock('x') + def obj.to_str() "" end + def obj.<=>(arg) 1 end + + ("abc" <=> obj).should == -1 + ("xyz" <=> obj).should == -1 + + obj = mock('x') + other = "abc" + obj.should_receive(:respond_to?).with(:to_str).and_return(true) + obj.should_receive(:respond_to?).with(:<=>).and_return(true) + obj.should_receive(:method_missing).with(:<=>, other).and_return(-1) + (other <=> obj).should == +1 + end +end diff --git a/1.8/core/string/concat_spec.rb b/1.8/core/string/concat_spec.rb new file mode 100644 index 0000000000..9e8100606a --- /dev/null +++ b/1.8/core/string/concat_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/concat.rb' + +describe "String#concat" do + it_behaves_like(:string_concat, :concat) +end \ No newline at end of file diff --git a/1.8/core/string/count_spec.rb b/1.8/core/string/count_spec.rb new file mode 100644 index 0000000000..26a858986f --- /dev/null +++ b/1.8/core/string/count_spec.rb @@ -0,0 +1,101 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#count" do + it "counts occurrences of chars from the intersection of the specified sets" do + s = "hello\nworld\x00\x00" + + s.count(s).should == s.size + s.count("lo").should == 5 + s.count("eo").should == 3 + s.count("l").should == 3 + s.count("\n").should == 1 + s.count("\x00").should == 2 + + s.count("").should == 0 + "".count("").should == 0 + + s.count("l", "lo").should == s.count("l") + s.count("l", "lo", "o").should == s.count("") + s.count("helo", "hel", "h").should == s.count("h") + s.count("helo", "", "x").should == 0 + end + + it "raises an ArgumentError when given no arguments" do + lambda { "hell yeah".count }.should raise_error(ArgumentError) + end + + it "negates sets starting with ^" do + s = "^hello\nworld\x00\x00" + + s.count("^").should == 1 # no negation, counts ^ + + s.count("^leh").should == 9 + s.count("^o").should == 12 + + s.count("helo", "^el").should == s.count("ho") + s.count("aeiou", "^e").should == s.count("aiou") + + "^_^".count("^^").should == 1 + "oa^_^o".count("a^").should == 3 + end + + it "counts all chars in a sequence" do + s = "hel-[()]-lo012^" + + s.count("\x00-\xFF").should == s.size + s.count("ej-m").should == 3 + s.count("e-h").should == 2 + + # no sequences + s.count("-").should == 2 + s.count("e-").should == s.count("e") + s.count("-") + s.count("-h").should == s.count("h") + s.count("-") + + s.count("---").should == s.count("-") + + # see an ASCII table for reference + s.count("--2").should == s.count("-./012") + s.count("(--").should == s.count("()*+,-") + s.count("A-a").should == s.count("A-Z[\\]^_`a") + + # empty sequences (end before start) + s.count("h-e").should == 0 + s.count("^h-e").should == s.size + + # negated sequences + s.count("^e-h").should == s.size - s.count("e-h") + s.count("^^-^").should == s.size - s.count("^") + s.count("^---").should == s.size - s.count("-") + + "abcdefgh".count("a-ce-fh").should == 6 + "abcdefgh".count("he-fa-c").should == 6 + "abcdefgh".count("e-fha-c").should == 6 + + "abcde".count("ac-e").should == 4 + "abcde".count("^ac-e").should == 1 + end + + it "tries to convert each set arg to a string using to_str" do + other_string = mock('lo') + def other_string.to_str() "lo" end + + other_string2 = mock('o') + def other_string2.to_str() "o" end + + s = "hello world" + s.count(other_string, other_string2).should == s.count("o") + + obj = mock('k') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("k") + s = "hacker kimono" + s.count(obj).should == s.count("k") + end + + it "raises a TypeError when a set arg can't be converted to a string" do + lambda { "hello world".count(?o) }.should raise_error(TypeError) + lambda { "hello world".count(:o) }.should raise_error(TypeError) + lambda { "hello world".count(mock('x')) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/string/crypt_spec.rb b/1.8/core/string/crypt_spec.rb new file mode 100644 index 0000000000..db73202240 --- /dev/null +++ b/1.8/core/string/crypt_spec.rb @@ -0,0 +1,86 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#crypt" do + # Note: MRI's documentation just says that the C stdlib function crypt() is + # called. + # + # I'm not sure if crypt() is guaranteed to produce the same result across + # different platforms. It seems that there is one standard UNIX implementation + # of crypt(), but that alternative implementations are possible. See + # http://www.unix.org.ua/orelly/networking/puis/ch08_06.htm + it "returns a cryptographic hash of self by applying the UNIX crypt algorithm with the specified salt" do + "".crypt("aa").should == "aaQSqAReePlq6" + "nutmeg".crypt("Mi").should == "MiqkFWCm1fNJI" + "ellen1".crypt("ri").should == "ri79kNd7V6.Sk" + "Sharon".crypt("./").should == "./UY9Q7TvYJDg" + "norahs".crypt("am").should == "amfIADT2iqjA." + "norahs".crypt("7a").should == "7azfT5tIdyh0I" + + # Only uses first 8 chars of string + "01234567".crypt("aa").should == "aa4c4gpuvCkSE" + "012345678".crypt("aa").should == "aa4c4gpuvCkSE" + "0123456789".crypt("aa").should == "aa4c4gpuvCkSE" + + # Only uses first 2 chars of salt + "hello world".crypt("aa").should == "aayPz4hyPS1wI" + "hello world".crypt("aab").should == "aayPz4hyPS1wI" + "hello world".crypt("aabc").should == "aayPz4hyPS1wI" + + # Maps null bytes in salt to .. + platform_is_not :darwin do + compliant_on :ruby, :rubinius do + "hello".crypt("\x00\x00").should == "" + end + end + + compliant_on :jruby do + "hello".crypt("\x00\x00").should == "\x00\x00dR0/E99ehpU" + end + + platform_is :darwin do + "hello".crypt("\x00\x00").should == "..dR0/E99ehpU" + end + end + + it "raises an ArgumentError when the salt is shorter than two characters" do + lambda { "hello".crypt("") }.should raise_error(ArgumentError) + lambda { "hello".crypt("f") }.should raise_error(ArgumentError) + end + + it "converts the salt arg to a string via to_str" do + obj = mock('aa') + def obj.to_str() "aa" end + + "".crypt(obj).should == "aaQSqAReePlq6" + + obj = mock('aa') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("aa") + "".crypt(obj).should == "aaQSqAReePlq6" + end + + it "raises a type error when the salt arg can't be converted to a string" do + lambda { "".crypt(5) }.should raise_error(TypeError) + lambda { "".crypt(mock('x')) }.should raise_error(TypeError) + end + + it "taints the result if either salt or self is tainted" do + tainted_salt = "aa" + tainted_str = "hello" + + tainted_salt.taint + tainted_str.taint + + "hello".crypt("aa").tainted?.should == false + tainted_str.crypt("aa").tainted?.should == true + "hello".crypt(tainted_salt).tainted?.should == true + tainted_str.crypt(tainted_salt).tainted?.should == true + end + + it "doesn't return subclass instances" do + StringSpecs::MyString.new("hello").crypt("aa").class.should == String + "hello".crypt(StringSpecs::MyString.new("aa")).class.should == String + StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).class.should == String + end +end diff --git a/1.8/core/string/delete_spec.rb b/1.8/core/string/delete_spec.rb new file mode 100644 index 0000000000..b1b6afb104 --- /dev/null +++ b/1.8/core/string/delete_spec.rb @@ -0,0 +1,108 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#delete" do + it "returns a new string with the chars from the intersection of sets removed" do + s = "hello" + s.delete("lo").should == "he" + s.should == "hello" + + "hello".delete("l", "lo").should == "heo" + + "hell yeah".delete("").should == "hell yeah" + end + + it "raises an ArgumentError when given no arguments" do + lambda { "hell yeah".delete }.should raise_error(ArgumentError) + end + + it "negates sets starting with ^" do + "hello".delete("aeiou", "^e").should == "hell" + "hello".delete("^leh").should == "hell" + "hello".delete("^o").should == "o" + "hello".delete("^").should == "hello" + "^_^".delete("^^").should == "^^" + "oa^_^o".delete("a^").should == "o_o" + end + + it "deletes all chars in a sequence" do + "hello".delete("\x00-\xFF").should == "" + "hello".delete("ej-m").should == "ho" + "hello".delete("e-h").should == "llo" + "hel-lo".delete("e-").should == "hllo" + "hel-lo".delete("-h").should == "ello" + "hel-lo".delete("---").should == "hello" + "hel-012".delete("--2").should == "hel" + "hel-()".delete("(--").should == "hel" + "hello".delete("h-e").should == "hello" + "hello".delete("^h-e").should == "" + "hello".delete("^e-h").should == "he" + "hello^".delete("^^-^").should == "^" + "hel--lo".delete("^---").should == "--" + + "abcdefgh".delete("a-ce-fh").should == "dg" + "abcdefgh".delete("he-fa-c").should == "dg" + "abcdefgh".delete("e-fha-c").should == "dg" + + "abcde".delete("ac-e").should == "b" + "abcde".delete("^ac-e").should == "acde" + + "ABCabc[]".delete("A-a").should == "bc" + end + + it "taints result when self is tainted" do + "hello".taint.delete("e").tainted?.should == true + "hello".taint.delete("a-z").tainted?.should == true + + "hello".delete("e".taint).tainted?.should == false + end + + it "tries to convert each set arg to a string using to_str" do + other_string = mock('lo') + def other_string.to_str() "lo" end + + other_string2 = mock('o') + def other_string2.to_str() "o" end + + "hello world".delete(other_string, other_string2).should == "hell wrld" + + obj = mock('x') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("o") + "hello world".delete(obj).should == "hell wrld" + end + + it "raises a TypeError when one set arg can't be converted to a string" do + lambda { "hello world".delete(?o) }.should raise_error(TypeError) + lambda { "hello world".delete(:o) }.should raise_error(TypeError) + lambda { "hello world".delete(mock('x')) }.should raise_error(TypeError) + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").delete("!").class.should == StringSpecs::MyString + end +end + +describe "String#delete!" do + it "modifies self in place and returns self" do + a = "hello" + a.delete!("aeiou", "^e").equal?(a).should == true + a.should == "hell" + end + + it "returns nil if no modifications were made" do + a = "hello" + a.delete!("z").should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + a = "hello" + a.freeze + + lambda { a.delete!("") }.should raise_error(TypeError) + lambda { a.delete!("aeiou", "^e") }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/downcase_spec.rb b/1.8/core/string/downcase_spec.rb new file mode 100644 index 0000000000..0a82a57b98 --- /dev/null +++ b/1.8/core/string/downcase_spec.rb @@ -0,0 +1,52 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#downcase" do + it "returns a copy of self with all uppercase letters downcased" do + "hELLO".downcase.should == "hello" + "hello".downcase.should == "hello" + end + + it "is locale insensitive (only replaces A-Z)" do + "ÄÖÜ".downcase.should == "ÄÖÜ" + + str = Array.new(256) { |c| c.chr }.join + expected = Array.new(256) do |i| + c = i.chr + c.between?("A", "Z") ? c.downcase : c + end.join + + str.downcase.should == expected + end + + it "taints result when self is tainted" do + "".taint.downcase.tainted?.should == true + "x".taint.downcase.tainted?.should == true + "X".taint.downcase.tainted?.should == true + end + + it "returns a subclass instance for subclasses" do + StringSpecs::MyString.new("FOObar").downcase.class.should == StringSpecs::MyString + end +end + +describe "String#downcase!" do + it "modifies self in place" do + a = "HeLlO" + a.downcase!.equal?(a).should == true + a.should == "hello" + end + + it "returns nil if no modifications were made" do + a = "hello" + a.downcase!.should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + lambda { "HeLlo".freeze.downcase! }.should raise_error(TypeError) + lambda { "hello".freeze.downcase! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/dump_spec.rb b/1.8/core/string/dump_spec.rb new file mode 100644 index 0000000000..29f3904012 --- /dev/null +++ b/1.8/core/string/dump_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#dump" do + # Older versions of MRI wrongly print \b as \010 + it "produces a version of self with all nonprinting charaters replaced by \\nnn notation" do + ("\000".."A").to_a.to_s.dump.should == "\"\\000\\001\\002\\003\\004\\005\\006\\a\\b\\t\\n\\v\\f\\r\\016\\017\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\e\\034\\035\\036\\037 !\\\"\\\#$%&'()*+,-./0123456789\"" + end + + it "ignores the $KCODE setting" do + old_kcode = $KCODE + + begin + $KCODE = "NONE" + "äöü".dump.should == "\"\\303\\244\\303\\266\\303\\274\"" + + $KCODE = "UTF-8" + "äöü".dump.should == "\"\\303\\244\\303\\266\\303\\274\"" + ensure + $KCODE = old_kcode + end + end + + it "taints result when self is tainted" do + "".taint.dump.tainted?.should == true + "x".taint.dump.tainted?.should == true + end + + it "returns a subclass instance for subclasses" do + StringSpecs::MyString.new("hi!").dump.class.should == StringSpecs::MyString + end +end diff --git a/1.8/core/string/each_byte_spec.rb b/1.8/core/string/each_byte_spec.rb new file mode 100644 index 0000000000..0941c7ad83 --- /dev/null +++ b/1.8/core/string/each_byte_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#each_byte" do + it "passes each byte in self to the given block" do + a = [] + "hello\x00".each_byte { |c| a << c } + a.should == [104, 101, 108, 108, 111, 0] + end + + it "keeps iterating from the old position (to new string end) when self changes" do + r = "" + s = "hello world" + s.each_byte do |c| + r << c + s.insert(0, "<>") if r.size < 3 + end + r.should == "h><>hello world" + + r = "" + s = "hello world" + s.each_byte { |c| s.slice!(-1); r << c } + r.should == "hello " + + r = "" + s = "hello world" + s.each_byte { |c| s.slice!(0); r << c } + r.should == "hlowrd" + + r = "" + s = "hello world" + s.each_byte { |c| s.slice!(0..-1); r << c } + r.should == "h" + end + + it "returns self" do + s = "hello" + (s.each_byte {}).equal?(s).should == true + end +end diff --git a/1.8/core/string/each_char_spec.rb b/1.8/core/string/each_char_spec.rb new file mode 100644 index 0000000000..66bee21405 --- /dev/null +++ b/1.8/core/string/each_char_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +extended_on :rubinius do + describe "String#each_char" do + it "passes each char in self to the given block" do + a = [] + "hello".each_char { |c| a << c } + a.should == ['h', 'e', 'l', 'l', 'o'] + end + end +end diff --git a/1.8/core/string/each_line_spec.rb b/1.8/core/string/each_line_spec.rb new file mode 100644 index 0000000000..7ef355e5bc --- /dev/null +++ b/1.8/core/string/each_line_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/each' + +describe "String#each_line" do + it_behaves_like(:string_each, :each_line) +end diff --git a/1.8/core/string/each_spec.rb b/1.8/core/string/each_spec.rb new file mode 100644 index 0000000000..deabbebaa3 --- /dev/null +++ b/1.8/core/string/each_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/each' + +describe "String#each" do + it_behaves_like(:string_each, :each) +end diff --git a/1.8/core/string/element_reference_spec.rb b/1.8/core/string/element_reference_spec.rb new file mode 100644 index 0000000000..42b2fd81f6 --- /dev/null +++ b/1.8/core/string/element_reference_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/slice.rb' + +describe "String#[]" do + it_behaves_like(:string_slice, :[]) +end diff --git a/1.8/core/string/element_set_spec.rb b/1.8/core/string/element_set_spec.rb new file mode 100644 index 0000000000..005c18d2dd --- /dev/null +++ b/1.8/core/string/element_set_spec.rb @@ -0,0 +1,261 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +# TODO: Add missing String#[]= specs: +# String#[range] = obj +# String#[re] = obj +# String#[re, idx] = obj +# String#[str] = obj + +describe "String#[]= with index" do + it "sets the code of the character at idx to char modulo 256" do + a = "hello" + a[0] = ?b + a.should == "bello" + a[-1] = ?a + a.should == "bella" + a[-1] = 0 + a.should == "bell\x00" + a[-5] = 0 + a.should == "\x00ell\x00" + + a = "x" + a[0] = ?y + a.should == "y" + a[-1] = ?z + a.should == "z" + + a[0] = 255 + a[0].should == 255 + a[0] = 256 + a[0].should == 0 + a[0] = 256 * 3 + 42 + a[0].should == 42 + a[0] = -214 + a[0].should == 42 + end + + it "raises an IndexError without changing self if idx is outside of self" do + a = "hello" + + lambda { a[20] = ?a }.should raise_error(IndexError) + a.should == "hello" + + lambda { a[-20] = ?a }.should raise_error(IndexError) + a.should == "hello" + + lambda { ""[0] = ?a }.should raise_error(IndexError) + lambda { ""[-1] = ?a }.should raise_error(IndexError) + end + + it "calls to_int on index" do + str = "hello" + str[0.5] = ?c + str.should == "cello" + + obj = mock('-1') + obj.should_receive(:to_int).and_return(-1) + str[obj] = ?y + str.should == "celly" + + obj = mock('-1') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(-1) + str[obj] = ?! + str.should == "cell!" + end + + it "sets the code to char % 256" do + str = "Hello" + + str[0] = ?a + 256 * 3 + str[0].should == ?a + str[0] = -200 + str[0].should == 56 + end + + it "doesn't call to_int on char" do + obj = mock('x') + obj.should_not_receive(:to_int) + lambda { "hi"[0] = obj }.should raise_error(TypeError) + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + a = "hello" + a.freeze + + lambda { a[0] = ?b }.should raise_error(TypeError) + end + end +end + +describe "String#[]= with String" do + it "replaces the char at idx with other_str" do + a = "hello" + a[0] = "bam" + a.should == "bamello" + a[-2] = "" + a.should == "bamelo" + end + + it "taints self if other_str is tainted" do + a = "hello" + a[0] = "".taint + a.tainted?.should == true + + a = "hello" + a[0] = "x".taint + a.tainted?.should == true + end + + it "raises an IndexError without changing self if idx is outside of self" do + str = "hello" + + lambda { str[20] = "bam" }.should raise_error(IndexError) + str.should == "hello" + + lambda { str[-20] = "bam" }.should raise_error(IndexError) + str.should == "hello" + + lambda { ""[0] = "bam" }.should raise_error(IndexError) + lambda { ""[-1] = "bam" }.should raise_error(IndexError) + end + + it "raises IndexError if the string index doesn't match a position in the string" do + str = "hello" + lambda { str['y'] = "bam" }.should raise_error(IndexError) + str.should == "hello" + end + + it "raises IndexError if the regexp index doesn't match a position in the string" do + str = "hello" + lambda { str[/y/] = "bam" }.should raise_error(IndexError) + str.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + a = "hello" + a.freeze + + lambda { a[0] = "bam" }.should raise_error(TypeError) + end + end + + it "calls to_int on index" do + str = "hello" + str[0.5] = "hi " + str.should == "hi ello" + + obj = mock('-1') + obj.should_receive(:to_int).and_return(-1) + str[obj] = "!" + str.should == "hi ell!" + + obj = mock('-1') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(-1) + str[obj] = "e vator" + str.should == "hi elle vator" + end + + it "tries to convert other_str to a String using to_str" do + other_str = mock('-test-') + def other_str.to_str() "-test-" end + + a = "abc" + a[1] = other_str + a.should == "a-test-c" + + obj = mock('ROAR') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("ROAR") + + a = "abc" + a[1] = obj + a.should == "aROARc" + end + + it "raises a TypeError if other_str can't be converted to a String" do + lambda { "test"[1] = :test }.should raise_error(TypeError) + lambda { "test"[1] = mock('x') }.should raise_error(TypeError) + lambda { "test"[1] = nil }.should raise_error(TypeError) + end +end + +describe "String#[]= with index, count" do + it "starts at idx and overwrites count characters before inserting the rest of other_str" do + a = "hello" + a[0, 2] = "xx" + a.should == "xxllo" + a = "hello" + a[0, 2] = "jello" + a.should == "jellollo" + end + + it "counts negative idx values from end of the string" do + a = "hello" + a[-1, 0] = "bob" + a.should == "hellbobo" + a = "hello" + a[-5, 0] = "bob" + a.should == "bobhello" + end + + it "overwrites and deletes characters if count is more than the length of other_str" do + a = "hello" + a[0, 4] = "x" + a.should == "xo" + a = "hello" + a[0, 5] = "x" + a.should == "x" + end + + it "deletes characters if other_str is an empty string" do + a = "hello" + a[0, 2] = "" + a.should == "llo" + end + + it "deletes characters up to the maximum length of the existing string" do + a = "hello" + a[0, 6] = "x" + a.should == "x" + a = "hello" + a[0, 100] = "" + a.should == "" + end + + it "appends other_str to the end of the string if idx == the length of the string" do + a = "hello" + a[5, 0] = "bob" + a.should == "hellobob" + end + + it "taints self if other_str is tainted" do + a = "hello" + a[0, 0] = "".taint + a.tainted?.should == true + + a = "hello" + a[1, 4] = "x".taint + a.tainted?.should == true + end + + it "raises an IndexError if |idx| is greater than the length of the string" do + lambda { "hello"[6, 0] = "bob" }.should raise_error(IndexError) + lambda { "hello"[-6, 0] = "bob" }.should raise_error(IndexError) + end + + it "raises an IndexError if count < 0" do + lambda { "hello"[0, -1] = "bob" }.should raise_error(IndexError) + lambda { "hello"[1, -1] = "bob" }.should raise_error(IndexError) + end + + it "raises a TypeError if other_str is a type other than String" do + lambda { "hello"[0, 2] = nil }.should raise_error(TypeError) + lambda { "hello"[0, 2] = :bob }.should raise_error(TypeError) + lambda { "hello"[0, 2] = 33 }.should raise_error(TypeError) + end +end diff --git a/1.8/core/string/empty_spec.rb b/1.8/core/string/empty_spec.rb new file mode 100644 index 0000000000..d11fae5a90 --- /dev/null +++ b/1.8/core/string/empty_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#empty?" do + it "returns true if the string has a length of zero" do + "hello".empty?.should == false + " ".empty?.should == false + "\x00".empty?.should == false + "".empty?.should == true + StringSpecs::MyString.new("").empty?.should == true + end +end diff --git a/1.8/core/string/entries_spec.rb b/1.8/core/string/entries_spec.rb new file mode 100644 index 0000000000..27f5c9ec53 --- /dev/null +++ b/1.8/core/string/entries_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_a' + +describe "String#entries" do + it_behaves_like :string_to_a, :entries +end diff --git a/1.8/core/string/eql_spec.rb b/1.8/core/string/eql_spec.rb new file mode 100644 index 0000000000..e11b5204b7 --- /dev/null +++ b/1.8/core/string/eql_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/equal_value.rb' + +describe "String#eql?" do + it_behaves_like(:string_equal_value, :eql?) +end + +describe "String#eql? when given a non-String" do + it "returns false" do + 'hello'.eql?(5).should == false + 'hello'.eql?(:hello).should == false + 'hello'.eql?(mock('x')).should == false + end + + it "does not try to call #to_str on the given argument" do + (obj = mock('x')).should_not_receive(:to_str) + 'hello'.eql?(obj).should == false + end +end \ No newline at end of file diff --git a/1.8/core/string/equal_value_spec.rb b/1.8/core/string/equal_value_spec.rb new file mode 100644 index 0000000000..dfe8e20f3f --- /dev/null +++ b/1.8/core/string/equal_value_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/equal_value.rb' + +describe "String#==" do + it_behaves_like(:string_equal_value, :==) +end + +describe "String#==" do + it "returns false if obj does not respond to to_str" do + ('hello' == 5).should == false + ('hello' == :hello).should == false + ('hello' == mock('x')).should == false + end + + it "returns obj == self if obj responds to to_str" do + obj = Object.new + def obj.to_str() nil end + def obj.==(o) true end + ('hello' == obj).should == true + ('world!' == obj).should == true + + obj = mock('x') + obj.should_receive(:respond_to?).with(:to_str).and_return(true) + obj.should_receive(:==).and_return(true) + ("abc" == obj).should == true + end +end diff --git a/1.8/core/string/fixtures/classes.rb b/1.8/core/string/fixtures/classes.rb new file mode 100644 index 0000000000..8eae324e7e --- /dev/null +++ b/1.8/core/string/fixtures/classes.rb @@ -0,0 +1,13 @@ +module StringSpecs + class MyString < String; end + class MyArray < Array; end + class MyRange < Range; end + + class SubString < String + attr_reader :special + + def initialize(str=nil) + @special = str + end + end +end diff --git a/1.8/core/string/gsub_spec.rb b/1.8/core/string/gsub_spec.rb new file mode 100644 index 0000000000..3e743e165f --- /dev/null +++ b/1.8/core/string/gsub_spec.rb @@ -0,0 +1,365 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#gsub with pattern and replacement" do + + it "doesn't freak out when replacing ^" do + "Text\n".gsub(/^/, ' ').should == " Text\n" + end + + it "returns a copy of self with all occurrences of pattern replaced with replacement" do + "hello".gsub(/[aeiou]/, '*').should == "h*ll*" + + str = "hello homely world. hah!" + str.gsub(/\Ah\S+\s*/, "huh? ").should == "huh? homely world. hah!" + + "hello".gsub(//, ".").should == ".h.e.l.l.o." + end + + it "ignores a block if supplied" do + "food".gsub(/f/, "g") { "w" }.should == "good" + end + + it "supports \\G which matches at the beginning of the remaining (non-matched) string" do + str = "hello homely world. hah!" + str.gsub(/\Gh\S+\s*/, "huh? ").should == "huh? huh? world. hah!" + end + + it "supports /i for ignoring case" do + str = "Hello. How happy are you?" + str.gsub(/h/i, "j").should == "jello. jow jappy are you?" + str.gsub(/H/i, "j").should == "jello. jow jappy are you?" + end + + it "doesn't interpret regexp metacharacters if pattern is a string" do + "12345".gsub('\d', 'a').should == "12345" + '\d'.gsub('\d', 'a').should == "a" + end + + it "replaces \\1 sequences with the regexp's corresponding capture" do + str = "hello" + + str.gsub(/([aeiou])/, '<\1>').should == "hll" + str.gsub(/(.)/, '\1\1').should == "hheelllloo" + + str.gsub(/.(.?)/, '<\0>(\1)').should == "(e)(l)()" + + str.gsub(/.(.)+/, '\1').should == "o" + + str = "ABCDEFGHIJKLabcdefghijkl" + re = /#{"(.)" * 12}/ + str.gsub(re, '\1').should == "Aa" + str.gsub(re, '\9').should == "Ii" + # Only the first 9 captures can be accessed in MRI + str.gsub(re, '\10').should == "A0a0" + end + + it "treats \\1 sequences without corresponding captures as empty strings" do + str = "hello!" + + str.gsub("", '<\1>').should == "<>h<>e<>l<>l<>o<>!<>" + str.gsub("h", '<\1>').should == "<>ello!" + + str.gsub(//, '<\1>').should == "<>h<>e<>l<>l<>o<>!<>" + str.gsub(/./, '\1\2\3').should == "" + str.gsub(/.(.{20})?/, '\1').should == "" + end + + it "replaces \\& and \\0 with the complete match" do + str = "hello!" + + str.gsub("", '<\0>').should == "<>h<>e<>l<>l<>o<>!<>" + str.gsub("", '<\&>').should == "<>h<>e<>l<>l<>o<>!<>" + str.gsub("he", '<\0>').should == "llo!" + str.gsub("he", '<\&>').should == "llo!" + str.gsub("l", '<\0>').should == "heo!" + str.gsub("l", '<\&>').should == "heo!" + + str.gsub(//, '<\0>').should == "<>h<>e<>l<>l<>o<>!<>" + str.gsub(//, '<\&>').should == "<>h<>e<>l<>l<>o<>!<>" + str.gsub(/../, '<\0>').should == "" + str.gsub(/../, '<\&>').should == "" + str.gsub(/(.)./, '<\0>').should == "" + end + + it "replaces \\` with everything before the current match" do + str = "hello!" + + str.gsub("", '<\`>').should == "<>hello!" + str.gsub("h", '<\`>').should == "<>ello!" + str.gsub("l", '<\`>').should == "heo!" + str.gsub("!", '<\`>').should == "hello" + + str.gsub(//, '<\`>').should == "<>hello!" + str.gsub(/../, '<\`>').should == "<>" + end + + it "replaces \\' with everything after the current match" do + str = "hello!" + + str.gsub("", '<\\\'>').should == "hello!<>" + str.gsub("h", '<\\\'>').should == "ello!" + str.gsub("ll", '<\\\'>').should == "heo!" + str.gsub("!", '<\\\'>').should == "hello<>" + + str.gsub(//, '<\\\'>').should == "hello!<>" + str.gsub(/../, '<\\\'>').should == "<>" + end + + it "replaces \\+ with the last paren that actually matched" do + str = "hello!" + + str.gsub(/(.)(.)/, '\+').should == "el!" + str.gsub(/(.)(.)+/, '\+').should == "!" + str.gsub(/(.)()/, '\+').should == "" + str.gsub(/(.)(.{20})?/, '<\+>').should == "" + + str = "ABCDEFGHIJKLabcdefghijkl" + re = /#{"(.)" * 12}/ + str.gsub(re, '\+').should == "Ll" + end + + it "treats \\+ as an empty string if there was no captures" do + "hello!".gsub(/./, '\+').should == "" + end + + it "maps \\\\ in replacement to \\" do + "hello".gsub(/./, '\\\\').should == '\\' * 5 + end + + it "leaves unknown \\x escapes in replacement untouched" do + "hello".gsub(/./, '\\x').should == '\\x' * 5 + "hello".gsub(/./, '\\y').should == '\\y' * 5 + end + + it "leaves \\ at the end of replacement untouched" do + "hello".gsub(/./, 'hah\\').should == 'hah\\' * 5 + end + + it "taints the result if the original string or replacement is tainted" do + hello = "hello" + hello_t = "hello" + a = "a" + a_t = "a" + empty = "" + empty_t = "" + + hello_t.taint; a_t.taint; empty_t.taint + + hello_t.gsub(/./, a).tainted?.should == true + hello_t.gsub(/./, empty).tainted?.should == true + + hello.gsub(/./, a_t).tainted?.should == true + hello.gsub(/./, empty_t).tainted?.should == true + hello.gsub(//, empty_t).tainted?.should == true + + hello.gsub(//.taint, "foo").tainted?.should == false + end + + it "tries to convert pattern to a string using to_str" do + pattern = mock('.') + def pattern.to_str() "." end + + "hello.".gsub(pattern, "!").should == "hello!" + end + + it "raises a TypeError when pattern can't be converted to a string" do + lambda { "hello".gsub(:woot, "x") }.should raise_error(TypeError) + lambda { "hello".gsub(?e, "x") }.should raise_error(TypeError) + end + + it "tries to convert replacement to a string using to_str" do + replacement = mock('hello_replacement') + def replacement.to_str() "hello_replacement" end + + "hello".gsub(/hello/, replacement).should == "hello_replacement" + end + + it "raises a TypeError when replacement can't be converted to a string" do + lambda { "hello".gsub(/[aeiou]/, :woot) }.should raise_error(TypeError) + lambda { "hello".gsub(/[aeiou]/, ?f) }.should raise_error(TypeError) + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").gsub(//, "").class.should == StringSpecs::MyString + StringSpecs::MyString.new("").gsub(/foo/, "").class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").gsub(/foo/, "").class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").gsub("foo", "").class.should == StringSpecs::MyString + end + + # Note: $~ cannot be tested because mspec messes with it + + it "sets $~ to MatchData of last match and nil when there's none" do + 'hello.'.gsub('hello', 'x') + $~[0].should == 'hello' + + 'hello.'.gsub('not', 'x') + $~.should == nil + + 'hello.'.gsub(/.(.)/, 'x') + $~[0].should == 'o.' + + 'hello.'.gsub(/not/, 'x') + $~.should == nil + end +end + +describe "String#gsub with pattern and block" do + it "returns a copy of self with all occurrences of pattern replaced with the block's return value" do + "hello".gsub(/./) { |s| s.succ + ' ' }.should == "i f m m p " + "hello!".gsub(/(.)(.)/) { |*a| a.inspect }.should == '["he"]["ll"]["o!"]' + end + + it "sets $~ for access from the block" do + str = "hello" + str.gsub(/([aeiou])/) { "<#{$~[1]}>" }.should == "hll" + str.gsub(/([aeiou])/) { "<#{$1}>" }.should == "hll" + str.gsub("l") { "<#{$~[0]}>" }.should == "heo" + + offsets = [] + + str.gsub(/([aeiou])/) do + md = $~ + md.string.should == str + offsets << md.offset(0) + str + end.should == "hhellollhello" + + offsets.should == [[1, 2], [4, 5]] + end + + it "restores $~ after leaving the block" do + [/./, "l"].each do |pattern| + old_md = nil + "hello".gsub(pattern) do + old_md = $~ + "ok".match(/./) + "x" + end + + $~.should == old_md + $~.string.should == "hello" + end + end + + it "sets $~ to MatchData of last match and nil when there's none for access from outside" do + 'hello.'.gsub('l') { 'x' } + $~.begin(0).should == 3 + $~[0].should == 'l' + + 'hello.'.gsub('not') { 'x' } + $~.should == nil + + 'hello.'.gsub(/.(.)/) { 'x' } + $~[0].should == 'o.' + + 'hello.'.gsub(/not/) { 'x' } + $~.should == nil + end + + it "raises a RuntimeError if the string is modified while substituting" do + str = "hello" + raise_error(RuntimeError) { str.gsub(//) { str[0] = 'x' } } + end + + it "doesn't interpolate special sequences like \\1 for the block's return value" do + repl = '\& \0 \1 \` \\\' \+ \\\\ foo' + "hello".gsub(/(.+)/) { repl }.should == repl + end + + it "converts the block's return value to a string using to_s" do + replacement = mock('hello_replacement') + def replacement.to_s() "hello_replacement" end + + "hello".gsub(/hello/) { replacement }.should == "hello_replacement" + + obj = mock('ok') + def obj.to_s() "ok" end + + "hello".gsub(/.+/) { obj }.should == "ok" + end + + it "taints the result if the original string or replacement is tainted" do + hello = "hello" + hello_t = "hello" + a = "a" + a_t = "a" + empty = "" + empty_t = "" + + hello_t.taint; a_t.taint; empty_t.taint + + hello_t.gsub(/./) { a }.tainted?.should == true + hello_t.gsub(/./) { empty }.tainted?.should == true + + hello.gsub(/./) { a_t }.tainted?.should == true + hello.gsub(/./) { empty_t }.tainted?.should == true + hello.gsub(//) { empty_t }.tainted?.should == true + + hello.gsub(//.taint) { "foo" }.tainted?.should == false + end +end + +describe "String#gsub! with pattern and replacement" do + it "modifies self in place and returns self" do + a = "hello" + a.gsub!(/[aeiou]/, '*').equal?(a).should == true + a.should == "h*ll*" + end + + it "taints self if replacement is tainted" do + a = "hello" + a.gsub!(/./.taint, "foo").tainted?.should == false + a.gsub!(/./, "foo".taint).tainted?.should == true + end + + it "returns nil if no modifications were made" do + a = "hello" + a.gsub!(/z/, '*').should == nil + a.gsub!(/z/, 'z').should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + s = "hello" + s.freeze + + s.gsub!(/ROAR/, "x") # ok + lambda { s.gsub!(/e/, "e") }.should raise_error(TypeError) + lambda { s.gsub!(/[aeiou]/, '*') }.should raise_error(TypeError) + end + end +end + +describe "String#gsub! with pattern and block" do + it "modifies self in place and returns self" do + a = "hello" + a.gsub!(/[aeiou]/) { '*' }.equal?(a).should == true + a.should == "h*ll*" + end + + it "taints self if block's result is tainted" do + a = "hello" + a.gsub!(/./.taint) { "foo" }.tainted?.should == false + a.gsub!(/./) { "foo".taint }.tainted?.should == true + end + + it "returns nil if no modifications were made" do + a = "hello" + a.gsub!(/z/) { '*' }.should == nil + a.gsub!(/z/) { 'z' }.should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a RuntimeError when self is frozen" do + s = "hello" + s.freeze + + s.gsub!(/ROAR/) { "x" } # ok + lambda { s.gsub!(/e/) { "e" } }.should raise_error(RuntimeError) + lambda { s.gsub!(/[aeiou]/) { '*' } }.should raise_error(RuntimeError) + end + end +end diff --git a/1.8/core/string/hash_spec.rb b/1.8/core/string/hash_spec.rb new file mode 100644 index 0000000000..c3fe08e951 --- /dev/null +++ b/1.8/core/string/hash_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#hash" do + it "returns a hash based on a string's length and content" do + "abc".hash.should == "abc".hash + "abc".hash.should_not == "cba".hash + end +end diff --git a/1.8/core/string/hex_spec.rb b/1.8/core/string/hex_spec.rb new file mode 100644 index 0000000000..618c944d39 --- /dev/null +++ b/1.8/core/string/hex_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +# TODO: Move actual results to String#to_int() and spec in terms of it +describe "String#hex" do + it "treats leading characters of self as a string of hex digits" do + "0a".hex.should == 10 + "0o".hex.should == 0 + "0x".hex.should == 0 + "A_BAD_BABE".hex.should == 0xABADBABE + "a__b".hex.should == 0xab + "0b1010".hex.should == "b1010".hex + "0d500".hex.should == "d500".hex + "abcdefG".hex.should == 0xabcdef + end + + it "takes an optional sign" do + "-1234".hex.should == -4660 + "+1234".hex.should == 4660 + end + + it "takes an optional 0x" do + "0x0a".hex.should == 10 + "0a".hex.should == 10 + end + + it "requires that the sign is in front of the 0x if present" do + "-0x1".hex.should == -1 + "0x-1".hex.should == 0 + end + + it "returns 0 on error" do + "".hex.should == 0 + "+-5".hex.should == 0 + "wombat".hex.should == 0 + "0x0x42".hex.should == 0 + end +end diff --git a/1.8/core/string/include_spec.rb b/1.8/core/string/include_spec.rb new file mode 100644 index 0000000000..0ef58c123e --- /dev/null +++ b/1.8/core/string/include_spec.rb @@ -0,0 +1,49 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#include? with String" do + it "returns true if self contains other_str" do + "hello".include?("lo").should == true + "hello".include?("ol").should == false + end + + it "ignores subclass differences" do + "hello".include?(StringSpecs::MyString.new("lo")).should == true + StringSpecs::MyString.new("hello").include?("lo").should == true + StringSpecs::MyString.new("hello").include?(StringSpecs::MyString.new("lo")).should == true + end + + it "tries to convert other to string using to_str" do + other = mock('lo') + def other.to_str() "lo" end + "hello".include?(other).should == true + + obj = mock('o') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("o") + "hello".include?(obj).should == true + end + + it "raises a TypeError if other can't be converted to string" do + lambda { "hello".include?(:lo) }.should raise_error(TypeError) + lambda { "hello".include?(mock('x')) }.should raise_error(TypeError) + end +end + +describe "String#include? with Fixnum" do + it "returns true if self contains the given char" do + "hello".include?(?h).should == true + "hello".include?(?z).should == false + "hello".include?(0).should == false + end + + it "uses fixnum % 256" do + "hello".include?(?h + 256 * 3).should == true + end + + it "doesn't try to convert fixnum to an Integer using to_int" do + obj = mock('x') + obj.should_not_receive(:to_int) + lambda { "hello".include?(obj) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/string/index_spec.rb b/1.8/core/string/index_spec.rb new file mode 100644 index 0000000000..1cde34a0ed --- /dev/null +++ b/1.8/core/string/index_spec.rb @@ -0,0 +1,356 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#index with object" do + it "raises a TypeError if obj isn't a String, Fixnum or Regexp" do + lambda { "hello".index(:sym) }.should raise_error(TypeError) + lambda { "hello".index(mock('x')) }.should raise_error(TypeError) + end + + it "doesn't try to convert obj to an Integer via to_int" do + obj = mock('x') + obj.should_not_receive(:to_int) + lambda { "hello".index(obj) }.should raise_error(TypeError) + end + + it "tries to convert obj to a string via to_str" do + obj = mock('lo') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("lo") + "hello".index(obj).should == "hello".index("lo") + + obj = mock('o') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("o") + "hello".index(obj).should == "hello".index("o") + end +end + +describe "String#index with Fixnum" do + it "returns the index of the first occurrence of the given character" do + "hello".index(?e).should == 1 + "hello".index(?l).should == 2 + end + + it "character values over 255 (256th ASCII character) always result in nil" do + # A naive implementation could try to use % 256 + "hello".index(?e + 256 * 3).should == nil + end + + it "negative character values always result in nil" do + # A naive implementation could try to use % 256 + "hello".index(-(256 - ?e)).should == nil + end + + it "starts the search at the given offset" do + "blablabla".index(?b, 0).should == 0 + "blablabla".index(?b, 1).should == 3 + "blablabla".index(?b, 2).should == 3 + "blablabla".index(?b, 3).should == 3 + "blablabla".index(?b, 4).should == 6 + "blablabla".index(?b, 5).should == 6 + "blablabla".index(?b, 6).should == 6 + + "blablabla".index(?a, 0).should == 2 + "blablabla".index(?a, 2).should == 2 + "blablabla".index(?a, 3).should == 5 + "blablabla".index(?a, 4).should == 5 + "blablabla".index(?a, 5).should == 5 + "blablabla".index(?a, 6).should == 8 + "blablabla".index(?a, 7).should == 8 + "blablabla".index(?a, 8).should == 8 + end + + it "starts the search at offset + self.length if offset is negative" do + str = "blablabla" + + [?a, ?b].each do |needle| + (-str.length .. -1).each do |offset| + str.index(needle, offset).should == + str.index(needle, offset + str.length) + end + end + + "blablabla".index(?b, -9).should == 0 + end + + it "returns nil if offset + self.length is < 0 for negative offsets" do + "blablabla".index(?b, -10).should == nil + "blablabla".index(?b, -20).should == nil + end + + it "returns nil if the character isn't found" do + "hello".index(0).should == nil + + "hello".index(?H).should == nil + "hello".index(?z).should == nil + "hello".index(?e, 2).should == nil + + "blablabla".index(?b, 7).should == nil + "blablabla".index(?b, 10).should == nil + + "blablabla".index(?a, 9).should == nil + "blablabla".index(?a, 20).should == nil + end + + it "converts start_offset to an integer via to_int" do + obj = mock('1') + obj.should_receive(:to_int).and_return(1) + "ROAR".index(?R, obj).should == 3 + + obj = mock('1') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(1) + "ROAR".index(?R, obj).should == 3 + end +end + +describe "String#index with String" do + it "behaves the same as String#index(char) for one-character strings" do + ["blablabla", "hello cruel world...!"].each do |str| + str.split("").uniq.each do |str| + chr = str[0] + str.index(str).should == str.index(chr) + + 0.upto(str.size + 1) do |start| + str.index(str, start).should == str.index(chr, start) + end + + (-str.size - 1).upto(-1) do |start| + str.index(str, start).should == str.index(chr, start) + end + end + end + end + + it "returns the index of the first occurrence of the given substring" do + "blablabla".index("").should == 0 + "blablabla".index("b").should == 0 + "blablabla".index("bla").should == 0 + "blablabla".index("blabla").should == 0 + "blablabla".index("blablabla").should == 0 + + "blablabla".index("l").should == 1 + "blablabla".index("la").should == 1 + "blablabla".index("labla").should == 1 + "blablabla".index("lablabla").should == 1 + + "blablabla".index("a").should == 2 + "blablabla".index("abla").should == 2 + "blablabla".index("ablabla").should == 2 + end + + it "doesn't set $~" do + $~ = nil + + 'hello.'.index('ll') + $~.should == nil + end + + it "ignores string subclasses" do + "blablabla".index(StringSpecs::MyString.new("bla")).should == 0 + StringSpecs::MyString.new("blablabla").index("bla").should == 0 + StringSpecs::MyString.new("blablabla").index(StringSpecs::MyString.new("bla")).should == 0 + end + + it "starts the search at the given offset" do + "blablabla".index("bl", 0).should == 0 + "blablabla".index("bl", 1).should == 3 + "blablabla".index("bl", 2).should == 3 + "blablabla".index("bl", 3).should == 3 + + "blablabla".index("bla", 0).should == 0 + "blablabla".index("bla", 1).should == 3 + "blablabla".index("bla", 2).should == 3 + "blablabla".index("bla", 3).should == 3 + + "blablabla".index("blab", 0).should == 0 + "blablabla".index("blab", 1).should == 3 + "blablabla".index("blab", 2).should == 3 + "blablabla".index("blab", 3).should == 3 + + "blablabla".index("la", 1).should == 1 + "blablabla".index("la", 2).should == 4 + "blablabla".index("la", 3).should == 4 + "blablabla".index("la", 4).should == 4 + + "blablabla".index("lab", 1).should == 1 + "blablabla".index("lab", 2).should == 4 + "blablabla".index("lab", 3).should == 4 + "blablabla".index("lab", 4).should == 4 + + "blablabla".index("ab", 2).should == 2 + "blablabla".index("ab", 3).should == 5 + "blablabla".index("ab", 4).should == 5 + "blablabla".index("ab", 5).should == 5 + + "blablabla".index("", 0).should == 0 + "blablabla".index("", 1).should == 1 + "blablabla".index("", 2).should == 2 + "blablabla".index("", 7).should == 7 + "blablabla".index("", 8).should == 8 + "blablabla".index("", 9).should == 9 + end + + it "starts the search at offset + self.length if offset is negative" do + str = "blablabla" + + ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle| + (-str.length .. -1).each do |offset| + str.index(needle, offset).should == + str.index(needle, offset + str.length) + end + end + end + + it "returns nil if the substring isn't found" do + "blablabla".index("B").should == nil + "blablabla".index("z").should == nil + "blablabla".index("BLA").should == nil + "blablabla".index("blablablabla").should == nil + "blablabla".index("", 10).should == nil + + "hello".index("he", 1).should == nil + "hello".index("he", 2).should == nil + end + + it "converts start_offset to an integer via to_int" do + obj = mock('1') + obj.should_receive(:to_int).and_return(1) + "RWOARW".index("RW", obj).should == 4 + + obj = mock('1') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(1) + "RWOARW".index("RW", obj).should == 4 + end +end + +describe "String#index with Regexp" do + it "behaves the same as String#index(string) for escaped string regexps" do + ["blablabla", "hello cruel world...!"].each do |str| + ["", "b", "bla", "lab", "o c", "d."].each do |needle| + regexp = Regexp.new(Regexp.escape(needle)) + str.index(regexp).should == str.index(needle) + + 0.upto(str.size + 1) do |start| + str.index(regexp, start).should == str.index(needle, start) + end + + (-str.size - 1).upto(-1) do |start| + str.index(regexp, start).should == str.index(needle, start) + end + end + end + end + + it "returns the index of the first match of regexp" do + "blablabla".index(/bla/).should == 0 + "blablabla".index(/BLA/i).should == 0 + + "blablabla".index(/.{0}/).should == 0 + "blablabla".index(/.{6}/).should == 0 + "blablabla".index(/.{9}/).should == 0 + + "blablabla".index(/.*/).should == 0 + "blablabla".index(/.+/).should == 0 + + "blablabla".index(/lab|b/).should == 0 + + "blablabla".index(/\A/).should == 0 + "blablabla".index(/\Z/).should == 9 + "blablabla".index(/\z/).should == 9 + "blablabla\n".index(/\Z/).should == 9 + "blablabla\n".index(/\z/).should == 10 + + "blablabla".index(/^/).should == 0 + "\nblablabla".index(/^/).should == 0 + "b\nablabla".index(/$/).should == 1 + "bl\nablabla".index(/$/).should == 2 + + "blablabla".index(/.l./).should == 0 + end + + it "sets $~ to MatchData of match and nil when there's none" do + 'hello.'.index(/.(.)/) + $~[0].should == 'he' + + 'hello.'.index(/not/) + $~.should == nil + end + + it "starts the search at the given offset" do + "blablabla".index(/.{0}/, 5).should == 5 + "blablabla".index(/.{1}/, 5).should == 5 + "blablabla".index(/.{2}/, 5).should == 5 + "blablabla".index(/.{3}/, 5).should == 5 + "blablabla".index(/.{4}/, 5).should == 5 + + "blablabla".index(/.{0}/, 3).should == 3 + "blablabla".index(/.{1}/, 3).should == 3 + "blablabla".index(/.{2}/, 3).should == 3 + "blablabla".index(/.{5}/, 3).should == 3 + "blablabla".index(/.{6}/, 3).should == 3 + + "blablabla".index(/.l./, 0).should == 0 + "blablabla".index(/.l./, 1).should == 3 + "blablabla".index(/.l./, 2).should == 3 + "blablabla".index(/.l./, 3).should == 3 + + "xblaxbla".index(/x./, 0).should == 0 + "xblaxbla".index(/x./, 1).should == 4 + "xblaxbla".index(/x./, 2).should == 4 + + "blablabla\n".index(/\Z/, 9).should == 9 + end + + it "starts the search at offset + self.length if offset is negative" do + str = "blablabla" + + ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle| + (-str.length .. -1).each do |offset| + str.index(needle, offset).should == + str.index(needle, offset + str.length) + end + end + end + + it "returns nil if the substring isn't found" do + "blablabla".index(/BLA/).should == nil + + "blablabla".index(/.{10}/).should == nil + "blaxbla".index(/.x/, 3).should == nil + "blaxbla".index(/..x/, 2).should == nil + end + + it "supports \\G which matches at the given start offset" do + "helloYOU.".index(/\GYOU/, 5).should == 5 + "helloYOU.".index(/\GYOU/).should == nil + + re = /\G.+YOU/ + # The # marks where \G will match. + [ + ["#hi!YOUall.", 0], + ["h#i!YOUall.", 1], + ["hi#!YOUall.", 2], + ["hi!#YOUall.", nil] + ].each do |spec| + + start = spec[0].index("#") + str = spec[0].delete("#") + + str.index(re, start).should == spec[1] + end + end + + it "converts start_offset to an integer via to_int" do + obj = mock('1') + obj.should_receive(:to_int).and_return(1) + "RWOARW".index(/R./, obj).should == 4 + + obj = mock('1') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(1) + "RWOARW".index(/R./, obj).should == 4 + end +end diff --git a/1.8/core/string/initialize_spec.rb b/1.8/core/string/initialize_spec.rb new file mode 100644 index 0000000000..2b19c2c087 --- /dev/null +++ b/1.8/core/string/initialize_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#initialize" do + it "is a private method" do + "".private_methods.should include("initialize") + end + + it "replaces contents of self with the passed string" do + s = "some string" + id = s.object_id + s.send :initialize, "another string" + s.should == "another string" + s.object_id.should == id + end + + it "does not change self when not passed a string" do + s = "some string" + s.send :initialize + s.should == "some string" + end + + it "replaces the taint status of self with that of the passed string" do + a = "an untainted string" + b = "a tainted string".taint + a.send :initialize, b + a.tainted?.should == true + end + + it "returns an instance of a subclass" do + a = StringSpecs::MyString.new("blah") + a.should be_kind_of(StringSpecs::MyString) + a.should == "blah" + end + + it "is called on subclasses" do + s = StringSpecs::SubString.new + s.special.should == nil + s.should == "" + + s = StringSpecs::SubString.new "subclass" + s.special.should == "subclass" + s.should == "" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + a = "hello".freeze + + a.send :initialize, a + lambda { a.send :initialize, "world" }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/insert_spec.rb b/1.8/core/string/insert_spec.rb new file mode 100644 index 0000000000..edb3072ee7 --- /dev/null +++ b/1.8/core/string/insert_spec.rb @@ -0,0 +1,73 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#insert with index, other" do + it "inserts other before the character at the given index" do + "abcd".insert(0, 'X').should == "Xabcd" + "abcd".insert(3, 'X').should == "abcXd" + "abcd".insert(4, 'X').should == "abcdX" + end + + it "modifies self in place" do + a = "abcd" + a.insert(4, 'X').should == "abcdX" + a.should == "abcdX" + end + + it "inserts after the given character on an negative count" do + "abcd".insert(-5, 'X').should == "Xabcd" + "abcd".insert(-3, 'X').should == "abXcd" + "abcd".insert(-1, 'X').should == "abcdX" + end + + it "raises an IndexError if the index is beyond string" do + lambda { "abcd".insert(5, 'X') }.should raise_error(IndexError) + lambda { "abcd".insert(-6, 'X') }.should raise_error(IndexError) + end + + it "converts index to an integer using to_int" do + other = mock('-3') + def other.to_int() -3 end + "abcd".insert(other, "XYZ").should == "abXYZcd" + + obj = mock('-3') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(-3) + "abcd".insert(obj, "XYZ").should == "abXYZcd" + end + + it "converts other to a string using to_str" do + other = mock('XYZ') + def other.to_str() "XYZ" end + "abcd".insert(-3, other).should == "abXYZcd" + + obj = mock('X') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("X") + "abcd".insert(-3, obj).should == "abXcd" + end + + it "taints self if string to insert is tainted" do + str = "abcd" + str.insert(0, "T".taint).tainted?.should == true + + str = "abcd" + other = mock('T') + def other.to_str() "T".taint end + str.insert(0, other).tainted?.should == true + end + + it "raises a TypeError if other can't be converted to string" do + lambda { "abcd".insert(-6, ?e) }.should raise_error(TypeError) + lambda { "abcd".insert(-6, :sym) }.should raise_error(TypeError) + lambda { "abcd".insert(-6, mock('x')) }.should raise_error(TypeError) + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + str = "abcd".freeze + lambda { str.insert(4, '') }.should raise_error(TypeError) + lambda { str.insert(4, 'X') }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/inspect_spec.rb b/1.8/core/string/inspect_spec.rb new file mode 100644 index 0000000000..a48b55a2ce --- /dev/null +++ b/1.8/core/string/inspect_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#inspect" do + # Older versions of MRI wrongly print \b as \010 + it "produces a version of self with all nonprinting charaters replaced by \\nnn notation" do + ("\000".."A").to_a.to_s.inspect.should == "\"\\000\\001\\002\\003\\004\\005\\006\\a\\b\\t\\n\\v\\f\\r\\016\\017\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\e\\034\\035\\036\\037 !\\\"\\\#$%&'()*+,-./0123456789\"" + end + + it "produces different output based on $KCODE" do + old_kcode = $KCODE + + begin + $KCODE = "NONE" + "äöü".inspect.should == "\"\\303\\244\\303\\266\\303\\274\"" + + $KCODE = "UTF-8" + "äöü".inspect.should == "\"äöü\"" + ensure + $KCODE = old_kcode + end + end + + it "can handle malformed UTF-8 string when $KCODE is UTF-8" do + old_kcode = $KCODE + + begin + $KCODE = "UTF-8" + # malformed UTF-8 sequence + "\007äöüz\303".inspect.should == "\"\\aäöüz\\303\"" + ensure + $KCODE = old_kcode + end + end + + it "taints the result if self is tainted" do + "foo".taint.inspect.tainted?.should == true + "foo\n".taint.inspect.tainted?.should == true + end + + it "does not return subclass instances" do + str = StringSpecs::MyString.new + str << "test" + str.should == "test" + str.inspect.class.should_not == StringSpecs::MyString + end +end diff --git a/1.8/core/string/intern_spec.rb b/1.8/core/string/intern_spec.rb new file mode 100644 index 0000000000..6b4cbf713c --- /dev/null +++ b/1.8/core/string/intern_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/to_sym.rb' + +describe "String#intern" do + it_behaves_like(:string_to_sym, :intern) +end \ No newline at end of file diff --git a/1.8/core/string/length_spec.rb b/1.8/core/string/length_spec.rb new file mode 100644 index 0000000000..4ee601e4d6 --- /dev/null +++ b/1.8/core/string/length_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/length' + +describe "String#length" do + it_behaves_like(:string_length, :length) +end \ No newline at end of file diff --git a/1.8/core/string/ljust_spec.rb b/1.8/core/string/ljust_spec.rb new file mode 100644 index 0000000000..b6f57fed09 --- /dev/null +++ b/1.8/core/string/ljust_spec.rb @@ -0,0 +1,93 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#ljust with length, padding" do + it "returns a new string of specified length with self left justified and padded with padstr" do + "hello".ljust(20, '1234').should == "hello123412341234123" + + "".ljust(1, "abcd").should == "a" + "".ljust(2, "abcd").should == "ab" + "".ljust(3, "abcd").should == "abc" + "".ljust(4, "abcd").should == "abcd" + "".ljust(6, "abcd").should == "abcdab" + + "OK".ljust(3, "abcd").should == "OKa" + "OK".ljust(4, "abcd").should == "OKab" + "OK".ljust(6, "abcd").should == "OKabcd" + "OK".ljust(8, "abcd").should == "OKabcdab" + end + + it "pads with whitespace if no padstr is given" do + "hello".ljust(20).should == "hello " + end + + it "returns self if it's longer than or as long as the specified length" do + "".ljust(0).should == "" + "".ljust(-1).should == "" + "hello".ljust(4).should == "hello" + "hello".ljust(-1).should == "hello" + "this".ljust(3).should == "this" + "radiology".ljust(8, '-').should == "radiology" + end + + it "taints result when self or padstr is tainted" do + "x".taint.ljust(4).tainted?.should == true + "x".taint.ljust(0).tainted?.should == true + "".taint.ljust(0).tainted?.should == true + "x".taint.ljust(4, "*").tainted?.should == true + "x".ljust(4, "*".taint).tainted?.should == true + end + + it "tries to convert length to an integer using to_int" do + "^".ljust(3.8, "_^").should == "^_^" + + obj = mock('3') + def obj.to_int() 3 end + + "o".ljust(obj, "_o").should == "o_o" + + obj = mock('3') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(3) + "~".ljust(obj, "_~").should == "~_~" + end + + it "raises a TypeError when length can't be converted to an integer" do + lambda { "hello".ljust("x") }.should raise_error(TypeError) + lambda { "hello".ljust("x", "y") }.should raise_error(TypeError) + lambda { "hello".ljust([]) }.should raise_error(TypeError) + lambda { "hello".ljust(mock('x')) }.should raise_error(TypeError) + end + + it "tries to convert padstr to a string using to_str" do + padstr = mock('123') + def padstr.to_str() "123" end + + "hello".ljust(10, padstr).should == "hello12312" + + obj = mock('k') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("k") + + "hello".ljust(7, obj).should == "hellokk" + end + + it "raises a TypeError when padstr can't be converted" do + lambda { "hello".ljust(20, :sym) }.should raise_error(TypeError) + lambda { "hello".ljust(20, ?c) }.should raise_error(TypeError) + lambda { "hello".ljust(20, mock('x')) }.should raise_error(TypeError) + end + + it "raises an ArgumentError when padstr is empty" do + lambda { "hello".ljust(10, '') }.should raise_error(ArgumentError) + end + + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").ljust(10).class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").ljust(10).class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).class.should == StringSpecs::MyString + + "".ljust(10, StringSpecs::MyString.new("x")).class.should == String + "foo".ljust(10, StringSpecs::MyString.new("x")).class.should == String + end +end diff --git a/1.8/core/string/lstrip_spec.rb b/1.8/core/string/lstrip_spec.rb new file mode 100644 index 0000000000..6346e3749f --- /dev/null +++ b/1.8/core/string/lstrip_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#lstrip" do + it "returns a copy of self with leading whitespace removed" do + " hello ".lstrip.should == "hello " + " hello world ".lstrip.should == "hello world " + "\n\r\t\n\v\r hello world ".lstrip.should == "hello world " + "hello".lstrip.should == "hello" + end + + # spec/core/string/lstrip_spec.rb + not_compliant_on :rubinius do + it "does not strip leading \0" do + "\x00hello".lstrip.should == "\x00hello" + end + end + + it "taints the result when self is tainted" do + "".taint.lstrip.tainted?.should == true + "ok".taint.lstrip.tainted?.should == true + " ok".taint.lstrip.tainted?.should == true + end +end + +describe "String#lstrip!" do + it "modifies self in place and returns self" do + a = " hello " + a.lstrip!.equal?(a).should == true + a.should == "hello " + end + + it "returns nil if no modifications were made" do + a = "hello" + a.lstrip!.should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + "hello".freeze.lstrip! # ok, nothing changed + "".freeze.lstrip! # ok, nothing changed + + lambda { " hello ".freeze.lstrip! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/match_spec.rb b/1.8/core/string/match_spec.rb new file mode 100644 index 0000000000..2d7b0a61cc --- /dev/null +++ b/1.8/core/string/match_spec.rb @@ -0,0 +1,80 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#=~" do + it "behaves the same way as index() when given a regexp" do + ("rudder" =~ /udder/).should == "rudder".index(/udder/) + ("boat" =~ /[^fl]oat/).should == "boat".index(/[^fl]oat/) + ("bean" =~ /bag/).should == "bean".index(/bag/) + ("true" =~ /false/).should == "true".index(/false/) + end + + it "raises a TypeError if a obj is a string" do + lambda { "some string" =~ "another string" }.should raise_error(TypeError) + lambda { "a" =~ StringSpecs::MyString.new("b") }.should raise_error(TypeError) + end + + it "invokes obj.=~ with self if obj is neither a string nor regexp" do + str = "w00t" + obj = mock('x') + + obj.should_receive(:=~).with(str).any_number_of_times.and_return(true) + str.should =~ obj + + obj.should_receive(:=~).with(str).any_number_of_times.and_return(false) + str.should =~ obj + end + + it "sets $~ to MatchData when there is a match and nil when there's none" do + 'hello' =~ /./ + $~[0].should == 'h' + + 'hello' =~ /not/ + $~.should == nil + end +end + +describe "String#match" do + it "matches the pattern against self" do + 'hello'.match(/(.)\1/)[0].should == 'll' + end + + it "tries to convert pattern to a string via to_str" do + obj = mock('.') + def obj.to_str() "." end + "hello".match(obj)[0].should == "h" + + obj = mock('.') + def obj.respond_to?(type) true end + def obj.method_missing(*args) "." end + "hello".match(obj)[0].should == "h" + end + + it "raises a TypeError if pattern is not a regexp or a string" do + lambda { 'hello'.match(10) }.should raise_error(TypeError) + lambda { 'hello'.match(:ell) }.should raise_error(TypeError) + end + + it "converts string patterns to regexps without escaping" do + 'hello'.match('(.)\1')[0].should == 'll' + end + + it "returns nil if there's no match" do + 'hello'.match('xx').should == nil + end + + it "matches \\G at the start of the string" do + 'hello'.match(/\Gh/)[0].should == 'h' + 'hello'.match(/\Go/).should == nil + end + + it "sets $~ to MatchData of match or nil when there is none" do + 'hello'.match(/./) + $~[0].should == 'h' + Regexp.last_match[0].should == 'h' + + 'hello'.match(/X/) + $~.should == nil + Regexp.last_match.should == nil + end +end diff --git a/1.8/core/string/modulo_spec.rb b/1.8/core/string/modulo_spec.rb new file mode 100644 index 0000000000..04da169bf0 --- /dev/null +++ b/1.8/core/string/modulo_spec.rb @@ -0,0 +1,714 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#%" do + it "formats multiple expressions" do + ("%b %x %d %s" % [10, 10, 10, 10]).should == "1010 a 10 10" + end + + it "formats expressions mid string" do + ("hello %s!" % "world").should == "hello world!" + end + + it "formats %% into %" do + ("%d%% %s" % [10, "of chickens!"]).should == "10% of chickens!" + end + + it "formats single % characters before a newline or NULL as literal %s" do + ("%" % []).should == "%" + ("foo%" % []).should == "foo%" + ("%\n" % []).should == "%\n" + ("foo%\n" % []).should == "foo%\n" + ("%\0" % []).should == "%\0" + ("foo%\0" % []).should == "foo%\0" + ("%\n.3f" % 1.2).should == "%\n.3f" + ("%\0.3f" % 1.2).should == "%\0.3f" + end + + it "raises an error if single % appears anywhere else" do + lambda { (" % " % []) }.should raise_error(ArgumentError) + lambda { ("foo%quux" % []) }.should raise_error(ArgumentError) + end + + it "raises an error if NULL or \n appear anywhere else in the format string" do + begin + old_debug, $DEBUG = $DEBUG, false + + lambda { "%.\n3f" % 1.2 }.should raise_error(ArgumentError) + lambda { "%.3\nf" % 1.2 }.should raise_error(ArgumentError) + lambda { "%.\03f" % 1.2 }.should raise_error(ArgumentError) + lambda { "%.3\0f" % 1.2 }.should raise_error(ArgumentError) + ensure + $DEBUG = old_debug + end + end + + it "ignores unused arguments when $DEBUG is false" do + begin + old_debug = $DEBUG + $DEBUG = false + + ("" % [1, 2, 3]).should == "" + ("%s" % [1, 2, 3]).should == "1" + ensure + $DEBUG = old_debug + end + end + + it "raises an ArgumentError for unused arguments when $DEBUG is true" do + begin + old_debug = $DEBUG + $DEBUG = true + s = $stderr + $stderr = IOStub.new + + lambda { "" % [1, 2, 3] }.should raise_error(ArgumentError) + lambda { "%s" % [1, 2, 3] }.should raise_error(ArgumentError) + ensure + $DEBUG = old_debug + $stderr = s + end + end + + it "always allows unused arguments when positional argument style is used" do + begin + old_debug = $DEBUG + $DEBUG = false + + ("%2$s" % [1, 2, 3]).should == "2" + $DEBUG = true + ("%2$s" % [1, 2, 3]).should == "2" + ensure + $DEBUG = old_debug + end + end + + it "replaces trailing absolute argument specifier without type with percent sign" do + ("hello %1$" % "foo").should == "hello %" + end + + it "raises an ArgumentError when given invalid argument specifiers" do + lambda { "%1" % [] }.should raise_error(ArgumentError) + lambda { "%+" % [] }.should raise_error(ArgumentError) + lambda { "%-" % [] }.should raise_error(ArgumentError) + lambda { "%#" % [] }.should raise_error(ArgumentError) + lambda { "%0" % [] }.should raise_error(ArgumentError) + lambda { "%*" % [] }.should raise_error(ArgumentError) + lambda { "%." % [] }.should raise_error(ArgumentError) + lambda { "%_" % [] }.should raise_error(ArgumentError) + lambda { "%0$s" % "x" }.should raise_error(ArgumentError) + lambda { "%*0$s" % [5, "x"] }.should raise_error(ArgumentError) + lambda { "%*1$.*0$1$s" % [1, 2, 3] }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when multiple positional argument tokens are given for one format specifier" do + lambda { "%1$1$s" % "foo" }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when multiple width star tokens are given for one format specifier" do + lambda { "%**s" % [5, 5, 5] }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when a width star token is seen after a width token" do + lambda { "%5*s" % [5, 5] }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when multiple precision tokens are given" do + lambda { "%.5.5s" % 5 }.should raise_error(ArgumentError) + lambda { "%.5.*s" % [5, 5] }.should raise_error(ArgumentError) + lambda { "%.*.5s" % [5, 5] }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when there are less arguments than format specifiers" do + ("foo" % []).should == "foo" + lambda { "%s" % [] }.should raise_error(ArgumentError) + lambda { "%s %s" % [1] }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when absolute and relative argument numbers are mixed" do + lambda { "%s %1$s" % "foo" }.should raise_error(ArgumentError) + lambda { "%1$s %s" % "foo" }.should raise_error(ArgumentError) + + lambda { "%s %2$s" % ["foo", "bar"] }.should raise_error(ArgumentError) + lambda { "%2$s %s" % ["foo", "bar"] }.should raise_error(ArgumentError) + + lambda { "%*2$s" % [5, 5, 5] }.should raise_error(ArgumentError) + lambda { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError) + lambda { "%*2$.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError) + lambda { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError) + end + + it "allows reuse of the one argument multiple via absolute argument numbers" do + ("%1$s %1$s" % "foo").should == "foo foo" + ("%1$s %2$s %1$s %2$s" % ["foo", "bar"]).should == "foo bar foo bar" + end + + it "always interprets an array argument as a list of argument parameters" do + lambda { "%p" % [] }.should raise_error(ArgumentError) + ("%p" % [1]).should == "1" + ("%p %p" % [1, 2]).should == "1 2" + end + + it "always interprets an array subclass argument as a list of argument parameters" do + lambda { "%p" % StringSpecs::MyArray[] }.should raise_error(ArgumentError) + ("%p" % StringSpecs::MyArray[1]).should == "1" + ("%p %p" % StringSpecs::MyArray[1, 2]).should == "1 2" + end + + it "allows positional arguments for width star and precision star arguments" do + ("%*1$.*2$3$d" % [10, 5, 1]).should == " 00001" + end + + it "calls to_int on width star and precision star tokens" do + w = mock('10') + def w.to_int() 10 end + p = mock('5') + def p.to_int() 5 end + + ("%*.*f" % [w, p, 1]).should == " 1.00000" + + w = mock('10') + w.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + w.should_receive(:method_missing).with(:to_int).and_return(10) + p = mock('5') + p.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + p.should_receive(:method_missing).with(:to_int).and_return(5) + + ("%*.*f" % [w, p, 1]).should == " 1.00000" + end + + it "doesn't call to_ary on its argument" do + obj = mock('[1,2]') + def obj.to_ary() [1, 2] end + def obj.to_s() "obj" end + lambda { "%s %s" % obj }.should raise_error(ArgumentError) + ("%s" % obj).should == "obj" + end + + it "doesn't return subclass instances when called on a subclass" do + universal = mock('0') + def universal.to_int() 0 end + def universal.to_str() "0" end + def universal.to_f() 0.0 end + + [ + "", "foo", + "%b", "%B", "%c", "%d", "%e", "%E", + "%f", "%g", "%G", "%i", "%o", "%p", + "%s", "%u", "%x", "%X" + ].each do |format| + (StringSpecs::MyString.new(format) % universal).class.should == String + end + end + + it "always taints the result when the format string is tainted" do + universal = mock('0') + def universal.to_int() 0 end + def universal.to_str() "0" end + def universal.to_f() 0.0 end + + [ + "", "foo", + "%b", "%B", "%c", "%d", "%e", "%E", + "%f", "%g", "%G", "%i", "%o", "%p", + "%s", "%u", "%x", "%X" + ].each do |format| + subcls_format = StringSpecs::MyString.new(format) + subcls_format.taint + format.taint + + (format % universal).tainted?.should == true + (subcls_format % universal).tainted?.should == true + end + end + + it "supports binary formats using %b" do + ("%b" % 10).should == "1010" + ("% b" % 10).should == " 1010" + ("%1$b" % [10, 20]).should == "1010" + ("%#b" % 10).should == "0b1010" + ("%+b" % 10).should == "+1010" + ("%-9b" % 10).should == "1010 " + ("%05b" % 10).should == "01010" + ("%*b" % [10, 6]).should == " 110" + ("%*b" % [-10, 6]).should == "110 " + + ("%b" % -5).should == "..1011" + ("%0b" % -5).should == "1011" + ("%.4b" % 2).should == "0010" + ("%.1b" % -5).should == "1011" + ("%.7b" % -5).should == "1111011" + ("%.10b" % -5).should == "1111111011" + ("% b" % -5).should == "-101" + ("%+b" % -5).should == "-101" + ("%b" % -(2 ** 64 + 5)).should == + "..101111111111111111111111111111111111111111111111111111111111111011" + end + + it "supports binary formats using %B with same behaviour as %b except for using 0B instead of 0b for #" do + ("%B" % 10).should == ("%b" % 10) + ("% B" % 10).should == ("% b" % 10) + ("%1$B" % [10, 20]).should == ("%1$b" % [10, 20]) + ("%+B" % 10).should == ("%+b" % 10) + ("%-9B" % 10).should == ("%-9b" % 10) + ("%05B" % 10).should == ("%05b" % 10) + ("%*B" % [10, 6]).should == ("%*b" % [10, 6]) + ("%*B" % [-10, 6]).should == ("%*b" % [-10, 6]) + + ("%B" % -5).should == ("%b" % -5) + ("%0B" % -5).should == ("%0b" % -5) + ("%.1B" % -5).should == ("%.1b" % -5) + ("%.7B" % -5).should == ("%.7b" % -5) + ("%.10B" % -5).should == ("%.10b" % -5) + ("% B" % -5).should == ("% b" % -5) + ("%+B" % -5).should == ("%+b" % -5) + ("%B" % -(2 ** 64 + 5)).should == ("%b" % -(2 ** 64 + 5)) + + ("%#B" % 10).should == "0B1010" + end + + it "supports character formats using %c" do + ("%c" % 10).should == "\n" + ("%2$c" % [10, 11, 14]).should == "\v" + ("%-4c" % 10).should == "\n " + ("%*c" % [10, 3]).should == " \003" + ("%c" % (256 + 42)).should == "*" + + lambda { "%c" % Object }.should raise_error(TypeError) + end + + it "uses argument % 256" do + ("%c" % [256 * 3 + 64]).should == ("%c" % 64) + ("%c" % -200).should == ("%c" % 56) + end + + it "calls to_int on argument for %c formats" do + obj = mock('65') + def obj.to_int() 65 end + ("%c" % obj).should == ("%c" % obj.to_int) + + obj = mock('65') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(65) + ("%c" % obj).should == "A" + end + + %w(d i).each do |f| + format = "%" + f + + it "supports integer formats using #{format}" do + ("%#{f}" % 10).should == "10" + ("% #{f}" % 10).should == " 10" + ("%1$#{f}" % [10, 20]).should == "10" + ("%+#{f}" % 10).should == "+10" + ("%-7#{f}" % 10).should == "10 " + ("%04#{f}" % 10).should == "0010" + ("%*#{f}" % [10, 4]).should == " 4" + end + end + + it "supports float formats using %e" do + ("%e" % 10).should == "1.000000e+01" + ("% e" % 10).should == " 1.000000e+01" + ("%1$e" % 10).should == "1.000000e+01" + ("%#e" % 10).should == "1.000000e+01" + ("%+e" % 10).should == "+1.000000e+01" + ("%-7e" % 10).should == "1.000000e+01" + ("%05e" % 10).should == "1.000000e+01" + ("%*e" % [10, 9]).should == "9.000000e+00" + end + + compliant_on :ruby do + it "supports float formats using %e, and downcases -Inf, Inf, and NaN" do + ("%e" % 1e1020).should == "inf" + ("%e" % -1e1020).should == "-inf" + ("%e" % (0.0/0)).should == "nan" + ("%e" % (-0e0/0)).should == "nan" + end + end + + # Inf, -Inf, and NaN are identifiers for results of floating point operations + # that cannot be expressed with any value in the set of real numbers. Upcasing + # or downcasing these identifiers for %e or %E, which refers to the case of the + # of the exponent identifier, is silly. + deviates_on :rubinius, :jruby do + it "supports float formats using %e, but Inf, -Inf, and NaN are not floats" do + ("%e" % 1e1020).should == "Inf" + ("%e" % -1e1020).should == "-Inf" + ("%e" % (-0e0/0)).should == "NaN" + ("%e" % (0.0/0)).should == "NaN" + end + + it "supports float formats using %E, but Inf, -Inf, and NaN are not floats" do + ("%E" % 1e1020).should == "Inf" + ("%E" % -1e1020).should == "-Inf" + ("%-10E" % 1e1020).should == "Inf " + ("%10E" % 1e1020).should == " Inf" + ("%+E" % 1e1020).should == "+Inf" + ("% E" % 1e1020).should == " Inf" + ("%E" % (0.0/0)).should == "NaN" + ("%E" % (-0e0/0)).should == "NaN" + end + end + + it "supports float formats using %E" do + ("%E" % 10).should == "1.000000E+01" + ("% E" % 10).should == " 1.000000E+01" + ("%1$E" % 10).should == "1.000000E+01" + ("%#E" % 10).should == "1.000000E+01" + ("%+E" % 10).should == "+1.000000E+01" + ("%-7E" % 10).should == "1.000000E+01" + ("%05E" % 10).should == "1.000000E+01" + ("%*E" % [10, 9]).should == "9.000000E+00" + end + + compliant_on :ruby do + it "supports float formats using %E, and upcases Inf, -Inf, and NaN" do + ("%E" % 1e1020).should == "INF" + ("%E" % -1e1020).should == "-INF" + ("%-10E" % 1e1020).should == "INF " + ("%+E" % 1e1020).should == "+INF" + ("% E" % 1e1020).should == " INF" + ("%E" % (0.0/0)).should == "NAN" + ("%E" % (-0e0/0)).should == "NAN" + end + + platform_is :darwin do + it "pads with zeros using %E with Inf, -Inf, and NaN" do + ("%010E" % -1e1020).should == "-000000INF" + ("%010E" % 1e1020).should == "0000000INF" + ("%010E" % (0.0/0)).should == "0000000NAN" + end + end + + platform_is_not :darwin do + it "pads with spaces for %E with Inf, -Inf, and NaN" do + ("%010E" % -1e1020).should == " -INF" + ("%010E" % 1e1020).should == " INF" + ("%010E" % (0.0/0)).should == " NAN" + end + end + end + + it "supports float formats using %f" do + ("%f" % 10).should == "10.000000" + ("% f" % 10).should == " 10.000000" + ("%1$f" % 10).should == "10.000000" + ("%#f" % 10).should == "10.000000" + ("%+f" % 10).should == "+10.000000" + ("%-7f" % 10).should == "10.000000" + ("%05f" % 10).should == "10.000000" + ("%*f" % [10, 9]).should == " 9.000000" + end + + it "supports float formats using %g" do + ("%g" % 10).should == "10" + ("% g" % 10).should == " 10" + ("%1$g" % 10).should == "10" + ("%#g" % 10).should == "10.0000" + ("%+g" % 10).should == "+10" + ("%-7g" % 10).should == "10 " + ("%05g" % 10).should == "00010" + ("%*g" % [10, 9]).should == " 9" + end + + it "supports float formats using %G" do + ("%G" % 10).should == "10" + ("% G" % 10).should == " 10" + ("%1$G" % 10).should == "10" + ("%#G" % 10).should == "10.0000" + ("%+G" % 10).should == "+10" + ("%-7G" % 10).should == "10 " + ("%05G" % 10).should == "00010" + ("%*G" % [10, 9]).should == " 9" + end + + it "supports octal formats using %o" do + ("%o" % 10).should == "12" + ("% o" % 10).should == " 12" + ("%1$o" % [10, 20]).should == "12" + ("%#o" % 10).should == "012" + ("%+o" % 10).should == "+12" + ("%-9o" % 10).should == "12 " + ("%05o" % 10).should == "00012" + ("%*o" % [10, 6]).should == " 6" + + # These are incredibly wrong. -05 == -5, not 7177777...whatever + ("%o" % -5).should == "..73" + ("%0o" % -5).should == "73" + ("%.4o" % 20).should == "0024" + ("%.1o" % -5).should == "73" + ("%.7o" % -5).should == "7777773" + ("%.10o" % -5).should == "7777777773" + + ("% o" % -26).should == "-32" + ("%+o" % -26).should == "-32" + ("%o" % -(2 ** 64 + 5)).should == "..75777777777777777777773" + end + + it "supports inspect formats using %p" do + ("%p" % 10).should == "10" + ("%1$p" % [10, 5]).should == "10" + ("%-22p" % 10).should == "10 " + ("%*p" % [10, 10]).should == " 10" + end + + it "calls inspect on arguments for %p format" do + obj = mock('obj') + def obj.inspect() "obj" end + ("%p" % obj).should == "obj" + + # undef is not working + # obj = mock('obj') + # class << obj; undef :inspect; end + # def obj.method_missing(*args) "obj" end + # ("%p" % obj).should == "obj" + end + + it "taints result for %p when argument.inspect is tainted" do + obj = mock('x') + def obj.inspect() "x".taint end + + ("%p" % obj).tainted?.should == true + + obj = mock('x'); obj.taint + def obj.inspect() "x" end + + ("%p" % obj).tainted?.should == false + end + + it "supports string formats using %s" do + ("%s" % 10).should == "10" + ("%1$s" % [10, 8]).should == "10" + ("%-5s" % 10).should == "10 " + ("%*s" % [10, 9]).should == " 9" + end + + it "calls to_s on arguments for %s format" do + obj = mock('obj') + def obj.to_s() "obj" end + + ("%s" % obj).should == "obj" + + # undef doesn't work + # obj = mock('obj') + # class << obj; undef :to_s; end + # def obj.method_missing(*args) "obj" end + # + # ("%s" % obj).should == "obj" + end + + it "taints result for %s when argument is tainted" do + ("%s" % "x".taint).tainted?.should == true + ("%s" % mock('x').taint).tainted?.should == true + ("%s" % 5.0.taint).tainted?.should == true + end + + # MRI crashes on this one. + # See http://groups.google.com/group/ruby-core-google/t/c285c18cd94c216d + it "raises an ArgumentError for huge precisions for %s" do + block = lambda { "%.25555555555555555555555555555555555555s" % "hello world" } + block.should raise_error(ArgumentError) + end + + # Note: %u has been changed to an alias for %d in MRI 1.9 trunk. + # Let's wait a bit for it to cool down and see if it will + # be changed for 1.8 as well. + it "supports unsigned formats using %u" do + ("%u" % 10).should == "10" + ("% u" % 10).should == " 10" + ("%1$u" % [10, 20]).should == "10" + ("%+u" % 10).should == "+10" + ("%-7u" % 10).should == "10 " + ("%04u" % 10).should == "0010" + ("%*u" % [10, 4]).should == " 4" + + platform_is :wordsize => 64 do + ("%u" % -5).should == "..#{2**64 - 5}" + ("%0u" % -5).should == (2**64 - 5).to_s + ("%.1u" % -5).should == (2**64 - 5).to_s + ("%.7u" % -5).should == (2**64 - 5).to_s + ("%.10u" % -5).should == (2**64 - 5).to_s + end + + platform_is_not :wordsize => 64 do + ("%u" % -5).should == "..#{2**32 - 5}" + ("%0u" % -5).should == (2**32 - 5).to_s + ("%.1u" % -5).should == (2**32 - 5).to_s + ("%.7u" % -5).should == (2**32 - 5).to_s + ("%.10u" % -5).should == (2**32 - 5).to_s + end + + deviates_on :ruby do + ("% u" % -26).should == "-26" + ("%+u" % -26).should == "-26" + end + end + + # TODO: This behavior is for MRI 1.8.6 p111, but it was + # changed later to prefix with '.', as the Kernel#sprintf doc requires. + # See: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/8418 + not_compliant_on :rubinius, :jruby do + it "supports negative bignums by prefixing the value with zeros" do + ("%u" % -(2 ** 64 + 5)).should == "0079228162495817593519834398715" + end + end + + # This is the proper, compliant behavior of both JRuby, and + # MRI 1.8.6 with patchlevel 114 and up. + compliant_on :jruby do + it "supports negative bignums by prefixing the value with dots" do + ("%u" % -(2 ** 64 + 5)).should == "..79228162495817593519834398715" + end + end + + deviates_on :rubinius do + it "does not support negative bignums" do + lambda { ("%u" % -(2 ** 64 + 5)) }.should raise_error(ArgumentError) + end + end + + it "supports hex formats using %x" do + ("%x" % 10).should == "a" + ("% x" % 10).should == " a" + ("%1$x" % [10, 20]).should == "a" + ("%#x" % 10).should == "0xa" + ("%+x" % 10).should == "+a" + ("%-9x" % 10).should == "a " + ("%05x" % 10).should == "0000a" + ("%*x" % [10, 6]).should == " 6" + + ("%x" % -5).should == "..fb" + ("%0x" % -5).should == "fb" + ("%.4x" % 20).should == "0014" + ("%.1x" % -5).should == "fb" + ("%.7x" % -5).should == "ffffffb" + ("%.10x" % -5).should == "fffffffffb" + ("% x" % -26).should == "-1a" + ("%+x" % -26).should == "-1a" + ("%x" % 0xFFFFFFFF).should == "ffffffff" + ("%x" % -(2 ** 64 + 5)).should == "..fefffffffffffffffb" + end + + it "supports hex formats using %X" do + ("%X" % 10).should == "A" + ("% X" % 10).should == " A" + ("%1$X" % [10, 20]).should == "A" + ("%#X" % 10).should == "0XA" + ("%+X" % 10).should == "+A" + ("%-9X" % 10).should == "A " + ("%05X" % 10).should == "0000A" + ("%*X" % [10, 6]).should == " 6" + + ("%X" % -5).should == "..FB" + ("%0X" % -5).should == "FB" + ("%.1X" % -5).should == "FB" + ("%.7X" % -5).should == "FFFFFFB" + ("%.10X" % -5).should == "FFFFFFFFFB" + ("% X" % -26).should == "-1A" + ("%+X" % -26).should == "-1A" + ("%X" % 0xFFFFFFFF).should == "FFFFFFFF" + ("%X" % -(2 ** 64 + 5)).should == "..FEFFFFFFFFFFFFFFFB" + end + + %w(b d i o u x X).each do |f| + format = "%" + f + + it "behaves as if calling Kernel#Integer for #{format} argument" do + (format % "10").should == (format % Kernel.Integer("10")) + (format % nil).should == (format % Kernel.Integer(nil)) + (format % "0x42").should == (format % Kernel.Integer("0x42")) + (format % "0b1101").should == (format % Kernel.Integer("0b1101")) + (format % "0b1101_0000").should == (format % Kernel.Integer("0b1101_0000")) + (format % "0777").should == (format % Kernel.Integer("0777")) + lambda { + # see [ruby-core:14139] for more details + (format % "0777").should == (format % Kernel.Integer("0777")) + }.should_not raise_error(ArgumentError) + + lambda { format % "0__7_7_7" }.should raise_error(ArgumentError) + + lambda { format % "" }.should raise_error(ArgumentError) + lambda { format % "x" }.should raise_error(ArgumentError) + lambda { format % "5x" }.should raise_error(ArgumentError) + lambda { format % "08" }.should raise_error(ArgumentError) + lambda { format % "0b2" }.should raise_error(ArgumentError) + lambda { format % "123__456" }.should raise_error(ArgumentError) + + obj = mock('5') + obj.should_receive(:to_i).and_return(5) + (format % obj).should == (format % 5) + + obj = mock('5') + obj.should_receive(:to_int).and_return(5) + (format % obj).should == (format % 5) + + obj = mock('4') + def obj.to_int() 4 end + def obj.to_i() 0 end + (format % obj).should == (format % 4) + + obj = mock('65') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(65) + (format % obj).should == (format % 65) + + obj = mock('65') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(false) + obj.should_receive(:respond_to?).with(:to_i).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_i).any_number_of_times.and_return(65) + (format % obj).should == (format % 65) + + obj = mock('4') + def obj.respond_to?(arg) true if [:to_i, :to_int].include?(arg) end + def obj.method_missing(name, *args) + name == :to_int ? 4 : 0 + end + (format % obj).should == (format % 4) + end + + it "doesn't taint the result for #{format} when argument is tainted" do + (format % "5".taint).tainted?.should == false + end + end + + %w(e E f g G).each do |f| + format = "%" + f + + it "behaves as if calling Kernel#Float for #{format} arguments" do + (format % 10).should == (format % 10.0) + (format % "-10.4e-20").should == (format % -10.4e-20) + (format % ".5").should == (format % 0.5) + (format % "-.5").should == (format % -0.5) + # Something is fucked up with this spec: + # it works just fine in individual mode, but not when run as part of a group + (format % "10_1_0.5_5_5").should == (format % 1010.555) + + (format % "0777").should == (format % 777) + + lambda { format % "" }.should raise_error(ArgumentError) + lambda { format % "x" }.should raise_error(ArgumentError) + lambda { format % "." }.should raise_error(ArgumentError) + lambda { format % "10." }.should raise_error(ArgumentError) + lambda { format % "5x" }.should raise_error(ArgumentError) + lambda { format % "0xA" }.should raise_error(ArgumentError) + lambda { format % "0b1" }.should raise_error(ArgumentError) + lambda { format % "10e10.5" }.should raise_error(ArgumentError) + lambda { format % "10__10" }.should raise_error(ArgumentError) + lambda { format % "10.10__10" }.should raise_error(ArgumentError) + + obj = mock('5.0') + obj.should_receive(:to_f).and_return(5.0) + (format % obj).should == (format % 5.0) + + obj = mock('3.14') + obj.should_receive(:respond_to?).with(:to_f).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_f).and_return(3.14) + (format % obj).should == (format % 3.14) + end + + it "doesn't taint the result for #{format} when argument is tainted" do + (format % "5".taint).tainted?.should == false + end + end +end diff --git a/1.8/core/string/multiply_spec.rb b/1.8/core/string/multiply_spec.rb new file mode 100644 index 0000000000..bf3fd41486 --- /dev/null +++ b/1.8/core/string/multiply_spec.rb @@ -0,0 +1,49 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#*" do + it "returns a new string containing count copies of self" do + ("cool" * 0).should == "" + ("cool" * 1).should == "cool" + ("cool" * 3).should == "coolcoolcool" + end + + it "tries to convert the given argument to an integer using to_int" do + ("cool" * 3.1).should == "coolcoolcool" + ("a" * 3.999).should == "aaa" + + a = mock('4') + def a.to_int() 4; end + ("a" * a).should == "aaaa" + + a = mock('4') + a.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + a.should_receive(:method_missing).with(:to_int).and_return(4) + ("a" * a).should == "aaaa" + end + + it "raises an ArgumentError when given integer is negative" do + lambda { "cool" * -3 }.should raise_error(ArgumentError) + lambda { "cool" * -3.14 }.should raise_error(ArgumentError) + end + + it "raises a RangeError when given integer is a Bignum" do + lambda { "cool" * 999999999999999999999 }.should raise_error(RangeError) + end + + it "returns subclass instances" do + (StringSpecs::MyString.new("cool") * 0).class.should == StringSpecs::MyString + (StringSpecs::MyString.new("cool") * 1).class.should == StringSpecs::MyString + (StringSpecs::MyString.new("cool") * 2).class.should == StringSpecs::MyString + end + + it "always taints the result when self is tainted" do + ["", "OK", StringSpecs::MyString.new(""), StringSpecs::MyString.new("OK")].each do |str| + str.taint + + [0, 1, 2].each do |arg| + (str * arg).tainted?.should == true + end + end + end +end diff --git a/1.8/core/string/next_spec.rb b/1.8/core/string/next_spec.rb new file mode 100644 index 0000000000..00a159b313 --- /dev/null +++ b/1.8/core/string/next_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/succ.rb' + +describe "String#next" do + it_behaves_like(:string_succ, :next) +end + +describe "String#next!" do + it_behaves_like(:string_succ_bang, :"next!") +end \ No newline at end of file diff --git a/1.8/core/string/oct_spec.rb b/1.8/core/string/oct_spec.rb new file mode 100644 index 0000000000..004f8562a6 --- /dev/null +++ b/1.8/core/string/oct_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +# Note: We can't completely spec this in terms of to_int() because hex() +# allows the base to be changed by a base specifier in the string. +# See http://groups.google.com/group/ruby-core-google/browse_frm/thread/b53e9c2003425703 +describe "String#oct" do + it "treats leading characters of self as a string of oct digits" do + "0".oct.should == 0 + "77".oct.should == 077 + "78".oct.should == 7 + "077".oct.should == 077 + "0o".oct.should == 0 + + "755_333".oct.should == 0755_333 + "7__3".oct.should == 073 + "5678".oct.should == 0567 + + "0b1010".oct.should == 0b1010 + "0xFF".oct.should == 0xFF + "0d500".oct.should == 500 + end + + it "takes an optional sign" do + "-1234".oct.should == -01234 + "+1234".oct.should == 01234 + end + + it "returns 0 on error" do + "".oct.should == 0 + "+-5".oct.should == 0 + "wombat".oct.should == 0 + end +end diff --git a/1.8/core/string/plus_spec.rb b/1.8/core/string/plus_spec.rb new file mode 100644 index 0000000000..5a019df0e6 --- /dev/null +++ b/1.8/core/string/plus_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#+" do + it "returns a new string containing the given string concatenated to self" do + ("" + "").should == "" + ("" + "Hello").should == "Hello" + ("Hello" + "").should == "Hello" + ("Ruby !" + "= Rubinius").should == "Ruby != Rubinius" + end + + it "converts any non-String argument with #to_str" do + c = mock 'str' + c.should_receive(:to_str).any_number_of_times.and_return(' + 1 = 2') + + ("1" + c).should == '1 + 1 = 2' + end + + it "raises a TypeError when given any object that fails #to_str" do + lambda { "" + Object.new }.should raise_error(TypeError) + lambda { "" + 65 }.should raise_error(TypeError) + end + + it "doesn't return subclass instances" do + (StringSpecs::MyString.new("hello") + "").class.should == String + (StringSpecs::MyString.new("hello") + "foo").class.should == String + (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("foo")).class.should == String + (StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("")).class.should == String + (StringSpecs::MyString.new("") + StringSpecs::MyString.new("")).class.should == String + ("hello" + StringSpecs::MyString.new("foo")).class.should == String + ("hello" + StringSpecs::MyString.new("")).class.should == String + end + + it "taints the result when self or other is tainted" do + strs = ["", "OK", StringSpecs::MyString.new(""), StringSpecs::MyString.new("OK")] + strs += strs.map { |s| s.dup.taint } + + strs.each do |str| + strs.each do |other| + (str + other).tainted?.should == (str.tainted? | other.tainted?) + end + end + end +end diff --git a/1.8/core/string/replace_spec.rb b/1.8/core/string/replace_spec.rb new file mode 100644 index 0000000000..5324cfe1c7 --- /dev/null +++ b/1.8/core/string/replace_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#replace" do + it "replaces the content of self with other and returns self" do + a = "some string" + a.replace("another string").equal?(a).should == true + a.should == "another string" + end + + it "replaces the taint status of self with that of other" do + a = "an untainted string" + b = "a tainted string".taint + a.replace(b) + a.tainted?.should == true + end + + it "tries to convert other to string using to_str" do + other = mock('x') + def other.to_str() "an object converted to a string" end + "hello".replace(other).should == "an object converted to a string" + + obj = mock('X') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("X") + "hello".replace(obj).should == "X" + end + + it "raises a TypeError if other can't be converted to string" do + lambda { "hello".replace(123) }.should raise_error(TypeError) + lambda { "hello".replace(:test) }.should raise_error(TypeError) + lambda { "hello".replace(mock('x')) }.should raise_error(TypeError) + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + a = "hello".freeze + + a.replace(a) # ok, no change + lambda { a.replace("") }.should raise_error(TypeError) + lambda { a.replace("world") }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/reverse_spec.rb b/1.8/core/string/reverse_spec.rb new file mode 100644 index 0000000000..4eb8ec9636 --- /dev/null +++ b/1.8/core/string/reverse_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#reverse" do + it "returns a new string with the characters of self in reverse order" do + "stressed".reverse.should == "desserts" + "m".reverse.should == "m" + "".reverse.should == "" + end + + it "taints the result if self is tainted" do + "".taint.reverse.tainted?.should == true + "m".taint.reverse.tainted?.should == true + end +end + +describe "String#reverse!" do + it "reverses self in place and always returns self" do + a = "stressed" + a.reverse!.equal?(a).should == true + a.should == "desserts" + + "".reverse!.should == "" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + "".freeze.reverse! # ok, no change + lambda { "anna".freeze.reverse! }.should raise_error(TypeError) + lambda { "hello".freeze.reverse! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/rindex_spec.rb b/1.8/core/string/rindex_spec.rb new file mode 100644 index 0000000000..92e7e55178 --- /dev/null +++ b/1.8/core/string/rindex_spec.rb @@ -0,0 +1,420 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#rindex with object" do + it "raises a TypeError if obj isn't a String, Fixnum or Regexp" do + lambda { "hello".rindex(:sym) }.should raise_error(TypeError) + lambda { "hello".rindex(mock('x')) }.should raise_error(TypeError) + end + + it "doesn't try to convert obj to an integer via to_int" do + obj = mock('x') + obj.should_not_receive(:to_int) + lambda { "hello".rindex(obj) }.should raise_error(TypeError) + end + + # Note: MRI doesn't call to_str, but should do so because index() does it. + # See http://groups.google.com/group/ruby-core-google/t/3f2d4129febd2a66 + + deviates_on :rubinius do + it "tries to convert obj to a string via to_str" do + obj = mock('lo') + def obj.to_str() "lo" end + "hello".rindex(obj).should == "hello".rindex("lo") + + obj = mock('o') + def obj.respond_to?(arg) true end + def obj.method_missing(*args) "o" end + "hello".rindex(obj).should == "hello".rindex("o") + end + end + + compliant_on :ruby, :jruby do + it "tries to convert obj to a string via to_str" do + obj = mock('lo') + def obj.to_str() "lo" end + lambda { "hello".rindex(obj) }.should raise_error(Exception) + + obj = mock('o') + def obj.respond_to?(arg) true end + def obj.method_missing(*args) "o" end + lambda { "hello".rindex(obj) }.should raise_error(Exception) + end + end +end + +describe "String#rindex with Fixnum" do + it "returns the index of the last occurrence of the given character" do + "hello".rindex(?e).should == 1 + "hello".rindex(?l).should == 3 + end + + it "doesn't use fixnum % 256" do + "hello".rindex(?e + 256 * 3).should == nil + "hello".rindex(-(256 - ?e)).should == nil + end + + it "starts the search at the given offset" do + "blablabla".rindex(?b, 0).should == 0 + "blablabla".rindex(?b, 1).should == 0 + "blablabla".rindex(?b, 2).should == 0 + "blablabla".rindex(?b, 3).should == 3 + "blablabla".rindex(?b, 4).should == 3 + "blablabla".rindex(?b, 5).should == 3 + "blablabla".rindex(?b, 6).should == 6 + "blablabla".rindex(?b, 7).should == 6 + "blablabla".rindex(?b, 8).should == 6 + "blablabla".rindex(?b, 9).should == 6 + "blablabla".rindex(?b, 10).should == 6 + + "blablabla".rindex(?a, 2).should == 2 + "blablabla".rindex(?a, 3).should == 2 + "blablabla".rindex(?a, 4).should == 2 + "blablabla".rindex(?a, 5).should == 5 + "blablabla".rindex(?a, 6).should == 5 + "blablabla".rindex(?a, 7).should == 5 + "blablabla".rindex(?a, 8).should == 8 + "blablabla".rindex(?a, 9).should == 8 + "blablabla".rindex(?a, 10).should == 8 + end + + it "starts the search at offset + self.length if offset is negative" do + str = "blablabla" + + [?a, ?b].each do |needle| + (-str.length .. -1).each do |offset| + str.rindex(needle, offset).should == + str.rindex(needle, offset + str.length) + end + end + end + + it "returns nil if the character isn't found" do + "hello".rindex(0).should == nil + + "hello".rindex(?H).should == nil + "hello".rindex(?z).should == nil + "hello".rindex(?o, 2).should == nil + + "blablabla".rindex(?a, 0).should == nil + "blablabla".rindex(?a, 1).should == nil + + "blablabla".rindex(?a, -8).should == nil + "blablabla".rindex(?a, -9).should == nil + + "blablabla".rindex(?b, -10).should == nil + "blablabla".rindex(?b, -20).should == nil + end + + it "tries to convert start_offset to an integer via to_int" do + obj = mock('5') + def obj.to_int() 5 end + "str".rindex(?s, obj).should == 0 + + obj = mock('5') + def obj.respond_to?(arg) true end + def obj.method_missing(*args); 5; end + "str".rindex(?s, obj).should == 0 + end + + it "raises a TypeError when given offset is nil" do + lambda { "str".rindex(?s, nil) }.should raise_error(TypeError) + lambda { "str".rindex(?t, nil) }.should raise_error(TypeError) + end +end + +describe "String#rindex with String" do + it "behaves the same as String#rindex(char) for one-character strings" do + ["blablabla", "hello cruel world...!"].each do |str| + str.split("").uniq.each do |str| + chr = str[0] + str.rindex(str).should == str.rindex(chr) + + 0.upto(str.size + 1) do |start| + str.rindex(str, start).should == str.rindex(chr, start) + end + + (-str.size - 1).upto(-1) do |start| + str.rindex(str, start).should == str.rindex(chr, start) + end + end + end + end + + it "returns the index of the last occurrence of the given substring" do + "blablabla".rindex("").should == 9 + "blablabla".rindex("a").should == 8 + "blablabla".rindex("la").should == 7 + "blablabla".rindex("bla").should == 6 + "blablabla".rindex("abla").should == 5 + "blablabla".rindex("labla").should == 4 + "blablabla".rindex("blabla").should == 3 + "blablabla".rindex("ablabla").should == 2 + "blablabla".rindex("lablabla").should == 1 + "blablabla".rindex("blablabla").should == 0 + + "blablabla".rindex("l").should == 7 + "blablabla".rindex("bl").should == 6 + "blablabla".rindex("abl").should == 5 + "blablabla".rindex("labl").should == 4 + "blablabla".rindex("blabl").should == 3 + "blablabla".rindex("ablabl").should == 2 + "blablabla".rindex("lablabl").should == 1 + "blablabla".rindex("blablabl").should == 0 + + "blablabla".rindex("b").should == 6 + "blablabla".rindex("ab").should == 5 + "blablabla".rindex("lab").should == 4 + "blablabla".rindex("blab").should == 3 + "blablabla".rindex("ablab").should == 2 + "blablabla".rindex("lablab").should == 1 + "blablabla".rindex("blablab").should == 0 + end + + it "doesn't set $~" do + $~ = nil + + 'hello.'.rindex('ll') + $~.should == nil + end + + it "ignores string subclasses" do + "blablabla".rindex(StringSpecs::MyString.new("bla")).should == 6 + StringSpecs::MyString.new("blablabla").rindex("bla").should == 6 + StringSpecs::MyString.new("blablabla").rindex(StringSpecs::MyString.new("bla")).should == 6 + end + + it "starts the search at the given offset" do + "blablabla".rindex("bl", 0).should == 0 + "blablabla".rindex("bl", 1).should == 0 + "blablabla".rindex("bl", 2).should == 0 + "blablabla".rindex("bl", 3).should == 3 + + "blablabla".rindex("bla", 0).should == 0 + "blablabla".rindex("bla", 1).should == 0 + "blablabla".rindex("bla", 2).should == 0 + "blablabla".rindex("bla", 3).should == 3 + + "blablabla".rindex("blab", 0).should == 0 + "blablabla".rindex("blab", 1).should == 0 + "blablabla".rindex("blab", 2).should == 0 + "blablabla".rindex("blab", 3).should == 3 + "blablabla".rindex("blab", 6).should == 3 + "blablablax".rindex("blab", 6).should == 3 + + "blablabla".rindex("la", 1).should == 1 + "blablabla".rindex("la", 2).should == 1 + "blablabla".rindex("la", 3).should == 1 + "blablabla".rindex("la", 4).should == 4 + + "blablabla".rindex("lab", 1).should == 1 + "blablabla".rindex("lab", 2).should == 1 + "blablabla".rindex("lab", 3).should == 1 + "blablabla".rindex("lab", 4).should == 4 + + "blablabla".rindex("ab", 2).should == 2 + "blablabla".rindex("ab", 3).should == 2 + "blablabla".rindex("ab", 4).should == 2 + "blablabla".rindex("ab", 5).should == 5 + + "blablabla".rindex("", 0).should == 0 + "blablabla".rindex("", 1).should == 1 + "blablabla".rindex("", 2).should == 2 + "blablabla".rindex("", 7).should == 7 + "blablabla".rindex("", 8).should == 8 + "blablabla".rindex("", 9).should == 9 + "blablabla".rindex("", 10).should == 9 + end + + it "starts the search at offset + self.length if offset is negative" do + str = "blablabla" + + ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle| + (-str.length .. -1).each do |offset| + str.rindex(needle, offset).should == + str.rindex(needle, offset + str.length) + end + end + end + + it "returns nil if the substring isn't found" do + "blablabla".rindex("B").should == nil + "blablabla".rindex("z").should == nil + "blablabla".rindex("BLA").should == nil + "blablabla".rindex("blablablabla").should == nil + + "hello".rindex("lo", 0).should == nil + "hello".rindex("lo", 1).should == nil + "hello".rindex("lo", 2).should == nil + + "hello".rindex("llo", 0).should == nil + "hello".rindex("llo", 1).should == nil + + "hello".rindex("el", 0).should == nil + "hello".rindex("ello", 0).should == nil + + "hello".rindex("", -6).should == nil + "hello".rindex("", -7).should == nil + + "hello".rindex("h", -6).should == nil + end + + it "tries to convert start_offset to an integer via to_int" do + obj = mock('5') + def obj.to_int() 5 end + "str".rindex("st", obj).should == 0 + + obj = mock('5') + def obj.respond_to?(arg) true end + def obj.method_missing(*args) 5 end + "str".rindex("st", obj).should == 0 + end + + it "raises a TypeError when given offset is nil" do + lambda { "str".rindex("st", nil) }.should raise_error(TypeError) + end +end + +describe "String#rindex with Regexp" do + it "behaves the same as String#rindex(string) for escaped string regexps" do + ["blablabla", "hello cruel world...!"].each do |str| + ["", "b", "bla", "lab", "o c", "d."].each do |needle| + regexp = Regexp.new(Regexp.escape(needle)) + str.rindex(regexp).should == str.rindex(needle) + + 0.upto(str.size + 1) do |start| + str.rindex(regexp, start).should == str.rindex(needle, start) + end + + (-str.size - 1).upto(-1) do |start| + str.rindex(regexp, start).should == str.rindex(needle, start) + end + end + end + end + + it "returns the index of the first match from the end of string of regexp" do + "blablabla".rindex(/bla/).should == 6 + "blablabla".rindex(/BLA/i).should == 6 + + "blablabla".rindex(/.{0}/).should == 9 + "blablabla".rindex(/.{1}/).should == 8 + "blablabla".rindex(/.{2}/).should == 7 + "blablabla".rindex(/.{6}/).should == 3 + "blablabla".rindex(/.{9}/).should == 0 + + "blablabla".rindex(/.*/).should == 9 + "blablabla".rindex(/.+/).should == 8 + + "blablabla".rindex(/bla|a/).should == 8 + + "blablabla".rindex(/\A/).should == 0 + "blablabla".rindex(/\Z/).should == 9 + "blablabla".rindex(/\z/).should == 9 + "blablabla\n".rindex(/\Z/).should == 10 + "blablabla\n".rindex(/\z/).should == 10 + + "blablabla".rindex(/^/).should == 0 + "\nblablabla".rindex(/^/).should == 1 + "b\nlablabla".rindex(/^/).should == 2 + "blablabla".rindex(/$/).should == 9 + + "blablabla".rindex(/.l./).should == 6 + end + + it "sets $~ to MatchData of match and nil when there's none" do + 'hello.'.rindex(/.(.)/) + $~[0].should == 'o.' + + 'hello.'.rindex(/not/) + $~.should == nil + end + + it "starts the search at the given offset" do + "blablabla".rindex(/.{0}/, 5).should == 5 + "blablabla".rindex(/.{1}/, 5).should == 5 + "blablabla".rindex(/.{2}/, 5).should == 5 + "blablabla".rindex(/.{3}/, 5).should == 5 + "blablabla".rindex(/.{4}/, 5).should == 5 + + "blablabla".rindex(/.{0}/, 3).should == 3 + "blablabla".rindex(/.{1}/, 3).should == 3 + "blablabla".rindex(/.{2}/, 3).should == 3 + "blablabla".rindex(/.{5}/, 3).should == 3 + "blablabla".rindex(/.{6}/, 3).should == 3 + + "blablabla".rindex(/.l./, 0).should == 0 + "blablabla".rindex(/.l./, 1).should == 0 + "blablabla".rindex(/.l./, 2).should == 0 + "blablabla".rindex(/.l./, 3).should == 3 + + "blablablax".rindex(/.x/, 10).should == 8 + "blablablax".rindex(/.x/, 9).should == 8 + "blablablax".rindex(/.x/, 8).should == 8 + + "blablablax".rindex(/..x/, 10).should == 7 + "blablablax".rindex(/..x/, 9).should == 7 + "blablablax".rindex(/..x/, 8).should == 7 + "blablablax".rindex(/..x/, 7).should == 7 + + "blablabla\n".rindex(/\Z/, 9).should == 9 + end + + it "starts the search at offset + self.length if offset is negative" do + str = "blablabla" + + ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle| + (-str.length .. -1).each do |offset| + str.rindex(needle, offset).should == + str.rindex(needle, offset + str.length) + end + end + end + + it "returns nil if the substring isn't found" do + "blablabla".rindex(/BLA/).should == nil + "blablabla".rindex(/.{10}/).should == nil + "blablablax".rindex(/.x/, 7).should == nil + "blablablax".rindex(/..x/, 6).should == nil + + "blablabla".rindex(/\Z/, 5).should == nil + "blablabla".rindex(/\z/, 5).should == nil + "blablabla\n".rindex(/\z/, 9).should == nil + end + + it "supports \\G which matches at the given start offset" do + "helloYOU.".rindex(/YOU\G/, 8).should == 5 + "helloYOU.".rindex(/YOU\G/).should == nil + + idx = "helloYOUall!".index("YOU") + re = /YOU.+\G.+/ + # The # marks where \G will match. + [ + ["helloYOU#all.", nil], + ["helloYOUa#ll.", idx], + ["helloYOUal#l.", idx], + ["helloYOUall#.", idx], + ["helloYOUall.#", nil] + ].each do |i| + start = i[0].index("#") + str = i[0].delete("#") + + str.rindex(re, start).should == i[1] + end + end + + it "tries to convert start_offset to an integer via to_int" do + obj = mock('5') + def obj.to_int() 5 end + "str".rindex(/../, obj).should == 1 + + obj = mock('5') + def obj.respond_to?(arg) true end + def obj.method_missing(*args); 5; end + "str".rindex(/../, obj).should == 1 + end + + it "raises a TypeError when given offset is nil" do + lambda { "str".rindex(/../, nil) }.should raise_error(TypeError) + end +end diff --git a/1.8/core/string/rjust_spec.rb b/1.8/core/string/rjust_spec.rb new file mode 100644 index 0000000000..ab73c39bfe --- /dev/null +++ b/1.8/core/string/rjust_spec.rb @@ -0,0 +1,93 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#rjust with length, padding" do + it "returns a new string of specified length with self right justified and padded with padstr" do + "hello".rjust(20, '1234').should == "123412341234123hello" + + "".rjust(1, "abcd").should == "a" + "".rjust(2, "abcd").should == "ab" + "".rjust(3, "abcd").should == "abc" + "".rjust(4, "abcd").should == "abcd" + "".rjust(6, "abcd").should == "abcdab" + + "OK".rjust(3, "abcd").should == "aOK" + "OK".rjust(4, "abcd").should == "abOK" + "OK".rjust(6, "abcd").should == "abcdOK" + "OK".rjust(8, "abcd").should == "abcdabOK" + end + + it "pads with whitespace if no padstr is given" do + "hello".rjust(20).should == " hello" + end + + it "returns self if it's longer than or as long as the specified length" do + "".rjust(0).should == "" + "".rjust(-1).should == "" + "hello".rjust(4).should == "hello" + "hello".rjust(-1).should == "hello" + "this".rjust(3).should == "this" + "radiology".rjust(8, '-').should == "radiology" + end + + it "taints result when self or padstr is tainted" do + "x".taint.rjust(4).tainted?.should == true + "x".taint.rjust(0).tainted?.should == true + "".taint.rjust(0).tainted?.should == true + "x".taint.rjust(4, "*").tainted?.should == true + "x".rjust(4, "*".taint).tainted?.should == true + end + + it "tries to convert length to an integer using to_int" do + "^".rjust(3.8, "^_").should == "^_^" + + obj = mock('3') + def obj.to_int() 3 end + + "o".rjust(obj, "o_").should == "o_o" + + obj = mock('3') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(3) + "~".rjust(obj, "~_").should == "~_~" + end + + it "raises a TypeError when length can't be converted to an integer" do + lambda { "hello".rjust("x") }.should raise_error(TypeError) + lambda { "hello".rjust("x", "y") }.should raise_error(TypeError) + lambda { "hello".rjust([]) }.should raise_error(TypeError) + lambda { "hello".rjust(mock('x')) }.should raise_error(TypeError) + end + + it "tries to convert padstr to a string using to_str" do + padstr = mock('123') + def padstr.to_str() "123" end + + "hello".rjust(10, padstr).should == "12312hello" + + obj = mock('k') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("k") + + "hello".rjust(7, obj).should == "kkhello" + end + + it "raises a TypeError when padstr can't be converted" do + lambda { "hello".rjust(20, :sym) }.should raise_error(TypeError) + lambda { "hello".rjust(20, ?c) }.should raise_error(TypeError) + lambda { "hello".rjust(20, mock('x')) }.should raise_error(TypeError) + end + + it "raises an ArgumentError when padstr is empty" do + lambda { "hello".rjust(10, '') }.should raise_error(ArgumentError) + end + + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").rjust(10).class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").rjust(10).class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).class.should == StringSpecs::MyString + + "".rjust(10, StringSpecs::MyString.new("x")).class.should == String + "foo".rjust(10, StringSpecs::MyString.new("x")).class.should == String + end +end diff --git a/1.8/core/string/rstrip_spec.rb b/1.8/core/string/rstrip_spec.rb new file mode 100644 index 0000000000..a68bcaeb63 --- /dev/null +++ b/1.8/core/string/rstrip_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#rstrip" do + it "returns a copy of self with trailing whitespace removed" do + " hello ".rstrip.should == " hello" + " hello world ".rstrip.should == " hello world" + " hello world \n\r\t\n\v\r".rstrip.should == " hello world" + "hello".rstrip.should == "hello" + "hello\x00".rstrip.should == "hello" + end + + it "taints the result when self is tainted" do + "".taint.rstrip.tainted?.should == true + "ok".taint.rstrip.tainted?.should == true + "ok ".taint.rstrip.tainted?.should == true + end +end + +describe "String#rstrip!" do + it "modifies self in place and returns self" do + a = " hello " + a.rstrip!.equal?(a).should == true + a.should == " hello" + end + + it "returns nil if no modifications were made" do + a = "hello" + a.rstrip!.should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + "hello".freeze.rstrip! # ok, nothing changed + "".freeze.rstrip! # ok, nothing changed + + lambda { " hello ".freeze.rstrip! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/scan_spec.rb b/1.8/core/string/scan_spec.rb new file mode 100644 index 0000000000..46fd05711b --- /dev/null +++ b/1.8/core/string/scan_spec.rb @@ -0,0 +1,181 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#scan" do + it "returns an array containing all matches" do + "cruel world".scan(/\w+/).should == ["cruel", "world"] + "cruel world".scan(/.../).should == ["cru", "el ", "wor"] + + # Edge case + "hello".scan(//).should == ["", "", "", "", "", ""] + "".scan(//).should == [""] + end + + it "stores groups as arrays in the returned arrays" do + "hello".scan(/()/).should == [[""]] * 6 + "hello".scan(/()()/).should == [["", ""]] * 6 + "cruel world".scan(/(...)/).should == [["cru"], ["el "], ["wor"]] + "cruel world".scan(/(..)(..)/).should == [["cr", "ue"], ["l ", "wo"]] + end + + it "scans for occurrences of the string if pattern is a string" do + "one two one two".scan('one').should == ["one", "one"] + "hello.".scan('.').should == ['.'] + end + + it "sets $~ to MatchData of last match and nil when there's none" do + 'hello.'.scan(/.(.)/) + $~[0].should == 'o.' + + 'hello.'.scan(/not/) + $~.should == nil + + 'hello.'.scan('l') + $~.begin(0).should == 3 + $~[0].should == 'l' + + 'hello.'.scan('not') + $~.should == nil + end + + it "supports \\G which matches the end of the previous match / string start for first match" do + "one two one two".scan(/\G\w+/).should == ["one"] + "one two one two".scan(/\G\w+\s*/).should == ["one ", "two ", "one ", "two"] + "one two one two".scan(/\G\s*\w+/).should == ["one", " two", " one", " two"] + end + + it "tries to convert pattern to a string via to_str" do + obj = mock('o') + obj.should_receive(:to_str).and_return("o") + "o_o".scan(obj).should == ["o", "o"] + + obj = mock('-') + obj.should_receive(:respond_to?).with(:to_str).and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("-") + "-_-".scan(obj).should == ["-", "-"] + end + + it "raises a TypeError if pattern isn't a Regexp and can't be converted to a String" do + lambda { "cruel world".scan(5) }.should raise_error(TypeError) + lambda { "cruel world".scan(:test) }.should raise_error(TypeError) + lambda { "cruel world".scan(mock('x')) }.should raise_error(TypeError) + end + + # Note: MRI taints for tainted regexp patterns, + # but not for tainted string patterns. + # TODO: Report to ruby-core. + it "taints the match strings if self is tainted, unless the taint happens in the method call" do + deviates_on :ruby do + a = "hello hello hello".scan("hello".taint) + a.each { |m| m.tainted?.should == false } + end + + a = "hello hello hello".taint.scan("hello") + a.each { |m| m.tainted?.should == true } + + a = "hello".scan(/./.taint) + a.each { |m| m.tainted?.should == true } + + a = "hello".taint.scan(/./) + a.each { |m| m.tainted?.should == true } + end +end + +describe "String#scan with pattern and block" do + it "returns self" do + s = "foo" + s.scan(/./) {}.equal?(s).should == true + s.scan(/roar/) {}.equal?(s).should == true + end + + it "passes each match to the block as one argument: an array" do + a = [] + "cruel world".scan(/\w+/) { |*w| a << w } + a.should == [["cruel"], ["world"]] + end + + it "passes groups to the block as one argument: an array" do + a = [] + "cruel world".scan(/(..)(..)/) { |w| a << w } + a.should == [["cr", "ue"], ["l ", "wo"]] + end + + it "sets $~ for access from the block" do + str = "hello" + + matches = [] + offsets = [] + + str.scan(/([aeiou])/) do + md = $~ + md.string.should == str + matches << md.to_a + offsets << md.offset(0) + str + end + + matches.should == [["e", "e"], ["o", "o"]] + offsets.should == [[1, 2], [4, 5]] + + matches = [] + offsets = [] + + str.scan("l") do + md = $~ + md.string.should == str + matches << md.to_a + offsets << md.offset(0) + str + end + + matches.should == [["l"], ["l"]] + offsets.should == [[2, 3], [3, 4]] + end + + it "restores $~ after leaving the block" do + [/./, "l"].each do |pattern| + old_md = nil + "hello".scan(pattern) do + old_md = $~ + "ok".match(/./) + "x" + end + + $~.should == old_md + $~.string.should == "hello" + end + end + + it "sets $~ to MatchData of last match and nil when there's none for access from outside" do + 'hello.'.scan('l') { 'x' } + $~.begin(0).should == 3 + $~[0].should == 'l' + + 'hello.'.scan('not') { 'x' } + $~.should == nil + + 'hello.'.scan(/.(.)/) { 'x' } + $~[0].should == 'o.' + + 'hello.'.scan(/not/) { 'x' } + $~.should == nil + end + + # Note: MRI taints for tainted regexp patterns, + # but not for tainted string patterns. + # TODO: Report to ruby-core. + it "taints the match strings if self is tainted, unless the tain happens inside the scan" do + deviates_on :ruby do + "hello hello hello".scan("hello".taint) { |m| m.tainted?.should == false } + end + + deviates_on :rubinius do + "hello hello hello".scan("hello".taint) { |m| m.tainted?.should == true } + end + + "hello hello hello".taint.scan("hello") { |m| m.tainted?.should == true } + + "hello".scan(/./.taint) { |m| m.tainted?.should == true } + "hello".taint.scan(/./) { |m| m.tainted?.should == true } + end +end diff --git a/1.8/core/string/shared/concat.rb b/1.8/core/string/shared/concat.rb new file mode 100644 index 0000000000..425a43745d --- /dev/null +++ b/1.8/core/string/shared/concat.rb @@ -0,0 +1,83 @@ +shared :string_concat do |cmd| + describe "String##{cmd}" do + it "concatenates the given argument to self and returns self" do + str = 'hello ' + str.send(cmd, 'world').equal?(str).should == true + str.should == "hello world" + end + + it "converts the given argument to a String using to_str" do + obj = mock('world!') + obj.should_receive(:to_str).and_return("world!") + a = 'hello '.send(cmd, obj) + a.should == 'hello world!' + + obj = mock('world!') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("world!") + a = 'hello '.send(cmd, obj) + a.should == 'hello world!' + end + + it "raises a TypeError if the given argument can't be converted to a String" do + lambda { a = 'hello '.send(cmd, :world) }.should raise_error(TypeError) + lambda { a = 'hello '.send(cmd, mock('x')) }.should raise_error(TypeError) + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + a = "hello" + a.freeze + + lambda { a.send(cmd, "") }.should raise_error(TypeError) + lambda { a.send(cmd, "test") }.should raise_error(TypeError) + end + end + + it "works when given a subclass instance" do + a = "hello" + a << StringSpecs::MyString.new(" world") + a.should == "hello world" + end + + it "taints self if other is tainted" do + x = "x" + x.send(cmd, "".taint).tainted?.should == true + + x = "x" + x.send(cmd, "y".taint).tainted?.should == true + end + end + + describe "String##{cmd} with Fixnum" do + it "converts the given Fixnum to a char before concatenating" do + b = 'hello '.send(cmd, 'world').send(cmd, 33) + b.should == "hello world!" + b.send(cmd, 0) + b.should == "hello world!\x00" + end + + it "raises a TypeError when the given Fixnum is not between 0 and 255" do + lambda { "hello world".send(cmd, 333) }.should raise_error(TypeError) + lambda { "".send(cmd, (256 * 3 + 64)) }.should raise_error(TypeError) + lambda { "".send(cmd, -200) }.should raise_error(TypeError) + end + + it "doesn't call to_int on its argument" do + x = mock('x') + x.should_not_receive(:to_int) + + lambda { "".send(cmd, x) }.should raise_error(TypeError) + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + a = "hello" + a.freeze + + lambda { a.send(cmd, 0) }.should raise_error(TypeError) + lambda { a.send(cmd, 33) }.should raise_error(TypeError) + end + end + end +end \ No newline at end of file diff --git a/1.8/core/string/shared/each.rb b/1.8/core/string/shared/each.rb new file mode 100644 index 0000000000..0f2f9955f2 --- /dev/null +++ b/1.8/core/string/shared/each.rb @@ -0,0 +1,98 @@ +shared :string_each do |cmd| + describe "String##{cmd}" do + it "splits self using the supplied record separator and passes each substring to the block" do + a = [] + "one\ntwo\r\nthree".send(cmd, "\n") { |s| a << s } + a.should == ["one\n", "two\r\n", "three"] + + b = [] + "hello\nworld".send(cmd, 'l') { |s| b << s } + b.should == [ "hel", "l", "o\nworl", "d" ] + + c = [] + "hello\n\n\nworld".send(cmd, "\n") { |s| c << s } + c.should == ["hello\n", "\n", "\n", "world"] + end + + it "taints substrings that are passed to the block if self is tainted" do + "one\ntwo\r\nthree".taint.send(cmd) { |s| s.tainted?.should == true } + + "x.y.".send(cmd, ".".taint) { |s| s.tainted?.should == false } + end + + it "passes self as a whole to the block if the separator is nil" do + a = [] + "one\ntwo\r\nthree".send(cmd, nil) { |s| a << s } + a.should == ["one\ntwo\r\nthree"] + end + + it "appends multiple successive newlines together when the separator is an empty string" do + a = [] + "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(cmd, '') { |s| a << s } + a.should == ["hello\nworld\n\n\n", "and\nuniverse\n\n\n\n\n"] + end + + it "uses $/ as the separator when none is given" do + [ + "", "x", "x\ny", "x\ry", "x\r\ny", "x\n\r\r\ny", + "hello hullo bello" + ].each do |str| + ["", "llo", "\n", "\r", nil].each do |sep| + begin + expected = [] + str.send(cmd, sep) { |x| expected << x } + + old_rec_sep, $/ = $/, sep + + actual = [] + str.send(cmd) { |x| actual << x } + + actual.should == expected + ensure + $/ = old_rec_sep + end + end + end + end + + it "yields subclass instances for subclasses" do + a = [] + StringSpecs::MyString.new("hello\nworld").send(cmd) { |s| a << s.class } + a.should == [StringSpecs::MyString, StringSpecs::MyString] + end + + it "returns self" do + s = "hello\nworld" + (s.send(cmd) {}).equal?(s).should == true + end + + it "tries to convert the separator to a string using to_str" do + separator = mock('l') + def separator.to_str() 'l' end + + a = [] + "hello\nworld".send(cmd, separator) { |s| a << s } + a.should == [ "hel", "l", "o\nworl", "d" ] + + obj = mock('l') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("l") + + a = [] + "hello\nworld".send(cmd, obj) { |s| a << s } + a.should == [ "hel", "l", "o\nworl", "d" ] + end + + it "raises a RuntimeError if the string is modified while substituting" do + str = "hello\nworld" + lambda { str.send(cmd) { str[0] = 'x' } }.should raise_error(RuntimeError) + end + + it "raises a TypeError when the separator can't be converted to a string" do + lambda { "hello world".send(cmd, false) }.should raise_error(TypeError) + lambda { "hello world".send(cmd, ?o) }.should raise_error(TypeError) + lambda { "hello world".send(cmd, :o) }.should raise_error(TypeError) + lambda { "hello world".send(cmd, mock('x')) }.should raise_error(TypeError) + end + end +end \ No newline at end of file diff --git a/1.8/core/string/shared/equal_value.rb b/1.8/core/string/shared/equal_value.rb new file mode 100644 index 0000000000..8635e94e18 --- /dev/null +++ b/1.8/core/string/shared/equal_value.rb @@ -0,0 +1,20 @@ +shared :string_equal_value do |cmd| + describe "String##{cmd} with String" do + it "returns true if self <=> string returns 0" do + 'hello'.send(cmd, 'hello').should == true + end + + it "returns false if self <=> string does not return 0" do + "more".send(cmd, "MORE").should == false + "less".send(cmd, "greater").should == false + end + + it "ignores subclass differences" do + a = "hello" + b = StringSpecs::MyString.new("hello") + + a.send(cmd, b).should == true + b.send(cmd, a).should == true + end + end +end \ No newline at end of file diff --git a/1.8/core/string/shared/length.rb b/1.8/core/string/shared/length.rb new file mode 100644 index 0000000000..d378163892 --- /dev/null +++ b/1.8/core/string/shared/length.rb @@ -0,0 +1,12 @@ +shared :string_length do |cmd| + describe "String##{cmd}" do + it "returns the length of self" do + "".send(cmd).should == 0 + "\x00".send(cmd).should == 1 + "one".send(cmd).should == 3 + "two".send(cmd).should == 3 + "three".send(cmd).should == 5 + "four".send(cmd).should == 4 + end + end +end \ No newline at end of file diff --git a/1.8/core/string/shared/slice.rb b/1.8/core/string/shared/slice.rb new file mode 100644 index 0000000000..75d554dcf1 --- /dev/null +++ b/1.8/core/string/shared/slice.rb @@ -0,0 +1,439 @@ +shared :string_slice do |cmd| + describe "String##{cmd} with index" do + it "returns the character code of the character at the given index" do + "hello".send(cmd, 0).should == ?h + "hello".send(cmd, -1).should == ?o + end + + it "returns nil if index is outside of self" do + "hello".send(cmd, 20).should == nil + "hello".send(cmd, -20).should == nil + + "".send(cmd, 0).should == nil + "".send(cmd, -1).should == nil + end + + it "calls to_int on the given index" do + "hello".send(cmd, 0.5).should == ?h + + obj = mock('1') + obj.should_receive(:to_int).and_return(1) + "hello".send(cmd, obj).should == ?e + + obj = mock('1') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(1) + "hello".send(cmd, obj).should == ?e + end + + it "raises a TypeError if the given index is nil" do + lambda { "hello".send(cmd, nil) }.should raise_error(TypeError) + end + + it "raises a TypeError if the given index can't be converted to an Integer" do + lambda { "hello".send(cmd, mock('x')) }.should raise_error(TypeError) + lambda { "hello".send(cmd, {}) }.should raise_error(TypeError) + lambda { "hello".send(cmd, []) }.should raise_error(TypeError) + end + end + + describe "String##{cmd} with index, length" do + it "returns the substring starting at the given index with the given length" do + "hello there".send(cmd, 0,0).should == "" + "hello there".send(cmd, 0,1).should == "h" + "hello there".send(cmd, 0,3).should == "hel" + "hello there".send(cmd, 0,6).should == "hello " + "hello there".send(cmd, 0,9).should == "hello the" + "hello there".send(cmd, 0,12).should == "hello there" + + "hello there".send(cmd, 1,0).should == "" + "hello there".send(cmd, 1,1).should == "e" + "hello there".send(cmd, 1,3).should == "ell" + "hello there".send(cmd, 1,6).should == "ello t" + "hello there".send(cmd, 1,9).should == "ello ther" + "hello there".send(cmd, 1,12).should == "ello there" + + "hello there".send(cmd, 3,0).should == "" + "hello there".send(cmd, 3,1).should == "l" + "hello there".send(cmd, 3,3).should == "lo " + "hello there".send(cmd, 3,6).should == "lo the" + "hello there".send(cmd, 3,9).should == "lo there" + + "hello there".send(cmd, 4,0).should == "" + "hello there".send(cmd, 4,3).should == "o t" + "hello there".send(cmd, 4,6).should == "o ther" + "hello there".send(cmd, 4,9).should == "o there" + + "foo".send(cmd, 2,1).should == "o" + "foo".send(cmd, 3,0).should == "" + "foo".send(cmd, 3,1).should == "" + + "".send(cmd, 0,0).should == "" + "".send(cmd, 0,1).should == "" + + "x".send(cmd, 0,0).should == "" + "x".send(cmd, 0,1).should == "x" + "x".send(cmd, 1,0).should == "" + "x".send(cmd, 1,1).should == "" + + "x".send(cmd, -1,0).should == "" + "x".send(cmd, -1,1).should == "x" + + "hello there".send(cmd, -3,2).should == "er" + end + + it "always taints resulting strings when self is tainted" do + str = "hello world" + str.taint + + str.send(cmd, 0,0).tainted?.should == true + str.send(cmd, 0,1).tainted?.should == true + str.send(cmd, 2,1).tainted?.should == true + end + + it "returns nil if the offset falls outside of self" do + "hello there".send(cmd, 20,3).should == nil + "hello there".send(cmd, -20,3).should == nil + + "".send(cmd, 1,0).should == nil + "".send(cmd, 1,1).should == nil + + "".send(cmd, -1,0).should == nil + "".send(cmd, -1,1).should == nil + + "x".send(cmd, 2,0).should == nil + "x".send(cmd, 2,1).should == nil + + "x".send(cmd, -2,0).should == nil + "x".send(cmd, -2,1).should == nil + end + + it "returns nil if the length is negative" do + "hello there".send(cmd, 4,-3).should == nil + "hello there".send(cmd, -4,-3).should == nil + end + + it "calls to_int on the given index and the given length" do + "hello".send(cmd, 0.5, 1).should == "h" + "hello".send(cmd, 0.5, 2.5).should == "he" + "hello".send(cmd, 1, 2.5).should == "el" + + obj = mock('2') + obj.should_receive(:to_int).exactly(4).times.and_return(2) + + "hello".send(cmd, obj, 1).should == "l" + "hello".send(cmd, obj, obj).should == "ll" + "hello".send(cmd, 0, obj).should == "he" + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).exactly(2).times.and_return(2) + "hello".send(cmd, obj, obj).should == "ll" + end + + it "raises a TypeError when idx or length can't be converted to an integer" do + lambda { "hello".send(cmd, mock('x'), 0) }.should raise_error(TypeError) + lambda { "hello".send(cmd, 0, mock('x')) }.should raise_error(TypeError) + + # I'm deliberately including this here. + # It means that str.send(cmd, other, idx) isn't supported. + lambda { "hello".send(cmd, "", 0) }.should raise_error(TypeError) + end + + it "raises a TypeError when the given index or the given length is nil" do + lambda { "hello".send(cmd, 1, nil) }.should raise_error(TypeError) + lambda { "hello".send(cmd, nil, 1) }.should raise_error(TypeError) + lambda { "hello".send(cmd, nil, nil) }.should raise_error(TypeError) + end + + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(cmd, 0,0).class.should == StringSpecs::MyString + s.send(cmd, 0,4).class.should == StringSpecs::MyString + s.send(cmd, 1,4).class.should == StringSpecs::MyString + end + end + + describe "String##{cmd} with Range" do + it "returns the substring given by the offsets of the range" do + "hello there".send(cmd, 1..1).should == "e" + "hello there".send(cmd, 1..3).should == "ell" + "hello there".send(cmd, 1...3).should == "el" + "hello there".send(cmd, -4..-2).should == "her" + "hello there".send(cmd, -4...-2).should == "he" + "hello there".send(cmd, 5..-1).should == " there" + "hello there".send(cmd, 5...-1).should == " ther" + + "".send(cmd, 0..0).should == "" + + "x".send(cmd, 0..0).should == "x" + "x".send(cmd, 0..1).should == "x" + "x".send(cmd, 0...1).should == "x" + "x".send(cmd, 0..-1).should == "x" + + "x".send(cmd, 1..1).should == "" + "x".send(cmd, 1..-1).should == "" + end + + it "returns nil if the beginning of the range falls outside of self" do + "hello there".send(cmd, 12..-1).should == nil + "hello there".send(cmd, 20..25).should == nil + "hello there".send(cmd, 20..1).should == nil + "hello there".send(cmd, -20..1).should == nil + "hello there".send(cmd, -20..-1).should == nil + + "".send(cmd, -1..-1).should == nil + "".send(cmd, -1...-1).should == nil + "".send(cmd, -1..0).should == nil + "".send(cmd, -1...0).should == nil + end + + it "returns an empty string if range.begin is inside self and > real end" do + "hello there".send(cmd, 1...1).should == "" + "hello there".send(cmd, 4..2).should == "" + "hello".send(cmd, 4..-4).should == "" + "hello there".send(cmd, -5..-6).should == "" + "hello there".send(cmd, -2..-4).should == "" + "hello there".send(cmd, -5..-6).should == "" + "hello there".send(cmd, -5..2).should == "" + + "".send(cmd, 0...0).should == "" + "".send(cmd, 0..-1).should == "" + "".send(cmd, 0...-1).should == "" + + "x".send(cmd, 0...0).should == "" + "x".send(cmd, 0...-1).should == "" + "x".send(cmd, 1...1).should == "" + "x".send(cmd, 1...-1).should == "" + end + + it "always taints resulting strings when self is tainted" do + str = "hello world" + str.taint + + str.send(cmd, 0..0).tainted?.should == true + str.send(cmd, 0...0).tainted?.should == true + str.send(cmd, 0..1).tainted?.should == true + str.send(cmd, 0...1).tainted?.should == true + str.send(cmd, 2..3).tainted?.should == true + str.send(cmd, 2..0).tainted?.should == true + end + + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(cmd, 0...0).class.should == StringSpecs::MyString + s.send(cmd, 0..4).class.should == StringSpecs::MyString + s.send(cmd, 1..4).class.should == StringSpecs::MyString + end + + it "calls to_int on range arguments" do + from = mock('from') + to = mock('to') + + # So we can construct a range out of them... + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + def from.to_int() 1 end + def to.to_int() -2 end + + "hello there".send(cmd, from..to).should == "ello ther" + "hello there".send(cmd, from...to).should == "ello the" + + from = mock('from') + to = mock('to') + + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + from.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + from.should_receive(:method_missing).with(:to_int).and_return(1) + to.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + to.should_receive(:method_missing).with(:to_int).and_return(-2) + + "hello there".send(cmd, from..to).should == "ello ther" + end + + it "works with Range subclasses" do + a = "GOOD" + range_incl = StringSpecs::MyRange.new(1, 2) + range_excl = StringSpecs::MyRange.new(-3, -1, true) + + a.send(cmd, range_incl).should == "OO" + a.send(cmd, range_excl).should == "OO" + end + end + + describe "String##{cmd} with Regexp" do + it "returns the matching portion of self" do + "hello there".send(cmd, /[aeiou](.)\1/).should == "ell" + "".send(cmd, //).should == "" + end + + it "returns nil if there is no match" do + "hello there".send(cmd, /xyz/).should == nil + end + + it "always taints resulting strings when self or regexp is tainted" do + strs = ["hello world"] + strs += strs.map { |s| s.dup.taint } + + strs.each do |str| + str.send(cmd, //).tainted?.should == str.tainted? + str.send(cmd, /hello/).tainted?.should == str.tainted? + + tainted_re = /./ + tainted_re.taint + + str.send(cmd, tainted_re).tainted?.should == true + end + end + + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(cmd, //).class.should == StringSpecs::MyString + s.send(cmd, /../).class.should == StringSpecs::MyString + end + + it "sets $~ to MatchData when there is a match and nil when there's none" do + 'hello'.send(cmd, /./) + $~[0].should == 'h' + + 'hello'.send(cmd, /not/) + $~.should == nil + end + end + + describe "String##{cmd} with Regexp, index" do + it "returns the capture for the given index" do + "hello there".send(cmd, /[aeiou](.)\1/, 0).should == "ell" + "hello there".send(cmd, /[aeiou](.)\1/, 1).should == "l" + "hello there".send(cmd, /[aeiou](.)\1/, -1).should == "l" + + "har".send(cmd, /(.)(.)(.)/, 0).should == "har" + "har".send(cmd, /(.)(.)(.)/, 1).should == "h" + "har".send(cmd, /(.)(.)(.)/, 2).should == "a" + "har".send(cmd, /(.)(.)(.)/, 3).should == "r" + "har".send(cmd, /(.)(.)(.)/, -1).should == "r" + "har".send(cmd, /(.)(.)(.)/, -2).should == "a" + "har".send(cmd, /(.)(.)(.)/, -3).should == "h" + end + + it "always taints resulting strings when self or regexp is tainted" do + strs = ["hello world"] + strs += strs.map { |s| s.dup.taint } + + strs.each do |str| + str.send(cmd, //, 0).tainted?.should == str.tainted? + str.send(cmd, /hello/, 0).tainted?.should == str.tainted? + + str.send(cmd, /(.)(.)(.)/, 0).tainted?.should == str.tainted? + str.send(cmd, /(.)(.)(.)/, 1).tainted?.should == str.tainted? + str.send(cmd, /(.)(.)(.)/, -1).tainted?.should == str.tainted? + str.send(cmd, /(.)(.)(.)/, -2).tainted?.should == str.tainted? + + tainted_re = /(.)(.)(.)/ + tainted_re.taint + + str.send(cmd, tainted_re, 0).tainted?.should == true + str.send(cmd, tainted_re, 1).tainted?.should == true + str.send(cmd, tainted_re, -1).tainted?.should == true + end + end + + it "returns nil if there is no match" do + "hello there".send(cmd, /(what?)/, 1).should == nil + end + + it "returns nil if there is no capture for the given index" do + "hello there".send(cmd, /[aeiou](.)\1/, 2).should == nil + # You can't refer to 0 using negative indices + "hello there".send(cmd, /[aeiou](.)\1/, -2).should == nil + end + + it "calls to_int on the given index" do + obj = mock('2') + obj.should_receive(:to_int).and_return(2) + + "har".send(cmd, /(.)(.)(.)/, 1.5).should == "h" + "har".send(cmd, /(.)(.)(.)/, obj).should == "a" + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(2) + "har".send(cmd, /(.)(.)(.)/, obj).should == "a" + end + + it "raises a TypeError when the given index can't be converted to Integer" do + lambda { "hello".send(cmd, /(.)(.)(.)/, mock('x')) }.should raise_error(TypeError) + lambda { "hello".send(cmd, /(.)(.)(.)/, {}) }.should raise_error(TypeError) + lambda { "hello".send(cmd, /(.)(.)(.)/, []) }.should raise_error(TypeError) + end + + it "raises a TypeError when the given index is nil" do + lambda { "hello".send(cmd, /(.)(.)(.)/, nil) }.should raise_error(TypeError) + end + + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(cmd, /(.)(.)/, 0).class.should == StringSpecs::MyString + s.send(cmd, /(.)(.)/, 1).class.should == StringSpecs::MyString + end + + it "sets $~ to MatchData when there is a match and nil when there's none" do + 'hello'.send(cmd, /.(.)/, 0) + $~[0].should == 'he' + + 'hello'.send(cmd, /.(.)/, 1) + $~[1].should == 'e' + + 'hello'.send(cmd, /not/, 0) + $~.should == nil + end + end + + describe "String##{cmd} with String" do + it "returns other_str if it occurs in self" do + s = "lo" + "hello there".send(cmd, s).should == s + end + + it "taints resulting strings when other is tainted" do + strs = ["", "hello world", "hello"] + strs += strs.map { |s| s.dup.taint } + + strs.each do |str| + strs.each do |other| + r = str.send(cmd, other) + + r.tainted?.should == !r.nil? & other.tainted? + end + end + end + + it "doesn't set $~" do + $~ = nil + + 'hello'.send(cmd, 'll') + $~.should == nil + end + + it "returns nil if there is no match" do + "hello there".send(cmd, "bye").should == nil + end + + it "doesn't call to_str on its argument" do + o = mock('x') + o.should_not_receive(:to_str) + + lambda { "hello".send(cmd, o) }.should raise_error(TypeError) + end + + it "returns a subclass instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".send(cmd, s) + r.should == "el" + r.class.should == StringSpecs::MyString + end + end +end \ No newline at end of file diff --git a/1.8/core/string/shared/sub.rb b/1.8/core/string/shared/sub.rb new file mode 100644 index 0000000000..0c20e89373 --- /dev/null +++ b/1.8/core/string/shared/sub.rb @@ -0,0 +1,12 @@ +shared :string_sub_bang_frozen_raises do |error| + describe "String#sub!" do + it "raises a #{error} when self is frozen" do + s = "hello" + s.freeze + + s.sub!(/ROAR/) { "x" } # ok + lambda { s.sub!(/e/) { "e" } }.should raise_error(error) + lambda { s.sub!(/[aeiou]/) { '*' } }.should raise_error(error) + end + end +end diff --git a/1.8/core/string/shared/succ.rb b/1.8/core/string/shared/succ.rb new file mode 100644 index 0000000000..9e20e57d03 --- /dev/null +++ b/1.8/core/string/shared/succ.rb @@ -0,0 +1,92 @@ +shared :string_succ do |cmd| + describe "String##{cmd}" do + it "returns an empty string for empty strings" do + "".send(cmd).should == "" + end + + it "returns the successor by increasing the rightmost alphanumeric (digit => digit, letter => letter with same case)" do + "abcd".send(cmd).should == "abce" + "THX1138".send(cmd).should == "THX1139" + + "<>".send(cmd).should == "<>" + "==A??".send(cmd).should == "==B??" + end + + it "increases non-alphanumerics (via ascii rules) if there are no alphanumerics" do + "***".send(cmd).should == "**+" + "**`".send(cmd).should == "**a" + end + + it "increases the next best alphanumeric (jumping over non-alphanumerics) if there is a carry" do + "dz".send(cmd).should == "ea" + "HZ".send(cmd).should == "IA" + "49".send(cmd).should == "50" + + "izz".send(cmd).should == "jaa" + "IZZ".send(cmd).should == "JAA" + "699".send(cmd).should == "700" + + "6Z99z99Z".send(cmd).should == "7A00a00A" + + "1999zzz".send(cmd).should == "2000aaa" + "NZ/[]ZZZ9999".send(cmd).should == "OA/[]AAA0000" + end + + it "increases the next best character if there is a carry for non-alphanumerics" do + "(\xFF".send(cmd).should == ")\x00" + "`\xFF".send(cmd).should == "a\x00" + "<\xFF\xFF".send(cmd).should == "=\x00\x00" + end + + it "adds an additional character (just left to the last increased one) if there is a carry and no character left to increase" do + "z".send(cmd).should == "aa" + "Z".send(cmd).should == "AA" + "9".send(cmd).should == "10" + + "zz".send(cmd).should == "aaa" + "ZZ".send(cmd).should == "AAA" + "99".send(cmd).should == "100" + + "9Z99z99Z".send(cmd).should == "10A00a00A" + + "ZZZ9999".send(cmd).should == "AAAA0000" + "/[]ZZZ9999".send(cmd).should == "/[]AAAA0000" + "Z/[]ZZZ9999".send(cmd).should == "AA/[]AAA0000" + + # non-alphanumeric cases + "\xFF".send(cmd).should == "\x01\x00" + "\xFF\xFF".send(cmd).should == "\x01\x00\x00" + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").send(cmd).class.should == StringSpecs::MyString + StringSpecs::MyString.new("a").send(cmd).class.should == StringSpecs::MyString + StringSpecs::MyString.new("z").send(cmd).class.should == StringSpecs::MyString + end + + it "taints the result if self is tainted" do + ["", "a", "z", "Z", "9", "\xFF", "\xFF\xFF"].each do |s| + s.taint.send(cmd).tainted?.should == true + end + end + end +end + +shared :string_succ_bang do |cmd| + describe "String##{cmd}" do + it "is equivalent to succ, but modifies self in place (still returns self)" do + ["", "abcd", "THX1138"].each do |s| + r = s.dup.send(cmd) + s.send(cmd).equal?(s).should == true + s.should == r + end + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + lambda { "".freeze.send(cmd) }.should raise_error(TypeError) + lambda { "abcd".freeze.send(cmd) }.should raise_error(TypeError) + end + end + end +end \ No newline at end of file diff --git a/1.8/core/string/shared/to_a.rb b/1.8/core/string/shared/to_a.rb new file mode 100644 index 0000000000..ef3e9c0d96 --- /dev/null +++ b/1.8/core/string/shared/to_a.rb @@ -0,0 +1,11 @@ +shared :string_to_a do |cmd| + describe "String##{cmd}" do + it "returns an empty array for empty strings" do + "".send(cmd).should == [] + end + + it "returns an array containing the string for non-empty strings" do + "hello".send(cmd).should == ["hello"] + end + end +end diff --git a/1.8/core/string/shared/to_s.rb b/1.8/core/string/shared/to_s.rb new file mode 100644 index 0000000000..f79a0b93c7 --- /dev/null +++ b/1.8/core/string/shared/to_s.rb @@ -0,0 +1,20 @@ +shared :string_to_s do |cmd| + describe "String##{cmd}" do + it "returns self when self.class == String" do + a = "a string" + a.equal?(a.send(cmd)).should == true + end + + it "returns a new instance of String when called on a subclass" do + a = StringSpecs::MyString.new("a string") + s = a.send(cmd) + s.should == "a string" + s.class.should == String + end + + it "taints the result when self is tainted" do + "x".taint.send(cmd).tainted?.should == true + StringSpecs::MyString.new("x").taint.send(cmd).tainted?.should == true + end + end +end diff --git a/1.8/core/string/shared/to_sym.rb b/1.8/core/string/shared/to_sym.rb new file mode 100644 index 0000000000..5bc4b674fd --- /dev/null +++ b/1.8/core/string/shared/to_sym.rb @@ -0,0 +1,16 @@ +shared :string_to_sym do |cmd| + describe "String##{cmd}" do + it "returns the symbol corresponding to self" do + "Koala".send(cmd).should == :Koala + 'cat'.send(cmd).should == :cat + '@cat'.send(cmd).should == :@cat + + 'cat and dog'.send(cmd).should == :"cat and dog" + end + + it "raises an ArgumentError when self can't be converted to symbol" do + lambda { "".send(cmd) }.should raise_error(ArgumentError) + lambda { "foo\x00bar".send(cmd) }.should raise_error(ArgumentError) + end + end +end \ No newline at end of file diff --git a/1.8/core/string/size_spec.rb b/1.8/core/string/size_spec.rb new file mode 100644 index 0000000000..b169ff97b9 --- /dev/null +++ b/1.8/core/string/size_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/length' + +describe "String#size" do + it_behaves_like(:string_length, :size) +end \ No newline at end of file diff --git a/1.8/core/string/slice_spec.rb b/1.8/core/string/slice_spec.rb new file mode 100644 index 0000000000..a7005e9fa0 --- /dev/null +++ b/1.8/core/string/slice_spec.rb @@ -0,0 +1,418 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/slice.rb' + +describe "String#slice" do + it_behaves_like(:string_slice, :slice) +end + +describe "String#slice! with index" do + it "deletes and return the char at the given position" do + a = "hello" + a.slice!(1).should == ?e + a.should == "hllo" + a.slice!(-1).should == ?o + a.should == "hll" + end + + it "returns nil if idx is outside of self" do + a = "hello" + a.slice!(20).should == nil + a.should == "hello" + a.slice!(-20).should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + lambda { "hello".freeze.slice!(1) }.should raise_error(TypeError) + end + + it "doesn't raise a TypeError if self is frozen and idx is outside of self" do + "hello".freeze.slice!(10) + "".freeze.slice!(0) + end + end + + it "calls to_int on index" do + "hello".slice!(0.5).should == ?h + + obj = mock('1') + # MRI calls this twice so we can't use should_receive here. + def obj.to_int() 1 end + "hello".slice!(obj).should == ?e + + obj = mock('1') + def obj.respond_to?(name) name == :to_int ? true : super; end + def obj.method_missing(name, *) name == :to_int ? 1 : super; end + "hello".slice!(obj).should == ?e + end +end + +describe "String#slice! with index, length" do + it "deletes and returns the substring at idx and the given length" do + a = "hello" + a.slice!(1, 2).should == "el" + a.should == "hlo" + + a.slice!(1, 0).should == "" + a.should == "hlo" + + a.slice!(-2, 4).should == "lo" + a.should == "h" + end + + it "always taints resulting strings when self is tainted" do + str = "hello world" + str.taint + + str.slice!(0, 0).tainted?.should == true + str.slice!(2, 1).tainted?.should == true + end + + it "returns nil if the given position is out of self" do + a = "hello" + a.slice(10, 3).should == nil + a.should == "hello" + + a.slice(-10, 20).should == nil + a.should == "hello" + end + + it "returns nil if the length is negative" do + a = "hello" + a.slice(4, -3).should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + lambda { "hello".freeze.slice!(1, 2) }.should raise_error(TypeError) + end + + it "doesn't raise a TypeError if self is frozen but the given position is out of self" do + "hello".freeze.slice!(10, 3) + "hello".freeze.slice!(-10, 3) + end + + it "doesn't raise a TypeError if self is frozen but length is negative" do + "hello".freeze.slice!(4, -3) + end + end + + it "calls to_int on idx and length" do + "hello".slice!(0.5, 2.5).should == "he" + + obj = mock('2') + def obj.to_int() 2 end + "hello".slice!(obj, obj).should == "ll" + + obj = mock('2') + def obj.respond_to?(name) name == :to_int; end + def obj.method_missing(name, *) name == :to_int ? 2 : super; end + "hello".slice!(obj, obj).should == "ll" + end + + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0, 0).class.should == StringSpecs::MyString + s.slice!(0, 4).class.should == StringSpecs::MyString + end +end + +describe "String#slice! Range" do + it "deletes and return the substring given by the offsets of the range" do + a = "hello" + a.slice!(1..3).should == "ell" + a.should == "ho" + a.slice!(0..0).should == "h" + a.should == "o" + a.slice!(0...0).should == "" + a.should == "o" + + # Edge Case? + "hello".slice!(-3..-9).should == "" + end + + it "returns nil if the given range is out of self" do + a = "hello" + a.slice!(-6..-9).should == nil + a.should == "hello" + + b = "hello" + b.slice!(10..20).should == nil + b.should == "hello" + end + + it "always taints resulting strings when self is tainted" do + str = "hello world" + str.taint + + str.slice!(0..0).tainted?.should == true + str.slice!(2..3).tainted?.should == true + end + + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0...0).class.should == StringSpecs::MyString + s.slice!(0..4).class.should == StringSpecs::MyString + end + + it "calls to_int on range arguments" do + from = mock('from') + to = mock('to') + + # So we can construct a range out of them... + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + def from.to_int() 1 end + def to.to_int() -2 end + + "hello there".slice!(from..to).should == "ello ther" + + from = mock('from') + to = mock('to') + + def from.<=>(o) 0 end + def to.<=>(o) 0 end + + def from.respond_to?(name) name == :to_int; end + def from.method_missing(name) name == :to_int ? 1 : super; end + def to.respond_to?(name) name == :to_int; end + def to.method_missing(name) name == :to_int ? -2 : super; end + + "hello there".slice!(from..to).should == "ello ther" + end + + it "works with Range subclasses" do + a = "GOOD" + range_incl = StringSpecs::MyRange.new(1, 2) + + a.slice!(range_incl).should == "OO" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + lambda { "hello".freeze.slice!(1..3) }.should raise_error(TypeError) + end + + it "doesn't raise a TypeError if self is frozen but the given range is out of self" do + "hello".freeze.slice!(10..20).should == nil + end + end +end + +describe "String#slice! with Regexp" do + it "deletes and returns the first match from self" do + s = "this is a string" + s.slice!(/s.*t/).should == 's is a st' + s.should == 'thiring' + + c = "hello hello" + c.slice!(/llo/).should == "llo" + c.should == "he hello" + end + + it "returns nil if there was no match" do + s = "this is a string" + s.slice!(/zzz/).should == nil + s.should == "this is a string" + end + + it "always taints resulting strings when self or regexp is tainted" do + strs = ["hello world"] + strs += strs.map { |s| s.dup.taint } + + strs.each do |str| + str = str.dup + str.slice!(//).tainted?.should == str.tainted? + str.slice!(/hello/).tainted?.should == str.tainted? + + tainted_re = /./ + tainted_re.taint + + str.slice!(tainted_re).tainted?.should == true + end + end + + it "doesn't taint self when regexp is tainted" do + s = "hello" + s.slice!(/./.taint) + s.tainted?.should == false + end + + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(//).class.should == StringSpecs::MyString + s.slice!(/../).class.should == StringSpecs::MyString + end + + # This currently fails, but passes in a pure Rubinius environment (without mspec) + # probably because mspec uses match internally for its operation + it "sets $~ to MatchData when there is a match and nil when there's none" do + 'hello'.slice!(/./) + $~[0].should == 'h' + + 'hello'.slice!(/not/) + $~.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + lambda { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(TypeError) + end + + it "doesn't raise a TypeError if self is frozen but there is no match" do + "this is a string".freeze.slice!(/zzz/).should == nil + end + end +end + +describe "String#slice! with Regexp, index" do + it "deletes and returns the capture for idx from self" do + str = "hello there" + str.slice!(/[aeiou](.)\1/, 0).should == "ell" + str.should == "ho there" + str.slice!(/(t)h/, 1).should == "t" + str.should == "ho here" + end + + it "always taints resulting strings when self or regexp is tainted" do + strs = ["hello world"] + strs += strs.map { |s| s.dup.taint } + + strs.each do |str| + str = str.dup + str.slice!(//, 0).tainted?.should == str.tainted? + str.slice!(/hello/, 0).tainted?.should == str.tainted? + + tainted_re = /(.)(.)(.)/ + tainted_re.taint + + str.slice!(tainted_re, 1).tainted?.should == true + end + end + + it "doesn't taint self when regexp is tainted" do + s = "hello" + s.slice!(/(.)(.)/.taint, 1) + s.tainted?.should == false + end + + it "returns nil if there was no match" do + s = "this is a string" + s.slice!(/x(zzz)/, 1).should == nil + s.should == "this is a string" + end + + it "returns nil if there is no capture for idx" do + "hello there".slice!(/[aeiou](.)\1/, 2).should == nil + # You can't refer to 0 using negative indices + "hello there".slice!(/[aeiou](.)\1/, -2).should == nil + end + + it "calls to_int on idx" do + obj = mock('2') + def obj.to_int() 2 end + + "har".slice!(/(.)(.)(.)/, 1.5).should == "h" + "har".slice!(/(.)(.)(.)/, obj).should == "a" + + obj = mock('2') + def obj.respond_to?(name) name == :to_int; end + def obj.method_missing(name) name == :to_int ? 2: super; end + "har".slice!(/(.)(.)(.)/, obj).should == "a" + end + + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(/(.)(.)/, 0).class.should == StringSpecs::MyString + s.slice!(/(.)(.)/, 1).class.should == StringSpecs::MyString + end + + it "sets $~ to MatchData when there is a match and nil when there's none" do + 'hello'[/.(.)/, 0] + $~[0].should == 'he' + + 'hello'[/.(.)/, 1] + $~[1].should == 'e' + + 'hello'[/not/, 0] + $~.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + lambda { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(TypeError) + end + + it "doesn't raise a TypeError if self is frozen but there is no match" do + "this is a string".freeze.slice!(/zzz/, 0).should == nil + end + + it "doesn't raise a TypeError if self is frozen but there is no capture for idx" do + "this is a string".freeze.slice!(/(.)/, 2).should == nil + end + end +end + +describe "String#slice! with String" do + it "removes and returns the first occurrence of other_str from self" do + c = "hello hello" + c.slice!('llo').should == "llo" + c.should == "he hello" + end + + it "taints resulting strings when other is tainted" do + strs = ["", "hello world", "hello"] + strs += strs.map { |s| s.dup.taint } + + strs.each do |str| + str = str.dup + strs.each do |other| + other = other.dup + r = str.slice!(other) + + r.tainted?.should == !r.nil? & other.tainted? + end + end + end + + it "doesn't set $~" do + $~ = nil + + 'hello'.slice!('ll') + $~.should == nil + end + + it "returns nil if self does not contain other" do + a = "hello" + a.slice!('zzz').should == nil + a.should == "hello" + end + + it "doesn't call to_str on its argument" do + o = mock('x') + o.should_not_receive(:to_str) + + lambda { "hello".slice!(o) }.should raise_error(TypeError) + end + + it "returns a subclass instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".slice!(s) + r.should == "el" + r.class.should == StringSpecs::MyString + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + lambda { "hello hello".freeze.slice!('llo') }.should raise_error(TypeError) + end + + it "doesn't raise a TypeError if self is frozen but self does not contain other" do + "this is a string".freeze.slice!('zzz').should == nil + end + end +end diff --git a/1.8/core/string/split_spec.rb b/1.8/core/string/split_spec.rb new file mode 100644 index 0000000000..a87d5c1da6 --- /dev/null +++ b/1.8/core/string/split_spec.rb @@ -0,0 +1,290 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#split with String" do + it "returns an array of substrings based on splitting on the given string" do + "mellow yellow".split("ello").should == ["m", "w y", "w"] + end + + it "suppresses trailing empty fields when limit isn't given or 0" do + "1,2,,3,4,,".split(',').should == ["1", "2", "", "3", "4"] + "1,2,,3,4,,".split(',', 0).should == ["1", "2", "", "3", "4"] + " a b c\nd ".split(" ").should == ["", "a", "b", "c\nd"] + "hai".split("hai").should == [] + ",".split(",").should == [] + ",".split(",", 0).should == [] + end + + it "returns an array with one entry if limit is 1: the original string" do + "hai".split("hai", 1).should == ["hai"] + "x.y.z".split(".", 1).should == ["x.y.z"] + "hello world ".split(" ", 1).should == ["hello world "] + "hi!".split("", 1).should == ["hi!"] + end + + it "returns at most limit fields when limit > 1" do + "hai".split("hai", 2).should == ["", ""] + + "1,2,,3,4,,".split(',', 2).should == ["1", "2,,3,4,,"] + "1,2,,3,4,,".split(',', 3).should == ["1", "2", ",3,4,,"] + "1,2,,3,4,,".split(',', 4).should == ["1", "2", "", "3,4,,"] + "1,2,,3,4,,".split(',', 5).should == ["1", "2", "", "3", "4,,"] + "1,2,,3,4,,".split(',', 6).should == ["1", "2", "", "3", "4", ","] + + "x".split('x', 2).should == ["", ""] + "xx".split('x', 2).should == ["", "x"] + "xx".split('x', 3).should == ["", "", ""] + "xxx".split('x', 2).should == ["", "xx"] + "xxx".split('x', 3).should == ["", "", "x"] + "xxx".split('x', 4).should == ["", "", "", ""] + end + + it "doesn't suppress or limit fields when limit is negative" do + "1,2,,3,4,,".split(',', -1).should == ["1", "2", "", "3", "4", "", ""] + "1,2,,3,4,,".split(',', -5).should == ["1", "2", "", "3", "4", "", ""] + " a b c\nd ".split(" ", -1).should == ["", "a", "b", "c\nd", ""] + ",".split(",", -1).should == ["", ""] + end + + it "defaults to $; when string isn't given or nil" do + begin + old_fs = $; + + [",", ":", "", "XY", nil].each do |fs| + $; = fs + + ["x,y,z,,,", "1:2:", "aXYbXYcXY", ""].each do |str| + expected = str.split(fs || " ") + + str.split(nil).should == expected + str.split.should == expected + + str.split(nil, -1).should == str.split(fs || " ", -1) + str.split(nil, 0).should == str.split(fs || " ", 0) + str.split(nil, 2).should == str.split(fs || " ", 2) + end + end + ensure + $; = old_fs + end + end + + it "ignores leading and continuous whitespace when string is a single space" do + " now's the time ".split(' ').should == ["now's", "the", "time"] + " now's the time ".split(' ', -1).should == ["now's", "the", "time", ""] + + "\t\n a\t\tb \n\r\r\nc\v\vd\v ".split(' ').should == ["a", "b", "c", "d"] + "a\x00a b".split(' ').should == ["a\x00a", "b"] + end + + it "splits between characters when its argument is an empty string" do + "hi!".split("").should == ["h", "i", "!"] + "hi!".split("", -1).should == ["h", "i", "!", ""] + "hi!".split("", 2).should == ["h", "i!"] + end + + it "tries converting its pattern argument to a string via to_str" do + obj = mock('::') + def obj.to_str() "::" end + "hello::world".split(obj).should == ["hello", "world"] + + obj = mock('::') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("::") + "hello::world".split(obj).should == ["hello", "world"] + end + + it "tries converting limit to an integer via to_int" do + obj = mock('2') + def obj.to_int() 2 end + "1.2.3.4".split(".", obj).should == ["1", "2.3.4"] + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_int).and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(2) + "1.2.3.4".split(".", obj).should == ["1", "2.3.4"] + end + + it "doesn't set $~" do + $~ = nil + "x.y.z".split(".") + $~.should == nil + end + + it "returns subclass instances based on self" do + ["", "x.y.z.", " x y "].each do |str| + ["", ".", " "].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.class.should == StringSpecs::MyString + end + + str.split(StringSpecs::MyString.new(pat), limit).each do |x| + x.class.should == String + end + end + end + end + end + + it "taints the resulting strings if self is tainted" do + ["", "x.y.z.", " x y "].each do |str| + ["", ".", " "].each do |pat| + [-1, 0, 1, 2].each do |limit| + str.dup.taint.split(pat).each do |x| + x.tainted?.should == true + end + + str.split(pat.dup.taint).each do |x| + x.tainted?.should == false + end + end + end + end + end +end + +describe "String#split with Regexp" do + it "divides self on regexp matches" do + " now's the time".split(/ /).should == ["", "now's", "", "the", "time"] + " x\ny ".split(/ /).should == ["", "x\ny"] + "1, 2.34,56, 7".split(/,\s*/).should == ["1", "2.34", "56", "7"] + "1x2X3".split(/x/i).should == ["1", "2", "3"] + end + + it "treats negative limits as no limit" do + "".split(%r!/+!, -1).should == [] + end + + it "suppresses trailing empty fields when limit isn't given or 0" do + "1,2,,3,4,,".split(/,/).should == ["1", "2", "", "3", "4"] + "1,2,,3,4,,".split(/,/, 0).should == ["1", "2", "", "3", "4"] + " a b c\nd ".split(/\s+/).should == ["", "a", "b", "c", "d"] + "hai".split(/hai/).should == [] + ",".split(/,/).should == [] + ",".split(/,/, 0).should == [] + end + + it "returns an array with one entry if limit is 1: the original string" do + "hai".split(/hai/, 1).should == ["hai"] + "xAyBzC".split(/[A-Z]/, 1).should == ["xAyBzC"] + "hello world ".split(/\s+/, 1).should == ["hello world "] + "hi!".split(//, 1).should == ["hi!"] + end + + it "returns at most limit fields when limit > 1" do + "hai".split(/hai/, 2).should == ["", ""] + + "1,2,,3,4,,".split(/,/, 2).should == ["1", "2,,3,4,,"] + "1,2,,3,4,,".split(/,/, 3).should == ["1", "2", ",3,4,,"] + "1,2,,3,4,,".split(/,/, 4).should == ["1", "2", "", "3,4,,"] + "1,2,,3,4,,".split(/,/, 5).should == ["1", "2", "", "3", "4,,"] + "1,2,,3,4,,".split(/,/, 6).should == ["1", "2", "", "3", "4", ","] + + "x".split(/x/, 2).should == ["", ""] + "xx".split(/x/, 2).should == ["", "x"] + "xx".split(/x/, 3).should == ["", "", ""] + "xxx".split(/x/, 2).should == ["", "xx"] + "xxx".split(/x/, 3).should == ["", "", "x"] + "xxx".split(/x/, 4).should == ["", "", "", ""] + end + + it "doesn't suppress or limit fields when limit is negative" do + "1,2,,3,4,,".split(/,/, -1).should == ["1", "2", "", "3", "4", "", ""] + "1,2,,3,4,,".split(/,/, -5).should == ["1", "2", "", "3", "4", "", ""] + " a b c\nd ".split(/\s+/, -1).should == ["", "a", "b", "c", "d", ""] + ",".split(/,/, -1).should == ["", ""] + end + + it "defaults to $; when regexp isn't given or nil" do + begin + old_fs = $; + + [/,/, /:/, //, /XY/, /./].each do |fs| + $; = fs + + ["x,y,z,,,", "1:2:", "aXYbXYcXY", ""].each do |str| + expected = str.split(fs) + + str.split(nil).should == expected + str.split.should == expected + + str.split(nil, -1).should == str.split(fs, -1) + str.split(nil, 0).should == str.split(fs, 0) + str.split(nil, 2).should == str.split(fs, 2) + end + end + ensure + $; = old_fs + end + end + + it "splits between characters when regexp matches a zero-length string" do + "hello".split(//).should == ["h", "e", "l", "l", "o"] + "hello".split(//, -1).should == ["h", "e", "l", "l", "o", ""] + "hello".split(//, 2).should == ["h", "ello"] + + "hi mom".split(/\s*/).should == ["h", "i", "m", "o", "m"] + end + + it "includes all captures in the result array" do + "hello".split(/(el)/).should == ["h", "el", "lo"] + "hi!".split(/()/).should == ["h", "", "i", "", "!"] + "hi!".split(/()/, -1).should == ["h", "", "i", "", "!", "", ""] + "hello".split(/((el))()/).should == ["h", "el", "el", "", "lo"] + "AabB".split(/([a-z])+/).should == ["A", "b", "B"] + end + + it "does not include non-matching captures in the result array" do + "hello".split(/(el)|(xx)/).should == ["h", "el", "lo"] + end + + it "tries converting limit to an integer via to_int" do + obj = mock('2') + def obj.to_int() 2 end + "1.2.3.4".split(".", obj).should == ["1", "2.3.4"] + + obj = mock('2') + obj.should_receive(:respond_to?).with(:to_int).and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(2) + "1.2.3.4".split(".", obj).should == ["1", "2.3.4"] + end + + it "doesn't set $~" do + $~ = nil + "x:y:z".split(/:/) + $~.should == nil + end + + it "returns the original string if no matches are found" do + "foo".split("\n").should == ["foo"] + end + + it "returns subclass instances based on self" do + ["", "x:y:z:", " x y "].each do |str| + [//, /:/, /\s+/].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.class.should == StringSpecs::MyString + end + end + end + end + end + + it "taints the resulting strings if self is tainted" do + ["", "x:y:z:", " x y "].each do |str| + [//, /:/, /\s+/].each do |pat| + [-1, 0, 1, 2].each do |limit| + str.dup.taint.split(pat).each do |x| + x.tainted?.should == true + end + + str.split(pat.dup.taint).each do |x| + x.tainted?.should == false + end + end + end + end + end +end diff --git a/1.8/core/string/squeeze_spec.rb b/1.8/core/string/squeeze_spec.rb new file mode 100644 index 0000000000..20fcf82dcd --- /dev/null +++ b/1.8/core/string/squeeze_spec.rb @@ -0,0 +1,107 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#squeeze" do + it "returns new string where runs of the same character are replaced by a single character when no args are given" do + "yellow moon".squeeze.should == "yelow mon" + end + + it "only squeezes chars that are in the intersection of all sets given" do + "woot squeeze cheese".squeeze("eost", "queo").should == "wot squeze chese" + " now is the".squeeze(" ").should == " now is the" + end + + it "negates sets starting with ^" do + s = "<>" + s.squeeze("beko", "^e").should == s.squeeze("bko") + s.squeeze("^").should == s.squeeze("o") + s.squeeze("^o").should == s.squeeze("") + s.squeeze("^").should == s + "^__^".squeeze("^^").should == "^_^" + "((^^__^^))".squeeze("_^").should == "((^_^))" + end + + it "squeezes all chars in a sequence" do + s = "--subbookkeeper--" + s.squeeze("\x00-\xFF").should == s.squeeze + s.squeeze("bk-o").should == s.squeeze("bklmno") + s.squeeze("b-e").should == s.squeeze("bcde") + s.squeeze("e-").should == "-subbookkeper-" + s.squeeze("-e").should == "-subbookkeper-" + s.squeeze("---").should == "-subbookkeeper-" + "ook--001122".squeeze("--2").should == "ook-012" + "ook--(())".squeeze("(--").should == "ook-()" + s.squeeze("e-b").should == s + s.squeeze("^e-b").should == s.squeeze + s.squeeze("^b-e").should == "-subbokeeper-" + "^^__^^".squeeze("^^-^").should == "^^_^^" + "^^--^^".squeeze("^---").should == "^--^" + + s.squeeze("b-dk-o-").should == "-subokeeper-" + s.squeeze("-b-dk-o").should == "-subokeeper-" + s.squeeze("b-d-k-o").should == "-subokeeper-" + + s.squeeze("bc-e").should == "--subookkeper--" + s.squeeze("^bc-e").should == "-subbokeeper-" + + "AABBCCaabbcc[[]]".squeeze("A-a").should == "ABCabbcc[]" + end + + it "taints the result when self is tainted" do + "hello".taint.squeeze("e").tainted?.should == true + "hello".taint.squeeze("a-z").tainted?.should == true + + "hello".squeeze("e".taint).tainted?.should == false + "hello".squeeze("l".taint).tainted?.should == false + end + + it "tries to convert each set arg to a string using to_str" do + other_string = mock('lo') + def other_string.to_str() "lo" end + + other_string2 = mock('o') + def other_string2.to_str() "o" end + + "hello room".squeeze(other_string, other_string2).should == "hello rom" + + obj = mock('o') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("o") + "hello room".squeeze(obj).should == "hello rom" + end + + it "raises a TypeError when one set arg can't be converted to a string" do + lambda { "hello world".squeeze(?o) }.should raise_error(TypeError) + lambda { "hello world".squeeze(:o) }.should raise_error(TypeError) + lambda { "hello world".squeeze(mock('x')) }.should raise_error(TypeError) + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").squeeze("!").class.should == StringSpecs::MyString + end +end + +describe "String#squeeze!" do + it "modifies self in place and returns self" do + a = "yellow moon" + a.squeeze!.equal?(a).should == true + a.should == "yelow mon" + end + + it "returns nil if no modifications were made" do + a = "squeeze" + a.squeeze!("u", "sq").should == nil + a.squeeze!("q").should == nil + a.should == "squeeze" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + a = "yellow moon" + a.freeze + + lambda { a.squeeze!("") }.should raise_error(TypeError) + lambda { a.squeeze! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/strip_spec.rb b/1.8/core/string/strip_spec.rb new file mode 100644 index 0000000000..7335b2a9c1 --- /dev/null +++ b/1.8/core/string/strip_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#strip" do + it "returns a new string with leading and trailing whitespace removed" do + " hello ".strip.should == "hello" + " hello world ".strip.should == "hello world" + "\tgoodbye\r\v\n".strip.should == "goodbye" + " goodbye \000".strip.should == "goodbye" + end + + it "taints the result when self is tainted" do + "".taint.strip.tainted?.should == true + "ok".taint.strip.tainted?.should == true + " ok ".taint.strip.tainted?.should == true + end +end + +describe "String#strip!" do + it "modifies self in place and returns self" do + a = " hello " + a.strip!.equal?(a).should == true + a.should == "hello" + end + + it "returns nil if no modifications where made" do + a = "hello" + a.strip!.should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + "hello".freeze.strip! # ok, nothing changed + "".freeze.strip! # ok, nothing changed + + lambda { " hello ".freeze.strip! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/sub_spec.rb b/1.8/core/string/sub_spec.rb new file mode 100644 index 0000000000..7217c96335 --- /dev/null +++ b/1.8/core/string/sub_spec.rb @@ -0,0 +1,384 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/sub.rb' + +describe "String#sub with pattern, replacement" do + it "returns a copy of self with all occurrences of pattern replaced with replacement" do + "hello".sub(/[aeiou]/, '*').should == "h*llo" + "hello".sub(//, ".").should == ".hello" + end + + it "ignores a block if supplied" do + "food".sub(/f/, "g") { "w" }.should == "good" + end + + it "supports \\G which matches at the beginning of the string" do + "hello world!".sub(/\Ghello/, "hi").should == "hi world!" + end + + it "supports /i for ignoring case" do + "Hello".sub(/h/i, "j").should == "jello" + "hello".sub(/H/i, "j").should == "jello" + end + + it "doesn't interpret regexp metacharacters if pattern is a string" do + "12345".sub('\d', 'a').should == "12345" + '\d'.sub('\d', 'a').should == "a" + end + + it "replaces \\1 sequences with the regexp's corresponding capture" do + str = "hello" + + str.sub(/([aeiou])/, '<\1>').should == "hllo" + str.sub(/(.)/, '\1\1').should == "hhello" + + str.sub(/.(.?)/, '<\0>(\1)').should == "(e)llo" + + str.sub(/.(.)+/, '\1').should == "o" + + str = "ABCDEFGHIJKL" + re = /#{"(.)" * 12}/ + str.sub(re, '\1').should == "A" + str.sub(re, '\9').should == "I" + # Only the first 9 captures can be accessed in MRI + str.sub(re, '\10').should == "A0" + end + + it "treats \\1 sequences without corresponding captures as empty strings" do + str = "hello!" + + str.sub("", '<\1>').should == "<>hello!" + str.sub("h", '<\1>').should == "<>ello!" + + str.sub(//, '<\1>').should == "<>hello!" + str.sub(/./, '\1\2\3').should == "ello!" + str.sub(/.(.{20})?/, '\1').should == "ello!" + end + + it "replaces \\& and \\0 with the complete match" do + str = "hello!" + + str.sub("", '<\0>').should == "<>hello!" + str.sub("", '<\&>').should == "<>hello!" + str.sub("he", '<\0>').should == "llo!" + str.sub("he", '<\&>').should == "llo!" + str.sub("l", '<\0>').should == "helo!" + str.sub("l", '<\&>').should == "helo!" + + str.sub(//, '<\0>').should == "<>hello!" + str.sub(//, '<\&>').should == "<>hello!" + str.sub(/../, '<\0>').should == "llo!" + str.sub(/../, '<\&>').should == "llo!" + str.sub(/(.)./, '<\0>').should == "llo!" + end + + it "replaces \\` with everything before the current match" do + str = "hello!" + + str.sub("", '<\`>').should == "<>hello!" + str.sub("h", '<\`>').should == "<>ello!" + str.sub("l", '<\`>').should == "helo!" + str.sub("!", '<\`>').should == "hello" + + str.sub(//, '<\`>').should == "<>hello!" + str.sub(/..o/, '<\`>').should == "he!" + end + + it "replaces \\' with everything after the current match" do + str = "hello!" + + str.sub("", '<\\\'>').should == "hello!" + str.sub("h", '<\\\'>').should == "ello!" + str.sub("ll", '<\\\'>').should == "heo!" + str.sub("!", '<\\\'>').should == "hello<>" + + str.sub(//, '<\\\'>').should == "hello!" + str.sub(/../, '<\\\'>').should == "llo!" + end + + it "replaces \\\\\\+ with \\\\+" do + "x".sub(/x/, '\\\+').should == "\\+" + end + + it "replaces \\+ with the last paren that actually matched" do + str = "hello!" + + str.sub(/(.)(.)/, '\+').should == "ello!" + str.sub(/(.)(.)+/, '\+').should == "!" + str.sub(/(.)()/, '\+').should == "ello!" + str.sub(/(.)(.{20})?/, '<\+>').should == "ello!" + + str = "ABCDEFGHIJKL" + re = /#{"(.)" * 12}/ + str.sub(re, '\+').should == "L" + end + + it "treats \\+ as an empty string if there was no captures" do + "hello!".sub(/./, '\+').should == "ello!" + end + + it "maps \\\\ in replacement to \\" do + "hello".sub(/./, '\\\\').should == '\\ello' + end + + it "leaves unknown \\x escapes in replacement untouched" do + "hello".sub(/./, '\\x').should == '\\xello' + "hello".sub(/./, '\\y').should == '\\yello' + end + + it "leaves \\ at the end of replacement untouched" do + "hello".sub(/./, 'hah\\').should == 'hah\\ello' + end + + it "taints the result if the original string or replacement is tainted" do + hello = "hello" + hello_t = "hello" + a = "a" + a_t = "a" + empty = "" + empty_t = "" + + hello_t.taint; a_t.taint; empty_t.taint + + hello_t.sub(/./, a).tainted?.should == true + hello_t.sub(/./, empty).tainted?.should == true + + hello.sub(/./, a_t).tainted?.should == true + hello.sub(/./, empty_t).tainted?.should == true + hello.sub(//, empty_t).tainted?.should == true + + hello.sub(//.taint, "foo").tainted?.should == false + end + + it "tries to convert pattern to a string using to_str" do + pattern = mock('.') + def pattern.to_str() "." end + + "hello.".sub(pattern, "!").should == "hello!" + + obj = mock('.') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return(".") + + "hello.".sub(obj, "!").should == "hello!" + end + + it "raises a TypeError when pattern can't be converted to a string" do + lambda { "hello".sub(:woot, "x") }.should raise_error(TypeError) + lambda { "hello".sub(?e, "x") }.should raise_error(TypeError) + end + + it "tries to convert replacement to a string using to_str" do + replacement = mock('hello_replacement') + def replacement.to_str() "hello_replacement" end + + "hello".sub(/hello/, replacement).should == "hello_replacement" + + obj = mock('ok') + obj.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_str).and_return("ok") + "hello".sub(/hello/, obj).should == "ok" + end + + it "raises a TypeError when replacement can't be converted to a string" do + lambda { "hello".sub(/[aeiou]/, :woot) }.should raise_error(TypeError) + lambda { "hello".sub(/[aeiou]/, ?f) }.should raise_error(TypeError) + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").sub(//, "").class.should == StringSpecs::MyString + StringSpecs::MyString.new("").sub(/foo/, "").class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").sub(/foo/, "").class.should == StringSpecs::MyString + StringSpecs::MyString.new("foo").sub("foo", "").class.should == StringSpecs::MyString + end + + it "sets $~ to MatchData of match and nil when there's none" do + 'hello.'.sub('hello', 'x') + $~[0].should == 'hello' + + 'hello.'.sub('not', 'x') + $~.should == nil + + 'hello.'.sub(/.(.)/, 'x') + $~[0].should == 'he' + + 'hello.'.sub(/not/, 'x') + $~.should == nil + end + + it 'replaces \\\1 with \1' do + "ababa".sub(/(b)/, '\\\1').should == "a\\1aba" + end + + it 'replaces \\\\1 with \\1' do + "ababa".sub(/(b)/, '\\\\1').should == "a\\1aba" + end + + it 'replaces \\\\\1 with \\' do + "ababa".sub(/(b)/, '\\\\\1').should == "a\\baba" + end + +end + +describe "String#sub with pattern and block" do + it "returns a copy of self with the first occurrences of pattern replaced with the block's return value" do + "hi".sub(/./) { |s| s[0].to_s + ' ' }.should == "104 i" + "hi!".sub(/(.)(.)/) { |*a| a.inspect }.should == '["hi"]!' + end + + it "sets $~ for access from the block" do + str = "hello" + str.sub(/([aeiou])/) { "<#{$~[1]}>" }.should == "hllo" + str.sub(/([aeiou])/) { "<#{$1}>" }.should == "hllo" + str.sub("l") { "<#{$~[0]}>" }.should == "helo" + + offsets = [] + + str.sub(/([aeiou])/) do + md = $~ + md.string.should == str + offsets << md.offset(0) + str + end.should == "hhellollo" + + offsets.should == [[1, 2]] + end + + it "restores $~ after leaving the block" do + [/./, "l"].each do |pattern| + old_md = nil + "hello".sub(pattern) do + old_md = $~ + "ok".match(/./) + "x" + end + + $~.should == old_md + $~.string.should == "hello" + end + end + + it "sets $~ to MatchData of last match and nil when there's none for access from outside" do + 'hello.'.sub('l') { 'x' } + $~.begin(0).should == 2 + $~[0].should == 'l' + + 'hello.'.sub('not') { 'x' } + $~.should == nil + + 'hello.'.sub(/.(.)/) { 'x' } + $~[0].should == 'he' + + 'hello.'.sub(/not/) { 'x' } + $~.should == nil + end + + it "doesn't raise a RuntimeError if the string is modified while substituting" do + str = "hello" + str.sub(//) { str[0] = 'x' }.should == "xhello" + str.should == "xello" + end + + it "doesn't interpolate special sequences like \\1 for the block's return value" do + repl = '\& \0 \1 \` \\\' \+ \\\\ foo' + "hello".sub(/(.+)/) { repl }.should == repl + end + + it "converts the block's return value to a string using to_s" do + obj = mock('hello_replacement') + obj.should_receive(:to_s).and_return("hello_replacement") + "hello".sub(/hello/) { obj }.should == "hello_replacement" + + obj = mock('ok') + obj.should_receive(:to_s).and_return("ok") + "hello".sub(/.+/) { obj }.should == "ok" + end + + it "taints the result if the original string or replacement is tainted" do + hello = "hello" + hello_t = "hello" + a = "a" + a_t = "a" + empty = "" + empty_t = "" + + hello_t.taint; a_t.taint; empty_t.taint + + hello_t.sub(/./) { a }.tainted?.should == true + hello_t.sub(/./) { empty }.tainted?.should == true + + hello.sub(/./) { a_t }.tainted?.should == true + hello.sub(/./) { empty_t }.tainted?.should == true + hello.sub(//) { empty_t }.tainted?.should == true + + hello.sub(//.taint) { "foo" }.tainted?.should == false + end +end + +describe "String#sub! with pattern, replacement" do + it "modifies self in place and returns self" do + a = "hello" + a.sub!(/[aeiou]/, '*').equal?(a).should == true + a.should == "h*llo" + end + + it "taints self if replacement is tainted" do + a = "hello" + a.sub!(/./.taint, "foo").tainted?.should == false + a.sub!(/./, "foo".taint).tainted?.should == true + end + + it "returns nil if no modifications were made" do + a = "hello" + a.sub!(/z/, '*').should == nil + a.sub!(/z/, 'z').should == nil + a.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + s = "hello" + s.freeze + + s.sub!(/ROAR/, "x") # ok + lambda { s.sub!(/e/, "e") }.should raise_error(TypeError) + lambda { s.sub!(/[aeiou]/, '*') }.should raise_error(TypeError) + end + end +end + +describe "String#sub! with pattern and block" do + it "modifies self in place and returns self" do + a = "hello" + a.sub!(/[aeiou]/) { '*' }.equal?(a).should == true + a.should == "h*llo" + end + + it "taints self if block's result is tainted" do + a = "hello" + a.sub!(/./.taint) { "foo" }.tainted?.should == false + a.sub!(/./) { "foo".taint }.tainted?.should == true + end + + it "returns nil if no modifications were made" do + a = "hello" + a.sub!(/z/) { '*' }.should == nil + a.sub!(/z/) { 'z' }.should == nil + a.should == "hello" + end + + not_compliant_on :rubinius do + it "raises a RuntimeError if the string is modified while substituting" do + str = "hello" + lambda { str.sub!(//) { str << 'x' } }.should raise_error(RuntimeError) + end + end + + compliant_on :jruby do + it_behaves_like(:string_sub_bang_frozen_raises, RuntimeError) + end + + compliant_on :ruby do + it_behaves_like(:string_sub_bang_frozen_raises, RuntimeError) + end +end diff --git a/1.8/core/string/succ_spec.rb b/1.8/core/string/succ_spec.rb new file mode 100644 index 0000000000..5b3f640760 --- /dev/null +++ b/1.8/core/string/succ_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/succ.rb' + +describe "String#succ" do + it_behaves_like(:string_succ, :succ) +end + +describe "String#succ!" do + it_behaves_like(:string_succ_bang, :"succ!") +end \ No newline at end of file diff --git a/1.8/core/string/sum_spec.rb b/1.8/core/string/sum_spec.rb new file mode 100644 index 0000000000..bc3982c7b0 --- /dev/null +++ b/1.8/core/string/sum_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#sum" do + it "returns a basic n-bit checksum of the characters in self" do + "ruby".sum.should == 450 + "ruby".sum(8).should == 194 + "rubinius".sum(23).should == 881 + end + + it "tries to convert n to an integer using to_int" do + obj = mock('8') + def obj.to_int() 8 end + + "hello".sum(obj).should == "hello".sum(obj.to_int) + + obj = mock('8') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(8) + + "hello".sum(obj).should == "hello".sum(8) + end +end diff --git a/1.8/core/string/swapcase_spec.rb b/1.8/core/string/swapcase_spec.rb new file mode 100644 index 0000000000..172daa8f7b --- /dev/null +++ b/1.8/core/string/swapcase_spec.rb @@ -0,0 +1,51 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#swapcase" do + it "returns a new string with all uppercase chars from self converted to lowercase and vice versa" do + "Hello".swapcase.should == "hELLO" + "cYbEr_PuNk11".swapcase.should == "CyBeR_pUnK11" + "+++---111222???".swapcase.should == "+++---111222???" + end + + it "taints resulting string when self is tainted" do + "".taint.swapcase.tainted?.should == true + "hello".taint.swapcase.tainted?.should == true + end + + it "is locale insensitive (only upcases a-z and only downcases A-Z)" do + "ÄÖÜ".swapcase.should == "ÄÖÜ" + "ärger".swapcase.should == "äRGER" + "BÄR".swapcase.should == "bÄr" + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").swapcase.class.should == StringSpecs::MyString + StringSpecs::MyString.new("hello").swapcase.class.should == StringSpecs::MyString + end +end + +describe "String#swapcase!" do + it "modifies self in place" do + a = "cYbEr_PuNk11" + a.swapcase!.equal?(a).should == true + a.should == "CyBeR_pUnK11" + end + + it "returns nil if no modifications were made" do + a = "+++---111222???" + a.swapcase!.should == nil + a.should == "+++---111222???" + + "".swapcase!.should == nil + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + ["", "hello"].each do |a| + a.freeze + lambda { a.swapcase! }.should raise_error(TypeError) + end + end + end +end diff --git a/1.8/core/string/to_a_spec.rb b/1.8/core/string/to_a_spec.rb new file mode 100644 index 0000000000..b384a80958 --- /dev/null +++ b/1.8/core/string/to_a_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_a' + +describe "String#to_a" do + it_behaves_like :string_to_a, :to_a +end diff --git a/1.8/core/string/to_f_spec.rb b/1.8/core/string/to_f_spec.rb new file mode 100644 index 0000000000..51bb8ec0d5 --- /dev/null +++ b/1.8/core/string/to_f_spec.rb @@ -0,0 +1,69 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +# src.scan(/[+-]?[\d_]+\.[\d_]+(e[+-]?[\d_]+)?\b|[+-]?[\d_]+e[+-]?[\d_]+\b/i) + +describe "String#to_f" do + it "treats leading characters of self as a floating point number" do + "123.45e1".to_f.should == 1234.5 + "45.67 degrees".to_f.should == 45.67 + "0".to_f.should == 0.0 + "123.45e1".to_f.should == 1234.5 + + ".5".to_f.should == 0.5 + ".5e1".to_f.should == 5.0 + + compliant_on(:ruby, :rubinius) do + "NaN".to_f.should == 0 + "Infinity".to_f.should == 0 + "-Infinity".to_f.should == 0 + end + + deviates_on(:jruby) do + "NaN".to_f.nan?.should == true + "Infinity".to_f.infinite?.should == 1 + "-Infinity".to_f.infinite?.should == -1 + end + end + + it "allows for varying case" do + "123.45e1".to_f.should == 1234.5 + "123.45E1".to_f.should == 1234.5 + end + + it "allows for varying signs" do + "+123.45e1".to_f.should == +123.45e1 + "-123.45e1".to_f.should == -123.45e1 + "123.45e+1".to_f.should == 123.45e+1 + "123.45e-1".to_f.should == 123.45e-1 + "+123.45e+1".to_f.should == +123.45e+1 + "+123.45e-1".to_f.should == +123.45e-1 + "-123.45e+1".to_f.should == -123.45e+1 + "-123.45e-1".to_f.should == -123.45e-1 + end + + it "allows for underscores, even in the decimal side" do + "1_234_567.890_1".to_f.should == 1_234_567.890_1 + end + + it "returns 0 for strings with any non-digit in them" do + "blah".to_f.should == 0 + "0b5".to_f.should == 0 + "0d5".to_f.should == 0 + "0o5".to_f.should == 0 + "0xx5".to_f.should == 0 + end + + it "takes an optional sign" do + "-45.67 degrees".to_f.should == -45.67 + "+45.67 degrees".to_f.should == 45.67 + "-5_5e-5_0".to_f.should == -55e-50 + "-".to_f.should == 0.0 + (1.0 / "-0".to_f).to_s.should == "-Infinity" + end + + it "returns 0.0 if the conversion fails" do + "bad".to_f.should == 0.0 + "thx1138".to_f.should == 0.0 + end +end diff --git a/1.8/core/string/to_i_spec.rb b/1.8/core/string/to_i_spec.rb new file mode 100644 index 0000000000..adff424ba0 --- /dev/null +++ b/1.8/core/string/to_i_spec.rb @@ -0,0 +1,124 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#to_i" do + it "ignores leading whitespaces" do + [ " 123", " 123", "\r\n\r\n123", "\t\t123", + "\r\n\t\n123", " \t\n\r\t 123"].each do |str| + str.to_i.should == 123 + end + end + + it "ignores leading underscores" do + "_123".to_i.should == 123 + "__123".to_i.should == 123 + "___123".to_i.should == 123 + end + + it "ignores underscores in between the digits" do + "1_2_3asdf".to_i.should == 123 + end + + it "ignores subsequent invalid characters" do + "123asdf".to_i.should == 123 + "123#123".to_i.should == 123 + "123 456".to_i.should == 123 + end + + it "returns 0 if self is no valid integer-representation" do + [ "++2", "+-2", "--2" ].each do |str| + str.to_i.should == 0 + end + end + + it "ignores a leading mix of whitespaces and underscores" do + [ "_ _123", "_\t_123", "_\r\n_123" ].each do |str| + str.to_i.should == 123 + end + end + + it "interprets leading characters as a number in the given base" do + "100110010010".to_i(2).should == 0b100110010010 + "100110201001".to_i(3).should == 186409 + "103110201001".to_i(4).should == 5064769 + "103110241001".to_i(5).should == 55165126 + "153110241001".to_i(6).should == 697341529 + "153160241001".to_i(7).should == 3521513430 + "153160241701".to_i(8).should == 14390739905 + "853160241701".to_i(9).should == 269716550518 + "853160241791".to_i(10).should == 853160241791 + + "F00D_BE_1337".to_i(16).should == 0xF00D_BE_1337 + "-hello_world".to_i(32).should == -18306744 + "abcXYZ".to_i(36).should == 623741435 + + ("z" * 24).to_i(36).should == 22452257707354557240087211123792674815 + + "5e10".to_i.should == 5 + end + + it "auto-detects base via base specifiers (default: 10) for base = 0" do + "01778".to_i(0).should == 0177 + "0b112".to_i(0).should == 0b11 + "0d19A".to_i(0).should == 19 + "0o178".to_i(0).should == 0o17 + "0xFAZ".to_i(0).should == 0xFA + "1234567890ABC".to_i(0).should == 1234567890 + + "-01778".to_i(0).should == -0177 + "-0b112".to_i(0).should == -0b11 + "-0d19A".to_i(0).should == -19 + "-0o178".to_i(0).should == -0o17 + "-0xFAZ".to_i(0).should == -0xFA + "-1234567890ABC".to_i(0).should == -1234567890 + end + + it "doesn't handle foreign base specifiers when base is > 0" do + [2, 3, 4, 8, 10].each do |base| + "0111".to_i(base).should == "111".to_i(base) + + "0b11".to_i(base).should == (base == 2 ? 0b11 : 0) + "0d11".to_i(base).should == (base == 10 ? 0d11 : 0) + "0o11".to_i(base).should == (base == 8 ? 0o11 : 0) + "0xFA".to_i(base).should == 0 + end + + "0xD00D".to_i(16).should == 0xD00D + + "0b11".to_i(16).should == 0xb11 + "0d11".to_i(16).should == 0xd11 + "0o11".to_i(25).should == 15026 + "0x11".to_i(34).should == 38183 + end + + it "tries to convert the base to an integer using to_int" do + obj = mock('8') + def obj.to_int() 8 end + + "777".to_i(obj).should == 0777 + + obj = mock('8') + obj.should_receive(:respond_to?).with(:to_int).any_number_of_times.and_return(true) + obj.should_receive(:method_missing).with(:to_int).and_return(8) + + "777".to_i(obj).should == 0777 + end + + it "requires that the sign if any appears before the base specifier" do + "0b-1".to_i(0).should == 0 + "0d-1".to_i(0).should == 0 + "0o-1".to_i(0).should == 0 + "0x-1".to_i(0).should == 0 + + "0b-1".to_i(2).should == 0 + "0o-1".to_i(8).should == 0 + "0d-1".to_i(10).should == 0 + "0x-1".to_i(16).should == 0 + end + + it "raises an ArgumentError for illegal bases (1, < 0 or > 36)" do + lambda { "".to_i(1) }.should raise_error(ArgumentError) + lambda { "".to_i(-1) }.should raise_error(ArgumentError) + lambda { "".to_i(37) }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/string/to_s_spec.rb b/1.8/core/string/to_s_spec.rb new file mode 100644 index 0000000000..632594faf3 --- /dev/null +++ b/1.8/core/string/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/to_s.rb' + +describe "String#to_s" do + it_behaves_like(:string_to_s, :to_s) +end \ No newline at end of file diff --git a/1.8/core/string/to_str_spec.rb b/1.8/core/string/to_str_spec.rb new file mode 100644 index 0000000000..00fc53b519 --- /dev/null +++ b/1.8/core/string/to_str_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/to_s.rb' + +describe "String#to_str" do + it_behaves_like(:string_to_s, :to_str) +end \ No newline at end of file diff --git a/1.8/core/string/to_sym_spec.rb b/1.8/core/string/to_sym_spec.rb new file mode 100644 index 0000000000..0da841d391 --- /dev/null +++ b/1.8/core/string/to_sym_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' +require File.dirname(__FILE__) + '/shared/to_sym.rb' + +describe "String#to_sym" do + it_behaves_like(:string_to_sym, :to_sym) +end \ No newline at end of file diff --git a/1.8/core/string/tr_s_spec.rb b/1.8/core/string/tr_s_spec.rb new file mode 100644 index 0000000000..7b8b681cc6 --- /dev/null +++ b/1.8/core/string/tr_s_spec.rb @@ -0,0 +1,103 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#tr_s" do + it "returns a string processed according to tr with newly duplicate characters removed" do + "hello".tr_s('l', 'r').should == "hero" + "hello".tr_s('el', '*').should == "h*o" + "hello".tr_s('el', 'hx').should == "hhxo" + "hello".tr_s('o', '.').should == "hell." + end + + it "accepts c1-c2 notation to denote ranges of characters" do + "hello".tr_s('a-y', 'b-z').should == "ifmp" + "123456789".tr_s("2-5", "abcdefg").should == "1abcd6789" + "hello ^--^".tr_s("e-", "__").should == "h_llo ^_^" + "hello ^--^".tr_s("---", "_").should == "hello ^_^" + end + + it "pads to_str with its last char if it is shorter than from_string" do + "this".tr_s("this", "x").should == "x" + end + + it "translates chars not in from_string when it starts with a ^" do + "hello".tr_s('^aeiou', '*').should == "*e*o" + "123456789".tr_s("^345", "abc").should == "c345c" + "abcdefghijk".tr_s("^d-g", "9131").should == "1defg1" + + "hello ^_^".tr_s("a-e^e", ".").should == "h.llo ._." + "hello ^_^".tr_s("^^", ".").should == ".^.^" + "hello ^_^".tr_s("^", "x").should == "hello x_x" + "hello ^-^".tr_s("^-^", "x").should == "x^-^" + "hello ^-^".tr_s("^^-^", "x").should == "x^x^" + "hello ^-^".tr_s("^---", "x").should == "x-x" + "hello ^-^".tr_s("^---l-o", "x").should == "xllox-x" + end + + it "tries to convert from_str and to_str to strings using to_str" do + from_str = mock('ab') + def from_str.to_str() "ab" end + + to_str = mock('AB') + def to_str.to_str() "AB" end + + "bla".tr_s(from_str, to_str).should == "BlA" + + from_str = mock('ab') + from_str.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + from_str.should_receive(:method_missing).with(:to_str).and_return("ab") + + to_str = mock('AB') + to_str.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + to_str.should_receive(:method_missing).with(:to_str).and_return("AB") + + "bla".tr_s(from_str, to_str).should == "BlA" + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").tr_s("e", "a").class.should == StringSpecs::MyString + end + + it "taints the result when self is tainted" do + ["h", "hello"].each do |str| + tainted_str = str.dup.taint + + tainted_str.tr_s("e", "a").tainted?.should == true + + str.tr_s("e".taint, "a").tainted?.should == false + str.tr_s("e", "a".taint).tainted?.should == false + end + end +end + +describe "String#tr_s!" do + it "modifies self in place" do + s = "hello" + s.tr_s!("l", "r").should == "hero" + s.should == "hero" + end + + it "returns nil if no modification was made" do + s = "hello" + s.tr_s!("za", "yb").should == nil + s.tr_s!("", "").should == nil + s.should == "hello" + end + + it "does not modify self if from_str is empty" do + s = "hello" + s.tr_s!("", "").should == nil + s.should == "hello" + s.tr_s!("", "yb").should == nil + s.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + s = "hello".freeze + lambda { s.tr_s!("el", "ar") }.should raise_error(TypeError) + lambda { s.tr_s!("l", "r") }.should raise_error(TypeError) + lambda { s.tr_s!("", "") }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/tr_spec.rb b/1.8/core/string/tr_spec.rb new file mode 100644 index 0000000000..55befb569a --- /dev/null +++ b/1.8/core/string/tr_spec.rb @@ -0,0 +1,103 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#tr" do + it "returns a new string with the characters from from_string replaced by the ones in to_string" do + "hello".tr('aeiou', '*').should == "h*ll*" + "hello".tr('el', 'ip').should == "hippo" + "Lisp".tr("Lisp", "Ruby").should == "Ruby" + end + + it "accepts c1-c2 notation to denote ranges of characters" do + "hello".tr('a-y', 'b-z').should == "ifmmp" + "123456789".tr("2-5","abcdefg").should == "1abcd6789" + "hello ^-^".tr("e-", "__").should == "h_llo ^_^" + "hello ^-^".tr("---", "_").should == "hello ^_^" + end + + it "pads to_str with its last char if it is shorter than from_string" do + "this".tr("this", "x").should == "xxxx" + "hello".tr("a-z", "A-H.").should == "HE..." + end + + it "translates chars not in from_string when it starts with a ^" do + "hello".tr('^aeiou', '*').should == "*e**o" + "123456789".tr("^345", "abc").should == "cc345cccc" + "abcdefghijk".tr("^d-g", "9131").should == "111defg1111" + + "hello ^_^".tr("a-e^e", ".").should == "h.llo ._." + "hello ^_^".tr("^^", ".").should == "......^.^" + "hello ^_^".tr("^", "x").should == "hello x_x" + "hello ^-^".tr("^-^", "x").should == "xxxxxx^-^" + "hello ^-^".tr("^^-^", "x").should == "xxxxxx^x^" + "hello ^-^".tr("^---", "x").should == "xxxxxxx-x" + "hello ^-^".tr("^---l-o", "x").should == "xxlloxx-x" + end + + it "tries to convert from_str and to_str to strings using to_str" do + from_str = mock('ab') + def from_str.to_str() "ab" end + + to_str = mock('AB') + def to_str.to_str() "AB" end + + "bla".tr(from_str, to_str).should == "BlA" + + from_str = mock('ab') + from_str.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + from_str.should_receive(:method_missing).with(:to_str).and_return("ab") + + to_str = mock('AB') + to_str.should_receive(:respond_to?).with(:to_str).any_number_of_times.and_return(true) + to_str.should_receive(:method_missing).with(:to_str).and_return("AB") + + "bla".tr(from_str, to_str).should == "BlA" + end + + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").tr("e", "a").class.should == StringSpecs::MyString + end + + it "taints the result when self is tainted" do + ["h", "hello"].each do |str| + tainted_str = str.dup.taint + + tainted_str.tr("e", "a").tainted?.should == true + + str.tr("e".taint, "a").tainted?.should == false + str.tr("e", "a".taint).tainted?.should == false + end + end +end + +describe "String#tr!" do + it "modifies self in place" do + s = "abcdefghijklmnopqR" + s.tr!("cdefg", "12").should == "ab12222hijklmnopqR" + s.should == "ab12222hijklmnopqR" + end + + it "returns nil if no modification was made" do + s = "hello" + s.tr!("za", "yb").should == nil + s.tr!("", "").should == nil + s.should == "hello" + end + + it "does not modify self if from_str is empty" do + s = "hello" + s.tr!("", "").should == nil + s.should == "hello" + s.tr!("", "yb").should == nil + s.should == "hello" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if self is frozen" do + s = "abcdefghijklmnopqR".freeze + lambda { s.tr!("cdefg", "12") }.should raise_error(TypeError) + lambda { s.tr!("R", "S") }.should raise_error(TypeError) + lambda { s.tr!("", "") }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/unpack_spec.rb b/1.8/core/string/unpack_spec.rb new file mode 100644 index 0000000000..a0f0109550 --- /dev/null +++ b/1.8/core/string/unpack_spec.rb @@ -0,0 +1,446 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +if ENV['MRI'] then + $: << 'kernel/core' + require 'unpack' +end + +# TODO: fucking hell... "according to the format string" is NOT a spec +# description! + +describe "String#unpack" do + it "returns an array by decoding self according to the format string" do + "abc \0\0abc \0\0".unpack('A6Z6').should == ["abc", "abc "] + "abc \0\0".unpack('a3a3').should == ["abc", " \000\000"] + "aa".unpack('b8B8').should == ["10000110", "01100001"] + "aaa".unpack('h2H2c').should == ["16", "61", 97] + "now=20is".unpack('M*').should == ["now is"] + "whole".unpack('xax2aX2aX1aX2a').should == ["h", "e", "l", "l", "o"] + end + + little_endian do + it "returns an array by decoding self in little-endian (native format) order according to the format string" do + "\xfe\xff\xfe\xff".unpack('sS').should == [-2, 65534] + end + end + + big_endian do + it "returns an array by decoding self in big-endian (native format) order according to the format string" do + "\xfe\xff\xfe\xff".unpack('sS').should == [-257, 65279] + end + end +end + +describe "String#unpack with nil format argument" do + it "raises a TypeError exception" do + lambda { "abc".unpack(nil) }.should raise_error(TypeError) + end +end + +describe "String#unpack with 'Z' directive" do + it "returns an array by decoding self according to the format string" do + "abc \0abc \0".unpack('Z*Z*').should == ["abc ", "abc "] + "abc \0abc \0".unpack('Z10').should == ["abc "] + "abc \0abc \0".unpack('Z7Z*').should == ["abc ", "c "] + "abc \0abc \0".unpack('Z50Z*').should == ["abc ", ""] + "abc \0\0\0abc \0".unpack('Z*Z*').should == ["abc ", ""] + "abc \0\0\0\0".unpack('Z*').should == ["abc "] + "abc \0\0\0\0".unpack('Z*Z*').should == ["abc ", ""] + "\0".unpack('Z*').should == [""] + "\0\0".unpack('Z*').should == [""] + "\0\0abc".unpack('Z*').should == [""] + "\0\0abc\0\0".unpack('Z*').should == [""] + "\0 abc\0\0abc\0abc \0\0 ".unpack('Z2Z*Z3ZZ*Z10Z10').should == ["", "abc", "", "c", "", "abc ", ""] + end +end + +describe "String#unpack with 'N' and 'n' directives" do + it "returns an array by decoding self according to the format string" do + "\xF3\x02\x00\x42".unpack('N').should == [4076994626] + "\xF3\x02".unpack('N').should == [nil] + "\xF3\x02\x00\x42\x32\x87\xF3\x00".unpack('N2').should == [4076994626, 847770368] + "\xF3\x02\xC0\x42\x3A\x87\xF3\x00".unpack('N*').should == [4077043778, 981988096] + "\xF3\x02\x00\x42".unpack('n').should == [62210] + "\x01\x62\xEE\x42".unpack('n-7n').should == [354, 60994] + "\xF3\x02\x00\x42".unpack('n5').should == [62210, 66, nil, nil, nil] + "\xF3".unpack('n').should == [nil] + "\xF3\x02\x00\x42\x32\x87\xF3\x00".unpack('n3').should == [62210, 66, 12935] + "\xF3\x02\x00\x42\x32\x87\xF3\x00".unpack('n*').should == [62210, 66, 12935, 62208] + "\xF3\x02\x00\x42\x32\x87\xF3\x02".unpack('n0N*').should == [4076994626, 847770370] + end +end + +describe "String#unpack with 'V' and 'v' directives" do + it "returns an array by decoding self according to the format string" do + "\xF3\x02\x00\x42".unpack('V').should == [1107297011] + "\xF3\x02".unpack('V').should == [nil] + "\xF3\xFF\xFF\xFF\x32\x0B\x02\x00".unpack('V2').should == [4294967283, 133938] + "\xF3\x02\xC0\x42\x3A\x87\xF3\x00".unpack('V*').should == [1119879923, 15959866] + "\xF3\x02\x00\x42".unpack('v').should == [755] + "\x01\x62\xEE\x42".unpack('v-7v').should == [25089, 17134] + "\xF3\x02\x00\x42".unpack('v5').should == [755, 16896, nil, nil, nil] + "\xF3".unpack('v').should == [nil] + "\xF3\xFF\xFF\xFF\x32\x87\xF3\x00".unpack('v3').should == [65523, 65535, 34610] + "\xF3\x02\x00\x42\x32\x87\xF3\x00".unpack('v*').should == [755, 16896, 34610, 243] + "\xF3\x02\x00\x42\x32\x87\xF3\x02".unpack('v0V*').should == [1107297011, 49514290] + end +end + +describe "String#unpack with 'C' and 'c' directives" do + it "returns an array by decoding self according to the format string" do + "\xF3\x02\x00\x42".unpack('C').should == [243] + "".unpack('C').should == [nil] + "\xF3\x02\x00\x42\x32\x87\xF3\x00".unpack('C2').should == [243, 2] + "\xF3\x02\xC0\x42\x3A\x87\xF3\x00".unpack('C*').should == [243, 2, 192, 66, 58, 135, 243, 0] + "\xF3\x02\x00\x42".unpack('c').should == [-13] + "\x01\x62\xEE\x42".unpack('c-7c').should == [1, 98] + "\xF3\x02\x00\x42".unpack('c5').should == [-13, 2, 0, 66, nil] + "\x80".unpack('c').should == [-128] + "\x7F\x02\x00\x42\x32\x87\xF3\x00".unpack('c3').should == [127, 2, 0] + "\x80\x02\x00\x42\xFF\x87\xF3\x00".unpack('c*').should == [-128, 2, 0, 66, -1, -121, -13, 0] + "\xF3\x02\x00\x42\x32\x87\xF3\x02".unpack('c0C*').should == [243, 2, 0, 66, 50, 135, 243, 2] + end +end + +describe "String#unpack with 'Q' and 'q' directives" do + little_endian do + it "returns an array in little-endian (native format) order by decoding self according to the format string" do + "\xF3\x02\x00\x42\x32\x23\xB3\xF0".unpack('Q').should == [17344245288696546035] + "\xF3\x02".unpack('Q*').should == [] + "\xF3\xFF\xFF\xFF\x32\x0B\x02\x00".unpack('Q2').should == [575263624658931] + "\xF3\x02\xC0\x42\x3A\x87\xF3\x00\xFA\xFF\x00\x02\x32\x87\xF3\xEE".unpack('Q*').should == + [68547103638422259, 17218254449219272698] + "\xF3\x02\x00\x42".unpack('q').should == [nil] + "\x01\x62\xEE\x42".unpack('q-7q').should == [nil, nil] + "\xF3\x02\x00\x42".unpack('q5').should == [nil, nil, nil, nil, nil] + "\xF3".unpack('q').should == [nil] + "\xF3\xFF\xFF\xFF\xFF\xFA\xF3\xFD".unpack('q3').should == [-147498385354522637, nil, nil] + "\x0A\x02\x00\x02\x32\x87\xF3\x00\xFA\xFF\x00\x02\x32\x87\xF3\xEE".unpack('q*').should == + [68547068192358922, -1228489624490278918] + "\x7F\x77\x77\x77\x77\x77\x77\x77".unpack('q0Q*').should == [8608480567731124095] + end + end + + big_endian do + it "returns an array in big-endian (native format) order by decoding self according to the format string" do + "\xF3\x02\x00\x42\x32\x23\xB3\xF0".unpack('Q').should == [17510558585478951920] + "\xF3\x02".unpack('Q*').should == [] + "\xF3\xFF\xFF\xFF\x32\x0B\x02\x00".unpack('Q2').should == [17582052941799031296] + "\xF3\x02\xC0\x42\x3A\x87\xF3\x00\xFA\xFF\x00\x02\x32\x87\xF3\xEE".unpack('Q*').should == + [17510769691852272384, 18086174637980906478] + "\xF3\x02\x00\x42".unpack('q').should == [nil] + "\x01\x62\xEE\x42".unpack('q-7q').should == [nil, nil] + "\xF3\x02\x00\x42".unpack('q5').should == [nil, nil, nil, nil, nil] + "\xF3".unpack('q').should == [nil] + "\xF3\xFF\xFF\xFF\xFF\xFA\xF3\xFD".unpack('q3').should == [-864691128455465987, nil, nil] + "\x0A\x02\x00\x02\x32\x87\xF3\x00\xFA\xFF\x00\x02\x32\x87\xF3\xEE".unpack('q*').should == + [721138899770405632, -360569435728645138] + "\x7F\x77\x77\x77\x77\x77\x77\x77".unpack('q0Q*').should == [9184941320034547575] + end + end + + little_endian do + it "returns Bignums for big numeric values on little-endian platforms" do + "\xF3\x02\x00\x42\x32\x23\xB3\xF0".unpack('Q')[0].class.should == + 17344245288696546035.class + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE".unpack('q')[0].class.should == -72057594037927937.class + end + end + + big_endian do + it "returns Bignums for big numeric values on big-endian platforms" do + "\xF3\x02\x00\x42\x32\x23\xB3\xF0".unpack('Q')[0].class.should == + 17344245288696546035.class + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE".unpack('q')[0].class.should == Fixnum + end + end + + it "returns Fixnums for small numeric values" do + "\x00\x00\x00\x00\x00\x00\x00\x00".unpack('Q').should == [0] + "\x00\x00\x00\x00\x00\x00\x00\x00".unpack('q').should == [0] + "\x00\x00\x00\x00\x00\x00\x00\x00".unpack('Q')[0].class.should == Fixnum + "\x00\x00\x00\x00\x00\x00\x00\x00".unpack('q')[0].class.should == Fixnum + end +end + +describe "String#unpack with 'a', 'X' and 'x' directives" do + it "returns an array by decoding self according to the format string" do + "abc".unpack('x3a').should == [""] + "abc".unpack('x3X3x0a').should == ["a"] + "abc".unpack('x2X-5a').should == ["b"] + "abcdefghijklmnopqrstuvwxyz".unpack('aaax10aX14X0a').should == ["a", "b", "c", "n", "a"] + "abcdefghijklmnopqrstuvwxyz".unpack('aa-8ax10aX*a').should == ["a", "b", "c", "n", "c"] + "abcdefghijklmnopqrstuvwxyz".unpack('x*aX26a').should == ["", "a"] + "abcdefghijklmnopqrstuvwxyz".unpack('x*x*x*aX26a').should == ["", "a"] + "abc".unpack('x3X*').should == [] + "abc".unpack('x3X*a').should == [""] + "abc".unpack('x3X*X3a').should == ["a"] + lambda { "abc".unpack('X*') }.should raise_error(ArgumentError) + lambda { "abc".unpack('x*x') }.should raise_error(ArgumentError) + lambda { "abc".unpack('x4') }.should raise_error(ArgumentError) + lambda { "abc".unpack('X') }.should raise_error(ArgumentError) + lambda { "abc".unpack('xX*') }.should raise_error(ArgumentError) + end +end + +describe "String#unpack with 'DdEeFfGg' directives" do + before :each do + @precision_small = 1E-12 + @precision_large = 1E+17 + end + + it "returns an array by decoding self according to the format string" do + res = "\xF3\x02\x00\x42\xF3\x02\x00\x42".unpack('eg') + res.length.should == 2 + res[0].should be_close(32.0028800964355, @precision_small) + res[1].should be_close(-1.02997409159585e+31, @precision_large) + + res = "\xF3\x02\x00\x42\xF3\x02\x00\x42".unpack('eg') + res.length.should == 2 + res[0].should be_close(32.0028800964355, @precision_small) + res[1].should be_close(-1.02997409159585e+31, @precision_large) + + "\xF3\x02".unpack('GD').should == [nil, nil] + +# "\xF3\x02\x00\x42\x32\x87\xF3\x00".unpack('E*')[0].should be_close( +# 4.44943241769783e-304, @precision_small) +# "\x00\x00\x00\x42\x32\x87\xF3\x02".unpack('g0G*')[0].should be_close( +# 1.40470576419087e-312, @precision_small) + end + + little_endian do + it "returns an array by decoding self in little-endian order according to the format string" do + # 'F2' pattern + res = "\xF3\xFF\xFF\xFF\x32\x0B\x02\x00".unpack('F2') + res.length.should == 2 + res[0].nan?.should == true + res[1].should be_close(1.87687113714737e-40, @precision_small) + + # 'f*' pattern + res = "\xF3\x02\xC0\x42\x3A\x87\xF3\x00".unpack('f*') + res.length.should == 2 + res[0].should be_close(96.0057601928711, @precision_small) + res[1].should be_close(2.23645357166299e-38, @precision_small) + + "\xFF\x80\x00\x00".unpack('g').to_s.should == "-Infinity" + "\x01\x62\xEE\x42".unpack('e-7e')[0].should be_close( + 119.191413879395, @precision_small) + "\x00\x00\x00\x00".unpack('f5').should == [0.0, nil, nil, nil, nil] + "\xF3".unpack('E').should == [nil] + + # 'd3' pattern + res = "\xF3\xFF\xFF\xFF\x32\x87\xF3\x00".unpack('d3') + res.length.should == 3 +# res[0].should be_close(4.44943499804409e-304, @precision_small) + res[1].should == nil + res[2].should == nil + end + end + + big_endian do + it "returns an array by decoding self in big-endian order according to the format string" do + # 'F2' pattern + res = "\xFF\xFF\xFF\xF3\x00\x02\x0B\x32".unpack('F2') + res.length.should == 2 + res[0].nan?.should == true + res[1].should be_close(1.87687113714737e-40, @precision_small) + + # 'f*' pattern + res = "\x42\xC0\x02\xF3\x00\xF3\x87\x3A".unpack('f*') + res.length.should == 2 + res[0].should be_close(96.0057601928711, @precision_small) + res[1].should be_close(2.23645357166299e-38, @precision_small) + + # 'd3' pattern + res = "\x00\xF3\x87\x32\xFF\xFF\xFF\xF3".unpack('d3') + res.length.should == 3 +# res[0].should be_close(4.44943499804409e-304, @precision_small) + res[1].should == nil + res[2].should == nil + end + end +end + +describe "String#unpack with 'B' and 'b' directives" do + it "returns an array by decoding self according to the format string" do + "\xFF\x00\x80\x01\x7E\xAA\xF0\x0F".unpack('B64').should == + ["1111111100000000100000000000000101111110101010101111000000001111"] + "\xFF\x00\x80\x01\x7E\xAA\xF0\x0F".unpack('b64').should == + ["1111111100000000000000011000000001111110010101010000111111110000"] + "\xFF\x00\x80\x01\x7E\xAA\xF0\x0F".unpack('B12b12B12b12B*b*').should == + ["111111110000", "000000011000", "011111101010", "000011111111", "", ""] + "\xFF\x00\x80\x01\x7E\xAA\xF0\x0F".unpack('B4b4B4b4B4b4B16').should == + ["1111", "0000", "1000", "1000", "0111", "0101", "1111000000001111"] + "\xFF\x00\x80\xAA".unpack('b-5B8b8b0B2b1B1').should == + ["1", "00000000", "00000001", "", "10", "", ""] + "\xFF\x00\x80\xAA".unpack('B0b0').should == ["", ""] + "\xFF\x00\x80\xAA".unpack('B3b*B*').should == ["111", "000000000000000101010101", ""] + "\xFF\x00\x80\xAA".unpack('B3B*b*').should == ["111", "000000001000000010101010", ""] + end +end + +describe "String#unpack with 'H' and 'h' directives" do + it "returns an array by decoding self according to the format string" do + "\xFF\x00\x80\x01\x7E\xAA\xF0\x0F".unpack('H16').should == ["ff0080017eaaf00f"] + "\xFF\x00\x80\x01\x7E\xAA\xF0\x0F".unpack('h16').should == ["ff000810e7aa0ff0"] + "\xFF\x00\x80\x01\x7E\xAA\xF0\x0F".unpack('H3h3H3h3H*h*').should == + ["ff0", "081", "7ea", "0ff", "", ""] + "\xFF\x00\x80\x01\x7E\xAA\xF0\x0F".unpack('HhHhHhH4').should == + ["f", "0", "8", "1", "7", "a", "f00f"] + "\xFF\x00\x80\xAA".unpack('h-5H2h2h0Hh1H1').should == + ["f", "00", "08", "", "a", "", ""] + "\xFF\x00\x80\xAA".unpack('H0h0').should == ["", ""] + "\xFF\x00\x80\xAA".unpack('H3h*H*').should == ["ff0", "08aa", ""] + "\xFF\x00\x80\xAA".unpack('H3H*h*').should == ["ff0", "80aa", ""] + end +end + +describe "String#unpack with 'IiLlSs' directives" do + platform_is :wordsize => 32 do + little_endian do + it "returns an array in little-endian (native format) by decoding self according to the format string" do + "\xF3\x02\x00\x42\x32\x23\xB3\xF0".unpack('SLI').should == [755, 590496256, nil] + "\xF3\x02".unpack('L*I*').should == [] + "\xF3\xFF\xFF\xFF\x32\x0B\x02\x00".unpack('I2').should == [4294967283, 133938] + "\xF3\x02\xC0\x42\x3A\x87\xF3\x00\xFA\xFF\x00\x02\x32\x87\xF3\xEE".unpack('L*').should == + [1119879923, 15959866, 33619962, 4008937266] + "\xF3\x02\x00\x42".unpack('i').should == [1107297011] + "\x01\x62\xEE\x42".unpack('l-7l').should == [1122918913, nil] + "\xF3\x02\x00\x42".unpack('s5').should == [755, 16896, nil, nil, nil] + "\xF3".unpack('s').should == [nil] + "\xF3\xFF\xFF\xFF\xFF\xFA\xF3\xFD".unpack('i3').should == [-13, -34342145, nil] + "\x0A\x02\x00\x02\x32\x87\xF3\x00\xFA\xFF\x00\x02\x32\x87\xF3\xEE".unpack('l*').should == + [33554954, 15959858, 33619962, -286030030] + "\x7F\x77\x77\x77\x77\x77\x77\x77".unpack('i0I*').should == [2004318079, 2004318071] + end + end + + big_endian do + it "returns an array in big-endian (native format) by decoding self according to the format string" do + "\xF3\x02\x00\x42\x32\x23\xB3\xF0".unpack('SLI').should == [62210, 4338211, nil] + "\xF3\x02".unpack('L*I*').should == [] + "\xF3\xFF\xFF\xFF\x32\x0B\x02\x00".unpack('I2').should == [4093640703, 839582208] + "\xF3\x02\xC0\x42\x3A\x87\xF3\x00\xFA\xFF\x00\x02\x32\x87\xF3\xEE".unpack('L*').should == + [4077043778, 981988096, 4211015682, 847770606] + "\xF3\x02\x00\x42".unpack('i').should == [-217972670] + "\x01\x62\xEE\x42".unpack('l-7l').should == [23260738, nil] + "\xF3\x02\x00\x42".unpack('s5').should == [-3326, 66, nil, nil, nil] + "\xF3".unpack('s').should == [nil] + "\xF3\xFF\xFF\xFF\xFF\xFA\xF3\xFD".unpack('i3').should == [-201326593, -330755, nil] + "\x0A\x02\x00\x02\x32\x87\xF3\x00\xFA\xFF\x00\x02\x32\x87\xF3\xEE".unpack('l*').should == + [167903234, 847770368, -83951614, 847770606] + "\x7F\x77\x77\x77\x77\x77\x77\x77".unpack('i0I*').should == [2138535799, 2004318071] + end + end + end +end + +describe "String#unpack with 'U' directive" do + it "returns an array by decoding self according to the format string" do + "\xFD\x80\x80\xB7\x80\x80".unpack('U').should == [1073967104] + "\xF9\x80\x80\x80\x80".unpack('U').should == [16777216] + "\xF1\x80\x80\x80".unpack('UU').should == [262144] + "\xE1\xB7\x80".unpack('U').should == [7616] + "\xC2\x80\xD2\x80".unpack('U-8U').should == [128, 1152] + "\x00\x7F".unpack('U100').should == [0, 127] + "\x05\x7D".unpack('U0U0').should == [] + "".unpack('U').should == [] + "\xF1\x80\x80\xB1\xE1\x8A\x80\xC2\xBF\x0C\x6B".unpack('U*').should == [262193, 4736, 191, 12, 107] + "\xF1\x8F\x85\xB1\xE1\x8A\x89\xC2\xBF\x0C\x6B".unpack('U2x2U').should == [323953, 4745, 12] + lambda { "\xF0\x80\x80\x80".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xE0\x80\x80".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xC0\x80".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xC1\x80".unpack('U') }.should raise_error(ArgumentError) + lambda { "\x80".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xF1\x80\x80".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xE1\x80".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xC2".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xF1\x00\x00\x00".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xE1\x00\x00".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xC2\x00".unpack('U') }.should raise_error(ArgumentError) + lambda { "\xFE".unpack('U') }.should raise_error(ArgumentError) + lambda { "\x03\xFF".unpack('UU') }.should raise_error(ArgumentError) + end +end + +describe "String#unpack with 'A' directive" do + it "returns an array by decoding self according to the format string" do + "".unpack('A').should == [""] + " \0 abc \0\0\0abc\0\0 \0abc".unpack('A*').should == + [" \000 abc \000\000\000abc\000\000 \000abc"] + " \0 abc \0\0\0abc\0\0 \0abc \0 a ".unpack('A16A-9A*A*A100').should == + [" \000 abc \000\000\000abc", "", "abc \000 a", "", ""] + " \0 abc \0\0\0abc\0\0 \0abc \0 a ".unpack('A3A4AAA').should == ["", "abc", "", "", ""] + " \0 abc \0\0\0abc\0\0 \0abc \0 a ".unpack('A2A0A14').should == ["", "", " abc \000\000\000abc"] + end +end + +describe "String#unpack with '@' directive" do + it "returns an array by decoding self according to the format string" do + "abcdefg".unpack('@2').should == [] + "abcdefg".unpack('@3@-5a').should == ["a"] + "abcdefg".unpack('@*@a').should == ["a"] + "abcdefg".unpack('@3@5a').should == ["f"] + "abcdefg".unpack('@*a').should == [""] + "abcdefg".unpack('@7a').should == [""] + lambda { "abcdefg".unpack('@8') }.should raise_error(ArgumentError) + end +end + +describe "String#unpack with 'M' directive" do + it "returns an array by decoding self according to the format string" do + "".unpack('M').should == [""] + "=5".unpack('Ma').should == ["", ""] + "abc=".unpack('M').should == ["abc"] + "a=*".unpack('MMMM').should == ["a", "*", "", ""] + + "\x3D72=65abcdefg=5%=33".unpack('M').should == ["reabcdefg"] + "\x3D72=65abcdefg=5%=33".unpack('M0').should == ["reabcdefg"] + "\x3D72=65abcdefg=5%=33".unpack('M100').should == ["reabcdefg"] + "\x3D72=65abcdefg=5%=33".unpack('M*').should == ["reabcdefg"] + "\x3D72=65abcdefg=5%=33".unpack('M-8M').should == ["reabcdefg", "%3"] + + "abc===abc".unpack('MMMMM').should == ["abc", "", "\253c", "", ""] + "=$$=47".unpack('MMMM').should == ["", "$$G", "", ""] + "=$$=4@=47".unpack('MMMMM').should == ["", "$$", "@G", "", ""] + "=$$=4@=47".unpack('M5000').should == [""] + "=4@".unpack('MMM').should == ["", "@", ""] + end +end + +describe "String#unpack with 'm' directive" do + it "returns an array by decoding self according to the format string" do + "YQ==".unpack('m').should == ["a"] + "YWE=".unpack('m').should == ["aa"] + "ab c=awerB2y+".unpack('mmmmm').should == ["i\267", "k\a\253\al\276", "", "", ""] + "a=b=c=d=e=f=g=".unpack('mamamamam').should == + ["i", "=", "q", "=", "y", "=", "", "", ""] + "a===b===c===d===e===f===g===".unpack('mamamamam').should == + ["i", "=", "q", "=", "y", "=", "", "", ""] + "ab c= de f= gh i= jk l=".unpack('mmmmmmmmmm').should == + ["i\267", "u\347", "\202\030", "\216I", "", "", "", "", "", ""] + "+/=\n".unpack('mam').should == ["\373", "=", ""] + "aA==aA==aA==".unpack('m-100').should == ["h"] + "aGk=aGk=aGk=".unpack('m*mm').should == ["hi", "hi", "hi"] + "aA".unpack('m55').should == [""] + "aGk".unpack('m').should == [""] + "/w==".unpack('m').should == ["\377"] + "Pj4+".unpack('m').should == [">>>"] + "<>:?Pj@$%^&*4+".unpack('m').should == [">>>"] + "<>:?Pja@$%^&*4+".unpack('ma').should == [">6\270", ""] + "<>:?P@$%^&*+".unpack('ma').should == ["", ""] + "54321".unpack('m').should == ["\347\215\366"] + "==43".unpack('m').should == [""] + "43aw".unpack('mmm').should == ["\343v\260", "", ""] + "=======43aw".unpack('m').should == ["\343v\260"] + "cmVxdWlyZSAnYmFzZTY0Jw==".unpack('m').should == ["require 'base64'"] + "+/=".unpack('m').should == ["\373"] + "YXNkb2Zpc09BSVNERk9BU0lESjk4ODc5ODI0YWlzdWYvLy8rKw==".unpack('m').should == + ["asdofisOAISDFOASIDJ98879824aisuf///++"] + "IUAjJSMgJCBeJV4qJV4oXiYqKV8qKF8oKStQe308Pj9LTCJLTCI6\n".unpack('m').should == + ["!@#$@#%# $ ^%^*%^(^&*)_*(_()+P{}<>?KL\"KL\":"] + "sfj98349//+ASDd98934jg+N,CBMZP2133GgHJiYrB12".unpack('m').should == + ["\261\370\375\363~=\377\377\200H7}\363\335\370\216\017\215\b\023\031?mw\334h\a&&+"] + end +end diff --git a/1.8/core/string/upcase_spec.rb b/1.8/core/string/upcase_spec.rb new file mode 100644 index 0000000000..154aaa91a7 --- /dev/null +++ b/1.8/core/string/upcase_spec.rb @@ -0,0 +1,52 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#upcase" do + it "returns a copy of self with all lowercase letters upcased" do + "Hello".upcase.should == "HELLO" + "hello".upcase.should == "HELLO" + end + + it "is locale insensitive (only replaces a-z)" do + "äöü".upcase.should == "äöü" + + str = Array.new(256) { |c| c.chr }.join + expected = Array.new(256) do |i| + c = i.chr + c.between?("a", "z") ? c.upcase : c + end.join + + str.upcase.should == expected + end + + it "taints result when self is tainted" do + "".taint.upcase.tainted?.should == true + "X".taint.upcase.tainted?.should == true + "x".taint.upcase.tainted?.should == true + end + + it "returns a subclass instance for subclasses" do + StringSpecs::MyString.new("fooBAR").upcase.class.should == StringSpecs::MyString + end +end + +describe "String#upcase!" do + it "modifies self in place" do + a = "HeLlO" + a.upcase!.equal?(a).should == true + a.should == "HELLO" + end + + it "returns nil if no modifications were made" do + a = "HELLO" + a.upcase!.should == nil + a.should == "HELLO" + end + + compliant_on :ruby, :jruby do + it "raises a TypeError when self is frozen" do + lambda { "HeLlo".freeze.upcase! }.should raise_error(TypeError) + lambda { "HELLO".freeze.upcase! }.should raise_error(TypeError) + end + end +end diff --git a/1.8/core/string/upto_spec.rb b/1.8/core/string/upto_spec.rb new file mode 100644 index 0000000000..9af93877fd --- /dev/null +++ b/1.8/core/string/upto_spec.rb @@ -0,0 +1,65 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes.rb' + +describe "String#upto" do + it "passes successive values, starting at self and ending at other_string, to the block" do + a = [] + "*+".upto("*3") { |s| a << s } + a.should == ["*+", "*,", "*-", "*.", "*/", "*0", "*1", "*2", "*3"] + end + + it "calls the block once even when start eqals stop" do + a = [] + "abc".upto("abc") { |s| a << s } + a.should == ["abc"] + end + + # This is weird but MRI behaves like that + it "upto calls block with self even if self is less than stop but stop length is less than self length" do + a = [] + "25".upto("5") { |s| a << s } + a.should == ["25"] + end + + it "upto doesn't call block if stop is less than self and stop length is less than self length" do + a = [] + "25".upto("1") { |s| a << s } + a.should == [] + end + + it "doesn't call the block if self is greater than stop" do + a = [] + "5".upto("2") { |s| a << s } + a.should == [] + end + + it "stops iterating as soon as the current value's character count gets higher than stop's" do + a = [] + "0".upto("A") { |s| a << s } + a.should == ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] + end + + it "returns self" do + "abc".upto("abd") { }.should == "abc" + "5".upto("2") { |i| i }.should == "5" + end + + it "tries to convert other to string using to_str" do + other = mock('abd') + def other.to_str() "abd" end + + a = [] + "abc".upto(other) { |s| a << s } + a.should == ["abc", "abd"] + end + + it "raises a TypeError if other can't be converted to a string" do + lambda { "abc".upto(123) }.should raise_error(TypeError) + lambda { "abc".upto(:def) { } }.should raise_error(TypeError) + lambda { "abc".upto(mock('x')) }.should raise_error(TypeError) + end + + it "raises a LocalJumpError if other is a string but no block was given" do + lambda { "abc".upto("def") }.should raise_error(LocalJumpError) + end +end diff --git a/1.8/core/struct/each_pair_spec.rb b/1.8/core/struct/each_pair_spec.rb new file mode 100644 index 0000000000..93f64a1f4a --- /dev/null +++ b/1.8/core/struct/each_pair_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#each_pair" do + it "passes each key value pair to the given block" do + car = Struct::Car.new('Ford', 'Ranger', 2001) + car.each_pair do |key, value| + value.should == car[key] + end + end + + it "fails if not passed a block" do + car = Struct::Car.new('Ford', 'Ranger') + lambda { car.each_pair }.should raise_error(LocalJumpError) + end +end diff --git a/1.8/core/struct/each_spec.rb b/1.8/core/struct/each_spec.rb new file mode 100644 index 0000000000..ce7d7a3596 --- /dev/null +++ b/1.8/core/struct/each_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#each" do + it "passes each value to the given block" do + car = Struct::Car.new('Ford', 'Ranger') + i = -1 + car.each do |value| + value.should == car[i += 1] + end + end + + it "fails if not passed a block" do + car = Struct::Car.new('Ford', 'Ranger') + lambda { car.each }.should raise_error(LocalJumpError) + end +end diff --git a/1.8/core/struct/element_reference_spec.rb b/1.8/core/struct/element_reference_spec.rb new file mode 100644 index 0000000000..cd909042ea --- /dev/null +++ b/1.8/core/struct/element_reference_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct[]" do + it "is a synonym for new" do + Struct::Ruby['2.0', 'i686'].class.should == Struct::Ruby + end +end + +describe "Struct#[]" do + it "returns the attribute referenced" do + car = Struct::Car.new('Ford', 'Ranger', 1983) + car['make'].should == 'Ford' + car['model'].should == 'Ranger' + car['year'].should == 1983 + car[:make].should == 'Ford' + car[:model].should == 'Ranger' + car[:year].should == 1983 + car[0].should == 'Ford' + car[1].should == 'Ranger' + car[2].should == 1983 + car[-3].should == 'Ford' + car[-2].should == 'Ranger' + car[-1].should == 1983 + end + + it "fails when it does not know about the requested attribute" do + car = Struct::Car.new('Ford', 'Ranger') + lambda { car[3] }.should raise_error(IndexError) + lambda { car[-4] }.should raise_error(IndexError) + lambda { car[:body] }.should raise_error(NameError) + lambda { car['wheels'] }.should raise_error(NameError) + end + + it "fails if passed too many arguments" do + car = Struct::Car.new('Ford', 'Ranger') + lambda { car[:make, :model] }.should raise_error(ArgumentError) + end + + it "fails if not passed a string, symbol, or integer" do + car = Struct::Car.new('Ford', 'Ranger') + lambda { car[Object.new] }.should raise_error(TypeError) + end +end diff --git a/1.8/core/struct/element_set_spec.rb b/1.8/core/struct/element_set_spec.rb new file mode 100644 index 0000000000..8064921d75 --- /dev/null +++ b/1.8/core/struct/element_set_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#[]=" do + it "assigns the passed value" do + car = Struct::Car.new('Ford', 'Ranger') + + car[:model] = 'Escape' + car[:model].should == 'Escape' + + car['model'] = 'Fusion' + car[:model].should == 'Fusion' + + car[1] = 'Excursion' + car[:model].should == 'Excursion' + + car[-1] = '2000-2005' + car[:year].should == '2000-2005' + end + + it "fails when trying to assign attributes which don't exist" do + car = Struct::Car.new('Ford', 'Ranger') + + lambda { car[:something] = true }.should raise_error(NameError) + lambda { car[3] = true }.should raise_error(IndexError) + lambda { car[-4] = true }.should raise_error(IndexError) + lambda { car[Object.new] = true }.should raise_error(TypeError) + end +end diff --git a/1.8/core/struct/eql_spec.rb b/1.8/core/struct/eql_spec.rb new file mode 100644 index 0000000000..763e814e4d --- /dev/null +++ b/1.8/core/struct/eql_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Struct#eql?" do + it_behaves_like(:struct_equal_value, :eql?) +end \ No newline at end of file diff --git a/1.8/core/struct/equal_value_spec.rb b/1.8/core/struct/equal_value_spec.rb new file mode 100644 index 0000000000..406a150451 --- /dev/null +++ b/1.8/core/struct/equal_value_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/equal_value' + +describe "Struct#==" do + it_behaves_like(:struct_equal_value, :==) +end diff --git a/1.8/core/struct/fixtures/classes.rb b/1.8/core/struct/fixtures/classes.rb new file mode 100644 index 0000000000..02fb77161d --- /dev/null +++ b/1.8/core/struct/fixtures/classes.rb @@ -0,0 +1,4 @@ +class Apple < Struct; end + +Struct.new('Ruby', :version, :platform) +Struct.new('Car', :make, :model, :year) diff --git a/1.8/core/struct/hash_spec.rb b/1.8/core/struct/hash_spec.rb new file mode 100644 index 0000000000..36618caf45 --- /dev/null +++ b/1.8/core/struct/hash_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#hash" do + + it "returns the same fixnum for structs with the same content" do + [Struct::Ruby.new("1.8.6", "PPC"), Struct::Car.new("Hugo", "Foo", "1972")].each do |stc| + stc.hash.should == stc.dup.hash + stc.hash.class.should == Fixnum + end + end + + it "returns the same value if structs are #eql?" do + car = Struct::Car.new("Honda", "Accord", "1998") + similar_car = Struct::Car.new("Honda", "Accord", "1998") + car.eql?(similar_car).should == true + car.hash.should == similar_car.hash + end + +end \ No newline at end of file diff --git a/1.8/core/struct/initialize_copy_spec.rb b/1.8/core/struct/initialize_copy_spec.rb new file mode 100644 index 0000000000..6b5ee5082e --- /dev/null +++ b/1.8/core/struct/initialize_copy_spec.rb @@ -0,0 +1,3 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + diff --git a/1.8/core/struct/initialize_spec.rb b/1.8/core/struct/initialize_spec.rb new file mode 100644 index 0000000000..3a8d7cbf72 --- /dev/null +++ b/1.8/core/struct/initialize_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#initialize" do + + it "is private" do + Struct::Car.private_instance_methods.map { |m| m.to_s }.include?("initialize").should == true + end + + it "does nothing when passed a set of fields equal to self" do + car = same_car = Struct::Car.new("Honda", "Accord", "1998") + car.instance_eval { initialize("Honda", "Accord", "1998") } + car.should == same_car + end + +end \ No newline at end of file diff --git a/1.8/core/struct/inspect_spec.rb b/1.8/core/struct/inspect_spec.rb new file mode 100644 index 0000000000..4e8ecafb58 --- /dev/null +++ b/1.8/core/struct/inspect_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#inspect" do + it "returns a string representation of some kind" do + car = Struct::Car.new('Ford', 'Ranger') + car.inspect.should == '#' + Whiskey = Struct.new(:name, :ounces) + Whiskey.new('Jack', 100).inspect.should == '#' + end +end diff --git a/1.8/core/struct/length_spec.rb b/1.8/core/struct/length_spec.rb new file mode 100644 index 0000000000..7ec58f3a61 --- /dev/null +++ b/1.8/core/struct/length_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#length" do + it "returns the number of attributes" do + Struct::Car.new('Cadillac', 'DeVille').length.should == 3 + Struct::Car.new.length.should == 3 + end +end diff --git a/1.8/core/struct/members_spec.rb b/1.8/core/struct/members_spec.rb new file mode 100644 index 0000000000..69d427b69b --- /dev/null +++ b/1.8/core/struct/members_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#members" do + it "returns an array of attribute names" do + Struct::Car.new.members.should == %w(make model year) + Struct::Car.new('Cadillac').members.should == %w(make model year) + Struct::Ruby.members.should == %w(version platform) + end +end diff --git a/1.8/core/struct/new_spec.rb b/1.8/core/struct/new_spec.rb new file mode 100644 index 0000000000..af82abe590 --- /dev/null +++ b/1.8/core/struct/new_spec.rb @@ -0,0 +1,124 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct.new" do + it "creates a constant in Struct namespace with string as first argument" do + struct = Struct.new('Animal', :name, :legs, :eyeballs) + struct.should == Struct::Animal + struct.name.should == "Struct::Animal" + end + + it "overwrites previously defined constants with string as first argument" do + first = Struct.new('Person', :height, :weight) + first.should == Struct::Person + + old, $VERBOSE = $VERBOSE, nil + second = Struct.new('Person', :hair, :sex) + second.should == Struct::Person + $VERBOSE = old + + first.members.should_not == second.members + end + + it "calls to_str on its first argument (constant name)" do + obj = mock('Foo') + def obj.to_str() "Foo" end + struct = Struct.new(obj) + struct.should == Struct::Foo + struct.name.should == "Struct::Foo" + end + + it "creates a new anonymous class with nil first argument" do + struct = Struct.new(nil, :foo) + struct.new("bar").foo.should == "bar" + struct.class.should == Class + struct.name.should == "" + end + + it "does not create a constant with symbol as first argument" do + struct = Struct.new(:Animal, :name, :legs, :eyeballs) + struct.should_not == Struct::Animal + end + + it "creates a new anonymous class with symbol arguments" do + struct = Struct.new(:make, :model) + struct.class.should == Class + struct.name.should == "" + end + + it "fails with invalid constant name as first argument" do + lambda { Struct.new('animal', :name, :legs, :eyeballs) }.should raise_error(NameError) + end + + it "raises a TypeError if object doesn't respond to to_sym" do + lambda { Struct.new(:animal, mock('giraffe')) }.should raise_error(TypeError) + lambda { Struct.new(:animal, 1.0) }.should raise_error(TypeError) + lambda { Struct.new(:animal, Time.now) }.should raise_error(TypeError) + lambda { Struct.new(:animal, Class) }.should raise_error(TypeError) + lambda { Struct.new(:animal, nil) }.should raise_error(TypeError) + lambda { Struct.new(:animal, true) }.should raise_error(TypeError) + lambda { Struct.new(:animal, ['chris', 'evan']) }.should raise_error(TypeError) + lambda { Struct.new(:animal, { :name => 'chris' }) }.should raise_error(TypeError) + end + + compliant_on :ruby, :jruby do + it "raises a TypeError if object is not a Symbol" do + obj = mock(':ruby') + def obj.to_sym() :ruby end + lambda { Struct.new(:animal, obj) }.should raise_error(TypeError) + end + end + + compliant_on :rbx do + it "calls to_sym if object responds to to_sym" do + obj = mock(':ruby') + def obj.to_sym() :ruby end + Struct.new(:animal, obj).new(nil, "bar").ruby.should == "bar" + end + end + + not_compliant_on :rubinius do + it "accepts Fixnums as Symbols unless fixnum.to_sym.nil?" do + old, $VERBOSE = $VERBOSE, nil + num = :foo.to_i + Struct.new(nil, num).new("bar").foo.should == "bar" + $VERBOSE = old + end + + it "raises an ArgumentError if fixnum#to_sym is nil" do + old, $VERBOSE = $VERBOSE, nil + num = 10000 + num.to_sym.should == nil # if this fails, we need a new Fixnum to test + lambda { Struct.new(:animal, num) }.should raise_error(ArgumentError) + $VERBOSE = old + end + end + + it "instance_eval's a passed block" do + klass = Struct.new(:something) { @something_else = 'something else entirely!' } + klass.instance_variables.should include('@something_else') + end + + it "creates a constant in subclass' namespace" do + struct = Apple.new('Computer', :size) + struct.should == Apple::Computer + end + + it "creates an instance" do + Struct::Ruby.new.kind_of?(Struct::Ruby).should == true + end + + it "creates reader methods" do + Struct::Ruby.new.methods.should include 'version' + Struct::Ruby.new.methods.should include 'platform' + end + + it "creates writer methods" do + Struct::Ruby.new.methods.should include 'version=' + Struct::Ruby.new.methods.should include 'platform=' + end + + it "fails with too many arguments" do + lambda { Struct::Ruby.new('2.0', 'i686', true) }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/struct/select_spec.rb b/1.8/core/struct/select_spec.rb new file mode 100644 index 0000000000..dc8e2d35dd --- /dev/null +++ b/1.8/core/struct/select_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#select" do + it "raises an ArgumentError if given any non-block arguments" do + lambda { Struct::Car.new.select(1) { } }.should raise_error(ArgumentError) + end + + it "returns a new array of elements for which block is true" do + struct = Struct::Car.new("Toyota", "Tercel", "2000") + struct.select { |i| i == "2000" }.should == [ "2000" ] + end + + it "returns an instance of Array" do + struct = Struct::Car.new("Ford", "Escort", "1995") + struct.select { true }.class.should == Array + end +end \ No newline at end of file diff --git a/1.8/core/struct/shared/equal_value.rb b/1.8/core/struct/shared/equal_value.rb new file mode 100644 index 0000000000..78686c0372 --- /dev/null +++ b/1.8/core/struct/shared/equal_value.rb @@ -0,0 +1,22 @@ +shared :struct_equal_value do |cmd| + describe "Struct##{cmd}" do + + it "returns true if the other is the same object" do + car = same_car = Struct::Car.new("Honda", "Accord", "1998") + car.send(cmd, same_car).should == true + end + + it "returns true if the other has all the same fields" do + car = Struct::Car.new("Honda", "Accord", "1998") + similar_car = Struct::Car.new("Honda", "Accord", "1998") + car.send(cmd, similar_car).should == true + end + + it "returns false if the other is a different object or has different fields" do + car = Struct::Car.new("Honda", "Accord", "1998") + different_car = Struct::Car.new("Honda", "Accord", "1995") + car.send(cmd, different_car).should == false + end + + end +end diff --git a/1.8/core/struct/size_spec.rb b/1.8/core/struct/size_spec.rb new file mode 100644 index 0000000000..4295246e53 --- /dev/null +++ b/1.8/core/struct/size_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#size" do + it "is a synonym for length" do + Struct::Car.new.size.should == Struct::Car.new.length + end +end diff --git a/1.8/core/struct/struct_spec.rb b/1.8/core/struct/struct_spec.rb new file mode 100644 index 0000000000..c8d025998d --- /dev/null +++ b/1.8/core/struct/struct_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct anonymous class instance methods" do + it "Enumerable methods should work" do + car = Struct::Car.new('Ford', 'Ranger', '2001') + car.detect { |value| value.include? 'F' }.should == 'Ford' + car.reject { |value| value.include? 'F' }.should == ['Ranger', '2001'] + end + + it "reader method should be a synonym for []" do + klass = Struct.new(:clock, :radio) + alarm = klass.new(true) + alarm.clock.should == alarm[:clock] + alarm.radio.should == alarm['radio'] + end + + it "reader method should not interfere with undefined methods" do + car = Struct::Car.new('Ford', 'Ranger') + lambda { car.something_weird }.should raise_error(NoMethodError) + end + + it "writer method be a synonym for []=" do + car = Struct::Car.new('Ford', 'Ranger') + car.model.should == 'Ranger' + car.model = 'F150' + car.model.should == 'F150' + car[:model].should == 'F150' + car['model'].should == 'F150' + car[1].should == 'F150' + end +end + +describe "Struct subclasses" do + it "can be subclassed" do + compact = Class.new Struct::Car + compact.new.class.should == compact + end +end + diff --git a/1.8/core/struct/to_a_spec.rb b/1.8/core/struct/to_a_spec.rb new file mode 100644 index 0000000000..9b76d0ba6f --- /dev/null +++ b/1.8/core/struct/to_a_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#to_a" do + it "returns the values for this instance as an array" do + Struct::Car.new('Geo', 'Metro', 1995).to_a.should == ['Geo', 'Metro', 1995] + Struct::Car.new('Ford').to_a.should == ['Ford', nil, nil] + end +end diff --git a/1.8/core/struct/to_s_spec.rb b/1.8/core/struct/to_s_spec.rb new file mode 100644 index 0000000000..b89a2319e6 --- /dev/null +++ b/1.8/core/struct/to_s_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#to_s" do + it "is a synonym for inspect" do + car = Struct::Car.new('Ford', 'Ranger') + car.inspect.should == car.to_s + end +end diff --git a/1.8/core/struct/values_at_spec.rb b/1.8/core/struct/values_at_spec.rb new file mode 100644 index 0000000000..64d470f107 --- /dev/null +++ b/1.8/core/struct/values_at_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#values_at" do + it "returns an array of values" do + clazz = Struct.new(:name, :director, :year) + movie = clazz.new('Sympathy for Mr. Vengence', 'Chan-wook Park', 2002) + movie.values_at(0, 1).should == ['Sympathy for Mr. Vengence', 'Chan-wook Park'] + movie.values_at(0..2).should == ['Sympathy for Mr. Vengence', 'Chan-wook Park', 2002] + end + + it "fails when passed unsupported types" do + car = Struct::Car.new('Ford', 'Ranger') + lambda { car.values_at('make') }.should raise_error(TypeError) + end +end diff --git a/1.8/core/struct/values_spec.rb b/1.8/core/struct/values_spec.rb new file mode 100644 index 0000000000..52d7ab1012 --- /dev/null +++ b/1.8/core/struct/values_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Struct#values" do + it "is a synonym for to_a" do + car = Struct::Car.new('Nissan', 'Maxima') + car.values.should == car.to_a + + Struct::Car.new.values.should == Struct::Car.new.to_a + end +end diff --git a/1.8/core/symbol/all_symbols_spec.rb b/1.8/core/symbol/all_symbols_spec.rb new file mode 100644 index 0000000000..20c317b071 --- /dev/null +++ b/1.8/core/symbol/all_symbols_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Symbol.all_symbols" do + it "returns an array containing all the Symbols in the symbol table" do + Symbol.all_symbols.is_a?(Array).should == true + Symbol.all_symbols.all? { |s| s.is_a?(Symbol) ? true : (p s; false) }.should == true + end + # it "is a pain in the ass to test..." +end diff --git a/1.8/core/symbol/case_compare_spec.rb b/1.8/core/symbol/case_compare_spec.rb new file mode 100644 index 0000000000..a23cc5b125 --- /dev/null +++ b/1.8/core/symbol/case_compare_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Symbol#===" do + it "returns true when the other is a Symbol" do + (Symbol === :ruby).should == true + (Symbol === :"ruby").should == true + (Symbol === :'ruby').should == true + (Symbol === 'ruby').should == false + end +end + +# Symbol === :fnord \ No newline at end of file diff --git a/1.8/core/symbol/equal_value_spec.rb b/1.8/core/symbol/equal_value_spec.rb new file mode 100644 index 0000000000..814a583e89 --- /dev/null +++ b/1.8/core/symbol/equal_value_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Symbol#==" do + it "only returns true when the other is exactly the same symbol" do + (:ruby == :ruby).should == true + (:ruby == :"ruby").should == true + (:ruby == :'ruby').should == true + (:@ruby == :@ruby).should == true + + (:ruby == :@ruby).should == false + (:foo == :bar).should == false + (:ruby == 'ruby').should == false + end +end diff --git a/1.8/core/symbol/id2name_spec.rb b/1.8/core/symbol/id2name_spec.rb new file mode 100644 index 0000000000..b591a4185a --- /dev/null +++ b/1.8/core/symbol/id2name_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/id2name' + +describe "Symbol#id2name" do + it_behaves_like(:symbol_id2name, :id2name) +end diff --git a/1.8/core/symbol/inspect_spec.rb b/1.8/core/symbol/inspect_spec.rb new file mode 100644 index 0000000000..a183dbc587 --- /dev/null +++ b/1.8/core/symbol/inspect_spec.rb @@ -0,0 +1,104 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Symbol#inspect" do + symbols = { + :fred => ":fred", + :fred? => ":fred?", + :fred! => ":fred!", + :$ruby => ":$ruby", + :@ruby => ":@ruby", + :@@ruby => ":@@ruby", + :"$ruby!" => ":\"$ruby!\"", + :"$ruby?" => ":\"$ruby?\"", + :"@ruby!" => ":\"@ruby!\"", + :"@ruby?" => ":\"@ruby?\"", + :"@@ruby!" => ":\"@@ruby!\"", + :"@@ruby?" => ":\"@@ruby?\"", + + :$-w => ":$-w", + :"$-ww" => ":\"$-ww\"", + :"$+" => ":$+", + :"$~" => ":$~", + :"$:" => ":$:", + :"$?" => ":$?", + :"$<" => ":$<", + :"$_" => ":$_", + :"$/" => ":$/", + :"$'" => ":$'", + :"$\"" => ":$\"", + :"$$" => ":$$", + :"$." => ":$.", + :"$," => ":$,", + :"$`" => ":$`", + :"$!" => ":$!", + :"$;" => ":$;", + :"$\\" => ":$\\", + :"$=" => ":$=", + :"$*" => ":$*", + :"$>" => ":$>", + :"$&" => ":$&", + :"$@" => ":$@", + :"$1234" => ":$1234", + + :-@ => ":-@", + :+@ => ":+@", + :% => ":%", + :& => ":&", + :* => ":*", + :** => ":**", + :"/" => ":/", # lhs quoted for emacs happiness + :< => ":<", + :<= => ":<=", + :<=> => ":<=>", + :== => ":==", + :=== => ":===", + :=~ => ":=~", + :> => ":>", + :>= => ":>=", + :>> => ":>>", + :[] => ":[]", + :[]= => ":[]=", + :"\<\<" => ":\<\<", + :^ => ":^", + :"`" => ":`", # for emacs, and justice! + :~ => ":~", + :| => ":|", + + :"!" => ":\"!\"", + :"!=" => ":\"!=\"", + :"!~" => ":\"!~\"", + :"\$" => ":\"$\"", # for justice! + :"&&" => ":\"&&\"", + :"'" => ":\"\'\"", + :"," => ":\",\"", + :"." => ":\".\"", + :".." => ":\"..\"", + :"..." => ":\"...\"", + :":" => ":\":\"", + :"::" => ":\"::\"", + :";" => ":\";\"", + :"=" => ":\"=\"", + :"=>" => ":\"=>\"", + :"\?" => ":\"?\"", # rawr! + :"@" => ":\"@\"", + :"||" => ":\"||\"", + :"|||" => ":\"|||\"", + :"++" => ":\"++\"", + + :"\"" => ":\"\\\"\"", + :"\"\"" => ":\"\\\"\\\"\"", + + :"9" => ":\"9\"", + :"foo bar" => ":\"foo bar\"", + :"*foo" => ":\"*foo\"", + :"foo " => ":\"foo \"", + :" foo" => ":\" foo\"", + :" " => ":\" \"", + } + + symbols.each do |input, expected| + it "returns self as a symbol literal for #{expected}" do + input.inspect.should == expected + end + end +end diff --git a/1.8/core/symbol/shared/id2name.rb b/1.8/core/symbol/shared/id2name.rb new file mode 100644 index 0000000000..3d824572b4 --- /dev/null +++ b/1.8/core/symbol/shared/id2name.rb @@ -0,0 +1,11 @@ +shared :symbol_id2name do |cmd| + describe "Symbol\##{cmd}" do + it "returns the string corresponding to self" do + :rubinius.send(cmd).should == "rubinius" + :squash.send(cmd).should == "squash" + :[].send(cmd).should == "[]" + :@ruby.send(cmd).should == "@ruby" + :@@ruby.send(cmd).should == "@@ruby" + end + end +end diff --git a/1.8/core/symbol/to_i_spec.rb b/1.8/core/symbol/to_i_spec.rb new file mode 100644 index 0000000000..75d7dd6699 --- /dev/null +++ b/1.8/core/symbol/to_i_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Symbol#to_i" do + not_compliant_on :rubinius do + it "returns an integer that is unique for each symbol for each program execution" do + :ruby.to_i.is_a?(Integer).should == true + :ruby.to_i.should == :ruby.to_i + :ruby.to_i.should_not == :rubinius.to_i + end + end +end diff --git a/1.8/core/symbol/to_int_spec.rb b/1.8/core/symbol/to_int_spec.rb new file mode 100644 index 0000000000..35ed14f035 --- /dev/null +++ b/1.8/core/symbol/to_int_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Symbol#to_int" do + not_compliant_on :rubinius do + it "returns Symbol#to_i" do + :ruby.to_int.is_a?(Integer).should == true + :ruby.to_int.should == :ruby.to_i + :ruby.to_int.should_not == :rubinius.to_i + end + end +end diff --git a/1.8/core/symbol/to_s_spec.rb b/1.8/core/symbol/to_s_spec.rb new file mode 100644 index 0000000000..f839b58d06 --- /dev/null +++ b/1.8/core/symbol/to_s_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/id2name' + +describe "Symbol#to_s" do + it_behaves_like(:symbol_id2name, :to_s) +end diff --git a/1.8/core/symbol/to_sym_spec.rb b/1.8/core/symbol/to_sym_spec.rb new file mode 100644 index 0000000000..360e73e8cb --- /dev/null +++ b/1.8/core/symbol/to_sym_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Symbol#to_sym" do + it "returns self" do + [:rubinius, :squash, :[], :@ruby, :@@ruby].each do |sym| + sym.to_sym.should == sym + end + end +end diff --git a/1.8/core/thread/abort_on_exception_spec.rb b/1.8/core/thread/abort_on_exception_spec.rb new file mode 100644 index 0000000000..67cd8310ad --- /dev/null +++ b/1.8/core/thread/abort_on_exception_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#abort_on_exception" do + it "is false unless $DEBUG is true" do + Thread.abort_on_exception.should == false unless $DEBUG + end + + it "is true if $DEBUG is true" do + Thread.abort_on_exception.should == true if $DEBUG + end + + it "is changeable to true or false" do + Thread.abort_on_exception = true + Thread.abort_on_exception.should == true + Thread.abort_on_exception = false + Thread.abort_on_exception.should == false + end + +end \ No newline at end of file diff --git a/1.8/core/thread/alive_spec.rb b/1.8/core/thread/alive_spec.rb new file mode 100644 index 0000000000..99f0e5d5b2 --- /dev/null +++ b/1.8/core/thread/alive_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#alive?" do + it "returns true as long as the thread is alive" do + c = Channel.new + t = Thread.new { c.receive } + begin + t.alive?.should == true + ensure + c << nil + end + end + + it "returns false when the thread is finished" do + t = Thread.new { } + t.join + t.alive?.should == false + end +end diff --git a/1.8/core/thread/critical_spec.rb b/1.8/core/thread/critical_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/critical_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/current_spec.rb b/1.8/core/thread/current_spec.rb new file mode 100644 index 0000000000..843d495831 --- /dev/null +++ b/1.8/core/thread/current_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread.current" do + it "returns a thread" do + current = Thread.current + current.class.should == Thread + end + + it "returns the current thread" do + t = Thread.new { Thread.current } + t.value.should.equal? t + Thread.current.should_not.equal? t.value + end +end diff --git a/1.8/core/thread/element_reference_spec.rb b/1.8/core/thread/element_reference_spec.rb new file mode 100644 index 0000000000..5c2ddaf0ff --- /dev/null +++ b/1.8/core/thread/element_reference_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#[]" do + it "gives access to thread local values" do + th = Thread.new do + Thread.current[:value] = 5 + end + th.join + th[:value].should == 5 + Thread.current[:value].should == nil + end + + it "is not shared across threads" do + t1 = Thread.new do + Thread.current[:value] = 1 + end + t2 = Thread.new do + Thread.current[:value] = 2 + end + [t1,t2].each {|x| x.join} + t1[:value].should == 1 + t2[:value].should == 2 + end + + it "is accessable using strings or symbols" do + t1 = Thread.new do + Thread.current[:value] = 1 + end + t2 = Thread.new do + Thread.current["value"] = 2 + end + [t1,t2].each {|x| x.join} + t1[:value].should == 1 + t1["value"].should == 1 + t2[:value].should == 2 + t2["value"].should == 2 + end + + it "raises exceptions on the wrong type of keys" do + lambda { Thread.current[nil] }.should raise_error(TypeError) + lambda { Thread.current[5] }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/thread/element_set_spec.rb b/1.8/core/thread/element_set_spec.rb new file mode 100644 index 0000000000..a6c72ae826 --- /dev/null +++ b/1.8/core/thread/element_set_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#[]=" do + it "raises exceptions on the wrong type of keys" do + lambda { Thread.current[nil] = true }.should raise_error(TypeError) + lambda { Thread.current[5] = true }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/thread/exit_spec.rb b/1.8/core/thread/exit_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/exit_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/fixtures/classes.rb b/1.8/core/thread/fixtures/classes.rb new file mode 100644 index 0000000000..7dfe5e92d1 --- /dev/null +++ b/1.8/core/thread/fixtures/classes.rb @@ -0,0 +1,6 @@ +unless defined? Channel + require 'thread' + class Channel < Queue + alias receive shift + end +end diff --git a/1.8/core/thread/fork_spec.rb b/1.8/core/thread/fork_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/fork_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/group_spec.rb b/1.8/core/thread/group_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/group_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/initialize_spec.rb b/1.8/core/thread/initialize_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/initialize_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/inspect_spec.rb b/1.8/core/thread/inspect_spec.rb new file mode 100644 index 0000000000..d30988c103 --- /dev/null +++ b/1.8/core/thread/inspect_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#inspect" do + it "can check it's own status" do + t = Thread.new { Thread.current.inspect } + t.value.should include('run') + end + + it "describes a sleeping thread" do + c = Channel.new + t = Thread.new do + sleep + c << Thread.current.inspect + sleep + end + + Thread.pass until t.status == 'sleep' + t.inspect.should include('sleep') + t.run + c.receive.should include('run') + Thread.pass until t.status == 'sleep' + t.inspect.should include('sleep') + t.run + t.join + t.inspect.should include('dead') + end + + compliant_on(:ruby) do + it "reports aborting on a killed thread" do + c = Channel.new + t = Thread.new { c << Thread.current.inspect; Thread.stop } + c.receive.should include('run') + t.inspect.should include('sleep') + Thread.critical = true + t.kill + t.inspect.should include('aborting') + Thread.critical = false + end + end +end diff --git a/1.8/core/thread/join_spec.rb b/1.8/core/thread/join_spec.rb new file mode 100644 index 0000000000..956c4997aa --- /dev/null +++ b/1.8/core/thread/join_spec.rb @@ -0,0 +1,42 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#join" do + it "returns the thread when it is finished" do + t = Thread.new {} + t.join.should.equal? t + end + + it "returns the thread when it is finished when given a timeout" do + t = Thread.new {} + t.join + t.join(0).should.equal? t + end + + it "returns nil if it is not finished when given a timeout" do + c = Channel.new + t = Thread.new { c.receive } + begin + t.join(0).should == nil + ensure + c << true + end + t.join.should == t + end + + it "accepts a floating point timeout length" do + c = Channel.new + t = Thread.new { c.receive } + begin + t.join(0.01).should == nil + ensure + c << true + end + t.join.should == t + end + + it "raises any exceptions encountered in the thread body" do + t = Thread.new { raise NotImplementedError.new("Just kidding") } + lambda { t.join }.should raise_error(NotImplementedError) + end +end diff --git a/1.8/core/thread/key_spec.rb b/1.8/core/thread/key_spec.rb new file mode 100644 index 0000000000..d8d0c6097c --- /dev/null +++ b/1.8/core/thread/key_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#key?" do + before :each do + @th = Thread.new do + Thread.current[:oliver] = "a" + end + @th.join + end + + it "tests for existance of thread local variables using symbols or strings" do + @th.key?(:oliver).should == true + @th.key?("oliver").should == true + @th.key?(:stanley).should == false + @th.key?(:stanley.to_s).should == false + end + + it "raises exceptions on the wrong type of keys" do + lambda { Thread.current.key? nil }.should raise_error(TypeError) + lambda { Thread.current.key? 5 }.should raise_error(ArgumentError) + end +end diff --git a/1.8/core/thread/keys_spec.rb b/1.8/core/thread/keys_spec.rb new file mode 100644 index 0000000000..a3b5379e33 --- /dev/null +++ b/1.8/core/thread/keys_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#keys" do + it "returns an array of the names of the thread-local variables as symbols" do + th = Thread.new do + Thread.current["cat"] = 'woof' + Thread.current[:cat] = 'meow' + Thread.current[:dog] = 'woof' + end + th.join + th.keys.sort_by {|x| x.to_s}.should == [:cat,:dog] + end +end diff --git a/1.8/core/thread/kill_spec.rb b/1.8/core/thread/kill_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/kill_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/list_spec.rb b/1.8/core/thread/list_spec.rb new file mode 100644 index 0000000000..99091937fc --- /dev/null +++ b/1.8/core/thread/list_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread::list" do + it "includes the current and main thread" do + Thread.list.should include(Thread.current) + Thread.list.should include(Thread.main) + end + + it "does not include deceased threads" do + t = Thread.new { 1; } + t.join + Thread.list.should_not include(t) + end + + it "includes waiting threads" do + c = Channel.new + t = Thread.new { c.receive } + t.run + begin + Thread.list.should include(t) + ensure + c << nil + t.join + end + end +end diff --git a/1.8/core/thread/main_spec.rb b/1.8/core/thread/main_spec.rb new file mode 100644 index 0000000000..461475c843 --- /dev/null +++ b/1.8/core/thread/main_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread.main" do + it "returns the main thread" do + Thread.new { @main = Thread.main ; @current = Thread.current}.join + @main.should_not == @current + @main.should == Thread.current + end +end diff --git a/1.8/core/thread/new_spec.rb b/1.8/core/thread/new_spec.rb new file mode 100644 index 0000000000..7c94f525e3 --- /dev/null +++ b/1.8/core/thread/new_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread.new" do + it "creates a thread executing the given block" do + c = Channel.new + Thread.new { c << true }.join + c << false + c.receive.should == true + end + + it "can pass arguments to the thread block" do + arr = [] + a, b, c = 1, 2, 3 + t = Thread.new(a,b,c) {|d,e,f| arr << d << e << f } + t.join + arr.should == [a,b,c] + end +end diff --git a/1.8/core/thread/pass_spec.rb b/1.8/core/thread/pass_spec.rb new file mode 100644 index 0000000000..16d5bca298 --- /dev/null +++ b/1.8/core/thread/pass_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread.pass" do + it "returns nil" do + Thread.pass.should == nil + end +end diff --git a/1.8/core/thread/priority_spec.rb b/1.8/core/thread/priority_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/priority_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/raise_spec.rb b/1.8/core/thread/raise_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/raise_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/run_spec.rb b/1.8/core/thread/run_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/run_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/safe_level_spec.rb b/1.8/core/thread/safe_level_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/safe_level_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/start_spec.rb b/1.8/core/thread/start_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/start_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/status_spec.rb b/1.8/core/thread/status_spec.rb new file mode 100644 index 0000000000..eef6f8232c --- /dev/null +++ b/1.8/core/thread/status_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#status" do + it "reports threads as running and returns false on correct termination" do + t = Thread.new { Thread.current.status } + t.value.should == 'run' + t.status.should == false + end + + it "returns nil if thread terminates with exception" do + t = Thread.new { raise "death to the unbelievers" } + lambda { t.join }.should raise_error(StandardError) + t.status.should == nil + end +end diff --git a/1.8/core/thread/stop_spec.rb b/1.8/core/thread/stop_spec.rb new file mode 100644 index 0000000000..7b8aa7a765 --- /dev/null +++ b/1.8/core/thread/stop_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread.stop" do + it "causes the current thread to sleep indefinitely" do + t = Thread.new { Thread.stop; 5 } + Thread.pass until t.status == 'sleep' + t.status.should == 'sleep' + t.run + t.value.should == 5 + end + + it "resets Thread.critical to false" do + t = Thread.new { Thread.critical = true; Thread.stop } + Thread.pass until t.status == 'sleep' + Thread.critical.should == false + t.run + t.join + end +end + +describe "Thread#stop?" do + it "reports if a thread has stopped due to sleeping" do + t = Thread.new { Thread.stop } + Thread.pass until t.status == 'sleep' + t.stop?.should == true + t.run + t.join + t.stop?.should == true + end +end diff --git a/1.8/core/thread/terminate_spec.rb b/1.8/core/thread/terminate_spec.rb new file mode 100644 index 0000000000..f91d1839dd --- /dev/null +++ b/1.8/core/thread/terminate_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' \ No newline at end of file diff --git a/1.8/core/thread/value_spec.rb b/1.8/core/thread/value_spec.rb new file mode 100644 index 0000000000..6dc0b134c3 --- /dev/null +++ b/1.8/core/thread/value_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#value" do + it "returns the result of the block" do + Thread.new { 3 }.value.should == 3 + end +end diff --git a/1.8/core/thread/wakeup_spec.rb b/1.8/core/thread/wakeup_spec.rb new file mode 100644 index 0000000000..60b87e4a52 --- /dev/null +++ b/1.8/core/thread/wakeup_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Thread#wakeup" do + ruby_bug do + it "does not result in a deadlock" do + c = Channel.new + t1 = Thread.new do + loop do + c << t1 + c << t1 + Thread.stop + end + end + t2 = Thread.new do + loop do + c << t2 + Thread.stop + end + end + + count1 = 0 + count2 = 0 + while(count1 < 10) do + case c.receive + when t1; count1+=1 + when t2; count2+=1 + end + t1.wakeup + t2.wakeup + end + count1.should > count2 + + t1.kill + t2.kill + end + end +end diff --git a/1.8/core/threadgroup/add_spec.rb b/1.8/core/threadgroup/add_spec.rb new file mode 100644 index 0000000000..1c79d06974 --- /dev/null +++ b/1.8/core/threadgroup/add_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "ThreadGroup#add" do + before(:each) do + @chan1,@chan2 = Channel.new,Channel.new + @thread = Thread.new { @chan1 << :go; @chan2.receive } + @chan1.receive + end + + after(:each) do + @chan2 << :done + @thread.join + end + + it "adds the given thread to a group and returns self" do + @thread.group.should_not == nil + + tg = ThreadGroup.new + tg.add(@thread).should == tg + @thread.group.should == tg + tg.list.include?(@thread).should == true + end + + it "removes itself from any other threadgroup" do + tg1 = ThreadGroup.new + tg2 = ThreadGroup.new + + tg1.add(@thread) + @thread.group.should == tg1 + tg2.add(@thread) + @thread.group.should == tg2 + tg2.list.include?(@thread).should == true + tg1.list.include?(@thread).should == false + end +end diff --git a/1.8/core/threadgroup/enclose_spec.rb b/1.8/core/threadgroup/enclose_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/threadgroup/enclose_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/threadgroup/enclosed_spec.rb b/1.8/core/threadgroup/enclosed_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/core/threadgroup/enclosed_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/core/threadgroup/fixtures/classes.rb b/1.8/core/threadgroup/fixtures/classes.rb new file mode 100644 index 0000000000..7dfe5e92d1 --- /dev/null +++ b/1.8/core/threadgroup/fixtures/classes.rb @@ -0,0 +1,6 @@ +unless defined? Channel + require 'thread' + class Channel < Queue + alias receive shift + end +end diff --git a/1.8/core/threadgroup/list_spec.rb b/1.8/core/threadgroup/list_spec.rb new file mode 100644 index 0000000000..2229ac25ee --- /dev/null +++ b/1.8/core/threadgroup/list_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "ThreadGroup#list" do + it "returns the list of threads in the group" do + chan = Channel.new + th1 = Thread.new { chan << :go; sleep } + chan.receive.should == :go + tg = ThreadGroup.new + tg.add(th1) + tg.list.should include(th1) + + th2 = Thread.new { chan << :go; sleep } + chan.receive.should == :go + + tg.add(th2) + (tg.list & [th1, th2]).should include(th1, th2) + + th1.run; th1.join + th2.run; th2.join + end +end diff --git a/1.8/core/time/_dump_spec.rb b/1.8/core/time/_dump_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/_dump_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/_load_spec.rb b/1.8/core/time/_load_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/_load_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/asctime_spec.rb b/1.8/core/time/asctime_spec.rb new file mode 100644 index 0000000000..4836b92e1c --- /dev/null +++ b/1.8/core/time/asctime_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/asctime' + +describe "Time#asctime" do + it_behaves_like(:time_asctime, :asctime) +end diff --git a/1.8/core/time/at_spec.rb b/1.8/core/time/at_spec.rb new file mode 100644 index 0000000000..c14e91d19d --- /dev/null +++ b/1.8/core/time/at_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time.at" do + it "converts to time object" do + # the #chomp calls are necessary because of RSpec + Time.at(1168475924).inspect.chomp.should == localtime(1168475924).chomp + end + + it "creates a new time object with the value given by time" do + t = Time.now + Time.at(t).inspect.should == t.inspect + end + + it "creates a dup time object with the value given by time" do + t1 = Time.new + t2 = Time.at(t1) + t1.object_id.should_not == t2.object_id + end + + it "is able to create a time object with a float" do + t = Time.at(10.5) + t.usec.should == 500000.0 + t.should_not == Time.at(10) + end + + it "is able to create a time object with a microseconds" do + t = Time.at(10, 500000) + t.usec.should == 500000.0 + t.should_not == Time.at(10) + end + +end diff --git a/1.8/core/time/comparison_spec.rb b/1.8/core/time/comparison_spec.rb new file mode 100644 index 0000000000..16d298b16d --- /dev/null +++ b/1.8/core/time/comparison_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#<=>" do + it "returns 1 if the first argument is a point in time after the second argument" do + (Time.now <=> Time.at(0)).should == 1 + (Time.at(0, 100) <=> Time.at(0, 0)).should == 1 + (Time.at(1202778512, 100) <=> Time.at(1202778512, 99)).should == 1 + end + + it "returns 0 if time is the same as other" do + (Time.at(1202778513) <=> Time.at(1202778513)).should == 0 + (Time.at(100, 100) <=> Time.at(100, 100)).should == 0 + end + + it "returns -1 if the first argument is a point in time before the second argument" do + (Time.at(0) <=> Time.now).should == -1 + (Time.at(0, 0) <=> Time.at(0, 100)).should == -1 + (Time.at(100, 100) <=> Time.at(101, 100)).should == -1 + end + + # see [ruby-core:15333] + it "returns nil when Time is compared to Numeric" do + (Time.at(100) <=> 100).should == nil + (Time.at(100) <=> 100.0).should == nil + end + + it "returns nil when Time is compared to some Object" do + (Time.at(100) <=> Object.new).should == nil + end +end diff --git a/1.8/core/time/ctime_spec.rb b/1.8/core/time/ctime_spec.rb new file mode 100644 index 0000000000..88312890ea --- /dev/null +++ b/1.8/core/time/ctime_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/asctime' + +describe "Time#ctime" do + it_behaves_like(:time_asctime, :ctime) +end diff --git a/1.8/core/time/day_spec.rb b/1.8/core/time/day_spec.rb new file mode 100644 index 0000000000..d5aa8a2b7d --- /dev/null +++ b/1.8/core/time/day_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/day' + +describe "Time#day" do + it_behaves_like(:time_day, :day) +end diff --git a/1.8/core/time/dst_spec.rb b/1.8/core/time/dst_spec.rb new file mode 100644 index 0000000000..37a5583c4a --- /dev/null +++ b/1.8/core/time/dst_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/isdst' + +describe "Time#dst?" do + it_behaves_like(:time_isdst, :dst?) +end diff --git a/1.8/core/time/dup_spec.rb b/1.8/core/time/dup_spec.rb new file mode 100644 index 0000000000..e26c8ea376 --- /dev/null +++ b/1.8/core/time/dup_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#dup" do + it "returns a Time object that represents the same time" do + t = Time.at(100) + t.dup.tv_sec.should == t.tv_sec + end + + it "copies the gmt state flag" do + Time.now.gmtime.dup.gmt?.should == true + end + + it "returns an independent Time object" do + t = Time.now + t2 = t.dup + t.gmtime + + t2.gmt?.should == false + end +end diff --git a/1.8/core/time/eql_spec.rb b/1.8/core/time/eql_spec.rb new file mode 100644 index 0000000000..cd5ae3f79c --- /dev/null +++ b/1.8/core/time/eql_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#eql?" do + it "returns true iff time is equal in seconds and usecs to other time" do + Time.at(100, 100).eql?(Time.at(100, 100)).should == true + Time.at(100, 100).eql?(Time.at(100, 99)).should == false + Time.at(100, 100).eql?(Time.at(99, 100)).should == false + end +end diff --git a/1.8/core/time/fixtures/methods.rb b/1.8/core/time/fixtures/methods.rb new file mode 100644 index 0000000000..578721f5ec --- /dev/null +++ b/1.8/core/time/fixtures/methods.rb @@ -0,0 +1,33 @@ +def with_timezone(name, offset = nil, daylight_saving_zone = "") + zone = name.dup + + if (offset) + # TZ convention is backwards + offset = -offset + + zone << offset.to_s + zone << ":00:00" + end + zone << daylight_saving_zone + + old = ENV["TZ"] + ENV["TZ"] = zone + + begin + yield + ensure + ENV["TZ"] = old + end +end + +def localtime(seconds) + platform_is :os => [:darwin, :bsd] do + return `LC_ALL=C date -r #{seconds} +'%a %b %d %H:%M:%S %z %Y'`.chomp + end + + platform_is :os => :linux do + return `LC_ALL=C date -d @#{seconds} +'%a %b %d %H:%M:%S %z %Y'`.chomp + end + + return `LC_ALL=C date -j -f "%s" #{seconds} "+%a %b %d %H:%M:%S %z %Y"`.chomp +end diff --git a/1.8/core/time/getgm_spec.rb b/1.8/core/time/getgm_spec.rb new file mode 100644 index 0000000000..6bd1dabc12 --- /dev/null +++ b/1.8/core/time/getgm_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/getgm' + +describe "Time#getgm" do + it_behaves_like(:time_getgm, :getgm) +end diff --git a/1.8/core/time/getlocal_spec.rb b/1.8/core/time/getlocal_spec.rb new file mode 100644 index 0000000000..d0ac106988 --- /dev/null +++ b/1.8/core/time/getlocal_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#getlocal" do + it "returns a new time which is the local representation of time" do + # Testing with America/Regina here because it doesn't have DST. + with_timezone("CST", -6) do + t = Time.gm(2007, 1, 9, 12, 0, 0) + t.localtime.should == Time.local(2007, 1, 9, 6, 0, 0) + end + end +end diff --git a/1.8/core/time/getutc_spec.rb b/1.8/core/time/getutc_spec.rb new file mode 100644 index 0000000000..94b5c41221 --- /dev/null +++ b/1.8/core/time/getutc_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/getgm' + +describe "Time#getutc" do + it_behaves_like(:time_getgm, :getutc) +end diff --git a/1.8/core/time/gm_spec.rb b/1.8/core/time/gm_spec.rb new file mode 100644 index 0000000000..2725cc2b5d --- /dev/null +++ b/1.8/core/time/gm_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/gm' +require File.dirname(__FILE__) + '/shared/time_params' + +describe "Time.gm" do + it_behaves_like(:time_gm, :gm) + it_behaves_like(:time_params, :gm) +end diff --git a/1.8/core/time/gmt_offset_spec.rb b/1.8/core/time/gmt_offset_spec.rb new file mode 100644 index 0000000000..f5289f6c86 --- /dev/null +++ b/1.8/core/time/gmt_offset_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/gmt_offset' + +describe "Time#gmt_offset" do + it_behaves_like(:time_gmt_offset, :gmt_offset) +end diff --git a/1.8/core/time/gmt_spec.rb b/1.8/core/time/gmt_spec.rb new file mode 100644 index 0000000000..2e42ae5ca3 --- /dev/null +++ b/1.8/core/time/gmt_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#gmt?" do + it "returns true if time represents a time in UTC (GMT)" do + Time.now.gmt?.should == false + Time.now.gmtime.gmt?.should == true + end +end diff --git a/1.8/core/time/gmtime_spec.rb b/1.8/core/time/gmtime_spec.rb new file mode 100644 index 0000000000..3adeb8311b --- /dev/null +++ b/1.8/core/time/gmtime_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/gmtime' + +describe "Time#gmtime" do + it_behaves_like(:time_gmtime, :gmtime) +end diff --git a/1.8/core/time/gmtoff_spec.rb b/1.8/core/time/gmtoff_spec.rb new file mode 100644 index 0000000000..9ec8414f44 --- /dev/null +++ b/1.8/core/time/gmtoff_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/gmt_offset' + +describe "Time#gmtoff" do + it_behaves_like(:time_gmt_offset, :gmtoff) +end diff --git a/1.8/core/time/hash_spec.rb b/1.8/core/time/hash_spec.rb new file mode 100644 index 0000000000..5efc05e1eb --- /dev/null +++ b/1.8/core/time/hash_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#hash" do + it "returns a unique integer for each time" do + Time.at(100).hash.should == 100 + Time.at(100, 123456).hash.should == 123428 + Time.gm(1980).hash.should == 315532800 + end +end diff --git a/1.8/core/time/hour_spec.rb b/1.8/core/time/hour_spec.rb new file mode 100644 index 0000000000..85f0240c40 --- /dev/null +++ b/1.8/core/time/hour_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#hour" do + it "returns the hour of the day (0..23) for time" do + with_timezone("CET", 1) do + Time.at(0).hour.should == 1 + end + end +end diff --git a/1.8/core/time/initialize_copy_spec.rb b/1.8/core/time/initialize_copy_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/initialize_copy_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/initialize_spec.rb b/1.8/core/time/initialize_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/initialize_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/inspect_spec.rb b/1.8/core/time/inspect_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/inspect_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/isdst_spec.rb b/1.8/core/time/isdst_spec.rb new file mode 100644 index 0000000000..7f03c12f76 --- /dev/null +++ b/1.8/core/time/isdst_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/isdst' + +describe "Time#isdst" do + it_behaves_like(:time_isdst, :isdst) +end diff --git a/1.8/core/time/local_spec.rb b/1.8/core/time/local_spec.rb new file mode 100644 index 0000000000..919e9fd260 --- /dev/null +++ b/1.8/core/time/local_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/local' +require File.dirname(__FILE__) + '/shared/time_params' + +describe "Time.local" do + it_behaves_like(:time_local, :local) + it_behaves_like(:time_params, :local) +end diff --git a/1.8/core/time/localtime_spec.rb b/1.8/core/time/localtime_spec.rb new file mode 100644 index 0000000000..862032ee08 --- /dev/null +++ b/1.8/core/time/localtime_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#localtime" do + it "returns the local representation of time" do + # Testing with America/Regina here because it doesn't have DST. + with_timezone("CST", -6) do + t = Time.gm(2007, 1, 9, 12, 0, 0) + t.localtime + t.should == Time.local(2007, 1, 9, 6, 0, 0) + end + end +end diff --git a/1.8/core/time/mday_spec.rb b/1.8/core/time/mday_spec.rb new file mode 100644 index 0000000000..9c2bd5ab49 --- /dev/null +++ b/1.8/core/time/mday_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/day' + +describe "Time#mday" do + it_behaves_like(:time_day, :mday) +end diff --git a/1.8/core/time/min_spec.rb b/1.8/core/time/min_spec.rb new file mode 100644 index 0000000000..21ee861ad0 --- /dev/null +++ b/1.8/core/time/min_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#min" do + it "returns the minute of the hour (0..59) for time" do + with_timezone("CET", 1) do + Time.at(0).min.should == 0 + end + end +end diff --git a/1.8/core/time/minus_spec.rb b/1.8/core/time/minus_spec.rb new file mode 100644 index 0000000000..0def59cd0b --- /dev/null +++ b/1.8/core/time/minus_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#-" do + it "decrements the time by the specified amount" do + (Time.at(100) - 100).should == Time.at(0) + (Time.at(100) - Time.at(99)).should == 1.0 + (Time.at(1.1) - 0.2).should == Time.at(0.9) + end + + it "accepts arguments that can be coerced into Float" do + (obj = mock('9.5')).should_receive(:to_f).and_return(9.5) + (Time.at(100) - obj).should == Time.at(90.5) + end + + it "raises TypeError on argument that can't be coerced into Float" do + lambda { Time.now - Object.new }.should raise_error(TypeError) + lambda { Time.now - "stuff" }.should raise_error(TypeError) + end + + it "raises TypeError on nil argument" do + lambda { Time.now - nil }.should raise_error(TypeError) + end +end diff --git a/1.8/core/time/mktime_spec.rb b/1.8/core/time/mktime_spec.rb new file mode 100644 index 0000000000..e78bf2c459 --- /dev/null +++ b/1.8/core/time/mktime_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/local' +require File.dirname(__FILE__) + '/shared/time_params' + +describe "Time.mktime" do + it_behaves_like(:time_local, :mktime) + it_behaves_like(:time_params, :mktime) +end diff --git a/1.8/core/time/mon_spec.rb b/1.8/core/time/mon_spec.rb new file mode 100644 index 0000000000..103641cb64 --- /dev/null +++ b/1.8/core/time/mon_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/month' + +describe "Time#mon" do + it_behaves_like(:time_month, :mon) +end diff --git a/1.8/core/time/month_spec.rb b/1.8/core/time/month_spec.rb new file mode 100644 index 0000000000..2576747479 --- /dev/null +++ b/1.8/core/time/month_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/month' + +describe "Time#month" do + it_behaves_like(:time_month, :month) +end diff --git a/1.8/core/time/now_spec.rb b/1.8/core/time/now_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/now_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/plus_spec.rb b/1.8/core/time/plus_spec.rb new file mode 100644 index 0000000000..0dde404633 --- /dev/null +++ b/1.8/core/time/plus_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#+" do + it "increments the time by the specified amount" do + (Time.at(0) + 100).should == Time.at(100) + (Time.at(1.1) + 0.9).should == Time.at(2) + end + + it "accepts arguments that can be coerced into Float" do + (obj = mock('10.5')).should_receive(:to_f).and_return(10.5) + (Time.at(100) + obj).should == Time.at(110.5) + end + + it "raises TypeError on argument that can't be coerced into Float" do + lambda { Time.now + Object.new }.should raise_error(TypeError) + lambda { Time.now + "stuff" }.should raise_error(TypeError) + end + + it "raises TypeError on Time argument" do + lambda { Time.now + Time.now }.should raise_error(TypeError) + end + + it "raises TypeError on nil argument" do + lambda { Time.now + nil }.should raise_error(TypeError) + end +end diff --git a/1.8/core/time/sec_spec.rb b/1.8/core/time/sec_spec.rb new file mode 100644 index 0000000000..9c728b4b3b --- /dev/null +++ b/1.8/core/time/sec_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#sec" do + it "returns the second of the minute(0..60) for time" do + Time.at(0).sec.should == 0 + end +end diff --git a/1.8/core/time/shared/asctime.rb b/1.8/core/time/shared/asctime.rb new file mode 100644 index 0000000000..6b0502be88 --- /dev/null +++ b/1.8/core/time/shared/asctime.rb @@ -0,0 +1,8 @@ +shared :time_asctime do |cmd| + describe "Time##{cmd}" do + it "returns a canonical string representation of time" do + t = Time.now + t.send(cmd).should == t.strftime("%a %b %e %H:%M:%S %Y") + end + end +end diff --git a/1.8/core/time/shared/day.rb b/1.8/core/time/shared/day.rb new file mode 100644 index 0000000000..edccfc733d --- /dev/null +++ b/1.8/core/time/shared/day.rb @@ -0,0 +1,9 @@ +shared :time_day do |cmd| + describe "Time##{cmd}" do + it "returns the day of the month (1..n) for time" do + with_timezone("CET", 1) do + Time.at(0).send(cmd).should == 1 + end + end + end +end diff --git a/1.8/core/time/shared/getgm.rb b/1.8/core/time/shared/getgm.rb new file mode 100644 index 0000000000..f55f188316 --- /dev/null +++ b/1.8/core/time/shared/getgm.rb @@ -0,0 +1,11 @@ +shared :time_getgm do |cmd| + describe "Time##{cmd}" do + it "returns a new time which is the utc representation of time" do + # Testing with America/Regina here because it doesn't have DST. + with_timezone("CST", -6) do + t = Time.local(2007, 1, 9, 6, 0, 0) + t.send(cmd).should == Time.gm(2007, 1, 9, 12, 0, 0) + end + end + end +end diff --git a/1.8/core/time/shared/gm.rb b/1.8/core/time/shared/gm.rb new file mode 100644 index 0000000000..583a143101 --- /dev/null +++ b/1.8/core/time/shared/gm.rb @@ -0,0 +1,11 @@ +shared :time_gm do |cmd| + describe "Time.#{cmd}" do + it "creates a time based on given values, interpreted as UTC (GMT)" do + Time.send(cmd, 2000,"jan",1,20,15,1).inspect.should == "Sat Jan 01 20:15:01 UTC 2000" + end + + it "creates a time based on given C-style gmtime arguments, interpreted as UTC (GMT)" do + Time.send(cmd, 1, 15, 20, 1, 1, 2000, :ignored, :ignored, :ignored, :ignored).inspect.should == "Sat Jan 01 20:15:01 UTC 2000" + end + end +end diff --git a/1.8/core/time/shared/gmt_offset.rb b/1.8/core/time/shared/gmt_offset.rb new file mode 100644 index 0000000000..ede5af5245 --- /dev/null +++ b/1.8/core/time/shared/gmt_offset.rb @@ -0,0 +1,9 @@ +shared :time_gmt_offset do |cmd| + describe "Time##{cmd}" do + it "returns the offset in seconds between the timezone of time and UTC" do + with_timezone("AST", 3) do + Time.new.send(cmd).should == 10800 + end + end + end +end diff --git a/1.8/core/time/shared/gmtime.rb b/1.8/core/time/shared/gmtime.rb new file mode 100644 index 0000000000..d0270a06ff --- /dev/null +++ b/1.8/core/time/shared/gmtime.rb @@ -0,0 +1,12 @@ +shared :time_gmtime do |cmd| + describe "Time##{cmd}" do + it "returns the utc representation of time" do + # Testing with America/Regina here because it doesn't have DST. + with_timezone("CST", -6) do + t = Time.local(2007, 1, 9, 6, 0, 0) + t.send(cmd) + t.should == Time.gm(2007, 1, 9, 12, 0, 0) + end + end + end +end diff --git a/1.8/core/time/shared/isdst.rb b/1.8/core/time/shared/isdst.rb new file mode 100644 index 0000000000..38f02819c0 --- /dev/null +++ b/1.8/core/time/shared/isdst.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../fixtures/methods' + +shared :time_isdst do |cmd| + describe "Time##{cmd}" do + it "dst? returns whether time is during daylight saving time" do + with_timezone("America/Los_Angeles") do + Time.local(2007, 9, 9, 0, 0, 0).send(cmd).should == true + Time.local(2007, 1, 9, 0, 0, 0).send(cmd).should == false + end + end + end +end diff --git a/1.8/core/time/shared/local.rb b/1.8/core/time/shared/local.rb new file mode 100644 index 0000000000..c7a7512c07 --- /dev/null +++ b/1.8/core/time/shared/local.rb @@ -0,0 +1,15 @@ +shared :time_local do |cmd| + describe "Time.#{cmd}" do + it "creates a time based on given values, interpreted in the local time zone" do + with_timezone("PST", -8) do + Time.send(cmd, 2000,"jan",1,20,15,1).inspect.should == "Sat Jan 01 20:15:01 -0800 2000" + end + end + + it "creates a time based on given C-style gmtime arguments, interpreted in the local time zone" do + with_timezone("PST", -8) do + Time.send(cmd, 1, 15, 20, 1, 1, 2000, :ignored, :ignored, :ignored, :ignored).inspect.should == "Sat Jan 01 20:15:01 -0800 2000" + end + end + end +end diff --git a/1.8/core/time/shared/month.rb b/1.8/core/time/shared/month.rb new file mode 100644 index 0000000000..3f9a776951 --- /dev/null +++ b/1.8/core/time/shared/month.rb @@ -0,0 +1,7 @@ +shared :time_month do |cmd| + describe "Time##{cmd}" do + it "returns the month of the year" do + Time.at(99999).mon.should == 1 + end + end +end diff --git a/1.8/core/time/shared/time_params.rb b/1.8/core/time/shared/time_params.rb new file mode 100644 index 0000000000..b1b5ed07f2 --- /dev/null +++ b/1.8/core/time/shared/time_params.rb @@ -0,0 +1,85 @@ +shared :time_params do |cmd| + describe "Time.#{cmd}" do + it "handles string-like second argument" do + Time.send(cmd, 2008, "12").should == Time.send(cmd, 2008, 12) + Time.send(cmd, 2008, "dec").should == Time.send(cmd, 2008, 12) + (obj = mock('12')).should_receive(:to_str).and_return("12") + Time.send(cmd, 2008, obj).should == Time.send(cmd, 2008, 12) + end + + ruby_bug do + # Exclude MRI 1.8.6 because it segfaults. :) + # But the problem is fixed in MRI repository already. + it "handles string-like second argument" do + (obj = mock('dec')).should_receive(:to_str).and_return('dec') + Time.send(cmd, 2008, obj).should == Time.send(cmd, 2008, 12) + end + end + + it "handles string arguments" do + Time.send(cmd, "2000", "1", "1" , "20", "15", "1").should == Time.send(cmd, 2000, 1, 1, 20, 15, 1) + Time.send(cmd, "1", "15", "20", "1", "1", "2000", :ignored, :ignored, :ignored, :ignored).should == Time.send(cmd, 1, 15, 20, 1, 1, 2000, :ignored, :ignored, :ignored, :ignored) + end + + it "handles float arguments" do + Time.send(cmd, 2000.0, 1.0, 1.0, 20.0, 15.0, 1.0).should == Time.send(cmd, 2000, 1, 1, 20, 15, 1) + Time.send(cmd, 1.0, 15.0, 20.0, 1.0, 1.0, 2000.0, :ignored, :ignored, :ignored, :ignored).should == Time.send(cmd, 1, 15, 20, 1, 1, 2000, :ignored, :ignored, :ignored, :ignored) + end + + it "should accept various year ranges" do + Time.send(cmd, 1901, 12, 31, 23, 59, 59, 0).wday.should == 2 + Time.send(cmd, 2037, 12, 31, 23, 59, 59, 0).wday.should == 4 + + platform_is :wordsize => 32 do + lambda { Time.send(cmd, 1900, 12, 31, 23, 59, 59, 0) }.should raise_error(ArgumentError) # mon + lambda { Time.send(cmd, 2038, 12, 31, 23, 59, 59, 0) }.should raise_error(ArgumentError) # mon + end + + platform_is :wordsize => 64 do + Time.send(cmd, 1900, 12, 31, 23, 59, 59, 0).wday.should == 1 + Time.send(cmd, 2038, 12, 31, 23, 59, 59, 0).wday.should == 5 + end + end + + it "throws ArgumentError for out of range values" do + # year-based Time.local(year (, month, day, hour, min, sec, usec)) + # Year range only fails on 32 bit archs + if defined? Rubinius && Rubinius::WORDSIZE == 32 + lambda { Time.send(cmd, 1111, 12, 31, 23, 59, 59, 0) }.should raise_error(ArgumentError) # year + end + lambda { Time.send(cmd, 2008, 13, 31, 23, 59, 59, 0) }.should raise_error(ArgumentError) # mon + lambda { Time.send(cmd, 2008, 12, 32, 23, 59, 59, 0) }.should raise_error(ArgumentError) # day + lambda { Time.send(cmd, 2008, 12, 31, 25, 59, 59, 0) }.should raise_error(ArgumentError) # hour + lambda { Time.send(cmd, 2008, 12, 31, 23, 61, 59, 0) }.should raise_error(ArgumentError) # min + lambda { Time.send(cmd, 2008, 12, 31, 23, 59, 61, 0) }.should raise_error(ArgumentError) # sec + + # second based Time.local(sec, min, hour, day, month, year, wday, yday, isdst, tz) + lambda { Time.send(cmd, 61, 59, 23, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored) }.should raise_error(ArgumentError) # sec + lambda { Time.send(cmd, 59, 61, 23, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored) }.should raise_error(ArgumentError) # min + lambda { Time.send(cmd, 59, 59, 25, 31, 12, 2008, :ignored, :ignored, :ignored, :ignored) }.should raise_error(ArgumentError) # hour + lambda { Time.send(cmd, 59, 59, 23, 32, 12, 2008, :ignored, :ignored, :ignored, :ignored) }.should raise_error(ArgumentError) # day + lambda { Time.send(cmd, 59, 59, 23, 31, 13, 2008, :ignored, :ignored, :ignored, :ignored) }.should raise_error(ArgumentError) # month + # Year range only fails on 32 bit archs + if defined? Rubinius && Rubinius::WORDSIZE == 32 + lambda { Time.send(cmd, 59, 59, 23, 31, 12, 1111, :ignored, :ignored, :ignored, :ignored) }.should raise_error(ArgumentError) # year + end + end + + it "throws ArgumentError for invalid number of arguments" do + # Time.local only takes either 1-8, or 10 arguments + lambda { + Time.send(cmd, 59, 1, 2, 3, 4, 2008, 0, 0, 0) + }.should raise_error(ArgumentError) # 9 go boom + + # please stop using should_not raise_error... it is implied + Time.send(cmd, 2008).wday.should == 2 + Time.send(cmd, 2008, 12).wday.should == 1 + Time.send(cmd, 2008, 12, 31).wday.should == 3 + Time.send(cmd, 2008, 12, 31, 23).wday.should == 3 + Time.send(cmd, 2008, 12, 31, 23, 59).wday.should == 3 + Time.send(cmd, 2008, 12, 31, 23, 59, 59).wday.should == 3 + Time.send(cmd, 2008, 12, 31, 23, 59, 59, 0).wday.should == 3 + Time.send(cmd, 59, 1, 2, 3, 4, 2008, :x, :x, :x, :x).wday.should == 4 + end + end +end diff --git a/1.8/core/time/shared/to_i.rb b/1.8/core/time/shared/to_i.rb new file mode 100644 index 0000000000..ba1782b4ff --- /dev/null +++ b/1.8/core/time/shared/to_i.rb @@ -0,0 +1,7 @@ +shared :time_to_i do |cmd| + describe "Time##{cmd}" do + it "returns the value of time as an integer number of seconds since epoch" do + Time.at(0).send(cmd).should == 0 + end + end +end diff --git a/1.8/core/time/strftime_spec.rb b/1.8/core/time/strftime_spec.rb new file mode 100644 index 0000000000..7a521a4520 --- /dev/null +++ b/1.8/core/time/strftime_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#strftime" do + it "formats time according to the directives in the given format string" do + with_timezone("GMT", 0) do + Time.at(0).strftime("There is %M minutes in epoch").should == "There is 00 minutes in epoch" + end + end + + it "supports week of year format with %U and %W" do + # start of the yer + saturday_first = Time.local(2000,1,1,14,58,42) + saturday_first.strftime("%U").should == "00" + saturday_first.strftime("%W").should == "00" + + sunday_second = Time.local(2000,1,2,14,58,42) + sunday_second.strftime("%U").should == "01" + sunday_second.strftime("%W").should == "00" + + monday_third = Time.local(2000,1,3,14,58,42) + monday_third.strftime("%U").should == "01" + monday_third.strftime("%W").should == "01" + + sunday_9th = Time.local(2000,1,9,14,58,42) + sunday_9th.strftime("%U").should == "02" + sunday_9th.strftime("%W").should == "01" + + monday_10th = Time.local(2000,1,10,14,58,42) + monday_10th.strftime("%U").should == "02" + monday_10th.strftime("%W").should == "02" + + # middle of the year + some_sunday = Time.local(2000,8,6,4,20,00) + some_sunday.strftime("%U").should == "32" + some_sunday.strftime("%W").should == "31" + some_monday = Time.local(2000,8,7,4,20,00) + some_monday.strftime("%U").should == "32" + some_monday.strftime("%W").should == "32" + + # end of year, and start of next one + saturday_30th = Time.local(2000,12,30,14,58,42) + saturday_30th.strftime("%U").should == "52" + saturday_30th.strftime("%W").should == "52" + + sunday_last = Time.local(2000,12,31,14,58,42) + sunday_last.strftime("%U").should == "53" + sunday_last.strftime("%W").should == "52" + + monday_first = Time.local(2001,1,1,14,58,42) + monday_first.strftime("%U").should == "00" + monday_first.strftime("%W").should == "01" + end +end diff --git a/1.8/core/time/succ_spec.rb b/1.8/core/time/succ_spec.rb new file mode 100644 index 0000000000..9919f502cc --- /dev/null +++ b/1.8/core/time/succ_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#succ" do + it "returns a new time one second later than time" do + Time.at(100).succ.should == Time.at(101) + end + + it "returns a new instance" do + t1 = Time.at(100) + t2 = t1.succ + t1.object_id.should_not == t2.object_id + end +end diff --git a/1.8/core/time/times_spec.rb b/1.8/core/time/times_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/times_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/to_a_spec.rb b/1.8/core/time/to_a_spec.rb new file mode 100644 index 0000000000..076770fa42 --- /dev/null +++ b/1.8/core/time/to_a_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#to_a" do + it "returns a 10 element array representing the deconstructed time" do + # Testing with America/Regina here because it doesn't have DST. + with_timezone("America/Regina") do + Time.at(0).to_a.should == [0, 0, 18, 31, 12, 1969, 3, 365, false, "CST"] + end + end +end diff --git a/1.8/core/time/to_f_spec.rb b/1.8/core/time/to_f_spec.rb new file mode 100644 index 0000000000..052dcf23f9 --- /dev/null +++ b/1.8/core/time/to_f_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#to_f" do + it "returns the float number of seconds + usecs since the epoch" do + Time.at(100, 100).to_f.should == 100.0001 + end +end diff --git a/1.8/core/time/to_i_spec.rb b/1.8/core/time/to_i_spec.rb new file mode 100644 index 0000000000..a5348ab506 --- /dev/null +++ b/1.8/core/time/to_i_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Time#to_i" do + it_behaves_like(:time_to_i, :to_i) +end diff --git a/1.8/core/time/to_s_spec.rb b/1.8/core/time/to_s_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/to_s_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/tv_sec_spec.rb b/1.8/core/time/tv_sec_spec.rb new file mode 100644 index 0000000000..a9e056f0f2 --- /dev/null +++ b/1.8/core/time/tv_sec_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/to_i' + +describe "Time#tv_sec" do + it_behaves_like(:time_to_i, :tv_sec) +end diff --git a/1.8/core/time/tv_usec_spec.rb b/1.8/core/time/tv_usec_spec.rb new file mode 100644 index 0000000000..cfbab5a69d --- /dev/null +++ b/1.8/core/time/tv_usec_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' diff --git a/1.8/core/time/usec_spec.rb b/1.8/core/time/usec_spec.rb new file mode 100644 index 0000000000..016608f7fc --- /dev/null +++ b/1.8/core/time/usec_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#usec" do + it "returns the microseconds for time" do + Time.at(0).usec.should == 0 + (Time.at(1.1) + 0.9).usec.should == 0 + (Time.at(1.1) - 0.2).usec.should == 900000 + end +end diff --git a/1.8/core/time/utc_offset_spec.rb b/1.8/core/time/utc_offset_spec.rb new file mode 100644 index 0000000000..fe2b8678d4 --- /dev/null +++ b/1.8/core/time/utc_offset_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/gmt_offset' + +describe "Time#utc_offset" do + it_behaves_like(:time_gmt_offset, :utc_offset) +end diff --git a/1.8/core/time/utc_spec.rb b/1.8/core/time/utc_spec.rb new file mode 100644 index 0000000000..e285b8851b --- /dev/null +++ b/1.8/core/time/utc_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' +require File.dirname(__FILE__) + '/shared/gm' +require File.dirname(__FILE__) + '/shared/gmtime' +require File.dirname(__FILE__) + '/shared/time_params' + +describe "Time#utc?" do + it "returns true if time represents a time in UTC (GMT)" do + Time.now.utc?.should == false + end +end + +describe "Time.utc" do + it_behaves_like(:time_gm, :utc) + it_behaves_like(:time_params, :utc) +end + +describe "Time#utc" do + it_behaves_like(:time_gmtime, :utc) +end diff --git a/1.8/core/time/wday_spec.rb b/1.8/core/time/wday_spec.rb new file mode 100644 index 0000000000..e01ba70ecb --- /dev/null +++ b/1.8/core/time/wday_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#wday" do + it "returns an integer representing the day of the week, 0..6, with Sunday being 0" do + with_timezone("GMT", 0) do + Time.at(0).wday.should == 4 + end + end +end diff --git a/1.8/core/time/yday_spec.rb b/1.8/core/time/yday_spec.rb new file mode 100644 index 0000000000..6f6744aa6c --- /dev/null +++ b/1.8/core/time/yday_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#yday" do + it "returns an integer representing the day of the year, 1..366" do + with_timezone("UTC") do + Time.at(9999999).yday.should == 116 + end + end +end diff --git a/1.8/core/time/year_spec.rb b/1.8/core/time/year_spec.rb new file mode 100644 index 0000000000..38e8004f56 --- /dev/null +++ b/1.8/core/time/year_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#year" do + it "returns the four digit year for time as an integer" do + with_timezone("CET", 1) do + Time.at(0).year.should == 1970 + end + end +end diff --git a/1.8/core/time/zone_spec.rb b/1.8/core/time/zone_spec.rb new file mode 100644 index 0000000000..343658564e --- /dev/null +++ b/1.8/core/time/zone_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/methods' + +describe "Time#zone" do + it "returns the time zone used for time" do + # Testing with Asia/Kuwait here because it doesn't have DST. + with_timezone("Asia/Kuwait") do + Time.now.zone.should == "AST" + end + end +end diff --git a/1.8/core/true/and_spec.rb b/1.8/core/true/and_spec.rb new file mode 100644 index 0000000000..f27ea2e698 --- /dev/null +++ b/1.8/core/true/and_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "TrueClass#&" do + it "returns false if other is nil or false, otherwise true" do + (true & true).should == true + (true & false).should == false + (true & nil).should == false + (true & "").should == true + (true & mock('x')).should == true + end +end diff --git a/1.8/core/true/inspect_spec.rb b/1.8/core/true/inspect_spec.rb new file mode 100644 index 0000000000..511445bbfe --- /dev/null +++ b/1.8/core/true/inspect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "TrueClass#inspect" do + it "returns the string 'true'" do + true.inspect.should == "true" + end +end diff --git a/1.8/core/true/or_spec.rb b/1.8/core/true/or_spec.rb new file mode 100644 index 0000000000..f57c67f282 --- /dev/null +++ b/1.8/core/true/or_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "TrueClass#|" do + it "returns true" do + (true | true).should == true + (true | false).should == true + (true | nil).should == true + (true | "").should == true + (true | mock('x')).should == true + end +end diff --git a/1.8/core/true/to_s_spec.rb b/1.8/core/true/to_s_spec.rb new file mode 100644 index 0000000000..204e725d0e --- /dev/null +++ b/1.8/core/true/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "TrueClass#to_s" do + it "returns the string 'true'" do + true.to_s.should == "true" + end +end diff --git a/1.8/core/true/xor_spec.rb b/1.8/core/true/xor_spec.rb new file mode 100644 index 0000000000..f3317b33ce --- /dev/null +++ b/1.8/core/true/xor_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "TrueClass#^" do + it "returns true if other is nil or false, otherwise false" do + (true ^ true).should == false + (true ^ false).should == true + (true ^ nil).should == true + (true ^ "").should == false + (true ^ mock('x')).should == false + end +end diff --git a/1.8/core/unboundmethod/arity_spec.rb b/1.8/core/unboundmethod/arity_spec.rb new file mode 100644 index 0000000000..417672034d --- /dev/null +++ b/1.8/core/unboundmethod/arity_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "UnboundMethod#arity" do + before(:each) do + @um = UnboundMethodSpecs::Methods.new + end + + it "returns the number of arguments accepted by a method, using Method#unbind" do + @um.method(:one).unbind.arity.should == 0 + @um.method(:two).unbind.arity.should == 1 + @um.method(:three).unbind.arity.should == 2 + @um.method(:four).unbind.arity.should == 2 + end + + it "returns the number arguments accepted by a method, using Module#instance_method" do + UnboundMethodSpecs::Methods.instance_method(:one).arity.should == 0 + UnboundMethodSpecs::Methods.instance_method(:two).arity.should == 1 + UnboundMethodSpecs::Methods.instance_method(:three).arity.should == 2 + UnboundMethodSpecs::Methods.instance_method(:four).arity.should == 2 + end + + it "if optional arguments returns the negative number of mandatory arguments, using Method#unbind" do + @um.method(:neg_one).unbind.arity.should == -1 + @um.method(:neg_two).unbind.arity.should == -2 + @um.method(:neg_three).unbind.arity.should == -3 + @um.method(:neg_four).unbind.arity.should == -3 + end + + it "if optional arguments returns the negative number of mandatory arguments, using Module#instance_method" do + UnboundMethodSpecs::Methods.instance_method(:neg_one).arity.should == -1 + UnboundMethodSpecs::Methods.instance_method(:neg_two).arity.should == -2 + UnboundMethodSpecs::Methods.instance_method(:neg_three).arity.should == -3 + UnboundMethodSpecs::Methods.instance_method(:neg_four).arity.should == -3 + end +end diff --git a/1.8/core/unboundmethod/bind_spec.rb b/1.8/core/unboundmethod/bind_spec.rb new file mode 100644 index 0000000000..b58dfd5298 --- /dev/null +++ b/1.8/core/unboundmethod/bind_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "UnboundMethod#bind" do + before :each do + @normal_um = UnboundMethodSpecs::Methods.new.method(:foo).unbind + @parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind + @child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind + @child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind + end + + it "raises TypeError if object is not kind_of? the Module the method defined in" do + lambda { @normal_um.bind(UnboundMethodSpecs::B.new) }.should raise_error(TypeError) + end + + it "returns Method for any object that is kind_of? the Module method was extracted from" do + @normal_um.bind(UnboundMethodSpecs::Methods.new).class.should == Method + end + + deviates_on :rubinius do + it "returns Method for any object kind_of? the Module the method is defined in" do + @parent_um.bind(UnboundMethodSpecs::Child1.new).class.should == Method + @child1_um.bind(UnboundMethodSpecs::Parent.new).class.should == Method + @child2_um.bind(UnboundMethodSpecs::Child1.new).class.should == Method + end + end + + it "Method returned for obj is equal to one directly returned by obj.method" do + obj = UnboundMethodSpecs::Methods.new + @normal_um.bind(obj).should == obj.method(:foo) + end +end diff --git a/1.8/core/unboundmethod/clone_spec.rb b/1.8/core/unboundmethod/clone_spec.rb new file mode 100644 index 0000000000..34ddfd8aff --- /dev/null +++ b/1.8/core/unboundmethod/clone_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "UnboundMethod#clone" do + it "returns a copy of the UnboundMethod" do + um1 = UnboundMethodSpecs::Methods.instance_method(:foo) + um2 = um1.clone + + (um1 == um2).should == true + um1.bind(UnboundMethodSpecs::Methods.new).call.should == um2.bind(UnboundMethodSpecs::Methods.new).call + end +end diff --git a/1.8/core/unboundmethod/equal_value_spec.rb b/1.8/core/unboundmethod/equal_value_spec.rb new file mode 100644 index 0000000000..92e21fa528 --- /dev/null +++ b/1.8/core/unboundmethod/equal_value_spec.rb @@ -0,0 +1,119 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +context "Creating UnboundMethods" do + specify "there is no difference between Method#unbind and Module#instance_method" do + UnboundMethodSpecs::Methods.instance_method(:foo).class.should == UnboundMethod + UnboundMethodSpecs::Methods.new.method(:foo).unbind.class.should == UnboundMethod + end +end + +describe "UnboundMethod#==" do + before :all do + @from_module = UnboundMethodSpecs::Methods.instance_method(:foo) + @from_unbind = UnboundMethodSpecs::Methods.new.method(:foo).unbind + + @includee = UnboundMethodSpecs::Mod.instance_method(:from_mod) + @includer = UnboundMethodSpecs::Methods.instance_method(:from_mod) + + @alias_1 = UnboundMethodSpecs::Methods.instance_method(:alias_1) + @alias_2 = UnboundMethodSpecs::Methods.instance_method(:alias_2) + + @original_body = UnboundMethodSpecs::Methods.instance_method(:original_body) + @identical_body = UnboundMethodSpecs::Methods.instance_method(:identical_body) + + @parent = UnboundMethodSpecs::Parent.instance_method(:foo) + @child1 = UnboundMethodSpecs::Child1.instance_method(:foo) + @child2 = UnboundMethodSpecs::Child2.instance_method(:foo) + + @child1_alt = UnboundMethodSpecs::Child1.instance_method(:foo) + + @discard_1 = UnboundMethodSpecs::Methods.instance_method(:discard_1) + @discard_2 = UnboundMethodSpecs::Methods.instance_method(:discard_2) + + @method_one = UnboundMethodSpecs::Methods.instance_method(:one) + @method_two = UnboundMethodSpecs::Methods.instance_method(:two) + end + + it "returns true if objects refer to the same method" do + (@from_module == @from_module).should == true + (@from_unbind == @from_unbind).should == true + (@from_module == @from_unbind).should == true + (@from_unbind == @from_module).should == true + end + + it "returns true if either is an alias for the other" do + (@from_module == @alias_1).should == true + (@alias_1 == @from_module).should == true + end + + it "returns true if both are aliases for a third method" do + (@from_module == @alias_1).should == true + (@alias_1 == @from_module).should == true + + (@from_module == @alias_2).should == true + (@alias_2 == @from_module).should == true + + (@alias_1 == @alias_2).should == true + (@alias_2 == @alias_1).should == true + end + + it "returns true if same method is extracted from the same subclass" do + (@child1 == @child1_alt).should == true + (@child1_alt == @child1).should == true + end + + # See below for MRI + deviates_on :rubinius do + it "returns true if same method extracted from super- and subclass" do + (@parent == @child1).should == true + (@child1 == @parent).should == true + end + + it "returns true if same method extracted from two different subclasses" do + (@child2 == @child1).should == true + (@child1 == @child2).should == true + end + + it "returns true if same method and the method is defined in an included Module" do + (@includee == @includer).should == true + (@includer == @includee).should == true + end + end + + it "returns false if UnboundMethods are different methods" do + (@method_one == @method_two).should == false + (@method_two == @method_one).should == false + end + + it "returns false if both have identical body but are not the same" do + (@original_name == @identical_body).should == false + (@identical_body == @original_name).should == false + end + + # See above for Rubinius + not_compliant_on :rubinius do + it "returns false if same method but one extracted from a subclass" do + (@parent == @child1).should == false + (@child1 == @parent).should == false + end + + it "returns false if same method but extracted from two different subclasses" do + (@child2 == @child1).should == false + (@child1 == @child2).should == false + end + + it "returns false if methods are the same but added from an included Module" do + (@includee == @includer).should == false + (@includer == @includee).should == false + end + end + + it "returns false if both have same Module, same name, identical body but not the same" do + class UnboundMethodSpecs::Methods + def discard_1; :discard; end + end + + (@discard_1 == UnboundMethodSpecs::Methods.instance_method(:discard_1)).should == false + end +end diff --git a/1.8/core/unboundmethod/fixtures/classes.rb b/1.8/core/unboundmethod/fixtures/classes.rb new file mode 100644 index 0000000000..6223a85c8a --- /dev/null +++ b/1.8/core/unboundmethod/fixtures/classes.rb @@ -0,0 +1,51 @@ +module UnboundMethodSpecs + module Mod + def from_mod; end + end + + class Methods + include Mod + + def foo + true + end + alias bar foo + alias alias_1 foo + alias alias_2 foo + + def original_body(); :this; end + def identical_body(); :this; end + + def one; end + def two(a); end + def three(a, b); end + def four(a, b, &c); end + + def neg_one(*a); end + def neg_two(a, *b); end + def neg_three(a, b, *c); end + def neg_four(a, b, *c, &d); end + + def discard_1(); :discard; end + def discard_2(); :discard; end + end + + class Parent + def foo; end + end + + class Child1 < Parent; end + class Child2 < Parent; end + + class A + def baz(a, b) + return [__FILE__, self.class] + end + end + + class B < A + end + + class C < B + end +end diff --git a/1.8/core/unboundmethod/inspect_spec.rb b/1.8/core/unboundmethod/inspect_spec.rb new file mode 100644 index 0000000000..effe571fc3 --- /dev/null +++ b/1.8/core/unboundmethod/inspect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + "/fixtures/classes" +require File.dirname(__FILE__) + '/shared/to_s' + +describe "UnboundMethod#inspect" do + it_behaves_like(:unboundmethod_to_s, :inspect) +end diff --git a/1.8/core/unboundmethod/shared/to_s.rb b/1.8/core/unboundmethod/shared/to_s.rb new file mode 100644 index 0000000000..03be692c12 --- /dev/null +++ b/1.8/core/unboundmethod/shared/to_s.rb @@ -0,0 +1,28 @@ +require "#{File.dirname __FILE__}/../../../spec_helper" +require "#{File.dirname __FILE__}/../fixtures/classes" + + +shared :unboundmethod_to_s do |cmd| + describe "UnboundMethod##{cmd}" do + before :each do + @from_module = UnboundMethodSpecs::Methods.instance_method(:from_mod) + @from_method = UnboundMethodSpecs::Methods.new.method(:from_mod).unbind + end + + it "returns a String" do + @from_module.send(cmd).class.should == String + @from_method.send(cmd).class.should == String + end + + it "the String reflects that this is an UnboundMethod object" do + @from_module.send(cmd).should =~ /\bUnboundMethod\b/ + @from_method.send(cmd).should =~ /\bUnboundMethod\b/ + end + + it "the String shows the method name, Module defined in and Module extracted from" do + @from_module.send(cmd).should =~ /\bfrom_mod\b/ + @from_module.send(cmd).should =~ /\bUnboundMethodSpecs::Mod\b/ + @from_method.send(cmd).should =~ /\bUnboundMethodSpecs::Methods\b/ + end + end +end diff --git a/1.8/core/unboundmethod/to_s_spec.rb b/1.8/core/unboundmethod/to_s_spec.rb new file mode 100644 index 0000000000..965f949f22 --- /dev/null +++ b/1.8/core/unboundmethod/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/to_s' + +describe "UnboundMethod#to_s" do + it_behaves_like(:unboundmethod_to_s, :to_s) +end diff --git a/1.8/fixtures/class.rb b/1.8/fixtures/class.rb new file mode 100644 index 0000000000..b0d8ae319e --- /dev/null +++ b/1.8/fixtures/class.rb @@ -0,0 +1,72 @@ +module ClassSpecs + class A; end + + class B + @@cvar = :cvar + @ivar = :ivar + end + + class C + def self.make_class_variable + @@cvar = :cvar + end + + def self.make_class_instance_variable + @civ = :civ + end + end + + class D + def make_class_variable + @@cvar = :cvar + end + end + + class E + def self.cmeth() :cmeth end + def meth() :meth end + + class << self + def smeth() :smeth end + end + + CONSTANT = :constant! + end + + class F; end + class F + def meth() :meth end + end + class F + def another() :another end + end + + class G + def override() :nothing end + def override() :override end + end + + class Container + class A; end + class B; end + end + + O = Object.new + class << O + def smeth + :smeth + end + end + + class H + def self.inherited(sub) + track_inherited << sub + end + + def self.track_inherited + @inherited_modules ||= [] + end + end + + class K < H; end +end diff --git a/1.8/fixtures/load/.gitignore b/1.8/fixtures/load/.gitignore new file mode 100644 index 0000000000..c14378cf54 --- /dev/null +++ b/1.8/fixtures/load/.gitignore @@ -0,0 +1,5 @@ +*.rba +*.rbc +*.old +*dummy* +*dynamic* diff --git a/1.8/fixtures/load/load_spec b/1.8/fixtures/load/load_spec new file mode 100644 index 0000000000..413912aaea --- /dev/null +++ b/1.8/fixtures/load/load_spec @@ -0,0 +1 @@ +$load_spec = Time.now diff --git a/1.8/fixtures/load/load_spec.rooby b/1.8/fixtures/load/load_spec.rooby new file mode 100644 index 0000000000..f9d02ec2a0 --- /dev/null +++ b/1.8/fixtures/load/load_spec.rooby @@ -0,0 +1 @@ +$load_spec_rooby = Time.now diff --git a/1.8/fixtures/load/load_spec_1.rb b/1.8/fixtures/load/load_spec_1.rb new file mode 100644 index 0000000000..1f18c996da --- /dev/null +++ b/1.8/fixtures/load/load_spec_1.rb @@ -0,0 +1 @@ +$load_spec_1 = Time.now diff --git a/1.8/fixtures/load/load_spec_10.rb b/1.8/fixtures/load/load_spec_10.rb new file mode 100644 index 0000000000..5e968ef424 --- /dev/null +++ b/1.8/fixtures/load/load_spec_10.rb @@ -0,0 +1 @@ +$load_spec_10 = Time.now diff --git a/1.8/fixtures/load/load_spec_2.rb b/1.8/fixtures/load/load_spec_2.rb new file mode 100644 index 0000000000..9dcc2ff12f --- /dev/null +++ b/1.8/fixtures/load/load_spec_2.rb @@ -0,0 +1 @@ +$load_spec_2 = Time.now diff --git a/1.8/fixtures/load/load_spec_3.rb b/1.8/fixtures/load/load_spec_3.rb new file mode 100644 index 0000000000..f67ddc2580 --- /dev/null +++ b/1.8/fixtures/load/load_spec_3.rb @@ -0,0 +1 @@ +$load_spec_3 = Time.now diff --git a/1.8/fixtures/load/load_spec_4.rb b/1.8/fixtures/load/load_spec_4.rb new file mode 100644 index 0000000000..2396a54c93 --- /dev/null +++ b/1.8/fixtures/load/load_spec_4.rb @@ -0,0 +1,12 @@ +one = [__FILE__, __LINE__] + + + + + + + + +two = [__FILE__, __LINE__] + +$load_spec_4 = [one, two] diff --git a/1.8/fixtures/load/load_spec_5.rb b/1.8/fixtures/load/load_spec_5.rb new file mode 100644 index 0000000000..f290adc5ca --- /dev/null +++ b/1.8/fixtures/load/load_spec_5.rb @@ -0,0 +1 @@ +$load_spec_5 = Time.now diff --git a/1.8/fixtures/load/load_spec_6.rb b/1.8/fixtures/load/load_spec_6.rb new file mode 100644 index 0000000000..78261135a9 --- /dev/null +++ b/1.8/fixtures/load/load_spec_6.rb @@ -0,0 +1 @@ +$load_spec_6 = Time.now diff --git a/1.8/fixtures/load/load_spec_7.rb b/1.8/fixtures/load/load_spec_7.rb new file mode 100644 index 0000000000..bea34e9f64 --- /dev/null +++ b/1.8/fixtures/load/load_spec_7.rb @@ -0,0 +1,2 @@ +$load_spec_7 ||= 1 +$load_spec_7 += 1 diff --git a/1.8/fixtures/load/load_spec_8.rb b/1.8/fixtures/load/load_spec_8.rb new file mode 100644 index 0000000000..b646053555 --- /dev/null +++ b/1.8/fixtures/load/load_spec_8.rb @@ -0,0 +1 @@ +$load_spec_8 = [1197436446, 943810] diff --git a/1.8/fixtures/load/load_spec_9.rb b/1.8/fixtures/load/load_spec_9.rb new file mode 100644 index 0000000000..cfdf63f309 --- /dev/null +++ b/1.8/fixtures/load/load_spec_9.rb @@ -0,0 +1 @@ +$load_spec_9 = Time.now diff --git a/1.8/fixtures/load/load_spec_wrap.rb b/1.8/fixtures/load/load_spec_wrap.rb new file mode 100644 index 0000000000..9ada33debe --- /dev/null +++ b/1.8/fixtures/load/load_spec_wrap.rb @@ -0,0 +1,7 @@ +class LoadSpecWrap + $load_spec_wrap = Time.now + + def self.lsw + :lsw + end +end diff --git a/1.8/fixtures/load/load_spec_wrap2.rb b/1.8/fixtures/load/load_spec_wrap2.rb new file mode 100644 index 0000000000..6a1033545a --- /dev/null +++ b/1.8/fixtures/load/load_spec_wrap2.rb @@ -0,0 +1,7 @@ +class LoadSpecWrapTwo + $load_spec_wrap2 = Time.now + + def self.lsw + :lsw + end +end diff --git a/1.8/fixtures/load/load_spec_wrap_2.rb b/1.8/fixtures/load/load_spec_wrap_2.rb new file mode 100644 index 0000000000..99db955cbc --- /dev/null +++ b/1.8/fixtures/load/load_spec_wrap_2.rb @@ -0,0 +1,7 @@ +class LoadSpecWrapTwo + $load_spec_wrap2 = :yep + + def self.lsw + :lsw + end +end diff --git a/1.8/fixtures/require/.gitignore b/1.8/fixtures/require/.gitignore new file mode 100644 index 0000000000..c14378cf54 --- /dev/null +++ b/1.8/fixtures/require/.gitignore @@ -0,0 +1,5 @@ +*.rba +*.rbc +*.old +*dummy* +*dynamic* diff --git a/1.8/fixtures/require/masked_require_spec_2.rb b/1.8/fixtures/require/masked_require_spec_2.rb new file mode 100644 index 0000000000..8fcff9a6c4 --- /dev/null +++ b/1.8/fixtures/require/masked_require_spec_2.rb @@ -0,0 +1 @@ +$require_spec_2 = :yep diff --git a/1.8/fixtures/require/masked_require_spec_3.rb b/1.8/fixtures/require/masked_require_spec_3.rb new file mode 100644 index 0000000000..1690ed444c --- /dev/null +++ b/1.8/fixtures/require/masked_require_spec_3.rb @@ -0,0 +1 @@ +$require_spec_3 = :yep diff --git a/1.8/fixtures/require/require_spec b/1.8/fixtures/require/require_spec new file mode 100644 index 0000000000..b3b4678587 --- /dev/null +++ b/1.8/fixtures/require/require_spec @@ -0,0 +1 @@ +$require_spec = :noext diff --git a/1.8/fixtures/require/require_spec.rb b/1.8/fixtures/require/require_spec.rb new file mode 100644 index 0000000000..1f1654edde --- /dev/null +++ b/1.8/fixtures/require/require_spec.rb @@ -0,0 +1 @@ +$require_spec = :rb diff --git a/1.8/fixtures/require/require_spec.rooby b/1.8/fixtures/require/require_spec.rooby new file mode 100644 index 0000000000..8ca74a8a4c --- /dev/null +++ b/1.8/fixtures/require/require_spec.rooby @@ -0,0 +1 @@ +$require_spec_rooby = :rooby diff --git a/1.8/fixtures/require/require_spec.rooby.rb b/1.8/fixtures/require/require_spec.rooby.rb new file mode 100644 index 0000000000..8be8d14b4f --- /dev/null +++ b/1.8/fixtures/require/require_spec.rooby.rb @@ -0,0 +1 @@ +$require_spec_rooby = :rb diff --git a/1.8/fixtures/require/require_spec_1.rb b/1.8/fixtures/require/require_spec_1.rb new file mode 100644 index 0000000000..b4abfbcf7b --- /dev/null +++ b/1.8/fixtures/require/require_spec_1.rb @@ -0,0 +1 @@ +$require_spec_1 = :yep diff --git a/1.8/fixtures/require/require_spec_10.rb b/1.8/fixtures/require/require_spec_10.rb new file mode 100644 index 0000000000..4d81ee16cb --- /dev/null +++ b/1.8/fixtures/require/require_spec_10.rb @@ -0,0 +1 @@ +$require_spec_10 = Time.new diff --git a/1.8/fixtures/require/require_spec_2.rb b/1.8/fixtures/require/require_spec_2.rb new file mode 100644 index 0000000000..dc0d325f5b --- /dev/null +++ b/1.8/fixtures/require/require_spec_2.rb @@ -0,0 +1 @@ +$require_spec_2 = Time.now diff --git a/1.8/fixtures/require/require_spec_3.rb b/1.8/fixtures/require/require_spec_3.rb new file mode 100644 index 0000000000..dff3702fac --- /dev/null +++ b/1.8/fixtures/require/require_spec_3.rb @@ -0,0 +1 @@ +$require_spec_3 = Time.now diff --git a/1.8/fixtures/require/require_spec_4.rb b/1.8/fixtures/require/require_spec_4.rb new file mode 100644 index 0000000000..1b8c05aeff --- /dev/null +++ b/1.8/fixtures/require/require_spec_4.rb @@ -0,0 +1,12 @@ +one = [__FILE__, __LINE__] + + + + + + + + +two = [__FILE__, __LINE__] + +$require_spec_4 = [one, two] diff --git a/1.8/fixtures/require/require_spec_6.rb b/1.8/fixtures/require/require_spec_6.rb new file mode 100644 index 0000000000..ec19573943 --- /dev/null +++ b/1.8/fixtures/require/require_spec_6.rb @@ -0,0 +1 @@ +$require_spec_6 = :yep diff --git a/1.8/fixtures/require/require_spec_7.rb b/1.8/fixtures/require/require_spec_7.rb new file mode 100644 index 0000000000..54c505d91a --- /dev/null +++ b/1.8/fixtures/require/require_spec_7.rb @@ -0,0 +1 @@ +$require_spec_7 = Time.new diff --git a/1.8/fixtures/require/require_spec_8.rb b/1.8/fixtures/require/require_spec_8.rb new file mode 100644 index 0000000000..ec7f6c37c2 --- /dev/null +++ b/1.8/fixtures/require/require_spec_8.rb @@ -0,0 +1 @@ +$require_spec_8 = Time.now diff --git a/1.8/fixtures/require/require_spec_9.rb b/1.8/fixtures/require/require_spec_9.rb new file mode 100644 index 0000000000..71c5f03ab5 --- /dev/null +++ b/1.8/fixtures/require/require_spec_9.rb @@ -0,0 +1 @@ +$require_spec_9 = Time.new diff --git a/1.8/fixtures/require/require_spec_raises.rb b/1.8/fixtures/require/require_spec_raises.rb new file mode 100644 index 0000000000..cbd2dd97b3 --- /dev/null +++ b/1.8/fixtures/require/require_spec_raises.rb @@ -0,0 +1,3 @@ +runner_is_not :rspec do +raise "no" +end diff --git a/1.8/fixtures/require/require_spec_recursive.rb b/1.8/fixtures/require/require_spec_recursive.rb new file mode 100644 index 0000000000..fcad24dd9d --- /dev/null +++ b/1.8/fixtures/require/require_spec_recursive.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/require_spec_recursive' +$require_spec_recursive = [1198633335, 432396] diff --git a/1.8/language/README b/1.8/language/README new file mode 100644 index 0000000000..09bf7b9bb9 --- /dev/null +++ b/1.8/language/README @@ -0,0 +1,30 @@ +There are numerous possible way of categorizing the entities and concepts that +make up a programming language. Ruby has a fairly large number of reserved +words. These words significantly describe major elements of the language, +including flow control constructs like 'for' and 'while', conditional +execution like 'if' and 'unless', exceptional execution control like 'rescue', +etc. There are also literals for the basic "types" like String, Regexp, Array +and Fixnum. + +Behavorial specifications describe the behavior of concrete entities. Rather +than using concepts of computation to organize these spec files, we use +entities of the Ruby language. Consider looking at any syntactic element of a +Ruby program. With (almost) no ambiguity, one can identify it as a literal, +reserved word, variable, etc. There is a spec file that corresponds to each +literal construct and most reserved words, with the exceptions noted below. +There are also several files that are more difficult to classify: all +predefined variables, constants, and objects (predefined_spec.rb), the +precedence of all operators (precedence_spec.rb), the behavior of assignment +to variables (variables_spec.rb), the behavior of subprocess execution +(execution_spec.rb), the behavior of the raise method as it impacts the +execution of a Ruby program (raise_spec.rb), and the block entities like +'begin', 'do', ' { ... }' (block_spec.rb). + +Several reserved words and other entities are combined with the primary +reserved word or entity to which they are related: + +false, true, nil, self predefined_spec.rb +in for_spec.rb +then, elsif if_spec.rb +when case_spec.rb +catch throw_spec.rb \ No newline at end of file diff --git a/1.8/language/alias_spec.rb b/1.8/language/alias_spec.rb new file mode 100644 index 0000000000..0331ae7837 --- /dev/null +++ b/1.8/language/alias_spec.rb @@ -0,0 +1,65 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +class AliasObject + def value; 5; end + def false_value; 6; end +end + +describe "The alias keyword" do + before(:each) do + @obj = AliasObject.new + @meta = class << @obj;self;end + end + + it "creates a new name for an existing method" do + @meta.class_eval do + alias __value value + end + @obj.__value.should == 5 + end + + it "adds the new method to the list of methods" do + original_methods = @obj.methods + @meta.class_eval do + alias __value value + end + (@obj.methods - original_methods).should == ["__value"] + end + + it "adds the new method to the list of public methods" do + original_methods = @obj.public_methods + @meta.class_eval do + alias __value value + end + (@obj.public_methods - original_methods).should == ["__value"] + end + + it "overwrites an existing method with the target name" do + @meta.class_eval do + alias false_value value + end + @obj.false_value.should == 5 + end + + it "is reversible" do + @meta.class_eval do + alias __value value + alias value false_value + end + @obj.value.should == 6 + + @meta.class_eval do + alias value __value + end + @obj.value.should == 5 + end + + it "operates on the object's metaclass when used in instance_eval" do + @obj.instance_eval do + alias __value value + end + + @obj.__value.should == 5 + lambda { AliasObject.new.__value }.should raise_error(NoMethodError) + end +end diff --git a/1.8/language/and_spec.rb b/1.8/language/and_spec.rb new file mode 100644 index 0000000000..91cd5b0637 --- /dev/null +++ b/1.8/language/and_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../spec_helper' diff --git a/1.8/language/array_spec.rb b/1.8/language/array_spec.rb new file mode 100644 index 0000000000..f4fce2d561 --- /dev/null +++ b/1.8/language/array_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Array literals" do + it "[] should return a new array populated with the given elements" do + array = [1, 'a', nil] + array[0].should == 1 + array[1].should == 'a' + array[2].should == nil + end +end + +describe "Bareword array literals" do + + it "%w() transforms unquoted barewords into an array" do + a = 3 + %w(a #{3+a} 3).should == ["a", '#{3+a}', "3"] + end + + it "%W() transforms unquoted barewords into an array, supporting interpolation" do + a = 3 + %W(a #{3+a} 3).should == ["a", '6', "3"] + end +end + +describe "The unpacking splat operator (*)" do + it "when applied to a literal nested array, unpacks its elements into the containing array" do + [1, 2, *[3, 4, 5]].should == [1, 2, 3, 4, 5] + end + + it "when applied to a nested referenced array, unpacks its elements into the containing array" do + splatted_array = [3, 4, 5] + [1, 2, *splatted_array].should == [1, 2, 3, 4, 5] + end + + it "unpacks the start and count arguments in an array slice assignment" do + alphabet_1 = ['a'..'z'].to_a + alphabet_2 = alphabet_1.dup + start_and_count_args = [1, 10] + + alphabet_1[1, 10] = 'a' + alphabet_2[*start_and_count_args] = 'a' + + alphabet_1.should == alphabet_2 + end + + # mSpec doesn't have pending specs yet + # it "unpacks a literal array into arguments in a method call" + # + # it "unpacks a referenced array into arguments in a method call" +end + +describe "The packing splat operator (*)" do + +end \ No newline at end of file diff --git a/1.8/language/block_spec.rb b/1.8/language/block_spec.rb new file mode 100644 index 0000000000..182b7759ad --- /dev/null +++ b/1.8/language/block_spec.rb @@ -0,0 +1,76 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require File.dirname(__FILE__) + '/fixtures/block' + +describe "A block with a 'rest' arg" do + it "collects all of the arguments passed to yield" do + ret = nil + BlockSpecs::Yield.new.splat(1,2,3) {|*args| ret = args} + ret.should == [1,2,3] + end +end + +describe "A block with an anonymous 'rest' arg" do + it "ignores all of the arguments passed to yield" do + ret = [1].each {|*| } + ret.should == [1] + end +end + +describe "Block parameters" do + it "assign to local variable" do + i = 0 + a = [1,2,3] + a.each {|i| ;} + i.should == 3 + end + + it "captures variables from the outer scope" do + a = [1,2,3] + sum = 0 + var = nil + a.each {|var| sum += var} + sum.should == 6 + var.should == 3 + end +end + +describe "A block whose arguments are splatted" do + it "captures the arguments passed to the block in an array" do + a = [] + BlockSpecs::Yield.new.two_args { |*args| a << args } + a.should == [[1, 2]] + end + + it "captures the array passed to the block in an array" do + a = [] + BlockSpecs::Yield.new.two_arg_array { |*args| a << args } + a.should == [[[1, 2]]] + end +end + +not_compliant_on :rubinius do + # This functionality is being removed from MRI and has never + # been used in 1.8, therefore rubinius doesn't support + # it already. + describe "Block parameters (to be removed from MRI)" do + it "assigns to a global variable" do + $global_for_block_assignment = 0 + a = [1,2,3] + a.each {|$global_for_block_assignment| ;} + $global_for_block_assignment.should == 3 + end + + it "calls method=" do + class T + def n; return @n; end + def n=(val); @n = val + 1; end + def initialize; @n = 0; end + end + t = T.new + t.n.should == 0 + a = [1,2,3] + a.each {|t.n| } + t.n.should == 4 + end + end +end diff --git a/1.8/language/break_spec.rb b/1.8/language/break_spec.rb new file mode 100644 index 0000000000..f5571b3961 --- /dev/null +++ b/1.8/language/break_spec.rb @@ -0,0 +1,144 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "The break statement" do + it "raises a LocalJumpError if used not within block or while/for loop" do + def x; break; end + lambda { x }.should raise_error(LocalJumpError) + end + + it "ends block execution if used whithin block" do + a = [] + lambda { + a << 1 + break + a << 2 + }.call + a.should == [1] + end + + it "causes block to return value passed to break" do + lambda { break 123; 456 }.call.should == 123 + end + + it "causes block to return nil if no value passed to break" do + lambda { break; 456 }.call.should == nil + end +end + +describe "Breaking out of a loop with a value" do + + it "assigns objects" do + a = loop do break; end; a.should == nil + a = loop do break nil; end; a.should == nil + a = loop do break 1; end; a.should == 1 + a = loop do break []; end; a.should == [] + a = loop do break [1]; end; a.should == [1] + a = loop do break [nil]; end; a.should == [nil] + a = loop do break [[]]; end; a.should == [[]] + a = loop do break [*[]]; end; a.should == [] + a = loop do break [*[1]]; end; a.should == [1] + a = loop do break [*[1,2]]; end; a.should == [1,2] + end + + it "assigns splatted objects" do + a = loop do break *nil; end; a.should == nil + a = loop do break *1; end; a.should == 1 + a = loop do break *[]; end; a.should == nil + a = loop do break *[1]; end; a.should == 1 + a = loop do break *[nil]; end; a.should == nil + a = loop do break *[[]]; end; a.should == [] + a = loop do break *[*[]]; end; a.should == nil + a = loop do break *[1]; end; a.should == 1 + a = loop do break *[*[1]]; end; a.should == 1 + a = loop do break *[1,2]; end; a.should == [1,2] + a = loop do break *[*[1,2]]; end; a.should == [1,2] + end + + it "assigns to a splatted reference" do + *a = loop do break; end; a.should == [nil] + *a = loop do break nil; end; a.should == [nil] + *a = loop do break 1; end; a.should == [1] + *a = loop do break []; end; a.should == [[]] + *a = loop do break [1]; end; a.should == [[1]] + *a = loop do break [nil]; end; a.should == [[nil]] + *a = loop do break [[]]; end; a.should == [[[]]] + *a = loop do break [1,2]; end; a.should == [[1,2]] + *a = loop do break [*[]]; end; a.should == [[]] + *a = loop do break [*[1]]; end; a.should == [[1]] + *a = loop do break [*[1,2]]; end; a.should == [[1,2]] + end + + it "assigns splatted objects to a splatted reference" do + *a = loop do break *nil; end; a.should == [nil] + *a = loop do break *1; end; a.should == [1] + *a = loop do break *[]; end; a.should == [nil] + *a = loop do break *[1]; end; a.should == [1] + *a = loop do break *[nil]; end; a.should == [nil] + *a = loop do break *[[]]; end; a.should == [[]] + *a = loop do break *[1,2]; end; a.should == [[1,2]] + *a = loop do break *[*[]]; end; a.should == [nil] + *a = loop do break *[*[1]]; end; a.should == [1] + *a = loop do break *[*[1,2]]; end; a.should == [[1,2]] + end + + it "assigns splatted objects to a splatted reference from a splatted loop" do + *a = *loop do break *nil; end; a.should == [nil] + *a = *loop do break *1; end; a.should == [1] + *a = *loop do break *[]; end; a.should == [nil] + *a = *loop do break *[1]; end; a.should == [1] + *a = *loop do break *[nil]; end; a.should == [nil] + *a = *loop do break *[[]]; end; a.should == [] + *a = *loop do break *[1,2]; end; a.should == [1,2] + *a = *loop do break *[*[]]; end; a.should == [nil] + *a = *loop do break *[*[1]]; end; a.should == [1] + *a = *loop do break *[*[1,2]]; end; a.should == [1,2] + end + + it "assigns objects to multiple block variables" do + a,b,*c = loop do break; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break nil; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break 1; end; [a,b,c].should == [1,nil,[]] + a,b,*c = loop do break []; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break [1]; end; [a,b,c].should == [1,nil,[]] + a,b,*c = loop do break [nil]; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break [[]]; end; [a,b,c].should == [[],nil,[]] + a,b,*c = loop do break [1,2]; end; [a,b,c].should == [1,2,[]] + a,b,*c = loop do break [*[]]; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break [*[1]]; end; [a,b,c].should == [1,nil,[]] + a,b,*c = loop do break [*[1,2]]; end; [a,b,c].should == [1,2,[]] + end + + it "assigns splatted objects to multiple block variables" do + a,b,*c = loop do break *nil; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break *1; end; [a,b,c].should == [1,nil,[]] + a,b,*c = loop do break *[]; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break *[1]; end; [a,b,c].should == [1,nil,[]] + a,b,*c = loop do break *[nil]; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break *[[]]; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break *[1,2]; end; [a,b,c].should == [1,2,[]] + a,b,*c = loop do break *[*[]]; end; [a,b,c].should == [nil,nil,[]] + a,b,*c = loop do break *[*[1]]; end; [a,b,c].should == [1,nil,[]] + a,b,*c = loop do break *[*[1,2]]; end; [a,b,c].should == [1,2,[]] + end + + it "stops any loop type at the correct spot" do + i = 0; loop do break i if i == 2; i+=1; end.should == 2 + i = 0; loop do break if i == 3; i+=1; end; i.should == 3 + i = 0; 0.upto(5) {|i| break i if i == 2 }.should == 2 + i = 0; 0.upto(5) {|i| break if i == 3 }; i.should == 3 + i = 0; while (i < 5) do break i if i == 2 ; i+=1; end.should == 2 + i = 0; while (i < 5) do break if i == 3 ; i+=1; end; i.should == 3 + end + + it "stops a yielded method at the correct spot" do + def break_test() + yield 1 + yield 2 + yield 3 + end + break_test {|i| break i if i == 2 }.should == 2 + i = 0 + break_test {|i| break i if i == 1 } + i.should == 1 + end +end diff --git a/1.8/language/case_spec.rb b/1.8/language/case_spec.rb new file mode 100644 index 0000000000..54538ddcfe --- /dev/null +++ b/1.8/language/case_spec.rb @@ -0,0 +1,288 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "The 'case'-construct" do + it "evaluates the body of the when clause matching the case target expression" do + case 1 + when 2: false + when 1: true + end.should == true + end + + it "evaluates the body of the when clause whose array expression includes the case target expression" do + case 2 + when 3, 4: false + when 1, 2: true + end.should == true + end + + it "evaluates the body of the when clause whose range expression includes the case target expression" do + case 5 + when 21..30: false + when 1..20: true + end.should == true + end + + it "returns nil when no 'then'-bodies are given" do + case "a" + when "a" + when "b" + end.should == nil + end + + it "evaluates the 'else'-body when no other expression matches" do + case "c" + when "a": 'foo' + when "b": 'bar' + else 'zzz' + end.should == 'zzz' + end + + it "returns nil when no expression matches and 'else'-body is empty" do + case "c" + when "a": "a" + when "b": "b" + else + end.should == nil + end + + it "returns 2 when a then body is empty" do + case Object.new + when Numeric then + 1 + when String then + # ok + else + 2 + end.should == 2 + end + + it "returns the statement following ':'" do + case "a" + when "a": 'foo' + when "b": 'bar' + end.should == 'foo' + end + + it "returns the statement following 'then'" do + case "a" + when "a" then 'foo' + when "b" then 'bar' + end.should == 'foo' + end + + it "allows mixing ':' and 'then'" do + case "b" + when "a": 'foo' + when "b" then 'bar' + end.should == 'bar' + end + + it "tests classes with case equality" do + case "a" + when String + 'foo' + when Symbol + 'bar' + end.should == 'foo' + end + + it "tests with matching regexps" do + case "hello" + when /abc/: false + when /^hell/: true + end.should == true + end + + it "does not test with equality when given classes" do + case :symbol.class + when Symbol + "bar" + when String + "bar" + else + "foo" + end.should == "foo" + end + + it "takes lists of values" do + case 'z' + when 'a', 'b', 'c', 'd' + "foo" + when 'x', 'y', 'z' + "bar" + end.should == "bar" + + case 'b' + when 'a', 'b', 'c', 'd' + "foo" + when 'x', 'y', 'z' + "bar" + end.should == "foo" + end + + it "expands arrays to lists of values" do + case 'z' + when *['a', 'b', 'c', 'd'] + "foo" + when *['x', 'y', 'z'] + "bar" + end.should == "bar" + end + + it "takes an expanded array in addition to a list of values" do + case 'f' + when 'f', *['a', 'b', 'c', 'd'] + "foo" + when *['x', 'y', 'z'] + "bar" + end.should == "foo" + + case 'b' + when 'f', *['a', 'b', 'c', 'd'] + "foo" + when *['x', 'y', 'z'] + "bar" + end.should == "foo" + end + + it "concats arrays before expanding them" do + a = ['a', 'b', 'c', 'd'] + b = ['f'] + + case 'f' + when 'f', *a|b + "foo" + when *['x', 'y', 'z'] + "bar" + end.should == "foo" + end + + it "never matches when clauses with no values" do + case nil + when *[] + "foo" + end.should == nil + end + + it "lets you define a method after the case statement" do + case (def foo; 'foo'; end; 'f') + when 'a' + 'foo' + when 'f' + 'bar' + end.should == 'bar' + end + + it "raises a SyntaxError when 'else' is used when no 'when' is given" do + lambda { + eval <<-CODE + case 4 + else + true + end + CODE + }.should raise_error(SyntaxError) + end + + it "raises a SyntaxError when 'else' is used before a 'when' was given" do + lambda { + eval <<-CODE + case 4 + else + true + when 4: false + end + CODE + }.should raise_error(SyntaxError) + end + + it "supports nested case statements" do + result = false + case :x + when Symbol + case :y + when Symbol + result = true + end + end + result.should == true + end + + it "supports nested case statements followed by a when with a splatted array" do + result = false + case :x + when Symbol + case :y + when Symbol + result = true + end + when *[Symbol] + result = false + end + result.should == true + end + + it "supports nested case statements followed by a when with a splatted non-array" do + result = false + case :x + when Symbol + case :y + when Symbol + result = true + end + when *Symbol + result = false + end + result.should == true + end + + it "works even if there's only one when statement" do + case 1 + when 1 + 100 + end.should == 100 + end +end + +describe "The 'case'-construct with no target expression" do + it "evaluates the body of the first clause when at least one of its condition expressions is true" do + case + when true, false: 'foo' + end.should == 'foo' + end + + it "evaluates the body of the first when clause that is not false/nil" do + case + when false: 'foo' + when 2: 'bar' + when 1 == 1: 'baz' + end.should == 'bar' + + case + when false: 'foo' + when nil: 'foo' + when 1 == 1: 'bar' + end.should == 'bar' + end + + it "evaluates the body of the else clause if all when clauses are false/nil" do + case + when false: 'foo' + when nil: 'foo' + when 1 == 2: 'bar' + else 'baz' + end.should == 'baz' + end + + it "evaluates multiple conditional expressions as a boolean disjunction" do + case + when true, false: 'foo' + else 'bar' + end.should == 'foo' + + case + when false, true: 'foo' + else 'bar' + end.should == 'foo' + end +end diff --git a/1.8/language/class_spec.rb b/1.8/language/class_spec.rb new file mode 100644 index 0000000000..f148025b75 --- /dev/null +++ b/1.8/language/class_spec.rb @@ -0,0 +1,150 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/class' + +ClassSpecsNumber = 12 + +module ClassSpecs + Number = 12 +end + +describe "A class definition" do + it "creates a new class" do + ClassSpecs::A.class.should == Class + ClassSpecs::A.new.class.should == ClassSpecs::A + end + + it "has no class variables" do + ClassSpecs::A.class_variables.should == [] + end + + it "raises TypeError if constant given as class name exists and is not a Module" do + lambda { + class ClassSpecsNumber + end + }.should raise_error(TypeError) + end + + # test case known to be detecting bugs (JRuby, MRI 1.9) + it "raises TypeError if the constant qualifying the class is nil" do + lambda { + class nil::Foo + end + }.should raise_error(TypeError) + end + + it "raises TypeError if any constant qualifying the class is not a Module" do + lambda { + class ClassSpecs::Number::MyClass + end + }.should raise_error(TypeError) + + lambda { + class ClassSpecsNumber::MyClass + end + }.should raise_error(TypeError) + end + +# # I do not think this is a valid spec -- rue +# it "has no class-level instance variables" do +# ClassSpecs::A.instance_variables.should == [] +# end + + it "allows the declaration of class variables in the body" do + ClassSpecs::B.class_variables.should == ["@@cvar"] + ClassSpecs::B.send(:class_variable_get, :@@cvar).should == :cvar + end + + it "stores instance variables defined in the class body in the class object" do + ClassSpecs::B.instance_variables.include?("@ivar").should == true + ClassSpecs::B.instance_variable_get(:@ivar).should == :ivar + end + + it "allows the declaration of class variables in a class method" do + ClassSpecs::C.class_variables.should == [] + ClassSpecs::C.make_class_variable + ClassSpecs::C.class_variables.should == ["@@cvar"] + end + + it "allows the definition of class-level instance variables in a class method" do + ClassSpecs::C.instance_variables.include?("@civ").should == false + ClassSpecs::C.make_class_instance_variable + ClassSpecs::C.instance_variables.include?("@civ").should == true + end + + it "allows the declaration of class variables in an instance method" do + ClassSpecs::D.class_variables.should == [] + ClassSpecs::D.new.make_class_variable + ClassSpecs::D.class_variables.should == ["@@cvar"] + end + + it "allows the definition of instance methods" do + ClassSpecs::E.new.meth.should == :meth + end + + it "allows the definition of class methods" do + ClassSpecs::E.cmeth.should == :cmeth + end + + it "allows the definition of class methods using class << self" do + ClassSpecs::E.smeth.should == :smeth + end + + it "allows the definition of Constants" do + Object.const_defined?('CONSTANT').should == false + ClassSpecs::E.const_defined?('CONSTANT').should == true + ClassSpecs::E::CONSTANT.should == :constant! + end + + it "returns the value of the last statement in the body" do + class ClassSpecs::Empty; end.should == nil + class ClassSpecs::Twenty; 20; end.should == 20 + class ClassSpecs::Plus; 10 + 20; end.should == 30 + class ClassSpecs::Singleton; class << self; :singleton; end; end.should == :singleton + end +end + +describe "An outer class definition" do + it "contains the inner classes" do + ClassSpecs::Container.constants.should include('A', 'B') + end +end + +describe "A Class Definitions extending an object" do + it "allows adding methods" do + ClassSpecs::O.smeth.should == :smeth + end + + it "raises a TypeError when trying to extend numbers" do + lambda { + eval <<-CODE + class << 1 + def xyz + self + end + end + CODE + }.should raise_error(TypeError) + end +end + +describe "Reopening a class" do + it "extends the previous definitions" do + c = ClassSpecs::F.new + c.meth.should == :meth + c.another.should == :another + end + + it "overwrites existing methods" do + ClassSpecs::G.new.override.should == :override + end + + it "raises a TypeError when superclasses mismatch" do + lambda { class ClassSpecs::A < Array; end }.should raise_error(TypeError) + end +end + +describe "class provides hooks" do + it "calls inherited when a class is created" do + ClassSpecs::H.track_inherited.should == [ClassSpecs::K] + end +end diff --git a/1.8/language/class_variable_spec.rb b/1.8/language/class_variable_spec.rb new file mode 100644 index 0000000000..dbfeca6537 --- /dev/null +++ b/1.8/language/class_variable_spec.rb @@ -0,0 +1,45 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +module ClassVariableSpec + class A + @@a_cvar = :a_cvar + def a_cvar() @@a_cvar end + def a_cvar=(val) @@a_cvar = val end + end + + class B < A; end + + module M + @@cvar = :value + + def cvar + @@cvar + end + end + + class C + extend M + end +end + +describe "class variables" do + + # HACK can't compare things directly, wrapping in [] + it "can be accessed from a subclass" do + [ClassVariableSpec::B.new.a_cvar].should == [:a_cvar] + end + + it "sets the value in the superclass from the subclass" do + a = ClassVariableSpec::A.new + b = ClassVariableSpec::B.new + b.a_cvar = :new_val + + [a.a_cvar].should == [:new_val] + end + + it "retrieves the value from the place it is defined" do + [ClassVariableSpec::C.cvar.should] == [:value] + end + +end + diff --git a/1.8/language/constants_spec.rb b/1.8/language/constants_spec.rb new file mode 100644 index 0000000000..094d8288be --- /dev/null +++ b/1.8/language/constants_spec.rb @@ -0,0 +1,116 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require File.dirname(__FILE__) + '/fixtures/constants' + +class StaticScope + def chain + ary = [] + ss = self + while ss + ary << ss.module + ss = ss.parent + end + + return ary + end +end + +describe "Constant lookup rule" do + it "finds a toplevel constant" do + Exception.should == ::Exception + end + + it "looks up the static, lexical scope in a class method" do + ConstantSpecs::A::B::C.number.should == 47 + ConstantSpecs::A::B::C.name.should == "specs" + ConstantSpecs::A::B::C.place.should == "boston" + end + + it "looks up the static, lexical scope in an instance method" do + ConstantSpecs::A::B::C.new.number.should == 47 + ConstantSpecs::A::B::C.new.name.should == "specs" + ConstantSpecs::A::B::C.new.place.should == "boston" + end + + it "looks up the superclass chain" do + ConstantSpecs::D.new.number.should == 47 + ConstantSpecs::D.number.should == 47 + end + + it "isn't influenced by the calling scope" do + ConstantSpecs::E.new.go.should == 8 + end + + it "isn't influenced by the calling scope, in modules" do + ConstantSpecs::I.new.go.should == ::Exception + end + + it "calls const_missing on the original scope" do + ConstantSpecs::A::B::C.new.fire_missing.should == :missing! + end + + it "is bound in blocks properly" do + ConstantSpecs::Foo.foo.should == 47 + end + + it "is bound in blocks, then singletons properly" do + ConstantSpecs::Foo.foo2.should == 47 + end + + # This expectation leaves the 'LeftoverConstant' laying around in + # the Object class. Unfortunately, due to the nature of includes, + # you can't remove constants from included modules. + it "looks up in modules included in Object" do + begin + module M; LeftoverConstant = 42; end + Object.send(:include, M) + lambda { Object::LeftoverConstant }.should_not raise_error() + ensure + Object.send :remove_const, :M + end + end + + it "only searches a Module or Class" do + lambda { :File::TEST }.should raise_error(TypeError) + end +end + +describe "Constant declaration" do + it "can be done under modules" do + begin + module M; end + proc{ M::Z = 3 }.should_not raise_error() + ensure + Object.send :remove_const, :M + end + end + + it "can be done under classes" do + begin + class C; end + proc{ C::Z = 3 }.should_not raise_error() + ensure + Object.send :remove_const, :C + end + end + + it "cannot be done under other types of constants" do + begin + V = 3 + proc{ V::Z = 3 }.should raise_error(TypeError) + ensure + Object.send :remove_const, :V + end + end + + it "returns the assigned variable" do + begin + module M; end + (Y = 3).should == 3 + (M::Z = 3).should == 3 + ensure + Object.send :remove_const, :Y + Object.send :remove_const, :M rescue nil + end + end +end + diff --git a/1.8/language/def_spec.rb b/1.8/language/def_spec.rb new file mode 100644 index 0000000000..df0261c06d --- /dev/null +++ b/1.8/language/def_spec.rb @@ -0,0 +1,406 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +# Language-level method behaviour +describe "Redefining a method" do + it "replaces the original method" do + def barfoo; 100; end + barfoo.should == 100 + + def barfoo; 200; end + barfoo.should == 200 + end +end + +describe "An instance method definition with a splat" do + it "accepts an unnamed '*' argument" do + def foo(*); end; + + foo.should == nil + foo(1, 2).should == nil + foo(1, 2, 3, 4, :a, :b, 'c', 'd').should == nil + end + + it "accepts a named * argument" do + def foo(*a); a; end; + foo.should == [] + foo(1, 2).should == [1, 2] + foo([:a]).should == [[:a]] + end + + it "accepts non-* arguments before the * argument" do + def foo(a, b, c, d, e, *f); [a, b, c, d, e, f]; end + foo(1, 2, 3, 4, 5, 6, 7, 8).should == [1, 2, 3, 4, 5, [6, 7, 8]] + end + + it "creates a method that can be invoked with an inline hash argument" do + def foo(a,b,*c); [a,b,c] end + + foo('abc', 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'shit', *[789, 'yeah']). + should == + ['abc', { 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'shit'}, [789, 'yeah']] + end + + it "creates a method that can be invoked with an inline hash and a block" do + def foo(a,b,*c,&d); [a,b,c,yield(d)] end + + foo('abc', 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'shit', *[789, 'yeah']) { 3 }. + should == + ['abc', { 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'shit'}, [789, 'yeah'], 3] + + foo('abc', 'rbx' => 'cool', 'specs' => 'fail sometimes', *[789, 'yeah']) do 3 end.should == + ['abc', { 'rbx' => 'cool', 'specs' => 'fail sometimes' }, [789, 'yeah'], 3] + + l = lambda { 3 } + + foo('abc', 'rbx' => 'cool', 'specs' => 'fail sometimes', *[789, 'yeah'], &l).should == + ['abc', { 'rbx' => 'cool', 'specs' => 'fail sometimes' }, [789, 'yeah'], 3] + end + + it "allows only a single * argument" do + lambda { eval 'def foo(a, *b, *c); end' }.should raise_error(SyntaxError) + end + + it "requires the presence of any arguments that precede the *" do + def foo(a, b, *c); end + lambda { foo 1 }.should raise_error(ArgumentError) + end +end + +describe "An instance method with a default argument" do + it "evaluates the default when no arguments are passed" do + def foo(a = 1) + a + end + foo.should == 1 + foo(2).should == 2 + end + + it "assigns an empty Array to an unused splat argument" do + def foo(a = 1, *b) + [a,b] + end + foo.should == [1, []] + foo(2).should == [2, []] + end + + it "evaluates the default when required arguments precede it" do + def foo(a, b = 2) + [a,b] + end + lambda { foo }.should raise_error(ArgumentError) + foo(1).should == [1, 2] + end + + it "prefers to assign to a default argument before a splat argument" do + def foo(a, b = 2, *c) + [a,b,c] + end + lambda { foo }.should raise_error(ArgumentError) + foo(1).should == [1,2,[]] + end + + it "prefers to assign to a default argument when there are no required arguments" do + def foo(a = 1, *args) + [a,args] + end + foo(2,2).should == [2,[2]] + end + + it "does not evaluate the default when passed a value and a * argument" do + def foo(a, b = 2, *args) + [a,b,args] + end + foo(2,3,3).should == [2,3,[3]] + end +end + +describe "A singleton method definition" do + it "can be declared for a local variable" do + a = "hi" + def a.foo + 5 + end + a.foo.should == 5 + end + + it "can be declared for an instance variable" do + @a = "hi" + def @a.foo + 6 + end + @a.foo.should == 6 + end + + it "can be declared for a global variable" do + $__a__ = "hi" + def $__a__.foo + 7 + end + $__a__.foo.should == 7 + end + + it "can be declared for a class variable" do + @@a = "hi" + def @@a.foo + 8 + end + @@a.foo.should == 8 + end + + it "can be declared with an empty method body" do + class DefSpec + def self.foo;end + end + DefSpec.foo.should == nil + end +end + +describe "A method defined with extreme default arguments" do + it "can redefine itself when the default is evaluated" do + class DefSpecs + def foo(x = (def foo; "hello"; end;1));x;end + end + + d = DefSpecs.new + d.foo(42).should == 42 + d.foo.should == 1 + d.foo.should == 'hello' + end + + it "may use an fcall as a default" do + def foo(x = caller()) + x + end + foo.shift.class.should == String + end + + it "evaluates the defaults in the method's scope" do + def foo(x = ($foo_self = self; nil)); end + foo + $foo_self.should == self + end + + it "may use preceding arguments as defaults" do + def foo(obj, width=obj.length) + width + end + foo('abcde').should == 5 + end + + it "may use a lambda as a default" do + def foo(output = 'a', prc = lambda {|n| output * n}) + prc.call(5) + end + foo.should == 'aaaaa' + end +end + +describe "A singleton method defined with extreme default arguments" do + it "may use a method definition as a default" do + $__a = "hi" + def $__a.foo(x = (def $__a.foo; "hello"; end;1));x;end + + $__a.foo(42).should == 42 + $__a.foo.should == 1 + $__a.foo.should == 'hello' + end + + it "may use an fcall as a default" do + a = "hi" + def a.foo(x = caller()) + x + end + a.foo.shift.class.should == String + end + + it "evaluates the defaults in the singleton scope" do + a = "hi" + def a.foo(x = ($foo_self = self; nil)); 5 ;end + a.foo + $foo_self.should == a + end + + it "may use preceding arguments as defaults" do + a = 'hi' + def a.foo(obj, width=obj.length) + width + end + a.foo('abcde').should == 5 + end + + it "may use a lambda as a default" do + a = 'hi' + def a.foo(output = 'a', prc = lambda {|n| output * n}) + prc.call(5) + end + a.foo.should == 'aaaaa' + end +end + +describe "A method definition inside a metaclass scope" do + it "can create a class method" do + class DefSpecSingleton + class << self + def a_class_method;self;end + end + end + + DefSpecSingleton.a_class_method.should == DefSpecSingleton + lambda { Object.a_class_method }.should raise_error(NoMethodError) + end + + it "can create a singleton method" do + obj = Object.new + class << obj + def a_singleton_method;self;end + end + + obj.a_singleton_method.should == obj + lambda { Object.new.a_singleton_method }.should raise_error(NoMethodError) + end +end + +describe "A nested method definition" do + it "creates an instance method when evaluated in an instance method" do + class DefSpecNested + def create_instance_method + def an_instance_method;self;end + an_instance_method + end + end + + obj = DefSpecNested.new + obj.create_instance_method.should == obj + obj.an_instance_method.should == obj + + other = DefSpecNested.new + other.an_instance_method.should == other + + DefSpecNested.instance_methods.should include("an_instance_method") + end + + it "creates a class method when evaluated in a class method" do + class DefSpecNested + class << self + def create_class_method + def a_class_method;self;end + a_class_method + end + end + end + + lambda { DefSpecNested.a_class_method }.should raise_error(NoMethodError) + DefSpecNested.create_class_method.should == DefSpecNested + DefSpecNested.a_class_method.should == DefSpecNested + lambda { Object.a_class_method }.should raise_error(NoMethodError) + lambda { DefSpecNested.new.a_class_method }.should raise_error(NoMethodError) + end + + it "creates a singleton method when evaluated in the metaclass of an instance" do + class DefSpecNested + def create_singleton_method + class << self + def a_singleton_method;self;end + end + a_singleton_method + end + end + + obj = DefSpecNested.new + obj.create_singleton_method.should == obj + obj.a_singleton_method.should == obj + + other = DefSpecNested.new + lambda { other.a_singleton_method }.should raise_error(NoMethodError) + end +end + +describe "A method definition inside an instance_eval" do + it "creates a singleton method" do + obj = Object.new + obj.instance_eval do + def an_instance_eval_method;self;end + end + obj.an_instance_eval_method.should == obj + + other = Object.new + lambda { other.an_instance_eval_method }.should raise_error(NoMethodError) + end + + it "creates a singleton method when evaluated inside a metaclass" do + obj = Object.new + obj.instance_eval do + class << self + def a_metaclass_eval_method;self;end + end + end + obj.a_metaclass_eval_method.should == obj + + other = Object.new + lambda { other.a_metaclass_eval_method }.should raise_error(NoMethodError) + end + + it "creates a class method when the receiver is a class" do + DefSpecNested.instance_eval do + def an_instance_eval_class_method;self;end + end + + DefSpecNested.an_instance_eval_class_method.should == DefSpecNested + lambda { Object.an_instance_eval_class_method }.should raise_error(NoMethodError) + end +end + +describe "A method definition in an eval" do + it "creates an instance method" do + class DefSpecNested + def eval_instance_method + eval "def an_eval_instance_method;self;end", binding + an_eval_instance_method + end + end + + obj = DefSpecNested.new + obj.eval_instance_method.should == obj + obj.an_eval_instance_method.should == obj + + other = DefSpecNested.new + other.an_eval_instance_method.should == other + + lambda { Object.new.an_eval_instance_method }.should raise_error(NoMethodError) + end + + it "creates a class method" do + class DefSpecNestedB + class << self + def eval_class_method + eval "def an_eval_class_method;self;end" #, binding + an_eval_class_method + end + end + end + + DefSpecNestedB.eval_class_method.should == DefSpecNestedB + DefSpecNestedB.an_eval_class_method.should == DefSpecNestedB + + lambda { Object.an_eval_class_method }.should raise_error(NoMethodError) + lambda { DefSpecNestedB.new.an_eval_class_method}.should raise_error(NoMethodError) + end + + it "creates a singleton method" do + class DefSpecNested + def eval_singleton_method + class << self + eval "def an_eval_singleton_method;self;end", binding + end + an_eval_singleton_method + end + end + + obj = DefSpecNested.new + obj.eval_singleton_method.should == obj + obj.an_eval_singleton_method.should == obj + + other = DefSpecNested.new + lambda { other.an_eval_singleton_method }.should raise_error(NoMethodError) + end +end diff --git a/1.8/language/defined_spec.rb b/1.8/language/defined_spec.rb new file mode 100644 index 0000000000..7617f428b2 --- /dev/null +++ b/1.8/language/defined_spec.rb @@ -0,0 +1,122 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "A ruby environment" do + class Foo + def no_args + end + def args(x) + end + end + + class Bar < Foo + def no_args + defined?(super) + end + def args + defined?( super() ) + end + end + + it "returns true when defined?(exit) is sent" do + !!defined?(exit).should == true + end + + it "returns true when defined?(Kernel.puts) is sent (attribute)" do + !!defined?(Kernel.puts).should == true + end + + it "returns false when defined?(DoesNotExist.puts) is sent" do + !!defined?(DoesNotExist.puts).should == false + end + + it "returns true when defined?(x = 2) is sent" do + !!defined?(x = 2).should == true + end + + it "returns true when defined?(Object) is sent" do + !!defined?(Object).should == true + end + + it "returns true when @@x = 1; defined?(@@x) is sent" do + @@x = 1 + !!defined?(@@x).should == true + end + + it "returns true when @x = 1; defined?(@x) is sent" do + @x = 1 + !!defined?(@x).should == true + end + + it "returns true when $x = 1; defined?($x) is sent" do + $x = 1 + !!defined?($x).should == true + end + + it "returns true when x = 1; defined?(x) is sent" do + x = 1 + !!defined?(x).should == true + end + + it "returns true when defined? is called on a block var" do + block = Proc.new { |x| defined?(x) } + !!(block.call(1)).should == true + end + + it "returns true when defined?('foo = bar') is sent" do + !!defined?('foo = bar').should == true + end + + it "returns true when defined?(self) is sent" do + !!defined?(self).should == true + end + + it "returns true when defined?(nil) is sent" do + !!defined?(nil).should == true + end + + it "returns true when defined?(true) is sent" do + !!defined?(true).should == true + end + + it "returns true when defined?(false) is sent" do + !!defined?(false).should == true + end + + it "returns false when defined?(x) is sent" do + !!defined?(x).should == false + end + + it "returns true when defined?(:File) is sent" do + !!defined?(:File).should == true + end + + it "returns 'constant' when defined?(File) is sent" do + defined?(File).should == "constant" + end + + it "returns 'constant' when defined?(File::SEPARATOR) is sent" do + defined?(File::SEPARATOR).should == "constant" + end + + it "returns 'method' when defined?(Object.nil?) is sent" do + defined?(Object.nil?).should == "method" + end + + it "returns 'expression' when defined?(0) is sent" do + defined?(0).should == "expression" + end + + # I (Evan) am not certain we'll support defined?(super) ever. + # for now, i'm marking these as compliant. + + compliant_on :ruby do + it "returns true when Bar#no_args uses defined?" do + (!!Bar.new.no_args).should == true + end + + it "returns true when Bar#args uses defined?" do + (!!Bar.new.args).should == true + end + end +end + diff --git a/1.8/language/else_spec.rb b/1.8/language/else_spec.rb new file mode 100644 index 0000000000..91cd5b0637 --- /dev/null +++ b/1.8/language/else_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../spec_helper' diff --git a/1.8/language/ensure_spec.rb b/1.8/language/ensure_spec.rb new file mode 100644 index 0000000000..5bedb7caf1 --- /dev/null +++ b/1.8/language/ensure_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require File.dirname(__FILE__) + '/fixtures/ensure' + +describe "The ensure keyword" do + it "executes as a result of a throw within it's block" do + i = [] + catch(:exit) do + begin + i << :begin + throw :exit + ensure + i << :ensure + end + i << :after_ensure + end + i.should == [:begin,:ensure] + end + + it "is run when calling a block that contains a return" do + t = EnsureSpec::Test.new + t.do_test.should == :did_test + t.values.should == [:start, :in_block, :end] + end + + it "propagates the original exception even when exceptions are caught inside the ensure block" do + code = lambda do + begin + raise EOFError, "foo" + ensure + "".size rescue nil + end + end + code.should raise_error(EOFError) + end +end diff --git a/1.8/language/execution_spec.rb b/1.8/language/execution_spec.rb new file mode 100644 index 0000000000..465293d3ef --- /dev/null +++ b/1.8/language/execution_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Execution literal" do + it "`` should return the result of the executed sub-process" do + ip = 'world' + `echo disc #{ip}`.should == "disc world\n" + end + + # NOTE: Interpolation ? It's not consistant with %w for example. + it "%x() is the same (with also interpolation)" do + ip = 'world' + %x(echo disc #{ip}).should == "disc world\n" + end + + # NOTE: %X doesn't exist. +end diff --git a/1.8/language/file_spec.rb b/1.8/language/file_spec.rb new file mode 100644 index 0000000000..9382dd723f --- /dev/null +++ b/1.8/language/file_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +# specs for __FILE__ + +describe "The __FILE__ constant" do + it "equals the current filename" do + File.basename(__FILE__).should == "file_spec.rb" + end + + it "equals (eval) inside an eval" do + eval("__FILE__").should == "(eval)" + end +end diff --git a/1.8/language/fixtures/block.rb b/1.8/language/fixtures/block.rb new file mode 100644 index 0000000000..94867c0ff2 --- /dev/null +++ b/1.8/language/fixtures/block.rb @@ -0,0 +1,28 @@ +module BlockSpecs + class Yield + def splat(*args) + yield *args + end + + def two_args + yield 1, 2 + end + + def two_arg_array + yield [1, 2] + end + end +end + +# def block_spec_method(*args) +# yield(*args) +# end +# +# def block_spec_method2 +# yield 1, 2 +# end +# +# def block_spec_method3 +# yield [1, 2] +# end +# diff --git a/1.8/language/fixtures/constants.rb b/1.8/language/fixtures/constants.rb new file mode 100644 index 0000000000..e2b5b2c650 --- /dev/null +++ b/1.8/language/fixtures/constants.rb @@ -0,0 +1,125 @@ +module ConstantSpecs + +module A + Place = "boston" + + module B + Name = "specs" + + class C + Number = 47 + + def self.number + Number + end + + def self.name + Name + end + + def self.place + Place + end + + def number + Number + end + + def name + Name + end + + def place + Place + end + + def fire_missing + NotAround + end + + def self.const_missing(name) + :missing! + end + end + end +end + +class D < A::B::C + def self.number + Number + end + + def number + Number + end +end + +TopNumber = 8 + +class E + + TopNumber = 1 + + def go + F.new.go + end +end + +class F + def go + TopNumber + end +end + +module G + def go + Exception + end +end + +class H + include G +end + +class I + + Exception = 10 + + def go + H.new.go + end +end + +class Foo + COMMAND_LINE = 47 + + def Foo.foo + Bar.bar do + COMMAND_LINE + end + end + + def Foo.foo2 + Bar.bar do + + obj = Object.new + def obj.foo + COMMAND_LINE + end + + obj.foo + end + end +end + +class Bar + def Bar.bar + yield + end +end + +Foo.foo + + +end + diff --git a/1.8/language/fixtures/ensure.rb b/1.8/language/fixtures/ensure.rb new file mode 100644 index 0000000000..1def67b109 --- /dev/null +++ b/1.8/language/fixtures/ensure.rb @@ -0,0 +1,27 @@ +module EnsureSpec + + class Test + + def initialize + @values = [] + end + + attr_reader :values + + def call_block + begin + @values << :start + yield + ensure + @values << :end + end + end + + def do_test + call_block do + @values << :in_block + return :did_test + end + end + end +end diff --git a/1.8/language/fixtures/private.rb b/1.8/language/fixtures/private.rb new file mode 100644 index 0000000000..66682e0bbb --- /dev/null +++ b/1.8/language/fixtures/private.rb @@ -0,0 +1,59 @@ +module Private + class A + def foo + "foo" + end + + private + def bar + "bar" + end + end + + class B + def foo + "foo" + end + + private + class C + def baz + "baz" + end + end + + class << self + def public_class_method1; 1; end + private + def private_class_method1; 1; end + end + def self.public_class_method2; 2; end + + def bar + "bar" + end + end + + module D + private + def foo + "foo" + end + end + + class E + include D + end + + class F + def foo + "foo" + end + end + + class G + def foo + "foo" + end + end +end diff --git a/1.8/language/fixtures/super.rb b/1.8/language/fixtures/super.rb new file mode 100644 index 0000000000..930151d37c --- /dev/null +++ b/1.8/language/fixtures/super.rb @@ -0,0 +1,169 @@ +module Super + module S1 + class A + def foo(a) + a << "A#foo" + bar(a) + end + def bar(a) + a << "A#bar" + end + end + class B < A + def foo(a) + a << "B#foo" + super(a) + end + def bar(a) + a << "B#bar" + super(a) + end + end + end + + module S2 + class A + def baz(a) + a << "A#baz" + end + end + class B < A + def foo(a) + a << "B#foo" + baz(a) + end + end + class C < B + def baz(a) + a << "C#baz" + super(a) + end + end + end + + module S3 + class A + def foo(a) + a << "A#foo" + end + def self.foo(a) + a << "A::foo" + end + def self.bar(a) + a << "A::bar" + foo(a) + end + end + class B < A + def self.foo(a) + a << "B::foo" + super(a) + end + def self.bar(a) + a << "B::bar" + super(a) + end + end + end + + module MS1 + module ModA + def foo(a) + a << "ModA#foo" + bar(a) + end + def bar(a) + a << "ModA#bar" + end + end + class A + include ModA + end + module ModB + def bar(a) + a << "ModB#bar" + super(a) + end + end + class B < A + def foo(a) + a << "B#foo" + super(a) + end + include ModB + end + end + + module MS2 + class A + def baz(a) + a << "A#baz" + end + end + module ModB + def foo(a) + a << "ModB#foo" + baz(a) + end + end + class B < A + include ModB + end + class C < B + def baz(a) + a << "C#baz" + super(a) + end + end + end + + module MS3 + module ModA + def foo(a) + a << "ModA#foo" + end + def bar(a) + a << "ModA#bar" + foo(a) + end + end + class A + def foo(a) + a << "A#foo" + end + class << self + include ModA + end + end + class B < A + def self.foo(a) + a << "B::foo" + super(a) + end + def self.bar(a) + a << "B::bar" + super(a) + end + end + end + + module MS4 + module Layer1 + def example + 5 + end + end + + module Layer2 + include Layer1 + def example + super + end + end + + class A + include Layer2 + public :example + end + end +end diff --git a/1.8/language/fixtures/variables.rb b/1.8/language/fixtures/variables.rb new file mode 100644 index 0000000000..2689031847 --- /dev/null +++ b/1.8/language/fixtures/variables.rb @@ -0,0 +1,30 @@ +module VariablesSpecs + class ParAsgn + attr_accessor :x + + def initialize + @x = 0 + end + + def inc + @x += 1 + end + + def to_ary + [1,2,3,4] + end + end + + class OpAsgn + attr_accessor :a, :side_effect + + def do_side_effect + self.side_effect = true + return @a + end + end + + def self.reverse_foo(a, b) + return b, a + end +end diff --git a/1.8/language/fixtures/yield.rb b/1.8/language/fixtures/yield.rb new file mode 100644 index 0000000000..8af4913b74 --- /dev/null +++ b/1.8/language/fixtures/yield.rb @@ -0,0 +1,5 @@ +module YieldSpecs + def self.no_block + yield + end +end diff --git a/1.8/language/for_spec.rb b/1.8/language/for_spec.rb new file mode 100644 index 0000000000..47fdb4e513 --- /dev/null +++ b/1.8/language/for_spec.rb @@ -0,0 +1,168 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +# for name[, name]... in expr [do] +# body +# end +describe "The for expression" do + it "iterates over an Enumerable passing each element to the block" do + j = 0 + for i in 1..3 + j += i + end + j.should == 6 + end + + it "iterates over an Hash passing each key-value pair to the block" do + k = 0 + l = 0 + + for i, j in { 1 => 10, 2 => 20 } + k += i + l += j + end + + k.should == 3 + l.should == 30 + end + + it "iterates over any object responding to 'each'" do + class XYZ + def each + (0..10).each { |i| yield i } + end + end + + j = 0 + for i in XYZ.new + j += i + end + j.should == 55 + end + + it "allows an instance variable as an iterator name" do + m = [1,2,3] + n = 0 + for @var in m + n += 1 + end + @var.should == 3 + n.should == 3 + end + + # TODO: commented out due to a compiler error + #it "allows a class variable as an iterator name" do + # m = [1,2,3] + # n = 0 + # for @@var in m + # n += 1 + # end + # @@var.should == 3 + # n.should == 3 + #end + + it "splats multiple arguments together if there are fewer arguments than values" do + v = $VERBOSE + $VERBOSE = nil + class OFor + def each + [[1,2,3], [4,5,6]].each do |a| + yield(a[0],a[1],a[2]) + end + end + end + o = OFor.new + qs = [] + for q in o + qs << q + end + $VERBOSE = v + qs.should == [[1,2,3], [4,5,6]] + q.should == [4,5,6] + end + + it "optionally takes a 'do' after the expression" do + j = 0 + for i in 1..3 do + j += i + end + j.should == 6 + end + + it "allows body begin on the same line if do is used" do + j = 0 + for i in 1..3 do j += i + end + j.should == 6 + end + + it "executes code in containing variable scope" do + for i in 1..2 + a = 123 + end + + a.should == 123 + end + + it "executes code in containing variable scope with 'do'" do + for i in 1..2 do + a = 123 + end + + a.should == 123 + end + + it "returns expr" do + for i in 1..3; end.should == (1..3) + for i,j in { 1 => 10, 2 => 20 }; end.should == { 1 => 10, 2 => 20 } + end + + it "breaks out of a loop upon 'break', returning nil" do + j = 0 + for i in 1..3 + j += i + + break if i == 2 + end.should == nil + + j.should == 3 + end + + it "allows 'break' to have an argument which becomes the value of the for expression" do + for i in 1..3 + break 10 if i == 2 + end.should == 10 + end + + it "starts the next iteration with 'next'" do + j = 0 + for i in 1..5 + next if i == 2 + + j += i + end + + j.should == 13 + end + + it "repeats current iteration with 'redo'" do + j = 0 + for i in 1..3 + j += i + + redo if i == 2 && j < 4 + end + + j.should == 8 + end + + it "repeats the loop from the beginning with 'retry'" do + j = 0 + for i in 1..5 + j += i + + retry if i == 3 && j < 7 + end + + j.should == 21 + end +end diff --git a/1.8/language/hash_spec.rb b/1.8/language/hash_spec.rb new file mode 100644 index 0000000000..c5cf435450 --- /dev/null +++ b/1.8/language/hash_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Hash literal" do + it "{} should return an empty hash" do + {}.size.should == 0 + {}.should == {} + end + + it "{} should return a new hash populated with the given elements" do + h = {:a => 'a', 'b' => 3, 44 => 2.3} + h.size.should == 3 + h.should == {:a => "a", "b" => 3, 44 => 2.3} + end +end diff --git a/1.8/language/if_spec.rb b/1.8/language/if_spec.rb new file mode 100644 index 0000000000..49da288031 --- /dev/null +++ b/1.8/language/if_spec.rb @@ -0,0 +1,344 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "The if expression" do + it "evaluates body if expression is true" do + a = [] + if true + a << 123 + end + a.should == [123] + end + + it "does not evaluate body if expression is false" do + a = [] + if false + a << 123 + end + a.should == [] + end + + it "does not evaluate else-body if expression is true" do + a = [] + if true + a << 123 + else + a << 456 + end + a.should == [123] + end + + it "evaluates only else-body if expression is false" do + a = [] + if false + a << 123 + else + a << 456 + end + a.should == [456] + end + + it "returns result of then-body evaluation if expression is true" do + if true + 123 + end.should == 123 + end + + it "returns result of last statement in then-body if expression is true" do + if true + 'foo' + 'bar' + 'baz' + end.should == 'baz' + end + + it "returns result of then-body evaluation if expression is true and else part is present" do + if true + 123 + else + 456 + end.should == 123 + end + + it "returns result of else-body evaluation if expression is false" do + if false + 123 + else + 456 + end.should == 456 + end + + it "returns nil if then-body is empty and expression is true" do + if true + end.should == nil + end + + it "returns nil if then-body is empty, expression is true and else part is present" do + if true + else + 456 + end.should == nil + end + + it "returns nil if then-body is empty, expression is true and else part is empty" do + if true + else + end.should == nil + end + + it "returns nil if else-body is empty and expression is false" do + if false + 123 + else + end.should == nil + end + + it "returns nil if else-body is empty, expression is false and then-body is empty" do + if false + else + end.should == nil + end + + it "considers an expression with nil result as false" do + if nil + 123 + else + 456 + end.should == 456 + end + + it "considers a non-nil and non-boolean object in expression result as true" do + if mock('x') + 123 + else + 456 + end.should == 123 + end + + it "considers a zero integer in expression result as true" do + if 0 + 123 + else + 456 + end.should == 123 + end + + it "allows starting then-body on the same line if colon is used" do + if true: 123 + else + 456 + end.should == 123 + end + + it "allows starting else-body on the same line" do + if false + 123 + else 456 + end.should == 456 + end + + it "allows both then- and else-bodies start on the same line (with colon after expression)" do + if false: 123 + else 456 + end.should == 456 + end + + it "evaluates subsequent elsif statements and execute body of first matching" do + if false + 123 + elsif false + 234 + elsif true + 345 + elsif true + 456 + end.should == 345 + end + + it "evaluates else-body if no if/elsif statements match" do + if false + 123 + elsif false + 234 + elsif false + 345 + else + 456 + end.should == 456 + end + + it "allows ':' after expression when then-body is on the next line" do + if true: + 123 + end.should == 123 + + if true; 123; end.should == 123 + end + + it "allows 'then' after expression when then-body is on the next line" do + if true then + 123 + end.should == 123 + + if true then ; 123; end.should == 123 + end + + it "allows then-body on the same line separated with ':'" do + if true: 123 + end.should == 123 + + if true: 123; end.should == 123 + end + + it "allows then-body on the same line separated with 'then'" do + if true then 123 + end.should == 123 + + if true then 123; end.should == 123 + end + + it "returns nil when then-body on the same line separated with ':' and expression is false" do + if false: 123 + end.should == nil + + if false: 123; end.should == nil + end + + it "returns nil when then-body on the same line separated with 'then' and expression is false" do + if false then 123 + end.should == nil + + if false then 123; end.should == nil + end + + it "returns nil when then-body separated by ':' is empty and expression is true" do + if true: + end.should == nil + + if true: ; end.should == nil + end + + it "returns nil when then-body separated by 'then' is empty and expression is true" do + if true then + end.should == nil + + if true then ; end.should == nil + end + + it "returns nil when then-body separated by ':', expression is false and no else part" do + if false: + end.should == nil + + if false: ; end.should == nil + end + + it "returns nil when then-body separated by 'then', expression is false and no else part" do + if false then + end.should == nil + + if false then ; end.should == nil + end + + it "evaluates then-body when then-body separated by ':', expression is true and else part is present" do + if true: 123 + else 456 + end.should == 123 + + if true: 123; else 456; end.should == 123 + end + + it "evaluates then-body when then-body separated by 'then', expression is true and else part is present" do + if true then 123 + else 456 + end.should == 123 + + if true then 123; else 456; end.should == 123 + end + + it "evaluates else-body when then-body separated by ':' and expression is false" do + if false: 123 + else 456 + end.should == 456 + + if false: 123; else 456; end.should == 456 + end + + it "evaluates else-body when then-body separated by 'then' and expression is false" do + if false then 123 + else 456 + end.should == 456 + + if false then 123; else 456; end.should == 456 + end + + it "allows elsif-body at the same line separated by ':' or 'then'" do + if false then 123 + elsif false: 234 + elsif true then 345 + elsif true: 456 + end.should == 345 + + if false: 123; elsif false then 234; elsif true: 345; elsif true then 456; end.should == 345 + end +end + +describe "The postfix if form" do + it "evaluates statement if expression is true" do + a = [] + a << 123 if true + a.should == [123] + end + + it "does not evaluate statement if expression is false" do + a = [] + a << 123 if false + a.should == [] + end + + it "returns result of expression if value is true" do + (123 if true).should == 123 + end + + it "returns nil if expression is false" do + (123 if false).should == nil + end + + it "considers a nil expression as false" do + (123 if nil).should == nil + end + + it "considers a non-nil object as true" do + (123 if mock('x')).should == 123 + end + + it "evaluates then-body in containing scope" do + a = 123 + if true + b = a+1 + end + b.should == 124 + end + + it "evaluates else-body in containing scope" do + a = 123 + if false + b = a+1 + else + b = a+2 + end + b.should == 125 + end + + it "evaluates elsif-body in containing scope" do + a = 123 + if false + b = a+1 + elsif false + b = a+2 + elsif true + b = a+3 + else + b = a+4 + end + b.should == 126 + end +end diff --git a/1.8/language/line_spec.rb b/1.8/language/line_spec.rb new file mode 100644 index 0000000000..c2255a2cdb --- /dev/null +++ b/1.8/language/line_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "The __LINE__ constant" do + it "increments for each line" do + cline = __LINE__ + __LINE__.should == cline + 1 + # comment is at cline + 2 + __LINE__.should == cline + 3 + end + + it "is eval aware" do + eval("__LINE__").should == 1 + cmd =<= 5 + next if i == 3 + a << i + end + a.should == [1, 2, 4] + end + + it "restarts the current iteration with redo" do + a = [] + loop do + a << 1 + redo if a.size < 2 + a << 2 + break if a.size == 3 + end + a.should == [1, 1, 2] + end + + it "uses a spaghetti nightmare of redo, next and break" do + a = [] + loop do + a << 1 + redo if a.size == 1 + a << 2 + next if a.size == 3 + a << 3 + break if a.size > 6 + end + a.should == [1, 1, 2, 1, 2, 3, 1, 2, 3] + end +end diff --git a/1.8/language/metaclass_spec.rb b/1.8/language/metaclass_spec.rb new file mode 100644 index 0000000000..fd0e15f0c4 --- /dev/null +++ b/1.8/language/metaclass_spec.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/class' + +describe "self in a metaclass body (class << obj)" do + it "is TrueClass for true" do + class << true; self; end.should == TrueClass + end + + it "is FalseClass for false" do + class << false; self; end.should == FalseClass + end + + it "is NilClass for nil" do + class << nil; self; end.should == NilClass + end + + it "raises a TypeError for numbers" do + lambda { class << 1; self; end }.should raise_error(TypeError) + end + + it "raises a TypeError for symbols" do + lambda { class << :symbol; self; end }.should raise_error(TypeError) + end + + it "is a singleton Class instance" do + cls = class << mock('x'); self; end + cls.is_a?(Class).should == true + cls.equal?(Object).should == false + end + + deviates_on(:rubinius) do + it "is a MetaClass instance" do + cls = class << mock('x'); self; end + cls.is_a?(MetaClass).should == true + end + + it "has the object's class as superclass" do + cls = class << "blah"; self; end + cls.superclass.should == String + end + end + +end diff --git a/1.8/language/method_spec.rb b/1.8/language/method_spec.rb new file mode 100644 index 0000000000..e87ec33980 --- /dev/null +++ b/1.8/language/method_spec.rb @@ -0,0 +1,181 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Calling a method" do + it "just works" do + def foo(a,b,c); [a,b,c] end + + foo(1,2,3).should == [1,2,3] + end + + it "with no arguments is ok" do + def mybar; 100 end + + mybar.should == 100 + end + + it "with block as block argument is ok" do + def foo(a,&b); [a,yield(b)] end + + foo(10) do 200 end.should == [10,200] + foo(10) { 200 }.should == [10,200] + end + + it "with lambda as block argument is ok" do + def foo(a,&b); [a,yield(b)] end + + l = lambda { 300 } + foo(10, &l).should == [10,300] + end + + it "with an object that responds to 'to_proc' as a block argument coerces it to a proc" do + x = "my proc" + class << x + def to_proc; Proc.new {|y| self + y}; end + end + + def foo(&b); b.call(" called"); end + def foo2; yield(" yielded"); end + + foo(&x).should == "my proc called" + foo2(&x).should == "my proc yielded" + end + it "fails with both lambda and block argument" do + def foo(a,&b); [a,yield(b)] end + + l = lambda { 300 } + lambda { eval "foo(10, &l){ 42}"}.should raise_error(SyntaxError) + end + + it "with same names as existing variables is ok" do + foobar = 100 + + def foobar; 200; end + + foobar.should == 100 + foobar().should == 200 + end + + it "with splat operator * and literal array unpacks params" do + def foo(a,b,c); [a,b,c] end + + foo(*[1,2,3]).should == [1,2,3] + end + + it "with splat operator * and referenced array unpacks params" do + def foo(a,b,c); [a,b,c] end + + a = [1,2,3] + foo(*a).should == [1,2,3] + end + + it "without parentheses works" do + def foo(a,b,c); [a,b,c] end + + (foo 1,2,3).should == [1,2,3] + end + + it "with invalid argument count raises an ArgumentError" do + def foo(a,b,c); end + + lambda { foo }.should raise_error(ArgumentError) + lambda { foo(1,2) }.should raise_error(ArgumentError) + lambda { foo(1,2,3,4) }.should raise_error(ArgumentError) + end + + # "Allows infinite arguments" is kinda hard to spec + it "allows any number of args beyond required to method with a splat" do + def foo(a, b, *c); [c.size, c.last]; end + + a = Array.new(2500) { Object.new } + obj = a[-1] + + lambda { foo 1 }.should raise_error(ArgumentError) + + res = foo 1, 2 + res.first.should == 0 + res.last.nil?.should == true + + res = foo 1, 2, 3 + res.first.should == 1 + res.last.should == 3 + + res = foo 1, 2, 3, *a + res.first.should == 2501 + res.last.equal?(obj).should == true + end + + it "allows to pass literal hashes without curly braces as the last parameter" do + def foo(a,b,c); [a,b,c] end + + foo('abc', 456, 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'weh').should == + ['abc', 456, { 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'weh'}] + + (foo 'abc', 456, 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'weh').should == + ['abc', 456, { 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'weh'}] + end + + it "allows to literal hashes without curly braces as the only parameter" do + def foo(a); a end + + foo(:rbx => :cool, :specs => :fail_sometimes).should == + { :rbx => :cool, :specs => :fail_sometimes } + + (foo :rbx => :cool, :specs => :fail_sometimes).should == + { :rbx => :cool, :specs => :fail_sometimes } + end + + it "allows to pass argument, a hash without curly braces and a block argument" do + def foo(a,b,&c); [a,b,yield(c)] end + + foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes') { 500 }.should == + [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] + + foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes') do 500 end.should == + [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] + + l = lambda { 500 } + + foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes', &l).should == + [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] + end + + it "with range in () should give higher priority to range" do + def myfoo(x); end + + def mybar(n) + myfoo (0..n).map { } + end + + mybar(10).should == nil + end + + it "with ambiguous missing parens, arguments go with innermost call" do + def f(*a); a.length; end + + (f f 5, 6).should == 1 + + lambda { eval "f 4, f 5, 6" }.should raise_error(SyntaxError) + + [f 5, 6].should == [2] + + (f (5+6)*7).should == 1 + (f(5+6)*7).should == 7 + + a, b = f 5, 6 + a.should == 2 + b.should == nil + end + +end + +describe "Calling a private setter method" do + it "permits self as a receiver" do + class << self + attr_writer :foo + private :foo= + end + + self.foo = 42 + end +end + diff --git a/1.8/language/module_spec.rb b/1.8/language/module_spec.rb new file mode 100644 index 0000000000..7c2978bd4b --- /dev/null +++ b/1.8/language/module_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +module LangModuleSpec + module Sub1; end +end + +module LangModuleSpec::Sub2; end + +describe "module" do + it "has the right name" do + LangModuleSpec::Sub1.name.should == "LangModuleSpec::Sub1" + LangModuleSpec::Sub2.name.should == "LangModuleSpec::Sub2" + end + + it "gets a name when assigned to a constant" do + m = Module.new + LangModuleSpec::Anon = Module.new + + m.name.should == "" + LangModuleSpec::Anon.name.should == "LangModuleSpec::Anon" + end +end diff --git a/1.8/language/next_spec.rb b/1.8/language/next_spec.rb new file mode 100644 index 0000000000..55898ae75e --- /dev/null +++ b/1.8/language/next_spec.rb @@ -0,0 +1,113 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "The next statement" do + it "raises a LocalJumpError if used not within block or while/for loop" do + def bad_meth; next; end + lambda { bad_meth }.should raise_error(LocalJumpError) + end + + it "ends block execution if used within block" do + a = [] + lambda { + a << 1 + next + a << 2 + }.call + a.should == [1] + end + + it "causes block to return nil" do + lambda { 123; next; 456 }.call.should == nil + end + + it "returns the argument passed" do + lambda { 123; next 234; 345 }.call.should == 234 + end +end + +describe "Assignment via next" do + it "assigns objects" do + def r(val); a = yield(); val.should == a; end + r(nil){next} + r(nil){next nil} + r(1){next 1} + r([]){next []} + r([1]){next [1]} + r([nil]){next [nil]} + r([[]]){next [[]]} + r([]){next [*[]]} + r([1]){next [*[1]]} + r([1,2]){next [*[1,2]]} + end + + it "assigns splatted objects" do + def r(val); a = yield(); val.should == a; end + r(nil){next *nil} + r(1){next *1} + r(nil){next *[]} + r(1){next *[1]} + r(nil){next *[nil]} + r([]){next *[[]]} + r(nil){next *[*[]]} + r(1){next *[*[1]]} + r([1,2]){next *[*[1,2]]} + end + + it "assigns objects to a splatted reference" do + def r(val); *a = yield(); val.should == a; end + r([nil]){next} + r([nil]){next nil} + r([1]){next 1} + r([[]]){next []} + r([[1]]){next [1]} + r([[nil]]){next [nil]} + r([[[]]]){next [[]]} + r([[1,2]]){next [1,2]} + r([[]]){next [*[]]} + r([[1]]){next [*[1]]} + r([[1,2]]){next [*[1,2]]} + end + + it "assigns splatted objects to a splatted reference via a splatted yield" do + def r(val); *a = *yield(); val.should == a; end + r([nil]){next *nil} + r([1]){next *1} + r([nil]){next *[]} + r([1]){next *[1]} + r([nil]){next *[nil]} + r([]){next *[[]]} + r([1,2]){next *[1,2]} + r([nil]){next *[*[]]} + r([1]){next *[*[1]]} + r([1,2]){next *[*[1,2]]} + end + + it "assigns objects to multiple variables" do + def r(val); a,b,*c = yield(); val.should == [a,b,c]; end + r([nil,nil,[]]){next} + r([nil,nil,[]]){next nil} + r([1,nil,[]]){next 1} + r([nil,nil,[]]){next []} + r([1,nil,[]]){next [1]} + r([nil,nil,[]]){next [nil]} + r([[],nil,[]]){next [[]]} + r([1,2,[]]){next [1,2]} + r([nil,nil,[]]){next [*[]]} + r([1,nil,[]]){next [*[1]]} + r([1,2,[]]){next [*[1,2]]} + end + + it "assigns splatted objects to multiple variables" do + def r(val); a,b,*c = *yield(); val.should == [a,b,c]; end + r([nil,nil,[]]){next *nil} + r([1,nil,[]]){next *1} + r([nil,nil,[]]){next *[]} + r([1,nil,[]]){next *[1]} + r([nil,nil,[]]){next *[nil]} + r([nil,nil,[]]){next *[[]]} + r([1,2,[]]){next *[1,2]} + r([nil,nil,[]]){next *[*[]]} + r([1,nil,[]]){next *[*[1]]} + r([1,2,[]]){next *[*[1,2]]} + end +end diff --git a/1.8/language/not_spec.rb b/1.8/language/not_spec.rb new file mode 100644 index 0000000000..91cd5b0637 --- /dev/null +++ b/1.8/language/not_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../spec_helper' diff --git a/1.8/language/numbers_spec.rb b/1.8/language/numbers_spec.rb new file mode 100644 index 0000000000..d4f01685cb --- /dev/null +++ b/1.8/language/numbers_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Ruby numbers in various ways" do + + it "the standard way" do + 435.should == 435 + end + + it "with underscore separations" do + 4_35.should == 435 + end + + it "with some decimals" do + 4.35.should == 4.35 + end + + it "with decimals but no integer part should be a SyntaxError" do + lambda { eval(".75") }.should raise_error(SyntaxError) + lambda { eval("-.75") }.should raise_error(SyntaxError) + end + + # TODO : find a better description + it "using the e expression" do + 1.2e-3.should == 0.0012 + end + + it "the hexdecimal notation" do + 0xffff.should == 65535 + end + + it "the binary notation" do + 0b01011.should == 11 + end + + it "octal representation" do + 0377.should == 255 + end + + it "character to numeric shortcut" do + ?z.should == 122 + end + + it "character with control character to numeric shortcut" do + # Control-Z + ?\C-z.should == 26 + + # Meta-Z + ?\M-z.should == 250 + + # Meta-Control-Z + ?\M-\C-z.should == 154 + end + +end diff --git a/1.8/language/or_spec.rb b/1.8/language/or_spec.rb new file mode 100644 index 0000000000..91cd5b0637 --- /dev/null +++ b/1.8/language/or_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../spec_helper' diff --git a/1.8/language/order_spec.rb b/1.8/language/order_spec.rb new file mode 100644 index 0000000000..12bd68b896 --- /dev/null +++ b/1.8/language/order_spec.rb @@ -0,0 +1,42 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "A method call" do + before :each do + @obj = Object.new + def @obj.foo(a, b, &c) + [a, b, c ? c.call : nil] + end + end + + it "evaluates the receiver first" do + (obj = @obj).foo(obj = nil, obj = nil).should == [nil, nil, nil] + end + + it "evaluates arguments after receiver" do + a = 0 + (a += 1; @obj).foo(a, a).should == [1, 1, nil] + a.should == 1 + end + + it "evaluates arguments left-to-right" do + a = 0 + @obj.foo(a += 1, a += 1).should == [1, 2, nil] + a.should == 2 + end + + it "evaluates block pass before arguments" do + a = 0 + p = proc {true} + @obj.foo(a += 1, a += 1, &(a += 1; p)).should == [2, 3, true] + a.should == 3 + end + + it "evaluates block pass before receiver" do + p1 = proc {true} + p2 = proc {false} + p1.should_not == p2 + + p = p1 + (p = p2; @obj).foo(1, 1, &p).should == [1, 1, true] + end +end diff --git a/1.8/language/precedence_spec.rb b/1.8/language/precedence_spec.rb new file mode 100644 index 0000000000..e25026441b --- /dev/null +++ b/1.8/language/precedence_spec.rb @@ -0,0 +1,473 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +# Specifying the behavior of operators in combination could +# lead to combinatorial explosion. A better way seems to be +# to use a technique from formal proofs that involve a set of +# equivalent statements. Suppose you have statements A, B, C. +# If they are claimed to be equivalent, this can be shown by +# proving that A implies B, B implies C, and C implies A. +# (Actually any closed circuit of implications.) +# +# Here, we can use a similar technique where we show starting +# at the top that each level of operator has precedence over +# the level below (as well as showing associativity within +# the precedence level). + +=begin +Excerpted from 'Programming Ruby: The Pragmatic Programmer's Guide' +Second Edition by Dave Thomas, Chad Fowler, and Andy Hunt, page 324 + +Table 22.4. Ruby operators (high to low precedence) +Method Operator Description +----------------------------------------------------------------------- + :: . + x* [ ] [ ]= Element reference, element set + x ** Exponentiation + x ! ~ + - Not, complement, unary plus and minus + (method names for the last two are +@ and -@) + x * / % Multiply, divide, and modulo + x + - Plus and minus + x >> << Right and left shift + x & “And†(bitwise for integers) + x ^ | Exclusive “or†and regular “or†(bitwise for integers) + x <= < > >= Comparison operators + x <=> == === != =~ !~ Equality and pattern match operators (!= + and !~ may not be defined as methods) + && Logical “and†+ || Logical “or†+ .. ... Range (inclusive and exclusive) + ? : Ternary if-then-else + = %= /= -= += |= &= Assignment + >>= <<= *= &&= ||= **= + defined? Check if symbol defined + not Logical negation + or and Logical composition + if unless while until Expression modifiers + begin/end Block expression +----------------------------------------------------------------------- + +* Operators marked with 'x' in the Method column are implemented as methods +and can be overridden (except != and !~ as noted). (But see the specs +below for implementations that define != and !~ as methods.) + +** These are not included in the excerpted table but are shown here for +completeness. +=end + +# ----------------------------------------------------------------------- +# It seems that this table is not correct as of MRI 1.8.6 +# The correct table derived from MRI's parse.y is as follows: +# +# Operator Assoc Description +#--------------------------------------------------------------- +# ! ~ + > Not, complement, unary plus +# ** > Exponentiation +# - > Unary minus +# * / % < Multiply, divide, and modulo +# + - < Plus and minus +# >> << < Right and left shift +# & < “And†(bitwise for integers) +# ^ | < Exclusive “or†and regular “or†(bitwise for integers) +# <= < > >= < Comparison operators +# <=> == === != =~ !~ no Equality and pattern match operators (!= +# and !~ may not be defined as methods) +# && < Logical “and†+# || < Logical “or†+# .. ... no Range (inclusive and exclusive) +# ? : > Ternary if-then-else +# rescue < Rescue modifier +# = %= /= -= += |= &= > Assignment +# >>= <<= *= &&= ||= **= +# defined? no Check if symbol defined +# not > Logical negation +# or and < Logical composition +# if unless while until no Expression modifiers +# ----------------------------------------------------------------------- +# +# [] and []= seem to fall out of here, as well as begin/end +# + +describe "Operators" do + it "! ~ + is right-associative" do + (!!true).should == true + (~~0).should == 0 + (++2).should == 2 + end + + it "! ~ + have a higher precedence than **" do + class FalseClass; def **(a); 1000; end; end + (!0**2).should == 1000 + class FalseClass; undef_method :**; end + + class UnaryPlusTest; def +@; 50; end; end + a = UnaryPlusTest.new + (+a**2).should == 2500 + + (~0**2).should == 1 + end + + it "** is right-associative" do + (2**2**3).should == 256 + end + + it "** has higher precedence than unary minus" do + (-2**2).should == -4 + end + + it "unary minus is right-associative" do + (--2).should == 2 + end + + it "unary minus has higher precedence than * / %" do + class UnaryMinusTest; def -@; 50; end; end + b = UnaryMinusTest.new + + (-b * 5).should == 250 + (-b / 5).should == 10 + (-b % 7).should == 1 + end + + it "* / % are left-associative" do + (2*1/2).should == (2*1)/2 + (2*1/2).should_not == 2*(1/2) + + (10/7/5).should == (10/7)/5 + (10/7/5).should_not == 10/(7/5) + + (101 % 55 % 7).should == (101 % 55) % 7 + (101 % 55 % 7).should_not == 101 % (55 % 7) + + (50*20/7%42).should == ((50*20)/7)%42 + (50*20/7%42).should_not == 50*(20/(7%42)) + end + + it "* / % have higher precedence than + -" do + (2+2*2).should == 6 + (1+10/5).should == 3 + (2+10%5).should == 2 + + (2-2*2).should == -2 + (1-10/5).should == -1 + (10-10%4).should == 8 + end + + it "+ - are left-associative" do + (2-3-4).should == -5 + (4-3+2).should == 3 + + class BinaryPlusTest < String; alias_method :plus, :+; def +(a); plus(a) + "!"; end; end + s = BinaryPlusTest.new("a") + + (s+s+s).should == (s+s)+s + (s+s+s).should_not == s+(s+s) + end + + it "+ - have higher precedence than >> <<" do + (2<<1+2).should == 16 + (8>>1+2).should == 1 + (4<<1-3).should == 1 + (2>>1-3).should == 8 + end + + it ">> << are left-associative" do + (1 << 2 << 3).should == 32 + (10 >> 1 >> 1).should == 2 + (10 << 4 >> 1).should == 80 + end + + it ">> << have higher precedence than &" do + (4 & 2 << 1).should == 4 + (2 & 4 >> 1).should == 2 + end + + it "& is left-associative" do + class BitwiseAndTest; def &(a); a+1; end; end + c = BitwiseAndTest.new + + (c & 5 & 2).should == (c & 5) & 2 + (c & 5 & 2).should_not == c & (5 & 2) + end + + it "& has higher precedence than ^ |" do + (8 ^ 16 & 16).should == 24 + (8 | 16 & 16).should == 24 + end + + it "^ | are left-associative" do + class OrAndXorTest; def ^(a); a+10; end; def |(a); a-10; end; end + d = OrAndXorTest.new + + (d ^ 13 ^ 16).should == (d ^ 13) ^ 16 + (d ^ 13 ^ 16).should_not == d ^ (13 ^ 16) + + (d | 13 | 4).should == (d | 13) | 4 + (d | 13 | 4).should_not == d | (13 | 4) + end + + it "^ | have higher precedence than <= < > >=" do + (10 <= 7 ^ 7).should == false + (10 < 7 ^ 7).should == false + (10 > 7 ^ 7).should == true + (10 >= 7 ^ 7).should == true + (10 <= 7 | 7).should == false + (10 < 7 | 7).should == false + (10 > 7 | 7).should == true + (10 >= 7 | 7).should == true + end + + it "<= < > >= are left-associative" do + class ComparisonTest + def <=(a); 0; end; + def <(a); 0; end; + def >(a); 0; end; + def >=(a); 0; end; + end + + e = ComparisonTest.new + + (e <= 0 <= 1).should == (e <= 0) <= 1 + (e <= 0 <= 1).should_not == e <= (0 <= 1) + + (e < 0 < 1).should == (e < 0) < 1 + (e < 0 < 1).should_not == e < (0 < 1) + + (e >= 0 >= 1).should == (e >= 0) >= 1 + (e >= 0 >= 1).should_not == e >= (0 >= 1) + + (e > 0 > 1).should == (e > 0) > 1 + (e > 0 > 1).should_not == e > (0 > 1) + end + + it "<= < > >= have higher precedence than <=> == === != =~ !~" do + (1 <=> 5 < 1).should == nil + (1 <=> 5 <= 1).should == nil + (1 <=> 5 > 1).should == nil + (1 <=> 5 >= 1).should == nil + + (1 == 5 < 1).should == false + (1 == 5 <= 1).should == false + (1 == 5 > 1).should == false + (1 == 5 >= 1).should == false + + (1 === 5 < 1).should == false + (1 === 5 <= 1).should == false + (1 === 5 > 1).should == false + (1 === 5 >= 1).should == false + + (1 != 5 < 1).should == true + (1 != 5 <= 1).should == true + (1 != 5 > 1).should == true + (1 != 5 >= 1).should == true + + (1 =~ 5 < 1).should == false + (1 =~ 5 <= 1).should == false + (1 =~ 5 > 1).should == false + (1 =~ 5 >= 1).should == false + + (1 !~ 5 < 1).should == true + (1 !~ 5 <= 1).should == true + (1 !~ 5 > 1).should == true + (1 !~ 5 >= 1).should == true + end + + it "<=> == === != =~ !~ are non-associative" do + lambda { eval("1 <=> 2 <=> 3") }.should raise_error(SyntaxError) + lambda { eval("1 == 2 == 3") }.should raise_error(SyntaxError) + lambda { eval("1 === 2 === 3") }.should raise_error(SyntaxError) + lambda { eval("1 != 2 != 3") }.should raise_error(SyntaxError) + lambda { eval("1 =~ 2 =~ 3") }.should raise_error(SyntaxError) + lambda { eval("1 !~ 2 !~ 3") }.should raise_error(SyntaxError) + end + + it "<=> == === != =~ !~ have higher precedence than &&" do + (false && 2 <=> 3).should == false + (false && 3 == false).should == false + (false && 3 === false).should == false + (false && 3 != true).should == false + + class FalseClass; def =~(o); o == false; end; end + (false && true =~ false).should == (false && (true =~ false)) + (false && true =~ false).should_not == ((false && true) =~ false) + class FalseClass; undef_method :=~; end + + (false && true !~ true).should == false + end + + it "&& is left-associative" do + # XXX: figure out how to test it + # (a && b) && c equals to a && (b && c) for all a,b,c values I can imagine so far + end + + it "&& has higher precedence than ||" do + (true || false && false).should == true + end + + it "|| is left-associative" do + # XXX: figure out how to test it + end + + it "|| has higher precedence than .. ..." do + (1..false||10).should == (1..10) + (1...false||10).should == (1...10) + end + + it ".. ... are non-associative" do + lambda { eval("1..2..3") }.should raise_error(SyntaxError) + lambda { eval("1...2...3") }.should raise_error(SyntaxError) + end + +# XXX: this is commented now due to a bug in compiler, which cannot +# distinguish between range and flip-flop operator so far. zenspider is +# currently working on a new lexer, which will be able to do that. +# As soon as it's done, these piece should be reenabled. +# +# it ".. ... have higher precedence than ? :" do +# (1..2 ? 3 : 4).should == 3 +# (1...2 ? 3 : 4).should == 3 +# end + + it "? : is right-associative" do + (true ? 2 : 3 ? 4 : 5).should == 2 + end + + def oops; raise end + + it "? : has higher precedence than rescue" do + + (true ? oops : 0 rescue 10).should == 10 + end + + it "rescue is left-associative" do + # XXX: figure how to test it (problem similar to || associativity) + end + + it "rescue has higher precedence than =" do + a = oops rescue 10 + a.should == 10 + + # rescue doesn't have the same sense for %= /= and friends + end + + it "= %= /= -= += |= &= >>= <<= *= &&= ||= **= are right-associative" do + a = b = 10 + a.should == 10 + b.should == 10 + + a = b = 10 + a %= b %= 3 + a.should == 0 + b.should == 1 + + a = b = 10 + a /= b /= 2 + a.should == 2 + b.should == 5 + + a = b = 10 + a -= b -= 2 + a.should == 2 + b.should == 8 + + a = b = 10 + a += b += 2 + a.should == 22 + b.should == 12 + + a,b = 32,64 + a |= b |= 2 + a.should == 98 + b.should == 66 + + a,b = 25,13 + a &= b &= 7 + a.should == 1 + b.should == 5 + + a,b=8,2 + a >>= b >>= 1 + a.should == 4 + b.should == 1 + + a,b=8,2 + a <<= b <<= 1 + a.should == 128 + b.should == 4 + + a,b=8,2 + a *= b *= 2 + a.should == 32 + b.should == 4 + + a,b=10,20 + a &&= b &&= false + a.should == false + b.should == false + + a,b=nil,nil + a ||= b ||= 10 + a.should == 10 + b.should == 10 + + a,b=2,3 + a **= b **= 2 + a.should == 512 + b.should == 9 + end + + it "= %= /= -= += |= &= >>= <<= *= &&= ||= **= have higher precedence than defined? operator" do + (defined? a = 10).should_not == nil + (defined? a %= 10).should_not == nil + (defined? a /= 10).should_not == nil + (defined? a -= 10).should_not == nil + (defined? a += 10).should_not == nil + (defined? a |= 10).should_not == nil + (defined? a &= 10).should_not == nil + (defined? a >>= 10).should_not == nil + (defined? a <<= 10).should_not == nil + (defined? a *= 10).should_not == nil + (defined? a &&= 10).should_not == nil + (defined? a ||= 10).should_not == nil + (defined? a **= 10).should_not == nil + end + + it "defined? is non-associative" do + # XXX: figure out how to test it + end + + it "defined? has higher precedence than not" do + # does it have sense? + (not defined? qqq).should == true + end + + it "not is right-associative" do + (not not false).should == false + (not not 10).should == true + end + + it "not has higher precedence than or/and" do + (not false and false).should == false + (not false or true).should == true + end + + it "or/and are left-associative" do + # XXX: figure out how to test it + end + + it "or/and have higher precedence than if unless while until modifiers" do + (1 if 2 and 3).should == 1 + (1 if 2 or 3).should == 1 + + (1 unless false and true).should == 1 + (1 unless false or false).should == 1 + + (1 while true and false).should == nil # would hang upon error + (1 while false or false).should == nil + + ((raise until true and false) rescue 10).should == 10 + (1 until false or true).should == nil # would hang upon error + end + + it "if unless while until are non-associative" do + # XXX: it seems to me they are right-associative + end +end diff --git a/1.8/language/predefined_spec.rb b/1.8/language/predefined_spec.rb new file mode 100644 index 0000000000..69b1b4d0fd --- /dev/null +++ b/1.8/language/predefined_spec.rb @@ -0,0 +1,431 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require 'stringio' + +# The following tables are excerpted from Programming Ruby: The Pragmatic Programmer's Guide' +# Second Edition by Dave Thomas, Chad Fowler, and Andy Hunt, page 319-22. +# +# Entries marked [r/o] are read-only and an error will be raised of the program attempts to +# modify them. Entries marked [thread] are thread local. + +=begin +Exception Information +--------------------------------------------------------------------------------------------------- + +$! Exception The exception object passed to raise. [thread] +$@ Array The stack backtrace generated by the last exception. [thread] +=end + +=begin +Pattern Matching Variables +--------------------------------------------------------------------------------------------------- + +These variables (except $=) are set to nil after an unsuccessful pattern match. + +$& String The string matched (following a successful pattern match). This variable is + local to the current scope. [r/o, thread] +$+ String The contents of the highest-numbered group matched following a successful + pattern match. Thus, in "cat" =~/(c|a)(t|z)/, $+ will be set to “tâ€. This + variable is local to the current scope. [r/o, thread] +$` String The string preceding the match in a successful pattern match. This variable + is local to the current scope. [r/o, thread] +$' String The string following the match in a successful pattern match. This variable + is local to the current scope. [r/o, thread] +$= Object Deprecated.1.8 If set to any value apart from nil or false, all pattern matches + will be case insensitive, string comparisons will ignore case, and string hash + values will be case insensitive. +$1 to $9 String The contents of successive groups matched in a successful pattern match. In + "cat" =~/(c|a)(t|z)/, $1 will be set to “a†and $2 to “tâ€. This variable + is local to the current scope. [r/o, thread] +$~ MatchData An object that encapsulates the results of a successful pattern match. The + variables $&, $`, $', and $1 to $9 are all derived from $~. Assigning to $~ + changes the values of these derived variables. This variable is local to the + current scope. [thread] +=end + + +describe "Predefined global $~" do + it "is set to contain the MatchData object of the last match if successful" do + md = /foo/.match 'foo' + $~.class.should == MatchData + $~.object_id.should == md.object_id + + /bar/ =~ 'bar' + $~.class.should == MatchData + $~.object_id.should_not == md.object_id + end + + it "is set to nil if the last match was unsuccessful" do + /foo/ =~ 'foo' + $~.nil?.should == false + + /foo/ =~ 'bar' + $~.nil?.should == true + end + + it "is set at the method-scoped level rather than block-scoped" do + obj = Object.new + def obj.foo; yield; end + def obj.foo2(&proc); proc.call; end + + match = /foo/.match "foo" + + obj.foo { match = /bar/.match("bar") } + + $~.should == match + + eval 'match = /baz/.match("baz")' + + $~.should == match + + obj.foo2 { match = /qux/.match("qux") } + + $~.should == match + end + + it "raises an error if assigned an object not nil or instanceof MatchData" do + lambda { $~ = nil }.should_not raise_error + lambda { $~ = /foo/.match("foo") }.should_not raise_error + lambda { $~ = Object.new }.should raise_error(TypeError) + lambda { $~ = 1 }.should raise_error(TypeError) + end +end + +describe "Predefined global $&" do + it "is equivalent to MatchData#[0] on the last match $~" do + /foo/ =~ 'barfoobaz' + $&.should == $~[0] + $&.should == 'foo' + end +end + +describe "Predefined global $`" do + it "is equivalent to MatchData#pre_match on the last match $~" do + /foo/ =~ 'barfoobaz' + $`.should == $~.pre_match + $`.should == 'bar' + end +end + +describe "Predefined global $'" do + it "is equivalent to MatchData#post_match on the last match $~" do + /foo/ =~ 'barfoobaz' + $'.should == $~.post_match + $'.should == 'baz' + end +end + +describe "Predefined global $+" do + it "is equivalent to $~.captures.last" do + /(f(o)o)/ =~ 'barfoobaz' + # causes a compiler exception as of 036b07375 + # $+.should == $~.captures.last + # $+.should == 'o' + end +end + +describe "Predefined globals $1..N" do + it "are equivalent to $~[N]" do + /(f)(o)(o)/ =~ 'foo' + $1.should == $~[1] + $2.should == $~[2] + $3.should == $~[3] + $4.should == $~[4] + + [$1, $2, $3, $4].should == ['f', 'o', 'o', nil] + end +end + +=begin +Input/Output Variables +--------------------------------------------------------------------------------------------------- + +$/ String The input record separator (newline by default). This is the value that rou- + tines such as Kernel#gets use to determine record boundaries. If set to + nil, gets will read the entire file. +$-0 String Synonym for $/. +$\ String The string appended to the output of every call to methods such as + Kernel#print and IO#write. The default value is nil. +$, String The separator string output between the parameters to methods such as + Kernel#print and Array#join. Defaults to nil, which adds no text. +$. Fixnum The number of the last line read from the current input file. +$; String The default separator pattern used by String#split. May be set from the + command line using the -F flag. +$< Object An object that provides access to the concatenation of the contents of all + the files given as command-line arguments or $stdin (in the case where + there are no arguments). $< supports methods similar to a File object: + binmode, close, closed?, each, each_byte, each_line, eof, eof?, + file, filename, fileno, getc, gets, lineno, lineno=, path, pos, pos=, + read, readchar, readline, readlines, rewind, seek, skip, tell, to_a, + to_i, to_io, to_s, along with the methods in Enumerable. The method + file returns a File object for the file currently being read. This may change + as $< reads through the files on the command line. [r/o] +$> IO The destination of output for Kernel#print and Kernel#printf. The + default value is $stdout. +$_ String The last line read by Kernel#gets or Kernel#readline. Many string- + related functions in the Kernel module operate on $_ by default. The vari- + able is local to the current scope. [thread] +$-F String Synonym for $;. +$stderr IO The current standard error output. +$stdin IO The current standard input. +$stdout IO The current standard output. Assignment to $stdout is deprecated: use + $stdout.reopen instead. +=end + + +describe "Predefined global $_" do + it "is set to the last line read by e.g. StringIO#gets" do + stdin = StringIO.new("foo\nbar\n", "r") + + read = stdin.gets + read.should == "foo\n" + $_.should == read + + read = stdin.gets + read.should == "bar\n" + $_.should == read + + read = stdin.gets + read.should == nil + $_.should == read + end + + it "is set at the method-scoped level rather than block-scoped" do + obj = Object.new + def obj.foo; yield; end + def obj.foo2; yield; end + + stdin = StringIO.new("foo\nbar\nbaz\nqux\n", "r") + match = stdin.gets + + obj.foo { match = stdin.gets } + + match.should == "bar\n" + $_.should == match + + eval 'match = stdin.gets' + + match.should == "baz\n" + $_.should == match + + obj.foo2 { match = stdin.gets } + + match.should == "qux\n" + $_.should == match + end + + it "can be assigned any value" do + lambda { $_ = nil }.should_not raise_error + lambda { $_ = "foo" }.should_not raise_error + lambda { $_ = Object.new }.should_not raise_error + lambda { $_ = 1 }.should_not raise_error + end +end + +=begin +Execution Environment Variables +--------------------------------------------------------------------------------------------------- + +$0 String The name of the top-level Ruby program being executed. Typically this will + be the program’s filename. On some operating systems, assigning to this + variable will change the name of the process reported (for example) by the + ps(1) command. +$* Array An array of strings containing the command-line options from the invoca- + tion of the program. Options used by the Ruby interpreter will have been + removed. [r/o] +$" Array An array containing the filenames of modules loaded by require. [r/o] +$$ Fixnum The process number of the program being executed. [r/o] +$? Process::Status The exit status of the last child process to terminate. [r/o, thread] +$: Array An array of strings, where each string specifies a directory to be searched for + Ruby scripts and binary extensions used by the load and require methods. + The initial value is the value of the arguments passed via the -I command- + line option, followed by an installation-defined standard library location, fol- + lowed by the current directory (“.â€). This variable may be set from within a + program to alter the default search path; typically, programs use $: << dir + to append dir to the path. [r/o] +$-a Object True if the -a option is specified on the command line. [r/o] +$-d Object Synonym for $DEBUG. +$DEBUG Object Set to true if the -d command-line option is specified. +__FILE__ String The name of the current source file. [r/o] +$F Array The array that receives the split input line if the -a command-line option is + used. +$FILENAME String The name of the current input file. Equivalent to $<.filename. [r/o] +$-i String If in-place edit mode is enabled (perhaps using the -i command-line + option), $-i holds the extension used when creating the backup file. If you + set a value into $-i, enables in-place edit mode. +$-I Array Synonym for $:. [r/o] +$-K String Sets the multibyte coding system for strings and regular expressions. Equiv- + alent to the -K command-line option. +$-l Object Set to true if the -l option (which enables line-end processing) is present + on the command line. [r/o] +__LINE__ String The current line number in the source file. [r/o] +$LOAD_PATH Array A synonym for $:. [r/o] +$-p Object Set to true if the -p option (which puts an implicit while gets . . . end + loop around your program) is present on the command line. [r/o] +$SAFE Fixnum The current safe level. This variable’s value may never be + reduced by assignment. [thread] +$VERBOSE Object Set to true if the -v, --version, -W, or -w option is specified on the com- + mand line. Set to false if no option, or -W1 is given. Set to nil if -W0 + was specified. Setting this option to true causes the interpreter and some + library routines to report additional information. Setting to nil suppresses + all warnings (including the output of Kernel.warn). +$-v Object Synonym for $VERBOSE. +$-w Object Synonym for $VERBOSE. +=end + +=begin +Standard Objects +--------------------------------------------------------------------------------------------------- + +ARGF Object A synonym for $<. +ARGV Array A synonym for $*. +ENV Object A hash-like object containing the program’s environment variables. An + instance of class Object, ENV implements the full set of Hash methods. Used + to query and set the value of an environment variable, as in ENV["PATH"] + and ENV["term"]="ansi". +false FalseClass Singleton instance of class FalseClass. [r/o] +nil NilClass The singleton instance of class NilClass. The value of uninitialized + instance and global variables. [r/o] +self Object The receiver (object) of the current method. [r/o] +true TrueClass Singleton instance of class TrueClass. [r/o] +=end + +describe "The predefined standard objects" do + it "includes ARGF" do + Object.const_defined?(:ARGF).should == true + end + + it "includes ARGV" do + Object.const_defined?(:ARGV).should == true + end + + it "includes a hash-like object ENV" do + Object.const_defined?(:ENV).should == true + ENV.respond_to?(:[]).should == true + end +end + +describe "The predefined standard object nil" do + it "is an instance of NilClass" do + nil.class.should == NilClass + end + + it "raises a SyntaxError if assigned to" do + # this needs to be tested with a subprocess because + # MRI aborts reading in the file + end +end + +describe "The predefined standard object true" do + it "is an instance of TrueClass" do + true.class.should == TrueClass + end + + it "raises a SyntaxError if assigned to" do + # this needs to be tested with a subprocess because + # MRI aborts reading in the file + end +end + +describe "The predefined standard object false" do + it "is an instance of FalseClass" do + false.class.should == FalseClass + end + + it "raises a SyntaxError if assigned to" do + # this needs to be tested with a subprocess because + # MRI aborts reading in the file + end +end + +=begin +Global Constants +--------------------------------------------------------------------------------------------------- + +The following constants are defined by the Ruby interpreter. + +DATA IO If the main program file contains the directive __END__, then + the constant DATA will be initialized so that reading from it will + return lines following __END__ from the source file. +FALSE FalseClass Synonym for false. +NIL NilClass Synonym for nil. +RUBY_PLATFORM String The identifier of the platform running this program. This string + is in the same form as the platform identifier used by the GNU + configure utility (which is not a coincidence). +RUBY_RELEASE_DATE String The date of this release. +RUBY_VERSION String The version number of the interpreter. +STDERR IO The actual standard error stream for the program. The initial + value of $stderr. +STDIN IO The actual standard input stream for the program. The initial + value of $stdin. +STDOUT IO The actual standard output stream for the program. The initial + value of $stdout. +SCRIPT_LINES__ Hash If a constant SCRIPT_LINES__ is defined and references a Hash, + Ruby will store an entry containing the contents of each file it + parses, with the file’s name as the key and an array of strings as + the value. +TOPLEVEL_BINDING Binding A Binding object representing the binding at Ruby’s top level— + the level where programs are initially executed. +TRUE TrueClass Synonym for true. +=end + +describe "The predefined global constants" do + it "includes DATA when main script contains __END__" do + ruby = IO.popen(RUBY_NAME, "w+") + ruby.puts( + "puts Object.const_defined?(:DATA)", + "__END__" + ) + ruby.close_write + ruby.gets.chomp.should == 'true' + end + + it "does not include DATA when main script contains no __END__" do + ruby = IO.popen(RUBY_NAME, "w+") + ruby.puts("puts Object.const_defined?(:DATA)") + ruby.close_write + ruby.gets.chomp.should == 'false' + end + + it "includes TRUE" do + Object.const_defined?(:TRUE).should == true + TRUE.equal?(true).should == true + end + + it "includes FALSE" do + Object.const_defined?(:FALSE).should == true + FALSE.equal?(false).should == true + end + + it "includes NIL" do + Object.const_defined?(:NIL).should == true + NIL.equal?(nil).should == true + end + + it "includes STDIN" do + Object.const_defined?(:STDIN).should == true + end + + it "includes STDOUT" do + Object.const_defined?(:STDOUT).should == true + end + + it "includes STDERR" do + Object.const_defined?(:STDERR).should == true + end + + it "includes RUBY_VERSION" do + Object.const_defined?(:RUBY_VERSION).should == true + end + + it "includes RUBY_RELEASE_DATE" do + Object.const_defined?(:RUBY_RELEASE_DATE).should == true + end + + it "includes RUBY_PLATFORM" do + Object.const_defined?(:RUBY_PLATFORM).should == true + end + + it "includes TOPLEVEL_BINDING" do + Object.const_defined?(:TOPLEVEL_BINDING).should == true + end +end diff --git a/1.8/language/private_spec.rb b/1.8/language/private_spec.rb new file mode 100644 index 0000000000..d9651d05dc --- /dev/null +++ b/1.8/language/private_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require File.dirname(__FILE__) + '/fixtures/private' + +describe "The private keyword" do + it "marks following methods as being private" do + a = Private::A.new + a.methods.should_not include("bar") + lambda { a.bar }.should raise_error(NoMethodError) + + b = Private::B.new + b.methods.should_not include("bar") + lambda { b.bar }.should raise_error(NoMethodError) + end + + it "is overridden when a new class is opened" do + c = Private::B::C.new + c.methods.should include("baz") + c.baz + Private::B::public_class_method1.should == 1 + Private::B::public_class_method2.should == 2 + lambda { Private::B::private_class_method1 }.should raise_error(NoMethodError) + end + + it "is no longer in effect when the class is closed" do + b = Private::B.new + b.methods.should include("foo") + b.foo + end + + it "changes visibility of previously called method" do + f = Private::F.new + f.foo + module Private + class F + private :foo + end + end + lambda { f.foo }.should raise_error(NoMethodError) + end + + it "changes visiblity of previously called methods with same send/call site" do + g = Private::G.new + lambda { + 2.times do + g.foo + module Private + class G + private :foo + end + end + end + }.should raise_error(NoMethodError) + end +end diff --git a/1.8/language/raise_spec.rb b/1.8/language/raise_spec.rb new file mode 100644 index 0000000000..e1922aef5c --- /dev/null +++ b/1.8/language/raise_spec.rb @@ -0,0 +1,244 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Exceptions" do + it "raise should abort execution" do + lambda { + begin + raise ArgumentError, "you don't know what you're talking about" + rescue ArgumentError => e + e.message.should == "you don't know what you're talking about" + raise + end + }.should raise_error(ArgumentError) + end + + # FIXME: code string is only necessary because ensure crashes shotgun + it "ensure should execute when exception is raised" do + module RaiseSpecs + class A + def exception + begin + raise ArgumentError, "exception" + rescue Exception => @e + # pass + ensure + @a = 'ensure ' << @e + end + @a + end + end + end + + RaiseSpecs::A.new.exception.should == "ensure exception" + end + + # FIXME: code string is only necessary because ensure crashes shotgun + it "ensure should execute when exception is not raised" do + class B + def exception + begin + @e = 'I never got to be an exception' + rescue Exception => @e + @e.message + ensure + @a = 'ensure ' << @e + end + return @a + end + end + + B.new.exception.should == "ensure I never got to be an exception" + end + + it "the result of ensure should be elided" do + begin + true + ensure + false + end.should == true + end + + it "the result of else should be returned when no exception is raised" do + begin + true + rescue + 5 + else + 6 + end.should == 6 + end + + it "the result of else should be returned when no exception is raised, even with an ensure" do + begin + true + rescue + 5 + else + 6 + ensure + 7 + end.should == 6 + end + + it "the result of else should be returned even if the body is empty" do + begin + rescue + 1 + else + 2 + end.should == 2 + end + + it "retry should restart execution at begin" do + class C + def exception + @ret = [] + @count = 1 + begin + @ret << @count + raise ArgumentError, 'just kidding' unless @count > 3 + rescue Exception => @e + @count += 1 + retry + else + @ret << 7 + ensure + @ret << @count + end + @ret + end + end + + C.new.exception.should == [1, 2, 3, 4, 7, 4] + end + + it "on a single line, a default can be assigned on exception" do + variable = [1,2,3].frist rescue 'exception' + variable.should == 'exception' + end + + it "that exceptions are not cleared exiting a thread" do + lambda { Thread.new { raise RangeError }.join }.should raise_error(RangeError) + end + + it "that StandardError is the default rescue class" do + begin + @ret = '' + begin + raise Exception, 'hey hey hey !' + rescue => ex + @ret = 'intercepted' + end + rescue Exception => ex + @ret = 'not intercepted' + end.should == 'not intercepted' + + begin + @ret = '' + begin + raise StandardError, 'hey hey hey !' + rescue => ex + @ret = 'intercepted' + end + rescue Exception => ex + @ret = 'not intercepted' + end.should == 'intercepted' + end + + it "that RuntimeError is the default raise class" do + begin + @ret = '' + raise + rescue => ex + @ret = ex.class.to_s + end.should == 'RuntimeError' + end + + it "that $! is cleared when an exception is rescued" do + begin + raise + rescue + end + $!.should == nil + end + + EXCEPTION_TREE = [ + :Exception, [ + :ScriptError, [ + :LoadError, + :NotImplementedError, + :SyntaxError + ], + :SignalException, [ + :Interrupt + ], + :StandardError, [ # default for rescue + :ArgumentError, + :IOError, [ + :EOFError + ], + :IndexError, + :LocalJumpError, + :NameError, [ + :NoMethodError + ], + :RangeError, [ + :FloatDomainError + ], + :RegexpError, + :RuntimeError, # default for raise + :SecurityError, + :SystemCallError, # FIXME : Errno::* missing + :SystemStackError, + :ThreadError, + :TypeError, + :ZeroDivisionError + ], + :SystemExit + ] + ] + + @exception_stack = [] + @last_exception = nil + + generate_exception_existance_spec = lambda do |exception_name| + it "exception #{exception_name} is in the core" do + Object.const_defined?(exception_name).should == true + end + end + + generate_exception_ancestor_spec = lambda do |exception_name, parent_name| + it "#{exception_name} has #{parent_name} as ancestor" do + exception = Object.const_get(exception_name.to_sym) + ancestors = exception.ancestors.map { |x| x.to_s } + ancestors.include?(parent_name.to_s).should == true + end + end + + build_spec_tree = lambda do |tree| + tree.each do |element| + case element + when Array + if @exception_stack + @exception_stack.push(@last_exception) + build_spec_tree.call(element) + @exception_stack.pop() + @last_exception = nil + else + raise 'Spec generation error, this case should never occur' + end + else + generate_exception_existance_spec.call(element) + @exception_stack.each do |parent_name| + generate_exception_ancestor_spec.call(element, parent_name) + end + @last_exception = element + end + end + end + + build_spec_tree.call(EXCEPTION_TREE) + + +end + diff --git a/1.8/language/redo_spec.rb b/1.8/language/redo_spec.rb new file mode 100644 index 0000000000..e97141c33e --- /dev/null +++ b/1.8/language/redo_spec.rb @@ -0,0 +1,49 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "The redo statement" do + it "raises a LocalJumpError if used not within block or while/for loop" do + def bad_meth_redo; redo; end + lambda { bad_meth_redo() }.should raise_error(LocalJumpError) + end + + it "restarts block execution if used within block" do + a = [] + lambda { + a << 1 + redo if a.size < 2 + a << 2 + }.call + a.should == [1, 1, 2] + end + + it "re-executes the closest loop" do + exist = [2,3] + processed = [] + order = [] + [1,2,3,4].each do |x| + order << x + begin + processed << x + if(exist.include?(x)) + raise StandardError, "included" + end + rescue StandardError => e + exist.delete(x) + redo + end + end + processed.should == [1,2,2,3,3,4] + exist.should == [] + order.should == [1,2,2,3,3,4] + end + + it "re-executes the last step in enumeration" do + list = [] + [1,2,3].each do |x| + list << x + break if list.size == 6 + redo if x == 3 + end + list.should == [1,2,3,3,3,3] + end +end diff --git a/1.8/language/regexp_spec.rb b/1.8/language/regexp_spec.rb new file mode 100644 index 0000000000..2ea3e8c846 --- /dev/null +++ b/1.8/language/regexp_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Literal Regexps" do + it "matches against $_ (last input) in a conditional if no explicit matchee provided" do + $_ = nil + + (true if /foo/).should_not == true + + $_ = "foo" + + (true if /foo/).should == true + end +end diff --git a/1.8/language/rescue_spec.rb b/1.8/language/rescue_spec.rb new file mode 100644 index 0000000000..91cd5b0637 --- /dev/null +++ b/1.8/language/rescue_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../spec_helper' diff --git a/1.8/language/retry_spec.rb b/1.8/language/retry_spec.rb new file mode 100644 index 0000000000..5c3269f214 --- /dev/null +++ b/1.8/language/retry_spec.rb @@ -0,0 +1,52 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "The retry statement" do + it "raises a LocalJumpError if used outside of a block" do + def bad_meth_retry; retry; end + lambda { bad_meth_retry() }.should raise_error(LocalJumpError) + lambda { lambda { retry }.call }.should raise_error(LocalJumpError) + end + + it "re-executes the closest block" do + retry_first = true + retry_second = true + results = [] + begin + results << 1 + raise + rescue + results << 2 + if retry_first + results << 3 + retry_first = false + retry + end + begin + results << 4 + raise + rescue + results << 5 + if retry_second + results << 6 + retry_second = false + retry + end + end + end + + results.should == [1, 2, 3, 1, 2, 4, 5, 6, 4, 5] + end + + # block retry has been officially deprecated by matz and is unsupported in 1.9 + compliant_on :ruby do + it "re-executes the entire enumeration" do + list = [] + [1,2,3].each do |x| + list << x + break if list.size == 6 + retry if x == 3 + end + list.should == [1,2,3,1,2,3] + end + end +end diff --git a/1.8/language/return_spec.rb b/1.8/language/return_spec.rb new file mode 100644 index 0000000000..81e2668b4a --- /dev/null +++ b/1.8/language/return_spec.rb @@ -0,0 +1,168 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Assignment via return" do + it "assigns objects to block variables" do + def r; return nil; end; a = r(); a.should == nil + def r; return 1; end; a = r(); a.should == 1 + def r; return []; end; a = r(); a.should == [] + def r; return [1]; end; a = r(); a.should == [1] + def r; return [nil]; end; a = r(); a.should == [nil] + def r; return [[]]; end; a = r(); a.should == [[]] + def r; return [*[]]; end; a = r(); a.should == [] + def r; return [*[1]]; end; a = r(); a.should == [1] + def r; return [*[1,2]]; end; a = r(); a.should == [1,2] + end + + it "assigns splatted objects to block variables" do + def r; return *nil; end; a = r(); a.should == nil + def r; return *1; end; a = r(); a.should == 1 + def r; return *[]; end; a = r(); a.should == nil + def r; return *[1]; end; a = r(); a.should == 1 + def r; return *[nil]; end; a = r(); a.should == nil + def r; return *[[]]; end; a = r(); a.should == [] + def r; return *[*[1]]; end; a = r(); a.should == 1 + def r; return *[*[1,2]]; end; a = r(); a.should == [1,2] + end + + it "assigns objects to block variables that include the splat operator inside the block" do + def r; return; end; a = *r(); a.should == nil + def r; return nil; end; a = *r(); a.should == nil + def r; return 1; end; a = *r(); a.should == 1 + def r; return []; end; a = *r(); a.should == nil + def r; return [1]; end; a = *r(); a.should == 1 + def r; return [nil]; end; a = *r(); a.should == nil + def r; return [[]]; end; a = *r(); a.should == [] + def r; return [1,2]; end; a = *r(); a.should == [1,2] + def r; return [*[]]; end; a = *r(); a.should == nil + def r; return [*[1]]; end; a = *r(); a.should == 1 + def r; return [*[1,2]]; end; a = *r(); a.should == [1,2] + end + + it "assigns objects to splatted block variables that include the splat operator inside the block" do + def r; return *nil; end; *a = r(); a.should == [nil] + def r; return *1; end; *a = r(); a.should == [1] + def r; return *[]; end; *a = r(); a.should == [nil] + def r; return *[1]; end; *a = r(); a.should == [1] + def r; return *[nil]; end; *a = r(); a.should == [nil] + def r; return *[[]]; end; *a = r(); a.should == [[]] + def r; return *[*[]]; end; *a = r(); a.should == [nil] + def r; return *[*[1]]; end; *a = r(); a.should == [1] + def r; return *[*[1,2]]; end; *a = r(); a.should == [[1,2]] + end + + it "assigns objects to splatted block variables that include the splat operator inside the block" do + def r; return *nil; end; *a = *r(); a.should == [nil] + def r; return *1; end; *a = *r(); a.should == [1] + def r; return *[]; end; *a = *r(); a.should == [nil] + def r; return *[1]; end; *a = *r(); a.should == [1] + def r; return *[nil]; end; *a = *r(); a.should == [nil] + def r; return *[[]]; end; *a = *r(); a.should == [] + def r; return *[*[]]; end; *a = *r(); a.should == [nil] + def r; return *[*[1]]; end; *a = *r(); a.should == [1] + def r; return *[*[1,2]]; end; *a = *r(); a.should == [1,2] + end + + it "assigns objects to multiple block variables" do + def r; return; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return nil; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return 1; end; a,b,*c = r(); [a,b,c].should == [1,nil,[]] + def r; return []; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return [1]; end; a,b,*c = r(); [a,b,c].should == [1,nil,[]] + def r; return [nil]; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return [[]]; end; a,b,*c = r(); [a,b,c].should == [[],nil,[]] + def r; return [*[]]; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return [*[1]]; end; a,b,*c = r(); [a,b,c].should == [1,nil,[]] + def r; return [*[1,2]]; end; a,b,*c = r(); [a,b,c].should == [1,2,[]] + end + + it "assigns splatted objects to multiple block variables" do + def r; return *nil; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return *1; end; a,b,*c = r(); [a,b,c].should == [1,nil,[]] + def r; return *[]; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return *[1]; end; a,b,*c = r(); [a,b,c].should == [1,nil,[]] + def r; return *[nil]; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return *[[]]; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return *[*[]]; end; a,b,*c = r(); [a,b,c].should == [nil,nil,[]] + def r; return *[*[1]]; end; a,b,*c = r(); [a,b,c].should == [1,nil,[]] + def r; return *[*[1,2]]; end; a,b,*c = r(); [a,b,c].should == [1,2,[]] + end +end + +describe "Return from within a begin" do + it "executes ensure before returning from function" do + def f(a) + begin + return a + ensure + a << 1 + end + end + f([]).should == [1] + end + + it "executes return in ensure before returning from function" do + def f(a) + begin + return a + ensure + return [0] + a << 1 + end + end + f([]).should == [0] + end + + it "executes ensures in stack order before returning from function" do + def f(a) + begin + begin + return a + ensure + a << 2 + end + ensure + a << 1 + end + end + f([]).should == [2,1] + end + + it "executes return at base of ensure stack" do + def f(a) + begin + begin + return a + ensure + a << 2 + return 2 + end + ensure + a << 1 + return 1 + end + end + a = [] + f(a).should == 1 + a.should == [2, 1] + end +end + +describe "Executing return from within a block" do + it "raises a LocalJumpError" do + def f; yield end + lambda { f { return 5 } }.should raise_error(LocalJumpError) + end + + it "causes the method calling the method that yields to the block to return" do + def f; yield; return 2 end + def b; f { return 5 } end + b.should == 5 + end +end + +describe "The return statement" do + it "raises a ThreadError if used to exit a thread" do + lambda { Thread.new { return }.join }.should raise_error(ThreadError) + end +end + diff --git a/1.8/language/string_spec.rb b/1.8/language/string_spec.rb new file mode 100644 index 0000000000..27fdb1291f --- /dev/null +++ b/1.8/language/string_spec.rb @@ -0,0 +1,146 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +# Thanks http://www.zenspider.com/Languages/Ruby/QuickRef.html + +describe "Ruby character strings" do + + before(:each) do + @ip = 'xxx' # used for interpolation + end + + it "don't get interpolated when put in single quotes" do + '#{@ip}'.should == '#{@ip}' + end + + it 'get interpolated with #{} when put in double quotes' do + "#{@ip}".should == 'xxx' + end + + it "interpolate instance variables just with the # character" do + "#@ip".should == 'xxx' + end + + it "interpolate global variables just with the # character" do + $ip = 'xxx' + "#$ip".should == 'xxx' + end + + it "interpolate class variables just with the # character" do + @@ip = 'xxx' + "#@@ip".should == 'xxx' + end + + it "allow underscore as part of a variable name in a simple interpolation" do + @my_ip = 'xxx' + "#@my_ip".should == 'xxx' + end + + it "have characters [.(=?!# end simple # interpolation" do + "#@ip[".should == 'xxx[' + "#@ip.".should == 'xxx.' + "#@ip(".should == 'xxx(' + "#@ip=".should == 'xxx=' + "#@ip?".should == 'xxx?' + "#@ip!".should == 'xxx!' + "#@ip#@ip".should == 'xxxxxx' + end + + it "allow using non-alnum characters as string delimiters" do + %(hey #{@ip}).should == "hey xxx" + %[hey #{@ip}].should == "hey xxx" + %{hey #{@ip}}.should == "hey xxx" + %.should == "hey xxx" + %!hey #{@ip}!.should == "hey xxx" + %@hey #{@ip}@.should == "hey xxx" + %#hey hey#.should == "hey hey" + %%hey #{@ip}%.should == "hey xxx" + %^hey #{@ip}^.should == "hey xxx" + %&hey #{@ip}&.should == "hey xxx" + %*hey #{@ip}*.should == "hey xxx" + %-hey #{@ip}-.should == "hey xxx" + %_hey #{@ip}_.should == "hey xxx" + %=hey #{@ip}=.should == "hey xxx" + %+hey #{@ip}+.should == "hey xxx" + %~hey #{@ip}~.should == "hey xxx" + %:hey #{@ip}:.should == "hey xxx" + %;hey #{@ip};.should == "hey xxx" + %"hey #{@ip}".should == "hey xxx" + %|hey #{@ip}|.should == "hey xxx" + %?hey #{@ip}?.should == "hey xxx" + %/hey #{@ip}/.should == "hey xxx" + %,hey #{@ip},.should == "hey xxx" + %.hey #{@ip}..should == "hey xxx" + + # surprised? huh + %'hey #{@ip}'.should == "hey xxx" + %\hey #{@ip}\.should == "hey xxx" + %`hey #{@ip}`.should == "hey xxx" + %$hey #{@ip}$.should == "hey xxx" + end + + it "using percent with 'q', stopping interpolation" do + %q(#{@ip}).should == '#{@ip}' + end + + it "using percent with 'Q' to interpolate" do + %Q(#{@ip}).should == 'xxx' + end + + # The backslashes : + # + # \t (tab), \n (newline), \r (carriage return), \f (form feed), \b + # (backspace), \a (bell), \e (escape), \s (whitespace), \nnn (octal), + # \xnn (hexadecimal), \cx (control x), \C-x (control x), \M-x (meta x), + # \M-\C-x (meta control x) + + it "backslashes follow the same rules as interpolation" do + "\t\n\r\f\b\a\e\s\075\x62\cx".should == "\t\n\r\f\b\a\e =b\030" + '\t\n\r\f\b\a\e =b\030'.should == "\\t\\n\\r\\f\\b\\a\\e =b\\030" + end + + it "allow HEREDOC with < 4 + end + i += 1 + end + i.should == 5 + end + + it "supports a second parameter" do + msg = catch(:exit) do + throw :exit,:msg + end + msg.should == :msg + end + + it "uses nil as a default second parameter" do + msg = catch(:exit) do + throw :exit + end + msg.should == nil + end + + it "returns the last value of catch if it nothing is thrown" do + catch(:exit) do + :noexit + end.should == :noexit + end + + it "supports nesting" do + i = [] + catch(:exita) do + i << :a + catch(:exitb) do + i << :b + throw :exita + i << :after_throw + end + i << :b_exit + end + i << :a_exit + + i.should == [:a,:b,:a_exit] + end + + it "supports nesting with the same name" do + i = [] + catch(:exit) do + i << :a + catch(:exit) do + i << :b + throw :exit,:msg + end.should == :msg + i << :b_exit + end.should == [:a,:b,:b_exit] + i << :a_exit + + i.should == [:a,:b,:b_exit,:a_exit] + end + + it "unwinds stack from within a method" do + def throw_method(handler,val) + throw handler,val + end + + catch(:exit) do + throw_method(:exit,5) + end.should == 5 + end + + it "raises a name error if outside of scope of a matching catch" do + lambda { throw :test,5 }.should raise_error(NameError) + lambda { catch(:different) { throw :test,5 } }.should raise_error(NameError) + end + + it "raises a ThreadError if used to exit a thread" do + lambda { + catch(:what) do + Thread.new do + throw :what + end.join + end + }.should raise_error(ThreadError) + end +end + diff --git a/1.8/language/undef_spec.rb b/1.8/language/undef_spec.rb new file mode 100644 index 0000000000..8a8d04a005 --- /dev/null +++ b/1.8/language/undef_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +class UndefSpecClass + def meth(other);other;end +end + +describe "The undef keyword" do + it "undefines 'meth='" do + obj = UndefSpecClass.new + (obj.meth 5).should == 5 + class UndefSpecClass + undef meth + end + lambda { obj.meth 5 }.should raise_error(NoMethodError) + end +end diff --git a/1.8/language/unless_spec.rb b/1.8/language/unless_spec.rb new file mode 100644 index 0000000000..951739eaab --- /dev/null +++ b/1.8/language/unless_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "The unless expression" do + it "evaluates the unless body when the expression is false" do + unless false + a = true + else + a = false + end + + a.should == true + end + + it "returns the last statement in the body" do + unless false + 'foo' + 'bar' + 'baz' + end.should == 'baz' + end + + it "evaluates the else body when the expression is true" do + unless true + 'foo' + else + 'bar' + end.should == 'bar' + end + + it "takes an optional then after the expression" do + unless false then + 'baz' + end.should == 'baz' + end + + it "does not return a value when the expression is true" do + unless true; end.should == nil + end + + it "allows expression and body to be on one line (using ':')" do + unless false: 'foo'; else 'bar'; end.should == 'foo' + end + + it "allows expression and body to be on one line (using 'then')" do + unless false then 'foo'; else 'bar'; end.should == 'foo' + end +end \ No newline at end of file diff --git a/1.8/language/until_spec.rb b/1.8/language/until_spec.rb new file mode 100644 index 0000000000..bf38b8082e --- /dev/null +++ b/1.8/language/until_spec.rb @@ -0,0 +1,225 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +# until bool-expr [do] +# body +# end +# +# begin +# body +# end until bool-expr +# +# expr until bool-expr +describe "The until expression" do + it "runs while the expression is false" do + i = 0 + until i > 9 + i += 1 + end + + i.should == 10 + end + + it "optionally takes a 'do' after the expression" do + i = 0 + until i > 9 do + i += 1 + end + + i.should == 10 + end + + it "allows body begin on the same line if do is used" do + i = 0 + until i > 9 do i += 1 + end + + i.should == 10 + end + + it "executes code in containing variable scope" do + i = 0 + until i == 1 + a = 123 + i = 1 + end + + a.should == 123 + end + + it "executes code in containing variable scope with 'do'" do + i = 0 + until i == 1 do + a = 123 + i = 1 + end + + a.should == 123 + end + + it "returns nil if ended when condition became true" do + i = 0 + while i > 9 + i += 1 + end.should == nil + end + + it "stops running body if interrupted by break" do + i = 0 + until i > 9 + i += 1 + break if i > 5 + end + i.should == 6 + end + + it "returns value passed to break if interrupted by break" do + until false + break 123 + end.should == 123 + end + + it "returns nil if interrupted by break with no arguments" do + until false + break + end.should == nil + end + + it "skips to end of body with next" do + a = [] + i = 0 + until (i+=1)>=5 + next if i==3 + a << i + end + a.should == [1, 2, 4] + end + + it "restarts the current iteration without reevaluating condition with redo" do + a = [] + i = 0 + j = 0 + until (i+=1)>=3 + a << i + j+=1 + redo if j<3 + end + a.should == [1, 1, 1, 2] + end +end + +describe "The until modifier" do + it "runs preceding statement while the condition is false" do + i = 0 + i += 1 until i > 9 + i.should == 10 + end + + it "evaluates condition before statement execution" do + a = [] + i = 0 + a << i until (i+=1) >= 3 + a.should == [1, 2] + end + + it "does not run preceding statement if the condition is true" do + i = 0 + i += 1 until true + i.should == 0 + end + + it "returns nil if ended when condition became true" do + i = 0 + (i += 1 until i>9).should == nil + end + + it "returns value passed to break if interrupted by break" do + (break 123 until false).should == 123 + end + + it "returns nil if interrupted by break with no arguments" do + (break until false).should == nil + end + + it "skips to end of body with next" do + i = 0 + j = 0 + ((i+=1) == 3 ? next : j+=i) until i > 10 + j.should == 63 + end + + it "restarts the current iteration without reevaluating condition with redo" do + i = 0 + j = 0 + (i+=1) == 4 ? redo : j+=i until (i+=1) > 10 + j.should == 34 + end +end + +describe "The until modifier with begin .. end block" do + it "runs block while the expression is false" do + i = 0 + begin + i += 1 + end until i > 9 + + i.should == 10 + end + + it "stops running block if interrupted by break" do + i = 0 + begin + i += 1 + break if i > 5 + end until i > 9 + + i.should == 6 + end + + it "returns value passed to break if interrupted by break" do + (begin; break 123; end until false).should == 123 + end + + it "returns nil if interrupted by break with no arguments" do + (begin; break; end until false).should == nil + end + + it "runs block at least once (even if the expression is true)" do + i = 0 + begin + i += 1 + end until true + + i.should == 1 + end + + it "evaluates condition after block execution" do + a = [] + i = 0 + begin + a << i + end until (i+=1)>=5 + a.should == [0, 1, 2, 3, 4] + end + + it "skips to end of body with next" do + a = [] + i = 0 + begin + next if i==3 + a << i + end until (i+=1)>=5 + a.should == [0, 1, 2, 4] + end + + it "restart the current iteration without reevaluting condition with redo" do + a = [] + i = 0 + j = 0 + begin + a << i + j+=1 + redo if j<3 + end until (i+=1)>=3 + a.should == [0, 0, 0, 1, 2] + end +end diff --git a/1.8/language/variables_spec.rb b/1.8/language/variables_spec.rb new file mode 100644 index 0000000000..74cda8889c --- /dev/null +++ b/1.8/language/variables_spec.rb @@ -0,0 +1,834 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require File.dirname(__FILE__) + '/fixtures/variables' + +describe "Basic assignment" do + it "allows the rhs to be assigned to the lhs" do + a = nil; a.should == nil + a = 1; a.should == 1 + a = []; a.should == [] + a = [1]; a.should == [1] + a = [nil]; a.should == [nil] + a = [[]]; a.should == [[]] + a = [1,2]; a.should == [1,2] + a = [*[]]; a.should == [] + a = [*[1]]; a.should == [1] + a = [*[1,2]]; a.should == [1, 2] + end + + it "allows the assignment of the rhs to the lhs using the rhs splat operator" do + a = *nil; a.should == nil + a = *1; a.should == 1 + a = *[]; a.should == nil + a = *[1]; a.should == 1 + a = *[nil]; a.should == nil + a = *[[]]; a.should == [] + a = *[1,2]; a.should == [1,2] + a = *[*[]]; a.should == nil + a = *[*[1]]; a.should == 1 + a = *[*[1,2]]; a.should == [1,2] + end + + it "allows the assignment of the rhs to the lhs using the lhs splat operator" do + * = 1,2 # Valid syntax, but pretty useless! Nothing to test + *a = nil; a.should == [nil] + *a = 1; a.should == [1] + *a = []; a.should == [[]] + *a = [1]; a.should == [[1]] + *a = [nil]; a.should == [[nil]] + *a = [[]]; a.should == [[[]]] + *a = [1,2]; a.should == [[1,2]] + *a = [*[]]; a.should == [[]] + *a = [*[1]]; a.should == [[1]] + *a = [*[1,2]]; a.should == [[1,2]] + end + + it "allows the assignment of rhs to the lhs using the lhs and rhs splat operators simultaneously" do + *a = *nil; a.should == [nil] + *a = *1; a.should == [1] + *a = *[]; a.should == [] + *a = *[1]; a.should == [1] + *a = *[nil]; a.should == [nil] + *a = *[[]]; a.should == [[]] + *a = *[1,2]; a.should == [1,2] + *a = *[*[]]; a.should == [] + *a = *[*[1]]; a.should == [1] + *a = *[*[1,2]]; a.should == [1,2] + end + + it "allows multiple values to be assigned" do + a,b,*c = nil; [a,b,c].should == [nil, nil, []] + a,b,*c = 1; [a,b,c].should == [1, nil, []] + a,b,*c = []; [a,b,c].should == [nil, nil, []] + a,b,*c = [1]; [a,b,c].should == [1, nil, []] + a,b,*c = [nil]; [a,b,c].should == [nil, nil, []] + a,b,*c = [[]]; [a,b,c].should == [[], nil, []] + a,b,*c = [1,2]; [a,b,c].should == [1,2,[]] + a,b,*c = [*[]]; [a,b,c].should == [nil, nil, []] + a,b,*c = [*[1]]; [a,b,c].should == [1, nil, []] + a,b,*c = [*[1,2]]; [a,b,c].should == [1, 2, []] + + a,b,*c = *nil; [a,b,c].should == [nil, nil, []] + a,b,*c = *1; [a,b,c].should == [1, nil, []] + a,b,*c = *[]; [a,b,c].should == [nil, nil, []] + a,b,*c = *[1]; [a,b,c].should == [1, nil, []] + a,b,*c = *[nil]; [a,b,c].should == [nil, nil, []] + a,b,*c = *[[]]; [a,b,c].should == [[], nil, []] + a,b,*c = *[1,2]; [a,b,c].should == [1,2,[]] + a,b,*c = *[*[]]; [a,b,c].should == [nil, nil, []] + a,b,*c = *[*[1]]; [a,b,c].should == [1, nil, []] + a,b,*c = *[*[1,2]]; [a,b,c].should == [1, 2, []] + end + + it "supports the {|r,| } form of block assignment" do + f = lambda {|r,| r.should == []} + f.call([], *[]) + + f = lambda{|x,| x} + f.call(42).should == 42 + f.call([42]).should == [42] + f.call([[42]]).should == [[42]] + f.call([42,55]).should == [42,55] + end + + it "allows assignment through lambda" do + f = lambda {|r,*l| r.should == []; l.should == [1]} + f.call([], *[1]) + + f = lambda{|x| x} + f.call(42).should == 42 + f.call([42]).should == [42] + f.call([[42]]).should == [[42]] + f.call([42,55]).should == [42,55] + + f = lambda{|*x| x} + f.call(42).should == [42] + f.call([42]).should == [[42]] + f.call([[42]]).should == [[[42]]] + f.call([42,55]).should == [[42,55]] + f.call(42,55).should == [42,55] + end + + it "allows chained assignment" do + (a = 1 + b = 2 + c = 4 + d = 8).should == 15 + d.should == 8 + c.should == 12 + b.should == 14 + a.should == 15 + end +end + +describe "Assignment using expansion" do + it "succeeds without conversion" do + *x = (1..7).to_a + x.should == [[1, 2, 3, 4, 5, 6, 7]] + end +end + +describe "Assigning multiple values" do + it "allows parallel assignment" do + a, b = 1, 2 + a.should == 1 + b.should == 2 + + a, = 1,2 + a.should == 1 + end + + it "allows safe parallel swapping" do + a, b = 1, 2 + a, b = b, a + a.should == 2 + b.should == 1 + end + + compliant_on :ruby, :jruby do + it "evaluates rhs left-to-right" do + a = VariablesSpecs::ParAsgn.new + d,e,f = a.inc, a.inc, a.inc + d.should == 1 + e.should == 2 + f.should == 3 + end + end + + # Rubinius evaluates the rhs args right-to-left, not left-to-right. + # In most cases, this should make no noticeable difference, and it is felt + # that RHS evaluation order ought to be left to the implementation. + deviates_on :rubinius do + it "evaluates rhs right-to-left" do + a = VariablesSpecs::ParAsgn.new + d,e,f = a.inc, a.inc, a.inc + d.should == 3 + e.should == 2 + f.should == 1 + end + end + + it "supports parallel assignment to lhs args via object.method=" do + a = VariablesSpecs::ParAsgn.new + a.x,b = 1,2 + a.x.should == 1 + b.should == 2 + + c = VariablesSpecs::ParAsgn.new + c.x,a.x = a.x,b + c.x.should == 1 + a.x.should == 2 + end + + it "supports parallel assignment to lhs args using []=" do + a = [1,2,3] + a[3],b = 4,5 + a.should == [1,2,3,4] + b.should == 5 + end + + it "bundles remaining values to an array when using the splat operator" do + a, *b = 1, 2, 3 + a.should == 1 + b.should == [2, 3] + + *a = 1, 2, 3 + a.should == [1, 2, 3] + + *a = 4 + a.should == [4] + + *a = nil + a.should == [nil] + + a,=*[1] + a.should == 1 + a,=*[[1]] + a.should == [1] + a,=*[[[1]]] + a.should == [[1]] + end + + it "calls #to_ary on rhs arg if rhs has only a single arg" do + x = VariablesSpecs::ParAsgn.new + a,b,c = x + a.should == 1 + b.should == 2 + c.should == 3 + + a,b,c = x,5 + a.should == x + b.should == 5 + c.should == nil + + a,b,c = 5,x + a.should == 5 + b.should == x + c.should == nil + + a,b,*c = x,5 + a.should == x + b.should == 5 + c.should == [] + + a,(*b),c = 5,x + a.should == 5 + b.should == [x] + c.should == nil + + a,(b,c) = 5,x + a.should == 5 + b.should == 1 + c.should == 2 + + a,(b,*c) = 5,x + a.should == 5 + b.should == 1 + c.should == [2,3,4] + + a,(b,(*c)) = 5,x + a.should == 5 + b.should == 1 + c.should == [2] + + a,(b,(*c),(*d)) = 5,x + a.should == 5 + b.should == 1 + c.should == [2] + d.should == [3] + + a,(b,(*c),(d,*e)) = 5,x + a.should == 5 + b.should == 1 + c.should == [2] + d.should == 3 + e.should == [] + end + + it "allows complex parallel assignment" do + a, (b, c), d = 1, [2, 3], 4 + a.should == 1 + b.should == 2 + c.should == 3 + d.should == 4 + + x, (y, z) = 1, 2, 3 + [x,y,z].should == [1,2,nil] + x, (y, z) = 1, [2,3] + [x,y,z].should == [1,2,3] + x, (y, z) = 1, [2] + [x,y,z].should == [1,2,nil] + + a,(b,c,*d),(e,f),*g = 0,[1,2,3,4],[5,6],7,8 + a.should == 0 + b.should == 1 + c.should == 2 + d.should == [3,4] + e.should == 5 + f.should == 6 + g.should == [7,8] + + x = VariablesSpecs::ParAsgn.new + a,(b,c,*d),(e,f),*g = 0,x,[5,6],7,8 + a.should == 0 + b.should == 1 + c.should == 2 + d.should == [3,4] + e.should == 5 + f.should == 6 + g.should == [7,8] + end + + it "allows a lhs arg to be used in another lhs args parallel assignment" do + c = [4,5,6] + a,b,c[a] = 1,2,3 + a.should == 1 + b.should == 2 + c.should == [4,3,6] + + c[a],b,a = 7,8,9 + a.should == 9 + b.should == 8 + c.should == [4,7,6] + end +end + +describe "Conditional assignment" do + it "assigns the lhs if previously unassigned" do + a=[] + a[0] ||= "bar" + a[0].should == "bar" + + h={} + h["foo"] ||= "bar" + h["foo"].should == "bar" + + h["foo".to_sym] ||= "bar" + h["foo".to_sym].should == "bar" + + aa = 5 + aa ||= 25 + aa.should == 5 + + bb ||= 25 + bb.should == 25 + + cc &&=33 + cc.should == nil + + cc = 5 + cc &&=44 + cc.should == 44 + end + + it "checks for class variable definition before fetching its value" do + class VariableSpecCVarSpec + @@cvarspec ||= 5 + @@cvarspec.should == 5 + end + end +end + +describe "Operator assignment 'var op= expr'" do + it "is equivalent to 'var = var op expr'" do + x = 13 + (x += 5).should == 18 + x.should == 18 + + x = 17 + (x -= 11).should == 6 + x.should == 6 + + x = 2 + (x *= 5).should == 10 + x.should == 10 + + x = 36 + (x /= 9).should == 4 + x.should == 4 + + x = 23 + (x %= 5).should == 3 + x.should == 3 + (x %= 3).should == 0 + x.should == 0 + + x = 2 + (x **= 3).should == 8 + x.should == 8 + + x = 4 + (x |= 3).should == 7 + x.should == 7 + (x |= 4).should == 7 + x.should == 7 + + x = 6 + (x &= 3).should == 2 + x.should == 2 + (x &= 4).should == 0 + x.should == 0 + + # XOR + x = 2 + (x ^= 3).should == 1 + x.should == 1 + (x ^= 4).should == 5 + x.should == 5 + + # Bit-shift left + x = 17 + (x <<= 3).should == 136 + x.should == 136 + + # Bit-shift right + x = 5 + (x >>= 1).should == 2 + x.should == 2 + + x = nil + (x ||= 17).should == 17 + x.should == 17 + (x ||= 2).should == 17 + x.should == 17 + + x = false + (x &&= true).should == false + x.should == false + (x &&= false).should == false + x.should == false + x = true + (x &&= true).should == true + x.should == true + (x &&= false).should == false + x.should == false + end + + it "uses short-circuit arg evaluation for operators ||= and &&=" do + x = 8 + y = VariablesSpecs::OpAsgn.new + (x ||= y.do_side_effect).should == 8 + y.side_effect.should == nil + + x = nil + (x &&= y.do_side_effect).should == nil + y.side_effect.should == nil + + y.a = 5 + (x ||= y.do_side_effect).should == 5 + y.side_effect.should == true + end +end + +describe "Operator assignment 'obj.meth op= expr'" do + it "is equivalent to 'obj.meth = obj.meth op expr'" do + @x = VariablesSpecs::OpAsgn.new + @x.a = 13 + (@x.a += 5).should == 18 + @x.a.should == 18 + + @x.a = 17 + (@x.a -= 11).should == 6 + @x.a.should == 6 + + @x.a = 2 + (@x.a *= 5).should == 10 + @x.a.should == 10 + + @x.a = 36 + (@x.a /= 9).should == 4 + @x.a.should == 4 + + @x.a = 23 + (@x.a %= 5).should == 3 + @x.a.should == 3 + (@x.a %= 3).should == 0 + @x.a.should == 0 + + @x.a = 2 + (@x.a **= 3).should == 8 + @x.a.should == 8 + + @x.a = 4 + (@x.a |= 3).should == 7 + @x.a.should == 7 + (@x.a |= 4).should == 7 + @x.a.should == 7 + + @x.a = 6 + (@x.a &= 3).should == 2 + @x.a.should == 2 + (@x.a &= 4).should == 0 + @x.a.should == 0 + + # XOR + @x.a = 2 + (@x.a ^= 3).should == 1 + @x.a.should == 1 + (@x.a ^= 4).should == 5 + @x.a.should == 5 + + @x.a = 17 + (@x.a <<= 3).should == 136 + @x.a.should == 136 + + @x.a = 5 + (@x.a >>= 1).should == 2 + @x.a.should == 2 + + @x.a = nil + (@x.a ||= 17).should == 17 + @x.a.should == 17 + (@x.a ||= 2).should == 17 + @x.a.should == 17 + + @x.a = false + (@x.a &&= true).should == false + @x.a.should == false + (@x.a &&= false).should == false + @x.a.should == false + @x.a = true + (@x.a &&= true).should == true + @x.a.should == true + (@x.a &&= false).should == false + @x.a.should == false + end + + it "uses short-circuit arg evaluation for operators ||= and &&=" do + x = 8 + y = VariablesSpecs::OpAsgn.new + (x ||= y.do_side_effect).should == 8 + y.side_effect.should == nil + + x = nil + (x &&= y.do_side_effect).should == nil + y.side_effect.should == nil + + y.a = 5 + (x ||= y.do_side_effect).should == 5 + y.side_effect.should == true + end +end + +describe "Operator assignment 'obj[idx] op= expr'" do + it "is equivalent to 'obj[idx] = obj[idx] op expr'" do + x = [2,13,7] + (x[1] += 5).should == 18 + x.should == [2,18,7] + + x = [17,6] + (x[0] -= 11).should == 6 + x.should == [6,6] + + x = [nil,2,28] + (x[2] *= 2).should == 56 + x.should == [nil,2,56] + + x = [3,9,36] + (x[2] /= x[1]).should == 4 + x.should == [3,9,4] + + x = [23,4] + (x[0] %= 5).should == 3 + x.should == [3,4] + (x[0] %= 3).should == 0 + x.should == [0,4] + + x = [1,2,3] + (x[1] **= 3).should == 8 + x.should == [1,8,3] + + x = [4,5,nil] + (x[0] |= 3).should == 7 + x.should == [7,5,nil] + (x[0] |= 4).should == 7 + x.should == [7,5,nil] + + x = [3,6,9] + (x[1] &= 3).should == 2 + x.should == [3,2,9] + (x[1] &= 4).should == 0 + x.should == [3,0,9] + + # XOR + x = [0,1,2] + (x[2] ^= 3).should == 1 + x.should == [0,1,1] + (x[2] ^= 4).should == 5 + x.should == [0,1,5] + + x = [17] + (x[0] <<= 3).should == 136 + x.should == [136] + + x = [nil,5,8] + (x[1] >>= 1).should == 2 + x.should == [nil,2,8] + + x = [1,nil,12] + (x[1] ||= 17).should == 17 + x.should == [1,17,12] + (x[1] ||= 2).should == 17 + x.should == [1,17,12] + + x = [true, false, false] + (x[1] &&= true).should == false + x.should == [true, false, false] + (x[1] &&= false).should == false + x.should == [true, false, false] + (x[0] &&= true).should == true + x.should == [true, false, false] + (x[0] &&= false).should == false + x.should == [false, false, false] + end + + it "uses short-circuit arg evaluation for operators ||= and &&=" do + x = 8 + y = VariablesSpecs::OpAsgn.new + (x ||= y.do_side_effect).should == 8 + y.side_effect.should == nil + + x = nil + (x &&= y.do_side_effect).should == nil + y.side_effect.should == nil + + y.a = 5 + (x ||= y.do_side_effect).should == 5 + y.side_effect.should == true + end + + it "handles complex index (idx) arguments" do + x = [1,2,3,4] + (x[0,2] += [5]).should == [1,2,5] + x.should == [1,2,5,3,4] + (x[0,2] += [3,4]).should == [1,2,3,4] + x.should == [1,2,3,4,5,3,4] + + (x[2..3] += [8]).should == [3,4,8] + x.should == [1,2,3,4,8,5,3,4] + + y = VariablesSpecs::OpAsgn.new + y.a = 1 + (x[y.do_side_effect] *= 2).should == 4 + x.should == [1,4,3,4,8,5,3,4] + + h = {'key1' => 23, 'key2' => 'val'} + (h['key1'] %= 5).should == 3 + (h['key2'] += 'ue').should == 'value' + h.should == {'key1' => 3, 'key2' => 'value'} + end +end + +describe "Single assignment" do + it "Assignment does not modify the lhs, it reassigns its reference" do + a = 'Foobar' + b = a + b = 'Bazquux' + a.should == 'Foobar' + b.should == 'Bazquux' + end + + it "Assignment does not copy the object being assigned, just creates a new reference to it" do + a = [] + b = a + b << 1 + a.should == [1] + end + + it "If rhs has multiple arguments, lhs becomes an Array of them" do + a = 1, 2, 3 + a.should == [1, 2, 3] + end +end + +describe "Multiple assignment without grouping or splatting" do + it "An equal number of arguments on lhs and rhs assigns positionally" do + a, b, c, d = 1, 2, 3, 4 + a.should == 1 + b.should == 2 + c.should == 3 + d.should == 4 + end + + it "If rhs has too few arguments, the missing ones on lhs are assigned nil" do + a, b, c = 1, 2 + a.should == 1 + b.should == 2 + c.should == nil + end + + it "If rhs has too many arguments, the extra ones are silently not assigned anywhere" do + a, b = 1, 2, 3 + a.should == 1 + b.should == 2 + end + + it "The assignments are done in parallel so that lhs and rhs are independent of eachother without copying" do + o_of_a, o_of_b = mock('a'), mock('b') + a, b = o_of_a, o_of_b + a, b = b, a + a.equal?(o_of_b).should == true + b.equal?(o_of_a).should == true + end +end + +describe "Multiple assignments with splats" do + # TODO make this normal once rubinius eval works + compliant_on :ruby do + it "* on the lhs has to be applied to the last parameter" do + lambda { eval 'a, *b, c = 1, 2, 3' }.should raise_error(SyntaxError) + end + end + + it "* on the lhs collects all parameters from its position onwards as an Array or an empty Array" do + a, *b = 1, 2 + c, *d = 1 + e, *f = 1, 2, 3 + g, *h = 1, [2, 3] + *i = 1, [2,3] + *j = [1,2,3] + *k = 1,2,3 + + a.should == 1 + b.should == [2] + c.should == 1 + d.should == [] + e.should == 1 + f.should == [2, 3] + g.should == 1 + h.should == [[2, 3]] + i.should == [1, [2, 3]] + j.should == [[1,2,3]] + k.should == [1,2,3] + end +end + +describe "Multiple assignments with grouping" do + it "A group on the lhs is considered one position and treats its corresponding rhs position like an Array" do + a, (b, c), d = 1, 2, 3, 4 + e, (f, g), h = 1, [2, 3, 4], 5 + i, (j, k), l = 1, 2, 3 + a.should == 1 + b.should == 2 + c.should == nil + d.should == 3 + e.should == 1 + f.should == 2 + g.should == 3 + h.should == 5 + i.should == 1 + j.should == 2 + k.should == nil + l.should == 3 + end + + it "supports multiple levels of nested groupings" do + a,(b,(c,d)) = 1,[2,[3,4]] + a.should == 1 + b.should == 2 + c.should == 3 + d.should == 4 + + a,(b,(c,d)) = [1,[2,[3,4]]] + a.should == 1 + b.should == 2 + c.should == 3 + d.should == 4 + + x = [1,[2,[3,4]]] + a,(b,(c,d)) = x + a.should == 1 + b.should == 2 + c.should == 3 + d.should == 4 + end + + compliant_on :ruby do + it "rhs cannot use parameter grouping, it is a syntax error" do + lambda { eval '(a, b) = (1, 2)' }.should raise_error(SyntaxError) + end + end +end + +compliant_on :ruby do + +describe "Multiple assignment" do + it "has the proper return value" do + (a,b,*c = *[5,6,7,8,9,10]).should == [5,6,7,8,9,10] + (d,e = VariablesSpecs.reverse_foo(4,3)).should == [3,4] + (f,g,h = VariablesSpecs.reverse_foo(6,7)).should == [7,6] + (i,*j = *[5,6,7]).should == [5,6,7] + (k,*l = [5,6,7]).should == [5,6,7] + a.should == 5 + b.should == 6 + c.should == [7,8,9,10] + d.should == 3 + e.should == 4 + f.should == 7 + g.should == 6 + h.should == nil + i.should == 5 + j.should == [6,7] + k.should == 5 + l.should == [6,7] + end +end +end + +# For now, masgn is deliberately non-compliant with MRI wrt the return val from an masgn. +# Rubinius returns true as the result of the assignment, but MRI returns an array +# containing all the elements on the rhs. As this result is never used, the cost +# of creating and then discarding this array is avoided +describe "Multiple assignment, array-style" do + compliant_on :ruby do + it "returns an array of all rhs values" do + (a,b = 5,6,7).should == [5,6,7] + a.should == 5 + b.should == 6 + + (c,d,*e = 99,8).should == [99,8] + c.should == 99 + d.should == 8 + e.should == [] + + (f,g,h = 99,8).should == [99,8] + f.should == 99 + g.should == 8 + h.should == nil + end + end + + deviates_on :rubinius do + it "returns true" do + (a,b = 5,6,7).should == true + a.should == 5 + b.should == 6 + + (c,d,*e = 99,8).should == true + c.should == 99 + d.should == 8 + e.should == [] + + (f,g,h = 99,8).should == true + f.should == 99 + g.should == 8 + h.should == nil + end + end +end diff --git a/1.8/language/while_spec.rb b/1.8/language/while_spec.rb new file mode 100644 index 0000000000..77905b660d --- /dev/null +++ b/1.8/language/while_spec.rb @@ -0,0 +1,224 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +# while bool-expr [do] +# body +# end +# +# begin +# body +# end while bool-expr +# +# expr while bool-expr +describe "The while expression" do + it "runs while the expression is true" do + i = 0 + while i < 3 + i += 1 + end + i.should == 3 + end + + it "optionally takes a 'do' after the expression" do + i = 0 + while i < 3 do + i += 1 + end + + i.should == 3 + end + + it "allows body begin on the same line if do is used" do + i = 0 + while i < 3 do i += 1 + end + + i.should == 3 + end + + it "executes code in containing variable scope" do + i = 0 + while i != 1 + a = 123 + i = 1 + end + + a.should == 123 + end + + it "executes code in containing variable scope with 'do'" do + i = 0 + while i != 1 do + a = 123 + i = 1 + end + + a.should == 123 + end + + it "returns nil if ended when condition became false" do + i = 0 + while i < 3 + i += 1 + end.should == nil + end + + it "stops running body if interrupted by break" do + i = 0 + while i < 10 + i += 1 + break if i > 5 + end + i.should == 6 + end + + it "returns value passed to break if interrupted by break" do + while true + break 123 + end.should == 123 + end + + it "returns nil if interrupted by break with no arguments" do + while true + break + end.should == nil + end + + it "skips to end of body with next" do + a = [] + i = 0 + while (i+=1)<5 + next if i==3 + a << i + end + a.should == [1, 2, 4] + end + + it "restarts the current iteration without reevaluating condition with redo" do + a = [] + i = 0 + j = 0 + while (i+=1)<3 + a << i + j+=1 + redo if j<3 + end + a.should == [1, 1, 1, 2] + end +end + +describe "The while modifier" do + it "runs preceding statement while the condition is true" do + i = 0 + i += 1 while i < 3 + i.should == 3 + end + + it "evaluates condition before statement execution" do + a = [] + i = 0 + a << i while (i+=1) < 3 + a.should == [1, 2] + end + + it "does not run preceding statement if the condition is false" do + i = 0 + i += 1 while false + i.should == 0 + end + + it "returns nil if ended when condition became false" do + i = 0 + (i += 1 while i<10).should == nil + end + + it "returns value passed to break if interrupted by break" do + (break 123 while true).should == 123 + end + + it "returns nil if interrupted by break with no arguments" do + (break while true).should == nil + end + + it "skips to end of body with next" do + i = 0 + j = 0 + ((i+=1) == 3 ? next : j+=i) while i <= 10 + j.should == 63 + end + + it "restarts the current iteration without reevaluating condition with redo" do + i = 0 + j = 0 + (i+=1) == 4 ? redo : j+=i while (i+=1) <= 10 + j.should == 34 + end +end + +describe "The while modifier with begin .. end block" do + it "runs block while the expression is true" do + i = 0 + begin + i += 1 + end while i < 3 + + i.should == 3 + end + + it "stops running block if interrupted by break" do + i = 0 + begin + i += 1 + break if i > 5 + end while i < 10 + + i.should == 6 + end + + it "returns value passed to break if interrupted by break" do + (begin; break 123; end while true).should == 123 + end + + it "returns nil if interrupted by break with no arguments" do + (begin; break; end while true).should == nil + end + + it "runs block at least once (even if the expression is false)" do + i = 0 + begin + i += 1 + end while false + + i.should == 1 + end + + it "evaluates condition after block execution" do + a = [] + i = 0 + begin + a << i + end while (i+=1)<5 + a.should == [0, 1, 2, 3, 4] + end + + it "skips to end of body with next" do + a = [] + i = 0 + begin + next if i==3 + a << i + end while (i+=1)<5 + a.should == [0, 1, 2, 4] + end + + it "restarts the current iteration without reevaluting condition with redo" do + a = [] + i = 0 + j = 0 + begin + a << i + j+=1 + redo if j<3 + end while (i+=1)<3 + a.should == [0, 0, 0, 1, 2] + end +end diff --git a/1.8/language/yield_spec.rb b/1.8/language/yield_spec.rb new file mode 100644 index 0000000000..096060244d --- /dev/null +++ b/1.8/language/yield_spec.rb @@ -0,0 +1,93 @@ +require File.dirname(__FILE__) + '/../spec_helper' +require File.dirname(__FILE__) + '/fixtures/yield' + +describe "Assignment via yield" do + + it "assigns objects to block variables" do + def f; yield nil; end; f {|a| a.should == nil } + def f; yield 1; end; f {|a| a.should == 1 } + def f; yield []; end; f {|a| a.should == [] } + def f; yield [1]; end; f {|a| a.should == [1] } + def f; yield [nil]; end; f {|a| a.should == [nil] } + def f; yield [[]]; end; f {|a| a.should == [[]] } + def f; yield [*[]]; end; f {|a| a.should == [] } + def f; yield [*[1]]; end; f {|a| a.should == [1] } + def f; yield [*[1,2]]; end; f {|a| a.should == [1,2] } + end + + it "assigns splatted objects to block variables" do + def f; yield *nil; end; f {|a| a.should == nil } + def f; yield *1; end; f {|a| a.should == 1 } + def f; yield *[1]; end; f {|a| a.should == 1 } + def f; yield *[nil]; end; f {|a| a.should == nil } + def f; yield *[[]]; end; f {|a| a.should == [] } + def f; yield *[*[1]]; end; f {|a| a.should == 1 } + end + + it "assigns objects followed by splatted objects to block variables" do + def f; yield 1, *nil; end; f {|a, b| b.should == nil } + def f; yield 1, *1; end; f {|a, b| b.should == 1 } + def f; yield 1, *[1]; end; f {|a, b| b.should == 1 } + def f; yield 1, *[nil]; end; f {|a, b| b.should == nil } + def f; yield 1, *[[]]; end; f {|a, b| b.should == [] } + def f; yield 1, *[*[1]]; end; f {|a, b| b.should == 1 } + end + + it "assigns objects to block variables that include the splat operator inside the block" do + def f; yield; end; f {|*a| a.should == [] } + def f; yield nil; end; f {|*a| a.should == [nil] } + def f; yield 1; end; f {|*a| a.should == [1] } + def f; yield []; end; f {|*a| a.should == [[]] } + def f; yield [1]; end; f {|*a| a.should == [[1]] } + def f; yield [nil]; end; f {|*a| a.should == [[nil]] } + def f; yield [[]]; end; f {|*a| a.should == [[[]]] } + def f; yield [1,2]; end; f {|*a| a.should == [[1,2]] } + def f; yield [*[]]; end; f {|*a| a.should == [[]] } + def f; yield [*[1]]; end; f {|*a| a.should == [[1]] } + def f; yield [*[1,2]]; end; f {|*a| a.should == [[1,2]] } + end + + it "assigns objects to splatted block variables that include the splat operator inside the block" do + def f; yield *nil; end; f {|*a| a.should == [nil] } + def f; yield *1; end; f {|*a| a.should == [1] } + def f; yield *[]; end; f {|*a| a.should == [] } + def f; yield *[1]; end; f {|*a| a.should == [1] } + def f; yield *[nil]; end; f {|*a| a.should == [nil] } + def f; yield *[[]]; end; f {|*a| a.should == [[]] } + def f; yield *[*[]]; end; f {|*a| a.should == [] } + def f; yield *[*[1]]; end; f {|*a| a.should == [1] } + def f; yield *[*[1,2]]; end; f {|*a| a.should == [1,2] } + end + + it "assigns objects to multiple block variables" do + def f; yield; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield nil; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield 1; end; f {|a,b,*c| [a,b,c].should == [1,nil,[]] } + def f; yield []; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield [1]; end; f {|a,b,*c| [a,b,c].should == [1,nil,[]] } + def f; yield [nil]; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield [[]]; end; f {|a,b,*c| [a,b,c].should == [[],nil,[]] } + def f; yield [*[]]; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield [*[1]]; end; f {|a,b,*c| [a,b,c].should == [1,nil,[]] } + def f; yield [*[1,2]]; end; f {|a,b,*c| [a,b,c].should == [1,2,[]] } + end + + it "assigns splatted objects to multiple block variables" do + def f; yield *nil; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield *1; end; f {|a,b,*c| [a,b,c].should == [1,nil,[]] } + def f; yield *[]; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield *[1]; end; f {|a,b,*c| [a,b,c].should == [1,nil,[]] } + def f; yield *[nil]; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield *[[]]; end; f {|a,b,*c| [a,b,c].should == [[],nil,[]] } + def f; yield *[*[]]; end; f {|a,b,*c| [a,b,c].should == [nil,nil,[]] } + def f; yield *[*[1]]; end; f {|a,b,*c| [a,b,c].should == [1,nil,[]] } + def f; yield *[*[1,2]]; end; f {|a,b,*c| [a,b,c].should == [1,2,[]] } + end + +end + +describe "The yield keyword" do + it "raises a LocalJumpError when invoked in a method not passed a block" do + lambda { YieldSpecs::no_block }.should raise_error(LocalJumpError) + end +end diff --git a/1.8/library/base64/b64encode_spec.rb b/1.8/library/base64/b64encode_spec.rb new file mode 100644 index 0000000000..48f91b0fa6 --- /dev/null +++ b/1.8/library/base64/b64encode_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'base64' + +describe "Base64#b64encode" do + it "returns and prints the Base64-encoded version of the given string with a newline after 60 characters" do + b64encoded_version = "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMgdG8gbGVhcm4g\nUnVieQ==\n" + lambda { + Base64.b64encode("Now is the time for all good coders to learn Ruby").should == b64encoded_version + }.should output(b64encoded_version) + end +end + +describe "Base64#b64encode" do + it "prints the Base64-encoded version of the given string in lines of 2 if the lenght of 2 is given" do + lambda { + Base64.b64encode("hello", 2).should == "aGVsbG8=\n" + }.should output("aG\nVs\nbG\n8=\n") + end +end diff --git a/1.8/library/base64/decode64_spec.rb b/1.8/library/base64/decode64_spec.rb new file mode 100644 index 0000000000..a54876d917 --- /dev/null +++ b/1.8/library/base64/decode64_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'base64' + +describe "Base64#decode64" do + it "returns the Base64-decoded version of the given string" do + Base64.decode64("U2VuZCByZWluZm9yY2VtZW50cw==\n").should == "Send reinforcements" + end +end diff --git a/1.8/library/base64/decode_b_spec.rb b/1.8/library/base64/decode_b_spec.rb new file mode 100644 index 0000000000..08efcad087 --- /dev/null +++ b/1.8/library/base64/decode_b_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'base64' + +describe "Base64#decode_d" do + it "supports an encoding type of base64 and the charachter set SHIFT_JIS" do + Base64.decode_b("=?SHIFT_JIS?B?Zm9v?=").should == 'foo' + end + + it "supports an encoding type of base64 and the character set ISO-2022-JP" do + Base64.decode_b("=?ISO-2022-JP?B?Zm9v?=").should == 'foo' + end + + # mSpec doesn't have pending specs yet + # Waiting on Kconv implementation + # it "decodes MIME encoded string and convert halfwidth katakana to fullwidth katakana." +end \ No newline at end of file diff --git a/1.8/library/base64/encode64_spec.rb b/1.8/library/base64/encode64_spec.rb new file mode 100644 index 0000000000..a22bc73d99 --- /dev/null +++ b/1.8/library/base64/encode64_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'base64' + +describe "Base64#encode64" do + it "returns the Base64-encoded version of the given string" do + Base64.encode64("Now is the time for all good coders\nto learn Ruby").should == + "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g\nUnVieQ==\n" + end + + it "returns the Base64-encoded version of the given string" do + Base64.encode64('Send reinforcements').should == "U2VuZCByZWluZm9yY2VtZW50cw==\n" + end +end diff --git a/1.8/library/bigdecimal/abs_spec.rb b/1.8/library/bigdecimal/abs_spec.rb new file mode 100644 index 0000000000..10287e2763 --- /dev/null +++ b/1.8/library/bigdecimal/abs_spec.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#abs" do + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @two = BigDecimal("2") + @three = BigDecimal("3") + @mixed = BigDecimal("1.23456789") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns the absolute value" do + pos_int = BigDecimal("2E5555") + neg_int = BigDecimal("-2E5555") + pos_frac = BigDecimal("2E-9999") + neg_frac = BigDecimal("-2E-9999") + + pos_int.abs.should == pos_int + neg_int.abs.should == pos_int + pos_frac.abs.should == pos_frac + neg_frac.abs.should == pos_frac + @one.abs.should == 1 + @two.abs.should == 2 + @three.abs.should == 3 + @mixed.abs.should == @mixed + @one_minus.abs.should == @one + end + + it "properly handles special values" do + @infinity.abs.should == @infinity + @infinity_minus.abs.should == @infinity + @nan.abs.nan?.should == true # have to do it this way, since == doesn't work on NaN + @zero.abs.should == 0 + @zero.abs.sign.should == BigDecimal::SIGN_POSITIVE_ZERO + @zero_pos.abs.should == 0 + @zero_pos.abs.sign.should == BigDecimal::SIGN_POSITIVE_ZERO + @zero_neg.abs.should == 0 + @zero_neg.abs.sign.should == BigDecimal::SIGN_POSITIVE_ZERO + end + +end diff --git a/1.8/library/bigdecimal/add_spec.rb b/1.8/library/bigdecimal/add_spec.rb new file mode 100644 index 0000000000..2671811c88 --- /dev/null +++ b/1.8/library/bigdecimal/add_spec.rb @@ -0,0 +1,67 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#add" do + + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @two = BigDecimal("2") + @three = BigDecimal("3") + @ten = BigDecimal("10") + @eleven = BigDecimal("11") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns a + b with given precision" do + # documentation states, that precision ist optional, but it ain't, + @two.add(@one, 1).should == @three + @one .add(@two, 1).should == @three + @one.add(@one_minus, 1).should == @zero + @ten.add(@one, 2).should == @eleven + @zero.add(@one, 1).should == @one + @frac_2.add(@frac_1, 10000).should == BigDecimal("1.9E-99999") + @frac_1.add(@frac_1, 10000).should == BigDecimal("2E-99999") + end + + it "returns NaN if NaN is involved" do + @one.add(@nan, 10000).nan?.should == true + @nan.add(@one, 1).nan?.should == true + end + + it "returns Infinity or -Infinity if these are involved" do + @zero.add(@infinity, 1).should == @infinity + @frac_2.add(@infinity, 1).should == @infinity + @one_minus.add(@infinity, 1).should == @infinity + @two.add(@infinity, 1).should == @infinity + + @zero.add(@infinity_minus, 1).should == @infinity_minus + @frac_2.add(@infinity_minus, 1).should == @infinity_minus + @one_minus.add(@infinity_minus, 1).should == @infinity_minus + @two.add(@infinity_minus, 1).should == @infinity_minus + + @infinity.add(@zero, 1).should == @infinity + @infinity.add(@frac_2, 1).should == @infinity + @infinity.add(@one_minus, 1).should == @infinity + @infinity.add(@two, 1).should == @infinity + + @infinity_minus.add(@zero, 1).should == @infinity_minus + @infinity_minus.add(@frac_2, 1).should == @infinity_minus + @infinity_minus.add(@one_minus, 1).should == @infinity_minus + @infinity_minus.add(@two, 1).should == @infinity_minus + + @infinity.add(@infinity, 10000).should == @infinity + @infinity_minus.add(@infinity_minus, 10000).should == @infinity_minus + end + + it "returns NaN if Infinity + (- Infinity)" do + @infinity.add(@infinity_minus, 10000).nan?.should == true + @infinity_minus.add(@infinity, 10000).nan?.should == true + end + +end diff --git a/1.8/library/bigdecimal/case_compare_spec.rb b/1.8/library/bigdecimal/case_compare_spec.rb new file mode 100644 index 0000000000..06f8ed801a --- /dev/null +++ b/1.8/library/bigdecimal/case_compare_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/eql.rb' + + +describe "BigDecimal#===" do + it_behaves_like(:bigdecimal_eql, :===) +end diff --git a/1.8/library/bigdecimal/ceil_spec.rb b/1.8/library/bigdecimal/ceil_spec.rb new file mode 100644 index 0000000000..73511409fe --- /dev/null +++ b/1.8/library/bigdecimal/ceil_spec.rb @@ -0,0 +1,98 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#ceil" do + before(:each) do + @zero = BigDecimal("0") + @one = BigDecimal("1") + @three = BigDecimal("3") + @four = BigDecimal("4") + @mixed = BigDecimal("1.23456789") + @mixed_big = BigDecimal("1.23456789E100") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + end + + it "returns a BigDecimal" do + @mixed.ceil.kind_of?(BigDecimal).should == true + @pos_int.ceil(2).kind_of?(BigDecimal).should == true + end + + it "returns the smallest integer greater or equal to self, if n is unspecified" do + @pos_int.ceil.should == @pos_int + @neg_int.ceil.should == @neg_int + @pos_frac.ceil.should == BigDecimal("1") + @neg_frac.ceil.should == @zero + @infinity.ceil.should == @infinity + @infinity_neg.ceil.should == @infinity_neg + @nan.ceil.nan?.should == true + @zero.ceil.should == 0 + @zero_pos.ceil.should == @zero_pos + @zero_neg.ceil.should == @zero_neg + + + BigDecimal('2.3').ceil.should == 3 + BigDecimal('2.5').ceil.should == 3 + BigDecimal('2.9999').ceil.should == 3 + BigDecimal('-2.3').ceil.should == -2 + BigDecimal('-2.5').ceil.should == -2 + BigDecimal('-2.9999').ceil.should == -2 + end + + it "returns n digits right of the decimal point if given n > 0" do + @mixed.ceil(1).should == BigDecimal("1.3") + @mixed.ceil(5).should == BigDecimal("1.23457") + + BigDecimal("-0.03").ceil(1).should == BigDecimal("0") + BigDecimal("0.03").ceil(1).should == BigDecimal("0.1") + + BigDecimal("23.45").ceil(0).should == BigDecimal('24') + BigDecimal("23.45").ceil(1).should == BigDecimal('23.5') + BigDecimal("23.45").ceil(2).should == BigDecimal('23.45') + + BigDecimal("-23.45").ceil(0).should == BigDecimal('-23') + BigDecimal("-23.45").ceil(1).should == BigDecimal('-23.4') + BigDecimal("-23.45").ceil(2).should == BigDecimal('-23.45') + + BigDecimal("2E-10").ceil(0).should == @one + BigDecimal("2E-10").ceil(9).should == BigDecimal('1E-9') + BigDecimal("2E-10").ceil(10).should == BigDecimal('2E-10') + BigDecimal("2E-10").ceil(11).should == BigDecimal('2E-10') + + (1..10).each do |n| + # 0.4, 0.34, 0.334, etc. + (@one/@three).ceil(n).should == BigDecimal("0.#{'3'*(n-1)}4") + # 1.4, 1.34, 1.334, etc. + (@four/@three).ceil(n).should == BigDecimal("1.#{'3'*(n-1)}4") + (BigDecimal('31')/@three).ceil(n).should == BigDecimal("10.#{'3'*(n-1)}4") + end + (1..10).each do |n| + # -0.4, -0.34, -0.334, etc. + (-@one/@three).ceil(n).should == BigDecimal("-0.#{'3'* n}") + end + (1..10).each do |n| + (@three/@one).ceil(n).should == @three + end + (1..10).each do |n| + (-@three/@one).ceil(n).should == -@three + end + end + + it "sets n digits left of the decimal point to 0, if given n < 0" do + BigDecimal("13345.234").ceil(-2).should == BigDecimal("13400.0") + @mixed_big.ceil(-99).should == BigDecimal("0.13E101") + @mixed_big.ceil(-100).should == BigDecimal("0.2E101") + @mixed_big.ceil(-95).should == BigDecimal("0.123457E101") + BigDecimal("1E10").ceil(-30).should == BigDecimal('1E30') + BigDecimal("-1E10").ceil(-30).should == @zero + end + +end diff --git a/1.8/library/bigdecimal/coerce_spec.rb b/1.8/library/bigdecimal/coerce_spec.rb new file mode 100644 index 0000000000..6b8deee086 --- /dev/null +++ b/1.8/library/bigdecimal/coerce_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#coerce" do + + it "returns [other, self] both as BigDecimal" do + one = BigDecimal("1.0") + five_point_28 = BigDecimal("5.28") + zero_minus = BigDecimal("-0.0") + some_value = 32434234234234234234 + + BigDecimal("1.2").coerce(1).should == [one, BigDecimal("1.2")] + five_point_28.coerce(1.0).should == [one, BigDecimal("5.28")] + one.coerce(one).should == [one, one] + one.coerce(2.5).should == [2.5, one] + BigDecimal("1").coerce(3.14).should == [3.14, one] + a, b = zero_minus.coerce(some_value) + a.should == BigDecimal(some_value.to_s) + b.should == zero_minus + a, b = one.coerce(some_value) + a.should == BigDecimal(some_value.to_s) + b.to_f.should be_close(1.0, TOLERANCE) # can we take out the to_f once BigDecimal#- is implemented? + b.should == one + end + +end diff --git a/1.8/library/bigdecimal/comparison_spec.rb b/1.8/library/bigdecimal/comparison_spec.rb new file mode 100644 index 0000000000..718fa7a338 --- /dev/null +++ b/1.8/library/bigdecimal/comparison_spec.rb @@ -0,0 +1,81 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#<=>" do + before(:each) do + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @mixed = BigDecimal("1.23456789") + @mixed_big = BigDecimal("1.23456789E100") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @int_mock = mock('123') + class << @int_mock + def coerce(other) + return [other, BigDecimal('123')] + end + def >= (other) + BigDecimal('123') >= other + end + end + + @values = [@mixed, @pos_int, @neg_int, @pos_frac, @neg_frac, + -2**32, -2**31, -2**30, -2**16, -2**8, -100, -10, -1, + @zero , 1, 2, 10, 2**8, 2**16, 2**32, @int_mock, @zero_pos, @zero_neg] + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + end + + + it "returns 0 if a == b" do + (@pos_int <=> @pos_int).should == 0 + (@neg_int <=> @neg_int).should == 0 + (@pos_frac <=> @pos_frac).should == 0 + (@neg_frac <=> @neg_frac).should == 0 + (@zero <=> @zero).should == 0 + (@infinity <=> @infinity).should == 0 + (@infinity_neg <=> @infinity_neg).should == 0 + end + + it "returns 1 if a > b" do + (@pos_int <=> @neg_int).should == 1 + (@pos_frac <=> @neg_frac).should == 1 + (@pos_frac <=> @zero).should == 1 + @values.each { |val| + (@infinity <=> val).should == 1 + } + end + + it "returns -1 if a < b" do + (@zero <=> @pos_frac).should == -1 + (@neg_int <=> @pos_frac).should == -1 + (@pos_frac <=> @pos_int).should == -1 + @values.each { |val| + (@infinity_neg <=> val).should == -1 + } + end + + it "returns nil if NaN is involved" do + @values += [@infinity, @infinity_neg, @nan] + @values << nil + @values << Object.new + @values.each { |val| + (@nan <=> val).should == nil + } + end + + it "returns nil if the argument is nil" do + (@zero <=> nil).should == nil + (@infinity <=> nil).should == nil + (@infinity_neg <=> nil).should == nil + (@mixed <=> nil).should == nil + (@pos_int <=> nil).should == nil + (@neg_frac <=> nil).should == nil + end +end diff --git a/1.8/library/bigdecimal/div_spec.rb b/1.8/library/bigdecimal/div_spec.rb new file mode 100644 index 0000000000..19613137e6 --- /dev/null +++ b/1.8/library/bigdecimal/div_spec.rb @@ -0,0 +1,87 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/quo' +require 'bigdecimal' + +describe "BigDecimal#div with precision set to 0" do + # BigDecimal#div with precision set to 0 behaves exactly like / or quo + begin + class BigDecimal + def div_with_zero_precision(arg) + div(arg, 0) + end + end + it_behaves_like(:bigdecimal_quo, :div_with_zero_precision) + ensure + class BigDecimal + undef div_with_zero_precision + end + end +end + +describe "BigDecimal#div" do + + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @two = BigDecimal("2") + @three = BigDecimal("3") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns a / b with optional precision" do + @two.div(@one).should == @two + @one.div(@two).should == @zero + # ^^ is this really intended for a class with arbitrary precision? + @one.div(@two, 1).should == BigDecimal("0.5") + @one.div(@one_minus).should == @one_minus + @one_minus.div(@one_minus).should == @one + @frac_2.div(@frac_1, 1).should == BigDecimal("0.9") + @frac_1.div(@frac_1).should == @one + + res = "0." + "3" * 1000 + (1..100).each { |idx| + @one.div(@three, idx).to_s("F").should == "0." + res[2, idx] + } + end + + it "returns NaN if NaN is involved" do + @one.div(@nan).nan?.should == true + @nan.div(@one).nan?.should == true + end + + it "returns NaN if divided by Infinity and no precision given" do + @zero.div(@infinity).nan?.should == true + @frac_2.div(@infinity).nan?.should == true + end + + it "returns 0 if divided by Infinity with given precision" do + @zero.div(@infinity, 0).should == 0 + @frac_2.div(@infinity, 1).should == 0 + @zero.div(@infinity, 100000).should == 0 + @frac_2.div(@infinity, 100000).should == 0 + end + + it "returns NaN if (+|-) Infinity divided by 1 and no precision given" do + @infinity_minus.div(@one).nan?.should == true + @infinity.div(@one).nan?.should == true + @infinity_minus.div(@one_minus).nan?.should == true + end + + it "returns (+|-)Infinity if (+|-)Infinity by 1 and precision given" do + @infinity_minus.div(@one, 0).should == @infinity_minus + @infinity.div(@one, 0).should == @infinity + @infinity_minus.div(@one_minus, 0).should == @infinity + end + + it "returns NaN if Infinity / ((+|-) Infinity)" do + @infinity.div(@infinity_minus, 100000).nan?.should == true + @infinity_minus.div(@infinity, 1).nan?.should == true + end + + +end diff --git a/1.8/library/bigdecimal/divide_spec.rb b/1.8/library/bigdecimal/divide_spec.rb new file mode 100644 index 0000000000..b652b673bd --- /dev/null +++ b/1.8/library/bigdecimal/divide_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/quo' +require 'bigdecimal' + +describe "BigDecimal#/" do + it_behaves_like(:bigdecimal_quo, :/) +end diff --git a/1.8/library/bigdecimal/divmod_spec.rb b/1.8/library/bigdecimal/divmod_spec.rb new file mode 100644 index 0000000000..4b4d5cd90b --- /dev/null +++ b/1.8/library/bigdecimal/divmod_spec.rb @@ -0,0 +1,157 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/modulo' +require 'bigdecimal' + +module DivmodSpecs + def self.check_both_nan(array) + array.length.should == 2 + array[0].nan?.should == true + array[1].nan?.should == true + end + def self.check_both_bigdecimal(array) + array.length.should == 2 + array[0].kind_of?(BigDecimal).should == true + array[1].kind_of?(BigDecimal).should == true + end +end + +describe "BigDecimal#mod_part_of_divmod" do + # BigDecimal#divmod[1] behaves exactly like #modulo + begin + class BigDecimal + def mod_part_of_dimvod(arg) + divmod(arg)[1] + end + end + it_behaves_like(:bigdecimal_modulo, :mod_part_of_dimvod, :exclude_float_zero) + ensure + class BigDecimal + undef mod_part_of_dimvod + end + end +end + +describe "BigDecimal#divmod" do + + before(:each) do + @a = BigDecimal("42.00000000000000000001") + + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + + @one = BigDecimal("1") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + + @special_vals = [@infinity, @infinity_minus, @nan] + @regular_vals = [ + @one, @mixed, @pos_int, @neg_int, @pos_frac, + @neg_frac, @one_minus, @frac_1, @frac_2] + @zeroes = [@zero, @zero_pos, @zero_neg] + end + + it "divides value, returns an array" do + res = @a.divmod(5) + res.kind_of?(Array).should == true + end + + it "array contains quotient and modulus as BigDecimal" do + res = @a.divmod(5) + DivmodSpecs::check_both_bigdecimal(res) + res[0].should == BigDecimal('0.8E1') + res[1].should == BigDecimal('2.00000000000000000001') + + BigDecimal('1').divmod(BigDecimal('2')).should == [0, 1] + BigDecimal('2').divmod(BigDecimal('1')).should == [2, 0] + + BigDecimal('1').divmod(BigDecimal('-2')).should == [-1, -1] + BigDecimal('2').divmod(BigDecimal('-1')).should == [-2, 0] + + BigDecimal('-1').divmod(BigDecimal('2')).should == [-1, 1] + BigDecimal('-2').divmod(BigDecimal('1')).should == [-2, 0] + end + + it "Can be reversed with * and +" do + # Example taken from BigDecimal documentation + a = BigDecimal.new("42") + b = BigDecimal.new("9") + q, m = a.divmod(b) + c = q * b + m + a.should == c + + values = [@one, @one_minus, BigDecimal('2'), BigDecimal('-2'), + BigDecimal('5'), BigDecimal('-5'), BigDecimal('10'), BigDecimal('-10'), + BigDecimal('20'), BigDecimal('-20'), BigDecimal('100'), BigDecimal('-100'), + BigDecimal('1.23456789E10'), BigDecimal('-1.23456789E10') + ] + + # TODO: file MRI bug: + # BigDecimal('1').divmod(BigDecimal('3E-9'))[0] #=> 0.3E9, + # but really should be 0.333333333E9 + ruby_bug { #MRI's precision is very low in some cases + values << BigDecimal('1E-10') + values << BigDecimal('-1E-10') + values << BigDecimal('2E55') + values << BigDecimal('-2E55') + values << BigDecimal('2E-5555') + values << BigDecimal('-2E-5555') + } + + values_and_zeroes = values + @zeroes + values_and_zeroes.each do |val1| + values.each do |val2| + res = val1.divmod(val2) + DivmodSpecs::check_both_bigdecimal(res) + res[0].should == ((val1/val2).floor) + res[1].should == (val1 - res[0] * val2) + end + end + end + + it "properly handles special values" do + values = @special_vals + @zeroes + values.each do |val1| + values.each do |val2| + DivmodSpecs::check_both_nan(val1.divmod(val2)) + end + end + + @special_vals.each do |val1| + @regular_vals.each do |val2| + DivmodSpecs::check_both_nan(val1.divmod(val2)) + end + end + + @regular_vals.each do |val1| + @special_vals.each do |val2| + DivmodSpecs::check_both_nan(val1.divmod(val2)) + end + end + end + + it "returns an array of two NaNs if the argument is zero" do + values = @regular_vals + @special_vals + values.each do |val1| + @zeroes.each do |val2| + DivmodSpecs::check_both_nan(val1.divmod(val2)) + end + end + end + + it "raises TypeError if the argument cannot be coerced to BigDecimal" do + lambda { + @one.divmod('1') + }.should raise_error(TypeError) + end + +end diff --git a/1.8/library/bigdecimal/eql_spec.rb b/1.8/library/bigdecimal/eql_spec.rb new file mode 100644 index 0000000000..93b5fe5ce0 --- /dev/null +++ b/1.8/library/bigdecimal/eql_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/eql.rb' + +describe "BigDecimal#eql?" do + it_behaves_like(:bigdecimal_eql, :eql?) +end diff --git a/1.8/library/bigdecimal/equal_value_spec.rb b/1.8/library/bigdecimal/equal_value_spec.rb new file mode 100644 index 0000000000..68df908581 --- /dev/null +++ b/1.8/library/bigdecimal/equal_value_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/eql.rb' + + +describe "BigDecimal#==" do + it_behaves_like(:bigdecimal_eql, :==) +end diff --git a/1.8/library/bigdecimal/exponent_spec.rb b/1.8/library/bigdecimal/exponent_spec.rb new file mode 100644 index 0000000000..a25ff0ba9c --- /dev/null +++ b/1.8/library/bigdecimal/exponent_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/power' +require 'bigdecimal' + +describe "BigDecimal#**" do + it_behaves_like(:bigdecimal_power, :**) +end + +describe "BigDecimal#exponent" do + + it "returns an Integer" do + BigDecimal("2E100000000").exponent.kind_of?(Integer).should == true + BigDecimal("2E-999").exponent.kind_of?(Integer).should == true + end + + it "is n if number can be represented as 0.xxx*10**n" do + BigDecimal("2E1000").exponent.should == 1001 + BigDecimal("1234567E10").exponent.should == 17 + end + +# commenting this spec out after discussion with Defiler, since it seems to be an MRI bug, not a real feature +=begin + platform_is :wordsize => 32 do + # TODO: write specs for both 32 and 64 bit + it "returns 0 if exponent can't be represented as Fixnum" do + BigDecimal("2E1000000000000000").exponent.should == 0 + BigDecimal("-5E-999999999999999").exponent.should == 0 + end + end +=end + + it "returns 0 if self is 0" do + BigDecimal("0").exponent.should == 0 + BigDecimal("+0").exponent.should == 0 + BigDecimal("-0").exponent.should == 0 + end + +end diff --git a/1.8/library/bigdecimal/finite_spec.rb b/1.8/library/bigdecimal/finite_spec.rb new file mode 100644 index 0000000000..d013b71fb1 --- /dev/null +++ b/1.8/library/bigdecimal/finite_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#finite?" do + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @two = BigDecimal("2") + @three = BigDecimal("3") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + @big = BigDecimal("2E40001") + @finite_vals = [@one, @zero, @zero_pos, @zero_neg, @two, + @three, @frac_1, @frac_2, @big, @one_minus] + end + + it "is false if Infinity or NaN" do + @infinity.finite?.should == false + @infinity_minus.finite?.should == false + @nan.finite?.should == false + end + + it "returns true for finite values" do + @finite_vals.each do |val| + val.finite?.should == true + end + end +end + diff --git a/1.8/library/bigdecimal/fix_spec.rb b/1.8/library/bigdecimal/fix_spec.rb new file mode 100644 index 0000000000..f9fe494c0d --- /dev/null +++ b/1.8/library/bigdecimal/fix_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#fix" do + before(:each) do + @zero = BigDecimal("0") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + end + + it "returns a BigDecimal" do + BigDecimal("2E100000000").fix.kind_of?(BigDecimal).should == true + BigDecimal("2E-999").kind_of?(BigDecimal).should == true + end + + it "returns the integer part of the absolute value" do + a = BigDecimal("2E1000") + a.fix.should == a + b = BigDecimal("-2E1000") + b.fix.should == b + BigDecimal("0.123456789E5").fix.should == BigDecimal("0.12345E5") + BigDecimal("-0.123456789E5").fix.should == BigDecimal("-0.12345E5") + end + + it "correctly handles special values" do + @infinity.fix.should == @infinity + @infinity_neg.fix.should == @infinity_neg + @nan.fix.nan?.should == true + end + + it "returns 0 if the absolute value is < 1" do + BigDecimal("0.99999").fix.should == 0 + BigDecimal("-0.99999").fix.should == 0 + BigDecimal("0.000000001").fix.should == 0 + BigDecimal("-0.00000001").fix.should == 0 + BigDecimal("-1000000").fix.should_not == 0 + @zero.fix.should == 0 + @zero_pos.fix.should == @zero_pos + @zero_neg.fix.should == @zero_neg + end + + it "does not allow any arguments" do + lambda { + @mixed.fix(10) + }.should raise_error(ArgumentError) + end + +end \ No newline at end of file diff --git a/1.8/library/bigdecimal/floor_spec.rb b/1.8/library/bigdecimal/floor_spec.rb new file mode 100644 index 0000000000..abc4092eb5 --- /dev/null +++ b/1.8/library/bigdecimal/floor_spec.rb @@ -0,0 +1,97 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#floor" do + before(:each) do + @one = BigDecimal("1") + @three = BigDecimal("3") + @four = BigDecimal("4") + @zero = BigDecimal("0") + @mixed = BigDecimal("1.23456789") + @mixed_big = BigDecimal("1.23456789E100") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + end + + it "returns the greatest integer smaller or equal to self" do + @pos_int.floor.should == @pos_int + @neg_int.floor.should == @neg_int + @pos_frac.floor.should == @zero + @neg_frac.floor.should == BigDecimal("-1") + @infinity.floor.should == @infinity + @infinity_neg.floor.should == @infinity_neg + @nan.floor.nan?.should == true + @zero.floor.should == 0 + @zero_pos.floor.should == @zero_pos + @zero_neg.floor.should == @zero_neg + + BigDecimal('2.3').floor.should == 2 + BigDecimal('2.5').floor.should == 2 + BigDecimal('2.9999').floor.should == 2 + BigDecimal('-2.3').floor.should == -3 + BigDecimal('-2.5').floor.should == -3 + BigDecimal('-2.9999').floor.should == -3 + BigDecimal('0.8').floor.should == 0 + BigDecimal('-0.8').floor.should == -1 + end + + it "returns n digits right of the decimal point if given n > 0" do + @mixed.floor(1).should == BigDecimal("1.2") + @mixed.floor(5).should == BigDecimal("1.23456") + + BigDecimal("-0.03").floor(1).should == BigDecimal("-0.1") + BigDecimal("0.03").floor(1).should == BigDecimal("0") + + BigDecimal("23.45").floor(0).should == BigDecimal('23') + BigDecimal("23.45").floor(1).should == BigDecimal('23.4') + BigDecimal("23.45").floor(2).should == BigDecimal('23.45') + + BigDecimal("-23.45").floor(0).should == BigDecimal('-24') + BigDecimal("-23.45").floor(1).should == BigDecimal('-23.5') + BigDecimal("-23.45").floor(2).should == BigDecimal('-23.45') + + BigDecimal("2E-10").floor(0).should == @zero + BigDecimal("2E-10").floor(9).should == @zero + BigDecimal("2E-10").floor(10).should == BigDecimal('2E-10') + BigDecimal("2E-10").floor(11).should == BigDecimal('2E-10') + + (1..10).each do |n| + # 0.3, 0.33, 0.333, etc. + (@one/@three).floor(n).should == BigDecimal("0.#{'3'*n}") + # 1.3, 1.33, 1.333, etc. + (@four/@three).floor(n).should == BigDecimal("1.#{'3'*n}") + (BigDecimal('31')/@three).floor(n).should == BigDecimal("10.#{'3'*n}") + end + (1..10).each do |n| + # -0.4, -0.34, -0.334, etc. + (-@one/@three).floor(n).should == BigDecimal("-0.#{'3'*(n-1)}4") + end + (1..10).each do |n| + (@three/@one).floor(n).should == @three + end + (1..10).each do |n| + (-@three/@one).floor(n).should == -@three + end + end + + it "sets n digits left of the decimal point to 0, if given n < 0" do + BigDecimal("13345.234").floor(-2).should == BigDecimal("13300.0") + @mixed_big.floor(-99).should == BigDecimal("0.12E101") + @mixed_big.floor(-100).should == BigDecimal("0.1E101") + @mixed_big.floor(-95).should == BigDecimal("0.123456E101") + (1..10).each do |n| + BigDecimal('1.8').floor(-n).should == @zero + end + BigDecimal("1E10").floor(-30).should == @zero + BigDecimal("-1E10").floor(-30).should == BigDecimal('-1E30') + end + +end diff --git a/1.8/library/bigdecimal/frac_spec.rb b/1.8/library/bigdecimal/frac_spec.rb new file mode 100644 index 0000000000..5cb2f9cf44 --- /dev/null +++ b/1.8/library/bigdecimal/frac_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#frac" do + before(:each) do + @zero = BigDecimal("0") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + end + + it "returns a BigDecimal" do + @pos_int.frac.kind_of?(BigDecimal).should == true + @neg_int.frac.kind_of?(BigDecimal).should == true + @pos_frac.kind_of?(BigDecimal).should == true + @neg_frac.kind_of?(BigDecimal).should == true + end + + it "returns the fractional part of the absolute value" do + @mixed.frac.should == BigDecimal("0.23456789") + @pos_frac.frac.should == @pos_frac + @neg_frac.frac.should == @neg_frac + end + + it "returns 0 if the value is 0" do + @zero.frac.should == @zero + end + + it "returns 0 if the value is an integer" do + @pos_int.frac.should == @zero + @neg_int.frac.should == @zero + end + + it "correctly handles special values" do + @infinity.frac.should == @infinity + @infinity_neg.frac.should == @infinity_neg + @nan.frac.nan?.should == true + end + +end \ No newline at end of file diff --git a/1.8/library/bigdecimal/gt_spec.rb b/1.8/library/bigdecimal/gt_spec.rb new file mode 100644 index 0000000000..34baea4074 --- /dev/null +++ b/1.8/library/bigdecimal/gt_spec.rb @@ -0,0 +1,91 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#>" do + before(:each) do + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @int_mock = mock('123') + class << @int_mock + def coerce(other) + return [other, BigDecimal('123')] + end + def > (other) + BigDecimal('123') > other + end + end + + @values = [@mixed, @pos_int, @neg_int, @pos_frac, @neg_frac, + -2**32, -2**31, -2**30, -2**16, -2**8, -100, -10, -1, + @zero , 1, 2, 10, 2**8, 2**16, 2**32, @int_mock, @zero_pos, @zero_neg] + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + end + + it "returns true if a > b" do + one = BigDecimal("1") + two = BigDecimal("2") + + frac_1 = BigDecimal("1E-99999") + frac_2 = BigDecimal("0.9E-99999") + (@zero > one).should == false + (two > @zero).should == true + (frac_2 > frac_1).should == false + + (@neg_int > @pos_int).should == false + (@pos_int > @neg_int).should == true + (@neg_int > @pos_frac).should == false + (@pos_frac > @neg_int).should == true + (@zero > @zero_pos).should == false + (@zero > @zero_neg).should == false + (@zero_neg > @zero_pos).should == false + (@zero_pos > @zero_neg).should == false + end + + it "properly handles infinity values" do + @values.each { |val| + (val > @infinity).should == false + (@infinity > val).should == true + (val > @infinity_neg).should == true + (@infinity_neg > val).should == false + } + (@infinity > @infinity).should == false + (@infinity_neg > @infinity_neg).should == false + (@infinity > @infinity_neg).should == true + (@infinity_neg > @infinity).should == false + end + + it "properly handles NaN values" do + @values += [@infinity, @infinity_neg, @nan] + @values << nil + @values << Object.new + @values.each { |val| + (@nan > val).should == nil + } + + lambda { 10 > @nan }.should raise_error(ArgumentError) + (10.5 > @nan).should == false + + (@infinity > @nan).should == nil + (@infinity_neg > @nan).should == nil + (@zero > @nan).should == nil + end + + it "returns nil if the argument is nil" do + (@zero > nil).should == nil + (@infinity > nil).should == nil + (@infinity_neg > nil).should == nil + (@mixed > nil).should == nil + (@pos_int > nil).should == nil + (@neg_frac > nil).should == nil + end +end diff --git a/1.8/library/bigdecimal/gte_spec.rb b/1.8/library/bigdecimal/gte_spec.rb new file mode 100644 index 0000000000..aa1de95121 --- /dev/null +++ b/1.8/library/bigdecimal/gte_spec.rb @@ -0,0 +1,95 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#>=" do + before(:each) do + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @int_mock = mock('123') + class << @int_mock + def coerce(other) + return [other, BigDecimal('123')] + end + def >= (other) + BigDecimal('123') >= other + end + end + + @values = [@mixed, @pos_int, @neg_int, @pos_frac, @neg_frac, + -2**32, -2**31, -2**30, -2**16, -2**8, -100, -10, -1, + @zero , 1, 2, 10, 2**8, 2**16, 2**32, @int_mock, @zero_pos, @zero_neg] + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + end + + it "returns true if a >= b" do + one = BigDecimal("1") + two = BigDecimal("2") + + frac_1 = BigDecimal("1E-99999") + frac_2 = BigDecimal("0.9E-99999") + + (@zero >= one).should == false + (two >= @zero).should == true + + (frac_2 >= frac_1).should == false + (two >= two).should == true + (frac_1 >= frac_1).should == true + + (@neg_int >= @pos_int).should == false + (@pos_int >= @neg_int).should == true + (@neg_int >= @pos_frac).should == false + (@pos_frac >= @neg_int).should == true + (@zero >= @zero_pos).should == true + (@zero >= @zero_neg).should == true + (@zero_neg >= @zero_pos).should == true + (@zero_pos >= @zero_neg).should == true + end + + it "properly handles infinity values" do + @values.each { |val| + (val >= @infinity).should == false + (@infinity >= val).should == true + (val >= @infinity_neg).should == true + (@infinity_neg >= val).should == false + } + (@infinity >= @infinity).should == true + (@infinity_neg >= @infinity_neg).should == true + (@infinity >= @infinity_neg).should == true + (@infinity_neg >= @infinity).should == false + end + + it "properly handles NaN values" do + @values += [@infinity, @infinity_neg, @nan] + @values << nil + @values << Object.new + @values.each { |val| + (@nan >= val).should == nil + } + + lambda { 10 >= @nan }.should raise_error(ArgumentError) + (10.5 >= @nan).should == false + + (@infinity >= @nan).should == nil + (@infinity_neg >= @nan).should == nil + (@zero >= @nan).should == nil + end + + it "returns nil if the argument is nil" do + (@zero >= nil).should == nil + (@infinity >= nil).should == nil + (@infinity_neg >= nil).should == nil + (@mixed >= nil).should == nil + (@pos_int >= nil).should == nil + (@neg_frac >= nil).should == nil + end +end diff --git a/1.8/library/bigdecimal/infinite_spec.rb b/1.8/library/bigdecimal/infinite_spec.rb new file mode 100644 index 0000000000..e5bfc1cfc4 --- /dev/null +++ b/1.8/library/bigdecimal/infinite_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#infinite?" do + + it "returns 1 if self is Infinity" do + # documentation says returns true. + BigDecimal("Infinity").infinite?.should == 1 + end + + it "returns -1 if self is -Infinity" do + # This is how MRI behaves. + BigDecimal("-Infinity").infinite?.should == -1 + end + + it "returns not true otherwise" do + # If nil or false is not really specified in documentation. + e2_plus = BigDecimal("2E40001") + e3_minus = BigDecimal("3E-20001") + really_small_zero = BigDecimal("0E-200000000") + really_big_zero = BigDecimal("0E200000000000") + e3_minus.infinite?.should == nil + e2_plus.infinite?.should == nil + really_small_zero.infinite?.should == nil + really_big_zero.infinite?.should == nil + BigDecimal("0.000000000000000000000000").infinite?.should == nil + end + + it "returns not true if self is NaN" do + # NaN is a special value which is neither finite nor infinite. + nan = BigDecimal("NaN") + nan.infinite?.should == nil + end + +end diff --git a/1.8/library/bigdecimal/inspect_spec.rb b/1.8/library/bigdecimal/inspect_spec.rb new file mode 100644 index 0000000000..5495aaec85 --- /dev/null +++ b/1.8/library/bigdecimal/inspect_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#inspect" do + + before(:each) do + @bigdec = BigDecimal.new("1234.5678") + end + + it "returns String" do + @bigdec.inspect.kind_of?(String).should == true + end + + it "returns String starting with #" do + @bigdec.inspect[0].should == 35 + end + + it "encloses information in angle brackets" do + @bigdec.inspect.should =~ /^.<.*>$/ + end + + it "is comma separated list of three items" do + @bigdec.inspect.should =~ /...*,.*,.*/ + end + + it "value after first comma is value as string" do + @bigdec.inspect.split(",")[1].should == "\'0.12345678E4\'" + end + + it "last part is number of significant digits" do + signific_string = "#{@bigdec.precs[0]}(#{@bigdec.precs[1]})" + @bigdec.inspect.split(",")[2].should == signific_string + ">" + end + + it "looks like this" do + regex = /^\#\$/ + @bigdec.inspect.should =~ regex + end + +end + diff --git a/1.8/library/bigdecimal/lt_spec.rb b/1.8/library/bigdecimal/lt_spec.rb new file mode 100644 index 0000000000..28d43a3bd1 --- /dev/null +++ b/1.8/library/bigdecimal/lt_spec.rb @@ -0,0 +1,89 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#<" do + before(:each) do + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @int_mock = mock('123') + class << @int_mock + def coerce(other) + return [other, BigDecimal('123')] + end + def < (other) + BigDecimal('123') < other + end + end + + @values = [@mixed, @pos_int, @neg_int, @pos_frac, @neg_frac, + -2**32, -2**31, -2**30, -2**16, -2**8, -100, -10, -1, + @zero , 1, 2, 10, 2**8, 2**16, 2**32, @int_mock, @zero_pos, @zero_neg] + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + end + + it "returns true if a < b" do + one = BigDecimal("1") + two = BigDecimal("2") + frac_1 = BigDecimal("1E-99999") + frac_2 = BigDecimal("0.9E-99999") + (@zero < one).should == true + (two < @zero).should == false + (frac_2 < frac_1).should == true + (@neg_int < @pos_int).should == true + (@pos_int < @neg_int).should == false + (@neg_int < @pos_frac).should == true + (@pos_frac < @neg_int).should == false + (@zero < @zero_pos).should == false + (@zero < @zero_neg).should == false + (@zero_neg < @zero_pos).should == false + (@zero_pos < @zero_neg).should == false + end + + it "properly handles infinity values" do + @values.each { |val| + (val < @infinity).should == true + (@infinity < val).should == false + (val < @infinity_neg).should == false + (@infinity_neg < val).should == true + } + (@infinity < @infinity).should == false + (@infinity_neg < @infinity_neg).should == false + (@infinity < @infinity_neg).should == false + (@infinity_neg < @infinity).should == true + end + + it "properly handles NaN values" do + @values += [@infinity, @infinity_neg, @nan] + @values << nil + @values << Object.new + @values.each { |val| + (@nan < val).should == nil + } + + lambda { 10 < @nan }.should raise_error(ArgumentError) + (10.5 < @nan).should == false + + (@infinity < @nan).should == nil + (@infinity_neg < @nan).should == nil + (@zero < @nan).should == nil + end + + it "returns nil if the argument is nil" do + (@zero < nil).should == nil + (@infinity < nil).should == nil + (@infinity_neg < nil).should == nil + (@mixed < nil).should == nil + (@pos_int < nil).should == nil + (@neg_frac < nil).should == nil + end +end diff --git a/1.8/library/bigdecimal/lte_spec.rb b/1.8/library/bigdecimal/lte_spec.rb new file mode 100644 index 0000000000..1d138419b9 --- /dev/null +++ b/1.8/library/bigdecimal/lte_spec.rb @@ -0,0 +1,95 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#<=" do + before(:each) do + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @int_mock = mock('123') + class << @int_mock + def coerce(other) + return [other, BigDecimal('123')] + end + def <= (other) + BigDecimal('123') <= other + end + end + + @values = [@mixed, @pos_int, @neg_int, @pos_frac, @neg_frac, + -2**32, -2**31, -2**30, -2**16, -2**8, -100, -10, -1, + @zero , 1, 2, 10, 2**8, 2**16, 2**32, @int_mock, @zero_pos, @zero_neg] + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + end + + it "returns true if a <= b" do + one = BigDecimal("1") + two = BigDecimal("2") + + frac_1 = BigDecimal("1E-99999") + frac_2 = BigDecimal("0.9E-99999") + + (@zero <= one).should == true + (two <= @zero).should == false + + (frac_2 <= frac_1).should == true + (two <= two).should == true + (frac_1 <= frac_1).should == true + + (@neg_int <= @pos_int).should == true + (@pos_int <= @neg_int).should == false + (@neg_int <= @pos_frac).should == true + (@pos_frac <= @neg_int).should == false + (@zero <= @zero_pos).should == true + (@zero <= @zero_neg).should == true + (@zero_neg <= @zero_pos).should == true + (@zero_pos <= @zero_neg).should == true + end + + it "properly handles infinity values" do + @values.each { |val| + (val <= @infinity).should == true + (@infinity <= val).should == false + (val <= @infinity_neg).should == false + (@infinity_neg <= val).should == true + } + (@infinity <= @infinity).should == true + (@infinity_neg <= @infinity_neg).should == true + (@infinity <= @infinity_neg).should == false + (@infinity_neg <= @infinity).should == true + end + + it "properly handles NaN values" do + @values += [@infinity, @infinity_neg, @nan] + @values << nil + @values << Object.new + @values.each { |val| + (@nan <= val).should == nil + } + + lambda { 10 <= @nan }.should raise_error(ArgumentError) + (10.5 <= @nan).should == false + + (@infinity <= @nan).should == nil + (@infinity_neg <= @nan).should == nil + (@zero <= @nan).should == nil + end + + it "returns nil if the argument is nil" do + (@zero <= nil).should == nil + (@infinity <= nil).should == nil + (@infinity_neg <= nil).should == nil + (@mixed <= nil).should == nil + (@pos_int <= nil).should == nil + (@neg_frac <= nil).should == nil + end +end diff --git a/1.8/library/bigdecimal/minus_spec.rb b/1.8/library/bigdecimal/minus_spec.rb new file mode 100644 index 0000000000..4a9591cd20 --- /dev/null +++ b/1.8/library/bigdecimal/minus_spec.rb @@ -0,0 +1,58 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#-" do + + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @two = BigDecimal("2") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns a - b" do + (@two - @one).should == @one + (@one - @two).should == @one_minus + (@one - @one_minus).should == @two + (@frac_2 - @frac_1).should == BigDecimal("-0.1E-99999") + (@two - @two).should == @zero + (@frac_1 - @frac_1).should == @zero + (BigDecimal('1.23456789') - BigDecimal('1.2')).should == BigDecimal("0.03456789") + end + + it "returns NaN if NaN is involved" do + (@one - @nan).nan?.should == true + (@nan - @one).nan?.should == true + (@nan - @nan).nan?.should == true + (@nan - @infinity).nan?.should == true + (@nan - @infinity_minus).nan?.should == true + (@infinity - @nan).nan?.should == true + (@infinity_minus - @nan).nan?.should == true + end + + it "returns NaN both operands are infinite with the same sign" do + (@infinity - @infinity).nan?.should == true + (@infinity_minus - @infinity_minus).nan?.should == true + end + + it "returns Infinity or -Infinity if these are involved" do + (@infinity - @infinity_minus).should == @infinity + (@infinity_minus - @infinity).should == @infinity_minus + + (@infinity - @zero).should == @infinity + (@infinity - @frac_2).should == @infinity + (@infinity - @two).should == @infinity + (@infinity - @one_minus).should == @infinity + + (@zero - @infinity).should == @infinity_minus + (@frac_2 - @infinity).should == @infinity_minus + (@two - @infinity).should == @infinity_minus + (@one_minus - @infinity).should == @infinity_minus + end + +end diff --git a/1.8/library/bigdecimal/modulo_spec.rb b/1.8/library/bigdecimal/modulo_spec.rb new file mode 100644 index 0000000000..a974134243 --- /dev/null +++ b/1.8/library/bigdecimal/modulo_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/modulo' + +describe "BigDecimal#%" do + it_behaves_like(:bigdecimal_modulo, :%) +end + +describe "BigDecimal#modulo" do + it_behaves_like(:bigdecimal_modulo, :modulo) +end diff --git a/1.8/library/bigdecimal/mult_spec.rb b/1.8/library/bigdecimal/mult_spec.rb new file mode 100644 index 0000000000..ca54c90d46 --- /dev/null +++ b/1.8/library/bigdecimal/mult_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/mult' +require 'bigdecimal' + +describe "BigDecimal#mult" do + # BigDecimal#mult with precision shares some behavior with BigDecimal#* + begin + class BigDecimal + def mult_with_precision(arg) + mult(arg, 10) + end + end + it_behaves_like(:bigdecimal_mult, :mult_with_precision, :mult) + ensure + class BigDecimal + undef mult_with_precision + end + end +end + +describe "BigDecimal#mult" do + before :each do + @one = BigDecimal "1" + @e3_minus = BigDecimal "3E-20001" + @e = BigDecimal "1.00000000000000000000123456789" + @tolerance = @e.sub @one, 1000 + @tolerance2 = BigDecimal "30001E-20005" + + end + + it "multiply self with other with (optional) precision" do + @e.mult(@one, 1).should be_close(@one, @tolerance) + @e3_minus.mult(@one, 1).should be_close(0, @tolerance2) + end + +end diff --git a/1.8/library/bigdecimal/multiply_spec.rb b/1.8/library/bigdecimal/multiply_spec.rb new file mode 100644 index 0000000000..3a32cbc5e3 --- /dev/null +++ b/1.8/library/bigdecimal/multiply_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/mult' +require 'bigdecimal' + +describe "BigDecimal#*" do + it_behaves_like(:bigdecimal_mult, :*) +end + +describe "BigDecimal#*" do + before(:each) do + @e3_minus = BigDecimal("3E-20001") + @e3_plus = BigDecimal("3E20001") + @e = BigDecimal("1.00000000000000000000123456789") + @one = BigDecimal("1") + end + + it "multiply self with other" do + (@e3_minus * @e3_plus).should == BigDecimal("9") + # Can't do this till we implement ** + # (@e3_minus * @e3_minus).should == @e3_minus ** 2 + # So let's rewrite it as: + (@e3_minus * @e3_minus).should == BigDecimal("9E-40002") + (@e * @one).should == @e + end +end diff --git a/1.8/library/bigdecimal/nan_spec.rb b/1.8/library/bigdecimal/nan_spec.rb new file mode 100644 index 0000000000..5e9c15a556 --- /dev/null +++ b/1.8/library/bigdecimal/nan_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#nan?" do + + it "returns true if self is not a number" do + BigDecimal("NaN").nan?.should == true + end + + it "returns false if self is not a NaN" do + BigDecimal("Infinity").nan?.should == false + BigDecimal("-Infinity").nan?.should == false + BigDecimal("0").nan?.should == false + BigDecimal("+0").nan?.should == false + BigDecimal("-0").nan?.should == false + BigDecimal("2E40001").nan?.should == false + BigDecimal("3E-20001").nan?.should == false + BigDecimal("0E-200000000").nan?.should == false + BigDecimal("0E200000000000").nan?.should == false + BigDecimal("0.000000000000000000000000").nan?.should == false + end + +end diff --git a/1.8/library/bigdecimal/new_spec.rb b/1.8/library/bigdecimal/new_spec.rb new file mode 100644 index 0000000000..9477db5376 --- /dev/null +++ b/1.8/library/bigdecimal/new_spec.rb @@ -0,0 +1,97 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal.new" do + + it "creates a new object of class BigDecimal" do + BigDecimal.new("3.14159").class.should == BigDecimal + (0..9).each {|i| + BigDecimal.new("1#{i}").should == 10 + i + BigDecimal.new("-1#{i}").should == -10 - i + BigDecimal.new("1E#{i}").should == 10**i + BigDecimal.new("1000000E-#{i}").should == 10**(6-i) + } + (1..9).each {|i| + BigDecimal.new("100.#{i}").to_s.should == "0.100#{i}E3" + BigDecimal.new("-100.#{i}").to_s.should == "-0.100#{i}E3" + } + end + + it "Number of significant digits >= given precision" do + pi_string = "3.1415923" + BigDecimal.new("3.1415923", 10).precs[1].should >= 10 + end + + it "determines precision from initial value" do + pi_string = "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593014782083152134043" + BigDecimal.new(pi_string).precs[1].should >= pi_string.size + end + + it "ignores leading whitespace" do + BigDecimal.new(" \t\n \r1234").should == BigDecimal.new("1234") + BigDecimal.new(" \t\n \rNaN \n").nan?.should == true + BigDecimal.new(" \t\n \rInfinity \n").infinite?.should == 1 + BigDecimal.new(" \t\n \r-Infinity \n").infinite?.should == -1 + BigDecimal.new(" \t\n \r-\t\t\tInfinity \n").should == 0.0 + end + + it "ignores trailing garbage" do + BigDecimal.new("123E45ruby").should == BigDecimal.new("123E45") + BigDecimal.new("123x45").should == BigDecimal.new("123") + BigDecimal.new("123.4%E5").should == BigDecimal.new("123.4") + BigDecimal.new("1E2E3E4E5E").should == BigDecimal.new("100") + end + + it "treats invalid strings as 0.0" do + BigDecimal.new("ruby").should == BigDecimal.new("0.0") + end + + it "allows omitting the integer part" do + BigDecimal.new(".123").should == BigDecimal.new("0.123") + BigDecimal.new("-.123").should == BigDecimal.new("-0.123") + end + + it "allows for underscores in all parts" do + reference = BigDecimal.new("12345.67E89") + + BigDecimal.new("12_345.67E89").should == reference + BigDecimal.new("1_2_3_4_5_._6____7_E89").should == reference + BigDecimal.new("12345_.67E_8__9_").should == reference + end + + it "accepts NaN and [+-]Infinity" do + BigDecimal.new("NaN").nan?.should == true + + pos_inf = BigDecimal.new("Infinity") + pos_inf.finite?.should == false + pos_inf.should > 0 + pos_inf.should == BigDecimal.new("+Infinity") + + neg_inf = BigDecimal.new("-Infinity") + neg_inf.finite?.should == false + neg_inf.should < 0 + end + + it "allows for [eEdD] as exponent separator" do + reference = BigDecimal.new("12345.67E89") + + BigDecimal.new("12345.67e89").should == reference + BigDecimal.new("12345.67E89").should == reference + BigDecimal.new("12345.67d89").should == reference + BigDecimal.new("12345.67D89").should == reference + end + + it "allows for varying signs" do + reference = BigDecimal.new("123.456E1") + + BigDecimal.new("+123.456E1").should == reference + BigDecimal.new("-123.456E1").should == -reference + BigDecimal.new("123.456E+1").should == reference + BigDecimal.new("12345.6E-1").should == reference + BigDecimal.new("+123.456E+1").should == reference + BigDecimal.new("+12345.6E-1").should == reference + BigDecimal.new("-123.456E+1").should == -reference + BigDecimal.new("-12345.6E-1").should == -reference + end + +end diff --git a/1.8/library/bigdecimal/nonzero_spec.rb b/1.8/library/bigdecimal/nonzero_spec.rb new file mode 100644 index 0000000000..05a7c41eb2 --- /dev/null +++ b/1.8/library/bigdecimal/nonzero_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#nonzero?" do + + it "returns self if self doesn't equal zero" do + # documentation says, it returns true. (04/10/08) + e2_plus = BigDecimal("2E40001") + e3_minus = BigDecimal("3E-20001") + infinity = BigDecimal("Infinity") + infinity_minus = BigDecimal("-Infinity") + nan = BigDecimal("NaN") + infinity.nonzero?.should.equal?(infinity) + infinity_minus.nonzero?.should.equal?(infinity_minus) + nan.nonzero?.should.equal?(nan) + e3_minus.nonzero?.should.equal?(e3_minus) + e2_plus.nonzero?.should.equal?(e2_plus) + end + + it "returns nil otherwise" do + # documentation states, it should return false. (04/10/08) + really_small_zero = BigDecimal("0E-200000000") + really_big_zero = BigDecimal("0E200000000000") + really_small_zero.nonzero?.should == nil + really_big_zero.nonzero?.should == nil + BigDecimal("0.000000000000000000000000").nonzero?.should == nil + end + +end diff --git a/1.8/library/bigdecimal/plus_spec.rb b/1.8/library/bigdecimal/plus_spec.rb new file mode 100644 index 0000000000..71fb4fecdb --- /dev/null +++ b/1.8/library/bigdecimal/plus_spec.rb @@ -0,0 +1,49 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#+" do + + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @two = BigDecimal("2") + @three = BigDecimal("3") + @ten = BigDecimal("10") + @eleven = BigDecimal("11") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns a + b" do + + (@two + @one).should == @three + (@one + @two).should == @three + (@one + @one_minus).should == @zero + (@zero + @one).should == @one + (@ten + @one).should == @eleven + (@frac_2 + @frac_1).should == BigDecimal("1.9E-99999") + (@frac_1 + @frac_1).should == BigDecimal("2E-99999") +# can't do it this way because * isn't implemented yet +# (@frac_1 + @frac_1).should == 2 * @frac_1 + end + + it "returns NaN if NaN is involved" do + (@one + @nan).nan?.should == true + (@nan + @one).nan?.should == true + end + + it "returns Infinity or -Infinity if these are involved" do + (@zero + @infinity).should == @infinity + (@frac_2 + @infinity).should == @infinity + (@two + @infinity_minus).should == @infinity_minus + end + + it "returns NaN if Infinity + (- Infinity)" do + (@infinity + @infinity_minus).nan?.should == true + end + +end diff --git a/1.8/library/bigdecimal/power_spec.rb b/1.8/library/bigdecimal/power_spec.rb new file mode 100644 index 0000000000..002593dae8 --- /dev/null +++ b/1.8/library/bigdecimal/power_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/power' + +describe "BigDecimal#power" do + it_behaves_like(:bigdecimal_power, :power) +end diff --git a/1.8/library/bigdecimal/precs_spec.rb b/1.8/library/bigdecimal/precs_spec.rb new file mode 100644 index 0000000000..b703e1aa49 --- /dev/null +++ b/1.8/library/bigdecimal/precs_spec.rb @@ -0,0 +1,48 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#precs" do + + before(:each) do + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + @zero = BigDecimal("0") + @zero_neg = BigDecimal("-0") + + @arr = [BigDecimal("2E40001"), BigDecimal("3E-20001"),\ + @infinity, @infinity_neg, @nan, @zero, @zero_neg] + end + + it "returns array of two values" do + @arr.each do |x| + x.precs.kind_of?(Array).should == true + x.precs.size.should == 2 + end + end + + it "returns Integers as array values" do + @arr.each do |x| + x.precs[0].kind_of?(Integer).should == true + x.precs[1].kind_of?(Integer).should == true + end + end + + it "returns the current value of significant digits as the first value" do + BigDecimal("3.14159").precs[0].should >= 6 + BigDecimal('1').precs[0].should == BigDecimal('1' + '0' * 100).precs[0] + [@infinity, @infinity_neg, @nan, @zero, @zero_neg].each do |value| + value.precs[0].should <= 4 + end + end + + it "returns the maximum number of significant digits as the second value" do + BigDecimal("3.14159").precs[1].should >= 6 + BigDecimal('1').precs[1].should < 10 + BigDecimal('1' + '0' * 100).precs[1] >= 101 + [@infinity, @infinity_neg, @nan, @zero, @zero_neg].each do |value| + value.precs[1].should <= 8 + end + end +end + diff --git a/1.8/library/bigdecimal/quo_spec.rb b/1.8/library/bigdecimal/quo_spec.rb new file mode 100644 index 0000000000..047ef101ca --- /dev/null +++ b/1.8/library/bigdecimal/quo_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/quo' +require 'bigdecimal' + +describe "BigDecimal#quo" do + it_behaves_like(:bigdecimal_quo, :quo) +end + diff --git a/1.8/library/bigdecimal/remainder_spec.rb b/1.8/library/bigdecimal/remainder_spec.rb new file mode 100644 index 0000000000..93d9ae36d4 --- /dev/null +++ b/1.8/library/bigdecimal/remainder_spec.rb @@ -0,0 +1,79 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#remainder" do + + before(:each) do + @zero = BigDecimal("0") + @one = BigDecimal("0") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "if both values are of same sign it equals modulo" do + BigDecimal('1234567890123456789012345679').remainder(BigDecimal('1')).should == @zero + BigDecimal('123456789').remainder(BigDecimal('333333333333333333333333333E-50')).should == BigDecimal('0.12233333333333333333345679E-24') + + @mixed.remainder(@pos_frac).should == @mixed % @pos_frac + @pos_int.remainder(@pos_frac).should == @pos_int % @pos_frac + @neg_frac.remainder(@neg_int).should == @neg_frac % @neg_int + @neg_int.remainder(@neg_frac).should == @neg_int % @neg_frac + end + + it "Otherwise, it is the modulus minus the value divided by" do + @mixed.remainder(@neg_frac).should == (@mixed % @neg_frac) * -1 + @pos_int.remainder(@neg_frac).should == (@pos_int % @neg_frac) * -1 + @neg_frac.remainder(@pos_int).should == @neg_frac % (@pos_int * -1) + @neg_int.remainder(@pos_frac).should == (@neg_int % @pos_frac) * -1 + end + + it "returns NaN used with zero" do + @mixed.remainder(@zero).nan?.should == true + @zero.remainder(@zero).nan?.should == true + end + + it "returns zero if used on zero" do + @zero.remainder(@mixed).should == @zero + end + + it "returns NaN if NaN is involved" do + @nan.remainder(@nan).nan?.should == true + @nan.remainder(@one).nan?.should == true + @one.remainder(@nan).nan?.should == true + @infinity.remainder(@nan).nan?.should == true + @nan.remainder(@infinity).nan?.should == true + end + + it "returns NaN if Infinity is involved" do + @infinity.remainder(@infinity).nan?.should == true + @infinity.remainder(@one).nan?.should == true + @infinity.remainder(@mixed).nan?.should == true + @infinity.remainder(@one_minus).nan?.should == true + @infinity.remainder(@frac_1).nan?.should == true + @one.remainder(@infinity).nan?.should == true + + @infinity_minus.remainder(@infinity_minus).nan?.should == true + @infinity_minus.remainder(@one).nan?.should == true + @one.remainder(@infinity_minus).nan?.should == true + @frac_2.remainder(@infinity_minus).nan?.should == true + + @infinity.remainder(@infinity_minus).nan?.should == true + @infinity_minus.remainder(@infinity).nan?.should == true + end + + it "raises TypeError if the argument cannot be coerced to BigDecimal" do + lambda { + @one.remainder('2') + }.should raise_error(TypeError) + end + +end diff --git a/1.8/library/bigdecimal/shared/eql.rb b/1.8/library/bigdecimal/shared/eql.rb new file mode 100644 index 0000000000..56ee3eb7c0 --- /dev/null +++ b/1.8/library/bigdecimal/shared/eql.rb @@ -0,0 +1,59 @@ +require 'bigdecimal' + +shared :bigdecimal_eql do |cmd| + + describe "BigDecimal##{cmd}" do + + before(:each) do + @bg6543_21 = BigDecimal.new("6543.21") + @bg5667_19 = BigDecimal.new("5667.19") + @a = BigDecimal("1.0000000000000000000000000000000000000000005") + @b = BigDecimal("1.00000000000000000000000000000000000000000005") + @bigint = BigDecimal("1000.0") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + end + + it "test for equality" do + @bg6543_21.send(cmd, @bg6543_21).should == true + @a.send(cmd, @a).should == true + @a.send(cmd, @b).should == false + @bg6543_21.send(cmd, @a).should == false + @bigint.send(cmd, 1000).should == true + end + + it "NaN is never equal to any number" do + @nan.send(cmd, @nan).should_not == true + @a.send(cmd, @nan).should_not == true + @nan.send(cmd, @a).should_not == true + @nan.send(cmd, @infinity).should_not == true + @nan.send(cmd, @infinity_minus).should_not == true + @infinity.send(cmd, @nan).should_not == true + @infinity_minus.send(cmd, @nan).should_not == true + end + + it "returns true for infinity values with the same sign" do + @infinity.send(cmd, @infinity).should == true + @infinity.send(cmd, BigDecimal("Infinity")).should == true + BigDecimal("Infinity").send(cmd, @infinity).should == true + + @infinity_minus.send(cmd, @infinity_minus).should == true + @infinity_minus.send(cmd, BigDecimal("-Infinity")).should == true + BigDecimal("-Infinity").send(cmd, @infinity_minus).should == true + end + + it "does not return true for infinity values with different signs" do + @infinity.send(cmd, @infinity_minus).should_not == true + @infinity_minus.send(cmd, @infinity).should_not == true + end + + it "does not return true when ininite value compared to finite one" do + @infinity.send(cmd, @a).should_not == true + @infinity_minus.send(cmd, @a).should_not == true + + @a.send(cmd, @infinity).should_not == true + @a.send(cmd, @infinity_minus).should_not == true + end + end +end diff --git a/1.8/library/bigdecimal/shared/modulo.rb b/1.8/library/bigdecimal/shared/modulo.rb new file mode 100644 index 0000000000..4f7a009bde --- /dev/null +++ b/1.8/library/bigdecimal/shared/modulo.rb @@ -0,0 +1,116 @@ +require 'bigdecimal' + +shared :bigdecimal_modulo do |cmd, mode| + + describe "BigDecimal##{cmd}" do + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @two = BigDecimal("2") + @three = BigDecimal("3") + @mixed = BigDecimal("1.23456789") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns self modulo other" do + bd6543 = BigDecimal.new("6543.21") + bd5667 = BigDecimal.new("5667.19") + a = BigDecimal("1.0000000000000000000000000000000000000000005") + b = BigDecimal("1.00000000000000000000000000000000000000000005") + + bd6543.send(cmd, 137).should == BigDecimal("104.21") + bd5667.send(cmd, bignum_value).should == 5667.19 + bd6543.send(cmd, BigDecimal("137.24")).should == BigDecimal("92.93") + bd6543.send(cmd, 137).should be_close(6543.21.%(137), TOLERANCE) + bd6543.send(cmd, 137).should == bd6543 % 137 + bd5667.send(cmd, bignum_value).should + be_close(5667.19.%(0xffffffff), TOLERANCE) + bd5667.send(cmd, bignum_value).should == bd5667.%(0xffffffff) + bd6543.send(cmd, 137.24).should be_close(6543.21.%(137.24), TOLERANCE) + a.send(cmd, b).should == BigDecimal("0.45E-42") + @zero.send(cmd, @one).should == @zero + @zero.send(cmd, @one_minus).should == @zero + @two.send(cmd, @one).should == @zero + @one.send(cmd, @two).should == @one + @frac_1.send(cmd, @one).should == @frac_1 + @frac_2.send(cmd, @one).should == @frac_2 + @one_minus.send(cmd, @one_minus).should == @zero + @one_minus.send(cmd, @one).should == @zero + @one_minus.send(cmd, @two).should == @one + @one.send(cmd, -@two).should == -@one + + @one_minus.modulo(BigDecimal('0.9')).should == BigDecimal('0.8') + @one.modulo(BigDecimal('-0.9')).should == BigDecimal('-0.8') + + @one_minus.modulo(BigDecimal('0.8')).should == BigDecimal('0.6') + @one.modulo(BigDecimal('-0.8')).should == BigDecimal('-0.6') + + @one_minus.modulo(BigDecimal('0.6')).should == BigDecimal('0.2') + @one.modulo(BigDecimal('-0.6')).should == BigDecimal('-0.2') + + @one_minus.modulo(BigDecimal('0.5')).should == @zero + @one.modulo(BigDecimal('-0.5')).should == @zero + @one_minus.modulo(BigDecimal('-0.5')).should == @zero + + @one_minus.modulo(BigDecimal('0.4')).should == BigDecimal('0.2') + @one.modulo(BigDecimal('-0.4')).should == BigDecimal('-0.2') + + @one_minus.modulo(BigDecimal('0.3')).should == BigDecimal('0.2') + @one_minus.modulo(BigDecimal('0.2')).should == @zero + end + + it "does NOT raise ZeroDivisionError if other is zero" do + bd6543 = BigDecimal.new("6543.21") + bd5667 = BigDecimal.new("5667.19") + a = BigDecimal("1.0000000000000000000000000000000000000000005") + b = BigDecimal("1.00000000000000000000000000000000000000000005") + + bd5667.send(cmd, 0).nan?.should == true + if (mode != :exclude_float_zero) + # MRI weird behavior. While #modulo returns NaN, + # #divmod[1] raises an Error, so we guard it here. + bd5667.send(cmd, 0.0).nan?.should == true + end + bd5667.send(cmd, BigDecimal("0")).nan?.should == true + @zero.send(cmd, @zero).nan?.should == true + end + + it "returns NaN if NaN is involved" do + @nan.send(cmd, @nan).nan?.should == true + @nan.send(cmd, @one).nan?.should == true + @one.send(cmd, @nan).nan?.should == true + @infinity.send(cmd, @nan).nan?.should == true + @nan.send(cmd, @infinity).nan?.should == true + end + + it "returns NaN if Infinity is involved" do + @infinity.send(cmd, @infinity).nan?.should == true + @infinity.send(cmd, @one).nan?.should == true + @infinity.send(cmd, @mixed).nan?.should == true + @infinity.send(cmd, @one_minus).nan?.should == true + @infinity.send(cmd, @frac_1).nan?.should == true + @one.send(cmd, @infinity).nan?.should == true + + @infinity_minus.send(cmd, @infinity_minus).nan?.should == true + @infinity_minus.send(cmd, @one).nan?.should == true + @one.send(cmd, @infinity_minus).nan?.should == true + @frac_2.send(cmd, @infinity_minus).nan?.should == true + + @infinity.send(cmd, @infinity_minus).nan?.should == true + @infinity_minus.send(cmd, @infinity).nan?.should == true + end + + it "raises TypeError if the argument cannot be coerced to BigDecimal" do + lambda { + @one.send(cmd, '2') + }.should raise_error(TypeError) + end + end +end diff --git a/1.8/library/bigdecimal/shared/mult.rb b/1.8/library/bigdecimal/shared/mult.rb new file mode 100644 index 0000000000..026de162c9 --- /dev/null +++ b/1.8/library/bigdecimal/shared/mult.rb @@ -0,0 +1,100 @@ +require 'bigdecimal' + +shared :bigdecimal_mult do |cmd, name| + describe "BigDecimal##{name ? name : cmd}" do + before :each do + @zero = BigDecimal "0" + @zero_pos = BigDecimal "+0" + @zero_neg = BigDecimal "-0" + + @one = BigDecimal "1" + @mixed = BigDecimal "1.23456789" + @pos_int = BigDecimal "2E5555" + @neg_int = BigDecimal "-2E5555" + @pos_frac = BigDecimal "2E-9999" + @neg_frac = BigDecimal "-2E-9999" + @nan = BigDecimal "NaN" + @infinity = BigDecimal "Infinity" + @infinity_minus = BigDecimal "-Infinity" + @one_minus = BigDecimal "-1" + @frac_1 = BigDecimal "1E-99999" + @frac_2 = BigDecimal "0.9E-99999" + + @e3_minus = BigDecimal "3E-20001" + @e = BigDecimal "1.00000000000000000000123456789" + @tolerance = @e.sub @one, 1000 + @tolerance2 = BigDecimal "30001E-20005" + + @special_vals = [@infinity, @infinity_minus, @nan] + @regular_vals = [ @one, @mixed, @pos_int, @neg_int, + @pos_frac, @neg_frac, @one_minus, + @frac_1, @frac_2 + ] + @zeroes = [@zero, @zero_pos, @zero_neg] + end + + it "returns zero of appropriate sign if self or argument is zero" do + @zero.send(cmd, @zero).sign.should == BigDecimal::SIGN_POSITIVE_ZERO + @zero_neg.send(cmd, @zero_neg).sign.should == BigDecimal::SIGN_POSITIVE_ZERO + @zero.send(cmd, @zero_neg).sign.should == BigDecimal::SIGN_NEGATIVE_ZERO + @zero_neg.send(cmd, @zero).sign.should == BigDecimal::SIGN_NEGATIVE_ZERO + + @one.send(cmd, @zero).sign.should == BigDecimal::SIGN_POSITIVE_ZERO + @one.send(cmd, @zero_neg).sign.should == BigDecimal::SIGN_NEGATIVE_ZERO + + @zero.send(cmd, @one).sign.should == BigDecimal::SIGN_POSITIVE_ZERO + @zero.send(cmd, @one_minus).sign.should == BigDecimal::SIGN_NEGATIVE_ZERO + @zero_neg.send(cmd, @one_minus).sign.should == BigDecimal::SIGN_POSITIVE_ZERO + @zero_neg.send(cmd, @one).sign.should == BigDecimal::SIGN_NEGATIVE_ZERO + end + + it "returns NaN if NaN is involved" do + values = @regular_vals + @zeroes + + values.each do |val| + @nan.send(cmd, val).nan?.should == true + val.send(cmd, @nan).nan?.should == true + end + end + + it "returns zero if self or argument is zero" do + values = @regular_vals + @zeroes + + values.each do |val| + @zeroes.each do |zero| + zero.send(cmd, val).should == 0 + zero.send(cmd, val).zero?.should == true + val.send(cmd, zero).should == 0 + val.send(cmd, zero).zero?.should == true + end + end + end + + it "returns infinite value if self or argument is infinite" do + values = @regular_vals + infs = [@infinity, @infinity_minus] + + values.each do |val| + infs.each do |inf| + inf.send(cmd, val).finite?.should == false + val.send(cmd, inf).finite?.should == false + end + end + + @infinity.send(cmd, @infinity).infinite?.should == 1 + @infinity_minus.send(cmd, @infinity_minus).infinite?.should == 1 + @infinity.send(cmd, @infinity_minus).infinite?.should == -1 + @infinity_minus.send(cmd, @infinity).infinite?.should == -1 + @infinity.send(cmd, @one).infinite?.should == 1 + @infinity_minus.send(cmd, @one).infinite?.should == -1 + end + + it "returns NaN if the result is undefined" do + @zero.send(cmd, @infinity).nan?.should == true + @zero.send(cmd, @infinity_minus).nan?.should == true + @infinity.send(cmd, @zero).nan?.should == true + @infinity_minus.send(cmd, @zero).nan?.should == true + end + + end +end diff --git a/1.8/library/bigdecimal/shared/power.rb b/1.8/library/bigdecimal/shared/power.rb new file mode 100644 index 0000000000..a985b60306 --- /dev/null +++ b/1.8/library/bigdecimal/shared/power.rb @@ -0,0 +1,71 @@ +require 'bigdecimal' + +shared :bigdecimal_power do |cmd| + + describe "BigDecimal##{cmd}" do + + it "powers of self" do + e3_minus = BigDecimal("3E-20001") + e3_minus_power_2 = BigDecimal("9E-40002") + e3_plus = BigDecimal("3E20001") + e2_plus = BigDecimal("2E40001") + e5_minus = BigDecimal("5E-40002") + e = BigDecimal("1.00000000000000000000123456789") + one = BigDecimal("1") + ten = BigDecimal("10") + tolerance = BigDecimal("1E-95") + ten_powers = BigDecimal("1E10000") + pi = BigDecimal("3.14159265358979") + e3_minus.send(cmd, 2).should == e3_minus_power_2 + e3_plus.send(cmd, 0).should == 1 + e3_minus.send(cmd, 1).should == e3_minus + e2_plus.send(cmd, -1).should == e5_minus + e2_plus.send(cmd, -1).should == e5_minus.power(1) + (e2_plus.send(cmd, -1) * e5_minus.send(cmd, -1)).should == 1 + e.send(cmd, 2).should == e * e + e.send(cmd, -1).should be_close(one.div(e, 120), tolerance) + ten.send(cmd, 10000).should == ten_powers + pi.send(cmd, 10).should be_close(Math::PI ** 10, TOLERANCE) + end + + it "powers of 1 equal 1" do + one = BigDecimal("1") + one.send(cmd, 0).should == 1 + one.send(cmd, 1).should == 1 + one.send(cmd, 10).should == 1 + one.send(cmd, -10).should == 1 + end + + it "0 to power of 0 is 1" do + zero = BigDecimal("0") + zero.send(cmd, 0).should == 1 + end + + it "0 to powers < 0 is Infinity" do + zero = BigDecimal("0") + infinity = BigDecimal("Infinity") + zero.send(cmd, -10).should == infinity + zero.send(cmd, -1).should == infinity + end + + it "other powers of 0 are 0" do + zero = BigDecimal("0") + zero.send(cmd, 1).should == 0 + zero.send(cmd, 10).should == 0 + end + + it "returns NaN if self is NaN" do + BigDecimal("NaN").send(cmd, -5).nan?.should == true + BigDecimal("NaN").send(cmd, 5).nan?.should == true + end + + it "returns NaN if self is infinite" do + BigDecimal("Infinity").send(cmd, -5).nan?.should == true + BigDecimal("-Infinity").send(cmd, -5).nan?.should == true + BigDecimal("Infinity").send(cmd, 5).nan?.should == true + BigDecimal("-Infinity").send(cmd, 5).nan?.should == true + end + + end + +end diff --git a/1.8/library/bigdecimal/shared/quo.rb b/1.8/library/bigdecimal/shared/quo.rb new file mode 100644 index 0000000000..fea7ff4e0f --- /dev/null +++ b/1.8/library/bigdecimal/shared/quo.rb @@ -0,0 +1,56 @@ +require 'bigdecimal' + +shared :bigdecimal_quo do |cmd| + + describe "BigDecimal##{cmd}" do + + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @two = BigDecimal("2") + @three = BigDecimal("3") + @eleven = BigDecimal("11") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns a / b" do + @two.send(cmd, @one).should == @two + @one.send(cmd, @two).should == BigDecimal("0.5") + @eleven.send(cmd, @three).should be_close(@three + (@two / @three), TOLERANCE) + @one.send(cmd, @one_minus).should == @one_minus + @one_minus.send(cmd, @one_minus).should == @one + @frac_2.send(cmd, @frac_1).should == BigDecimal("0.9") + @frac_1.send(cmd, @frac_1).should == @one + (@one.send(cmd, BigDecimal('-2E5555'))).should == BigDecimal('-0.5E-5555') + (@one.send(cmd, BigDecimal('2E-5555'))).should == BigDecimal('0.5E5555') + end + + it "returns NaN if NaN is involved" do + @one.send(cmd, @nan).nan?.should == true + @nan.send(cmd ,@one).nan?.should == true + end + + it "returns 0 if divided by Infinity" do + @zero.send(cmd, @infinity).should == 0 + @frac_2.send(cmd, @infinity).should == 0 + end + + it "returns (+|-) Infinity if (+|-) Infinity divided by one" do + @infinity_minus.send(cmd, @one).should == @infinity_minus + @infinity.send(cmd, @one).should == @infinity + @infinity_minus.send(cmd, @one_minus).should == @infinity + end + + it "returns NaN if Infinity / ((+|-) Infinity)" do + @infinity.send(cmd, @infinity_minus).nan?.should == true + @infinity_minus.send(cmd, @infinity).nan?.should == true + end + + end + +end diff --git a/1.8/library/bigdecimal/shared/to_int.rb b/1.8/library/bigdecimal/shared/to_int.rb new file mode 100644 index 0000000000..f15af423cf --- /dev/null +++ b/1.8/library/bigdecimal/shared/to_int.rb @@ -0,0 +1,21 @@ +require 'bigdecimal' + +shared :bigdecimal_to_int do |cmd| + + describe "BigDecimal##{cmd}" do + + it "returns nil if BigDecimal is infinity or NaN" do + BigDecimal("Infinity").send(cmd).should == nil + BigDecimal("NaN").send(cmd).should == nil + end + + it "returns Integer or Bignum otherwise" do + BigDecimal("3E-20001").send(cmd).should == 0 + BigDecimal("2E4000").send(cmd).should == 2 * 10 ** 4000 + BigDecimal("2").send(cmd).should == 2 + BigDecimal("2E10").send(cmd).should == 20000000000 + BigDecimal("3.14159").send(cmd).should == 3 + end + end + +end diff --git a/1.8/library/bigdecimal/sign_spec.rb b/1.8/library/bigdecimal/sign_spec.rb new file mode 100644 index 0000000000..da304ee6f9 --- /dev/null +++ b/1.8/library/bigdecimal/sign_spec.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#sign" do + + it "BigDecimal defines several constants for signs" do + # are these really correct? + BigDecimal::SIGN_POSITIVE_INFINITE.should == 3 + BigDecimal::SIGN_NEGATIVE_INFINITE.should == -3 + BigDecimal::SIGN_POSITIVE_ZERO.should == 1 + BigDecimal::SIGN_NEGATIVE_ZERO.should == -1 + BigDecimal::SIGN_POSITIVE_FINITE.should == 2 + BigDecimal::SIGN_NEGATIVE_FINITE.should == -2 + end + + it "returns positive value if BigDecimal greater than 0" do + BigDecimal("1").sign.should == BigDecimal::SIGN_POSITIVE_FINITE + BigDecimal("1E-20000000").sign.should == BigDecimal::SIGN_POSITIVE_FINITE + BigDecimal("1E200000000").sign.should == BigDecimal::SIGN_POSITIVE_FINITE + BigDecimal("Infinity").sign.should == BigDecimal::SIGN_POSITIVE_INFINITE + end + + it "returns negative value if BigDecimal less than 0" do + BigDecimal("-1").sign.should == BigDecimal::SIGN_NEGATIVE_FINITE + BigDecimal("-1E-9990000").sign.should == BigDecimal::SIGN_NEGATIVE_FINITE + BigDecimal("-1E20000000").sign.should == BigDecimal::SIGN_NEGATIVE_FINITE + BigDecimal("-Infinity").sign.should == BigDecimal::SIGN_NEGATIVE_INFINITE + end + + it "returns positive zero if BigDecimal equals positve zero" do + BigDecimal("0").sign.should == BigDecimal::SIGN_POSITIVE_ZERO + BigDecimal("0E-200000000").sign.should == BigDecimal::SIGN_POSITIVE_ZERO + BigDecimal("0E200000000").sign.should == BigDecimal::SIGN_POSITIVE_ZERO + end + + it "returns negative zero if BigDecimal equals negative zero" do + BigDecimal("-0").sign.should == BigDecimal::SIGN_NEGATIVE_ZERO + BigDecimal("-0E-200000000").sign.should == BigDecimal::SIGN_NEGATIVE_ZERO + BigDecimal("-0E200000000").sign.should == BigDecimal::SIGN_NEGATIVE_ZERO + end + + it "returns BigDecimal::SIGN_NaN if BigDecimal is NaN" do + BigDecimal("NaN").sign.should == BigDecimal::SIGN_NaN + end + +end + diff --git a/1.8/library/bigdecimal/split_spec.rb b/1.8/library/bigdecimal/split_spec.rb new file mode 100644 index 0000000000..49d8eef944 --- /dev/null +++ b/1.8/library/bigdecimal/split_spec.rb @@ -0,0 +1,88 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#split" do + + before(:each) do + @arr = BigDecimal("0.314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593014782083152134043E1").split + @arr_neg = BigDecimal("-0.314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593014782083152134043E1").split + @digits = "922337203685477580810101333333333333333333333333333" + @arr_big = BigDecimal("00#{@digits}000").split + @arr_big_neg = BigDecimal("-00#{@digits}000").split + @huge = BigDecimal('100000000000000000000000000000000000000000001E90000000').split + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + @zero = BigDecimal("0") + @zero_neg = BigDecimal("-0") + end + + it "splits BigDecimal in an array with four values" do + @arr.size.should == 4 + end + + it "First value: 1 for numbers > 0" do + @arr[0].should == 1 + @arr_big[0].should == 1 + @zero.split[0].should == 1 + @huge[0].should == 1 + BigDecimal("+0").split[0].should == 1 + BigDecimal("1E400").split[0].should == 1 + @infinity.split[0].should == 1 + end + + it "First value: -1 for numbers < 0" do + @arr_neg[0].should == -1 + @arr_big_neg[0].should == -1 + @zero_neg.split[0].should == -1 + BigDecimal("-1E400").split[0].should == -1 + @infinity_neg.split[0].should == -1 + end + + it "First value: 0 if BigDecimal is NaN" do + BigDecimal("NaN").split[0].should == 0 + end + + it "Second value: a string with the significant digits" do + string = "314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593014782083152134043" + @arr[1].should == string + @arr_big[1].should == @digits + @arr_big_neg[1].should == @digits + @huge[1].should == "100000000000000000000000000000000000000000001" + @infinity.split[1].should == @infinity.to_s + @nan.split[1].should == @nan.to_s + @infinity_neg.split[1].should == @infinity.to_s + @zero.split[1].should == "0" + BigDecimal("-0").split[1].should == "0" + end + + it "Third value: the base (currently always ten)" do + @arr[2].should == 10 + @arr_neg[2].should == 10 + @arr_big[2].should == 10 + @arr_big_neg[2].should == 10 + @huge[2].should == 10 + @infinity.split[2].should == 10 + @nan.split[2].should == 10 + @infinity_neg.split[2].should == 10 + @zero.split[2].should == 10 + @zero_neg.split[2].should == 10 + end + + it "Fourth value: The exponent" do + @arr[3].should == 1 + @arr_neg[3].should == 1 + @arr_big[3].should == 54 + @arr_big_neg[3].should == 54 + @huge[3].should == 90000045 + @infinity.split[3].should == 0 + @nan.split[3].should == 0 + @infinity_neg.split[3].should == 0 + @zero.split[3].should == 0 + @zero_neg.split[3].should == 0 + end + +end + + diff --git a/1.8/library/bigdecimal/sqrt_spec.rb b/1.8/library/bigdecimal/sqrt_spec.rb new file mode 100644 index 0000000000..05112adbf0 --- /dev/null +++ b/1.8/library/bigdecimal/sqrt_spec.rb @@ -0,0 +1,75 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#sqrt" do + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @two = BigDecimal("2") + @three = BigDecimal("3") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns sqrt of self with at least the given precision" do + string = "1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157" + (1..100).each { |idx| + @two.sqrt(idx).to_s("F")[0, idx].should == string[0, idx] + } + sqrt_3 = "1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248575" + (1..100).each { |idx| + @three.sqrt(idx).to_s("F")[0, idx].should == sqrt_3[0, idx] + } + BigDecimal('121').sqrt(5).should be_close(11, 0.00001) + @frac_2.sqrt(1).to_s.should == "0.3E-49999" + end + + it "requires a single fixnum argument" do + lambda { + @one.sqrt + }.should raise_error(ArgumentError) + lambda { + @one.sqrt(-1) + }.should raise_error(ArgumentError) + lambda { + @one.sqrt(1, 1) + }.should raise_error(ArgumentError) + lambda { + @one.sqrt(nil) + }.should raise_error(TypeError) + lambda { + @one.sqrt("stuff") + }.should raise_error(TypeError) + lambda { + @one.sqrt(Object.new) + }.should raise_error(TypeError) + @one.sqrt(1).should == 1 + @one.sqrt(0).should == 1 + end + + it "raises FloatDomainError on negative values" do + lambda { + BigDecimal('-1').sqrt(10) + }.should raise_error(FloatDomainError) + end + + it "properly handles special values" do + @infinity.sqrt(1).should == @infinity + lambda { + @infinity_minus.sqrt(1) + }.should raise_error(FloatDomainError) + lambda { + @nan.sqrt(1) + }.should raise_error(FloatDomainError) + @zero.sqrt(1).should == 0 + @zero_pos.sqrt(1).should == 0 + @zero_neg.sqrt(1).should == 0 + end + +end diff --git a/1.8/library/bigdecimal/sub_spec.rb b/1.8/library/bigdecimal/sub_spec.rb new file mode 100644 index 0000000000..04d82916dd --- /dev/null +++ b/1.8/library/bigdecimal/sub_spec.rb @@ -0,0 +1,53 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#sub" do + + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @two = BigDecimal("2") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + end + + it "returns a - b with given precision" do + # documentation states, that precision is optional + # but implementation raises ArgumentError if not given. + + @two.sub(@one, 1).should == @one + @one.sub(@two, 1).should == @one_minus + @one.sub(@one_minus, 1).should == @two + @frac_2.sub(@frac_1, 1000000).should == BigDecimal("-0.1E-99999") + @frac_2.sub(@frac_1, 1).should == BigDecimal("-0.1E-99999") + # the above two examples puzzle me. + in_arow_one = BigDecimal("1.23456789") + in_arow_two = BigDecimal("1.2345678") + in_arow_one.sub(in_arow_two, 10).should == BigDecimal("0.9E-7") + @two.sub(@two,1).should == @zero + @frac_1.sub(@frac_1, 1000000).should == @zero + end + + it "returns NaN if NaN is involved" do + @one.sub(@nan, 1).nan?.should == true + @nan.sub(@one, 1).nan?.should == true + end + + it "returns NaN if both values are infinite with the same signs" do + @infinity.sub(@infinity, 1).nan?.should == true + @infinity_minus.sub(@infinity_minus, 1).nan?.should == true + end + + it "returns Infinity or -Infinity if these are involved" do + @infinity.sub(@infinity_minus, 1).should == @infinity + @infinity_minus.sub(@infinity, 1).should == @infinity_minus + @zero.sub(@infinity, 1).should == @infinity_minus + @frac_2.sub( @infinity, 1).should == @infinity_minus + @two.sub(@infinity, 1).should == @infinity_minus + end + +end diff --git a/1.8/library/bigdecimal/to_f_spec.rb b/1.8/library/bigdecimal/to_f_spec.rb new file mode 100644 index 0000000000..d73d17bd87 --- /dev/null +++ b/1.8/library/bigdecimal/to_f_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#to_f" do + + it "returns number of type float" do + BigDecimal("3.14159").to_f.class.should == Float + end + + it "Floating point rounding occurs" do + bigdec = BigDecimal("3.141592653589793238462643383279502884197169399375") + bigdec.to_f.should be_close(3.14159265358979, TOLERANCE) + end + +end + diff --git a/1.8/library/bigdecimal/to_i_spec.rb b/1.8/library/bigdecimal/to_i_spec.rb new file mode 100644 index 0000000000..fcd9acc9e0 --- /dev/null +++ b/1.8/library/bigdecimal/to_i_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_int' +require 'bigdecimal' + +describe "BigDecimal#to_i" do + it_behaves_like(:bigdecimal_to_int, :to_i) +end diff --git a/1.8/library/bigdecimal/to_int_spec.rb b/1.8/library/bigdecimal/to_int_spec.rb new file mode 100644 index 0000000000..c3c00897e8 --- /dev/null +++ b/1.8/library/bigdecimal/to_int_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/to_int' +require 'bigdecimal' + + +describe "BigDecimal#to_int" do + it_behaves_like(:bigdecimal_to_int, :to_int) +end diff --git a/1.8/library/bigdecimal/to_s_spec.rb b/1.8/library/bigdecimal/to_s_spec.rb new file mode 100644 index 0000000000..b1cf80a9c1 --- /dev/null +++ b/1.8/library/bigdecimal/to_s_spec.rb @@ -0,0 +1,60 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#to_s" do + + before(:each) do + @bigdec_str = "3.14159265358979323846264338327950288419716939937" + @bigneg_str = "-3.1415926535897932384626433832795028841971693993" + @bigdec = BigDecimal(@bigdec_str) + @bigneg = BigDecimal(@bigneg_str) + end + + it "return type is of class String" do + @bigdec.to_s.kind_of?(String).should == true + @bigneg.to_s.kind_of?(String).should == true + end + + it "the default format looks like 0.xxxxEnn" do + @bigdec.to_s.should =~ /^0\.[0-9]*E[0-9]*$/ + end + + it "takes an optional argument" do + lambda {@bigdec.to_s("F")}.should_not raise_error() + end + + it "starts with + if + is supplied and value is positive" do + @bigdec.to_s("+").should =~ /^\+.*/ + @bigneg.to_s("+").should_not =~ /^\+.*/ + end + + it "inserts a space every n chars, if integer n is supplied" do + str =\ + "0.314 159 265 358 979 323 846 264 338 327 950 288 419 716 939 937E1" + @bigdec.to_s(3).should == str + str1 = '-123.45678 90123 45678 9' + BigDecimal.new("-123.45678901234567890").to_s('5F').should == str1 + # trailing zeroes removed + BigDecimal.new("1.00000000000").to_s('1F').should == "1.0" + # 0 is treated as no spaces + BigDecimal.new("1.2345").to_s('0F').should == "1.2345" + end + + it "can return a leading space for values > 0" do + @bigdec.to_s(" F").should =~ /\ .*/ + @bigneg.to_s(" F").should_not =~ /\ .*/ + end + + it "can use engineering notation" do + @bigdec.to_s("E").should =~ /^0\.[0-9]*E[0-9]*$/ + end + + it "can use conventional floating point notation" do + @bigdec.to_s("F").should == @bigdec_str + @bigneg.to_s("F").should == @bigneg_str + str2 = "+123.45678901 23456789" + BigDecimal.new('123.45678901234567890').to_s('+8F').should == str2 + end + +end + diff --git a/1.8/library/bigdecimal/truncate_spec.rb b/1.8/library/bigdecimal/truncate_spec.rb new file mode 100644 index 0000000000..bb14d4646a --- /dev/null +++ b/1.8/library/bigdecimal/truncate_spec.rb @@ -0,0 +1,78 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#truncate" do + + before(:each) do + @arr = ['3.14159', '8.7', "0.314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593014782083152134043E1"] + @big = BigDecimal("123456.789") + @nan = BigDecimal('NaN') + @infinity = BigDecimal('Infinity') + @infinity_negative = BigDecimal('-Infinity') + end + + it "returns value of type Bigdecimal." do + @arr.each do |x| + BigDecimal(x).truncate.kind_of?(BigDecimal).should == true + end + end + + it "returns the integer part as a BigDecimal if no precision given" do + BigDecimal(@arr[0]).truncate.should == 3 + BigDecimal(@arr[1]).truncate.should == 8 + BigDecimal(@arr[2]).truncate.should == 3 + BigDecimal('0').truncate.should == 0 + BigDecimal('0.1').truncate.should == 0 + BigDecimal('-0.1').truncate.should == 0 + BigDecimal('1.5').truncate.should == 1 + BigDecimal('-1.5').truncate.should == -1 + BigDecimal('1E10').truncate.should == BigDecimal('1E10') + BigDecimal('-1E10').truncate.should == BigDecimal('-1E10') + BigDecimal('1.8888E10').truncate.should == BigDecimal('1.8888E10') + BigDecimal('-1E-1').truncate.should == 0 + end + + it "returns value of given precision otherwise" do + BigDecimal('-1.55').truncate(1).should == BigDecimal('-1.5') + BigDecimal('1.55').truncate(1).should == BigDecimal('1.5') + BigDecimal(@arr[0]).truncate(2).should == BigDecimal("3.14") + BigDecimal('123.456').truncate(2).should == BigDecimal("123.45") + BigDecimal('123.456789').truncate(4).should == BigDecimal("123.4567") + BigDecimal('0.456789').truncate(10).should == BigDecimal("0.456789") + BigDecimal('-1E-1').truncate(1).should == BigDecimal('-0.1') + BigDecimal('-1E-1').truncate(2).should == BigDecimal('-0.1E0') + BigDecimal('-1E-1').truncate.should == BigDecimal('0') + BigDecimal('-1E-1').truncate(0).should == BigDecimal('0') + BigDecimal('-1E-1').truncate(-1).should == BigDecimal('0') + BigDecimal('-1E-1').truncate(-2).should == BigDecimal('0') + + BigDecimal(@arr[1]).truncate(1).should == BigDecimal("8.7") + BigDecimal(@arr[2]).truncate(100).should == BigDecimal(\ + "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679") + end + + it "sets n digits left of the decimal point to 0, if given n < 0" do + @big.truncate(-1).should == BigDecimal("123450.0") + @big.truncate(-2).should == BigDecimal("123400.0") + BigDecimal(@arr[2]).truncate(-1).should == 0 + end + + it "returns NaN if self is NaN" do + @nan.truncate(-1).nan?.should == true + @nan.truncate(+1).nan?.should == true + @nan.truncate(0).nan?.should == true + @nan.truncate.nan?.should == true + end + + it "returns Infinity if self is infinite" do + @infinity.truncate(-1).should == @infinity + @infinity.truncate(+1).should == @infinity + @infinity.truncate(0).should == @infinity + @infinity.truncate.should == @infinity + + @infinity_negative.truncate(-1).should == @infinity_negative + @infinity_negative.truncate(+1).should == @infinity_negative + @infinity_negative.truncate(0).should == @infinity_negative + @infinity_negative.truncate.should == @infinity_negative + end +end diff --git a/1.8/library/bigdecimal/uminus_spec.rb b/1.8/library/bigdecimal/uminus_spec.rb new file mode 100644 index 0000000000..f0c29f937a --- /dev/null +++ b/1.8/library/bigdecimal/uminus_spec.rb @@ -0,0 +1,58 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#-@" do + before(:each) do + @one = BigDecimal("1") + @zero = BigDecimal("0") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + @nan = BigDecimal("NaN") + @infinity = BigDecimal("Infinity") + @infinity_minus = BigDecimal("-Infinity") + @one_minus = BigDecimal("-1") + @frac_1 = BigDecimal("1E-99999") + @frac_2 = BigDecimal("0.9E-99999") + @big = BigDecimal("333E99999") + @big_neg = BigDecimal("-333E99999") + @values = [@one, @zero, @zero_pos, @zero_neg, @infinity, + @infinity_minus, @one_minus, @frac_1, @frac_2, @big, @big_neg] + end + + it "negates self" do + @one.send(:-@).should == @one_minus + @one_minus.send(:-@).should == @one + @frac_1.send(:-@).should == BigDecimal("-1E-99999") + @frac_2.send(:-@).should == BigDecimal("-0.9E-99999") + @big.send(:-@).should == @big_neg + @big_neg.send(:-@).should == @big + BigDecimal("2.221").send(:-@).should == BigDecimal("-2.221") + BigDecimal("2E10000").send(:-@).should == BigDecimal("-2E10000") + some_number = BigDecimal("2455999221.5512") + some_number_neg = BigDecimal("-2455999221.5512") + some_number.send(:-@).should == some_number_neg + (-BigDecimal("-5.5")).should == BigDecimal("5.5") + another_number = BigDecimal("-8.551551551551551551") + another_number_pos = BigDecimal("8.551551551551551551") + another_number.send(:-@).should == another_number_pos + @values.each do |val| + (val.send(:-@).send(:-@)).should == val + end + end + + it "properly handles special values" do + @infinity.send(:-@).should == @infinity_minus + @infinity_minus.send(:-@).should == @infinity + @infinity.send(:-@).infinite?.should == -1 + @infinity_minus.send(:-@).infinite?.should == 1 + + @zero.send(:-@).should == @zero + @zero.send(:-@).sign.should == -1 + @zero_pos.send(:-@).should == @zero + @zero_pos.send(:-@).sign.should == -1 + @zero_neg.send(:-@).should == @zero + @zero_neg.send(:-@).sign.should == 1 + + @nan.send(:-@).nan?.should == true + end +end diff --git a/1.8/library/bigdecimal/uplus_spec.rb b/1.8/library/bigdecimal/uplus_spec.rb new file mode 100644 index 0000000000..f3fc1c8026 --- /dev/null +++ b/1.8/library/bigdecimal/uplus_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#+@" do + it "returns the same value with same sign (twos complement)" do + first = BigDecimal("34.56") + first.send(:+@).should == first + second = BigDecimal("-34.56") + second.send(:+@).should == second + third = BigDecimal("0.0") + third.send(:+@).should == third + fourth = BigDecimal("2E1000000") + fourth.send(:+@).should == fourth + fifth = BigDecimal("123456789E-1000000") + fifth.send(:+@).should == fifth + end +end + + + diff --git a/1.8/library/bigdecimal/ver_spec.rb b/1.8/library/bigdecimal/ver_spec.rb new file mode 100644 index 0000000000..22e501f376 --- /dev/null +++ b/1.8/library/bigdecimal/ver_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal.ver" do + + it "returns the Version number" do + lambda {BigDecimal.ver }.should_not raise_error() + BigDecimal.ver.should_not == nil + end + +end \ No newline at end of file diff --git a/1.8/library/bigdecimal/zero_spec.rb b/1.8/library/bigdecimal/zero_spec.rb new file mode 100644 index 0000000000..cce911a2f9 --- /dev/null +++ b/1.8/library/bigdecimal/zero_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'bigdecimal' + +describe "BigDecimal#zero?" do + + it "returns true if self does equal zero" do + really_small_zero = BigDecimal("0E-200000000") + really_big_zero = BigDecimal("0E200000000000") + really_small_zero.zero?.should == true + really_big_zero.zero?.should == true + BigDecimal("0.000000000000000000000000").zero?.should == true + BigDecimal("0").zero?.should == true + BigDecimal("0E0").zero?.should == true + BigDecimal("+0").zero?.should == true + BigDecimal("-0").zero?.should == true + end + + it "returns false otherwise" do + BigDecimal("0000000001").zero?.should == false + BigDecimal("2E40001").zero?.should == false + BigDecimal("3E-20001").zero?.should == false + BigDecimal("Infinity").zero?.should == false + BigDecimal("-Infinity").zero?.should == false + BigDecimal("NaN").zero?.should == false + end + +end + diff --git a/1.8/library/cgi/cookie/domain_spec.rb b/1.8/library/cgi/cookie/domain_spec.rb new file mode 100644 index 0000000000..8068719ec8 --- /dev/null +++ b/1.8/library/cgi/cookie/domain_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie#domain=" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/cookie/expires_spec.rb b/1.8/library/cgi/cookie/expires_spec.rb new file mode 100644 index 0000000000..b4481facf0 --- /dev/null +++ b/1.8/library/cgi/cookie/expires_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie#expires" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "CGI::Cookie#expires=" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/cookie/initialize_spec.rb b/1.8/library/cgi/cookie/initialize_spec.rb new file mode 100644 index 0000000000..355bbed660 --- /dev/null +++ b/1.8/library/cgi/cookie/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/cookie/name_spec.rb b/1.8/library/cgi/cookie/name_spec.rb new file mode 100644 index 0000000000..ae50f4e7ad --- /dev/null +++ b/1.8/library/cgi/cookie/name_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie#name" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "CGI::Cookie#name=" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/cookie/parse_spec.rb b/1.8/library/cgi/cookie/parse_spec.rb new file mode 100644 index 0000000000..3bad68489a --- /dev/null +++ b/1.8/library/cgi/cookie/parse_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie.parse" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/cookie/path_spec.rb b/1.8/library/cgi/cookie/path_spec.rb new file mode 100644 index 0000000000..a19a20d488 --- /dev/null +++ b/1.8/library/cgi/cookie/path_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie#path" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "CGI::Cookie#path=" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/cookie/secure_spec.rb b/1.8/library/cgi/cookie/secure_spec.rb new file mode 100644 index 0000000000..1fcf2122f6 --- /dev/null +++ b/1.8/library/cgi/cookie/secure_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie#secure=" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/cookie/to_s_spec.rb b/1.8/library/cgi/cookie/to_s_spec.rb new file mode 100644 index 0000000000..73400a05a5 --- /dev/null +++ b/1.8/library/cgi/cookie/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie#to_s" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/cookie/value_spec.rb b/1.8/library/cgi/cookie/value_spec.rb new file mode 100644 index 0000000000..df412938f9 --- /dev/null +++ b/1.8/library/cgi/cookie/value_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Cookie#value" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "CGI::Cookie#value=" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/env_table_spec.rb b/1.8/library/cgi/env_table_spec.rb new file mode 100644 index 0000000000..5aa9cff8da --- /dev/null +++ b/1.8/library/cgi/env_table_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI#env_table" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/escapeElement_spec.rb b/1.8/library/cgi/escapeElement_spec.rb new file mode 100644 index 0000000000..f9833d80c1 --- /dev/null +++ b/1.8/library/cgi/escapeElement_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.escapeElement" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/escapeHTML_spec.rb b/1.8/library/cgi/escapeHTML_spec.rb new file mode 100644 index 0000000000..653bc88ab1 --- /dev/null +++ b/1.8/library/cgi/escapeHTML_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.escapeHTML" do + + it "escape '& < > \"' to '& < > "" do + input = '& < > "' + expected = '& < > "' + CGI::escapeHTML(input).should == expected + end + + it "not escape characters except '& < > \"'" do + input = (0x20..0x7E).to_a.collect {|ch| ch.chr}.join('') + expected = input.gsub(/&/,'&').gsub(//,'>').gsub(/"/,'"') + CGI::escapeHTML(input).should == expected + end + + it "raise error when argument is not a string" do + lambda { CGI::escapeHTML(nil) }.should raise_error(Exception) # NoMethodError + lambda { CGI::escapeHTML(123) }.should raise_error(Exception) # NoMethodError + lambda { CGI::escapeHTML(true) }.should raise_error(Exception) # NoMethodError + end + +end diff --git a/1.8/library/cgi/escape_spec.rb b/1.8/library/cgi/escape_spec.rb new file mode 100644 index 0000000000..a59b000a08 --- /dev/null +++ b/1.8/library/cgi/escape_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.escape" do + + it "encode characters" do + #input = (0x20..0x7E).to_a.collect{|ch| ch.chr}.join + input = " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + expected = "+%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E" + CGI::escape(input).should == expected + end + + it "encode unicode string" do + input = "http://ja.wikipedia.org/wiki/\343\203\255\343\203\240\343\202\271\343\202\253\343\203\273\343\203\221\343\203\255\343\203\273\343\202\246\343\203\253\343\203\273\343\203\251\343\203\224\343\203\245\343\202\277" + expected = 'http%3A%2F%2Fja.wikipedia.org%2Fwiki%2F%E3%83%AD%E3%83%A0%E3%82%B9%E3%82%AB%E3%83%BB%E3%83%91%E3%83%AD%E3%83%BB%E3%82%A6%E3%83%AB%E3%83%BB%E3%83%A9%E3%83%94%E3%83%A5%E3%82%BF' + CGI::escape(input).should == expected + end + + it "raise exception when argument is not a string" do + lambda { CGI::escape(nil) }.should raise_error(Exception) # NoMethodError + lambda { CGI::escape(123) }.should raise_error(Exception) # NoMethodError + lambda { CGI::escape(true) }.should raise_error(Exception) # NoMethodError + end + +end diff --git a/1.8/library/cgi/header_spec.rb b/1.8/library/cgi/header_spec.rb new file mode 100644 index 0000000000..5c3d9a9aeb --- /dev/null +++ b/1.8/library/cgi/header_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI#header" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/html3/doctype_spec.rb b/1.8/library/cgi/html3/doctype_spec.rb new file mode 100644 index 0000000000..0e64a8e1c0 --- /dev/null +++ b/1.8/library/cgi/html3/doctype_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Html3#doctype" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/html3/element_init_spec.rb b/1.8/library/cgi/html3/element_init_spec.rb new file mode 100644 index 0000000000..46aec0c4e8 --- /dev/null +++ b/1.8/library/cgi/html3/element_init_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Html3#element_init" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/html4/doctype_spec.rb b/1.8/library/cgi/html4/doctype_spec.rb new file mode 100644 index 0000000000..7e87c8aa41 --- /dev/null +++ b/1.8/library/cgi/html4/doctype_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Html4#doctype" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/html4/element_init_spec.rb b/1.8/library/cgi/html4/element_init_spec.rb new file mode 100644 index 0000000000..32c97bb580 --- /dev/null +++ b/1.8/library/cgi/html4/element_init_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Html4#element_init" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/html4fr/doctype_spec.rb b/1.8/library/cgi/html4fr/doctype_spec.rb new file mode 100644 index 0000000000..5b17502218 --- /dev/null +++ b/1.8/library/cgi/html4fr/doctype_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Html4Fr#doctype" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/html4fr/element_init_spec.rb b/1.8/library/cgi/html4fr/element_init_spec.rb new file mode 100644 index 0000000000..742af17394 --- /dev/null +++ b/1.8/library/cgi/html4fr/element_init_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Html4Fr#element_init" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/html4tr/doctype_spec.rb b/1.8/library/cgi/html4tr/doctype_spec.rb new file mode 100644 index 0000000000..0b7c80ed5f --- /dev/null +++ b/1.8/library/cgi/html4tr/doctype_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Html4Tr#doctype" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/html4tr/element_init_spec.rb b/1.8/library/cgi/html4tr/element_init_spec.rb new file mode 100644 index 0000000000..d9720d24f2 --- /dev/null +++ b/1.8/library/cgi/html4tr/element_init_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::Html4Tr#element_init" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/a_spec.rb b/1.8/library/cgi/htmlextension/a_spec.rb new file mode 100644 index 0000000000..ec8e58a2eb --- /dev/null +++ b/1.8/library/cgi/htmlextension/a_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#a" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/base_spec.rb b/1.8/library/cgi/htmlextension/base_spec.rb new file mode 100644 index 0000000000..e4d8ea0644 --- /dev/null +++ b/1.8/library/cgi/htmlextension/base_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#base" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/blockquote_spec.rb b/1.8/library/cgi/htmlextension/blockquote_spec.rb new file mode 100644 index 0000000000..c351914f1e --- /dev/null +++ b/1.8/library/cgi/htmlextension/blockquote_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#blockquote" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/caption_spec.rb b/1.8/library/cgi/htmlextension/caption_spec.rb new file mode 100644 index 0000000000..211e3abf8b --- /dev/null +++ b/1.8/library/cgi/htmlextension/caption_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#caption" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/checkbox_group_spec.rb b/1.8/library/cgi/htmlextension/checkbox_group_spec.rb new file mode 100644 index 0000000000..55ef3eef71 --- /dev/null +++ b/1.8/library/cgi/htmlextension/checkbox_group_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#checkbox_group" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/checkbox_spec.rb b/1.8/library/cgi/htmlextension/checkbox_spec.rb new file mode 100644 index 0000000000..10e3689590 --- /dev/null +++ b/1.8/library/cgi/htmlextension/checkbox_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#checkbox" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/file_field_spec.rb b/1.8/library/cgi/htmlextension/file_field_spec.rb new file mode 100644 index 0000000000..7c3ad7ff32 --- /dev/null +++ b/1.8/library/cgi/htmlextension/file_field_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#file_field" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/form_spec.rb b/1.8/library/cgi/htmlextension/form_spec.rb new file mode 100644 index 0000000000..b33dba87ca --- /dev/null +++ b/1.8/library/cgi/htmlextension/form_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#form" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/hidden_spec.rb b/1.8/library/cgi/htmlextension/hidden_spec.rb new file mode 100644 index 0000000000..8fd727a6a9 --- /dev/null +++ b/1.8/library/cgi/htmlextension/hidden_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#hidden" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/html_spec.rb b/1.8/library/cgi/htmlextension/html_spec.rb new file mode 100644 index 0000000000..a98dde7252 --- /dev/null +++ b/1.8/library/cgi/htmlextension/html_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#html" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/image_button_spec.rb b/1.8/library/cgi/htmlextension/image_button_spec.rb new file mode 100644 index 0000000000..3f263a96c6 --- /dev/null +++ b/1.8/library/cgi/htmlextension/image_button_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#image_button" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/img_spec.rb b/1.8/library/cgi/htmlextension/img_spec.rb new file mode 100644 index 0000000000..d9ed1f4cd6 --- /dev/null +++ b/1.8/library/cgi/htmlextension/img_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#img" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/multipart_form_spec.rb b/1.8/library/cgi/htmlextension/multipart_form_spec.rb new file mode 100644 index 0000000000..c1ea9dbfdb --- /dev/null +++ b/1.8/library/cgi/htmlextension/multipart_form_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#multipart_form" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/password_field_spec.rb b/1.8/library/cgi/htmlextension/password_field_spec.rb new file mode 100644 index 0000000000..c138e77f98 --- /dev/null +++ b/1.8/library/cgi/htmlextension/password_field_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#password_field" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/popup_menu_spec.rb b/1.8/library/cgi/htmlextension/popup_menu_spec.rb new file mode 100644 index 0000000000..aaeacdc501 --- /dev/null +++ b/1.8/library/cgi/htmlextension/popup_menu_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#popup_menu" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/radio_button_spec.rb b/1.8/library/cgi/htmlextension/radio_button_spec.rb new file mode 100644 index 0000000000..b9a5b410d3 --- /dev/null +++ b/1.8/library/cgi/htmlextension/radio_button_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#radio_button" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/radio_group_spec.rb b/1.8/library/cgi/htmlextension/radio_group_spec.rb new file mode 100644 index 0000000000..bad03ba11e --- /dev/null +++ b/1.8/library/cgi/htmlextension/radio_group_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#radio_group" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/reset_spec.rb b/1.8/library/cgi/htmlextension/reset_spec.rb new file mode 100644 index 0000000000..9ee51b9b3c --- /dev/null +++ b/1.8/library/cgi/htmlextension/reset_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#reset" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/scrolling_list_spec.rb b/1.8/library/cgi/htmlextension/scrolling_list_spec.rb new file mode 100644 index 0000000000..0c886cf021 --- /dev/null +++ b/1.8/library/cgi/htmlextension/scrolling_list_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#scrolling_list" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/submit_spec.rb b/1.8/library/cgi/htmlextension/submit_spec.rb new file mode 100644 index 0000000000..dcc60872ad --- /dev/null +++ b/1.8/library/cgi/htmlextension/submit_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#submit" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/text_field_spec.rb b/1.8/library/cgi/htmlextension/text_field_spec.rb new file mode 100644 index 0000000000..987b7dfcdf --- /dev/null +++ b/1.8/library/cgi/htmlextension/text_field_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#text_field" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/htmlextension/textarea_spec.rb b/1.8/library/cgi/htmlextension/textarea_spec.rb new file mode 100644 index 0000000000..e7acc9c78a --- /dev/null +++ b/1.8/library/cgi/htmlextension/textarea_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::HtmlExtension#textarea" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/initialize_spec.rb b/1.8/library/cgi/initialize_spec.rb new file mode 100644 index 0000000000..fcc4469aa2 --- /dev/null +++ b/1.8/library/cgi/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/out_spec.rb b/1.8/library/cgi/out_spec.rb new file mode 100644 index 0000000000..3aa44adc05 --- /dev/null +++ b/1.8/library/cgi/out_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI#out" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/parse_spec.rb b/1.8/library/cgi/parse_spec.rb new file mode 100644 index 0000000000..e2c535468f --- /dev/null +++ b/1.8/library/cgi/parse_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.parse" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/pretty_spec.rb b/1.8/library/cgi/pretty_spec.rb new file mode 100644 index 0000000000..e3c55a6fde --- /dev/null +++ b/1.8/library/cgi/pretty_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.pretty" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/print_spec.rb b/1.8/library/cgi/print_spec.rb new file mode 100644 index 0000000000..e8f8313661 --- /dev/null +++ b/1.8/library/cgi/print_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI#print" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/accept_charset_spec.rb b/1.8/library/cgi/queryextension/accept_charset_spec.rb new file mode 100644 index 0000000000..99efd8a5d6 --- /dev/null +++ b/1.8/library/cgi/queryextension/accept_charset_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#accept_charset" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/accept_encoding_spec.rb b/1.8/library/cgi/queryextension/accept_encoding_spec.rb new file mode 100644 index 0000000000..d6f5f553e9 --- /dev/null +++ b/1.8/library/cgi/queryextension/accept_encoding_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#accept_encoding" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/accept_language_spec.rb b/1.8/library/cgi/queryextension/accept_language_spec.rb new file mode 100644 index 0000000000..e4c172cc50 --- /dev/null +++ b/1.8/library/cgi/queryextension/accept_language_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#accept_language" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/accept_spec.rb b/1.8/library/cgi/queryextension/accept_spec.rb new file mode 100644 index 0000000000..2f6499a01d --- /dev/null +++ b/1.8/library/cgi/queryextension/accept_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#accept" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/auth_type_spec.rb b/1.8/library/cgi/queryextension/auth_type_spec.rb new file mode 100644 index 0000000000..c847c62568 --- /dev/null +++ b/1.8/library/cgi/queryextension/auth_type_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#auth_type" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/cache_control_spec.rb b/1.8/library/cgi/queryextension/cache_control_spec.rb new file mode 100644 index 0000000000..128ce8d716 --- /dev/null +++ b/1.8/library/cgi/queryextension/cache_control_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#cache_control" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/content_length_spec.rb b/1.8/library/cgi/queryextension/content_length_spec.rb new file mode 100644 index 0000000000..b21925435e --- /dev/null +++ b/1.8/library/cgi/queryextension/content_length_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#content_length" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/content_type_spec.rb b/1.8/library/cgi/queryextension/content_type_spec.rb new file mode 100644 index 0000000000..c5d54543ea --- /dev/null +++ b/1.8/library/cgi/queryextension/content_type_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#content_type" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/cookies_spec.rb b/1.8/library/cgi/queryextension/cookies_spec.rb new file mode 100644 index 0000000000..7828784dcf --- /dev/null +++ b/1.8/library/cgi/queryextension/cookies_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#cookies" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "CGI::QueryExtension#cookies=" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/element_reference_spec.rb b/1.8/library/cgi/queryextension/element_reference_spec.rb new file mode 100644 index 0000000000..1f5b2d76ea --- /dev/null +++ b/1.8/library/cgi/queryextension/element_reference_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#[]" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/from_spec.rb b/1.8/library/cgi/queryextension/from_spec.rb new file mode 100644 index 0000000000..1c2486b330 --- /dev/null +++ b/1.8/library/cgi/queryextension/from_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#from" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/gateway_interface_spec.rb b/1.8/library/cgi/queryextension/gateway_interface_spec.rb new file mode 100644 index 0000000000..fe3343cdae --- /dev/null +++ b/1.8/library/cgi/queryextension/gateway_interface_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#gateway_interface" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/has_key_spec.rb b/1.8/library/cgi/queryextension/has_key_spec.rb new file mode 100644 index 0000000000..5397280c91 --- /dev/null +++ b/1.8/library/cgi/queryextension/has_key_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#has_key?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/host_spec.rb b/1.8/library/cgi/queryextension/host_spec.rb new file mode 100644 index 0000000000..6f1eb6f705 --- /dev/null +++ b/1.8/library/cgi/queryextension/host_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#host" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/include_spec.rb b/1.8/library/cgi/queryextension/include_spec.rb new file mode 100644 index 0000000000..bd22255e4a --- /dev/null +++ b/1.8/library/cgi/queryextension/include_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#include?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/initialize_query_spec.rb b/1.8/library/cgi/queryextension/initialize_query_spec.rb new file mode 100644 index 0000000000..3568455e4e --- /dev/null +++ b/1.8/library/cgi/queryextension/initialize_query_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#initialize_query" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/key_spec.rb b/1.8/library/cgi/queryextension/key_spec.rb new file mode 100644 index 0000000000..cbebd5e460 --- /dev/null +++ b/1.8/library/cgi/queryextension/key_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#key?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/keys_spec.rb b/1.8/library/cgi/queryextension/keys_spec.rb new file mode 100644 index 0000000000..2273b73088 --- /dev/null +++ b/1.8/library/cgi/queryextension/keys_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#keys" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/multipart_spec.rb b/1.8/library/cgi/queryextension/multipart_spec.rb new file mode 100644 index 0000000000..500397553a --- /dev/null +++ b/1.8/library/cgi/queryextension/multipart_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#multipart?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/negotiate_spec.rb b/1.8/library/cgi/queryextension/negotiate_spec.rb new file mode 100644 index 0000000000..4c10cfa81a --- /dev/null +++ b/1.8/library/cgi/queryextension/negotiate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#negotiate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/params_spec.rb b/1.8/library/cgi/queryextension/params_spec.rb new file mode 100644 index 0000000000..ad2ad35b20 --- /dev/null +++ b/1.8/library/cgi/queryextension/params_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#params" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "CGI::QueryExtension#params=" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/path_info_spec.rb b/1.8/library/cgi/queryextension/path_info_spec.rb new file mode 100644 index 0000000000..25490ab6e4 --- /dev/null +++ b/1.8/library/cgi/queryextension/path_info_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#path_info" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/path_translated_spec.rb b/1.8/library/cgi/queryextension/path_translated_spec.rb new file mode 100644 index 0000000000..39cc77fc4c --- /dev/null +++ b/1.8/library/cgi/queryextension/path_translated_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#path_translated" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/pragma_spec.rb b/1.8/library/cgi/queryextension/pragma_spec.rb new file mode 100644 index 0000000000..ad6a2201e3 --- /dev/null +++ b/1.8/library/cgi/queryextension/pragma_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#pragma" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/query_string_spec.rb b/1.8/library/cgi/queryextension/query_string_spec.rb new file mode 100644 index 0000000000..9955f1ae9e --- /dev/null +++ b/1.8/library/cgi/queryextension/query_string_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#query_string" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/raw_cookie2_spec.rb b/1.8/library/cgi/queryextension/raw_cookie2_spec.rb new file mode 100644 index 0000000000..026f1c64b3 --- /dev/null +++ b/1.8/library/cgi/queryextension/raw_cookie2_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#raw_cookie2" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/raw_cookie_spec.rb b/1.8/library/cgi/queryextension/raw_cookie_spec.rb new file mode 100644 index 0000000000..6d4d28f789 --- /dev/null +++ b/1.8/library/cgi/queryextension/raw_cookie_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#raw_cookie" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/read_from_cmdline_spec.rb b/1.8/library/cgi/queryextension/read_from_cmdline_spec.rb new file mode 100644 index 0000000000..aedfb4360a --- /dev/null +++ b/1.8/library/cgi/queryextension/read_from_cmdline_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#read_from_cmdline" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/read_multipart_spec.rb b/1.8/library/cgi/queryextension/read_multipart_spec.rb new file mode 100644 index 0000000000..0e9c659bd0 --- /dev/null +++ b/1.8/library/cgi/queryextension/read_multipart_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#read_multipart" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/referer_spec.rb b/1.8/library/cgi/queryextension/referer_spec.rb new file mode 100644 index 0000000000..b02ce27ac4 --- /dev/null +++ b/1.8/library/cgi/queryextension/referer_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#referer" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/remote_addr_spec.rb b/1.8/library/cgi/queryextension/remote_addr_spec.rb new file mode 100644 index 0000000000..7a85bdab99 --- /dev/null +++ b/1.8/library/cgi/queryextension/remote_addr_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#remote_addr" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/remote_host_spec.rb b/1.8/library/cgi/queryextension/remote_host_spec.rb new file mode 100644 index 0000000000..b5850d7bae --- /dev/null +++ b/1.8/library/cgi/queryextension/remote_host_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#remote_host" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/remote_ident_spec.rb b/1.8/library/cgi/queryextension/remote_ident_spec.rb new file mode 100644 index 0000000000..69ace79426 --- /dev/null +++ b/1.8/library/cgi/queryextension/remote_ident_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#remote_ident" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/remote_user_spec.rb b/1.8/library/cgi/queryextension/remote_user_spec.rb new file mode 100644 index 0000000000..dcd2f97b7b --- /dev/null +++ b/1.8/library/cgi/queryextension/remote_user_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#remote_user" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/request_method_spec.rb b/1.8/library/cgi/queryextension/request_method_spec.rb new file mode 100644 index 0000000000..ad41dce89c --- /dev/null +++ b/1.8/library/cgi/queryextension/request_method_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#request_method" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/script_name_spec.rb b/1.8/library/cgi/queryextension/script_name_spec.rb new file mode 100644 index 0000000000..0c2d53fb45 --- /dev/null +++ b/1.8/library/cgi/queryextension/script_name_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#script_name" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/server_name_spec.rb b/1.8/library/cgi/queryextension/server_name_spec.rb new file mode 100644 index 0000000000..d8b14a31c2 --- /dev/null +++ b/1.8/library/cgi/queryextension/server_name_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#server_name" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/server_port_spec.rb b/1.8/library/cgi/queryextension/server_port_spec.rb new file mode 100644 index 0000000000..77f1d3f484 --- /dev/null +++ b/1.8/library/cgi/queryextension/server_port_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#server_port" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/server_protocol_spec.rb b/1.8/library/cgi/queryextension/server_protocol_spec.rb new file mode 100644 index 0000000000..204732cab3 --- /dev/null +++ b/1.8/library/cgi/queryextension/server_protocol_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#server_protocol" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/server_software_spec.rb b/1.8/library/cgi/queryextension/server_software_spec.rb new file mode 100644 index 0000000000..2b2768213c --- /dev/null +++ b/1.8/library/cgi/queryextension/server_software_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#server_software" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/user_agent_spec.rb b/1.8/library/cgi/queryextension/user_agent_spec.rb new file mode 100644 index 0000000000..708ed5fc40 --- /dev/null +++ b/1.8/library/cgi/queryextension/user_agent_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension#user_agent" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/value/element_reference_spec.rb b/1.8/library/cgi/queryextension/value/element_reference_spec.rb new file mode 100644 index 0000000000..950eeb1d9d --- /dev/null +++ b/1.8/library/cgi/queryextension/value/element_reference_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension::Value#[]" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/value/first_spec.rb b/1.8/library/cgi/queryextension/value/first_spec.rb new file mode 100644 index 0000000000..45f81283f9 --- /dev/null +++ b/1.8/library/cgi/queryextension/value/first_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension::Value#first" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/value/last_spec.rb b/1.8/library/cgi/queryextension/value/last_spec.rb new file mode 100644 index 0000000000..6c5fdd9bfa --- /dev/null +++ b/1.8/library/cgi/queryextension/value/last_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension::Value#last" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/value/set_params_spec.rb b/1.8/library/cgi/queryextension/value/set_params_spec.rb new file mode 100644 index 0000000000..e733b92426 --- /dev/null +++ b/1.8/library/cgi/queryextension/value/set_params_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension::Value#set_params" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/value/to_a_spec.rb b/1.8/library/cgi/queryextension/value/to_a_spec.rb new file mode 100644 index 0000000000..b34c87b32f --- /dev/null +++ b/1.8/library/cgi/queryextension/value/to_a_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension::Value#to_a" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/queryextension/value/to_ary_spec.rb b/1.8/library/cgi/queryextension/value/to_ary_spec.rb new file mode 100644 index 0000000000..9677fed73d --- /dev/null +++ b/1.8/library/cgi/queryextension/value/to_ary_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../../spec_helper' +require 'cgi' + +describe "CGI::QueryExtension::Value#to_ary" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/rfc1123_date_spec.rb b/1.8/library/cgi/rfc1123_date_spec.rb new file mode 100644 index 0000000000..fa1b7d9f36 --- /dev/null +++ b/1.8/library/cgi/rfc1123_date_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.rfc1123_date" do + + it "convert Time object into RFC1123 format such as 'Sat, 01 Dec 2007 15:56:42 GMT'" do + sec = 1196524602 + input = Time.at(sec) + expected = 'Sat, 01 Dec 2007 15:56:42 GMT' + CGI.rfc1123_date(input).should == expected + end + + it "raise error when argument is not Time object" do + str = 'Sat, 01 Dec 2007 15:56:42 GMT' + lambda { CGI.rfc1123_date(str) }.should raise_error(Exception) # NoMethodError + end + +end diff --git a/1.8/library/cgi/stdinput_spec.rb b/1.8/library/cgi/stdinput_spec.rb new file mode 100644 index 0000000000..75c638db01 --- /dev/null +++ b/1.8/library/cgi/stdinput_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI#stdinput" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/stdoutput_spec.rb b/1.8/library/cgi/stdoutput_spec.rb new file mode 100644 index 0000000000..70209350c6 --- /dev/null +++ b/1.8/library/cgi/stdoutput_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI#stdoutput" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/tagmaker/nOE_element_def_spec.rb b/1.8/library/cgi/tagmaker/nOE_element_def_spec.rb new file mode 100644 index 0000000000..24ef3aa054 --- /dev/null +++ b/1.8/library/cgi/tagmaker/nOE_element_def_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::TagMaker#nOE_element_def" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/tagmaker/nO_element_def_spec.rb b/1.8/library/cgi/tagmaker/nO_element_def_spec.rb new file mode 100644 index 0000000000..0849f8c170 --- /dev/null +++ b/1.8/library/cgi/tagmaker/nO_element_def_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::TagMaker#nO_element_def" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/tagmaker/nn_element_def_spec.rb b/1.8/library/cgi/tagmaker/nn_element_def_spec.rb new file mode 100644 index 0000000000..0576942b97 --- /dev/null +++ b/1.8/library/cgi/tagmaker/nn_element_def_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'cgi' + +describe "CGI::TagMaker#nn_element_def" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/unescapeElement_spec.rb b/1.8/library/cgi/unescapeElement_spec.rb new file mode 100644 index 0000000000..cf3e0a5a54 --- /dev/null +++ b/1.8/library/cgi/unescapeElement_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.unescapeElement" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/cgi/unescapeHTML_spec.rb b/1.8/library/cgi/unescapeHTML_spec.rb new file mode 100644 index 0000000000..8a07a54612 --- /dev/null +++ b/1.8/library/cgi/unescapeHTML_spec.rb @@ -0,0 +1,42 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.unescapeHTML" do + + it "unescape '& < > "' to '& < > \"'" do + input = '& < > "' + expected = '& < > "' + CGI::unescapeHTML(input).should == expected + end + + it "doesn't unescape other html entities such as '©' or '&heart'" do + input = '©&heart;' + expected = input + CGI::unescapeHTML(input).should == expected + end + + it "unescape 'c' format entities" do + input = '"&'<>' + expected = '"&\'<>' + CGI::unescapeHTML(input).should == expected + end + + it "unescape '香' format entities" do + input = '"&'<>' + expected = '"&\'<>' + CGI::unescapeHTML(input).should == expected + end + + it "leave invalid format string" do + input = '&<&>"&abcdefghijklmn' + expected = '&<&>"&abcdefghijklmn' + CGI::unescapeHTML(input).should == expected + end + + it "raise error when non-string is passed" do + lambda { CGI::unescapeHTML(nil) }.should raise_error(Exception) + lambda { CGI::unescapeHTML(123) }.should raise_error(Exception) + lambda { CGI::unescapeHTML(true) }.should raise_error(Exception) + end + +end diff --git a/1.8/library/cgi/unescape_spec.rb b/1.8/library/cgi/unescape_spec.rb new file mode 100644 index 0000000000..359001efb8 --- /dev/null +++ b/1.8/library/cgi/unescape_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'cgi' + +describe "CGI.unescape" do + + it "decode '%' format string" do + input = '%a4%Aa' + expected = "\244\252" + CGI::unescape(input).should == expected + end + + it "leave invalid format string as is" do + input = "%XX%5%%%" + expected = input + CGI::unescape(input).should == expected + end + + it "raise error when non-string is passed" do + lambda { CGI::unescape(nil) }.should raise_error(Exception) # NoMethodError + lambda { CGI::unescape(123) }.should raise_error(Exception) # NoMethodError + lambda { CGI::unescape(true) }.should raise_error(Exception) # NoMethodError + end + +end diff --git a/1.8/library/complex/abs2_spec.rb b/1.8/library/complex/abs2_spec.rb new file mode 100644 index 0000000000..7fbb9a4f63 --- /dev/null +++ b/1.8/library/complex/abs2_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#abs2" do + it "needs to be reviewed for spec completeness" do + end + + it "returns the sum of the squares of the real and imaginary parts" do + Complex(1, -2).abs2.should == 1 + 4 + Complex(-0.1, 0.2).abs2.should be_close(0.01 + 0.04, TOLERANCE) + Complex(0, 0).abs2.should == 0 + end +end diff --git a/1.8/library/complex/abs_spec.rb b/1.8/library/complex/abs_spec.rb new file mode 100644 index 0000000000..81ae7d7d9f --- /dev/null +++ b/1.8/library/complex/abs_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#abs" do + it "needs to be reviewed for spec completeness" do + end + + it "returns the modulus: |a + bi| = Ã((a ^ 2) + (b ^ 2))" do + Complex(0, 0).abs.should == 0 + Complex(3, 4).abs.should == 5 # well-known integer case + Complex(-3, 4).abs.should == 5 + Complex(1, -1).abs.should be_close(Math.sqrt(2), TOLERANCE) + Complex(6.5, 0).abs.should be_close(6.5, TOLERANCE) + Complex(0, -7.2).abs.should be_close(7.2, TOLERANCE) + end +end diff --git a/1.8/library/complex/angle_spec.rb b/1.8/library/complex/angle_spec.rb new file mode 100644 index 0000000000..e1ff67370a --- /dev/null +++ b/1.8/library/complex/angle_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/arg.rb' + +describe "Complex#angle" do + it_behaves_like(:complex_arg, :angle) +end diff --git a/1.8/library/complex/arg_spec.rb b/1.8/library/complex/arg_spec.rb new file mode 100644 index 0000000000..8b0d90edf5 --- /dev/null +++ b/1.8/library/complex/arg_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/arg.rb' + +describe "Complex#arg" do + it_behaves_like(:complex_arg, :arg) +end diff --git a/1.8/library/complex/coerce_spec.rb b/1.8/library/complex/coerce_spec.rb new file mode 100644 index 0000000000..48e95d63fa --- /dev/null +++ b/1.8/library/complex/coerce_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#coerce" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/comparison_spec.rb b/1.8/library/complex/comparison_spec.rb new file mode 100644 index 0000000000..30c77354d6 --- /dev/null +++ b/1.8/library/complex/comparison_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#<=>" do + it "needs to be reviewed for spec completeness" do + end + + it "compares the absolute values of the two arguments" do + (Complex(1, 2) <=> Complex(2, 1)).should == 0 + (Complex(-3, -10) <=> Complex(2, 1)).should > 0 + (Complex(3, 5) <=> Complex(100.0, -190.5)).should < 0 + end +end diff --git a/1.8/library/complex/conj_spec.rb b/1.8/library/complex/conj_spec.rb new file mode 100644 index 0000000000..12737ab2aa --- /dev/null +++ b/1.8/library/complex/conj_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/conjugate.rb' + +describe "Complex#conj" do + it_behaves_like(:complex_conjugate, :conj) +end diff --git a/1.8/library/complex/conjugate_spec.rb b/1.8/library/complex/conjugate_spec.rb new file mode 100644 index 0000000000..461198383e --- /dev/null +++ b/1.8/library/complex/conjugate_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/conjugate.rb' + +describe "Complex#conjugate" do + it_behaves_like(:complex_conjugate, :conjugate) +end diff --git a/1.8/library/complex/denominator_spec.rb b/1.8/library/complex/denominator_spec.rb new file mode 100644 index 0000000000..71edbf7955 --- /dev/null +++ b/1.8/library/complex/denominator_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#denominator" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/divide_spec.rb b/1.8/library/complex/divide_spec.rb new file mode 100644 index 0000000000..1da7040bc9 --- /dev/null +++ b/1.8/library/complex/divide_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#/ with [Complex]" do + it "needs to be reviewed for spec completeness" do + end + + it "divides according to the usual rule for complex numbers" do + a = 1 + b = 2 + c = 10 + d = 20 + (Complex((a * c) - (b * d), (a * d) + (b * c)) / Complex(a, b)).should == Complex(c, d) + + e = 1.5 + f = 2.1 + g = 100.2 + h = -30.3 + (Complex((e * g) - (f * h), (e * h) + (f * g)) / Complex(e, f)).should be_close(Complex(g, h), TOLERANCE) # remember the floating-point arithmetic + end +end + +describe "Complex#/ with [real]" do + it "needs to be reviewed for spec completeness" do + end + + it "divides both parts of the complex number by the real number" do + (Complex(20, 40) / 2).should == Complex(10, 20) + (Complex(15, 16) / 2.0).should be_close(Complex(7.5, 8), TOLERANCE) + end +end \ No newline at end of file diff --git a/1.8/library/complex/equal_value_spec.rb b/1.8/library/complex/equal_value_spec.rb new file mode 100644 index 0000000000..6f04c2f4bd --- /dev/null +++ b/1.8/library/complex/equal_value_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#==" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/exponent_spec.rb b/1.8/library/complex/exponent_spec.rb new file mode 100644 index 0000000000..a08823f34c --- /dev/null +++ b/1.8/library/complex/exponent_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#**" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/generic_spec.rb b/1.8/library/complex/generic_spec.rb new file mode 100644 index 0000000000..852c42d567 --- /dev/null +++ b/1.8/library/complex/generic_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex.generic?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/hash_spec.rb b/1.8/library/complex/hash_spec.rb new file mode 100644 index 0000000000..5632ee851e --- /dev/null +++ b/1.8/library/complex/hash_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#hash" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/imag_spec.rb b/1.8/library/complex/imag_spec.rb new file mode 100644 index 0000000000..dbbdb5a879 --- /dev/null +++ b/1.8/library/complex/imag_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#imag" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/image_spec.rb b/1.8/library/complex/image_spec.rb new file mode 100644 index 0000000000..d409af4fbb --- /dev/null +++ b/1.8/library/complex/image_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#image" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/initialize_spec.rb b/1.8/library/complex/initialize_spec.rb new file mode 100644 index 0000000000..e1db155eca --- /dev/null +++ b/1.8/library/complex/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/inspect_spec.rb b/1.8/library/complex/inspect_spec.rb new file mode 100644 index 0000000000..8b0163e1f6 --- /dev/null +++ b/1.8/library/complex/inspect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#inspect" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/minus_spec.rb b/1.8/library/complex/minus_spec.rb new file mode 100644 index 0000000000..4aadfb88f0 --- /dev/null +++ b/1.8/library/complex/minus_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#- with [Complex]" do + it "needs to be reviewed for spec completeness" do + end + + it "subtracts both the real and imaginary components" do + a = 1 + b = 2 + c = 10 + d = 20 + (Complex(a, b) - Complex(c, d)).should == Complex(a - c, b - d) + + e = 1.5 + f = 2.1 + g = 100.2 + h = -30.3 + (Complex(e, f) - Complex(g, h)).should == Complex(e - g, f - h) + end +end + +describe "Complex#- with [real]" do + it "needs to be reviewed for spec completeness" do + end + + it "subtracts the real number from the real part of the complex number" do + (Complex(1, 2) - 50).should == Complex(-49, 2) + (Complex(1, 2) - 50.5).should == Complex(-49.5, 2) + end +end \ No newline at end of file diff --git a/1.8/library/complex/modulo_spec.rb b/1.8/library/complex/modulo_spec.rb new file mode 100644 index 0000000000..74d06b7633 --- /dev/null +++ b/1.8/library/complex/modulo_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#% with [Complex]" do + it "needs to be reviewed for spec completeness" do + end + +quarantine! do # second part of the test fails on MRI, RBX, JRuby!!! + it "returns the remainder from complex division" do + # Is this spec even correct? It doesn't work on MRI or rbx, at least not for the floating-point case. + a = 1 + b = 2 + c = 10 + d = 20 + e = 3 + f = 4 + x = (Complex(a, b) * Complex(c, d)) + Complex(e, f) + (x % Complex(c, d)).should == Complex(e, f) + + a = 1.5 + b = 2.1 + c = 100.2 + d = -30.3 + e = 0.3 + f = 0.2 + x = (Complex(a, b) * Complex(c, d)) + Complex(e, f) + (x % Complex(c, d)).should be_close(Complex(e, f), TOLERANCE) + end +end + +end + +describe "Complex#% with [real]" do + it "needs to be reviewed for spec completeness" do + end + + it "returns the remainder from dividing both parts of the complex number by the real number" do + (Complex(21, 42) % 10).should == Complex(1, 2) + (Complex(15.5, 16.5) % 2.0).should be_close(Complex(1.5, 0.5), TOLERANCE) + end +end \ No newline at end of file diff --git a/1.8/library/complex/multiply_spec.rb b/1.8/library/complex/multiply_spec.rb new file mode 100644 index 0000000000..246c9c4aa9 --- /dev/null +++ b/1.8/library/complex/multiply_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#* with [Complex]" do + it "needs to be reviewed for spec completeness" do + end + + it "multiplies according to the usual rule for complex numbers: (a + bi) * (c + di) = ac - bd + (ad + bc)i" do + a = 1 + b = 2 + c = 10 + d = 20 + (Complex(a, b) * Complex(c, d)).should == Complex((a * c) - (b * d), (a * d) + (b * c)) + + e = 1.5 + f = 2.1 + g = 100.2 + h = -30.3 + (Complex(e, f) * Complex(g, h)).should == Complex((e * g) - (f * h), (e * h) + (f * g)) + end +end + +describe "Complex#* with [real]" do + it "needs to be reviewed for spec completeness" do + end + + it "multiplies both parts of the complex number by the real number" do + (Complex(3, 2) * 50).should == Complex(150, 100) + (Complex(-3, 2) * 50.5).should == Complex(-151.5, 101) + end +end \ No newline at end of file diff --git a/1.8/library/complex/new_spec.rb b/1.8/library/complex/new_spec.rb new file mode 100644 index 0000000000..bed665575d --- /dev/null +++ b/1.8/library/complex/new_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + + +describe "Complex.new" do + it "needs to be reviewed for spec completeness" do + end + + it "creates a new object of class Complex" do + Complex.new(1, 2).class.should == Complex + end + + it "raises an error with non-Numeric arguments" do + lambda { Complex.new(1, "foo") }.should raise_error + lambda { Complex.new("bar", 2) }.should raise_error + end +end + +describe "Complex.new!" do + it "needs to be reviewed for spec completeness" do + end + + it "creates a new object of class Complex" do + Complex.new!(1, 2).class.should == Complex + end + + it "defaults to 0 for the second argument" do + Complex.new!(5).should == Complex.new!(5, 0) + lambda { Complex.new!("foo") }.should raise_error + end + + it "behaves just like Complex.new when given 2 arguments" do + Complex.new!(5, 6).should == Complex.new(5, 6) + lambda { Complex.new(1, "foo") }.should raise_error + end +end \ No newline at end of file diff --git a/1.8/library/complex/numerator_spec.rb b/1.8/library/complex/numerator_spec.rb new file mode 100644 index 0000000000..b650eca6e0 --- /dev/null +++ b/1.8/library/complex/numerator_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#numerator" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/plus_spec.rb b/1.8/library/complex/plus_spec.rb new file mode 100644 index 0000000000..c959d9a565 --- /dev/null +++ b/1.8/library/complex/plus_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#+ with [Complex]" do + it "needs to be reviewed for spec completeness" do + end + + it "adds both the real and imaginary components" do + a = 1 + b = 2 + c = 10 + d = 20 + (Complex(a, b) + Complex(c, d)).should == Complex(a + c, b + d) + + e = 1.5 + f = 2.1 + g = 100.2 + h = -30.3 + (Complex(e, f) + Complex(g, h)).should == Complex(e + g, f + h) + end +end + +describe "Complex#+ with [real]" do + it "needs to be reviewed for spec completeness" do + end + + it "adds the real number to the real part of the complex number" do + (Complex(1, 2) + 50).should == Complex(51, 2) + (Complex(1, 2) + 50.5).should == Complex(51.5, 2) + end +end \ No newline at end of file diff --git a/1.8/library/complex/polar_spec.rb b/1.8/library/complex/polar_spec.rb new file mode 100644 index 0000000000..72c340ffba --- /dev/null +++ b/1.8/library/complex/polar_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex.polar" do + it "needs to be reviewed for spec completeness" do + end +end + +describe "Complex#polar" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/real_spec.rb b/1.8/library/complex/real_spec.rb new file mode 100644 index 0000000000..81f05c190e --- /dev/null +++ b/1.8/library/complex/real_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#real" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/complex/shared/arg.rb b/1.8/library/complex/shared/arg.rb new file mode 100644 index 0000000000..0ed2650602 --- /dev/null +++ b/1.8/library/complex/shared/arg.rb @@ -0,0 +1,16 @@ +require 'complex' + +shared :complex_arg do |cmd| + describe "Complex##{cmd}" do + it "needs to be reviewed for spec completeness" do + end + + it "returns the argument -- i.e., the angle from (1, 0) in the complex plane" do + TwoPi = 2 * Math::PI + (Complex(1, 0).send(cmd) % TwoPi).should be_close(0, TOLERANCE) + (Complex(0, 2).send(cmd) % TwoPi).should be_close(Math::PI * 0.5, TOLERANCE) + (Complex(-100, 0).send(cmd) % TwoPi).should be_close(Math::PI, TOLERANCE) + (Complex(0, -75.3).send(cmd) % TwoPi).should be_close(Math::PI * 1.5, TOLERANCE) + end + end +end \ No newline at end of file diff --git a/1.8/library/complex/shared/conjugate.rb b/1.8/library/complex/shared/conjugate.rb new file mode 100644 index 0000000000..7e1a908f00 --- /dev/null +++ b/1.8/library/complex/shared/conjugate.rb @@ -0,0 +1,15 @@ +require 'complex' + +shared :complex_conjugate do |cmd| + describe "Complex##{cmd}" do + it "needs to be reviewed for spec completeness" do + end + + it "returns the complex conjugate: conj a + bi = a - bi" do + Complex(3, 5).send(cmd).should == Complex(3, -5) + Complex(3, -5).send(cmd).should == Complex(3, 5) + Complex(-3.0, 5.2).send(cmd).should be_close(Complex(-3.0, -5.2), TOLERANCE) + Complex(3.0, -5.2).send(cmd).should be_close(Complex(3.0, 5.2), TOLERANCE) + end + end +end \ No newline at end of file diff --git a/1.8/library/complex/to_s_spec.rb b/1.8/library/complex/to_s_spec.rb new file mode 100644 index 0000000000..69a83471ab --- /dev/null +++ b/1.8/library/complex/to_s_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'complex' + +describe "Complex#to_s" do + it "needs to be reviewed for spec completeness" do + end + + specify "if real component is 0, just return imaginary component" do + Complex(0, 5).to_s.should == "5i" + Complex(0.0, -3.2).to_s.should == "-3.2i" + end + + specify "if real component is nonzero and imaginary component is nonnegative, return 'a+bi'" do + Complex(1, 5).to_s.should == "1+5i" + Complex(1, 0.0).to_s.should == "1+0.0i" # at least, that's how MRI does it, weird as it seems + Complex(1, 0).to_s.should == "1+0i" + Complex(-2.5, 1.5).to_s.should == "-2.5+1.5i" + end + + specify "if real component is nonzero and imaginary component is negative, return 'a-bi'" do + Complex(1, -5).to_s.should == "1-5i" + Complex(-2.5, -1.5).to_s.should == "-2.5-1.5i" + end +end diff --git a/1.8/library/csv/basicwriter/close_on_terminate_spec.rb b/1.8/library/csv/basicwriter/close_on_terminate_spec.rb new file mode 100644 index 0000000000..85266c4b59 --- /dev/null +++ b/1.8/library/csv/basicwriter/close_on_terminate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::BasicWriter#close_on_terminate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/basicwriter/initialize_spec.rb b/1.8/library/csv/basicwriter/initialize_spec.rb new file mode 100644 index 0000000000..a339a9c062 --- /dev/null +++ b/1.8/library/csv/basicwriter/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::BasicWriter#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/basicwriter/terminate_spec.rb b/1.8/library/csv/basicwriter/terminate_spec.rb new file mode 100644 index 0000000000..5105dd164b --- /dev/null +++ b/1.8/library/csv/basicwriter/terminate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::BasicWriter#terminate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/cell/data_spec.rb b/1.8/library/csv/cell/data_spec.rb new file mode 100644 index 0000000000..01318c1ceb --- /dev/null +++ b/1.8/library/csv/cell/data_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Cell#data" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/cell/initialize_spec.rb b/1.8/library/csv/cell/initialize_spec.rb new file mode 100644 index 0000000000..fc23a19451 --- /dev/null +++ b/1.8/library/csv/cell/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Cell#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/fixtures/one_line.csv b/1.8/library/csv/fixtures/one_line.csv new file mode 100644 index 0000000000..0e88c499a7 --- /dev/null +++ b/1.8/library/csv/fixtures/one_line.csv @@ -0,0 +1 @@ +1,2 \ No newline at end of file diff --git a/1.8/library/csv/foreach_spec.rb b/1.8/library/csv/foreach_spec.rb new file mode 100644 index 0000000000..ea21cf870e --- /dev/null +++ b/1.8/library/csv/foreach_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.foreach" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/generate_line_spec.rb b/1.8/library/csv/generate_line_spec.rb new file mode 100644 index 0000000000..c82763cae3 --- /dev/null +++ b/1.8/library/csv/generate_line_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.generate_line" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/generate_row_spec.rb b/1.8/library/csv/generate_row_spec.rb new file mode 100644 index 0000000000..4fa15bd66e --- /dev/null +++ b/1.8/library/csv/generate_row_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.generate_row" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/generate_spec.rb b/1.8/library/csv/generate_spec.rb new file mode 100644 index 0000000000..f6a8610908 --- /dev/null +++ b/1.8/library/csv/generate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.generate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/iobuf/close_spec.rb b/1.8/library/csv/iobuf/close_spec.rb new file mode 100644 index 0000000000..3ff3220d9d --- /dev/null +++ b/1.8/library/csv/iobuf/close_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::IOBuf#close" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/iobuf/initialize_spec.rb b/1.8/library/csv/iobuf/initialize_spec.rb new file mode 100644 index 0000000000..1bfd488b2a --- /dev/null +++ b/1.8/library/csv/iobuf/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::IOBuf#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/iobuf/read_spec.rb b/1.8/library/csv/iobuf/read_spec.rb new file mode 100644 index 0000000000..ad63ecd50b --- /dev/null +++ b/1.8/library/csv/iobuf/read_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::IOBuf#read" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/iobuf/terminate_spec.rb b/1.8/library/csv/iobuf/terminate_spec.rb new file mode 100644 index 0000000000..072e82d111 --- /dev/null +++ b/1.8/library/csv/iobuf/terminate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::IOBuf#terminate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/ioreader/close_on_terminate_spec.rb b/1.8/library/csv/ioreader/close_on_terminate_spec.rb new file mode 100644 index 0000000000..19ef9f9e0e --- /dev/null +++ b/1.8/library/csv/ioreader/close_on_terminate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::IOReader#close_on_terminate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/ioreader/get_row_spec.rb b/1.8/library/csv/ioreader/get_row_spec.rb new file mode 100644 index 0000000000..fa44d7e053 --- /dev/null +++ b/1.8/library/csv/ioreader/get_row_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::IOReader#get_row" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/ioreader/initialize_spec.rb b/1.8/library/csv/ioreader/initialize_spec.rb new file mode 100644 index 0000000000..194a6e9815 --- /dev/null +++ b/1.8/library/csv/ioreader/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::IOReader#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/ioreader/terminate_spec.rb b/1.8/library/csv/ioreader/terminate_spec.rb new file mode 100644 index 0000000000..efb2362897 --- /dev/null +++ b/1.8/library/csv/ioreader/terminate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::IOReader#terminate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/open_spec.rb b/1.8/library/csv/open_spec.rb new file mode 100644 index 0000000000..59030138e8 --- /dev/null +++ b/1.8/library/csv/open_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.open" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/parse_line_spec.rb b/1.8/library/csv/parse_line_spec.rb new file mode 100644 index 0000000000..e65a4d70ad --- /dev/null +++ b/1.8/library/csv/parse_line_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.parse_line" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/parse_row_spec.rb b/1.8/library/csv/parse_row_spec.rb new file mode 100644 index 0000000000..e6cf7d5d4c --- /dev/null +++ b/1.8/library/csv/parse_row_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.parse_row" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/parse_spec.rb b/1.8/library/csv/parse_spec.rb new file mode 100644 index 0000000000..7fb5c1808b --- /dev/null +++ b/1.8/library/csv/parse_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.parse" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/read_spec.rb b/1.8/library/csv/read_spec.rb new file mode 100644 index 0000000000..fa129dcbe9 --- /dev/null +++ b/1.8/library/csv/read_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.read" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/reader/close_spec.rb b/1.8/library/csv/reader/close_spec.rb new file mode 100644 index 0000000000..0ff44c3ecc --- /dev/null +++ b/1.8/library/csv/reader/close_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Reader#close" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/reader/create_spec.rb b/1.8/library/csv/reader/create_spec.rb new file mode 100644 index 0000000000..2cfc1ffbac --- /dev/null +++ b/1.8/library/csv/reader/create_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Reader.create" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/reader/each_spec.rb b/1.8/library/csv/reader/each_spec.rb new file mode 100644 index 0000000000..f02491464e --- /dev/null +++ b/1.8/library/csv/reader/each_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Reader#each" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/reader/get_row_spec.rb b/1.8/library/csv/reader/get_row_spec.rb new file mode 100644 index 0000000000..cfcdc680ff --- /dev/null +++ b/1.8/library/csv/reader/get_row_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Reader#get_row" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/reader/initialize_spec.rb b/1.8/library/csv/reader/initialize_spec.rb new file mode 100644 index 0000000000..e1280edea6 --- /dev/null +++ b/1.8/library/csv/reader/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Reader#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/reader/parse_spec.rb b/1.8/library/csv/reader/parse_spec.rb new file mode 100644 index 0000000000..fcb0860358 --- /dev/null +++ b/1.8/library/csv/reader/parse_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../../../../spec_helper' +require 'csv' + +describe "CSV::Reader.parse" do + + it "processes empty input without calling block" do + empty_input = mock('empty file') + empty_input.should_receive(:read).once.and_return(nil) + CSV::Reader.parse(empty_input) do |row| + Expectation.fail_with('block should not be executed', 'but executed') + end + Mock.verify_count + end + + it "calls block once for one row of input" do + input_stream = File.open(File.dirname(__FILE__) + '/../fixtures/one_line.csv', 'rb') + count = 0 + CSV::Reader.parse(input_stream) do |row| + count += 1 + end + count.should == 1 + end + +end diff --git a/1.8/library/csv/reader/shift_spec.rb b/1.8/library/csv/reader/shift_spec.rb new file mode 100644 index 0000000000..282f5c35f0 --- /dev/null +++ b/1.8/library/csv/reader/shift_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Reader#shift" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/reader/terminate_spec.rb b/1.8/library/csv/reader/terminate_spec.rb new file mode 100644 index 0000000000..273ab3aea9 --- /dev/null +++ b/1.8/library/csv/reader/terminate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Reader#terminate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/readlines_spec.rb b/1.8/library/csv/readlines_spec.rb new file mode 100644 index 0000000000..bb5bc13f78 --- /dev/null +++ b/1.8/library/csv/readlines_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'csv' + +describe "CSV.readlines" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/add_buf_spec.rb b/1.8/library/csv/streambuf/add_buf_spec.rb new file mode 100644 index 0000000000..e1912e990a --- /dev/null +++ b/1.8/library/csv/streambuf/add_buf_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#add_buf" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/buf_size_spec.rb b/1.8/library/csv/streambuf/buf_size_spec.rb new file mode 100644 index 0000000000..2d2dd1d5c5 --- /dev/null +++ b/1.8/library/csv/streambuf/buf_size_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#buf_size" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/drop_spec.rb b/1.8/library/csv/streambuf/drop_spec.rb new file mode 100644 index 0000000000..9365c3775b --- /dev/null +++ b/1.8/library/csv/streambuf/drop_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#drop" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/element_reference_spec.rb b/1.8/library/csv/streambuf/element_reference_spec.rb new file mode 100644 index 0000000000..9bf31ab404 --- /dev/null +++ b/1.8/library/csv/streambuf/element_reference_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#[]" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/get_spec.rb b/1.8/library/csv/streambuf/get_spec.rb new file mode 100644 index 0000000000..fae10dc4bb --- /dev/null +++ b/1.8/library/csv/streambuf/get_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#get" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/idx_is_eos_spec.rb b/1.8/library/csv/streambuf/idx_is_eos_spec.rb new file mode 100644 index 0000000000..f3e82464dd --- /dev/null +++ b/1.8/library/csv/streambuf/idx_is_eos_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#idx_is_eos?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/initialize_spec.rb b/1.8/library/csv/streambuf/initialize_spec.rb new file mode 100644 index 0000000000..884ec3697d --- /dev/null +++ b/1.8/library/csv/streambuf/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/is_eos_spec.rb b/1.8/library/csv/streambuf/is_eos_spec.rb new file mode 100644 index 0000000000..dbe7481772 --- /dev/null +++ b/1.8/library/csv/streambuf/is_eos_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#is_eos?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/read_spec.rb b/1.8/library/csv/streambuf/read_spec.rb new file mode 100644 index 0000000000..69c66707d7 --- /dev/null +++ b/1.8/library/csv/streambuf/read_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#read" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/rel_buf_spec.rb b/1.8/library/csv/streambuf/rel_buf_spec.rb new file mode 100644 index 0000000000..01cbea1086 --- /dev/null +++ b/1.8/library/csv/streambuf/rel_buf_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#rel_buf" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/streambuf/terminate_spec.rb b/1.8/library/csv/streambuf/terminate_spec.rb new file mode 100644 index 0000000000..7aef20db56 --- /dev/null +++ b/1.8/library/csv/streambuf/terminate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StreamBuf#terminate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/stringreader/get_row_spec.rb b/1.8/library/csv/stringreader/get_row_spec.rb new file mode 100644 index 0000000000..ce93cfb772 --- /dev/null +++ b/1.8/library/csv/stringreader/get_row_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StringReader#get_row" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/stringreader/initialize_spec.rb b/1.8/library/csv/stringreader/initialize_spec.rb new file mode 100644 index 0000000000..0b1227d6a1 --- /dev/null +++ b/1.8/library/csv/stringreader/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::StringReader#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/writer/add_row_spec.rb b/1.8/library/csv/writer/add_row_spec.rb new file mode 100644 index 0000000000..b13335ad04 --- /dev/null +++ b/1.8/library/csv/writer/add_row_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Writer#add_row" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/writer/append_spec.rb b/1.8/library/csv/writer/append_spec.rb new file mode 100644 index 0000000000..4219c11f71 --- /dev/null +++ b/1.8/library/csv/writer/append_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Writer#<<" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/writer/close_spec.rb b/1.8/library/csv/writer/close_spec.rb new file mode 100644 index 0000000000..f16c123bfa --- /dev/null +++ b/1.8/library/csv/writer/close_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Writer#close" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/writer/create_spec.rb b/1.8/library/csv/writer/create_spec.rb new file mode 100644 index 0000000000..83bdfe7b5d --- /dev/null +++ b/1.8/library/csv/writer/create_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Writer.create" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/writer/generate_spec.rb b/1.8/library/csv/writer/generate_spec.rb new file mode 100644 index 0000000000..55255c10e3 --- /dev/null +++ b/1.8/library/csv/writer/generate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Writer.generate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/writer/initialize_spec.rb b/1.8/library/csv/writer/initialize_spec.rb new file mode 100644 index 0000000000..8ee569bf25 --- /dev/null +++ b/1.8/library/csv/writer/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Writer#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/csv/writer/terminate_spec.rb b/1.8/library/csv/writer/terminate_spec.rb new file mode 100644 index 0000000000..f31dcd8e86 --- /dev/null +++ b/1.8/library/csv/writer/terminate_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'csv' + +describe "CSV::Writer#terminate" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/date/accessor_spec.rb b/1.8/library/date/accessor_spec.rb new file mode 100644 index 0000000000..cfe9583508 --- /dev/null +++ b/1.8/library/date/accessor_spec.rb @@ -0,0 +1,91 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#ajd" do + it "should be able to determine the Astronomical Julian day for a date" do + Date.civil(2007, 1, 17).ajd.should == 4908235.to_r / 2 + end +end + +describe "Date#amjd" do + it "should be able to determine the Astronomical Modified Julian day for a date" do + Date.civil(2007, 1, 17).amjd.should == 54117 + end +end + +describe "Date#day_fraction" do + it "should be able to determine the day fraction for a date" do + Date.civil(2007, 1, 17).day_fraction.should == 0 + end +end + +describe "Date#mjd" do + it "should be able to determine the Modified Julian day for a date" do + Date.civil(2007, 1, 17).mjd.should == 54117 + end +end + +describe "Date#ld" do + it "should be able to determine the Modified Julian day for a date" do + Date.civil(2007, 1, 17).ld.should == 154958 + end +end + +describe "Date#year" do + it "should be able to determine the year for a date" do + Date.civil(2007, 1, 17).year.should == 2007 + end +end + +describe "Date#yday" do + it "should be able to determine the year for a date" do + Date.civil(2007, 1, 17).yday.should == 17 + Date.civil(2008, 10, 28).yday.should == 302 + end +end + +describe "Date#mon" do + it "should be able to determine the month for a date" do + Date.civil(2007, 1, 17).mon.should == 1 + Date.civil(2008, 10, 28).mon.should == 10 + end +end + +describe "Date#mday" do + it "should be able to determine the day of the month for a date" do + Date.civil(2007, 1, 17).mday.should == 17 + Date.civil(2008, 10, 28).mday.should == 28 + end +end + +describe "Date#wday" do + it "should be able to determine the week day for a date" do + Date.civil(2007, 1, 17).wday.should == 3 + Date.civil(2008, 10, 26).wday.should == 0 + end +end + +describe "Date#cwyear" do + it "should be able to determine the commercial year for a date" do + Date.civil(2007, 1, 17).cwyear.should == 2007 + Date.civil(2008, 10, 28).cwyear.should == 2008 + Date.civil(2007, 12, 31).cwyear.should == 2008 + Date.civil(2010, 1, 1).cwyear.should == 2009 + end +end + +describe "Date#cweek" do + it "should be able to determine the commercial week for a date" do + Date.civil(2007, 1, 17).cweek.should == 3 + Date.civil(2008, 10, 28).cweek.should == 44 + Date.civil(2007, 12, 31).cweek.should == 1 + Date.civil(2010, 1, 1).cweek.should == 53 + end +end + +describe "Date#cwday" do + it "should be able to determine the commercial week day for a date" do + Date.civil(2007, 1, 17).cwday.should == 3 + Date.civil(2008, 10, 26).cwday.should == 7 + end +end \ No newline at end of file diff --git a/1.8/library/date/add_month_spec.rb b/1.8/library/date/add_month_spec.rb new file mode 100644 index 0000000000..2bdf3e1ca6 --- /dev/null +++ b/1.8/library/date/add_month_spec.rb @@ -0,0 +1,24 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#>>" do + + it "should add a number of months to a Date" do + d = Date.civil(2007,2,27) >> 10 + d.should == Date.civil(2007, 12, 27) + end + + + it "should result in the last day of a month if the day doesn't exist" do + d = Date.civil(2008,3,31) >> 1 + d.should == Date.civil(2008, 4, 30) + end + + it "should raise an error on non numeric parameters" do + lambda { Date.civil(2007,2,27) >> :hello }.should raise_error(TypeError) + lambda { Date.civil(2007,2,27) >> "hello" }.should raise_error(TypeError) + lambda { Date.civil(2007,2,27) >> Date.new }.should raise_error(TypeError) + lambda { Date.civil(2007,2,27) >> Object.new }.should raise_error(TypeError) + end + +end \ No newline at end of file diff --git a/1.8/library/date/add_spec.rb b/1.8/library/date/add_spec.rb new file mode 100644 index 0000000000..6ec6b71d01 --- /dev/null +++ b/1.8/library/date/add_spec.rb @@ -0,0 +1,23 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#+" do + + it "should add a number of days to a Date" do + d = Date.civil(2007,2,27) + 10 + d.should == Date.civil(2007, 3, 9) + end + + it "should add a negative number of days to a Date" do + d = Date.civil(2007,2,27).+(-10) + d.should == Date.civil(2007, 2, 17) + end + + it "should raise an error on non numeric parameters" do + lambda { Date.civil(2007,2,27) + :hello }.should raise_error(TypeError) + lambda { Date.civil(2007,2,27) + "hello" }.should raise_error(TypeError) + lambda { Date.civil(2007,2,27) + Date.new }.should raise_error(TypeError) + lambda { Date.civil(2007,2,27) + Object.new }.should raise_error(TypeError) + end + +end \ No newline at end of file diff --git a/1.8/library/date/boat_spec.rb b/1.8/library/date/boat_spec.rb new file mode 100644 index 0000000000..d1d3490cfc --- /dev/null +++ b/1.8/library/date/boat_spec.rb @@ -0,0 +1,20 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#<=>" do + + it "should be able to compare two same dates" do + (Date.civil(2000, 04, 06) <=> Date.civil(2000, 04, 06)).should == 0 + end + + it "should be able to compute the difference between two dates" do + (Date.civil(2000, 04, 05) <=> Date.civil(2000, 04, 06)).should == -1 + (Date.civil(2001, 04, 05) <=> Date.civil(2000, 04, 06)).should == 1 + end + + it "should be able to compare to another numeric" do + (Date.civil(2000, 04, 05) <=> Date.civil(2000, 04, 06).jd).should == -1 + (Date.civil(2001, 04, 05) <=> Date.civil(2000, 04, 06).jd).should == 1 + end + +end \ No newline at end of file diff --git a/1.8/library/date/civil_spec.rb b/1.8/library/date/civil_spec.rb new file mode 100644 index 0000000000..e26968c432 --- /dev/null +++ b/1.8/library/date/civil_spec.rb @@ -0,0 +1,28 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/civil' + +describe "Date#civil" do + + it_behaves_like(:date_civil, :civil) + +end + +describe "Date#valid_civil?" do + + it "should be able to determine if a date is valid" do + Date.valid_civil?(1582, 10, 14).should == nil + Date.valid_civil?(1582, 10, 15).should == Date.civil(1582, 10, 15).jd + Date.valid_civil?(1582, 10, 14, Date::ENGLAND).should_not == nil + Date.valid_civil?(1582, 10, 14, Date::ENGLAND).should == Date.civil(1582, 10, 14, Date::ENGLAND).jd + end + + it "should be able to handle negative months and days" do + Date.valid_civil?(1582, -3, -18).should == nil + Date.valid_civil?(1582, -3, -17).should == Date.civil(1582, 10, 15).jd + + Date.valid_civil?(2007, -11, -10).should == Date.civil(2007, 2, 19).jd + Date.valid_civil?(2008, -11, -10).should == Date.civil(2008, 2, 20).jd + end + +end diff --git a/1.8/library/date/commercial_spec.rb b/1.8/library/date/commercial_spec.rb new file mode 100644 index 0000000000..c960ed7d6e --- /dev/null +++ b/1.8/library/date/commercial_spec.rb @@ -0,0 +1,29 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/commercial' + +describe "Date#commercial" do + + it_behaves_like(:date_commercial, :commercial) + +end + +describe "Date#valid_commercial?" do + + it "should be able to determine if the date is a valid commercial date" do + Date.valid_commercial?(1582, 41, 4).should == nil + Date.valid_commercial?(1582, 41, 5).should == Date.civil(1582, 10, 15).jd + # valid_commercial? can't handle dates before the Gregorian calendar + Date.valid_commercial?(1582, 41, 4, Date::ENGLAND).should == nil + Date.valid_commercial?(1752, 37, 4, Date::ENGLAND).should == Date.civil(1752, 9, 14, Date::ENGLAND).jd + end + + it "should be able to handle negative week and day numbers" do + Date.valid_commercial?(1582, -12, -4).should == nil + Date.valid_commercial?(1582, -12, -3).should == Date.civil(1582, 10, 15).jd + + Date.valid_commercial?(2007, -44, -2).should == Date.civil(2007, 3, 3).jd + Date.valid_commercial?(2008, -44, -2).should == Date.civil(2008, 3, 1).jd + end + +end \ No newline at end of file diff --git a/1.8/library/date/constants_spec.rb b/1.8/library/date/constants_spec.rb new file mode 100644 index 0000000000..bc4bc6d0c8 --- /dev/null +++ b/1.8/library/date/constants_spec.rb @@ -0,0 +1,39 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date constants" do + + it "should define ITALY" do + Date::ITALY.should == 2299161 # 1582-10-15 + end + + it "should define ENGLAND" do + Date::ENGLAND.should == 2361222 # 1752-09-14 + end + + ruby_bug do + it "should define JULIAN" do + (Date::JULIAN <=> Date::Infinity.new).should == 0 + end + end + + ruby_bug do + it "should define GREGORIAN" do + (Date::GREGORIAN <=> -Date::Infinity.new).should == 0 + end + end + + it "should define MONTHNAMES" do + Date::MONTHNAMES.should == [nil] + %w(January February March April May June July + August September October November December) + end + + it "should define DAYNAMES" do + Date::DAYNAMES.should == %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday) + end + + it "should define ABBR_MONTHNAMES" do + Date::ABBR_DAYNAMES.should == %w(Sun Mon Tue Wed Thu Fri Sat) + end + +end \ No newline at end of file diff --git a/1.8/library/date/conversions_spec.rb b/1.8/library/date/conversions_spec.rb new file mode 100644 index 0000000000..fb435182e2 --- /dev/null +++ b/1.8/library/date/conversions_spec.rb @@ -0,0 +1,153 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + + +describe "Date#new_start" do + it "should convert a date object into another with a new calendar reform" do + Date.civil(1582, 10, 14, Date::ENGLAND).new_start.should == Date.civil(1582, 10, 24) + Date.civil(1582, 10, 4, Date::ENGLAND).new_start.should == Date.civil(1582, 10, 4) + Date.civil(1582, 10, 15).new_start(Date::ENGLAND).should == Date.civil(1582, 10, 5, Date::ENGLAND) + Date.civil(1752, 9, 14).new_start(Date::ENGLAND).should == Date.civil(1752, 9, 14, Date::ENGLAND) + Date.civil(1752, 9, 13).new_start(Date::ENGLAND).should == Date.civil(1752, 9, 2, Date::ENGLAND) + end +end + +describe "Date#italy" do + it "should convert a date object into another with the Italian calendar reform" do + Date.civil(1582, 10, 14, Date::ENGLAND).italy.should == Date.civil(1582, 10, 24) + Date.civil(1582, 10, 4, Date::ENGLAND).italy.should == Date.civil(1582, 10, 4) + end +end + +describe "Date#england" do + it "should convert a date object into another with the English calendar reform" do + Date.civil(1582, 10, 15).england.should == Date.civil(1582, 10, 5, Date::ENGLAND) + Date.civil(1752, 9, 14).england.should == Date.civil(1752, 9, 14, Date::ENGLAND) + Date.civil(1752, 9, 13).england.should == Date.civil(1752, 9, 2, Date::ENGLAND) + end +end + +describe "Date#julian" do + it "should convert a date object into another with the Julian calendar" do + Date.civil(1582, 10, 15).julian.should == Date.civil(1582, 10, 5, Date::JULIAN) + Date.civil(1752, 9, 14).julian.should == Date.civil(1752, 9, 3, Date::JULIAN) + Date.civil(1752, 9, 13).julian.should == Date.civil(1752, 9, 2, Date::JULIAN) + end +end + +describe "Date#gregorian" do + it "should convert a date object into another with the Gregorian calendar" do + Date.civil(1582, 10, 4).gregorian.should == Date.civil(1582, 10, 14, Date::GREGORIAN) + Date.civil(1752, 9, 14).gregorian.should == Date.civil(1752, 9, 14, Date::GREGORIAN) + end +end + +describe "Date#ordinal_to_jd" do + it "should convert an ordinal date (year-day) to a Julian day number" do + Date.ordinal_to_jd(2007, 55).should == 2454156 + end +end + +describe "Date#jd_to_ordinal" do + it "should convert a Julian day number into an ordinal date" do + Date.jd_to_ordinal(2454156).should == [2007, 55] + end +end + +describe "Date#civil_to_jd" do + it "should convert a civil date into a Julian day number" do + Date.civil_to_jd(2007, 2, 24).should == 2454156 + end +end + +describe "Date#jd_to_civil" do + it "should convert a Julian day into a civil date" do + Date.jd_to_civil(2454156).should == [2007, 2, 24] + end +end + +describe "Date#commercial_to_jd" do + it "should convert a commercial date (year - week - day of week) into a Julian day number" do + Date.commercial_to_jd(2007, 45, 1).should == 2454410 + end +end + +describe "Date#jd_to_commercial" do + it "should convert a Julian day number into a commercial date" do + Date.jd_to_commercial(2454410).should == [2007, 45, 1] + end +end + +describe "Date#ajd_to_jd" do + it "should convert a Astronomical Julian day number into a Julian day number" do + Date.ajd_to_jd(2454410).should == [2454410, Rational(1,2)] + Date.ajd_to_jd(2454410, 1.to_r / 2).should == [2454411, 0] + end +end + +describe "Date#jd_to_ajd" do + it "should convert a Julian day number into a Astronomical Julian day number" do + Date.jd_to_ajd(2454410, 0).should == 2454410 - Rational(1, 2) + Date.jd_to_ajd(2454410, 1.to_r / 2).should == 2454410 + end +end + +describe "Date#day_fraction_to_time" do + it "should be able to convert a day fraction into time" do + Date.day_fraction_to_time(2).should == [48, 0, 0, 0] + Date.day_fraction_to_time(1).should == [24, 0, 0, 0] + Date.day_fraction_to_time(1.to_r / 2).should == [12, 0, 0, 0] + Date.day_fraction_to_time(1.to_r / 7).should == [3, 25, 42, 1.to_r / 100800] + end +end + +describe "Date#time_to_day_fraction" do + it "should be able to convert a time into a day fraction" do + Date.time_to_day_fraction(48, 0, 0).should == 2 + Date.time_to_day_fraction(24, 0, 0).should == 1 + Date.time_to_day_fraction(12, 0, 0).should == 1.to_r / 2 + Date.time_to_day_fraction(10, 20, 10).should == 10.to_r / 24 + 20.to_r / (24 * 60) + 10.to_r / (24 * 60 * 60) + end +end + +describe "Date#amjd_to_ajd" do + it "shoud be able to convert Astronomical Modified Julian day numbers into Astronomical Julian day numbers" do + Date.amjd_to_ajd(10).should == 10 + 2400000 + 1.to_r / 2 + end +end + +describe "Date#ajd_to_amjd" do + it "shoud be able to convert Astronomical Julian day numbers into Astronomical Modified Julian day numbers" do + Date.ajd_to_amjd(10000010).should == 10000010 - 2400000 - 1.to_r / 2 + end +end + +describe "Date#mjd_to_jd" do + it "shoud be able to convert Modified Julian day numbers into Julian day numbers" do + Date.mjd_to_jd(2000).should == 2000 + 2400001 + end +end + +describe "Date#jd_to_mjd" do + it "shoud be able to convert Julian day numbers into Modified Julian day numbers" do + Date.jd_to_mjd(2500000).should == 2500000 - 2400001 + end +end + +describe "Date#ld_to_jd" do + it "should be able to convert the number of days since the Gregorian calendar in Italy into Julian day numbers" do + Date.ld_to_jd(450000).should == 450000 + 2299160 + end +end + +describe "Date#jd_to_ld" do + it "should be able to convert Julian day numbers into the number of days since the Gregorian calendar in Italy" do + Date.jd_to_ld(2450000).should == 2450000 - 2299160 + end +end + +describe "Date#jd_to_wday" do + it "should be able to convert a Julian day number into a week day number" do + Date.jd_to_wday(2454482).should == 3 + end +end \ No newline at end of file diff --git a/1.8/library/date/downto_spec.rb b/1.8/library/date/downto_spec.rb new file mode 100644 index 0000000000..2ac84f107d --- /dev/null +++ b/1.8/library/date/downto_spec.rb @@ -0,0 +1,18 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#downto" do + + it "should be able to step backward in time" do + ds = Date.civil(2000, 4, 14) + de = Date.civil(2000, 3, 29) + count = 0 + ds.step(de, -1) do |d| + d.should <= ds + d.should >= de + count += 1 + end + count.should == 17 + end + +end diff --git a/1.8/library/date/eql_spec.rb b/1.8/library/date/eql_spec.rb new file mode 100644 index 0000000000..d9a7a19ed9 --- /dev/null +++ b/1.8/library/date/eql_spec.rb @@ -0,0 +1,15 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#eql?" do + + it "should be able determine equality between date objects" do + + Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 11)).should == true + Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 12)).should_not == true + + Date.civil(2007, 10, 11).eql?(Date.civil(2007, 10, 12) - 1).should == true + + end + +end \ No newline at end of file diff --git a/1.8/library/date/gregorian_spec.rb b/1.8/library/date/gregorian_spec.rb new file mode 100644 index 0000000000..10751a7faa --- /dev/null +++ b/1.8/library/date/gregorian_spec.rb @@ -0,0 +1,28 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#gregorian?" do + + it "should mark a day before the calendar reform as Julian" do + Date.civil(1007, 2, 27).gregorian?.should == false + Date.civil(1907, 2, 27, Date.civil(2000, 1, 1).jd).gregorian?.should == false + end + + it "should mark a day after the calendar reform as Julian" do + Date.civil(2007, 2, 27).gregorian?.should == true + Date.civil(1007, 2, 27, Date.civil(1000, 1, 1).jd).gregorian?.should == true + end + +end + +describe "Date#gregorian_leap?" do + + it "should be able to determine whether a year is a leap year in the Gregorian calendar" do + Date.gregorian_leap?(1900).should == false + Date.gregorian_leap?(1999).should == false + Date.gregorian_leap?(2000).should == true + Date.gregorian_leap?(2002).should == false + Date.gregorian_leap?(2004).should == true + end + +end \ No newline at end of file diff --git a/1.8/library/date/hash_spec.rb b/1.8/library/date/hash_spec.rb new file mode 100644 index 0000000000..5e8615f1ab --- /dev/null +++ b/1.8/library/date/hash_spec.rb @@ -0,0 +1,14 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#hash" do + + it "should be able determine the hash value for a date" do + Date.civil(2004, 7, 12).respond_to?(:hash).should == true + end + + it "should be the case that the same date results in the same hash" do + Date.civil(2004, 7, 12).hash.should == Date.civil(2004, 7, 12).hash + end + +end \ No newline at end of file diff --git a/1.8/library/date/infinity_spec.rb b/1.8/library/date/infinity_spec.rb new file mode 100644 index 0000000000..42b3d3de67 --- /dev/null +++ b/1.8/library/date/infinity_spec.rb @@ -0,0 +1,75 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date::Infinity" do + + it "should be able to check whether Infinity is zero" do + i = Date::Infinity.new + i.zero?.should == false + end + + it "should be able to check whether Infinity is finite" do + i1 = Date::Infinity.new + i1.finite?.should == false + i2 = Date::Infinity.new(-1) + i2.finite?.should == false + i3 = Date::Infinity.new(0) + i3.finite?.should == false + end + + it "should be able to check whether Infinity is infinite" do + i1 = Date::Infinity.new + i1.infinite?.should == 1 + i2 = Date::Infinity.new(-1) + i2.infinite?.should == -1 + i3 = Date::Infinity.new(0) + i3.infinite?.should == nil + end + + it "should be able to check whether Infinity is not a number" do + i1 = Date::Infinity.new + i1.nan?.should == false + i2 = Date::Infinity.new(-1) + i2.nan?.should == false + i3 = Date::Infinity.new(0) + i3.nan?.should == true + end + + # These checks fail on MRI because of a bug in Date::Infinity#<=> + ruby_bug do + it "should be able to compare Infinity objects" do + i1 = Date::Infinity.new + i2 = Date::Infinity.new(-1) + i3 = Date::Infinity.new(0) + i4 = Date::Infinity.new + (i4 <=> i1).should == 0 + (i3 <=> i1).should == -1 + (i2 <=> i1).should == -1 + (i3 <=> i2).should == 1 + end + end + + # Also fails because of the same bug as the previous spec + ruby_bug do + it "should be able to return plus Infinity for abs" do + i1 = Date::Infinity.new + i2 = Date::Infinity.new(-1) + i3 = Date::Infinity.new(0) + (i2.abs <=> i1).should == 0 + (i3.abs <=> i1).should == 0 + end + end + + ruby_bug do + it "should be able to use -@ and +@ for Date::Infinity" do + (Date::Infinity.new <=> +Date::Infinity.new).should == 0 + (Date::Infinity.new(-1) <=> -Date::Infinity.new).should == 0 + end + end + + it "should be able to coerce a Date::Infinity object" do + Date::Infinity.new.coerce(1).should == [-1, 1] + Date::Infinity.new(0).coerce(2).should == [0, 0] + Date::Infinity.new(-1).coerce(1.5).should == [1, -1] + end +end diff --git a/1.8/library/date/julian_spec.rb b/1.8/library/date/julian_spec.rb new file mode 100644 index 0000000000..c5638844fa --- /dev/null +++ b/1.8/library/date/julian_spec.rb @@ -0,0 +1,52 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#jd" do + + it "should be able to construct a Date object based on the Julian day" do + Date.jd(2454482).should == Date.civil(2008, 1, 16) + end + + it "should be able to determine the Julian day for a Date object" do + Date.civil(2008, 1, 16).jd.should == 2454482 + end + +end + +describe "Date#julian?" do + + it "should mark a day before the calendar reform as Julian" do + Date.civil(1007, 2, 27).julian?.should == true + Date.civil(1907, 2, 27, Date.civil(2000, 1, 1).jd).julian?.should == true + end + + it "should mark a day after the calendar reform as Julian" do + Date.civil(2007, 2, 27).julian?.should == false + Date.civil(1007, 2, 27, Date.civil(1000, 1, 1).jd).julian?.should == false + end + +end + +describe "Date#julian_leap?" do + + it "should be able to determine whether a year is a leap year in the Julian calendar" do + Date.julian_leap?(1900).should == true + Date.julian_leap?(1999).should == false + Date.julian_leap?(2000).should == true + Date.julian_leap?(2002).should == false + Date.julian_leap?(2004).should == true + end + +end + +describe "Date#valid_jd?" do + + it "should be able to determine if a day number is a valid Julian day number, true for all numbers" do + # This might need to check the type of the jd parameter. Date.valid_jd?(:number) is of course + # bogus but returns itself with the current implementation + Date.valid_jd?(-100).should == -100 + Date.valid_jd?(0).should == 0 + Date.valid_jd?(100).should == 100 + end + +end \ No newline at end of file diff --git a/1.8/library/date/minus_month_spec.rb b/1.8/library/date/minus_month_spec.rb new file mode 100644 index 0000000000..e50edc2e2a --- /dev/null +++ b/1.8/library/date/minus_month_spec.rb @@ -0,0 +1,23 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#<<" do + + it "should substract a number of months from a date" do + d = Date.civil(2007,2,27) << 10 + d.should == Date.civil(2006, 4, 27) + end + + it "should result in the last day of a month if the day doesn't exist" do + d = Date.civil(2008,3,31) << 1 + d.should == Date.civil(2008, 2, 29) + end + + it "should raise an error on non numeric parameters" do + lambda { Date.civil(2007,2,27) << :hello }.should raise_error(NoMethodError) + lambda { Date.civil(2007,2,27) << "hello" }.should raise_error(NoMethodError) + lambda { Date.civil(2007,2,27) << Date.new }.should raise_error(NoMethodError) + lambda { Date.civil(2007,2,27) << Object.new }.should raise_error(NoMethodError) + end + +end \ No newline at end of file diff --git a/1.8/library/date/minus_spec.rb b/1.8/library/date/minus_spec.rb new file mode 100644 index 0000000000..ab3b9d7a61 --- /dev/null +++ b/1.8/library/date/minus_spec.rb @@ -0,0 +1,30 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#-" do + + it "should substract a number of days from a Date" do + d = Date.civil(2007, 5 ,2) - 13 + d.should == Date.civil(2007, 4, 19) + end + + it "should substract a negative number of days from a Date" do + d = Date.civil(2007, 4, 19).-(-13) + d.should == Date.civil(2007, 5 ,2) + end + + it "should be able to compute the different between two dates" do + (Date.civil(2007,2,27) - Date.civil(2007,2,27)).should == 0 + (Date.civil(2007,2,27) - Date.civil(2007,2,26)).should == 1 + (Date.civil(2006,2,27) - Date.civil(2007,2,27)).should == -365 + (Date.civil(2008,2,27) - Date.civil(2007,2,27)).should == 365 + + end + + it "should raise an error on non numeric parameters" do + lambda { Date.civil(2007,2,27) - :hello }.should raise_error(TypeError) + lambda { Date.civil(2007,2,27) - "hello" }.should raise_error(TypeError) + lambda { Date.civil(2007,2,27) - Object.new }.should raise_error(TypeError) + end + +end \ No newline at end of file diff --git a/1.8/library/date/new_spec.rb b/1.8/library/date/new_spec.rb new file mode 100644 index 0000000000..b011bf683e --- /dev/null +++ b/1.8/library/date/new_spec.rb @@ -0,0 +1,9 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/civil' + +describe "Date#new" do + + it_behaves_like(:date_civil, :new) + +end diff --git a/1.8/library/date/neww_spec.rb b/1.8/library/date/neww_spec.rb new file mode 100644 index 0000000000..0134949f08 --- /dev/null +++ b/1.8/library/date/neww_spec.rb @@ -0,0 +1,9 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/commercial' + +describe "Date#neww" do + + it_behaves_like(:date_commercial, :neww) + +end diff --git a/1.8/library/date/ordinal_spec.rb b/1.8/library/date/ordinal_spec.rb new file mode 100644 index 0000000000..2169d8b018 --- /dev/null +++ b/1.8/library/date/ordinal_spec.rb @@ -0,0 +1,29 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/commercial' + +describe "Date#ordinal" do + + it "should be able to construct a Date object from an ordinal date" do + lambda { Date.ordinal(1582, 287) }.should raise_error(ArgumentError) + Date.ordinal(1582, 288).should == Date.civil(1582, 10, 15) + Date.ordinal(1582, 287, Date::ENGLAND).should == Date.civil(1582, 10, 14, Date::ENGLAND) + end + +end + +describe "Date#valid_ordinal?" do + + it "should be able to determine if the date is a valid ordinal date" do + Date.valid_ordinal?(1582, 287).should == nil + Date.valid_ordinal?(1582, 288).should == Date.civil(1582, 10, 15).jd + Date.valid_ordinal?(1582, 287, Date::ENGLAND).should_not == nil + Date.valid_ordinal?(1582, 287, Date::ENGLAND).should == Date.civil(1582, 10, 14, Date::ENGLAND).jd + end + + it "should be able to handle negative day numbers" do + Date.valid_ordinal?(1582, -79).should == nil + Date.valid_ordinal?(2007, -100).should == Date.valid_ordinal?(2007, 266) + end + +end \ No newline at end of file diff --git a/1.8/library/date/parse_spec.rb b/1.8/library/date/parse_spec.rb new file mode 100644 index 0000000000..16fbceb36a --- /dev/null +++ b/1.8/library/date/parse_spec.rb @@ -0,0 +1,77 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/parse' +require File.dirname(__FILE__) + '/shared/parse_us' +require File.dirname(__FILE__) + '/shared/parse_eu' + +describe "Date#parse" do + + + # The space separator is also different, doesn't work for only numbers + it "can parse a day name into a Date object" do + d = Date.parse("friday") + d.should == Date.commercial(d.cwyear, d.cweek, 5) + end + + it "can parse a month name into a Date object" do + d = Date.parse("october") + d.should == Date.civil(Date.today.year, 10) + end + + it "can parse a month day into a Date object" do + d = Date.parse("5th") + d.should == Date.civil(Date.today.year, Date.today.month, 5) + end + + # Specs using numbers + it "can't handle a single digit" do + lambda{ Date.parse("1") }.should raise_error(ArgumentError) + end + + it "can handle DD as month day number" do + d = Date.parse("10") + d.should == Date.civil(Date.today.year, Date.today.month, 10) + end + + it "can handle DDD as year day number" do + d = Date.parse("100") + d.should == Date.civil(Date.today.year, 4, 9) + end + + it "can handle MMDD as month and day" do + d = Date.parse("1108") + d.should == Date.civil(Date.today.year, 11, 8) + end + + it "can handle YYDDD as year and day number" do + d = Date.parse("10100") + d.should == Date.civil(10, 4, 10) + end + + it "can handle YYMMDD as year month and day" do + d = Date.parse("201023") + d.should == Date.civil(20, 10, 23) + end + + it "can handle YYYYDDD as year and day number" do + d = Date.parse("1910100") + d.should == Date.civil(1910, 4, 10) + end + + it "can handle YYYYMMDD as year and day number" do + d = Date.parse("19101101") + d.should == Date.civil(1910, 11, 1) + end + + # The combination of using the - separator and using names for + # months doesn't work, so - is excluded here. + it_behaves_like(:date_parse, '.') + it_behaves_like(:date_parse, '/') + it_behaves_like(:date_parse, ' ') + + # Numeric date parsing doesn't work when using spaces + it_behaves_like(:date_parse_us, '.') + it_behaves_like(:date_parse_us, '/') + it_behaves_like(:date_parse_eu, '-') + +end \ No newline at end of file diff --git a/1.8/library/date/relationship_spec.rb b/1.8/library/date/relationship_spec.rb new file mode 100644 index 0000000000..f6210149df --- /dev/null +++ b/1.8/library/date/relationship_spec.rb @@ -0,0 +1,20 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#===" do + + it "should be able to compare two same dates" do + (Date.civil(2000, 04, 06) <=> Date.civil(2000, 04, 06)).should == 0 + end + + it "should be able to compute the difference between two dates" do + (Date.civil(2000, 04, 05) <=> Date.civil(2000, 04, 06)).should == -1 + (Date.civil(2001, 04, 05) <=> Date.civil(2000, 04, 06)).should == 1 + end + + it "should be able to compare to another numeric" do + (Date.civil(2000, 04, 05) <=> Date.civil(2000, 04, 06).jd).should == -1 + (Date.civil(2001, 04, 05) <=> Date.civil(2000, 04, 06).jd).should == 1 + end + +end \ No newline at end of file diff --git a/1.8/library/date/shared/civil.rb b/1.8/library/date/shared/civil.rb new file mode 100644 index 0000000000..80c8115304 --- /dev/null +++ b/1.8/library/date/shared/civil.rb @@ -0,0 +1,71 @@ +shared :date_civil do |cmd| + + describe "Date##{cmd}" do + it "creates a Date for -4712 by default" do + # the #chomp calls are necessary because of RSpec + d = Date.send(cmd) + d.year.should == -4712 + d.month.should == 1 + d.day.should == 1 + d.julian?.should == true + d.jd.should == 0 + end + + it "creates a date with arguments" do + d = Date.send(cmd, 2000, 3, 5) + d.year.should == 2000 + d.month.should == 3 + d.day.should == 5 + d.julian?.should == false + d.jd.should == 2451609 + + # Should also work with years far in the past and future + + d = Date.send(cmd, -9000, 7, 5) + d.year.should == -9000 + d.month.should == 7 + d.day.should == 5 + d.julian?.should == true + d.jd.should == -1566006 + + d = Date.send(cmd, 9000, 10, 14) + d.year.should == 9000 + d.month.should == 10 + d.day.should == 14 + d.julian?.should == false + d.jd.should == 5008529 + + end + + it "doesn't create dates for invalid arguments" do + lambda { Date.send(cmd, 2000, 13, 31) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 2000, 12, 32) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 2000, 2, 30) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 1900, 2, 29) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 2000, 2, 29) }.should_not raise_error(ArgumentError) + + lambda { Date.send(cmd, 1582, 10, 14) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 1582, 10, 15) }.should_not raise_error(ArgumentError) + + end + + it "creats a Date for different calendar reform dates" do + d1 = Date.send(cmd, 1582, 10, 4) + d1.succ.day.should == 15 + + d2 = Date.send(cmd, 1582, 10, 4, Date::ENGLAND) + d2.succ.day.should == 5 + + # Choose an arbitrary reform date + r = Date.send(cmd, 2000, 2, 3) + + d3 = Date.send(cmd, 2000, 2, 3, r.jd) + (d3 - 1).day.should == 20 + (d3 - 1).month.should == 1 + + lambda { Date.send(cmd, 2000, 2, 2, r.jd) }.should raise_error(ArgumentError) + end + + end + +end \ No newline at end of file diff --git a/1.8/library/date/shared/commercial.rb b/1.8/library/date/shared/commercial.rb new file mode 100644 index 0000000000..60c39352c8 --- /dev/null +++ b/1.8/library/date/shared/commercial.rb @@ -0,0 +1,45 @@ +shared :date_commercial do |cmd| + + describe "Date##{cmd}" do + + it "creates a Date for the day of Julian calendar reform in Italy by default" do + d = Date.send(cmd) + d.year.should == 1582 + d.month.should == 10 + d.day.should == 15 + end + + it "Creates a Date for the friday in the year and week given" do + d = Date.send(cmd, 2000, 1) + d.year.should == 2000 + d.month.should == 1 + d.day.should == 7 + d.cwday.should == 5 + end + + it "Creates a Date for the correct day given the year, week and day number" do + d = Date.send(cmd, 2004, 1, 1) + d.year.should == 2003 + d.month.should == 12 + d.day.should == 29 + d.cwday.should == 1 + d.cweek.should == 1 + d.cwyear.should == 2004 + end + + it "creates only Date objects for valid weeks" do + lambda { Date.send(cmd, 2004, 53, 1) }.should_not raise_error(ArgumentError) + lambda { Date.send(cmd, 2004, 53, 0) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 2004, 53, 8) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 2004, 54, 1) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 2004, 0, 1) }.should raise_error(ArgumentError) + + lambda { Date.send(cmd, 2003, 52, 1) }.should_not raise_error(ArgumentError) + lambda { Date.send(cmd, 2003, 53, 1) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 2003, 52, 0) }.should raise_error(ArgumentError) + lambda { Date.send(cmd, 2003, 52, 8) }.should raise_error(ArgumentError) + end + + end + +end \ No newline at end of file diff --git a/1.8/library/date/shared/parse.rb b/1.8/library/date/shared/parse.rb new file mode 100644 index 0000000000..91b8add065 --- /dev/null +++ b/1.8/library/date/shared/parse.rb @@ -0,0 +1,60 @@ +shared :date_parse do |sep| + + describe "Date#parse(#{sep})" do + + it "can parse a mmm-YYYY string into a Date object" do + d = Date.parse("feb#{sep}2008") + d.year.should == 2008 + d.month.should == 2 + d.day.should == 1 + end + + it "can parse a 'DD mmm YYYY' string into a Date object" do + d = Date.parse("23#{sep}feb#{sep}2008") + d.year.should == 2008 + d.month.should == 2 + d.day.should == 23 + end + + it "can parse a 'mmm DD YYYY' string into a Date object" do + d = Date.parse("23#{sep}feb#{sep}2008") + d.year.should == 2008 + d.month.should == 2 + d.day.should == 23 + end + + it "can parse a 'YYYY mmm DD' string into a Date object" do + d = Date.parse("2008#{sep}feb#{sep}23") + d.year.should == 2008 + d.month.should == 2 + d.day.should == 23 + end + + it "can parse a month name and day into a Date object" do + d = Date.parse("november#{sep}5th") + d.should == Date.civil(Date.today.year, 11, 5) + end + + it "can parse a month name, day and year into a Date object" do + d = Date.parse("november#{sep}5th#{sep}2005") + d.should == Date.civil(2005, 11, 5) + end + + it "can parse a year, month name and day into a Date object" do + d = Date.parse("2005#{sep}november#{sep}5th") + d.should == Date.civil(2005, 11, 5) + end + + it "can parse a year, day and month name into a Date object" do + d = Date.parse("5th#{sep}november#{sep}2005") + d.should == Date.civil(2005, 11, 5) + end + + it "can handle negative year numbers" do + d = Date.parse("5th#{sep}november#{sep}-2005") + d.should == Date.civil(-2005, 11, 5) + end + + end + +end \ No newline at end of file diff --git a/1.8/library/date/shared/parse_eu.rb b/1.8/library/date/shared/parse_eu.rb new file mode 100644 index 0000000000..19f7332f6b --- /dev/null +++ b/1.8/library/date/shared/parse_eu.rb @@ -0,0 +1,35 @@ +shared :date_parse_eu do |sep| + + describe "Date#parse(#{sep})" do + # The - separator let's it work like European format, so it as a different spec + it "can parse a YYYY-MM-DD string into a Date object" do + d = Date.parse("2007#{sep}10#{sep}01") + d.year.should == 2007 + d.month.should == 10 + d.day.should == 1 + end + + it "can parse a MM-DD-YYYY string into a Date object" do + d = Date.parse("10#{sep}01#{sep}2007") + d.year.should == 2007 + d.month.should == 1 + d.day.should == 10 + end + + it "can parse a MM-DD-YY string into a Date object" do + d = Date.parse("10#{sep}01#{sep}07") + d.year.should == 10 + d.month.should == 1 + d.day.should == 7 + end + + it "can parse a MM-DD-YY string into a Date object using the year digits as 20XX" do + d = Date.parse("10#{sep}01#{sep}07", true) + d.year.should == 2010 + d.month.should == 1 + d.day.should == 7 + end + + end + +end \ No newline at end of file diff --git a/1.8/library/date/shared/parse_us.rb b/1.8/library/date/shared/parse_us.rb new file mode 100644 index 0000000000..b758fd32f7 --- /dev/null +++ b/1.8/library/date/shared/parse_us.rb @@ -0,0 +1,35 @@ +shared :date_parse_us do |sep| + + describe "Date#parse(#{sep})" do + # The - separator let's it work like European format, so it as a different spec + it "can parse a YYYY-MM-DD string into a Date object" do + d = Date.parse("2007#{sep}10#{sep}01") + d.year.should == 2007 + d.month.should == 10 + d.day.should == 1 + end + + it "can parse a MM-DD-YYYY string into a Date object" do + d = Date.parse("10#{sep}01#{sep}2007") + d.year.should == 2007 + d.month.should == 10 + d.day.should == 1 + end + + it "can parse a MM-DD-YY string into a Date object" do + d = Date.parse("10#{sep}01#{sep}07") + d.year.should == 7 + d.month.should == 10 + d.day.should == 1 + end + + it "can parse a MM-DD-YY string into a Date object using the year digits as 20XX" do + d = Date.parse("10#{sep}01#{sep}07", true) + d.year.should == 2007 + d.month.should == 10 + d.day.should == 1 + end + + end + +end \ No newline at end of file diff --git a/1.8/library/date/step_spec.rb b/1.8/library/date/step_spec.rb new file mode 100644 index 0000000000..ff1931ea22 --- /dev/null +++ b/1.8/library/date/step_spec.rb @@ -0,0 +1,56 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#step" do + + it "should be able to step forward in time" do + ds = Date.civil(2008, 10, 11) + de = Date.civil(2008, 9, 29) + count = 0 + de.step(ds) do |d| + d.should <= ds + d.should >= de + count += 1 + end + count.should == 13 + + count = 0 + de.step(ds, 5) do |d| + d.should <= ds + d.should >= de + count += 1 + end + count.should == 3 + + count = 0 + ds.step(de) do |d|; count += 1; end + count.should == 0 + + end + + it "should be able to step backward in time" do + ds = Date.civil(2000, 4, 14) + de = Date.civil(2000, 3, 29) + count = 0 + ds.step(de, -1) do |d| + d.should <= ds + d.should >= de + count += 1 + end + count.should == 17 + + count = 0 + ds.step(de, -5) do |d| + d.should <= ds + d.should >= de + count += 1 + end + count.should == 4 + + count = 0 + de.step(ds, -1) do |d|; count += 1; end + count.should == 0 + + end + +end \ No newline at end of file diff --git a/1.8/library/date/strftime_spec.rb b/1.8/library/date/strftime_spec.rb new file mode 100644 index 0000000000..356e0c22ca --- /dev/null +++ b/1.8/library/date/strftime_spec.rb @@ -0,0 +1,205 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#strftime" do + + it "should be able to print the date" do + Date.civil(2000, 4, 6).strftime.should == "2000-04-06" + Date.civil(2000, 4, 6).strftime.should == Date.civil(2000, 4, 6).to_s + end + + it "should be able to print the full day name" do + Date.civil(2000, 4, 6).strftime("%A").should == "Thursday" + end + + it "should be able to print the short day name" do + Date.civil(2000, 4, 6).strftime("%a").should == "Thu" + end + + it "should be able to print the full month name" do + Date.civil(2000, 4, 6).strftime("%B").should == "April" + end + + it "should be able to print the short month name" do + Date.civil(2000, 4, 6).strftime("%b").should == "Apr" + Date.civil(2000, 4, 6).strftime("%h").should == "Apr" + Date.civil(2000, 4, 6).strftime("%b").should == Date.civil(2000, 4, 6).strftime("%h") + end + + it "should be able to print the century" do + Date.civil(2000, 4, 6).strftime("%C").should == "20" + end + + it "should be able to print the month day with leading zeroes" do + Date.civil(2000, 4, 6).strftime("%d").should == "06" + end + + it "should be able to print the month day with leading spaces" do + Date.civil(2000, 4, 6).strftime("%e").should == " 6" + end + + it "should be able to print the commercial year with leading zeroes" do + Date.civil(2000, 4, 6).strftime("%G").should == "2000" + Date.civil( 200, 4, 6).strftime("%G").should == "0200" + end + + it "should be able to print the commercial year with only two digits" do + Date.civil(2000, 4, 6).strftime("%g").should == "00" + Date.civil( 200, 4, 6).strftime("%g").should == "00" + end + + it "should be able to print the hour with leading zeroes (hour is always 00)" do + Date.civil(2000, 4, 6).strftime("%H").should == "00" + end + + it "should be able to print the hour in 12 hour notation with leading zeroes" do + Date.civil(2000, 4, 6).strftime("%I").should == "12" + end + + it "should be able to print the year day with leading zeroes" do + Date.civil(2000, 4, 6).strftime("%j").should == "097" + end + + it "should be able to print the hour in 24 hour notation with leading spaces" do + Date.civil(2000, 4, 6).strftime("%k").should == " 0" + end + + it "should be able to print the hour in 12 hour notation with leading spaces" do + Date.civil(2000, 4, 6).strftime("%l").should == "12" + end + + it "should be able to print the minutes with leading zeroes" do + Date.civil(2000, 4, 6).strftime("%M").should == "00" + end + + it "should be able to print the month with leading zeroes" do + Date.civil(2000, 4, 6).strftime("%m").should == "04" + end + + it "should be able to add a newline" do + Date.civil(2000, 4, 6).strftime("%n").should == "\n" + end + + it "should be able to show AM/PM" do + Date.civil(2000, 4, 6).strftime("%P").should == "am" + end + + it "should be able to show am/pm" do + Date.civil(2000, 4, 6).strftime("%p").should == "AM" + end + + it "should be able to show the number of seconds with leading zeroes" do + Date.civil(2000, 4, 6).strftime("%S").should == "00" + end + + it "should be able to show the number of seconds with leading zeroes" do + Date.civil(2000, 4, 6).strftime("%S").should == "00" + end + + it "should be able to show the number of seconds since the unix epoch" do + Date.civil(2000, 4, 6).strftime("%s").should == "954979200" + end + + it "should be able to add a tab" do + Date.civil(2000, 4, 6).strftime("%t").should == "\t" + end + + it "should be able to show the week number with the week starting on sunday and monday" do + Date.civil(2000, 4, 6).strftime("%U").should == "14" + Date.civil(2000, 4, 6).strftime("%W").should == "14" + Date.civil(2000, 4, 6).strftime("%U").should == Date.civil(2000, 4, 6).strftime("%W") + Date.civil(2000, 4, 9).strftime("%U").should == "15" + Date.civil(2000, 4, 9).strftime("%W").should == "14" + Date.civil(2000, 4, 9).strftime("%U").should_not == Date.civil(2000, 4, 9).strftime("%W") + end + + it "should be able to show the commercial week day" do + Date.civil(2000, 4, 9).strftime("%u").should == "7" + Date.civil(2000, 4, 10).strftime("%u").should == "1" + end + + it "should be able to show the commercial week" do + Date.civil(2000, 4, 9).strftime("%V").should == "14" + Date.civil(2000, 4, 10).strftime("%V").should == "15" + end + + it "should be able to show the week day" do + Date.civil(2000, 4, 9).strftime("%w").should == "0" + Date.civil(2000, 4, 10).strftime("%w").should == "1" + end + + it "should be able to show the year in YYYY format" do + Date.civil(2000, 4, 9).strftime("%Y").should == "2000" + end + + it "should be able to show the year in YY format" do + Date.civil(2000, 4, 9).strftime("%y").should == "00" + end + + it "should be able to show the timezone of the date with a : separator" do + Date.civil(2000, 4, 9).strftime("%Z").should == "+00:00" + end + + it "should be able to show the timezone of the date with a : separator" do + Date.civil(2000, 4, 9).strftime("%z").should == "+0000" + end + + it "should be able to escape the % character" do + Date.civil(2000, 4, 9).strftime("%%").should == "%" + end + + ############################ + # Specs that combine stuff # + ############################ + + it "should be able to print the date in full" do + Date.civil(2000, 4, 6).strftime("%c").should == "Thu Apr 6 00:00:00 2000" + Date.civil(2000, 4, 6).strftime("%c").should == Date.civil(2000, 4, 6).strftime('%a %b %e %H:%M:%S %Y') + end + + it "should be able to print the date with slashes" do + Date.civil(2000, 4, 6).strftime("%D").should == "04/06/00" + Date.civil(2000, 4, 6).strftime("%D").should == Date.civil(2000, 4, 6).strftime('%m/%d/%y') + end + + it "should be able to print the date as YYYY-MM-DD" do + Date.civil(2000, 4, 6).strftime("%F").should == "2000-04-06" + Date.civil(2000, 4, 6).strftime("%F").should == Date.civil(2000, 4, 6).strftime('%Y-%m-%d') + end + + it "should be able to show HH:MM" do + Date.civil(2000, 4, 6).strftime("%R").should == "00:00" + Date.civil(2000, 4, 6).strftime("%R").should == Date.civil(2000, 4, 6).strftime('%H:%M') + end + + it "should be able to show HH:MM:SS AM/PM" do + Date.civil(2000, 4, 6).strftime("%r").should == "12:00:00 AM" + Date.civil(2000, 4, 6).strftime("%r").should == Date.civil(2000, 4, 6).strftime('%I:%M:%S %p') + end + + it "should be able to show HH:MM:SS" do + Date.civil(2000, 4, 6).strftime("%T").should == "00:00:00" + Date.civil(2000, 4, 6).strftime("%T").should == Date.civil(2000, 4, 6).strftime('%H:%M:%S') + end + + it "should be able to show the commercial week" do + Date.civil(2000, 4, 9).strftime("%v").should == " 9-Apr-2000" + Date.civil(2000, 4, 9).strftime("%v").should == Date.civil(2000, 4, 9).strftime('%e-%b-%Y') + end + + it "should be able to show HH:MM:SS" do + Date.civil(2000, 4, 6).strftime("%X").should == "00:00:00" + Date.civil(2000, 4, 6).strftime("%X").should == Date.civil(2000, 4, 6).strftime('%H:%M:%S') + end + + it "should be able to show MM/DD/YY" do + Date.civil(2000, 4, 6).strftime("%x").should == "04/06/00" + Date.civil(2000, 4, 6).strftime("%x").should == Date.civil(2000, 4, 6).strftime('%m/%d/%y') + end + + it "should be able to show a full notation" do + Date.civil(2000, 4, 9).strftime("%+").should == "Sun Apr 9 00:00:00 +00:00 2000" + Date.civil(2000, 4, 9).strftime("%+").should == Date.civil(2000, 4, 9).strftime('%a %b %e %H:%M:%S %Z %Y') + end + +end \ No newline at end of file diff --git a/1.8/library/date/strptime_spec.rb b/1.8/library/date/strptime_spec.rb new file mode 100644 index 0000000000..5a63ce26cc --- /dev/null +++ b/1.8/library/date/strptime_spec.rb @@ -0,0 +1,139 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#strftime" do + + it "should be able to parse without arguments" do + Date.strptime.should == Date.civil(-4712, 1, 1) + end + + it "should be able to parse the default date format" do + Date.strptime("2000-04-06").should == Date.civil(2000, 4, 6) + Date.civil(2000, 4, 6).strftime.should == Date.civil(2000, 4, 6).to_s + end + + it "should be able to parse the full day name" do + d = Date.today + # strptime assumed week that start on sunday, not monday + week = d.cweek + week += 1 if d.cwday == 7 + Date.strptime("Thursday", "%A").should == Date.commercial(d.cwyear, week, 4) + end + + it "should be able to parse the short day name" do + d = Date.today + # strptime assumed week that start on sunday, not monday + week = d.cweek + week += 1 if d.cwday == 7 + Date.strptime("Thu", "%a").should == Date.commercial(d.cwyear, week, 4) + end + + it "should be able to parse the full month name" do + d = Date.today + Date.strptime("April", "%B").should == Date.civil(d.year, 4, 1) + end + + it "should be able to parse the short month name" do + d = Date.today + Date.strptime("Apr", "%b").should == Date.civil(d.year, 4, 1) + Date.strptime("Apr", "%h").should == Date.civil(d.year, 4, 1) + end + + it "should be able to parse the century" do + Date.strptime("06 20", "%y %C").should == Date.civil(2006, 1, 1) + end + + it "should be able to parse the month day with leading zeroes" do + d = Date.today + Date.strptime("06", "%d").should == Date.civil(d.year, d.month, 6) + end + + it "should be able to parse the month day with leading spaces" do + d = Date.today + Date.strptime(" 6", "%e").should == Date.civil(d.year, d.month, 6) + end + + it "should be able to parse the commercial year with leading zeroes" do + Date.strptime("2000", "%G").should == Date.civil(2000, 1, 3) + Date.strptime("2002", "%G").should == Date.civil(2001, 12, 31) + end + + it "should be able to parse the commercial year with only two digits" do + Date.strptime("68", "%g").should == Date.civil(2068, 1, 2) + Date.strptime("69", "%g").should == Date.civil(1968, 12, 30) + end + + it "should be able to parse the year day with leading zeroes" do + d = Date.today + Date.strptime("097", "%j").should == Date.civil(2008, 4, 6) + end + + it "should be able to parse the month with leading zeroes" do + d = Date.today + Date.strptime("04", "%m").should == Date.civil(d.year, 4, 1) + end + + it "should be able to show the week number with the week starting on sunday and monday" do + d = Date.today + Date.strptime("14", "%U").should == Date.commercial(d.cwyear, 14, 7) + Date.strptime("14", "%W").should == Date.commercial(d.cwyear, 15, 7) + end + + it "should be able to show the commercial week day" do + Date.strptime("2008 1", "%G %u").should == Date.civil(2007, 12, 31) + end + + it "should be able to show the commercial week" do + d = Date.commercial(Date.today.year,1,1) + Date.strptime("1", "%V").should == d + Date.strptime("15", "%V").should == Date.commercial(d.cwyear, 15, 1) + end + + it "should be able to show the week day" do + d = Date.today + Date.strptime("2007 4", "%Y %w").should == Date.civil(2007, 1, 4) + end + + it "should be able to show the year in YYYY format" do + Date.strptime("2007", "%Y").should == Date.civil(2007, 1, 1) + end + + it "should be able to show the year in YY format" do + Date.strptime("00", "%y").should == Date.civil(2000, 1, 1) + end + + ############################ + # Specs that combine stuff # + ############################ + + it "should be able to parse the date in full" do + Date.strptime("Thu Apr 6 00:00:00 2000", "%c").should == Date.civil(2000, 4, 6) + Date.strptime("Thu Apr 6 00:00:00 2000", "%a %b %e %H:%M:%S %Y").should == Date.civil(2000, 4, 6) + end + + it "should be able to parse the date with slashes" do + Date.strptime("04/06/00", "%D").should == Date.civil(2000, 4, 6) + Date.strptime("04/06/00", "%m/%d/%y").should == Date.civil(2000, 4, 6) + end + + it "should be able to parse the date as YYYY-MM-DD" do + Date.strptime("2000-04-06", "%F").should == Date.civil(2000, 4, 6) + Date.strptime("2000-04-06", "%Y-%m-%d").should == Date.civil(2000, 4, 6) + end + + it "should be able to show the commercial week" do + Date.strptime(" 9-Apr-2000", "%v").should == Date.civil(2000, 4, 9) + Date.strptime(" 9-Apr-2000", "%e-%b-%Y").should == Date.civil(2000, 4, 9) + end + + it "should be able to show MM/DD/YY" do + Date.strptime("04/06/00", "%x").should == Date.civil(2000, 4, 6) + Date.strptime("04/06/00", "%m/%d/%y").should == Date.civil(2000, 4, 6) + end + + it "should be able to show a full notation" do + Date.strptime("Sun Apr 9 00:00:00 +00:00 2000", "%+").should == Date.civil(2000, 4, 9) + Date.strptime("Sun Apr 9 00:00:00 +00:00 2000", "%a %b %e %H:%M:%S %Z %Y").should == Date.civil(2000, 4, 9) + end + +end \ No newline at end of file diff --git a/1.8/library/date/upto_spec.rb b/1.8/library/date/upto_spec.rb new file mode 100644 index 0000000000..41c1733e87 --- /dev/null +++ b/1.8/library/date/upto_spec.rb @@ -0,0 +1,18 @@ +require 'date' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Date#upto" do + + it "should be able to step forward in time" do + ds = Date.civil(2008, 10, 11) + de = Date.civil(2008, 9, 29) + count = 0 + de.upto(ds) do |d| + d.should <= ds + d.should >= de + count += 1 + end + count.should == 13 + end + +end \ No newline at end of file diff --git a/1.8/library/digest/md5/append_spec.rb b/1.8/library/digest/md5/append_spec.rb new file mode 100644 index 0000000000..02a3355bd6 --- /dev/null +++ b/1.8/library/digest/md5/append_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/update' + +describe "Digest::MD5#<<" do + it_behaves_like(:md5_update, :<<) +end diff --git a/1.8/library/digest/md5/block_length_spec.rb b/1.8/library/digest/md5/block_length_spec.rb new file mode 100644 index 0000000000..61430d1811 --- /dev/null +++ b/1.8/library/digest/md5/block_length_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#block_length" do + + it 'returns the length of digest block' do + cur_digest = Digest::MD5.new + cur_digest.block_length.should == MD5Constants::BlockLength + end + +end + diff --git a/1.8/library/digest/md5/digest_bang_spec.rb b/1.8/library/digest/md5/digest_bang_spec.rb new file mode 100644 index 0000000000..45428a5782 --- /dev/null +++ b/1.8/library/digest/md5/digest_bang_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#digest!" do + + it 'returns a digest and can digest!' do + cur_digest = Digest::MD5.new + cur_digest << MD5Constants::Contents + cur_digest.digest!().should == MD5Constants::Digest + cur_digest.digest().should == MD5Constants::BlankDigest + end + +end diff --git a/1.8/library/digest/md5/digest_length_spec.rb b/1.8/library/digest/md5/digest_length_spec.rb new file mode 100644 index 0000000000..55ebd3e522 --- /dev/null +++ b/1.8/library/digest/md5/digest_length_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#digest_length" do + + it 'returns the length of computed digests' do + cur_digest = Digest::MD5.new + cur_digest.digest_length.should == MD5Constants::DigestLength + end + +end + diff --git a/1.8/library/digest/md5/digest_spec.rb b/1.8/library/digest/md5/digest_spec.rb new file mode 100644 index 0000000000..3833025403 --- /dev/null +++ b/1.8/library/digest/md5/digest_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#digest" do + + it 'returns a digest' do + cur_digest = Digest::MD5.new + cur_digest.digest().should == MD5Constants::BlankDigest + + # add something to check that the state is reset later + cur_digest << "test" + + cur_digest.digest(MD5Constants::Contents).should == MD5Constants::Digest + # second invocation is intentional, to make sure there are no side-effects + cur_digest.digest(MD5Constants::Contents).should == MD5Constants::Digest + + # after all is done, verify that the digest is in the original, blank state + cur_digest.digest.should == MD5Constants::BlankDigest + end + +end + +describe "Digest::MD5.digest" do + + it 'returns a digest' do + Digest::MD5.digest(MD5Constants::Contents).should == MD5Constants::Digest + # second invocation is intentional, to make sure there are no side-effects + Digest::MD5.digest(MD5Constants::Contents).should == MD5Constants::Digest + Digest::MD5.digest("").should == MD5Constants::BlankDigest + end + +end diff --git a/1.8/library/digest/md5/equal_spec.rb b/1.8/library/digest/md5/equal_spec.rb new file mode 100644 index 0000000000..ee6f7789c0 --- /dev/null +++ b/1.8/library/digest/md5/equal_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#==" do + + it 'should be equal to itself' do + cur_digest = Digest::MD5.new + cur_digest.should == cur_digest + end + + it 'should be equal to string representing its hexdigest' do + cur_digest = Digest::MD5.new + cur_digest.should == MD5Constants::BlankHexdigest + end + + it 'should be equal to appropriate object that responds to to_str' do + # blank digest + cur_digest = Digest::MD5.new + (obj = mock(MD5Constants::BlankHexdigest)).should_receive(:to_str).and_return(MD5Constants::BlankHexdigest) + cur_digest.should == obj + + # non-blank digest + cur_digest = Digest::MD5.new + cur_digest << "test" + d_value = cur_digest.hexdigest + (obj = mock(d_value)).should_receive(:to_str).and_return(d_value) + cur_digest.should == obj + end + + it 'should be equal for same digest different object' do + cur_digest = Digest::MD5.new + cur_digest2 = Digest::MD5.new + cur_digest.should == cur_digest2 + end + +end + diff --git a/1.8/library/digest/md5/hexdigest_bang_spec.rb b/1.8/library/digest/md5/hexdigest_bang_spec.rb new file mode 100644 index 0000000000..0348d2b6bd --- /dev/null +++ b/1.8/library/digest/md5/hexdigest_bang_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#hexdigest!" do + + it 'returns a hexdigest and resets the state' do + cur_digest = Digest::MD5.new + + cur_digest << MD5Constants::Contents + cur_digest.hexdigest!.should == MD5Constants::Hexdigest + cur_digest.hexdigest.should == MD5Constants::BlankHexdigest + end + +end diff --git a/1.8/library/digest/md5/hexdigest_spec.rb b/1.8/library/digest/md5/hexdigest_spec.rb new file mode 100644 index 0000000000..3d29c6664e --- /dev/null +++ b/1.8/library/digest/md5/hexdigest_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#hexdigest" do + + it 'returns a hexdigest' do + cur_digest = Digest::MD5.new + cur_digest.hexdigest.should == MD5Constants::BlankHexdigest + + # add something to check that the state is reset later + cur_digest << "test" + + cur_digest.hexdigest(MD5Constants::Contents).should == MD5Constants::Hexdigest + # second invocation is intentional, to make sure there are no side-effects + cur_digest.hexdigest(MD5Constants::Contents).should == MD5Constants::Hexdigest + + # after all is done, verify that the digest is in the original, blank state + cur_digest.hexdigest.should == MD5Constants::BlankHexdigest + end + +end + +describe "Digest::MD5.hexdigest" do + + it 'returns a hexdigest' do + Digest::MD5.hexdigest(MD5Constants::Contents).should == MD5Constants::Hexdigest + # second invocation is intentional, to make sure there are no side-effects + Digest::MD5.hexdigest(MD5Constants::Contents).should == MD5Constants::Hexdigest + Digest::MD5.hexdigest("").should == MD5Constants::BlankHexdigest + end + +end diff --git a/1.8/library/digest/md5/inspect_spec.rb b/1.8/library/digest/md5/inspect_spec.rb new file mode 100644 index 0000000000..185831ad95 --- /dev/null +++ b/1.8/library/digest/md5/inspect_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#inspect" do + + it 'returns a Ruby object representation' do + cur_digest = Digest::MD5.new + cur_digest.inspect.should == "#<#{MD5Constants::Klass}: #{cur_digest.hexdigest()}>" + end + +end + diff --git a/1.8/library/digest/md5/length_spec.rb b/1.8/library/digest/md5/length_spec.rb new file mode 100644 index 0000000000..86afd756b5 --- /dev/null +++ b/1.8/library/digest/md5/length_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/length' + +describe "Digest::MD5#length" do + it_behaves_like :md5_length, :length +end + diff --git a/1.8/library/digest/md5/reset_spec.rb b/1.8/library/digest/md5/reset_spec.rb new file mode 100644 index 0000000000..7938cb5def --- /dev/null +++ b/1.8/library/digest/md5/reset_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#reset" do + + it 'can returns digest state to initial conditions' do + cur_digest = Digest::MD5.new + cur_digest.update MD5Constants::Contents + cur_digest.digest().should_not == MD5Constants::BlankDigest + cur_digest.reset + cur_digest.digest().should == MD5Constants::BlankDigest + end + +end + diff --git a/1.8/library/digest/md5/shared/constants.rb b/1.8/library/digest/md5/shared/constants.rb new file mode 100644 index 0000000000..91d5465076 --- /dev/null +++ b/1.8/library/digest/md5/shared/constants.rb @@ -0,0 +1,15 @@ +require 'digest/md5' + +module MD5Constants + + Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + + Klass = ::Digest::MD5 + BlockLength = 64 + DigestLength = 16 + BlankDigest = "\324\035\214\331\217\000\262\004\351\200\t\230\354\370B~" + Digest = "\2473\267qw\276\364\343\345\320\304\350\313\314\217n" + BlankHexdigest = "d41d8cd98f00b204e9800998ecf8427e" + Hexdigest = "a733b77177bef4e3e5d0c4e8cbcc8f6e" + +end diff --git a/1.8/library/digest/md5/shared/length.rb b/1.8/library/digest/md5/shared/length.rb new file mode 100644 index 0000000000..7927a36147 --- /dev/null +++ b/1.8/library/digest/md5/shared/length.rb @@ -0,0 +1,14 @@ +shared :md5_length do |cmd| + + describe "Digest::MD5##{cmd}" do + + it 'returns the length of the digest' do + cur_digest = Digest::MD5.new + cur_digest.send(cmd).should == MD5Constants::BlankDigest.size + cur_digest << MD5Constants::Contents + cur_digest.send(cmd).should == MD5Constants::Digest.size + end + + end + +end diff --git a/1.8/library/digest/md5/shared/sample.rb b/1.8/library/digest/md5/shared/sample.rb new file mode 100644 index 0000000000..91d5465076 --- /dev/null +++ b/1.8/library/digest/md5/shared/sample.rb @@ -0,0 +1,15 @@ +require 'digest/md5' + +module MD5Constants + + Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + + Klass = ::Digest::MD5 + BlockLength = 64 + DigestLength = 16 + BlankDigest = "\324\035\214\331\217\000\262\004\351\200\t\230\354\370B~" + Digest = "\2473\267qw\276\364\343\345\320\304\350\313\314\217n" + BlankHexdigest = "d41d8cd98f00b204e9800998ecf8427e" + Hexdigest = "a733b77177bef4e3e5d0c4e8cbcc8f6e" + +end diff --git a/1.8/library/digest/md5/shared/update.rb b/1.8/library/digest/md5/shared/update.rb new file mode 100644 index 0000000000..25056be12b --- /dev/null +++ b/1.8/library/digest/md5/shared/update.rb @@ -0,0 +1,12 @@ +shared :md5_update do |cmd| + + describe "Digest::MD5##{cmd}" do + it 'can update' do + cur_digest = Digest::MD5.new + cur_digest.send cmd, MD5Constants::Contents + cur_digest.digest.should == MD5Constants::Digest + end + + end + +end diff --git a/1.8/library/digest/md5/size_spec.rb b/1.8/library/digest/md5/size_spec.rb new file mode 100644 index 0000000000..30a9b66700 --- /dev/null +++ b/1.8/library/digest/md5/size_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/length' + +describe "Digest::MD5#size" do + it_behaves_like :md5_length, :size +end + diff --git a/1.8/library/digest/md5/to_s_spec.rb b/1.8/library/digest/md5/to_s_spec.rb new file mode 100644 index 0000000000..5f2077a442 --- /dev/null +++ b/1.8/library/digest/md5/to_s_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'digest/md5' + +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::MD5#to_s" do + + it 'returns a hexdigest' do + cur_digest = Digest::MD5.new + cur_digest.to_s.should == MD5Constants::BlankHexdigest + end + + it 'does not change the internal state' do + cur_digest = Digest::MD5.new + cur_digest.to_s.should == MD5Constants::BlankHexdigest + cur_digest.to_s.should == MD5Constants::BlankHexdigest + + cur_digest << MD5Constants::Contents + cur_digest.to_s.should == MD5Constants::Hexdigest + cur_digest.to_s.should == MD5Constants::Hexdigest + end + +end diff --git a/1.8/library/digest/md5/update_spec.rb b/1.8/library/digest/md5/update_spec.rb new file mode 100644 index 0000000000..12ca44c247 --- /dev/null +++ b/1.8/library/digest/md5/update_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/update' + +describe "Digest::MD5#update" do + it_behaves_like :md5_update, :update +end diff --git a/1.8/library/digest/sha1/digest_spec.rb b/1.8/library/digest/sha1/digest_spec.rb new file mode 100644 index 0000000000..2b731d252b --- /dev/null +++ b/1.8/library/digest/sha1/digest_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA1#digest" do + + it 'returns a digest' do + cur_digest = Digest::SHA1.new + cur_digest.digest().should == SHA1Constants::BlankDigest + cur_digest.digest(SHA1Constants::Contents).should == SHA1Constants::Digest + end + +end + +describe "Digest::SHA1.digest" do + + it 'returns a digest' do + Digest::SHA1.digest(SHA1Constants::Contents).should == SHA1Constants::Digest + end + +end diff --git a/1.8/library/digest/sha1/shared/constants.rb b/1.8/library/digest/sha1/shared/constants.rb new file mode 100644 index 0000000000..ce55588193 --- /dev/null +++ b/1.8/library/digest/sha1/shared/constants.rb @@ -0,0 +1,15 @@ +require 'digest/sha1' + +module SHA1Constants + + Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + + Klass = ::Digest::SHA1 + BlockLength = 64 + DigestLength = 20 + BlankDigest = "\3329\243\356^kK\r2U\277\357\225`\030\220\257\330\a\t" + Digest = "X!\255b\323\035\352\314a|q\344+\376\317\361V9\324\343" + BlankHexdigest = "da39a3ee5e6b4b0d3255bfef95601890afd80709" + Hexdigest = "e907d2ba21c6c74bc0efd76e44d11fb9bbb7a75e" + +end diff --git a/1.8/library/digest/sha256/append_spec.rb b/1.8/library/digest/sha256/append_spec.rb new file mode 100644 index 0000000000..8532536972 --- /dev/null +++ b/1.8/library/digest/sha256/append_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/update' + +describe "Digest::SHA256#<<" do + it_behaves_like(:sha256_update, :<<) +end diff --git a/1.8/library/digest/sha256/block_length_spec.rb b/1.8/library/digest/sha256/block_length_spec.rb new file mode 100644 index 0000000000..ffd38bebde --- /dev/null +++ b/1.8/library/digest/sha256/block_length_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#block_length" do + + it 'returns the length of digest block' do + cur_digest = Digest::SHA256.new + cur_digest.block_length.should == SHA256Constants::BlockLength + end + +end + diff --git a/1.8/library/digest/sha256/digest_bang_spec.rb b/1.8/library/digest/sha256/digest_bang_spec.rb new file mode 100644 index 0000000000..ba99a30f1f --- /dev/null +++ b/1.8/library/digest/sha256/digest_bang_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#digest!" do + + it 'returns a digest and can digest!' do + cur_digest = Digest::SHA256.new + cur_digest << SHA256Constants::Contents + cur_digest.digest!().should == SHA256Constants::Digest + cur_digest.digest().should == SHA256Constants::BlankDigest + end + +end diff --git a/1.8/library/digest/sha256/digest_length_spec.rb b/1.8/library/digest/sha256/digest_length_spec.rb new file mode 100644 index 0000000000..69484fc6b9 --- /dev/null +++ b/1.8/library/digest/sha256/digest_length_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#digest_length" do + + it 'returns the length of computed digests' do + cur_digest = Digest::SHA256.new + cur_digest.digest_length.should == SHA256Constants::DigestLength + end + +end + diff --git a/1.8/library/digest/sha256/digest_spec.rb b/1.8/library/digest/sha256/digest_spec.rb new file mode 100644 index 0000000000..81a85a7b4a --- /dev/null +++ b/1.8/library/digest/sha256/digest_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#digest" do + + it 'returns a digest' do + cur_digest = Digest::SHA256.new + cur_digest.digest().should == SHA256Constants::BlankDigest + + # add something to check that the state is reset later + cur_digest << "test" + + cur_digest.digest(SHA256Constants::Contents).should == SHA256Constants::Digest + # second invocation is intentional, to make sure there are no side-effects + cur_digest.digest(SHA256Constants::Contents).should == SHA256Constants::Digest + + # after all is done, verify that the digest is in the original, blank state + cur_digest.digest.should == SHA256Constants::BlankDigest + end + +end + +describe "Digest::SHA256.digest" do + + it 'returns a digest' do + Digest::SHA256.digest(SHA256Constants::Contents).should == SHA256Constants::Digest + # second invocation is intentional, to make sure there are no side-effects + Digest::SHA256.digest(SHA256Constants::Contents).should == SHA256Constants::Digest + Digest::SHA256.digest("").should == SHA256Constants::BlankDigest + end + +end diff --git a/1.8/library/digest/sha256/equal_spec.rb b/1.8/library/digest/sha256/equal_spec.rb new file mode 100644 index 0000000000..43bcf10cac --- /dev/null +++ b/1.8/library/digest/sha256/equal_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#==" do + + it 'should be equal to itself' do + cur_digest = Digest::SHA256.new + cur_digest.should == cur_digest + end + + it 'should be equal to string representing its hexdigest' do + cur_digest = Digest::SHA256.new + cur_digest.should == SHA256Constants::BlankHexdigest + end + + it 'should be equal to appropriate object that responds to to_str' do + # blank digest + cur_digest = Digest::SHA256.new + (obj = mock(SHA256Constants::BlankHexdigest)).should_receive(:to_str).and_return(SHA256Constants::BlankHexdigest) + cur_digest.should == obj + + # non-blank digest + cur_digest = Digest::SHA256.new + cur_digest << "test" + d_value = cur_digest.hexdigest + (obj = mock(d_value)).should_receive(:to_str).and_return(d_value) + cur_digest.should == obj + end + + it 'should be equal for same digest different object' do + cur_digest = Digest::SHA256.new + cur_digest2 = Digest::SHA256.new + cur_digest.should == cur_digest2 + end + +end + diff --git a/1.8/library/digest/sha256/hexdigest_bang_spec.rb b/1.8/library/digest/sha256/hexdigest_bang_spec.rb new file mode 100644 index 0000000000..706eb9c3b0 --- /dev/null +++ b/1.8/library/digest/sha256/hexdigest_bang_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#hexdigest!" do + + it 'returns a hexdigest and resets the state' do + cur_digest = Digest::SHA256.new + + cur_digest << SHA256Constants::Contents + cur_digest.hexdigest!.should == SHA256Constants::Hexdigest + cur_digest.hexdigest.should == SHA256Constants::BlankHexdigest + end + +end diff --git a/1.8/library/digest/sha256/hexdigest_spec.rb b/1.8/library/digest/sha256/hexdigest_spec.rb new file mode 100644 index 0000000000..3ab6ce908b --- /dev/null +++ b/1.8/library/digest/sha256/hexdigest_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#hexdigest" do + + it 'returns a hexdigest' do + cur_digest = Digest::SHA256.new + cur_digest.hexdigest.should == SHA256Constants::BlankHexdigest + + # add something to check that the state is reset later + cur_digest << "test" + + cur_digest.hexdigest(SHA256Constants::Contents).should == SHA256Constants::Hexdigest + # second invocation is intentional, to make sure there are no side-effects + cur_digest.hexdigest(SHA256Constants::Contents).should == SHA256Constants::Hexdigest + + # after all is done, verify that the digest is in the original, blank state + cur_digest.hexdigest.should == SHA256Constants::BlankHexdigest + end + +end + +describe "Digest::SHA256.hexdigest" do + + it 'returns a hexdigest' do + Digest::SHA256.hexdigest(SHA256Constants::Contents).should == SHA256Constants::Hexdigest + # second invocation is intentional, to make sure there are no side-effects + Digest::SHA256.hexdigest(SHA256Constants::Contents).should == SHA256Constants::Hexdigest + Digest::SHA256.hexdigest("").should == SHA256Constants::BlankHexdigest + end + +end diff --git a/1.8/library/digest/sha256/inspect_spec.rb b/1.8/library/digest/sha256/inspect_spec.rb new file mode 100644 index 0000000000..cd8ac82152 --- /dev/null +++ b/1.8/library/digest/sha256/inspect_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#inspect" do + + it 'returns a Ruby object representation' do + cur_digest = Digest::SHA256.new + cur_digest.inspect.should == "#<#{SHA256Constants::Klass}: #{cur_digest.hexdigest()}>" + end + +end + diff --git a/1.8/library/digest/sha256/length_spec.rb b/1.8/library/digest/sha256/length_spec.rb new file mode 100644 index 0000000000..190123a87b --- /dev/null +++ b/1.8/library/digest/sha256/length_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/length' + +describe "Digest::SHA256#length" do + it_behaves_like :sha256_length, :length +end + diff --git a/1.8/library/digest/sha256/reset_spec.rb b/1.8/library/digest/sha256/reset_spec.rb new file mode 100644 index 0000000000..5a3eecb34a --- /dev/null +++ b/1.8/library/digest/sha256/reset_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#reset" do + + it 'can returns digest state to initial conditions' do + cur_digest = Digest::SHA256.new + cur_digest.update SHA256Constants::Contents + cur_digest.digest().should_not == SHA256Constants::BlankDigest + cur_digest.reset + cur_digest.digest().should == SHA256Constants::BlankDigest + end + +end + diff --git a/1.8/library/digest/sha256/shared/constants.rb b/1.8/library/digest/sha256/shared/constants.rb new file mode 100644 index 0000000000..ee9e407cd6 --- /dev/null +++ b/1.8/library/digest/sha256/shared/constants.rb @@ -0,0 +1,15 @@ +require 'digest/sha2' + +module SHA256Constants + + Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + + Klass = ::Digest::SHA256 + BlockLength = 64 + DigestLength = 32 + BlankDigest = "\343\260\304B\230\374\034\024\232\373\364\310\231o\271$'\256A\344d\233\223L\244\225\231\exR\270U" + Digest = "\230b\265\344_\337\357\337\242\004\314\311A\211jb\350\373\254\370\365M\230B\002\372\020j\as\270\376" + BlankHexdigest = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + Hexdigest = "9862b5e45fdfefdfa204ccc941896a62e8fbacf8f54d984202fa106a0773b8fe" + +end diff --git a/1.8/library/digest/sha256/shared/length.rb b/1.8/library/digest/sha256/shared/length.rb new file mode 100644 index 0000000000..f3ef944155 --- /dev/null +++ b/1.8/library/digest/sha256/shared/length.rb @@ -0,0 +1,14 @@ +shared :sha256_length do |cmd| + + describe "Digest::SHA256##{cmd}" do + + it 'returns the length of the digest' do + cur_digest = Digest::SHA256.new + cur_digest.send(cmd).should == SHA256Constants::BlankDigest.size + cur_digest << SHA256Constants::Contents + cur_digest.send(cmd).should == SHA256Constants::Digest.size + end + + end + +end diff --git a/1.8/library/digest/sha256/shared/update.rb b/1.8/library/digest/sha256/shared/update.rb new file mode 100644 index 0000000000..58dbc6da85 --- /dev/null +++ b/1.8/library/digest/sha256/shared/update.rb @@ -0,0 +1,12 @@ +shared :sha256_update do |cmd| + + describe "Digest::SHA256##{cmd}" do + it 'can update' do + cur_digest = Digest::SHA256.new + cur_digest.send cmd, SHA256Constants::Contents + cur_digest.digest.should == SHA256Constants::Digest + end + + end + +end diff --git a/1.8/library/digest/sha256/size_spec.rb b/1.8/library/digest/sha256/size_spec.rb new file mode 100644 index 0000000000..63c6e61798 --- /dev/null +++ b/1.8/library/digest/sha256/size_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/length' + +describe "Digest::SHA256#size" do + it_behaves_like :sha256_length, :size +end + diff --git a/1.8/library/digest/sha256/to_s_spec.rb b/1.8/library/digest/sha256/to_s_spec.rb new file mode 100644 index 0000000000..e60adb2d3c --- /dev/null +++ b/1.8/library/digest/sha256/to_s_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA256#to_s" do + + it 'returns a hexdigest' do + cur_digest = Digest::SHA256.new + cur_digest.to_s.should == SHA256Constants::BlankHexdigest + end + + it 'does not change the internal state' do + cur_digest = Digest::SHA256.new + cur_digest.to_s.should == SHA256Constants::BlankHexdigest + cur_digest.to_s.should == SHA256Constants::BlankHexdigest + + cur_digest << SHA256Constants::Contents + cur_digest.to_s.should == SHA256Constants::Hexdigest + cur_digest.to_s.should == SHA256Constants::Hexdigest + end + +end diff --git a/1.8/library/digest/sha256/update_spec.rb b/1.8/library/digest/sha256/update_spec.rb new file mode 100644 index 0000000000..caedfd5884 --- /dev/null +++ b/1.8/library/digest/sha256/update_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/update' + +describe "Digest::SHA256#update" do + it_behaves_like :sha256_update, :update +end diff --git a/1.8/library/digest/sha384/append_spec.rb b/1.8/library/digest/sha384/append_spec.rb new file mode 100644 index 0000000000..1626cc10ed --- /dev/null +++ b/1.8/library/digest/sha384/append_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/update' + +describe "Digest::SHA384#<<" do + it_behaves_like(:sha384_update, :<<) +end diff --git a/1.8/library/digest/sha384/block_length_spec.rb b/1.8/library/digest/sha384/block_length_spec.rb new file mode 100644 index 0000000000..d201886791 --- /dev/null +++ b/1.8/library/digest/sha384/block_length_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#block_length" do + + it 'returns the length of digest block' do + cur_digest = Digest::SHA384.new + cur_digest.block_length.should == SHA384Constants::BlockLength + end + +end + diff --git a/1.8/library/digest/sha384/digest_bang_spec.rb b/1.8/library/digest/sha384/digest_bang_spec.rb new file mode 100644 index 0000000000..5a9f9a83da --- /dev/null +++ b/1.8/library/digest/sha384/digest_bang_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#digest!" do + + it 'returns a digest and can digest!' do + cur_digest = Digest::SHA384.new + cur_digest << SHA384Constants::Contents + cur_digest.digest!().should == SHA384Constants::Digest + cur_digest.digest().should == SHA384Constants::BlankDigest + end + +end diff --git a/1.8/library/digest/sha384/digest_length_spec.rb b/1.8/library/digest/sha384/digest_length_spec.rb new file mode 100644 index 0000000000..bd21c7e27d --- /dev/null +++ b/1.8/library/digest/sha384/digest_length_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#digest_length" do + + it 'returns the length of computed digests' do + cur_digest = Digest::SHA384.new + cur_digest.digest_length.should == SHA384Constants::DigestLength + end + +end + diff --git a/1.8/library/digest/sha384/digest_spec.rb b/1.8/library/digest/sha384/digest_spec.rb new file mode 100644 index 0000000000..a43dca2b79 --- /dev/null +++ b/1.8/library/digest/sha384/digest_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#digest" do + + it 'returns a digest' do + cur_digest = Digest::SHA384.new + cur_digest.digest().should == SHA384Constants::BlankDigest + + # add something to check that the state is reset later + cur_digest << "test" + + cur_digest.digest(SHA384Constants::Contents).should == SHA384Constants::Digest + # second invocation is intentional, to make sure there are no side-effects + cur_digest.digest(SHA384Constants::Contents).should == SHA384Constants::Digest + + # after all is done, verify that the digest is in the original, blank state + cur_digest.digest.should == SHA384Constants::BlankDigest + end + +end + +describe "Digest::SHA384.digest" do + + it 'returns a digest' do + Digest::SHA384.digest(SHA384Constants::Contents).should == SHA384Constants::Digest + # second invocation is intentional, to make sure there are no side-effects + Digest::SHA384.digest(SHA384Constants::Contents).should == SHA384Constants::Digest + Digest::SHA384.digest("").should == SHA384Constants::BlankDigest + end + +end diff --git a/1.8/library/digest/sha384/equal_spec.rb b/1.8/library/digest/sha384/equal_spec.rb new file mode 100644 index 0000000000..0dacf4b07e --- /dev/null +++ b/1.8/library/digest/sha384/equal_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#==" do + + it 'should be equal to itself' do + cur_digest = Digest::SHA384.new + cur_digest.should == cur_digest + end + + it 'should be equal to string representing its hexdigest' do + cur_digest = Digest::SHA384.new + cur_digest.should == SHA384Constants::BlankHexdigest + end + + it 'should be equal to appropriate object that responds to to_str' do + # blank digest + cur_digest = Digest::SHA384.new + (obj = mock(SHA384Constants::BlankHexdigest)).should_receive(:to_str).and_return(SHA384Constants::BlankHexdigest) + cur_digest.should == obj + + # non-blank digest + cur_digest = Digest::SHA384.new + cur_digest << "test" + d_value = cur_digest.hexdigest + (obj = mock(d_value)).should_receive(:to_str).and_return(d_value) + cur_digest.should == obj + end + + it 'should be equal for same digest different object' do + cur_digest = Digest::SHA384.new + cur_digest2 = Digest::SHA384.new + cur_digest.should == cur_digest2 + end + +end + diff --git a/1.8/library/digest/sha384/hexdigest_bang_spec.rb b/1.8/library/digest/sha384/hexdigest_bang_spec.rb new file mode 100644 index 0000000000..db47f0f12e --- /dev/null +++ b/1.8/library/digest/sha384/hexdigest_bang_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#hexdigest!" do + + it 'returns a hexdigest and resets the state' do + cur_digest = Digest::SHA384.new + + cur_digest << SHA384Constants::Contents + cur_digest.hexdigest!.should == SHA384Constants::Hexdigest + cur_digest.hexdigest.should == SHA384Constants::BlankHexdigest + end + +end diff --git a/1.8/library/digest/sha384/hexdigest_spec.rb b/1.8/library/digest/sha384/hexdigest_spec.rb new file mode 100644 index 0000000000..d1904b9770 --- /dev/null +++ b/1.8/library/digest/sha384/hexdigest_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#hexdigest" do + + it 'returns a hexdigest' do + cur_digest = Digest::SHA384.new + cur_digest.hexdigest.should == SHA384Constants::BlankHexdigest + + # add something to check that the state is reset later + cur_digest << "test" + + cur_digest.hexdigest(SHA384Constants::Contents).should == SHA384Constants::Hexdigest + # second invocation is intentional, to make sure there are no side-effects + cur_digest.hexdigest(SHA384Constants::Contents).should == SHA384Constants::Hexdigest + + # after all is done, verify that the digest is in the original, blank state + cur_digest.hexdigest.should == SHA384Constants::BlankHexdigest + end + +end + +describe "Digest::SHA384.hexdigest" do + + it 'returns a hexdigest' do + Digest::SHA384.hexdigest(SHA384Constants::Contents).should == SHA384Constants::Hexdigest + # second invocation is intentional, to make sure there are no side-effects + Digest::SHA384.hexdigest(SHA384Constants::Contents).should == SHA384Constants::Hexdigest + Digest::SHA384.hexdigest("").should == SHA384Constants::BlankHexdigest + end + +end diff --git a/1.8/library/digest/sha384/inspect_spec.rb b/1.8/library/digest/sha384/inspect_spec.rb new file mode 100644 index 0000000000..86b89310f9 --- /dev/null +++ b/1.8/library/digest/sha384/inspect_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#inspect" do + + it 'returns a Ruby object representation' do + cur_digest = Digest::SHA384.new + cur_digest.inspect.should == "#<#{SHA384Constants::Klass}: #{cur_digest.hexdigest()}>" + end + +end + diff --git a/1.8/library/digest/sha384/length_spec.rb b/1.8/library/digest/sha384/length_spec.rb new file mode 100644 index 0000000000..64ea505307 --- /dev/null +++ b/1.8/library/digest/sha384/length_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/length' + +describe "Digest::SHA384#length" do + it_behaves_like :sha384_length, :length +end + diff --git a/1.8/library/digest/sha384/reset_spec.rb b/1.8/library/digest/sha384/reset_spec.rb new file mode 100644 index 0000000000..e188e97970 --- /dev/null +++ b/1.8/library/digest/sha384/reset_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#reset" do + + it 'can returns digest state to initial conditions' do + cur_digest = Digest::SHA384.new + cur_digest.update SHA384Constants::Contents + cur_digest.digest().should_not == SHA384Constants::BlankDigest + cur_digest.reset + cur_digest.digest().should == SHA384Constants::BlankDigest + end + +end + diff --git a/1.8/library/digest/sha384/shared/constants.rb b/1.8/library/digest/sha384/shared/constants.rb new file mode 100644 index 0000000000..149a1fc9dd --- /dev/null +++ b/1.8/library/digest/sha384/shared/constants.rb @@ -0,0 +1,16 @@ +require 'digest/sha2' + +module SHA384Constants + + Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + + + Klass = ::Digest::SHA384 + BlockLength = 128 + DigestLength = 48 + BlankDigest = "8\260`\247Q\254\2268L\3312~\261\261\343j!\375\267\021\024\276\aCL\f\307\277c\366\341\332'N\336\277\347oe\373\325\032\322\361H\230\271[" + Digest = "B&\266:\314\216z\361!TD\001{`\355\323\320MW%\270\272\0034n\034\026g\a\217\"\333s\202\275\002Y*\217]\207u\f\034\244\231\266f" + BlankHexdigest = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b" + Hexdigest = "4226b63acc8e7af1215444017b60edd3d04d5725b8ba03346e1c1667078f22db7382bd02592a8f5d87750c1ca499b666" + +end diff --git a/1.8/library/digest/sha384/shared/length.rb b/1.8/library/digest/sha384/shared/length.rb new file mode 100644 index 0000000000..6148132dd8 --- /dev/null +++ b/1.8/library/digest/sha384/shared/length.rb @@ -0,0 +1,14 @@ +shared :sha384_length do |cmd| + + describe "Digest::SHA384##{cmd}" do + + it 'returns the length of the digest' do + cur_digest = Digest::SHA384.new + cur_digest.send(cmd).should == SHA384Constants::BlankDigest.size + cur_digest << SHA384Constants::Contents + cur_digest.send(cmd).should == SHA384Constants::Digest.size + end + + end + +end diff --git a/1.8/library/digest/sha384/shared/update.rb b/1.8/library/digest/sha384/shared/update.rb new file mode 100644 index 0000000000..ebc61f7cab --- /dev/null +++ b/1.8/library/digest/sha384/shared/update.rb @@ -0,0 +1,12 @@ +shared :sha384_update do |cmd| + + describe "Digest::SHA384##{cmd}" do + it 'can update' do + cur_digest = Digest::SHA384.new + cur_digest.send cmd, SHA384Constants::Contents + cur_digest.digest.should == SHA384Constants::Digest + end + + end + +end diff --git a/1.8/library/digest/sha384/size_spec.rb b/1.8/library/digest/sha384/size_spec.rb new file mode 100644 index 0000000000..f68acfc8d3 --- /dev/null +++ b/1.8/library/digest/sha384/size_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/length' + +describe "Digest::SHA384#size" do + it_behaves_like :sha384_length, :size +end + diff --git a/1.8/library/digest/sha384/to_s_spec.rb b/1.8/library/digest/sha384/to_s_spec.rb new file mode 100644 index 0000000000..6852bbd565 --- /dev/null +++ b/1.8/library/digest/sha384/to_s_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA384#to_s" do + + it 'returns a hexdigest' do + cur_digest = Digest::SHA384.new + cur_digest.to_s.should == SHA384Constants::BlankHexdigest + end + + it 'does not change the internal state' do + cur_digest = Digest::SHA384.new + cur_digest.to_s.should == SHA384Constants::BlankHexdigest + cur_digest.to_s.should == SHA384Constants::BlankHexdigest + + cur_digest << SHA384Constants::Contents + cur_digest.to_s.should == SHA384Constants::Hexdigest + cur_digest.to_s.should == SHA384Constants::Hexdigest + end + +end diff --git a/1.8/library/digest/sha384/update_spec.rb b/1.8/library/digest/sha384/update_spec.rb new file mode 100644 index 0000000000..5690ad9877 --- /dev/null +++ b/1.8/library/digest/sha384/update_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/update' + +describe "Digest::SHA384#update" do + it_behaves_like :sha384_update, :update +end diff --git a/1.8/library/digest/sha512/append_spec.rb b/1.8/library/digest/sha512/append_spec.rb new file mode 100644 index 0000000000..cf0e73bc30 --- /dev/null +++ b/1.8/library/digest/sha512/append_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/update' + +describe "Digest::SHA512#<<" do + it_behaves_like(:sha512_update, :<<) +end diff --git a/1.8/library/digest/sha512/block_length_spec.rb b/1.8/library/digest/sha512/block_length_spec.rb new file mode 100644 index 0000000000..4873a4f532 --- /dev/null +++ b/1.8/library/digest/sha512/block_length_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#block_length" do + + it 'returns the length of digest block' do + cur_digest = Digest::SHA512.new + cur_digest.block_length.should == SHA512Constants::BlockLength + end + +end + diff --git a/1.8/library/digest/sha512/digest_bang_spec.rb b/1.8/library/digest/sha512/digest_bang_spec.rb new file mode 100644 index 0000000000..a9577d4bab --- /dev/null +++ b/1.8/library/digest/sha512/digest_bang_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#digest!" do + + it 'returns a digest and can digest!' do + cur_digest = Digest::SHA512.new + cur_digest << SHA512Constants::Contents + cur_digest.digest!().should == SHA512Constants::Digest + cur_digest.digest().should == SHA512Constants::BlankDigest + end + +end diff --git a/1.8/library/digest/sha512/digest_length_spec.rb b/1.8/library/digest/sha512/digest_length_spec.rb new file mode 100644 index 0000000000..10f62ca929 --- /dev/null +++ b/1.8/library/digest/sha512/digest_length_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#digest_length" do + + it 'returns the length of computed digests' do + cur_digest = Digest::SHA512.new + cur_digest.digest_length.should == SHA512Constants::DigestLength + end + +end + diff --git a/1.8/library/digest/sha512/digest_spec.rb b/1.8/library/digest/sha512/digest_spec.rb new file mode 100644 index 0000000000..9cd2a7ca4b --- /dev/null +++ b/1.8/library/digest/sha512/digest_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#digest" do + + it 'returns a digest' do + cur_digest = Digest::SHA512.new + cur_digest.digest().should == SHA512Constants::BlankDigest + + # add something to check that the state is reset later + cur_digest << "test" + + cur_digest.digest(SHA512Constants::Contents).should == SHA512Constants::Digest + # second invocation is intentional, to make sure there are no side-effects + cur_digest.digest(SHA512Constants::Contents).should == SHA512Constants::Digest + + # after all is done, verify that the digest is in the original, blank state + cur_digest.digest.should == SHA512Constants::BlankDigest + end + +end + +describe "Digest::SHA512.digest" do + + it 'returns a digest' do + Digest::SHA512.digest(SHA512Constants::Contents).should == SHA512Constants::Digest + # second invocation is intentional, to make sure there are no side-effects + Digest::SHA512.digest(SHA512Constants::Contents).should == SHA512Constants::Digest + Digest::SHA512.digest("").should == SHA512Constants::BlankDigest + end + +end diff --git a/1.8/library/digest/sha512/equal_spec.rb b/1.8/library/digest/sha512/equal_spec.rb new file mode 100644 index 0000000000..27b9e9321d --- /dev/null +++ b/1.8/library/digest/sha512/equal_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#==" do + + it 'should be equal to itself' do + cur_digest = Digest::SHA512.new + cur_digest.should == cur_digest + end + + it 'should be equal to string representing its hexdigest' do + cur_digest = Digest::SHA512.new + cur_digest.should == SHA512Constants::BlankHexdigest + end + + it 'should be equal to appropriate object that responds to to_str' do + # blank digest + cur_digest = Digest::SHA512.new + (obj = mock(SHA512Constants::BlankHexdigest)).should_receive(:to_str).and_return(SHA512Constants::BlankHexdigest) + cur_digest.should == obj + + # non-blank digest + cur_digest = Digest::SHA512.new + cur_digest << "test" + d_value = cur_digest.hexdigest + (obj = mock(d_value)).should_receive(:to_str).and_return(d_value) + cur_digest.should == obj + end + + it 'should be equal for same digest different object' do + cur_digest = Digest::SHA512.new + cur_digest2 = Digest::SHA512.new + cur_digest.should == cur_digest2 + end + +end + diff --git a/1.8/library/digest/sha512/hexdigest_bang_spec.rb b/1.8/library/digest/sha512/hexdigest_bang_spec.rb new file mode 100644 index 0000000000..edd6fad5c6 --- /dev/null +++ b/1.8/library/digest/sha512/hexdigest_bang_spec.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#hexdigest!" do + + it 'returns a hexdigest and resets the state' do + cur_digest = Digest::SHA512.new + + cur_digest << SHA512Constants::Contents + cur_digest.hexdigest!.should == SHA512Constants::Hexdigest + cur_digest.hexdigest.should == SHA512Constants::BlankHexdigest + end + +end diff --git a/1.8/library/digest/sha512/hexdigest_spec.rb b/1.8/library/digest/sha512/hexdigest_spec.rb new file mode 100644 index 0000000000..6a2a55d684 --- /dev/null +++ b/1.8/library/digest/sha512/hexdigest_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#hexdigest" do + + it 'returns a hexdigest' do + cur_digest = Digest::SHA512.new + cur_digest.hexdigest.should == SHA512Constants::BlankHexdigest + + # add something to check that the state is reset later + cur_digest << "test" + + cur_digest.hexdigest(SHA512Constants::Contents).should == SHA512Constants::Hexdigest + # second invocation is intentional, to make sure there are no side-effects + cur_digest.hexdigest(SHA512Constants::Contents).should == SHA512Constants::Hexdigest + + # after all is done, verify that the digest is in the original, blank state + cur_digest.hexdigest.should == SHA512Constants::BlankHexdigest + end + +end + +describe "Digest::SHA512.hexdigest" do + + it 'returns a hexdigest' do + Digest::SHA512.hexdigest(SHA512Constants::Contents).should == SHA512Constants::Hexdigest + # second invocation is intentional, to make sure there are no side-effects + Digest::SHA512.hexdigest(SHA512Constants::Contents).should == SHA512Constants::Hexdigest + Digest::SHA512.hexdigest("").should == SHA512Constants::BlankHexdigest + end + +end diff --git a/1.8/library/digest/sha512/inspect_spec.rb b/1.8/library/digest/sha512/inspect_spec.rb new file mode 100644 index 0000000000..b8e142e498 --- /dev/null +++ b/1.8/library/digest/sha512/inspect_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#inspect" do + + it 'returns a Ruby object representation' do + cur_digest = Digest::SHA512.new + cur_digest.inspect.should == "#<#{SHA512Constants::Klass}: #{cur_digest.hexdigest()}>" + end + +end + diff --git a/1.8/library/digest/sha512/length_spec.rb b/1.8/library/digest/sha512/length_spec.rb new file mode 100644 index 0000000000..56bd419e80 --- /dev/null +++ b/1.8/library/digest/sha512/length_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/length' + +describe "Digest::SHA512#length" do + it_behaves_like :sha512_length, :length +end + diff --git a/1.8/library/digest/sha512/reset_spec.rb b/1.8/library/digest/sha512/reset_spec.rb new file mode 100644 index 0000000000..3caa0156df --- /dev/null +++ b/1.8/library/digest/sha512/reset_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#reset" do + + it 'can returns digest state to initial conditions' do + cur_digest = Digest::SHA512.new + cur_digest.update SHA512Constants::Contents + cur_digest.digest().should_not == SHA512Constants::BlankDigest + cur_digest.reset + cur_digest.digest().should == SHA512Constants::BlankDigest + end + +end + diff --git a/1.8/library/digest/sha512/shared/constants.rb b/1.8/library/digest/sha512/shared/constants.rb new file mode 100644 index 0000000000..908113ea71 --- /dev/null +++ b/1.8/library/digest/sha512/shared/constants.rb @@ -0,0 +1,15 @@ +require 'digest/sha2' + +module SHA512Constants + + Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + + Klass = ::Digest::SHA512 + BlockLength = 128 + DigestLength = 64 + BlankDigest = "\317\203\3415~\357\270\275\361T(P\326m\200\a\326 \344\005\vW\025\334\203\364\251!\323l\351\316G\320\321<]\205\362\260\377\203\030\322\207~\354/c\2711\275GAz\201\24582z\371'\332>" + Digest = "\241\231\232\365\002z\241\331\242\310=\367F\272\004\326\331g\315n\251Q\222\250\374E\257\254=\325\225\003SM\350\244\234\220\233=\031\230A;\000\203\233\340\323t\333\271\222w\266\307\2678\344\255j\003\216\300" + BlankHexdigest = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + Hexdigest = "a1999af5027aa1d9a2c83df746ba04d6d967cd6ea95192a8fc45afac3dd59503534de8a49c909b3d1998413b00839be0d374dbb99277b6c7b738e4ad6a038ec0" + +end diff --git a/1.8/library/digest/sha512/shared/length.rb b/1.8/library/digest/sha512/shared/length.rb new file mode 100644 index 0000000000..f275bc5fa0 --- /dev/null +++ b/1.8/library/digest/sha512/shared/length.rb @@ -0,0 +1,14 @@ +shared :sha512_length do |cmd| + + describe "Digest::SHA512##{cmd}" do + + it 'returns the length of the digest' do + cur_digest = Digest::SHA512.new + cur_digest.send(cmd).should == SHA512Constants::BlankDigest.size + cur_digest << SHA512Constants::Contents + cur_digest.send(cmd).should == SHA512Constants::Digest.size + end + + end + +end diff --git a/1.8/library/digest/sha512/shared/update.rb b/1.8/library/digest/sha512/shared/update.rb new file mode 100644 index 0000000000..0abe19574e --- /dev/null +++ b/1.8/library/digest/sha512/shared/update.rb @@ -0,0 +1,12 @@ +shared :sha512_update do |cmd| + + describe "Digest::SHA512##{cmd}" do + it 'can update' do + cur_digest = Digest::SHA512.new + cur_digest.send cmd, SHA512Constants::Contents + cur_digest.digest.should == SHA512Constants::Digest + end + + end + +end diff --git a/1.8/library/digest/sha512/size_spec.rb b/1.8/library/digest/sha512/size_spec.rb new file mode 100644 index 0000000000..7f8ecfd40f --- /dev/null +++ b/1.8/library/digest/sha512/size_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/length' + +describe "Digest::SHA512#size" do + it_behaves_like :sha512_length, :size +end + diff --git a/1.8/library/digest/sha512/to_s_spec.rb b/1.8/library/digest/sha512/to_s_spec.rb new file mode 100644 index 0000000000..b9d1894fa9 --- /dev/null +++ b/1.8/library/digest/sha512/to_s_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' + +describe "Digest::SHA512#to_s" do + + it 'returns a hexdigest' do + cur_digest = Digest::SHA512.new + cur_digest.to_s.should == SHA512Constants::BlankHexdigest + end + + it 'does not change the internal state' do + cur_digest = Digest::SHA512.new + cur_digest.to_s.should == SHA512Constants::BlankHexdigest + cur_digest.to_s.should == SHA512Constants::BlankHexdigest + + cur_digest << SHA512Constants::Contents + cur_digest.to_s.should == SHA512Constants::Hexdigest + cur_digest.to_s.should == SHA512Constants::Hexdigest + end + +end diff --git a/1.8/library/digest/sha512/update_spec.rb b/1.8/library/digest/sha512/update_spec.rb new file mode 100644 index 0000000000..fff7829f4e --- /dev/null +++ b/1.8/library/digest/sha512/update_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/constants' +require File.dirname(__FILE__) + '/shared/update' + +describe "Digest::SHA512#update" do + it_behaves_like :sha512_update, :update +end diff --git a/1.8/library/drb/config_spec.rb b/1.8/library/drb/config_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/config_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/current_server_spec.rb b/1.8/library/drb/current_server_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/current_server_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/drbobject/__drbref_spec.rb b/1.8/library/drb/drbobject/__drbref_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/__drbref_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/__drburi_spec.rb b/1.8/library/drb/drbobject/__drburi_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/__drburi_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/_dump_spec.rb b/1.8/library/drb/drbobject/_dump_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/_dump_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/_load_spec.rb b/1.8/library/drb/drbobject/_load_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/_load_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/eql_spec.rb b/1.8/library/drb/drbobject/eql_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/eql_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/equal_value_spec.rb b/1.8/library/drb/drbobject/equal_value_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/equal_value_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/hash_spec.rb b/1.8/library/drb/drbobject/hash_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/hash_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/method_missing_spec.rb b/1.8/library/drb/drbobject/method_missing_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/method_missing_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/new_spec.rb b/1.8/library/drb/drbobject/new_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/new_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/new_with_spec.rb b/1.8/library/drb/drbobject/new_with_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/new_with_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/new_with_uri_spec.rb b/1.8/library/drb/drbobject/new_with_uri_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/new_with_uri_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/prepare_backtrace_spec.rb b/1.8/library/drb/drbobject/prepare_backtrace_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/prepare_backtrace_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/pretty_print_cycle_spec.rb b/1.8/library/drb/drbobject/pretty_print_cycle_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/pretty_print_cycle_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/pretty_print_spec.rb b/1.8/library/drb/drbobject/pretty_print_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/pretty_print_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/respond_to_spec.rb b/1.8/library/drb/drbobject/respond_to_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/respond_to_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/drbobject/with_friend_spec.rb b/1.8/library/drb/drbobject/with_friend_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/drb/drbobject/with_friend_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/drb/fetch_server_spec.rb b/1.8/library/drb/fetch_server_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/fetch_server_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/fixtures/test_server.rb b/1.8/library/drb/fixtures/test_server.rb new file mode 100644 index 0000000000..c83faf0723 --- /dev/null +++ b/1.8/library/drb/fixtures/test_server.rb @@ -0,0 +1,8 @@ +class TestServer + def add(*args) + args.inject {|n,v| n+v} + end + def add_yield(x) + return (yield x)+1 + end +end diff --git a/1.8/library/drb/front_spec.rb b/1.8/library/drb/front_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/front_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/here_spec.rb b/1.8/library/drb/here_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/here_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/install_acl_spec.rb b/1.8/library/drb/install_acl_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/install_acl_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/install_id_conv_spec.rb b/1.8/library/drb/install_id_conv_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/install_id_conv_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/primary_server_spec.rb b/1.8/library/drb/primary_server_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/primary_server_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/regist_server_spec.rb b/1.8/library/drb/regist_server_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/regist_server_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/remove_server_spec.rb b/1.8/library/drb/remove_server_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/remove_server_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/start_service_spec.rb b/1.8/library/drb/start_service_spec.rb new file mode 100644 index 0000000000..70db6a4e78 --- /dev/null +++ b/1.8/library/drb/start_service_spec.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/test_server' +require 'drb' + +describe "DRb.start_service" do + before :all do + @port = 9001 + (Process.pid & 7 ) + end + + before :each do + @url = "druby://localhost:#{@port}" + @port += 1 + end + + it "should run a basic remote call" do + lambda { DRb.current_server }.should raise_error(DRb::DRbServerNotFound) + server = DRb.start_service(@url, TestServer.new) + DRb.current_server.should == server + obj = DRbObject.new(nil, @url) + obj.add(1,2,3).should == 6 + DRb.stop_service + lambda { DRb.current_server }.should raise_error(DRb::DRbServerNotFound) + end + + it "should run a basic remote call passing a block" do + lambda { DRb.current_server }.should raise_error(DRb::DRbServerNotFound) + server = DRb.start_service(@url, TestServer.new) + DRb.current_server.should == server + obj = DRbObject.new(nil, @url) + obj.add_yield(2) do |i| + i.should == 2 + i+1 + end.should == 4 + DRb.stop_service + lambda { DRb.current_server }.should raise_error(DRb::DRbServerNotFound) + end +end diff --git a/1.8/library/drb/stop_service_spec.rb b/1.8/library/drb/stop_service_spec.rb new file mode 100644 index 0000000000..c06bf99e50 --- /dev/null +++ b/1.8/library/drb/stop_service_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "DRb.stop_service" do + before :all do + # for concurrent processes + @port = 9001 + (Process.pid & 7 ) + end + + before :each do + # because each spec needs it's own port since DRb is broken that way as exhibited below + @url = "druby://localhost:#{@port}" + @port += 1 + end + + it "should correctly clear the port so a new server can start" do + 10.times do + server = nil + lambda { server = DRb.start_service(@url, TestServer.new) }.should_not raise_error + DRb.current_server.should == server + lambda { DRb.stop_service }.should_not raise_error + end + end +end diff --git a/1.8/library/drb/thread_spec.rb b/1.8/library/drb/thread_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/thread_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/to_id_spec.rb b/1.8/library/drb/to_id_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/to_id_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/to_obj_spec.rb b/1.8/library/drb/to_obj_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/to_obj_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/drb/uri_spec.rb b/1.8/library/drb/uri_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/drb/uri_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/enumerator/each_cons_spec.rb b/1.8/library/enumerator/each_cons_spec.rb new file mode 100644 index 0000000000..601c4012d9 --- /dev/null +++ b/1.8/library/enumerator/each_cons_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require 'enumerator' + +describe "Enumerator#each_cons" do + it "iterates the block for each array of n consecutive elements" do + a = [] + EnumSpecs::Numerous.new.each_cons(4) { |e| a << e } + a.should == [[2, 5, 3, 6], [5, 3, 6, 1], [3, 6, 1, 4]] + end +end diff --git a/1.8/library/enumerator/each_slice_spec.rb b/1.8/library/enumerator/each_slice_spec.rb new file mode 100644 index 0000000000..2b82bdbc83 --- /dev/null +++ b/1.8/library/enumerator/each_slice_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require 'enumerator' + +describe "Enumerator#each_slice" do + it "iterates the block for each slice of n elements" do + a = [] + EnumSpecs::Numerous.new.each_slice(3) { |e| a << e } + a.should == [[2, 5, 3], [6, 1, 4]] + end +end diff --git a/1.8/library/enumerator/enum_cons_spec.rb b/1.8/library/enumerator/enum_cons_spec.rb new file mode 100644 index 0000000000..d9321fa963 --- /dev/null +++ b/1.8/library/enumerator/enum_cons_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require 'enumerator' + +describe "Enumerator#enum_cons" do + it "returns an enumerator of the receiver with iteration of each_cons for each array of n concecutive elements" do + a = [] + enum = EnumSpecs::Numerous.new.enum_cons(3) + enum.each {|x| a << x} + enum.kind_of?(Enumerable::Enumerator).should == true + a.should == [[2, 5, 3], [5, 3, 6], [3, 6, 1], [6, 1, 4]] + end +end diff --git a/1.8/library/enumerator/enum_slice_spec.rb b/1.8/library/enumerator/enum_slice_spec.rb new file mode 100644 index 0000000000..6777007ee2 --- /dev/null +++ b/1.8/library/enumerator/enum_slice_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require 'enumerator' + +describe "Enumerator#enum_slice" do + it "returns an enumerator of the receiver with iteration of each_slice for each slice of n elements" do + a = [] + enum = EnumSpecs::Numerous.new.enum_slice(4) + enum.kind_of?(Enumerable::Enumerator).should == true + enum.each { |e| a << e } + a.should == [[2, 5, 3, 6], [1, 4]] + end +end diff --git a/1.8/library/enumerator/enum_with_index_spec.rb b/1.8/library/enumerator/enum_with_index_spec.rb new file mode 100644 index 0000000000..9515a639f4 --- /dev/null +++ b/1.8/library/enumerator/enum_with_index_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require 'enumerator' + +describe "Enumerator#enum_with_index" do + it "returns an enumerator of the receiver with an iteration of each_with_index" do + a = [] + enum = EnumSpecs::Numerous.new.enum_with_index + enum.kind_of?(Enumerable::Enumerator).should == true + enum.each { |e| a << e } + a.should == [[2, 0], [5, 1], [3, 2], [6, 3], [1, 4], [4, 5]] + end +end diff --git a/1.8/library/enumerator/fixtures/classes.rb b/1.8/library/enumerator/fixtures/classes.rb new file mode 100644 index 0000000000..3014b22e54 --- /dev/null +++ b/1.8/library/enumerator/fixtures/classes.rb @@ -0,0 +1,13 @@ +module EnumSpecs + class Numerous + include Enumerable + + def initialize(*list) + @list = list.empty? ? [2, 5, 3, 6, 1, 4] : list + end + + def each + @list.each { |i| yield i } + end + end +end diff --git a/1.8/library/enumerator/new_spec.rb b/1.8/library/enumerator/new_spec.rb new file mode 100644 index 0000000000..d138c4f8df --- /dev/null +++ b/1.8/library/enumerator/new_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'enumerator' + +describe "Enumerator.new" do + it "creates a new custom enumerator with the given object, iterator and arguments" do + enum = Enumerable::Enumerator.new(1, :upto, 3) + enum.kind_of?(Enumerable::Enumerator).should == true + end + + it "creates a new custom enumerator that responds to #each" do + enum = Enumerable::Enumerator.new(1, :upto, 3) + enum.respond_to?(:each).should == true + end + + it "creates a new custom enumerator that runs correctly" do + Enumerable::Enumerator.new(1, :upto, 3).map{|x|x}.should == [1,2,3] + end +end diff --git a/1.8/library/erb/def_class_spec.rb b/1.8/library/erb/def_class_spec.rb new file mode 100644 index 0000000000..37ffde4dd6 --- /dev/null +++ b/1.8/library/erb/def_class_spec.rb @@ -0,0 +1,29 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe 'ERB#def_class' do + + it "return an unnamed class which has instance method to render eRuby script" do + input = <<'END' +@arg1=<%=@arg1.inspect%> +@arg2=<%=@arg2.inspect%> +END + expected = <<'END' +@arg1="foo" +@arg2=123 +END + class MyClass1ForErb_ + def initialize(arg1, arg2) + @arg1 = arg1; @arg2 = arg2 + end + end + filename = 'example.rhtml' + #erb = ERB.new(File.read(filename)) + erb = ERB.new(input) + erb.filename = filename + MyClass1ForErb = erb.def_class(MyClass1ForErb_, 'render()') + MyClass1ForErb.method_defined?(:render).should == true + MyClass1ForErb.new('foo', 123).render().should == expected + end + +end diff --git a/1.8/library/erb/def_method_spec.rb b/1.8/library/erb/def_method_spec.rb new file mode 100644 index 0000000000..4ae5316c6b --- /dev/null +++ b/1.8/library/erb/def_method_spec.rb @@ -0,0 +1,26 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe 'ERB#def_method' do + + it "define module's instance method to render eRuby file" do + input = <<'END' +arg1=<%= arg1.inspect %> +arg2=<%= arg2.inspect %> +END + expected = <<'END' +arg1="foo" +arg2=123 +END + # + filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml + #erb = ERB.new(File.read(filename)) + erb = ERB.new(input) + class MyClass0ForErb + end + erb.def_method(MyClass0ForErb, 'render(arg1, arg2)', filename) + MyClass0ForErb.method_defined?(:render) + MyClass0ForErb.new.render('foo', 123).should == expected + end + +end diff --git a/1.8/library/erb/def_module_spec.rb b/1.8/library/erb/def_module_spec.rb new file mode 100644 index 0000000000..c6ee8ae3ca --- /dev/null +++ b/1.8/library/erb/def_module_spec.rb @@ -0,0 +1,27 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe 'ERB#def_module' do + + it "return unnamed module which has instance method to render eRuby" do + input = <<'END' +arg1=<%= arg1.inspect %> +arg2=<%= arg2.inspect %> +END + expected = <<'END' +arg1="foo" +arg2=123 +END + filename = 'example.rhtml' + #erb = ERB.new(File.read(filename)) + erb = ERB.new(input) + erb.filename = filename + MyModule2ForErb = erb.def_module('render(arg1, arg2)') + MyModule2ForErb.method_defined?(':render') + class MyClass2ForErb + include MyModule2ForErb + end + MyClass2ForErb.new.render('foo', 123).should == expected + end + +end diff --git a/1.8/library/erb/defmethod/def_erb_method_spec.rb b/1.8/library/erb/defmethod/def_erb_method_spec.rb new file mode 100644 index 0000000000..13215a50c1 --- /dev/null +++ b/1.8/library/erb/defmethod/def_erb_method_spec.rb @@ -0,0 +1,62 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe 'ERB::DefMethod.def_erb_method' do + + + input = <<'END' +<% for item in @items %> +<%= item %> +<% end %> +END + + + it "define method to render eRuby file as an instance method of current module" do + expected = <<'END' + +10 + +20 + +30 + +END + # + begin + File.open('_example.rhtml', 'w') {|f| f.write(input) } + class MyClass3ForEruby + extend ERB::DefMethod + def_erb_method('render()', '_example.rhtml') + def initialize(items) + @items = items + end + end + MyClass3ForEruby.new([10,20,30]).render().should == expected + ensure + File.unlink('_example.rhtml') + end + + end + + + it "define method to render eRuby object as an instance method of current module" do + expected = <<'END' +10 +20 +30 +END + # + MY_INPUT4_FOR_ERB = input + class MyClass4ForErb + extend ERB::DefMethod + erb = ERB.new(MY_INPUT4_FOR_ERB, nil, '<>') + def_erb_method('render()', erb) + def initialize(items) + @items = items + end + end + MyClass4ForErb.new([10,20,30]).render().should == expected + end + + +end diff --git a/1.8/library/erb/filename_spec.rb b/1.8/library/erb/filename_spec.rb new file mode 100644 index 0000000000..2a37a702f3 --- /dev/null +++ b/1.8/library/erb/filename_spec.rb @@ -0,0 +1,54 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ERB#filename" do + # TODO: why does this fail on rubinius? + it "raises an exception if there are errors processing content" do + filename = 'foobar.rhtml' + erb = ERB.new('<% if true %>') # will raise SyntaxError + erb.filename = filename + lambda { + begin + erb.result(binding) + rescue Exception => e + @ex = e + raise e + end + }.should raise_error(SyntaxError) + expected = filename + + @ex.message =~ /^(.*?):(\d+): / + $1.should == expected + $2.to_i.should == 1 + + # TODO: why is this different on rubinius? + extended_on :rubinius do + @ex.file.should == expected + @ex.line.should == 1 + end + end + + # TODO: why does this fail on rubinius? + it "uses '(erb)' as filename when filename is not set" do + erb = ERB.new('<% if true %>') # will raise SyntaxError + lambda { + begin + erb.result(binding) + rescue Exception => e + @ex = e + raise e + end + }.should raise_error(SyntaxError) + expected = '(erb)' + + @ex.message =~ /^(.*?):(\d+): / + $1.should == expected + $2.to_i.should == 1 + + # TODO: why is this different on rubinius? + extended_on :rubinius do + @ex.file.should == expected + @ex.line.should == 1 + end + end +end diff --git a/1.8/library/erb/new_spec.rb b/1.8/library/erb/new_spec.rb new file mode 100644 index 0000000000..a17c80db44 --- /dev/null +++ b/1.8/library/erb/new_spec.rb @@ -0,0 +1,309 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../spec_helper' + + +## http://doc.loveruby.net/refm/api/view/library/erb + + +describe "ERB.new" do + + eruby_str = <<'END' +
    +<% for item in list %> + <% if item %> +
  • <%= item %> + <% end %> +<% end %> +
+END + + + ## trim_mode == 0 , '', or nil + it "compile eRuby script into ruby code when trim mode is 0 or not specified" do + input = eruby_str + expected = <<'END' +_erbout = ''; _erbout.concat "
    \n" + for item in list ; _erbout.concat "\n" +_erbout.concat " "; if item ; _erbout.concat "\n" +_erbout.concat "
  • "; _erbout.concat(( item ).to_s); _erbout.concat "\n" +_erbout.concat " "; end ; _erbout.concat "\n" + end ; _erbout.concat "\n" +_erbout.concat "
\n" +_erbout +END + expected.chomp! + ERB.new(input).src.should == expected + [0, '', nil].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + ## trim_mode == 1 or '>' + it 'remove "\n" when trim_mode is 1 or \'>\'' do + input = eruby_str + expected = <<'END' +_erbout = ''; _erbout.concat "
    \n" + for item in list +_erbout.concat " "; if item +_erbout.concat "
  • "; _erbout.concat(( item ).to_s) +_erbout.concat " "; end + end +_erbout.concat "
\n" +_erbout +END + expected.chomp! + [1, '>'].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + ## trim_mode == 2 or '<>' + it 'remove spaces at beginning of line and "\n" when trim_mode is 2 or \'<>\'' do + input = eruby_str + expected = <<'END' +_erbout = ''; _erbout.concat "
    \n" + for item in list +_erbout.concat " "; if item ; _erbout.concat "\n" +_erbout.concat "
  • "; _erbout.concat(( item ).to_s); _erbout.concat "\n" +_erbout.concat " "; end ; _erbout.concat "\n" + end +_erbout.concat "
\n" +_erbout +END + expected.chomp! + [2, '<>'].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + ## trim_mode == '-' + it "removes spaces arount '<%- -%>' when trim_mode is '-'" do + #input = eruby_str.gsub(/<%/, '<%-') + input = <<'END' +
    +<%- for item in list -%> + <%- if item -%> +
  • <%= item -%> + <%- end -%> +<%- end -%> +
+END + expected = <<'END' +_erbout = ''; _erbout.concat "
    \n" + for item in list + if item +_erbout.concat "
  • "; _erbout.concat(( item ).to_s) + end + end +_erbout.concat "
\n" +_erbout +END + expected.chomp! + ['-'].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + ## trim_mode == '-' #2 + it "not support '<%-= expr %> even when trim_mode is '-'" do + input = <<'END' +

+ <%= expr -%> + <%-= expr -%> +

+END + expected = <<'END' +_erbout = ''; _erbout.concat "

\n" +_erbout.concat " "; _erbout.concat(( expr ).to_s) += expr +_erbout.concat "

\n" +_erbout +END + expected.chomp! + ['-'].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + erubystr2 = <<'END' +
    +%for item in list +% if item +
  • <%= item %> + <% end %> +<% end %> +
+%%% +END + + + ## trim_mode == '%' + it "regard lines starting with '%' as '<% ... %>' when trim_mode is '%'" do + input = erubystr2 + expected = <<'END' +_erbout = ''; _erbout.concat "
    \n" +for item in list + if item +_erbout.concat "
  • "; _erbout.concat(( item ).to_s); _erbout.concat "\n" +_erbout.concat " "; end ; _erbout.concat "\n" + end ; _erbout.concat "\n" +_erbout.concat "
\n" +_erbout.concat "%%\n" +_erbout +END + expected.chomp! + ['%'].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + ## trim_mode == '%>' + it "regard lines starting with '%' as '<% ... %>' and remove \"\\n\" when trim_mode is '%>'" do + input = erubystr2 + expected = <<'END' +_erbout = ''; _erbout.concat "
    \n" +for item in list + if item +_erbout.concat "
  • "; _erbout.concat(( item ).to_s) +_erbout.concat " "; end + end +_erbout.concat "
\n" +_erbout.concat "%%\n" +_erbout +END + expected.chomp! + ['%>'].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + ## trim_mode == '%<>' + it "regard lines starting with '%' as '<% ... %>' and remove \"\\n\" when trim_mode is '%<>'" do + input = erubystr2 + expected = <<'END' +_erbout = ''; _erbout.concat "
    \n" +for item in list + if item +_erbout.concat "
  • "; _erbout.concat(( item ).to_s); _erbout.concat "\n" +_erbout.concat " "; end ; _erbout.concat "\n" + end +_erbout.concat "
\n" +_erbout.concat "%%\n" +_erbout +END + expected.chomp! + ['%<>'].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + ## trim_mode == '%-' + it "regard lines starting with '%' as '<% ... %>' and spaces around '<%- -%>' when trim_mode is '%-'" do + input = <<'END' +
    +%for item in list +% if item +
  • <%= item -%> + <%- end -%> +<%- end -%> +
+%%% +END + expected = <<'END' +_erbout = ''; _erbout.concat "
    \n" +for item in list + if item +_erbout.concat "
  • "; _erbout.concat(( item ).to_s) + end + end +_erbout.concat "
\n" +_erbout.concat "%%\n" +_erbout +END + expected.chomp! + ['%-'].each do |trim_mode| + ERB.new(input, nil, trim_mode).src.should == expected + end + end + + + ## safe_level + #it "set savel level" do + # input = '' + # safe_level = 4 + # erb = ERB.new(input, safe_level) + #end + + + ## eoutvar + it "change '_erbout' variable name" do + input = eruby_str + expected = <<'END' +buf = ''; buf.concat "
    \n" + for item in list ; buf.concat "\n" +buf.concat " "; if item ; buf.concat "\n" +buf.concat "
  • "; buf.concat(( item ).to_s); buf.concat "\n" +buf.concat " "; end ; buf.concat "\n" + end ; buf.concat "\n" +buf.concat "
\n" +buf +END + expected.chomp! + ERB.new(input, nil, nil, 'buf').src.should == expected + end + + + ## <%# ... %> + it "ignore '<%# ... %>'" do + input = <<'END' +<%# for item in list %> +<%#= item %> +<%# end %> +END + expected = <<'END' +_erbout = ''; _erbout.concat "\n" +_erbout.concat ""; _erbout.concat "\n" +_erbout.concat "\n" +_erbout +END + expected.chomp! + ERB.new(input).src.should == expected + # + expected = <<'END' +_erbout = '' +_erbout.concat ""; _erbout.concat "\n" + +_erbout +END + expected.chomp! + ERB.new(input, nil, '<>').src.should == expected + end + + + ## <%% ... %%> + it "convert '<%% ... %%>' into '<% ... %>'" do + input = <<'END' +<%% for item in list %> +<%%= item %> +<%% end %%> +END + expected = <<'END' +_erbout = ''; _erbout.concat "<% for item in list %>\n" +_erbout.concat "<%= item %>\n" +_erbout.concat "<% end %%>\n" +_erbout +END + expected.chomp! + ERB.new(input).src.should == expected + end + + +end diff --git a/1.8/library/erb/result_spec.rb b/1.8/library/erb/result_spec.rb new file mode 100644 index 0000000000..49e8088a71 --- /dev/null +++ b/1.8/library/erb/result_spec.rb @@ -0,0 +1,102 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ERB#result" do + + + it "return the result of compiled ruby code" do + input = <<'END' +
    +<% for item in list %> +
  • <%= item %> +<% end %> +
+END + expected = <<'END' +
    + +
  • AAA + +
  • BBB + +
  • CCC + +
+END + erb = ERB.new(input) + list = %w[AAA BBB CCC] + actual = erb.result(binding) + actual.should == expected + end + + + it "share local variables" do + input = "<% var = 456 %>" + expected = 456 + var = 123 + ERB.new(input).result(binding) + var.should == expected + end + + + it "is not able to h() or u() unless including ERB::Util" do + input = "<%=h '<>' %>" + lambda { + ERB.new(input).result() + }.should raise_error(NameError) + end + + + it "is able to h() or u() if ERB::Util is included" do + class MyERB1 + include ERB::Util + def main + input = "<%=h '<>' %>" + return ERB.new(input).result(binding) + end + end + expected = '<>' + actual = MyERB1.new.main() + actual.should == expected + end + + + it "use TOPLEVEL_BINDING if binding is not passed" do + class MyERB2 + include ERB::Util + def main1 + #input = "<%= binding.to_s %>" + input = "<%= _xxx_var_ %>" + return ERB.new(input).result() + end + def main2 + input = "<%=h '<>' %>" + return ERB.new(input).result() + end + end + + eval '_xxx_var_ = 123', TOPLEVEL_BINDING + expected = '123' + MyERB2.new.main1().should == expected + + lambda { + actual = MyERB2.new.main2() + }.should raise_error(NameError) + end + + + #-- + #it "does not change current $SAFE even if safe_level is specifiled at ERB#initialize" do + # input = "$SAFE=<%=$SAFE.inspect%>" + # expected = "$SAFE=2" + # safe_level = 2 + # erb = ERB.new(input, safe_level) + # curr_safe_level = $SAFE + # erb.result(binding()).should == expected + # $SAFE.should == curr_safe_level # BUG: $SAFE will be changed in current Rubinius + #end + #++ + + +end + diff --git a/1.8/library/erb/run_spec.rb b/1.8/library/erb/run_spec.rb new file mode 100644 index 0000000000..3b6f3dbc28 --- /dev/null +++ b/1.8/library/erb/run_spec.rb @@ -0,0 +1,97 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ERB#run" do + # TODO: what is this? why does it not use + # lambda { ... }.should output + def _steal_stdout + orig = $stdout + s = '' + def s.write(arg); self << arg.to_s; end + $stdout = s + begin + yield + ensure + $stdout = orig + end + return s + end + + it "print the result of compiled ruby code" do + input = < +<% for item in list %> +
  • <%= item %> +<% end %> + +END + expected = < + +
  • AAA + +
  • BBB + +
  • CCC + + +END + erb = ERB.new(input) + list = %w[AAA BBB CCC] + actual = _steal_stdout { erb.run(binding) } + actual.should == expected + end + + it "share local variables" do + input = "<% var = 456 %>" + expected = 456 + var = 123 + _steal_stdout { ERB.new(input).run(binding) } + var.should == expected + end + + it "is not able to h() or u() unless including ERB::Util" do + input = "<%=h '<>' %>" + lambda { + _steal_stdout { ERB.new(input).run() } + }.should raise_error(NameError) + end + + it "is able to h() or u() if ERB::Util is included" do + class MyERB1 + include ERB::Util + def main + input = "<%=h '<>' %>" + ERB.new(input).run(binding) + end + end + expected = '<>' + actual = _steal_stdout { MyERB1.new.main() } + actual.should == expected + end + + it "use TOPLEVEL_BINDING if binding is not passed" do + class MyERB2 + include ERB::Util + def main1 + #input = "<%= binding.to_s %>" + input = "<%= _xxx_var_ %>" + return ERB.new(input).run() + end + def main2 + input = "<%=h '<>' %>" + return ERB.new(input).run() + end + end + + eval '_xxx_var_ = 123', TOPLEVEL_BINDING + expected = '123' + actual = _steal_stdout { MyERB2.new.main1() } + actual.should == expected + + lambda { + _steal_stdout { MyERB2.new.main2() } + }.should raise_error(NameError) + end +end + diff --git a/1.8/library/erb/src_spec.rb b/1.8/library/erb/src_spec.rb new file mode 100644 index 0000000000..4a6bbec07d --- /dev/null +++ b/1.8/library/erb/src_spec.rb @@ -0,0 +1,26 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "ERB#src" do + + it "return compiled ruby code" do + input = <<'END' +
      +<% for item in list %> +
    • <%= item %>
    • +<% end %> +
    +END + expected = <<'END' +_erbout = ''; _erbout.concat "
      \n" + for item in list ; _erbout.concat "\n" +_erbout.concat "
    • "; _erbout.concat(( item ).to_s); _erbout.concat "
    • \n" + end ; _erbout.concat "\n" +_erbout.concat "
    \n" +_erbout +END + expected.chomp! + ERB.new(input).src.should == expected + end + +end diff --git a/1.8/library/erb/util/h_spec.rb b/1.8/library/erb/util/h_spec.rb new file mode 100644 index 0000000000..142926c6cc --- /dev/null +++ b/1.8/library/erb/util/h_spec.rb @@ -0,0 +1,7 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/html_escape' + +describe "ERB::Util.h" do + it_behaves_like :erb_util_html_escape, :h +end diff --git a/1.8/library/erb/util/html_escape_spec.rb b/1.8/library/erb/util/html_escape_spec.rb new file mode 100644 index 0000000000..85069d6d8d --- /dev/null +++ b/1.8/library/erb/util/html_escape_spec.rb @@ -0,0 +1,8 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/html_escape' + +describe "ERB::Util.html_escape" do + it_behaves_like :erb_util_html_escape, :html_escape +end + diff --git a/1.8/library/erb/util/shared/html_escape.rb b/1.8/library/erb/util/shared/html_escape.rb new file mode 100644 index 0000000000..5c71a97a50 --- /dev/null +++ b/1.8/library/erb/util/shared/html_escape.rb @@ -0,0 +1,43 @@ +shared :erb_util_html_escape do |cmd| + + describe "ERB::Util.#{cmd}" do + + it "escape '& < > \"' to '& < > "" do + input = '& < > "' + expected = '& < > "' + ERB::Util.__send__(cmd, input).should == expected + end + + it "not escape characters except '& < > \"'" do + input = (0x20..0x7E).to_a.collect {|ch| ch.chr}.join('') + expected = input.gsub(/&/,'&').gsub(//,'>').gsub(/"/,'"') + ERB::Util.__send__(cmd, input).should == expected + end + + it "return empty string when argument is nil" do + input = nil + expected = '' + ERB::Util.__send__(cmd, input).should == expected + end + + it "returns string when argument is number" do + input = 123 + expected = '123' + ERB::Util.__send__(cmd, input).should == expected + input = 3.14159 + expected = '3.14159' + ERB::Util.__send__(cmd, input).should == expected + end + + it "returns string when argument is boolean" do + input = true + expected = 'true' + ERB::Util.__send__(cmd, input).should == expected + input = false + expected = 'false' + ERB::Util.__send__(cmd, input).should == expected + end + + end + +end diff --git a/1.8/library/erb/util/shared/url_encode.rb b/1.8/library/erb/util/shared/url_encode.rb new file mode 100644 index 0000000000..61289e5f86 --- /dev/null +++ b/1.8/library/erb/util/shared/url_encode.rb @@ -0,0 +1,44 @@ +shared :erb_util_url_encode do |cmd| + + describe "ERB::Util.#{cmd}" do + + it "encode characters" do + #input = (0x20..0x7E).to_a.collect{|ch| ch.chr}.join + input = " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + expected = "%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E" + ERB::Util.__send__(cmd, input).should == expected + end + + it "encode unicode string" do + input = "http://ja.wikipedia.org/wiki/\343\203\255\343\203\240\343\202\271\343\202\253\343\203\273\343\203\221\343\203\255\343\203\273\343\202\246\343\203\253\343\203\273\343\203\251\343\203\224\343\203\245\343\202\277" + expected = 'http%3A%2F%2Fja.wikipedia.org%2Fwiki%2F%E3%83%AD%E3%83%A0%E3%82%B9%E3%82%AB%E3%83%BB%E3%83%91%E3%83%AD%E3%83%BB%E3%82%A6%E3%83%AB%E3%83%BB%E3%83%A9%E3%83%94%E3%83%A5%E3%82%BF' + ERB::Util.__send__(cmd, input).should == expected + end + + it "returns empty string when argument is nil" do + input = nil + expected = '' + ERB::Util.__send__(cmd, input).should == expected + end + + it "returns string when argument is number" do + input = 123 + expected = '123' + ERB::Util.__send__(cmd, input).should == expected + input = 3.14159 + expected = '3.14159' + ERB::Util.__send__(cmd, input).should == expected + end + + it "returns string when argument is boolean" do + input = true + expected = 'true' + ERB::Util.__send__(cmd, input).should == expected + input = false + expected = 'false' + ERB::Util.__send__(cmd, input).should == expected + end + + end + +end diff --git a/1.8/library/erb/util/u_spec.rb b/1.8/library/erb/util/u_spec.rb new file mode 100644 index 0000000000..cd8da92e0e --- /dev/null +++ b/1.8/library/erb/util/u_spec.rb @@ -0,0 +1,8 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/url_encode' + +describe "ERB::Util.u" do + it_behaves_like :erb_util_url_encode, :u +end + diff --git a/1.8/library/erb/util/url_encode_spec.rb b/1.8/library/erb/util/url_encode_spec.rb new file mode 100644 index 0000000000..a58437db55 --- /dev/null +++ b/1.8/library/erb/util/url_encode_spec.rb @@ -0,0 +1,7 @@ +require 'erb' +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/shared/url_encode' + +describe "ERB::Util.url_encode" do + it_behaves_like :erb_util_url_encode, :url_encode +end diff --git a/1.8/library/etc/endgrent_spec.rb b/1.8/library/etc/endgrent_spec.rb new file mode 100644 index 0000000000..b1187a056b --- /dev/null +++ b/1.8/library/etc/endgrent_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' diff --git a/1.8/library/etc/endpwent_spec.rb b/1.8/library/etc/endpwent_spec.rb new file mode 100644 index 0000000000..b1187a056b --- /dev/null +++ b/1.8/library/etc/endpwent_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' diff --git a/1.8/library/etc/getgrent_spec.rb b/1.8/library/etc/getgrent_spec.rb new file mode 100644 index 0000000000..b1187a056b --- /dev/null +++ b/1.8/library/etc/getgrent_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' diff --git a/1.8/library/etc/getgrgid_spec.rb b/1.8/library/etc/getgrgid_spec.rb new file mode 100644 index 0000000000..4fddd0c754 --- /dev/null +++ b/1.8/library/etc/getgrgid_spec.rb @@ -0,0 +1,61 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' + +describe "Etc.getgrgid" do + before(:all) do + @gid = `id -g`.strip.to_i + @name = `id -gn`.strip + end + + deviates_on :rubinius, :ruby19 do + it "returns a Group struct instance for the given user" do + gr = Etc.getgrgid(@gid) + + deviates_on :rubinius do + gr.is_a?(Etc::Group).should == true + end + + compliant_on :ruby19 do + gr.is_a?(Struct::Group).should == true + end + + gr.gid.should == @gid + gr.name.should == @name + end + end + + compliant_on :ruby do + platform_is_not :darwin do + it "ignores its argument" do + lambda { Etc.getgrgid("foo") }.should raise_error(TypeError) + Etc.getgrgid(42) + Etc.getgrgid(9876) + end + end + + it "returns a Group struct instance for the current user's group" do + gr = Etc.getgrgid(@gid) + gr.is_a?(Struct::Group).should == true + gr.gid.should == @gid + gr.name.should == @name + end + end + + deviates_on :rubinius, :ruby19 do + it "only accepts integers as argument" do + lambda { + Etc.getgrgid("foo") + Etc.getgrgid(nil) + }.should raise_error(TypeError) + end + end + + deviates_on :rubinius, :ruby19 do + it "uses Process.gid as the default value for the argument" do + gr = Etc.getgrgid + + gr.gid.should == @gid + gr.name.should == @name + end + end +end diff --git a/1.8/library/etc/getgrnam_spec.rb b/1.8/library/etc/getgrnam_spec.rb new file mode 100644 index 0000000000..cc0b42f301 --- /dev/null +++ b/1.8/library/etc/getgrnam_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' + +describe "Etc.getgrnam" do + it "returns a Group struct instance for the given group" do + gr = Etc.getgrnam("daemon") + + deviates_on :rubinius do + gr.is_a?(Etc::Group).should == true + end + + compliant_on :ruby do + gr.is_a?(Struct::Group).should == true + end + end + + it "only accepts strings as argument" do + lambda { + Etc.getgrnam(123) + Etc.getgrnam(nil) + }.should raise_error(TypeError) + end +end diff --git a/1.8/library/etc/getlogin_spec.rb b/1.8/library/etc/getlogin_spec.rb new file mode 100644 index 0000000000..ddde192371 --- /dev/null +++ b/1.8/library/etc/getlogin_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' + +describe "Etc.getlogin" do + it "returns the name of the user who runs this process" do + Etc.getlogin.should == `whoami`.strip + end +end diff --git a/1.8/library/etc/getpwent_spec.rb b/1.8/library/etc/getpwent_spec.rb new file mode 100644 index 0000000000..b1187a056b --- /dev/null +++ b/1.8/library/etc/getpwent_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' diff --git a/1.8/library/etc/getpwnam_spec.rb b/1.8/library/etc/getpwnam_spec.rb new file mode 100644 index 0000000000..3fd247e596 --- /dev/null +++ b/1.8/library/etc/getpwnam_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' + +describe "Etc.getpwnam" do + it "returns a Passwd struct instance for the given user" do + pw = Etc.getpwnam(`whoami`.strip) + + deviates_on :rubinius do + pw.is_a?(Etc::Passwd).should == true + end + + compliant_on :ruby do + pw.is_a?(Struct::Passwd).should == true + end + end + + it "only accepts strings as argument" do + lambda { + Etc.getpwnam(123) + Etc.getpwnam(nil) + }.should raise_error(TypeError) + end +end diff --git a/1.8/library/etc/getpwuid_spec.rb b/1.8/library/etc/getpwuid_spec.rb new file mode 100644 index 0000000000..0f2b32ecad --- /dev/null +++ b/1.8/library/etc/getpwuid_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' + +describe "Etc.getpwuid" do + it "returns a Passwd struct instance for the given user" do + pw = Etc.getpwuid(`id -u`.strip.to_i) + + deviates_on :rubinius do + pw.is_a?(Etc::Passwd).should == true + end + + compliant_on :ruby do + pw.is_a?(Struct::Passwd).should == true + end + end + + it "only accepts integers as argument" do + lambda { + Etc.getpwuid("foo") + Etc.getpwuid(nil) + }.should raise_error(TypeError) + end + + deviates_on :rubinius, :ruby19 do + it "uses Process.uid as the default value for the argument" do + pw = Etc.getpwuid + end + end +end diff --git a/1.8/library/etc/group_spec.rb b/1.8/library/etc/group_spec.rb new file mode 100644 index 0000000000..b1187a056b --- /dev/null +++ b/1.8/library/etc/group_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' diff --git a/1.8/library/etc/passwd_spec.rb b/1.8/library/etc/passwd_spec.rb new file mode 100644 index 0000000000..b1187a056b --- /dev/null +++ b/1.8/library/etc/passwd_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' diff --git a/1.8/library/etc/setgrent_spec.rb b/1.8/library/etc/setgrent_spec.rb new file mode 100644 index 0000000000..b1187a056b --- /dev/null +++ b/1.8/library/etc/setgrent_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' diff --git a/1.8/library/etc/setpwent_spec.rb b/1.8/library/etc/setpwent_spec.rb new file mode 100644 index 0000000000..b1187a056b --- /dev/null +++ b/1.8/library/etc/setpwent_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'etc' diff --git a/1.8/library/ftools/catname_spec.rb b/1.8/library/ftools/catname_spec.rb new file mode 100644 index 0000000000..fce3227a5c --- /dev/null +++ b/1.8/library/ftools/catname_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.catname" do + it "returns the 2nd arg if it's not a directory" do + File.catname("blah", "/etc/passwd").should == "/etc/passwd" + end + + it "uses File.join with the args" do + File.catname("passwd", ".").should == "./passwd" + end + + it "uses File.basename on the 1st arg before joining" do + File.catname("etc/passwd", ".").should == "./passwd" + end +end diff --git a/1.8/library/ftools/chmod_spec.rb b/1.8/library/ftools/chmod_spec.rb new file mode 100644 index 0000000000..fcc3676a62 --- /dev/null +++ b/1.8/library/ftools/chmod_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.chmod" do + before(:each) do + (1..2).each do |n| + system "echo 'hello rubinius' > chmod_test_#{n}" + system "chmod 0777 chmod_test_#{n}" + end + end + + after(:each) do + (1..2).each { |n| File.unlink "chmod_test_#{n}" rescue nil } + end + + it "changes the mode to 1st arg for files in 2nd arg" do + `ls -l chmod_test_1`.should =~ /^-rwxrwxrwx / + `ls -l chmod_test_2`.should =~ /^-rwxrwxrwx / + File.chmod 0644, "chmod_test_1", "chmod_test_2" + `ls -l chmod_test_1`.should =~ /^-rw-r--r-- / + `ls -l chmod_test_2`.should =~ /^-rw-r--r-- / + end +end diff --git a/1.8/library/ftools/compare_spec.rb b/1.8/library/ftools/compare_spec.rb new file mode 100644 index 0000000000..b7f3597d36 --- /dev/null +++ b/1.8/library/ftools/compare_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.compare" do + before(:each) do + (1..3).to_a.each do |n| + if n == 3 + system "echo 'hello mri' > compare_test_#{n}" + else + system "echo 'hello rubinius' > compare_test_#{n}" + end + system "chmod a+x compare_test_#{n}" + end + end + + after(:each) do + (1..3).to_a.each { |n| File.unlink "compare_test_#{n}" } + end + + it "compares the file at 1st arg to the file at 2nd arg" do + File.compare("compare_test_1", "compare_test_2").should == true + File.compare("compare_test_2", "compare_test_1").should == true + + File.compare("compare_test_1", "compare_test_3").should == false + File.compare("compare_test_2", "compare_test_3").should == false + end +end diff --git a/1.8/library/ftools/copy_spec.rb b/1.8/library/ftools/copy_spec.rb new file mode 100644 index 0000000000..2c50e3ea58 --- /dev/null +++ b/1.8/library/ftools/copy_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.copy" do + before(:each) do + system "echo 'hello rubinius' > copy_test" + system "chmod a+x copy_test" + end + + after(:each) do + File.unlink "copy_test" + File.unlink "copy_test_dest" rescue nil + end + + it "copies the file at 1st arg to the file at 2nd arg" do + File.copy("copy_test", "copy_test_dest") + fd = File.open("copy_test_dest") + data = fd.read + data.should == "hello rubinius\n" + fd.close + + omode = File.stat("copy_test").mode + mode = File.stat("copy_test_dest").mode + + omode.should == mode + end +end diff --git a/1.8/library/ftools/install_spec.rb b/1.8/library/ftools/install_spec.rb new file mode 100644 index 0000000000..f3801d0de2 --- /dev/null +++ b/1.8/library/ftools/install_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.install" do + before(:each) do + system "echo 'hello rubinius' > install_test_1" + system "chmod 0777 install_test_1" + end + + after(:each) do + (1..2).each { |n| File.unlink "install_test_#{n}" rescue nil } + end + + it "changes the mode to 1st arg for files in 2nd arg" do + `ls -l install_test_1`.should =~ /^-rwxrwxrwx / + File.install "install_test_1", "install_test_2", 0644 + `ls -l install_test_2`.should =~ /^-rw-r--r-- / + end +end diff --git a/1.8/library/ftools/makedirs_spec.rb b/1.8/library/ftools/makedirs_spec.rb new file mode 100644 index 0000000000..d3743cf076 --- /dev/null +++ b/1.8/library/ftools/makedirs_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.makedirs" do + before(:each) do + end + + after(:each) do + system "rmdir makedirs_test/second_dir" if File.exist?("makedirs_test/second_dir") + system "rmdir makedirs_test" if File.exist?("makedirs_test") + end + + it "creates the dirs from arg" do + File.exist?("makedirs_test").should == false + File.makedirs("makedirs_test/second_dir") + File.exist?("makedirs_test").should == true + File.directory?("makedirs_test").should == true + File.exist?("makedirs_test/second_dir").should == true + File.directory?("makedirs_test/second_dir").should == true + end +end diff --git a/1.8/library/ftools/move_spec.rb b/1.8/library/ftools/move_spec.rb new file mode 100644 index 0000000000..e655808b76 --- /dev/null +++ b/1.8/library/ftools/move_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.move" do + before(:each) do + system "echo 'hello rubinius' > move_test" + system "chmod a+x move_test" + end + + after(:each) do + File.unlink "move_test_dest" + File.unlink "move_test" rescue nil + end + + it "moves the file at 1st arg to the file at 2nd arg" do + omode = File.stat("move_test").mode + File.move("move_test", "move_test_dest") + fd = File.open("move_test_dest") + data = fd.read + data.should == "hello rubinius\n" + fd.close + mode = File.stat("move_test_dest").mode + + omode.should == mode + end +end diff --git a/1.8/library/ftools/safe_unlink_spec.rb b/1.8/library/ftools/safe_unlink_spec.rb new file mode 100644 index 0000000000..c6bee9598d --- /dev/null +++ b/1.8/library/ftools/safe_unlink_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.safe_unlink" do + before(:each) do + (1..2).each do |n| + system "echo 'hello rubinius' > safe_unlink_test_#{n}" + system "chmod 0777 safe_unlink_test_#{n}" + end + end + + after(:each) do + (1..2).each { |n| File.unlink "safe_unlink_test_#{n}" rescue nil } + end + + it "deletes the files in arg and returns an array of files deleted" do + File.exist?("safe_unlink_test_1").should == true + File.exist?("safe_unlink_test_2").should == true + File.safe_unlink("safe_unlink_test_1", "safe_unlink_test_2").should == ["safe_unlink_test_1", "safe_unlink_test_2"] + File.exist?("safe_unlink_test_1").should == false + File.exist?("safe_unlink_test_2").should == false + end +end diff --git a/1.8/library/ftools/syscopy_spec.rb b/1.8/library/ftools/syscopy_spec.rb new file mode 100644 index 0000000000..8af8ac8f8d --- /dev/null +++ b/1.8/library/ftools/syscopy_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ftools' + +describe "File.syscopy" do + before(:each) do + system "echo 'hello rubinius' > syscopy_test" + system "chmod a+x syscopy_test" + end + + after(:each) do + File.unlink "syscopy_test" + File.unlink "syscopy_test_dest" rescue nil + end + + it "copies the file at 1st arg to the file at 2nd arg" do + File.syscopy("syscopy_test", "syscopy_test_dest") + fd = File.open("syscopy_test_dest") + data = fd.read + data.should == "hello rubinius\n" + fd.close + + omode = File.stat("syscopy_test").mode + mode = File.stat("syscopy_test_dest").mode + + omode.should == mode + end +end diff --git a/1.8/library/generator/each_spec.rb b/1.8/library/generator/each_spec.rb new file mode 100644 index 0000000000..926d76f4ac --- /dev/null +++ b/1.8/library/generator/each_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "Generator#each" do + it "enumerates the elements" do + g = GeneratorSpecs.four_elems + result = [] + + g.each { |element| + result << element + } + + result.should == ['A', 'B', 'C', 'Z'] + end + + it "rewinds the generator and only then enumerates the elements" do + g = GeneratorSpecs.four_elems + g.next; g.next + result = [] + + g.each { |element| + result << element + } + + result.should == ['A', 'B', 'C', 'Z'] + end +end diff --git a/1.8/library/generator/fixtures/common.rb b/1.8/library/generator/fixtures/common.rb new file mode 100644 index 0000000000..9d66e18024 --- /dev/null +++ b/1.8/library/generator/fixtures/common.rb @@ -0,0 +1,19 @@ +require 'generator' + +module GeneratorSpecs + def self.empty + Generator.new([]) + end + + def self.one_elem + Generator.new([1]) + end + + def self.two_elems + Generator.new([1, 2]) + end + + def self.four_elems + Generator.new(['A', 'B', 'C', 'Z']) + end +end diff --git a/1.8/library/generator/new_spec.rb b/1.8/library/generator/new_spec.rb new file mode 100644 index 0000000000..72d8cc0c5e --- /dev/null +++ b/1.8/library/generator/new_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'generator' + +describe "Generator.new" do + it "creates a new generator from an Enumerable object" do + g = Generator.new(['A', 'B', 'C', 'Z']) + g.should_not == nil + g.kind_of?(Generator).should == true + end + + it "creates a new generator from a block" do + g = Generator.new { |g| + for i in 'A'..'C' + g.yield i + end + g.yield 'Z' + } + + g.should_not == nil + g.kind_of?(Generator).should == true + end +end diff --git a/1.8/library/generator/next_spec.rb b/1.8/library/generator/next_spec.rb new file mode 100644 index 0000000000..b8b4f8185c --- /dev/null +++ b/1.8/library/generator/next_spec.rb @@ -0,0 +1,74 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "Generator#next?" do + it "returns false for empty generator" do + GeneratorSpecs.empty.next?.should == false + end + + it "returns true for non-empty generator" do + g = Generator.new([1]) + g.next?.should == true + + GeneratorSpecs.two_elems.next?.should == true + + g = Generator.new(['A', 'B', 'C', 'D', 'E', 'F']) + g.next?.should == true + end + + it "returns true if the generator has not reached the end yet" do + g = GeneratorSpecs.two_elems + g.next + g.next?.should == true + end + + it "returns false if the generator has reached the end" do + g = GeneratorSpecs.two_elems + g.next + g.next + g.next?.should == false + end + + it "returns false if end? returns true" do + g = GeneratorSpecs.two_elems + def g.end?; true end + g.next?.should == false + end +end + +describe "Generator#next" do + it "raises an EOFError on empty generator" do + lambda { GeneratorSpecs.empty.next }.should raise_error(EOFError) + end + + it "raises an EOFError if no elements available" do + g = GeneratorSpecs.two_elems + g.next; + g.next + lambda { g.next }.should raise_error(EOFError) + end + + it "raises an EOFError if end? returns true" do + g = GeneratorSpecs.two_elems + def g.end?; true end + lambda { g.next }.should raise_error(EOFError) + end + + it "returns the element at the current position and moves forward" do + g = GeneratorSpecs.two_elems + g.index.should == 0 + g.next.should == 1 + g.index.should == 1 + end + + it "subsequent calls should return all elements in proper order" do + g = GeneratorSpecs.four_elems + + result = [] + while g.next? + result << g.next + end + + result.should == ['A', 'B', 'C', 'Z'] + end +end diff --git a/1.8/library/generator/rewind_spec.rb b/1.8/library/generator/rewind_spec.rb new file mode 100644 index 0000000000..b32f8477b4 --- /dev/null +++ b/1.8/library/generator/rewind_spec.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "Generator#rewind" do + it "does nothing for empty generator" do + g = GeneratorSpecs.empty + g.index.should == 0 + g.rewind + g.index.should == 0 + end + + it "rewinds the generator" do + g = GeneratorSpecs.two_elems + orig = g.next + g.index.should == 1 + g.rewind + g.index.should == 0 + g.next.should == orig + end + + it "rewinds the previously finished generator" do + g = GeneratorSpecs.two_elems + g.next; g.next + g.rewind + g.end?.should == false + g.next?.should == true + g.next.should == 1 + end +end diff --git a/1.8/library/getoptlong/each_option_spec.rb b/1.8/library/getoptlong/each_option_spec.rb new file mode 100644 index 0000000000..670c8460f8 --- /dev/null +++ b/1.8/library/getoptlong/each_option_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' +require File.dirname(__FILE__) + '/shared/each' + +describe "GetoptLong#each_option" do + it_behaves_like(:getoptlong_each, :each_option) +end \ No newline at end of file diff --git a/1.8/library/getoptlong/each_spec.rb b/1.8/library/getoptlong/each_spec.rb new file mode 100644 index 0000000000..217c11fa6d --- /dev/null +++ b/1.8/library/getoptlong/each_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' +require File.dirname(__FILE__) + '/shared/each' + +describe "GetoptLong#each" do + it_behaves_like(:getoptlong_each, :each) +end \ No newline at end of file diff --git a/1.8/library/getoptlong/error_message_spec.rb b/1.8/library/getoptlong/error_message_spec.rb new file mode 100644 index 0000000000..e602bde992 --- /dev/null +++ b/1.8/library/getoptlong/error_message_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' + +describe "GetoptLong#error_message" do + before :each do + @stderr = $stderr + @argv = ARGV + end + + after :each do + $stderr = @stderr + ARGV = @argv + end + + it "returns nil if no error occurred" do + opts = GetoptLong.new + opts.error_message.should == nil + end + + it "returns the error message of the last error that occurred" do + begin + $stderr = IOStub.new + ARGV = [] + + opts = GetoptLong.new + opts.get + opts.ordering = GetoptLong::PERMUTE + rescue ArgumentError + opts.error_message.should == "argument error" + end + end +end \ No newline at end of file diff --git a/1.8/library/getoptlong/get_option_spec.rb b/1.8/library/getoptlong/get_option_spec.rb new file mode 100644 index 0000000000..45d2b59c64 --- /dev/null +++ b/1.8/library/getoptlong/get_option_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' +require File.dirname(__FILE__) + '/shared/get' + +describe "GetoptLong#get_option" do + it_behaves_like(:getoptlong_get, :get_option) +end \ No newline at end of file diff --git a/1.8/library/getoptlong/get_spec.rb b/1.8/library/getoptlong/get_spec.rb new file mode 100644 index 0000000000..f9d1857dd3 --- /dev/null +++ b/1.8/library/getoptlong/get_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' +require File.dirname(__FILE__) + '/shared/get' + +describe "GetoptLong#get" do + it_behaves_like(:getoptlong_get, :get) +end \ No newline at end of file diff --git a/1.8/library/getoptlong/initialize_spec.rb b/1.8/library/getoptlong/initialize_spec.rb new file mode 100644 index 0000000000..eab0942156 --- /dev/null +++ b/1.8/library/getoptlong/initialize_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' + +describe "GetoptLong#initialize" do + it "sets ordering to REQUIRE_ORDER if ENV['POSIXLY_CORRECT'] is set" do + begin + old_env_value = ENV["POSIXLY_CORRECT"] + ENV["POSIXLY_CORRECT"] = "" + + opt = GetoptLong.new + opt.ordering.should == GetoptLong::REQUIRE_ORDER + ensure + ENV["POSIXLY_CORRECT"] = old_env_value + end + end + + it "sets ordering to PERMUTE if ENV['POSIXLY_CORRECT'] is not set" do + begin + old_env_value = ENV["POSIXLY_CORRECT"] + ENV["POSIXLY_CORRECT"] = nil + + opt = GetoptLong.new + opt.ordering.should == GetoptLong::PERMUTE + ensure + ENV["POSIXLY_CORRECT"] = old_env_value + end + end +end \ No newline at end of file diff --git a/1.8/library/getoptlong/ordering_spec.rb b/1.8/library/getoptlong/ordering_spec.rb new file mode 100644 index 0000000000..5ffc7332e4 --- /dev/null +++ b/1.8/library/getoptlong/ordering_spec.rb @@ -0,0 +1,45 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' + +describe "GetoptLong#ordering=" do + it "raises an ArgumentError if called after processing has started" do + begin + s = $stderr + $stderr = IOStub.new + old_argv = ARGV + ARGV = [ "--size", "10k", "--verbose" ] + + opts = GetoptLong.new([ '--size', GetoptLong::REQUIRED_ARGUMENT ], + [ '--verbose', GetoptLong::NO_ARGUMENT ]) + opts.get + + lambda { + opts.ordering = GetoptLong::PERMUTE + }.should raise_error(ArgumentError) + ensure + ARGV = old_argv + $stderr = s + end + end + + it "raises an ArgumentError if given an invalid value" do + opts = GetoptLong.new + + lambda { + opts.ordering = 12345 + }.should raise_error(ArgumentError) + end + + it "does not allow changing ordering to PERMUTE if ENV['POSIXLY_CORRECT'] is set" do + begin + old_env_value = ENV['POSIXLY_CORRECT'] + ENV['POSIXLY_CORRECT'] = "" + + opts = GetoptLong.new + opts.ordering = GetoptLong::PERMUTE + opts.ordering.should == GetoptLong::REQUIRE_ORDER + ensure + ENV['POSIXLY_CORRECT'] = old_env_value + end + end +end \ No newline at end of file diff --git a/1.8/library/getoptlong/set_options_spec.rb b/1.8/library/getoptlong/set_options_spec.rb new file mode 100644 index 0000000000..710fce57a9 --- /dev/null +++ b/1.8/library/getoptlong/set_options_spec.rb @@ -0,0 +1,92 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' + +describe "GetoptLong#set_options" do + before :each do + @argv = ARGV + ARGV = [] + @opts = GetoptLong.new + end + + after :each do + ARGV = @argv + end + + it "allows setting command line options" do + ARGV = ["--size", "10k", "-v", "arg1", "arg2"] + + @opts.set_options( + ["--size", GetoptLong::REQUIRED_ARGUMENT], + ["--verbose", "-v", GetoptLong::NO_ARGUMENT] + ) + + @opts.get.should == ["--size", "10k"] + @opts.get.should == ["--verbose", ""] + @opts.get.should == nil + end + + it "discards previously defined command line options" do + ARGV = ["--size", "10k", "-v", "arg1", "arg2"] + + @opts.set_options( + ["--size", GetoptLong::REQUIRED_ARGUMENT], + ["--verbose", "-v", GetoptLong::NO_ARGUMENT] + ) + + @opts.set_options( + ["-s", "--size", GetoptLong::REQUIRED_ARGUMENT], + ["-v", GetoptLong::NO_ARGUMENT] + ) + + @opts.get.should == ["-s", "10k"] + @opts.get.should == ["-v", ""] + @opts.get.should == nil + end + + it "raises an ArgumentError if too many argument flags where given" do + lambda { + @opts.set_options(["--size", GetoptLong::NO_ARGUMENT, GetoptLong::REQUIRED_ARGUMENT]) + }.should raise_error(ArgumentError) + end + + it "raises a RuntimeError if processing has already started" do + @opts.get + lambda { + @opts.set_options() + }.should raise_error(RuntimeError) + end + + it "raises an ArgumentError if no argument flag was given" do + lambda { + @opts.set_options(["--size"]) + }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError if one of the given arguments is not an Array" do + lambda { + @opts.set_options( + ["--size", GetoptLong::REQUIRED_ARGUMENT], + "test") + }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError if the same option is given twice" do + lambda { + @opts.set_options( + ["--size", GetoptLong::NO_ARGUMENT], + ["--size", GetoptLong::OPTIONAL_ARGUMENT]) + }.should raise_error(ArgumentError) + + lambda { + @opts.set_options( + ["--size", GetoptLong::NO_ARGUMENT], + ["-s", "--size", GetoptLong::OPTIONAL_ARGUMENT]) + }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError if the given option is invalid" do + lambda { + @opts.set_options(["-size", GetoptLong::NO_ARGUMENT]) + }.should raise_error(ArgumentError) + end +end \ No newline at end of file diff --git a/1.8/library/getoptlong/shared/each.rb b/1.8/library/getoptlong/shared/each.rb new file mode 100644 index 0000000000..e52263416a --- /dev/null +++ b/1.8/library/getoptlong/shared/each.rb @@ -0,0 +1,25 @@ +shared :getoptlong_each do |cmd| + describe "GetoptLong##{cmd}" do + before(:each) do + @opts = GetoptLong.new( + [ '--size', '-s', GetoptLong::REQUIRED_ARGUMENT ], + [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ], + [ '--query', '-q', GetoptLong::NO_ARGUMENT ], + [ '--check', '--valid', '-c', GetoptLong::NO_ARGUMENT ] + ) + end + + it "passes each argument/value pair to the block" do + begin + old_argv = ARGV + ARGV = [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] + + pairs = [] + @opts.send(cmd) { |arg, val| pairs << [ arg, val ] } + pairs.should == [ [ "--size", "10k" ], [ "--verbose", "" ], [ "--query", ""] ] + ensure + ARGV = old_argv + end + end + end +end \ No newline at end of file diff --git a/1.8/library/getoptlong/shared/get.rb b/1.8/library/getoptlong/shared/get.rb new file mode 100644 index 0000000000..dd82877706 --- /dev/null +++ b/1.8/library/getoptlong/shared/get.rb @@ -0,0 +1,80 @@ +shared :getoptlong_get do |cmd| + describe "GetoptLong##{cmd}" do + before(:each) do + @opts = GetoptLong.new( + [ '--size', '-s', GetoptLong::REQUIRED_ARGUMENT ], + [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ], + [ '--query', '-q', GetoptLong::NO_ARGUMENT ], + [ '--check', '--valid', '-c', GetoptLong::NO_ARGUMENT ] + ) + end + + it "returns the next option name and its argument as an Array" do + begin + old_argv = ARGV + ARGV = [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] + + @opts.send(cmd).should == [ "--size", "10k" ] + @opts.send(cmd).should == [ "--verbose", "" ] + @opts.send(cmd).should == [ "--query", ""] + @opts.send(cmd).should == nil + ensure + ARGV = old_argv + end + end + + it "shifts ARGV on each call" do + begin + old_argv = ARGV + ARGV = [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] + + @opts.send(cmd) + ARGV.should == [ "-v", "-q", "a.txt", "b.txt" ] + + @opts.send(cmd) + ARGV.should == [ "-q", "a.txt", "b.txt" ] + + @opts.send(cmd) + ARGV.should == [ "a.txt", "b.txt" ] + + @opts.send(cmd) + ARGV.should == [ "a.txt", "b.txt" ] + ensure + ARGV = old_argv + end + end + + it "terminates processing when encountering '--'" do + begin + old_argv = ARGV + ARGV = [ "--size", "10k", "--", "-v", "-q", "a.txt", "b.txt" ] + + @opts.send(cmd) + ARGV.should == ["--", "-v", "-q", "a.txt", "b.txt"] + + @opts.send(cmd) + ARGV.should == ["-v", "-q", "a.txt", "b.txt"] + + @opts.send(cmd) + ARGV.should == ["-v", "-q", "a.txt", "b.txt"] + ensure + ARGV = old_argv + end + end + + it "raises a if an argument was required, but none given" do + begin + s = $stderr + $stderr = IOStub.new + old_argv = ARGV + ARGV = [ "--size" ] + + lambda { @opts.send(cmd) }.should raise_error(GetoptLong::MissingArgument) + ensure + ARGV = old_argv + $stderr = s + end + end + + end +end \ No newline at end of file diff --git a/1.8/library/getoptlong/terminate_spec.rb b/1.8/library/getoptlong/terminate_spec.rb new file mode 100644 index 0000000000..00b70832d0 --- /dev/null +++ b/1.8/library/getoptlong/terminate_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' + +describe "GetoptLong#terminate" do + before(:each) do + @opts = GetoptLong.new( + [ '--size', '-s', GetoptLong::REQUIRED_ARGUMENT ], + [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ], + [ '--query', '-q', GetoptLong::NO_ARGUMENT ], + [ '--check', '--valid', '-c', GetoptLong::NO_ARGUMENT ] + ) + end + + it "terminates option proccessing" do + begin + old_argv = ARGV + ARGV = [ "--size", "10k", "-v", "-q", "a.txt", "b.txt" ] + + @opts.get.should == [ "--size", "10k" ] + @opts.terminate + @opts.get.should == nil + ensure + ARGV = old_argv + end + end + + it "returns self when option processsing is terminated" do + @opts.terminate.should == @opts + end + + it "returns nil when option processing was already terminated" do + @opts.terminate + @opts.terminate.should == nil + end +end \ No newline at end of file diff --git a/1.8/library/getoptlong/terminated_spec.rb b/1.8/library/getoptlong/terminated_spec.rb new file mode 100644 index 0000000000..2463eb3cff --- /dev/null +++ b/1.8/library/getoptlong/terminated_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'getoptlong' + +describe "GetoptLong#terminated?" do + it "returns true if option processing has terminated" do + begin + old_argv_value = ARGV + ARGV = [ "--size", "10k" ] + opts = GetoptLong.new(["--size", GetoptLong::REQUIRED_ARGUMENT]) + opts.terminated?.should == false + + opts.get.should == ["--size", "10k"] + opts.terminated?.should == false + + opts.get.should == nil + opts.terminated?.should == true + ensure + ARGV = old_argv_value + end + end +end \ No newline at end of file diff --git a/1.8/library/ipaddr/hton_spec.rb b/1.8/library/ipaddr/hton_spec.rb new file mode 100644 index 0000000000..1ed49c5890 --- /dev/null +++ b/1.8/library/ipaddr/hton_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ipaddr' + +describe 'IPAddr#hton' do + + it 'should be able to convert IPAddr to network byte order' do + addr = '' + IPAddr.new("1234:5678:9abc:def0:1234:5678:9abc:def0").hton.each_byte do |c| + addr += sprintf("%02x", c) + end + addr.should == "123456789abcdef0123456789abcdef0" + addr = '' + IPAddr.new("123.45.67.89").hton.each_byte do |c| + addr += sprintf("%02x", c) + end + addr.should == sprintf("%02x%02x%02x%02x", 123, 45, 67, 89) + end + +end + +describe 'IPAddr#new_ntoh' do + + it "should be able to create a new IPAddr using hton notation" do + a = IPAddr.new("3ffe:505:2::") + IPAddr.new_ntoh(a.hton).to_s.should == "3ffe:505:2::" + a = IPAddr.new("192.168.2.1") + IPAddr.new_ntoh(a.hton).to_s.should == "192.168.2.1" + end + +end \ No newline at end of file diff --git a/1.8/library/ipaddr/ipv4_conversion_spec.rb b/1.8/library/ipaddr/ipv4_conversion_spec.rb new file mode 100644 index 0000000000..621f8b1591 --- /dev/null +++ b/1.8/library/ipaddr/ipv4_conversion_spec.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ipaddr' + +describe 'IPAddr#ipv4_compat' do + + it 'should ipv4_compat?' do + a = IPAddr.new("::192.168.1.2") + a.to_s.should == "::192.168.1.2" + a.to_string.should == "0000:0000:0000:0000:0000:0000:c0a8:0102" + a.family.should == Socket::AF_INET6 + a.ipv4_compat?.should == true + b = a.native + b.to_s.should == "192.168.1.2" + b.family.should == Socket::AF_INET + b.ipv4_compat?.should == false + + a = IPAddr.new("192.168.1.2") + b = a.ipv4_compat + b.to_s.should == "::192.168.1.2" + b.family.should == Socket::AF_INET6 + end + +end + +describe 'IPAddr#ipv4_mapped' do + + it 'should ipv4_mapped' do + a = IPAddr.new("::ffff:192.168.1.2") + a.to_s.should == "::ffff:192.168.1.2" + a.to_string.should == "0000:0000:0000:0000:0000:ffff:c0a8:0102" + a.family.should == Socket::AF_INET6 + a.ipv4_mapped?.should == true + b = a.native + b.to_s.should == "192.168.1.2" + b.family.should == Socket::AF_INET + b.ipv4_mapped?.should == false + + a = IPAddr.new("192.168.1.2") + b = a.ipv4_mapped + b.to_s.should == "::ffff:192.168.1.2" + b.family.should == Socket::AF_INET6 + end + +end + + diff --git a/1.8/library/ipaddr/new_spec.rb b/1.8/library/ipaddr/new_spec.rb new file mode 100644 index 0000000000..0ebb95ac30 --- /dev/null +++ b/1.8/library/ipaddr/new_spec.rb @@ -0,0 +1,87 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ipaddr' + +describe "IPAddr#new" do + it 'it should initialize IPAddr' do + lambda{ IPAddr.new("3FFE:505:ffff::/48") }.should_not raise_error + lambda{ IPAddr.new("0:0:0:1::") }.should_not raise_error + lambda{ IPAddr.new("2001:200:300::/48") }.should_not raise_error + end + + it 'it should initialize IPAddr ipv6 address with short notation' do + a = IPAddr.new + a.to_s.should == "::" + a.to_string.should == "0000:0000:0000:0000:0000:0000:0000:0000" + a.family.should == Socket::AF_INET6 + end + + it 'it should initialize IPAddr ipv6 address with long notation' do + a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678") + a.to_s.should == "123:4567:89ab:cdef:abc:def0:1234:5678" + a.to_string.should == "0123:4567:89ab:cdef:0abc:def0:1234:5678" + a.family.should == Socket::AF_INET6 + end + + it 'it should initialize IPAddr ipv6 address with / subnet notation' do + a = IPAddr.new("3ffe:505:2::/48") + a.to_s.should == "3ffe:505:2::" + a.to_string.should == "3ffe:0505:0002:0000:0000:0000:0000:0000" + a.family.should == Socket::AF_INET6 + a.ipv4?.should == false + a.ipv6?.should == true + a.inspect.should == "#" + end + + it 'it should initialize IPAddr ipv6 address with mask subnet notation' do + a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::") + a.to_s.should == "3ffe:505:2::" + a.to_string.should == "3ffe:0505:0002:0000:0000:0000:0000:0000" + a.family.should == Socket::AF_INET6 + end + + it 'it should initialize IPAddr ipv4 address with all zeroes' do + a = IPAddr.new("0.0.0.0") + a.to_s.should == "0.0.0.0" + a.to_string.should == "0.0.0.0" + a.family.should == Socket::AF_INET + end + + it 'it should initialize IPAddr ipv4 address' do + a = IPAddr.new("192.168.1.2") + a.to_s.should == "192.168.1.2" + a.to_string.should == "192.168.1.2" + a.family.should == Socket::AF_INET + a.ipv4?.should == true + a.ipv6?.should == false + end + + it 'it should initialize IPAddr ipv4 address with / subnet notation' do + a = IPAddr.new("192.168.1.2/24") + a.to_s.should == "192.168.1.0" + a.to_string.should == "192.168.1.0" + a.family.should == Socket::AF_INET + a.inspect.should == "#" + end + + it 'it should initialize IPAddr ipv4 address wuth subnet mask' do + a = IPAddr.new("192.168.1.2/255.255.255.0") + a.to_s.should == "192.168.1.0" + a.to_string.should == "192.168.1.0" + a.family.should == Socket::AF_INET + end + + it 'it should raise errors on incorrect IPAddr strings' do + [ + ["fe80::1%fxp0"], + ["::1/255.255.255.0"], + ["::1:192.168.1.2/120"], + [IPAddr.new("::1").to_i], + ["::ffff:192.168.1.2/120", Socket::AF_INET], + ["[192.168.1.2]/120"], + ].each { |args| + lambda{ + IPAddr.new(*args) + }.should raise_error(ArgumentError) + } + end +end \ No newline at end of file diff --git a/1.8/library/ipaddr/operator_spec.rb b/1.8/library/ipaddr/operator_spec.rb new file mode 100644 index 0000000000..582440d6e7 --- /dev/null +++ b/1.8/library/ipaddr/operator_spec.rb @@ -0,0 +1,80 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ipaddr' + +describe 'IPAddr Operator' do + IN6MASK32 = "ffff:ffff::" + IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + + before do + @in6_addr_any = IPAddr.new() + @a = IPAddr.new("3ffe:505:2::/48") + @b = IPAddr.new("0:0:0:1::") + @c = IPAddr.new(IN6MASK32) + end + + it 'should be able to bitwise or' do + (@a | @b).to_s.should == "3ffe:505:2:1::" + a = @a + a |= @b + a.to_s.should == "3ffe:505:2:1::" + @a.to_s.should == "3ffe:505:2::" + (@a | 0x00000000000000010000000000000000).to_s.should == "3ffe:505:2:1::" + end + + it 'should be able to bitwise and' do + (@a & @c).to_s.should == "3ffe:505::" + a = @a + a &= @c + a.to_s.should == "3ffe:505::" + @a.to_s.should == "3ffe:505:2::" + (@a & 0xffffffff000000000000000000000000).to_s.should == "3ffe:505::" + end + + it 'should be able to bitshift right' do + (@a >> 16).to_s.should == "0:3ffe:505:2::" + a = @a + a >>= 16 + a.to_s.should == "0:3ffe:505:2::" + @a.to_s.should == "3ffe:505:2::" + end + + it 'should be able to bitshift left' do + (@a << 16).to_s.should == "505:2::" + a = @a + a <<= 16 + a.to_s.should == "505:2::" + @a.to_s.should == "3ffe:505:2::" + end + + it 'should be able to invert' do + a = ~@in6_addr_any + a.to_s.should == IN6MASK128 + @in6_addr_any.to_s.should == "::" + end + + it 'should be able to test for equality' do + @a.should == IPAddr.new("3ffe:505:2::") + @a.should_not == IPAddr.new("3ffe:505:3::") + end + + it 'should be able to set a mask' do + a = @a.mask(32) + a.to_s.should == "3ffe:505::" + @a.to_s.should == "3ffe:505:2::" + end + + it 'should be able to check whether an addres is included in a range' do + @a.should include(IPAddr.new("3ffe:505:2::")) + @a.should include(IPAddr.new("3ffe:505:2::1")) + @a.should_not include(IPAddr.new("3ffe:505:3::")) + net1 = IPAddr.new("192.168.2.0/24") + net1.should include(IPAddr.new("192.168.2.0")) + net1.should include(IPAddr.new("192.168.2.255")) + net1.should_not include(IPAddr.new("192.168.3.0")) + # test with integer parameter + int = (192 << 24) + (168 << 16) + (2 << 8) + 13 + + net1.should include(int) + net1.should_not include(int+255) + end +end \ No newline at end of file diff --git a/1.8/library/ipaddr/reverse_spec.rb b/1.8/library/ipaddr/reverse_spec.rb new file mode 100644 index 0000000000..0852b99d68 --- /dev/null +++ b/1.8/library/ipaddr/reverse_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ipaddr' + +describe "IPAddr#reverse" do + it 'should be able to generate the reverse DNS lookup entry' do + IPAddr.new("3ffe:505:2::f").reverse.should == "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa" + IPAddr.new("192.168.2.1").reverse.should == "1.2.168.192.in-addr.arpa" + end +end + +describe "IPAddr#ip6_arpa" do + it 'should be able to convert an IPv6 address into the reverse DNS lookup representation according to RFC3172' do + IPAddr.new("3ffe:505:2::f").ip6_arpa.should == "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa" + lambda{ + IPAddr.new("192.168.2.1").ip6_arpa + }.should raise_error(ArgumentError) + end +end + +describe "IPAddr#ip6_int" do + it 'should be able to convert an IPv6 address into the reverse DNS lookup representation according to RFC1886' do + IPAddr.new("3ffe:505:2::f").ip6_int.should == "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int" + lambda{ + IPAddr.new("192.168.2.1").ip6_int + }.should raise_error(ArgumentError) + end +end \ No newline at end of file diff --git a/1.8/library/ipaddr/to_s_spec.rb b/1.8/library/ipaddr/to_s_spec.rb new file mode 100644 index 0000000000..b2931a04ea --- /dev/null +++ b/1.8/library/ipaddr/to_s_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ipaddr' + +describe "IPAddr#to_s" do + + it 'it should display IPAddr using short notation' do + IPAddr.new("0:0:0:1::").to_s.should == "0:0:0:1::" + IPAddr.new("2001:200:300::/48").to_s.should == "2001:200:300::" + IPAddr.new("[2001:200:300::]/48").to_s.should == "2001:200:300::" + IPAddr.new("3ffe:505:2::1").to_s.should == "3ffe:505:2::1" + end + +end + +describe "IPAddr#to_string" do + + it "should be able to display an IPAddr using full notation" do + IPAddr.new("3ffe:505:2::1").to_string.should == "3ffe:0505:0002:0000:0000:0000:0000:0001" + end + +end \ No newline at end of file diff --git a/1.8/library/matrix/Fail_spec.rb b/1.8/library/matrix/Fail_spec.rb new file mode 100644 index 0000000000..2ed3311fc0 --- /dev/null +++ b/1.8/library/matrix/Fail_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#Fail" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/I_spec.rb b/1.8/library/matrix/I_spec.rb new file mode 100644 index 0000000000..798cd6c6c3 --- /dev/null +++ b/1.8/library/matrix/I_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/identity' + +describe "Matrix.I" do + it_behaves_like(:matrix_identity, :I) +end diff --git a/1.8/library/matrix/Raise_spec.rb b/1.8/library/matrix/Raise_spec.rb new file mode 100644 index 0000000000..a629cc0a3b --- /dev/null +++ b/1.8/library/matrix/Raise_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#Raise" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/clone_spec.rb b/1.8/library/matrix/clone_spec.rb new file mode 100644 index 0000000000..9429a5e207 --- /dev/null +++ b/1.8/library/matrix/clone_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#clone" do + before(:each) do + @a = Matrix[[1, 2], [3, 4], [5, 6]] + end + + it "returns a shallow copy of the matrix" do + b = @a.clone + @a.should_not.equal?(b) + b.class.should == Matrix + b.should == @a + 0.upto(@a.row_size - 1) do |i| + @a.row(i).should_not.equal?(b.row(i)) + end + end + + before(:each) do + @a = Matrix[[1, 2], [3, 4], [5, 6]] + end + +quarantine! do # The test fails on MRI 1.8.6 pl 111, pl 114, MRI 1.8.7, JRuby + it "returns a copy of the matrix, but with all the references different" do + b = @a.clone + b.class.should == Matrix + b.should == @a + b.should_not === @a + 0.upto(@a.row_size - 1) do |i| + 0.upto(@a.column_size - 1) do |j| + b[i, j].should == @a[i, j] + b[i, j].should_not === @a[i, j] + end + end + end +end + +end diff --git a/1.8/library/matrix/coerce_spec.rb b/1.8/library/matrix/coerce_spec.rb new file mode 100644 index 0000000000..de86cc20b1 --- /dev/null +++ b/1.8/library/matrix/coerce_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#coerce" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/collect_spec.rb b/1.8/library/matrix/collect_spec.rb new file mode 100644 index 0000000000..7546a45aed --- /dev/null +++ b/1.8/library/matrix/collect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/collect' +require 'matrix' + +describe "Matrix#collect" do + it_behaves_like(:collect, :collect) +end \ No newline at end of file diff --git a/1.8/library/matrix/column_size_spec.rb b/1.8/library/matrix/column_size_spec.rb new file mode 100644 index 0000000000..92f82900b7 --- /dev/null +++ b/1.8/library/matrix/column_size_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#column_size" do + it "returns the number of elements in a column" do + data = [[1,2]] + Matrix[ *data ].column_size.should == 2 + end + + it "raises an exception on an empty Matrix" do + # Note that MRI raises NoMethodError because #size is called + # on nil. This appears to be more of an "oops" rather than + # an aspect of the interface. We don't spec the exception class. + lambda{ Matrix[].column_size }.should raise_error + end +end + diff --git a/1.8/library/matrix/column_spec.rb b/1.8/library/matrix/column_spec.rb new file mode 100644 index 0000000000..b20a669440 --- /dev/null +++ b/1.8/library/matrix/column_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#column" do + before :all do + @data = [[1,2],[1,2]] + end + + it "returns a Vector when called without a block" do + Matrix[ *@data ].column(1).should == Vector[2,2] + end + + it "yields each element in the column to the block" do + Matrix[ *@data ].column(1) do |n| + n.should == 2 + end + end +end \ No newline at end of file diff --git a/1.8/library/matrix/column_vector_spec.rb b/1.8/library/matrix/column_vector_spec.rb new file mode 100644 index 0000000000..e9a9af7b85 --- /dev/null +++ b/1.8/library/matrix/column_vector_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.column_vector" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/column_vectors_spec.rb b/1.8/library/matrix/column_vectors_spec.rb new file mode 100644 index 0000000000..e0a050c4cf --- /dev/null +++ b/1.8/library/matrix/column_vectors_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#column_vectors" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/columns_spec.rb b/1.8/library/matrix/columns_spec.rb new file mode 100644 index 0000000000..0644c4c112 --- /dev/null +++ b/1.8/library/matrix/columns_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.columns" do + before :each do + @a = [1, 2] + @b = [3, 4] + @m = Matrix.columns([@a, @b]) + end + + it "creates a matrix from argument columns" do + @m.column(0).to_a.should == @a + @m.column(1).to_a.should == @b + end +end diff --git a/1.8/library/matrix/compare_by_row_vectors_spec.rb b/1.8/library/matrix/compare_by_row_vectors_spec.rb new file mode 100644 index 0000000000..7dd8b4fca1 --- /dev/null +++ b/1.8/library/matrix/compare_by_row_vectors_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#compare_by_row_vectors" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/det_spec.rb b/1.8/library/matrix/det_spec.rb new file mode 100644 index 0000000000..fd461ab497 --- /dev/null +++ b/1.8/library/matrix/det_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#det" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/determinant_spec.rb b/1.8/library/matrix/determinant_spec.rb new file mode 100644 index 0000000000..1ff84c759e --- /dev/null +++ b/1.8/library/matrix/determinant_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#determinant" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/diagonal_spec.rb b/1.8/library/matrix/diagonal_spec.rb new file mode 100644 index 0000000000..848033658f --- /dev/null +++ b/1.8/library/matrix/diagonal_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.diagonal" do + before(:each) do + @m = Matrix.diagonal(10, 11, 12, 13, 14) + end + + it "returns an object of type Matrix" do + @m.class.should == Matrix + end + + it "sets the diagonal to the arguments" do + (0..4).each do |i| + @m[i, i].should == i + 10 + end + end + + it "fills all non-diagonal cells with 0" do + (0..4).each do |i| + (0..4).each do |j| + if i != j + @m[i, j].should == 0 + end + end + end + end +end diff --git a/1.8/library/matrix/divide_spec.rb b/1.8/library/matrix/divide_spec.rb new file mode 100644 index 0000000000..9b8b0fe2bc --- /dev/null +++ b/1.8/library/matrix/divide_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#/" do + before :each do + @a = Matrix[ [1, 2], [3, 4] ] + @b = Matrix[ [4, 5], [6, 7] ] + @c = Matrix[ [1.2, 2.4], [3.6, 4.8] ] + end + + it "returns the result of dividing self by another Matrix" do + (@a / @b).should == Matrix[ [-2, 0], [-4, 0] ] + ((@a / @b) / @b).should == Matrix[ [0,0], [0,0] ] + end + + it "returns the result of dividing self by a Fixnum" do + (@a / 2).should == Matrix[ [0, 1], [1, 2] ] + end + + it "returns the result of dividing self by a Bignum" do + (@a / bignum_value).should == Matrix[ [0, 0], [0, 0] ] + end + + it "returns the result of dividing self by a Float" do + (@c / 1.2).should == Matrix[ [1, 2], [3, 4] ] + end + + it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do + lambda { @a / Matrix[ 1 ] }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "returns an instance of Matrix" do + (@a /@b).should be_kind_of(Matrix) + end +end diff --git a/1.8/library/matrix/element_reference_spec.rb b/1.8/library/matrix/element_reference_spec.rb new file mode 100644 index 0000000000..1d67ac60fd --- /dev/null +++ b/1.8/library/matrix/element_reference_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.[]" do + # Matrix.[] is really a constructor, not an element reference function... + + before(:each) do + @a = [1, 2, 3] + @b = [4, 5, 6] + @c = [7, 8, 9] + @m = Matrix[@a, @b, @c] + end + + it "returns an object of type Matrix" do + @m.class.should == Matrix + end + + it "makes each argument into a row" do + @m.row(0).to_a.should == @a + @m.row(1).to_a.should == @b + @m.row(2).to_a.should == @c + end +end + +describe "Matrix#[]" do + it "returns element at (i, j)" do + m = Matrix[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]] + (0..3).each do |i| + (0..2).each do |j| + m[i, j].should == (i * 3) + j + end + end + end +end diff --git a/1.8/library/matrix/eql_spec.rb b/1.8/library/matrix/eql_spec.rb new file mode 100644 index 0000000000..8a7b0fc2f8 --- /dev/null +++ b/1.8/library/matrix/eql_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#eql?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/equal_value_spec.rb b/1.8/library/matrix/equal_value_spec.rb new file mode 100644 index 0000000000..90dbbb043a --- /dev/null +++ b/1.8/library/matrix/equal_value_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#==" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/exponent_spec.rb b/1.8/library/matrix/exponent_spec.rb new file mode 100644 index 0000000000..d853066b6e --- /dev/null +++ b/1.8/library/matrix/exponent_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#**" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/hash_spec.rb b/1.8/library/matrix/hash_spec.rb new file mode 100644 index 0000000000..dae8197dd3 --- /dev/null +++ b/1.8/library/matrix/hash_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#hash" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/identity_spec.rb b/1.8/library/matrix/identity_spec.rb new file mode 100644 index 0000000000..a636c263c7 --- /dev/null +++ b/1.8/library/matrix/identity_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/identity' + +describe "Matrix.identity" do + it_behaves_like(:matrix_identity, :identity) +end diff --git a/1.8/library/matrix/included_spec.rb b/1.8/library/matrix/included_spec.rb new file mode 100644 index 0000000000..db56a7db4d --- /dev/null +++ b/1.8/library/matrix/included_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.included" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/init_rows_spec.rb b/1.8/library/matrix/init_rows_spec.rb new file mode 100644 index 0000000000..48fe3ac0bf --- /dev/null +++ b/1.8/library/matrix/init_rows_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#init_rows" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/initialize_spec.rb b/1.8/library/matrix/initialize_spec.rb new file mode 100644 index 0000000000..3f2d88ede6 --- /dev/null +++ b/1.8/library/matrix/initialize_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#initialize" do + it "is private" do + Matrix[].private_methods.should include("initialize") + end + + it "returns an instance of Matrix" do + Matrix[].should be_kind_of(Matrix) + end +end diff --git a/1.8/library/matrix/inspect_spec.rb b/1.8/library/matrix/inspect_spec.rb new file mode 100644 index 0000000000..d5b9a59e53 --- /dev/null +++ b/1.8/library/matrix/inspect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#inspect" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/inv_spec.rb b/1.8/library/matrix/inv_spec.rb new file mode 100644 index 0000000000..4c9f21cb68 --- /dev/null +++ b/1.8/library/matrix/inv_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#inv" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/inverse_from_spec.rb b/1.8/library/matrix/inverse_from_spec.rb new file mode 100644 index 0000000000..6eb236df4e --- /dev/null +++ b/1.8/library/matrix/inverse_from_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#inverse_from" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/inverse_spec.rb b/1.8/library/matrix/inverse_spec.rb new file mode 100644 index 0000000000..46cf1f5525 --- /dev/null +++ b/1.8/library/matrix/inverse_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#inverse" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/map_spec.rb b/1.8/library/matrix/map_spec.rb new file mode 100644 index 0000000000..8d74c63fcd --- /dev/null +++ b/1.8/library/matrix/map_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/collect' +require 'matrix' + +describe "Matrix#map" do + it_behaves_like(:collect, :map) +end \ No newline at end of file diff --git a/1.8/library/matrix/minor_spec.rb b/1.8/library/matrix/minor_spec.rb new file mode 100644 index 0000000000..03a48b6ebc --- /dev/null +++ b/1.8/library/matrix/minor_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#minor" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/minus_spec.rb b/1.8/library/matrix/minus_spec.rb new file mode 100644 index 0000000000..2571592b6a --- /dev/null +++ b/1.8/library/matrix/minus_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#-" do + before :each do + @a = Matrix[ [1, 2], [3, 4] ] + @b = Matrix[ [4, 5], [6, 7] ] + end + + it "returns the result of subtracting the corresponding elements of other from self" do + (@a - @b).should == Matrix[ [-3,-3], [-3,-3] ] + end + + it "returns an instance of Matrix" do + (@a - @b).should be_kind_of(Matrix) + end + + it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do + lambda { @a - Matrix[ 1 ] }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do + lambda { @a - 2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + lambda { @a - 1.2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + lambda { @a - bignum_value }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + end + + it "raises an exception if other is not a Matrix" do + # Note that MRI raises NoMethodError because #coerce is called + # on objects that don't provide it. This appears to be more of + # an "oops" rather than an aspect of the interface. We don't + # spec the exception class. + + lambda { @a - nil }.should raise_error + lambda { @a - "a" }.should raise_error + lambda { @a - [ [1, 2] ] }.should raise_error + lambda { @a - Object.new }.should raise_error + end +end diff --git a/1.8/library/matrix/multiply_spec.rb b/1.8/library/matrix/multiply_spec.rb new file mode 100644 index 0000000000..c1949fc189 --- /dev/null +++ b/1.8/library/matrix/multiply_spec.rb @@ -0,0 +1,36 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#*" do + before :each do + @a = Matrix[ [1, 2], [3, 4] ] + @b = Matrix[ [4, 5], [6, 7] ] + end + + it "returns the result of multiplying the corresponding elements of self and a Matrix" do + (@a * @b).should == Matrix[ [16,19], [36,43] ] + end + + it "returns the result of multiplying the corresponding elements of self and a Vector" do + (@a * Vector[1,2]).should == Vector[5, 11] + end + + it "returns the result of multiplying the elements of self and a Fixnum" do + (@a * 2).should == Matrix[ [2, 4], [6, 8] ] + end + + it "returns the result of multiplying the elements of self and a Bignum" do + (@a * bignum_value).should == Matrix[ + [9223372036854775808, 18446744073709551616], + [27670116110564327424, 36893488147419103232] + ] + end + + it "returns the result of multiplying the elements of self and a Float" do + (@a * 2.0).should == Matrix[ [2.0, 4.0], [6.0, 8.0] ] + end + + it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do + lambda { @a * Matrix[ 1 ] }.should raise_error(Matrix::ErrDimensionMismatch) + end +end diff --git a/1.8/library/matrix/new_spec.rb b/1.8/library/matrix/new_spec.rb new file mode 100644 index 0000000000..2a57b33f2b --- /dev/null +++ b/1.8/library/matrix/new_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#new" do + + it "should a Matrix" do + lambda { Matrix.new }.should raise_error + end + +end diff --git a/1.8/library/matrix/plus_spec.rb b/1.8/library/matrix/plus_spec.rb new file mode 100644 index 0000000000..45b6a8cb5b --- /dev/null +++ b/1.8/library/matrix/plus_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#+" do + before :each do + @a = Matrix[ [1,2], [3,4] ] + @b = Matrix[ [4,5], [6,7] ] + end + + it "returns the result of adding the corresponding elements of self and other" do + (@a + @b).should == Matrix[ [5,7], [9,11] ] + end + + it "returns an instance of Matrix" do + (@a + @b).should be_kind_of(Matrix) + end + + it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do + lambda { @a + Matrix[ 1 ] }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do + lambda { @a + 2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + lambda { @a + 1.2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + lambda { @a + bignum_value }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + end + + it "raises an exception if other is not a Matrix" do + # Note that MRI raises NoMethodError because #coerce is called + # on objects that don't provide it. This appears to be more of + # an "oops" rather than an aspect of the interface. We don't + # spec the exception class. + + lambda { @a + nil }.should raise_error + lambda { @a + "a" }.should raise_error + lambda { @a + [ [1, 2] ] }.should raise_error + lambda { @a + Object.new }.should raise_error + end +end diff --git a/1.8/library/matrix/rank_spec.rb b/1.8/library/matrix/rank_spec.rb new file mode 100644 index 0000000000..5afcb9b056 --- /dev/null +++ b/1.8/library/matrix/rank_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#rank" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/regular_spec.rb b/1.8/library/matrix/regular_spec.rb new file mode 100644 index 0000000000..101f3d3561 --- /dev/null +++ b/1.8/library/matrix/regular_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#regular?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/row_size_spec.rb b/1.8/library/matrix/row_size_spec.rb new file mode 100644 index 0000000000..2c7ba79096 --- /dev/null +++ b/1.8/library/matrix/row_size_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#row_size" do + it "returns the number of elements in a row" do + data = [[1,2], [3, 4]] + Matrix[ *data ].row_size.should == 2 + end + + it "returns 0 for an empty Matrix" do + Matrix[].row_size.should == 0 + end +end diff --git a/1.8/library/matrix/row_spec.rb b/1.8/library/matrix/row_spec.rb new file mode 100644 index 0000000000..86c7f8bd55 --- /dev/null +++ b/1.8/library/matrix/row_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#row" do + before :all do + @data = [ [1, 2], [1, 2] ] + end + + it "returns a Vector when called without a block" do + Matrix[ *@data ].row(0).should == Vector[1,2] + end + + it "returns an Array when called with a block" do + Matrix[ *@data ].row(0) { |x| x }.should == [1, 2] + end +end \ No newline at end of file diff --git a/1.8/library/matrix/row_vector_spec.rb b/1.8/library/matrix/row_vector_spec.rb new file mode 100644 index 0000000000..1c65439850 --- /dev/null +++ b/1.8/library/matrix/row_vector_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.row_vector" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/row_vectors_spec.rb b/1.8/library/matrix/row_vectors_spec.rb new file mode 100644 index 0000000000..c26dc7bca0 --- /dev/null +++ b/1.8/library/matrix/row_vectors_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#row_vectors" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/rows_spec.rb b/1.8/library/matrix/rows_spec.rb new file mode 100644 index 0000000000..106d7af5d0 --- /dev/null +++ b/1.8/library/matrix/rows_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.rows" do + before :each do + @a = [1, 2] + @b = [3, 4] + @m = Matrix.rows([@a, @b]) + end + + it "returns a Matrix" do + @m.class.should == Matrix + end + + it "creates a matrix from argument rows" do + @m.row(0).to_a.should == @a + @m.row(1).to_a.should == @b + end + + it "copies the original rows by default" do + @a << 3 + @b << 6 + @m.row(0).equal?(@a).should == false + @m.row(1).equal?(@b).should == false + end + + it "references the original rows if copy is false" do + @m_ref = Matrix.rows([@a, @b], false) + @a << 3 + @b << 6 + @m_ref.row(0).to_a.should == @a + @m_ref.row(1).to_a.should == @b + end +end diff --git a/1.8/library/matrix/scalar/Fail_spec.rb b/1.8/library/matrix/scalar/Fail_spec.rb new file mode 100644 index 0000000000..8ba9fd4641 --- /dev/null +++ b/1.8/library/matrix/scalar/Fail_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#Fail" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar/Raise_spec.rb b/1.8/library/matrix/scalar/Raise_spec.rb new file mode 100644 index 0000000000..ad67e8d5fd --- /dev/null +++ b/1.8/library/matrix/scalar/Raise_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#Raise" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar/divide_spec.rb b/1.8/library/matrix/scalar/divide_spec.rb new file mode 100644 index 0000000000..8ab1bf20e1 --- /dev/null +++ b/1.8/library/matrix/scalar/divide_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#/" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar/exponent_spec.rb b/1.8/library/matrix/scalar/exponent_spec.rb new file mode 100644 index 0000000000..6413acfe99 --- /dev/null +++ b/1.8/library/matrix/scalar/exponent_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#**" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar/included_spec.rb b/1.8/library/matrix/scalar/included_spec.rb new file mode 100644 index 0000000000..7da6009014 --- /dev/null +++ b/1.8/library/matrix/scalar/included_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar.included" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar/initialize_spec.rb b/1.8/library/matrix/scalar/initialize_spec.rb new file mode 100644 index 0000000000..2b60b2a962 --- /dev/null +++ b/1.8/library/matrix/scalar/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar/minus_spec.rb b/1.8/library/matrix/scalar/minus_spec.rb new file mode 100644 index 0000000000..6986d0e75b --- /dev/null +++ b/1.8/library/matrix/scalar/minus_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#-" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar/multiply_spec.rb b/1.8/library/matrix/scalar/multiply_spec.rb new file mode 100644 index 0000000000..d1b61710a9 --- /dev/null +++ b/1.8/library/matrix/scalar/multiply_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#*" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar/plus_spec.rb b/1.8/library/matrix/scalar/plus_spec.rb new file mode 100644 index 0000000000..a7bcb90c82 --- /dev/null +++ b/1.8/library/matrix/scalar/plus_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#+" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/scalar_spec.rb b/1.8/library/matrix/scalar_spec.rb new file mode 100644 index 0000000000..1dcf1484f6 --- /dev/null +++ b/1.8/library/matrix/scalar_spec.rb @@ -0,0 +1,67 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.scalar" do + + before(:each) do + @side = 3 + @value = 8 + @a = Matrix.scalar(@side, @value) + end + + it "returns a Matrix" do + @a.class.should == Matrix + end + + it "returns a n x n matrix" do + @a.row_size.should == @side + @a.column_size.should == @side + end + + it "initializes diagonal to value" do + (0...@a.row_size).each do |i| + @a[i, i].should == @value + end + end + + it "initializes all non-diagonal values to 0" do + (0...@a.row_size).each do |i| + (0...@a.column_size).each do |j| + if i != j + @a[i, j].should == 0 + end + end + end + end + + before(:each) do + @side = 3 + @value = 8 + @a = Matrix.scalar(@side, @value) + end + + it "returns a Matrix" do + @a.class.should == Matrix + end + + it "returns a square matrix, where the first argument specifies the side of the square" do + @a.row_size.should == @side + @a.column_size.should == @side + end + + it "puts the second argument in all diagonal values" do + (0...@a.row_size).each do |i| + @a[i, i].should == @value + end + end + + it "fills all values not on the main diagonal with 0" do + (0...@a.row_size).each do |i| + (0...@a.column_size).each do |j| + if i != j + @a[i, j].should == 0 + end + end + end + end +end diff --git a/1.8/library/matrix/shared/collect.rb b/1.8/library/matrix/shared/collect.rb new file mode 100644 index 0000000000..e1762b7a30 --- /dev/null +++ b/1.8/library/matrix/shared/collect.rb @@ -0,0 +1,15 @@ +shared :collect do |cmd| + describe "Matrix##{cmd}" do + before :all do + @data = [ [1, 2], [1, 2] ] + end + + it "returns an instance of Matrix" do + Matrix[ *@data ].send(cmd){|n| n * 2 }.should be_kind_of(Matrix) + end + + it "returns a Matrix where each element is the result of the block" do + Matrix[ *@data ].send(cmd) { |n| n * 2 }.should == Matrix[ [2, 4], [2, 4] ] + end + end +end diff --git a/1.8/library/matrix/shared/identity.rb b/1.8/library/matrix/shared/identity.rb new file mode 100644 index 0000000000..c36c6a253f --- /dev/null +++ b/1.8/library/matrix/shared/identity.rb @@ -0,0 +1,14 @@ +require 'matrix' + +shared :matrix_identity do |cmd| + describe "Matrix.#{cmd}" do + it "returns a Matrix" do + Matrix.send(cmd, 2).class.should == Matrix + end + + it "returns a n x n identity matrix" do + Matrix.send(cmd, 3).should == Matrix.scalar(3, 1) + Matrix.send(cmd, 100).should == Matrix.scalar(100, 1) + end + end +end diff --git a/1.8/library/matrix/shared/transpose.rb b/1.8/library/matrix/shared/transpose.rb new file mode 100644 index 0000000000..dca6493e6f --- /dev/null +++ b/1.8/library/matrix/shared/transpose.rb @@ -0,0 +1,9 @@ +require 'matrix' + +shared :matrix_transpose do |cmd| + describe "Matrix##{cmd}" do + it "returns a transposed matrix" do + Matrix[[1, 2], [3, 4], [5, 6]].transpose.should == Matrix[[1, 3, 5], [2, 4, 6]] + end + end +end diff --git a/1.8/library/matrix/singular_spec.rb b/1.8/library/matrix/singular_spec.rb new file mode 100644 index 0000000000..59d2e17155 --- /dev/null +++ b/1.8/library/matrix/singular_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#singular?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/square_spec.rb b/1.8/library/matrix/square_spec.rb new file mode 100644 index 0000000000..c6b08d27d4 --- /dev/null +++ b/1.8/library/matrix/square_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#square?" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/t_spec.rb b/1.8/library/matrix/t_spec.rb new file mode 100644 index 0000000000..f9050924c1 --- /dev/null +++ b/1.8/library/matrix/t_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/transpose' + +describe "Matrix#transpose" do + it_behaves_like(:matrix_transpose, :t) +end diff --git a/1.8/library/matrix/to_a_spec.rb b/1.8/library/matrix/to_a_spec.rb new file mode 100644 index 0000000000..443d482c15 --- /dev/null +++ b/1.8/library/matrix/to_a_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#to_a" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/to_s_spec.rb b/1.8/library/matrix/to_s_spec.rb new file mode 100644 index 0000000000..45916859e8 --- /dev/null +++ b/1.8/library/matrix/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#to_s" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/tr_spec.rb b/1.8/library/matrix/tr_spec.rb new file mode 100644 index 0000000000..bb9778aab2 --- /dev/null +++ b/1.8/library/matrix/tr_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#tr" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/trace_spec.rb b/1.8/library/matrix/trace_spec.rb new file mode 100644 index 0000000000..a5d182f631 --- /dev/null +++ b/1.8/library/matrix/trace_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix#trace" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/matrix/transpose_spec.rb b/1.8/library/matrix/transpose_spec.rb new file mode 100644 index 0000000000..5fcbe10c3f --- /dev/null +++ b/1.8/library/matrix/transpose_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/transpose' + +describe "Matrix#transpose" do + it_behaves_like(:matrix_transpose, :transpose) +end diff --git a/1.8/library/matrix/unit_spec.rb b/1.8/library/matrix/unit_spec.rb new file mode 100644 index 0000000000..cc2d0432e1 --- /dev/null +++ b/1.8/library/matrix/unit_spec.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/identity' + +describe "Matrix.unit" do + it_behaves_like(:matrix_identity, :unit) +end diff --git a/1.8/library/matrix/zero_spec.rb b/1.8/library/matrix/zero_spec.rb new file mode 100644 index 0000000000..a29381a533 --- /dev/null +++ b/1.8/library/matrix/zero_spec.rb @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'matrix' + +describe "Matrix.zero" do + it "returns an object of type Matrix" do + Matrix.zero(3).class.should == Matrix + end + + it "creates a n x n matrix" do + m3 = Matrix.zero(3) + m3.row_size.should == 3 + m3.column_size.should == 3 + + m8 = Matrix.zero(8) + m8.row_size.should == 8 + m8.column_size.should == 8 + end + + it "initializes all cells to 0" do + size = 10 + m = Matrix.zero(size) + + (0...size).each do |i| + (0...size).each do |j| + m[i, j].should == 0 + end + end + end + + it "returns an object of type Matrix" do + Matrix.zero(3).class.should == Matrix + end + + it "creates a square matrix with size given by the argument" do + m3 = Matrix.zero(3) + m3.row_size.should == 3 + m3.column_size.should == 3 + + m8 = Matrix.zero(8) + m8.row_size.should == 8 + m8.column_size.should == 8 + end + + it "initializes all cells to 0" do + size = 10 # arbitrary value + m = Matrix.zero(size) + + (0...size).each do |i| + (0...size).each do |j| + m[i, j].should == 0 + end + end + end +end diff --git a/1.8/library/observer/add_observer_spec.rb b/1.8/library/observer/add_observer_spec.rb new file mode 100644 index 0000000000..297ff68450 --- /dev/null +++ b/1.8/library/observer/add_observer_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Observer#add_observer" do + + before(:each) do + @observable = ObservableSpecs.new + @observer = ObserverCallbackSpecs.new + end + + it "adds the observer" do + @observer.value.should == nil + @observable.changed + @observable.notify_observers("test") + @observer.value.should == nil + + @observable.add_observer(@observer) + @observable.changed + @observable.notify_observers("test2") + @observer.value.should == "test2" + end + +end diff --git a/1.8/library/observer/count_observers_spec.rb b/1.8/library/observer/count_observers_spec.rb new file mode 100644 index 0000000000..3fa34b4088 --- /dev/null +++ b/1.8/library/observer/count_observers_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Observer#count_observers" do + before(:each) do + @observable = ObservableSpecs.new + @observer = ObserverCallbackSpecs.new + end + + it "counts the observers" do + @observable.count_observers.should == 0 + @observable.add_observer(@observer) + @observable.count_observers.should == 1 + @observable.add_observer(@observer) + @observable.count_observers.should == 2 + end + +end diff --git a/1.8/library/observer/delete_observer_spec.rb b/1.8/library/observer/delete_observer_spec.rb new file mode 100644 index 0000000000..aecc76979a --- /dev/null +++ b/1.8/library/observer/delete_observer_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Observer#delete_observer" do + before(:each) do + @observable = ObservableSpecs.new + @observer = ObserverCallbackSpecs.new + end + + it "deletes the observer" do + @observable.add_observer(@observer) + @observable.delete_observer(@observer) + + @observable.changed + @observable.notify_observers("test") + @observer.value.should == nil + end + +end diff --git a/1.8/library/observer/delete_observers_spec.rb b/1.8/library/observer/delete_observers_spec.rb new file mode 100644 index 0000000000..d2f2b31f4a --- /dev/null +++ b/1.8/library/observer/delete_observers_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Observer#delete_observers" do + before(:each) do + @observable = ObservableSpecs.new + @observer = ObserverCallbackSpecs.new + end + + it "deletes the observers" do + @observable.add_observer(@observer) + @observable.delete_observers + + @observable.changed + @observable.notify_observers("test") + @observer.value.should == nil + end + +end diff --git a/1.8/library/observer/fixtures/classes.rb b/1.8/library/observer/fixtures/classes.rb new file mode 100644 index 0000000000..8586e87e05 --- /dev/null +++ b/1.8/library/observer/fixtures/classes.rb @@ -0,0 +1,17 @@ +require 'observer' + +class ObserverCallbackSpecs + attr_reader :value + + def initialize + @value = nil + end + + def update(value) + @value = value + end +end + +class ObservableSpecs + include Observable +end \ No newline at end of file diff --git a/1.8/library/observer/notify_observers_spec.rb b/1.8/library/observer/notify_observers_spec.rb new file mode 100644 index 0000000000..babf89d04e --- /dev/null +++ b/1.8/library/observer/notify_observers_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Observer#notify_observers" do + + before(:each) do + @observable = ObservableSpecs.new + @observer = ObserverCallbackSpecs.new + @observable.add_observer(@observer) + end + + it "must call changed before notifying observers" do + @observer.value.should == nil + @observable.notify_observers("test") + @observer.value.should == nil + end + + it "verifies observer responds to update" do + lambda { + @observable.add_observer(@observable) + }.should raise_error(NoMethodError) + end + + it "receives the callback" do + @observer.value.should == nil + @observable.changed + @observable.notify_observers("test") + @observer.value.should == "test" + end + +end diff --git a/1.8/library/openssl/hmac/digest_spec.rb b/1.8/library/openssl/hmac/digest_spec.rb new file mode 100644 index 0000000000..fdb90ac081 --- /dev/null +++ b/1.8/library/openssl/hmac/digest_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../shared/constants' +require 'openssl' + +describe "OpenSSL::HMAC.digest" do + include HMACConstants + it 'returns an SHA1 digest' do + cur_digest = OpenSSL::Digest::Digest.new('SHA1') + cur_digest.digest.should == HMACConstants::BlankSHA1Digest + digest = OpenSSL::HMAC.digest(cur_digest, + HMACConstants::Key, + HMACConstants::Contents) + digest.should == HMACConstants::SHA1Digest + end +end + +# Should add in similar specs for MD5, RIPEMD160, and SHA256 diff --git a/1.8/library/openssl/hmac/hexdigest_spec.rb b/1.8/library/openssl/hmac/hexdigest_spec.rb new file mode 100644 index 0000000000..c5374ef33e --- /dev/null +++ b/1.8/library/openssl/hmac/hexdigest_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../shared/constants' +require 'openssl' + +describe "OpenSSL::HMAC.hexdigest" do + include HMACConstants + it 'returns an SHA1 hex digest' do + cur_digest = OpenSSL::Digest::Digest.new('SHA1') + cur_digest.hexdigest.should == HMACConstants::BlankSHA1HexDigest + hexdigest = OpenSSL::HMAC.hexdigest(cur_digest, + HMACConstants::Key, + HMACConstants::Contents) + hexdigest.should == HMACConstants::SHA1Hexdigest + end +end + +# Should add in similar specs for MD5, RIPEMD160, and SHA256 diff --git a/1.8/library/openssl/shared/constants.rb b/1.8/library/openssl/shared/constants.rb new file mode 100644 index 0000000000..c3a492f851 --- /dev/null +++ b/1.8/library/openssl/shared/constants.rb @@ -0,0 +1,10 @@ +module HMACConstants + + Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + Key = 'sekrit' + + BlankSHA1Digest = "\3329\243\356^kK\r2U\277\357\225`\030\220\257\330\a\t" + SHA1Digest = "\236\022\323\341\037\236\262n\344\t\372:\004J\242\330\257\270\363\264" + BlankSHA1HexDigest = "da39a3ee5e6b4b0d3255bfef95601890afd80709" + SHA1Hexdigest = "9e12d3e11f9eb26ee409fa3a044aa2d8afb8f3b4" +end diff --git a/1.8/library/openstruct/delete_field_spec.rb b/1.8/library/openstruct/delete_field_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/delete_field_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/equal_value_spec.rb b/1.8/library/openstruct/equal_value_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/equal_value_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/initialize_copy_spec.rb b/1.8/library/openstruct/initialize_copy_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/initialize_copy_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/inspect_spec.rb b/1.8/library/openstruct/inspect_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/inspect_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/marshal_dump_spec.rb b/1.8/library/openstruct/marshal_dump_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/marshal_dump_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/marshal_load_spec.rb b/1.8/library/openstruct/marshal_load_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/marshal_load_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/method_missing_spec.rb b/1.8/library/openstruct/method_missing_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/method_missing_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/new_ostruct_member_spec.rb b/1.8/library/openstruct/new_ostruct_member_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/new_ostruct_member_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/new_spec.rb b/1.8/library/openstruct/new_spec.rb new file mode 100644 index 0000000000..d8f1ca8f16 --- /dev/null +++ b/1.8/library/openstruct/new_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ostruct' + +describe "OpenStruct.new" do + it "returns a new OpenStruct Object without any attributes" do + OpenStruct.new.to_s.should == "#" + end +end + +describe "OpenStruct.new when given a hash" do + before :each do + @os = OpenStruct.new(:name => "John Smith", :age => 70, :pension => 300) + end + + it "has the given keys as attributes" do + @os.age.should == 70 + @os.pension.should == 300 + @os.name.should == "John Smith" + end + + it "responds to methods named after the hash keys" do + @os.respond_to?(:age).should == true + @os.respond_to?(:name).should == true + @os.respond_to?(:pension).should == true + + @os.respond_to?(:some_test).should == false + @os.respond_to?(:some_other_test).should == false + end + + it "creates attributes dynamically" do + @os.attr_1 = "foo" + @os.attr_2 = [1,2,3] + @os.attr_3 = { :foo => "bar" } + + @os.attr_1.should == "foo" + @os.attr_2.should == [1,2,3] + @os.attr_3.should == { :foo => "bar" } + end + + it "does not allow adding methods named the same as one of OpenStruct method" do + @os = OpenStruct.new(:marshal_dump => "overwritten") + @os.respond_to?(:marshal_dump=).should == false + end +end diff --git a/1.8/library/openstruct/table_spec.rb b/1.8/library/openstruct/table_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/table_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/openstruct/to_s_spec.rb b/1.8/library/openstruct/to_s_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/openstruct/to_s_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/pathname/absolute_spec.rb b/1.8/library/pathname/absolute_spec.rb new file mode 100644 index 0000000000..51ff29b2af --- /dev/null +++ b/1.8/library/pathname/absolute_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'pathname' + +describe "Pathname#absolute?" do + + it "should return true for the root directory" do + Pathname.new('/').absolute?.should == true + end + + it "should return true for a dir starting with a slash" do + Pathname.new('/usr/local/bin').absolute?.should == true + end + + it "should return false for a dir not starting with a slash" do + Pathname.new('fish').absolute?.should == false + end + + it "should return false for a dir not starting with a slash" do + Pathname.new('fish/dog/cow').absolute?.should == false + end + +end + diff --git a/1.8/library/pathname/equal_value_spec.rb b/1.8/library/pathname/equal_value_spec.rb new file mode 100644 index 0000000000..e48f122448 --- /dev/null +++ b/1.8/library/pathname/equal_value_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'pathname' + +describe "Pathname#==" do + + it "returns true when identical paths are used" do + (Pathname.new('') == Pathname.new('')).should == true + end + + it "returns true when identical paths are used" do + (Pathname.new('') == Pathname.new('/usr/local/bin')).should == false + end + +end + diff --git a/1.8/library/pathname/hash_spec.rb b/1.8/library/pathname/hash_spec.rb new file mode 100644 index 0000000000..68e76dfc81 --- /dev/null +++ b/1.8/library/pathname/hash_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'pathname' + +describe "Pathname#hash" do + + it "should equal the hash of the pathname" do + Pathname.new('/usr/local/bin/').hash.should == '/usr/local/bin/'.hash + end + + it "should not equal the hash of a different pathname" do + Pathname.new('/usr/local/bin/').hash.should_not == '/usr/bin/'.hash + end + +end + diff --git a/1.8/library/pathname/new_spec.rb b/1.8/library/pathname/new_spec.rb new file mode 100644 index 0000000000..1d917b7cb1 --- /dev/null +++ b/1.8/library/pathname/new_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'pathname' + +describe "Pathname.new" do + it "returns a new Pathname Object with 1 argument" do + Pathname.new('').class.should == Pathname + end + + it "raises an ArgumentError when called with \0" do + lambda { Pathname.new("\0")}.should raise_error(ArgumentError) + end + + it "is tainted if path is tainted" do + path = '/usr/local/bin'.taint + Pathname.new(path).tainted?.should == true + end + +end + diff --git a/1.8/library/pathname/parent_spec.rb b/1.8/library/pathname/parent_spec.rb new file mode 100644 index 0000000000..225d471404 --- /dev/null +++ b/1.8/library/pathname/parent_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'pathname' + +describe "Pathname#parent" do + + it "should have parent of root as root" do + Pathname.new('/').parent.to_s.should == '/' + end + + it "should have parent of /usr/ as root" do + Pathname.new('/usr/').parent.to_s.should == '/' + end + + it "should have parent of /usr/local as root" do + Pathname.new('/usr/local').parent.to_s.should == '/usr' + end + +end + diff --git a/1.8/library/pathname/relative_spec.rb b/1.8/library/pathname/relative_spec.rb new file mode 100644 index 0000000000..8ec066033c --- /dev/null +++ b/1.8/library/pathname/relative_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'pathname' + +describe "Pathname#relative?" do + + it "should return false for the root directory" do + Pathname.new('/').relative?.should == false + end + + it "should return false for a dir starting with a slash" do + Pathname.new('/usr/local/bin').relative?.should == false + end + + it "should return true for a dir not starting with a slash" do + Pathname.new('fish').relative?.should == true + end + + it "should return true for a dir not starting with a slash" do + Pathname.new('fish/dog/cow').relative?.should == true + end + +end + diff --git a/1.8/library/pathname/root_spec.rb b/1.8/library/pathname/root_spec.rb new file mode 100644 index 0000000000..12455ec165 --- /dev/null +++ b/1.8/library/pathname/root_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'pathname' + +describe "Pathname#root?" do + + it "should return true for root directories" do + Pathname.new('/').root?.should == true + end + + it "should return false for empty string" do + Pathname.new('').root?.should == false + end + + it "should return false for a top level directory" do + Pathname.new('/usr').root?.should == false + end + + it "should return false for a top level with .. appended directory" do + Pathname.new('/usr/..').root?.should == false + end + + it "should return false for a directory below top level" do + Pathname.new('/usr/local/bin/').root?.should == false + end + +end + diff --git a/1.8/library/pathname/sub_spec.rb b/1.8/library/pathname/sub_spec.rb new file mode 100644 index 0000000000..c741d81c00 --- /dev/null +++ b/1.8/library/pathname/sub_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'pathname' + +describe "Pathname#sub" do + + it "should replace the pattern with rest" do + Pathname.new('/usr/local/bin/').sub(/local/, 'fish').to_s.should == '/usr/fish/bin/' + end + + it "should return a new object" do + p = Pathname.new('/usr/local/bin/') + p.sub(/local/, 'fish').should_not == p + end + +end + diff --git a/1.8/library/rational/abs_spec.rb b/1.8/library/rational/abs_spec.rb new file mode 100644 index 0000000000..d01ebb5ab8 --- /dev/null +++ b/1.8/library/rational/abs_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#abs" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/coerce_spec.rb b/1.8/library/rational/coerce_spec.rb new file mode 100644 index 0000000000..12ffa2ff0b --- /dev/null +++ b/1.8/library/rational/coerce_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#coerce" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/comparison_spec.rb b/1.8/library/rational/comparison_spec.rb new file mode 100644 index 0000000000..d4d4ef02c3 --- /dev/null +++ b/1.8/library/rational/comparison_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#<=>" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/denominator_spec.rb b/1.8/library/rational/denominator_spec.rb new file mode 100644 index 0000000000..25778dd9d0 --- /dev/null +++ b/1.8/library/rational/denominator_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#denominator" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/divide_spec.rb b/1.8/library/rational/divide_spec.rb new file mode 100644 index 0000000000..0384fd7f08 --- /dev/null +++ b/1.8/library/rational/divide_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#/" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/divmod_spec.rb b/1.8/library/rational/divmod_spec.rb new file mode 100644 index 0000000000..aa7217b5b2 --- /dev/null +++ b/1.8/library/rational/divmod_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#divmod" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/equal_value_spec.rb b/1.8/library/rational/equal_value_spec.rb new file mode 100644 index 0000000000..64f20c6d9e --- /dev/null +++ b/1.8/library/rational/equal_value_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#==" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/exponent_spec.rb b/1.8/library/rational/exponent_spec.rb new file mode 100644 index 0000000000..c9fe4c0fa0 --- /dev/null +++ b/1.8/library/rational/exponent_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#**" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/hash_spec.rb b/1.8/library/rational/hash_spec.rb new file mode 100644 index 0000000000..79d92f7579 --- /dev/null +++ b/1.8/library/rational/hash_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#hash" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/initialize_spec.rb b/1.8/library/rational/initialize_spec.rb new file mode 100644 index 0000000000..5c154ece46 --- /dev/null +++ b/1.8/library/rational/initialize_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#initialize" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/inspect_spec.rb b/1.8/library/rational/inspect_spec.rb new file mode 100644 index 0000000000..7f98434a1c --- /dev/null +++ b/1.8/library/rational/inspect_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#inspect" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/minus_spec.rb b/1.8/library/rational/minus_spec.rb new file mode 100644 index 0000000000..54905ad411 --- /dev/null +++ b/1.8/library/rational/minus_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#-" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/modulo_spec.rb b/1.8/library/rational/modulo_spec.rb new file mode 100644 index 0000000000..68ef971424 --- /dev/null +++ b/1.8/library/rational/modulo_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#%" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/multiply_spec.rb b/1.8/library/rational/multiply_spec.rb new file mode 100644 index 0000000000..3091d36dd9 --- /dev/null +++ b/1.8/library/rational/multiply_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#*" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/new_spec.rb b/1.8/library/rational/new_spec.rb new file mode 100644 index 0000000000..185f455727 --- /dev/null +++ b/1.8/library/rational/new_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational.new!" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/numerator_spec.rb b/1.8/library/rational/numerator_spec.rb new file mode 100644 index 0000000000..e992eabe97 --- /dev/null +++ b/1.8/library/rational/numerator_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#numerator" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/plus_spec.rb b/1.8/library/rational/plus_spec.rb new file mode 100644 index 0000000000..e97ddbec6b --- /dev/null +++ b/1.8/library/rational/plus_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#+" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/reduce_spec.rb b/1.8/library/rational/reduce_spec.rb new file mode 100644 index 0000000000..73b4536b0a --- /dev/null +++ b/1.8/library/rational/reduce_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational.reduce" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/round_spec.rb b/1.8/library/rational/round_spec.rb new file mode 100644 index 0000000000..5729811197 --- /dev/null +++ b/1.8/library/rational/round_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +# Rounds num to the nearest integer +describe "Rational#round" do + it " round (down) " do + Rational( 0, 1).round.should == 0.0 + Rational( 101,100).round.should == 1 + Rational(-101,100).round.should == -1 + end + + it " round (up) " do + Rational( 191,100).round.should == 2 + Rational(-191,100).round.should == -2 + end + +end diff --git a/1.8/library/rational/to_f_spec.rb b/1.8/library/rational/to_f_spec.rb new file mode 100644 index 0000000000..c10d6c0a19 --- /dev/null +++ b/1.8/library/rational/to_f_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#to_f" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/to_i_spec.rb b/1.8/library/rational/to_i_spec.rb new file mode 100644 index 0000000000..0bd02b2755 --- /dev/null +++ b/1.8/library/rational/to_i_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#to_i" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/to_r_spec.rb b/1.8/library/rational/to_r_spec.rb new file mode 100644 index 0000000000..7f3b23f734 --- /dev/null +++ b/1.8/library/rational/to_r_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#to_r" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rational/to_s_spec.rb b/1.8/library/rational/to_s_spec.rb new file mode 100644 index 0000000000..91aac67544 --- /dev/null +++ b/1.8/library/rational/to_s_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'rational' + +describe "Rational#to_s" do + it "needs to be reviewed for spec completeness" do + end +end diff --git a/1.8/library/rexml/document/add_element_spec.rb b/1.8/library/rexml/document/add_element_spec.rb new file mode 100644 index 0000000000..3c2f92d7f6 --- /dev/null +++ b/1.8/library/rexml/document/add_element_spec.rb @@ -0,0 +1,31 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#add_element" do + it "adds arg1 with attributes arg2 as root node" do + d = REXML::Document.new + e = REXML::Element.new("root") + d.add_element e + d.root.should == e + end + + it "sets arg2 as arg1's attributes" do + d = REXML::Document.new + e = REXML::Element.new("root") + attr = {"foo" => "bar"} + d.add_element(e,attr) + d.root.attributes["foo"].should == attr["foo"] + end + + it "accepts a node name as arg1 and adds it as root" do + d = REXML::Document.new + d.add_element "foo" + d.root.name.should == "foo" + end + + it "sets arg1's context to the root's context" do + d = REXML::Document.new("", {"foo" => "bar"}) + d.add_element "foo" + d.root.context.should == d.context + end +end diff --git a/1.8/library/rexml/document/add_spec.rb b/1.8/library/rexml/document/add_spec.rb new file mode 100644 index 0000000000..1e80dffbcc --- /dev/null +++ b/1.8/library/rexml/document/add_spec.rb @@ -0,0 +1,64 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +# This spec defines Document#add and Document#<< + +shared :document_add do |cmd| + describe "REXML::Document##{cmd}" do + before :each do + @doc = REXML::Document.new("") + @decl = REXML::XMLDecl.new("1.0") + end + + it "sets document's XML declaration" do + @doc.add(@decl) + @doc.xml_decl.should == @decl + end + + it "inserts XML declaration as first node" do + @doc.add(@decl) + @doc.children[0].version.should == "1.0" + end + + it "overwrites existing XML declaration" do + @doc.add(@decl) + @doc.add(REXML::XMLDecl.new("2.0")) + @doc.xml_decl.version.should == "2.0" + end + + it "sets document DocType" do + @doc.add(REXML::DocType.new("transitional")) + @doc.doctype.name.should == "transitional" + end + + # Bug #19058 in Ruby's tracker has a patch to fix this. + ruby_bug do + # MRI 1.8.x and 1.9 bug. A patch has been submitted. + # http://rubyforge.org/tracker/index.php?func=detail&aid=19058&group_id=426&atid=1698 + it "overwrites existing DocType" do + @doc.add REXML::DocType.new("transitional") + @doc.add REXML::DocType.new("strict") + @doc.doctype.name.should == "strict" + end + end + + it "adds root node unless it exists" do + d = REXML::Document.new("") + elem = REXML::Element.new "root" + d.add elem + d.root.should == elem + end + + it "refuses to add second root" do + lambda {@doc.add REXML::Element.new("foo")}.should raise_error(RuntimeError) + end + end +end + +describe "REXML::Document#add" do + it_behaves_like(:document_add, :add) +end + +describe "REXML::Document#<<" do + it_behaves_like(:document_add, :<<) +end diff --git a/1.8/library/rexml/document/clone_spec.rb b/1.8/library/rexml/document/clone_spec.rb new file mode 100644 index 0000000000..816808fc52 --- /dev/null +++ b/1.8/library/rexml/document/clone_spec.rb @@ -0,0 +1,20 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +# According to the MRI documentation (http://www.ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html), +# clone's behavior "should be obvious". Apparently "obvious" means cloning +# only the attributes and the context of the document, not its children. +describe "REXML::Document#clone" do + it "clones document attributes" do + d = REXML::Document.new("foo") + d.attributes["foo"] = "bar" + e = d.clone + e.attributes.should == d.attributes + end + + it "clones document context" do + d = REXML::Document.new("foo", {"foo" => "bar"}) + e = d.clone + e.context.should == d.context + end +end diff --git a/1.8/library/rexml/document/doctype_spec.rb b/1.8/library/rexml/document/doctype_spec.rb new file mode 100644 index 0000000000..a97e95e7a9 --- /dev/null +++ b/1.8/library/rexml/document/doctype_spec.rb @@ -0,0 +1,15 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#doctype" do + it "returns the doctype" do + d = REXML::Document.new + dt = REXML::DocType.new("foo") + d.add dt + d.doctype.should == dt + end + + it "returns nil if there's no doctype" do + REXML::Document.new.doctype.should == nil + end +end diff --git a/1.8/library/rexml/document/encoding_spec.rb b/1.8/library/rexml/document/encoding_spec.rb new file mode 100644 index 0000000000..5155245f95 --- /dev/null +++ b/1.8/library/rexml/document/encoding_spec.rb @@ -0,0 +1,22 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#encoding" do + before :each do + @doc = REXML::Document.new + end + + it "returns encoding from XML declaration" do + @doc.add REXML::XMLDecl.new(nil, "UTF-16", nil) + @doc.encoding.should == "UTF-16" + end + + it "returns encoding from XML declaration (for UTF-16 as well)" do + @doc.add REXML::XMLDecl.new("1.0", "UTF-8", nil) + @doc.encoding.should == "UTF-8" + end + + it "uses UTF-8 as default encoding" do + @doc.encoding.should == "UTF-8" + end +end diff --git a/1.8/library/rexml/document/expanded_name_spec.rb b/1.8/library/rexml/document/expanded_name_spec.rb new file mode 100644 index 0000000000..50074efffd --- /dev/null +++ b/1.8/library/rexml/document/expanded_name_spec.rb @@ -0,0 +1,18 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +shared :document_expanded_name do |cmd| + describe "REXML::Document##{cmd}" do + it "returns an empty string for root" do # root nodes have no expanded name + REXML::Document.new.expanded_name.should == "" + end + end +end + +describe "REXML::Document#expanded_name" do + it_behaves_like(:document_expanded_name, :expanded_name) +end + +describe "REXML::Document#name" do + it_behaves_like(:document_expanded_name, :name) +end diff --git a/1.8/library/rexml/document/new_spec.rb b/1.8/library/rexml/document/new_spec.rb new file mode 100644 index 0000000000..87d4c17841 --- /dev/null +++ b/1.8/library/rexml/document/new_spec.rb @@ -0,0 +1,38 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#new" do + + it "initializes context of {} unless specified" do + d = REXML::Document.new("") + d.context.should == {} + end + + it "has empty attributes if source is nil" do + d = REXML::Document.new(nil) + d.elements.should be_empty + end + + it "can use other document context" do + s = REXML::Document.new("") + d = REXML::Document.new(s) + d.context.should == s.context + end + + it "clones source attributes" do + s = REXML::Document.new("") + s.attributes["some_attr"] = "some_val" + d = REXML::Document.new(s) + d.attributes.should == s.attributes + end + + it "raises an error if source is not a Document, String or IO" do + lambda {s = REXML::Document.new(3)}.should raise_error(RuntimeError) + end + + it "does not perform XML validation" do + lambda {s = REXML::Document.new("Invalid document")} + end +end + + diff --git a/1.8/library/rexml/document/node_type_spec.rb b/1.8/library/rexml/document/node_type_spec.rb new file mode 100644 index 0000000000..9ee8bd8110 --- /dev/null +++ b/1.8/library/rexml/document/node_type_spec.rb @@ -0,0 +1,8 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#node_type" do + it "returns :document" do + REXML::Document.new.node_type.should == :document + end +end diff --git a/1.8/library/rexml/document/root_spec.rb b/1.8/library/rexml/document/root_spec.rb new file mode 100644 index 0000000000..3c57aacaba --- /dev/null +++ b/1.8/library/rexml/document/root_spec.rb @@ -0,0 +1,12 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#root" do + it "returns document root tag name" do + REXML::Document.new("").root.name.should == "foo" + end + + it "returns nil if there is not root" do + REXML::Document.new.root.should == nil + end +end diff --git a/1.8/library/rexml/document/stand_alone_spec.rb b/1.8/library/rexml/document/stand_alone_spec.rb new file mode 100644 index 0000000000..00e16ddbd5 --- /dev/null +++ b/1.8/library/rexml/document/stand_alone_spec.rb @@ -0,0 +1,19 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#stand_alone?" do + it "returns the XMLDecl standalone value" do + d = REXML::Document.new + decl = REXML::XMLDecl.new("1.0", "UTF-8", "yes") + d.add decl + d.stand_alone?.should == "yes" + end + + # According to the docs this should return the default XMLDecl but that + # will carry some more problems when printing the document. Currently, it + # returns nil. See http://www.ruby-forum.com/topic/146812#650061 + it "returns the default value when no XML declaration present" do + REXML::Document.new.stand_alone?.should == nil + end + +end diff --git a/1.8/library/rexml/document/version_spec.rb b/1.8/library/rexml/document/version_spec.rb new file mode 100644 index 0000000000..de8e75368f --- /dev/null +++ b/1.8/library/rexml/document/version_spec.rb @@ -0,0 +1,14 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#version" do + it "returns XML version from declaration" do + d = REXML::Document.new + d.add REXML::XMLDecl.new("1.1") + d.version.should == "1.1" + end + + it "returns the default version when declaration is not present" do + REXML::Document.new.version.should == REXML::XMLDecl::DEFAULT_VERSION + end +end diff --git a/1.8/library/rexml/document/write_spec.rb b/1.8/library/rexml/document/write_spec.rb new file mode 100644 index 0000000000..22f8fc60c5 --- /dev/null +++ b/1.8/library/rexml/document/write_spec.rb @@ -0,0 +1,42 @@ +require 'rexml/document' +require 'rexml/formatters/transitive' +require File.dirname(__FILE__) + '/../../../spec_helper' + +# Maybe this can be cleaned +describe "REXML::Document#write" do + before :each do + @d = REXML::Document.new + city = REXML::Element.new "Springfield" + street = REXML::Element.new "EvergreenTerrace" + address = REXML::Element.new "House742" + @d << city << street << address + @str = "" + end + + it "returns document source as string" do + @d.write(@str) + @str.should == "" + end + + it "returns document indented" do + @d.write(@str, 2) + @str.should =~ /\s*\s*\s*\s*<\/EvergreenTerrace>\s*<\/Springfield>/ + end + + # REXML in p114 is screwed up: + # Document#write uses wrong arity for Formatters::Transitive#initialize + # + # In branch_1_8 in rev 15833 REXML is organized completely differently. + # So we are waiting for further changes to REXML in 1.8.x branch. + ruby_bug do + it "returns document with transitive support" do + @d.write(@str, 2, true) + @str.should =~ "\s*<\/EvergreenTerrace\s*><\/Springfield\s*>" + end + end + + it "returns document with support for IE" do + @d.write(@str, -1, false, true) + @str.should == "" + end +end diff --git a/1.8/library/rexml/document/xml_decl_spec.rb b/1.8/library/rexml/document/xml_decl_spec.rb new file mode 100644 index 0000000000..39c1f0345c --- /dev/null +++ b/1.8/library/rexml/document/xml_decl_spec.rb @@ -0,0 +1,15 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Document#xml_decl" do + it "returns XML declaration of the document" do + d = REXML::Document.new + decl = REXML::XMLDecl.new("1.0", "UTF-16", "yes") + d.add decl + d.xml_decl.should == decl + end + + it "returns default XML declaration unless present" do + REXML::Document.new.xml_decl.should == REXML::XMLDecl.new + end +end diff --git a/1.8/library/rexml/element/add_attribute_spec.rb b/1.8/library/rexml/element/add_attribute_spec.rb new file mode 100644 index 0000000000..d53a7f27ad --- /dev/null +++ b/1.8/library/rexml/element/add_attribute_spec.rb @@ -0,0 +1,36 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#add_attribute" do + before :each do + @person = REXML::Element.new "person" + @person.attributes["name"] = "Bill" + end + + it "adds a new attribute" do + @person.add_attribute("age", "17") + @person.attributes["age"].should == "17" + end + + it "overwrites an existing attribute" do + @person.add_attribute("name", "Bill") + @person.attributes["name"].should == "Bill" + end + + it "accepts a pair of strings" do + @person.add_attribute("male", "true") + @person.attributes["male"].should == "true" + end + + it "accepts an Attribute for key" do + attr = REXML::Attribute.new("male", "true") + @person.add_attribute attr + @person.attributes["male"].should == "true" + end + + it "ignores value if key is an Attribute" do + attr = REXML::Attribute.new("male", "true") + @person.add_attribute(attr, "false") + @person.attributes["male"].should == "true" + end +end diff --git a/1.8/library/rexml/element/add_attributes_spec.rb b/1.8/library/rexml/element/add_attributes_spec.rb new file mode 100644 index 0000000000..803f4d7e9f --- /dev/null +++ b/1.8/library/rexml/element/add_attributes_spec.rb @@ -0,0 +1,23 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#add_attribute" do + before :each do + @person = REXML::Element.new "person" + @person.attributes["name"] = "Bill" + end + + it "adds multiple attributes to element" do + @person.add_attributes({"name" => "Joe", "age" => "27"}) + @person.attributes["name"].should == "Joe" + @person.attributes["age"].should == "27" + end + + it "accepts an array of arguments" do + attrs = { "name" => "Joe", "age" => "27"} + @person.add_attributes attrs.to_a + @person.attributes["name"].should == "Joe" + @person.attributes["age"].should == "27" + end + +end diff --git a/1.8/library/rexml/element/add_element_spec.rb b/1.8/library/rexml/element/add_element_spec.rb new file mode 100644 index 0000000000..0bd35370b0 --- /dev/null +++ b/1.8/library/rexml/element/add_element_spec.rb @@ -0,0 +1,39 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + + +describe "REXML::Element#add_element" do + before :each do + @root = REXML::Element.new("root") + end + + it "adds a child without attributes" do + name = REXML::Element.new("name") + @root.add_element name + @root.elements["name"].name.should == name.name + @root.elements["name"].attributes.should == name.attributes + @root.elements["name"].context == name.context + end + + it "adds a child with attributes" do + person = REXML::Element.new("person") + @root.add_element(person, {"name" => "Madonna"}) + @root.elements["person"].name.should == person.name + @root.elements["person"].attributes.should == person.attributes + @root.elements["person"].context == person.context + end + + it "adds a child with name" do + @root.add_element "name" + @root.elements["name"].name.should == "name" + @root.elements["name"].attributes.should == {} + @root.elements["name"].context == {} + end + + it "returns the added child" do + name = @root.add_element "name" + @root.elements["name"].name.should == name.name + @root.elements["name"].attributes.should == name.attributes + @root.elements["name"].context == name.context + end +end diff --git a/1.8/library/rexml/element/add_namespace_spec.rb b/1.8/library/rexml/element/add_namespace_spec.rb new file mode 100644 index 0000000000..3d8cf6bb86 --- /dev/null +++ b/1.8/library/rexml/element/add_namespace_spec.rb @@ -0,0 +1,24 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#add_namespace" do + before :each do + @elem = REXML::Element.new("person") + end + + it "adds a namespace to element" do + @elem.add_namespace("foo", "bar") + @elem.namespace("foo").should == "bar" + end + + it "accepts a prefix string as prefix" do + @elem.add_namespace("xmlns:foo", "bar") + @elem.namespace("foo").should == "bar" + end + + it "uses prefix as URI if uri is nil" do + @elem.add_namespace("some_uri", nil) + @elem.namespace.should == "some_uri" + end +end + diff --git a/1.8/library/rexml/element/add_text_spec.rb b/1.8/library/rexml/element/add_text_spec.rb new file mode 100644 index 0000000000..f3d55ff7ad --- /dev/null +++ b/1.8/library/rexml/element/add_text_spec.rb @@ -0,0 +1,24 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#add_namespace" do + before :each do + @name = REXML::Element.new "Name" + end + + it "adds text to an element" do + @name.add_text "Ringo" + @name.to_s.should == "Ringo" + end + + it "accepts a Text" do + @name.add_text(REXML::Text.new("Ringo")) + @name.to_s.should == "Ringo" + end + + it "joins the new text with the old one" do + @name.add_text "Ringo" + @name.add_text " Starr" + @name.to_s.should == "Ringo Starr" + end +end diff --git a/1.8/library/rexml/element/attributes_spec.rb b/1.8/library/rexml/element/attributes_spec.rb new file mode 100644 index 0000000000..9375d2c872 --- /dev/null +++ b/1.8/library/rexml/element/attributes_spec.rb @@ -0,0 +1,128 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +# Covers Element#add_attribute, Element#add_attributes, Element#attribute, +# Element#delete_attribute, Element#has_attributes? + +describe "REXML::Element#add_attribute" do + it "adds an attribute" do + p = REXML::Element.new "Person" + tony = REXML::Attribute.new("name", "Tony") + p.add_attribute tony + p.attributes["name"].should == "Tony" + end + + it "adds an attribute from a string" do + p = REXML::Element.new "Person" + p.add_attribute("name", "Tony") + p.attributes["name"].should == "Tony" + end + + it "replaces existing attribute with the same name" do + p = REXML::Element.new "Godfather" + p.add_attribute("name", "Vito") + p.add_attribute("name", "Anthony") + p.attributes["name"].should == "Anthony" + end + + it "returns the attribute added" do + p = REXML::Element.new "Person" + tony = REXML::Attribute.new("name", "Tony") + attr = p.add_attribute tony + attr.should == tony + end +end + +describe "REXML::Element#add_attributes" do + it "adds attributes from hash" do + p = REXML::Element.new "Person" + attrs = {"name" => "Chris", "age" => "30", "weight" => "170"} + p.add_attributes attrs + p.attributes["name"].should == "Chris" + p.attributes["age"].should == "30" + p.attributes["weight"].should == "170" + end + + it "adds attributes from array" do + p = REXML::Element.new "Person" + attrs = [["name", "Chris"], ["weight", "170"], ["age", "30"]] + p.add_attributes attrs + p.attributes["name"].should == "Chris" + p.attributes["age"].should == "30" + p.attributes["weight"].should == "170" + end +end + + # TODO: Add a case with a namespace +describe "REXML::Element#attribute" do + it "returns attribute by name" do + p = REXML::Element.new "Person" + a = REXML::Attribute.new ("drink", "coffee") + p.add_attribute a + p.attribute("drink").should == a + end +end + +describe "REXML::Element#delete_attribute" do + it "deletes attribute by name" do + p = REXML::Element.new "Person" + p.add_attribute("food", "pizza") + p.delete_attribute("food") + p.attribute("food").should == nil + end + + # Unlike the docs say in http://www.ruby-doc.org/stdlib/libdoc/rexml/rdoc/classes/REXML/Element.html#M002966 + # this returns the element _without_ the deleted attribute, not the deleted + # attribute by itself. This can be seen on the docs' examples. A patch was sent in: + # http://rubyforge.org/tracker/index.php?func=detail&aid=19038&group_id=426&atid=1698 + it "returns modified element" do + p = REXML::Element.new "Person" + p.add_attribute("food", "pizza") + del_attr = p.delete_attribute("food") + del_attr.should == p + end + + + ruby_bug do + # According to the docs, it can also receive an Attribute as key and delete + # it, but this doesn't seem to be the case. A patch was sent in: + # http://rubyforge.org/tracker/index.php?func=detail&aid=19039&group_id=426&atid=1698 + it "deletes the attribute 'key'" do + p = REXML::Element.new "Person" + a = REXML::Attribute.new("name", "John") + p.add_attribute a + p.delete_attribute a + p.attribute("name").should == nil + end + end +end + +describe "REXML::Element#has_attributes" do + it "returns true if element has attributes set" do + p = REXML::Element.new "Person" + a = REXML::Attribute.new("name", "John") + p.add_attribute a + p.has_attributes?.should == true + end + + it "returns false if element has no attributes set" do + p = REXML::Element.new "Person" + a = REXML::Attribute.new("name", "John") + p.has_attributes?.should == false + end +end + +describe "REXML::Element.attributes" do + it "returns the Element's Attributes" do + p = REXML::Element.new "Person" + a = REXML::Attribute.new("name", "John") + attrs = REXML::Attributes.new(p) + attrs.add a + p.add_attribute a + p.attributes.should == attrs + end + + it "returns an empty hash if element has no attributes" do + REXML::Element.new("Person").attributes.should == {} + end +end diff --git a/1.8/library/rexml/element/clone_spec.rb b/1.8/library/rexml/element/clone_spec.rb new file mode 100644 index 0000000000..efacbda78d --- /dev/null +++ b/1.8/library/rexml/element/clone_spec.rb @@ -0,0 +1,29 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#clone" do + before :each do + @e = REXML::Element.new "a" + end + it "creates a copy of element" do + @e.clone.to_s.should == @e.to_s + end + + it "copies the attributes" do + @e.add_attribute("foo", "bar") + @e.clone.to_s.should == @e.to_s + end + + it "does not copy the text" do + @e.add_text "some text..." + @e.clone.to_s.should_not == @e + @e.clone.to_s.should == "" + end + + it "does not copy the child elements" do + b = REXML::Element.new "b" + @e << b + @e.clone.should_not == @e + @e.clone.to_s.should == "" + end +end diff --git a/1.8/library/rexml/element/comments_spec.rb b/1.8/library/rexml/element/comments_spec.rb new file mode 100644 index 0000000000..085a668c32 --- /dev/null +++ b/1.8/library/rexml/element/comments_spec.rb @@ -0,0 +1,21 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#comments" do + before :each do + @e = REXML::Element.new "root" + @c1 = REXML::Comment.new "this is a comment" + @c2 = REXML::Comment.new "this is another comment" + @e << @c1 + @e << @c2 + end + + it "returns the array of comments" do + @e.comments.should == [@c1, @c2] + end + + it "returns a frozen object" do + comment = REXML::Comment.new "The insertion should fail" + @e.comments.frozen?.should == true + end +end diff --git a/1.8/library/rexml/element/delete_element_spec.rb b/1.8/library/rexml/element/delete_element_spec.rb new file mode 100644 index 0000000000..1795b52d3c --- /dev/null +++ b/1.8/library/rexml/element/delete_element_spec.rb @@ -0,0 +1,51 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#delete_element" do + before :each do + @root = REXML::Element.new("root") + end + + it "deletes the child element" do + node = REXML::Element.new("some_node") + @root.add_element node + @root.delete_element node + @root.elements.size.should == 0 + end + + it "deletes a child via XPath" do + @root.add_element "some_node" + @root.delete_element "some_node" + @root.elements.size.should == 0 + end + + it "deletes the child at index" do + @root.add_element "some_node" + @root.delete_element 1 + @root.elements.size.should == 0 + end + + # According to the docs this should return the deleted element + # but it won't if it's an Element. + ruby_bug do + it "deletes Element and returns it" do + node = REXML::Element.new("some_node") + @root.add_element node + del_node = @root.delete_element node + del_node.should == node + end + end + + # Note how passing the string will return the removed element + # but passing the Element as above won't. + it "deletes an element and returns it" do + node = REXML::Element.new("some_node") + @root.add_element node + del_node = @root.delete_element "some_node" + del_node.should == node + end + + it "returns nil unless element exists" do + @root.delete_element("something").should == nil + end +end diff --git a/1.8/library/rexml/element/each_element_with_attribute_spec.rb b/1.8/library/rexml/element/each_element_with_attribute_spec.rb new file mode 100644 index 0000000000..472eeee6e9 --- /dev/null +++ b/1.8/library/rexml/element/each_element_with_attribute_spec.rb @@ -0,0 +1,35 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#each_element_with_attributes" do + before :each do + @document = REXML::Element.new("people") + @father = REXML::Element.new("Person") + @father.attributes["name"] = "Joe" + @son = REXML::Element.new("Child") + @son.attributes["name"] = "Fred" + @document.root << @father + @document.root << @son + @childs = [] + end + + it "returns childs with attribute" do + @document.each_element_with_attribute("name") { |elem| @childs << elem } + @childs[0].should == @father + @childs[1].should == @son + end + + it "takes attribute value as second argument" do + @document.each_element_with_attribute("name", "Fred"){ |elem| elem.should == @son } + end + + it "takes max number of childs as third argument" do + @document.each_element_with_attribute("name", nil, 1) { |elem| @childs << elem } + @childs.size.should == 1 + @childs[0].should == @father + end + + it "takes XPath filter as fourth argument" do + @document.each_element_with_attribute("name", nil, 0, "Child"){ |elem| elem.should == @son} + end +end diff --git a/1.8/library/rexml/element/each_element_with_text_spec.rb b/1.8/library/rexml/element/each_element_with_text_spec.rb new file mode 100644 index 0000000000..34c16970c7 --- /dev/null +++ b/1.8/library/rexml/element/each_element_with_text_spec.rb @@ -0,0 +1,31 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#each_element_with_text" do + before :each do + @document = REXML::Element.new("people") + + @joe = REXML::Element.new("Person") + @joe.text = "Joe" + @fred = REXML::Element.new("Person") + @fred.text = "Fred" + @another = REXML::Element.new("AnotherPerson") + @another.text = "Fred" + @document.root << @joe + @document.root << @fred + @document.root << @another + @childs = [] + end + + it "returns childs with text" do + @document.each_element_with_text("Joe"){|c| c.should == @joe} + end + + it "takes max as second argument" do + @document.each_element_with_text("Fred", 1){ |c| c.should == @fred} + end + + it "takes XPath filter as third argument" do + @document.each_element_with_text("Fred", 0, "Person"){ |c| c.should == @fred} + end +end diff --git a/1.8/library/rexml/element/get_text_spec.rb b/1.8/library/rexml/element/get_text_spec.rb new file mode 100644 index 0000000000..28c4d4f575 --- /dev/null +++ b/1.8/library/rexml/element/get_text_spec.rb @@ -0,0 +1,18 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#get_text" do + before :each do + @doc = REXML::Document.new "

    some textthis is bold! more text

    " + end + + it "returns the first text child node" do + @doc.root.get_text.value.should == "some text" + @doc.root.get_text.should be_kind_of(REXML::Text) + end + + it "returns text from an element matching path" do + @doc.root.get_text("b").value.should == "this is bold!" + @doc.root.get_text("b").should be_kind_of(REXML::Text) + end +end diff --git a/1.8/library/rexml/element/inspect_spec.rb b/1.8/library/rexml/element/inspect_spec.rb new file mode 100644 index 0000000000..4252db067f --- /dev/null +++ b/1.8/library/rexml/element/inspect_spec.rb @@ -0,0 +1,27 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#inspect" do + + before :each do + @name = REXML::Element.new "name" + end + + it "returns the node as a string" do + @name.inspect.should == "" + end + + it "inserts '...' if the node has children" do + e = REXML::Element.new "last_name" + @name << e + @name.inspect.should == " ... " + # This might make more sense but differs from MRI's default behavior + # @name.inspect.should == " ... " + end + + it "inserts the attributes in the string" do + @name.add_attribute "language" + @name.attributes["language"] = "english" + @name.inspect.should == "" + end +end diff --git a/1.8/library/rexml/element/namespace_spec.rb b/1.8/library/rexml/element/namespace_spec.rb new file mode 100644 index 0000000000..4126ab203b --- /dev/null +++ b/1.8/library/rexml/element/namespace_spec.rb @@ -0,0 +1,22 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#namespace" do + before :each do + @doc = REXML::Document.new("
    ") + @elem = @doc.elements["//b"] + end + + it "returns the default namespace" do + @elem.namespace.should == "1" + end + + it "accepts a namespace prefix" do + @elem.namespace("y").should == "2" + @doc.elements["//c"].namespace("z").should == "3" + end + + it "returns nil if namespace is not defined" do + @elem.namespace("z").should == nil + end +end diff --git a/1.8/library/rexml/element/namespaces_spec.rb b/1.8/library/rexml/element/namespaces_spec.rb new file mode 100644 index 0000000000..f776887530 --- /dev/null +++ b/1.8/library/rexml/element/namespaces_spec.rb @@ -0,0 +1,32 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#namespaces" do + before :each do + doc = REXML::Document.new("") + @elem = doc.elements["//c"] + end + + it "returns a hash of the namespaces" do + ns = {"y"=>"2", "z"=>"3", "xmlns"=>"1"} + @elem.namespaces.keys.sort.should == ns.keys.sort + @elem.namespaces.values.sort.should == ns.values.sort + end + + it "returns an empty hash if no namespaces exist" do + e = REXML::Element.new "element" + e.namespaces.kind_of?(Hash).should == true + e.namespaces.should be_empty + end + + it "uses namespace prefixes as keys" do + prefixes = ["y", "z", "xmlns"] + @elem.namespaces.keys.sort.should == prefixes.sort + end + + it "uses namespace values as the hash values" do + values = ["2", "3", "1"] + @elem.namespaces.values.sort.should == values.sort + end + +end diff --git a/1.8/library/rexml/element/new_spec.rb b/1.8/library/rexml/element/new_spec.rb new file mode 100644 index 0000000000..4c6e9f4867 --- /dev/null +++ b/1.8/library/rexml/element/new_spec.rb @@ -0,0 +1,35 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#new" do + + it "creates element from tag name" do + REXML::Element.new("foo").name.should == "foo" + end + + it "creates element with default attributes" do + e = REXML::Element.new + e.name.should == REXML::Element::UNDEFINED + e.context.should == nil + e.parent.should == nil + end + + it "creates element from another element" do + e = REXML::Element.new "foo" + f = REXML::Element.new e + e.name.should == f.name + e.context.should == f.context + e.parent.should == f.parent + end + + it "takes parent as second argument" do + parent = REXML::Element.new "foo" + child = REXML::Element.new "bar", parent + child.parent.should == parent + end + + it "takes context as third argument" do + context = {"some_key" => "some_value"} + REXML::Element.new("foo", nil, context).context.should == context + end +end diff --git a/1.8/library/rexml/element/next_element_spec.rb b/1.8/library/rexml/element/next_element_spec.rb new file mode 100644 index 0000000000..fc76cad4c1 --- /dev/null +++ b/1.8/library/rexml/element/next_element_spec.rb @@ -0,0 +1,19 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#next_element" do + before :each do + @a = REXML::Element.new "a" + @b = REXML::Element.new "b" + @c = REXML::Element.new "c" + @a.root << @b + @a.root << @c + end + it "returns next existing element" do + @a.elements["b"].next_element.should == @c + end + + it "returns nil on last element" do + @a.elements["c"].next_element.should == nil + end +end diff --git a/1.8/library/rexml/element/node_type_spec.rb b/1.8/library/rexml/element/node_type_spec.rb new file mode 100644 index 0000000000..f5ac341a00 --- /dev/null +++ b/1.8/library/rexml/element/node_type_spec.rb @@ -0,0 +1,8 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#node_type" do + it "returns :element" do + REXML::Element.new("MyElem").node_type.should == :element + end +end diff --git a/1.8/library/rexml/element/prefixes_spec.rb b/1.8/library/rexml/element/prefixes_spec.rb new file mode 100644 index 0000000000..7033a96735 --- /dev/null +++ b/1.8/library/rexml/element/prefixes_spec.rb @@ -0,0 +1,23 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#prefixes" do + before :each do + doc = REXML::Document.new("") + @elem = doc.elements["//c"] + end + + it "returns an array of the prefixes of the namespaces" do + @elem.prefixes.should == ["y", "z"] + end + + it "does not include the default namespace" do + @elem.prefixes.include?("xmlns").should == false + end + + it "returns an empty array if no namespace was defined" do + doc = REXML::Document.new "" + root = doc.elements["//root"] + root.prefixes.should == [] + end +end diff --git a/1.8/library/rexml/element/previous_element_spec.rb b/1.8/library/rexml/element/previous_element_spec.rb new file mode 100644 index 0000000000..a3aa179ec4 --- /dev/null +++ b/1.8/library/rexml/element/previous_element_spec.rb @@ -0,0 +1,20 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#previous_element" do + before :each do + @a = REXML::Element.new "a" + @b = REXML::Element.new "b" + @c = REXML::Element.new "c" + @a.root << @b + @a.root << @c + end + + it "returns previous element" do + @a.elements["c"].previous_element.should == @b + end + + it "returns nil on first element" do + @a.elements["b"].previous_element.should == nil + end +end diff --git a/1.8/library/rexml/element/raw_spec.rb b/1.8/library/rexml/element/raw_spec.rb new file mode 100644 index 0000000000..1736d80d9a --- /dev/null +++ b/1.8/library/rexml/element/raw_spec.rb @@ -0,0 +1,24 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#raw" do + it "returns true if raw mode is set to all" do + REXML::Element.new("MyElem", nil, {:raw => :all}).raw.should == true + end + + it "returns true if raw mode is set to expanded_name" do + REXML::Element.new("MyElem", nil, {:raw => "MyElem"}).raw.should == true + end + + it "returns false if raw mode is not set" do + REXML::Element.new("MyElem", nil, {:raw => ""}).raw.should == false + end + + it "returns false if raw is not :all or expanded_name" do + REXML::Element.new("MyElem", nil, {:raw => "Something"}).raw.should == false + end + + it "returns nil if context is not set" do + REXML::Element.new("MyElem").raw.should == nil + end +end diff --git a/1.8/library/rexml/element/root_spec.rb b/1.8/library/rexml/element/root_spec.rb new file mode 100644 index 0000000000..dc90d65a29 --- /dev/null +++ b/1.8/library/rexml/element/root_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'rexml/document' + +describe "REXML::Element#root" do + before :each do + @doc = REXML::Document.new + @root = REXML::Element.new "root" + @node = REXML::Element.new "node" + @doc << @root << @node + end + + it "returns first child on documents" do + @doc.root.should == @root + end + + it "returns self on root nodes" do + @root.root.should == @root + end + + it "returns parent's root on child nodes" do + @node.root.should == @root + end + + it "returns self on standalone nodes" do + e = REXML::Element.new "Elem" # Not that doesn't have a parent node + e.root.should == e + end +end diff --git a/1.8/library/rexml/element/text_spec.rb b/1.8/library/rexml/element/text_spec.rb new file mode 100644 index 0000000000..a1eaac568e --- /dev/null +++ b/1.8/library/rexml/element/text_spec.rb @@ -0,0 +1,46 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "REXML::Element#test" do + before :each do + @e = REXML::Element.new "name" + @e.text = "John" + end + + it "returns the text node of element" do + @e.text.should == "John" + end + + it "returns the text node value" do + t = REXML::Text.new "Joe" + @e.text = t + @e.text.should == "Joe" + @e.text.should_not == t + end + + it "returns nil if no text is attached" do + elem = REXML::Element.new "name" + elem.text.should == nil + end +end + +describe "REXML::Element#text=" do + before :each do + @e = REXML::Element.new "name" + @e.text = "John" + end + + it "sets the text node" do + @e.to_s.should == "John" + end + + it "replaces existing text" do + @e.text = "Joe" + @e.to_s.should == "Joe" + end + + it "receives nil as an argument" do + @e.text = nil + @e.to_s.should == "" + end +end diff --git a/1.8/library/rexml/shared/each_element.rb b/1.8/library/rexml/shared/each_element.rb new file mode 100644 index 0000000000..77bba14876 --- /dev/null +++ b/1.8/library/rexml/shared/each_element.rb @@ -0,0 +1,38 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +shared :each_element do |klass, cmd| + describe "REXML::#{klass}##{cmd}" do + before :each do + @e = REXML::Element.new "root" + s1 = REXML::Element.new "node1" + s2 = REXML::Element.new "node2" + s3 = REXML::Element.new "node3" + s4 = REXML::Element.new "sub_node" + @e << s1 + @e << s2 + @e << s3 + @e << s4 + end + + it "iterates through element" do + str = "" + @e.each_element { |elem| str << elem.name << " " } + str.should == "node1 node2 node3 sub_node " + end + + it "iterates through element filtering with XPath" do + str = "" + @e.each_element("/*"){ |e| str << e.name << " "} + str.should == "node1 node2 node3 sub_node " + end + end +end + +describe "REXML::Element#each_element" do + it_behaves_like(:each_element, "Element", :each_element) +end + +describe "REXML::Elements#each" do + it_behaves_like(:each_element, "Elements", :each) +end diff --git a/1.8/library/rexml/shared/elements_to_a.rb b/1.8/library/rexml/shared/elements_to_a.rb new file mode 100644 index 0000000000..54b1030fa9 --- /dev/null +++ b/1.8/library/rexml/shared/elements_to_a.rb @@ -0,0 +1,38 @@ +require 'rexml/document' +require File.dirname(__FILE__) + '/../../../spec_helper' + +shared :elements_to_a do |klass, cmd| + describe "REXML::#{klass}##{cmd}" do + before :each do + @e = REXML::Element.new "root" + @first = REXML::Element.new("FirstChild") + @second = REXML::Element.new("SecondChild") + @e << @first + @e << @second + end + + it "returns elements that match xpath" do + @e.elements.to_a("FirstChild").first.should == @first + end + + # According to the docs REXML::Element#get_elements is an alias for + # REXML::Elements.to_a. Implementation wise there's a difference, get_elements + # always needs the first param (even if it's nil). + # A patch was submitted: + # http://rubyforge.org/tracker/index.php?func=detail&aid=19354&group_id=426&atid=1698 + ruby_bug do + it "returns all childs if xpath is nil" do + @e.elements.to_a.should == [@first, @second] + end + end + + end +end + +describe "REXML::REXML::Elements#to_a" do + it_behaves_like(:elements_to_a, "Elements", :to_a) +end + +describe "REXML::REXML::Element#get_elements" do + it_behaves_like(:elements_to_a, "Element", :get_elements) +end diff --git a/1.8/library/set/add_spec.rb b/1.8/library/set/add_spec.rb new file mode 100644 index 0000000000..c8c919c51c --- /dev/null +++ b/1.8/library/set/add_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/add' +require 'set' + +describe "Set#add" do + it_behaves_like :set_add, :add +end + +describe "Set#add?" do + before :each do + @set = Set.new + end + + it "adds the object to the set and returns self" do + @set.add?("cat").should == Set["cat"] + end + + it "returns nil if the object is already in the set" do + @set.add?("cat") + @set.add?("cat").should == nil + end +end diff --git a/1.8/library/set/append_spec.rb b/1.8/library/set/append_spec.rb new file mode 100644 index 0000000000..f0136e5fb8 --- /dev/null +++ b/1.8/library/set/append_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/add' +require 'set' + +describe "Set#<<" do + it_behaves_like :set_add, :<< +end diff --git a/1.8/library/set/classify_spec.rb b/1.8/library/set/classify_spec.rb new file mode 100644 index 0000000000..cf381b1dbd --- /dev/null +++ b/1.8/library/set/classify_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#classify" do + it "returns a Hash" do + Set["a", "bb"].classify { |x| x.length }.should be_kind_of(Hash) + end + + it "classifies the set by the return value of the block" do + set = Set["one", "two", "three", "four"] + c = set.classify { |x| x.length } + c.keys.should include(3, 4, 5) + c[3].should == Set["one", "two"] + c[4].should == Set["four"] + c[5].should == Set["three"] + end +end diff --git a/1.8/library/set/clear_spec.rb b/1.8/library/set/clear_spec.rb new file mode 100644 index 0000000000..f39bf96e0f --- /dev/null +++ b/1.8/library/set/clear_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#clear" do + it "removes all the elements and returns self" do + saved = set = Set[:a, :b, :c] + set.clear.should == saved + set.empty?.should == true + end +end diff --git a/1.8/library/set/collect_spec.rb b/1.8/library/set/collect_spec.rb new file mode 100644 index 0000000000..194946cba1 --- /dev/null +++ b/1.8/library/set/collect_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#collect!" do + it "destructively performs #collect and returns self" do + saved = set = Set[1, 2, 3, 4, 5] + set.collect! { |x| x * 2 }.should == saved + set.should == Set[2, 4, 6, 8, 10] + end +end diff --git a/1.8/library/set/constructor_spec.rb b/1.8/library/set/constructor_spec.rb new file mode 100644 index 0000000000..8d262d3294 --- /dev/null +++ b/1.8/library/set/constructor_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set.[]" do + it "creates a new Set" do + set = Set[1, 2, 3] + other = Set.new + other << 1 << 2 << 3 + set.should == other + end +end diff --git a/1.8/library/set/delete_if_spec.rb b/1.8/library/set/delete_if_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/delete_if_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/delete_spec.rb b/1.8/library/set/delete_spec.rb new file mode 100644 index 0000000000..0337bd9970 --- /dev/null +++ b/1.8/library/set/delete_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#delete" do + it "deletes the object and returns self" do + saved = set = Set[:a, :b, :c] + set.delete(:a).should == saved + set.should == Set[:b, :c] + end +end + +describe "Set#delete?" do + it "deletes the object and returns self" do + saved = set = Set[:a, :b, :c] + set.delete?(:b).should == saved + set.should == Set[:a, :c] + end + + it "returns nil if the element is not in the set" do + Set[:a, :b, :c].delete?(:d).should == nil + end +end diff --git a/1.8/library/set/difference_spec.rb b/1.8/library/set/difference_spec.rb new file mode 100644 index 0000000000..d0a26e3731 --- /dev/null +++ b/1.8/library/set/difference_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/difference' +require 'set' + +describe "Set#difference" do + it_behaves_like :set_difference, :difference +end diff --git a/1.8/library/set/divide_spec.rb b/1.8/library/set/divide_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/divide_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/each_spec.rb b/1.8/library/set/each_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/each_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/empty_spec.rb b/1.8/library/set/empty_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/empty_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/equal_value_spec.rb b/1.8/library/set/equal_value_spec.rb new file mode 100644 index 0000000000..d25661f741 --- /dev/null +++ b/1.8/library/set/equal_value_spec.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#==" do + it "returns true if the sets are equal" do + s1 = Set[:a, :b, :c] + s2 = Set[:a, :b, :c] + s1.should == s2 + s1 << :d + s1.should_not == s2 + end +end diff --git a/1.8/library/set/exclusion_spec.rb b/1.8/library/set/exclusion_spec.rb new file mode 100644 index 0000000000..496c26b036 --- /dev/null +++ b/1.8/library/set/exclusion_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#^" do + before :each do + @set = Set[1, 2, 3, 4] + end + + it "returns a new set containing elements not in both self and other" do + set = @set ^ Set[3, 4, 5] + set.should == Set[1, 2, 5] + end + + it "accepts any enumerable as other" do + set = @set ^ [3, 4] + set.should == Set[1, 2] + end +end diff --git a/1.8/library/set/flatten_merge_spec.rb b/1.8/library/set/flatten_merge_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/flatten_merge_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/flatten_spec.rb b/1.8/library/set/flatten_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/flatten_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/include_spec.rb b/1.8/library/set/include_spec.rb new file mode 100644 index 0000000000..2298390fd5 --- /dev/null +++ b/1.8/library/set/include_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include' +require 'set' + +describe "Set#include?" do + it_behaves_like :set_include, :include? +end diff --git a/1.8/library/set/inspect_spec.rb b/1.8/library/set/inspect_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/inspect_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/intersection_spec.rb b/1.8/library/set/intersection_spec.rb new file mode 100644 index 0000000000..1c6725424e --- /dev/null +++ b/1.8/library/set/intersection_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/intersection' +require 'set' + +describe "Set#intersection" do + it_behaves_like :set_intersection, :intersection +end + +describe "Set#&" do + it_behaves_like :set_intersection, :& +end diff --git a/1.8/library/set/length_spec.rb b/1.8/library/set/length_spec.rb new file mode 100644 index 0000000000..231f1da0bd --- /dev/null +++ b/1.8/library/set/length_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/length' +require 'set' + +describe "Set#length" do + it_behaves_like :set_length, :length +end diff --git a/1.8/library/set/map_spec.rb b/1.8/library/set/map_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/map_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/member_spec.rb b/1.8/library/set/member_spec.rb new file mode 100644 index 0000000000..db89362c98 --- /dev/null +++ b/1.8/library/set/member_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/include' +require 'set' + +describe "Set#member?" do + it_behaves_like :set_include, :member? +end diff --git a/1.8/library/set/merge_spec.rb b/1.8/library/set/merge_spec.rb new file mode 100644 index 0000000000..b13e31e834 --- /dev/null +++ b/1.8/library/set/merge_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#merge" do + before :each do + @set = Set[:a, :b] + end + + it "adds the elements of other to the set and returns self" do + @set.merge(Set[:b, :c, :d]).should == @set + @set.should == Set[:a, :b, :c, :d] + end + + it "accepts any enumerable as other" do + @set.merge([:a, :b, :c]).should == Set[:a, :b, :c] + end +end diff --git a/1.8/library/set/minus_spec.rb b/1.8/library/set/minus_spec.rb new file mode 100644 index 0000000000..9bbd6eb44c --- /dev/null +++ b/1.8/library/set/minus_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/difference' +require 'set' + +describe "Set#difference" do + it_behaves_like :set_difference, :- +end diff --git a/1.8/library/set/plus_spec.rb b/1.8/library/set/plus_spec.rb new file mode 100644 index 0000000000..e6938437d7 --- /dev/null +++ b/1.8/library/set/plus_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/union' +require 'set' + +describe "Set#+" do + it_behaves_like :set_union, :+ +end diff --git a/1.8/library/set/pretty_print_cycle_spec.rb b/1.8/library/set/pretty_print_cycle_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/pretty_print_cycle_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/pretty_print_spec.rb b/1.8/library/set/pretty_print_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/pretty_print_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/proper_subset_spec.rb b/1.8/library/set/proper_subset_spec.rb new file mode 100644 index 0000000000..6dbed817b5 --- /dev/null +++ b/1.8/library/set/proper_subset_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#proper_subset?" do + + before :each do + @set = Set[1, 2, 3, 4] + @subset = Set[1, 2, 3] + @empty_set = Set[] + end + + it "returns true if a subset" do + @subset.proper_subset?(@set).should == true + end + + it "returns false when compared to itself" do + @set.proper_subset?(@set).should == false + end + + it "returns true when comparing set to empty set" do + @empty_set.proper_subset?(@set).should == true + end + + it "returns false when comparing empty set to itself" do + @empty_set.proper_subset?(@empty_set).should == false + end + +end diff --git a/1.8/library/set/proper_superset_spec.rb b/1.8/library/set/proper_superset_spec.rb new file mode 100644 index 0000000000..65afdbfbd3 --- /dev/null +++ b/1.8/library/set/proper_superset_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#superset?" do + + before :each do + @set = Set[1, 2, 3, 4] + @superset = Set[1, 2, 3, 4, 5] + @empty_set = Set[] + end + + it "returns true if a proper superset" do + @superset.proper_superset?(@set).should == true + end + + it "returns false when compared to itself" do + @set.proper_superset?(@set).should == false + end + + it "returns false when non-empty set compared to an empty set" do + @empty_set.proper_superset?(@set).should == false + end + + it "returns false then empty set compared to itself" do + @empty_set.proper_superset?(@empty_set).should == false + end + +end diff --git a/1.8/library/set/reject_spec.rb b/1.8/library/set/reject_spec.rb new file mode 100644 index 0000000000..65ff4d1a18 --- /dev/null +++ b/1.8/library/set/reject_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' diff --git a/1.8/library/set/replace_spec.rb b/1.8/library/set/replace_spec.rb new file mode 100644 index 0000000000..8c108cc1fb --- /dev/null +++ b/1.8/library/set/replace_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#replace" do + before :each do + @set = Set[:a, :b, :c] + end + + it "replaces the contents with other and returns self" do + @set.replace(Set[1, 2, 3]).should == @set + @set.should == Set[1, 2, 3] + end + + it "accepts any enumerable as other" do + @set.replace([1, 2, 3]).should == Set[1, 2, 3] + end +end diff --git a/1.8/library/set/shared/add.rb b/1.8/library/set/shared/add.rb new file mode 100644 index 0000000000..e7811022a9 --- /dev/null +++ b/1.8/library/set/shared/add.rb @@ -0,0 +1,11 @@ +shared :set_add do |cmd| + describe "Set##{cmd}" do + before :each do + @set = Set.new + end + + it "adds the object to the set and returns self" do + @set.send(cmd, "dog").should == Set["dog"] + end + end +end diff --git a/1.8/library/set/shared/difference.rb b/1.8/library/set/shared/difference.rb new file mode 100644 index 0000000000..24a26107ea --- /dev/null +++ b/1.8/library/set/shared/difference.rb @@ -0,0 +1,15 @@ +shared :set_difference do |cmd| + describe "Set##{cmd}" do + before :each do + @set = Set[:a, :b, :c] + end + + it "returns a new set excluding the elements in other" do + @set.send(cmd, Set[:a, :b]).should == Set[:c] + end + + it "accepts any enumerable as other" do + @set.send(cmd, [:b, :c]).should == Set[:a] + end + end +end diff --git a/1.8/library/set/shared/include.rb b/1.8/library/set/shared/include.rb new file mode 100644 index 0000000000..20c984ae94 --- /dev/null +++ b/1.8/library/set/shared/include.rb @@ -0,0 +1,9 @@ +shared :set_include do |cmd| + describe "Set##{cmd}" do + it "returns true if the set contains the object" do + set = Set[:a, :b, :c] + set.send(cmd, :a).should == true + set.send(cmd, :e).should == false + end + end +end diff --git a/1.8/library/set/shared/intersection.rb b/1.8/library/set/shared/intersection.rb new file mode 100644 index 0000000000..5cd866a521 --- /dev/null +++ b/1.8/library/set/shared/intersection.rb @@ -0,0 +1,15 @@ +shared :set_intersection do |cmd| + describe "Set##{cmd}" do + before :each do + @set = Set[:a, :b, :c] + end + + it "returns a new set containing only elements shared by self and other" do + @set.send(cmd, Set[:b, :c, :d, :e]).should == Set[:b, :c] + end + + it "accepts any enumerable as other" do + @set.send(cmd, [:b, :c, :d]).should == Set[:b, :c] + end + end +end diff --git a/1.8/library/set/shared/length.rb b/1.8/library/set/shared/length.rb new file mode 100644 index 0000000000..988d4ffa1c --- /dev/null +++ b/1.8/library/set/shared/length.rb @@ -0,0 +1,8 @@ +shared :set_length do |cmd| + describe "Set##{cmd}" do + it "returns the number of elements in the set" do + set = Set[:a, :b, :c] + set.send(cmd).should == 3 + end + end +end diff --git a/1.8/library/set/shared/union.rb b/1.8/library/set/shared/union.rb new file mode 100644 index 0000000000..fcfe2a5e9a --- /dev/null +++ b/1.8/library/set/shared/union.rb @@ -0,0 +1,15 @@ +shared :set_union do |cmd| + describe "Set##{cmd}" do + before :each do + @set = Set[:a, :b, :c] + end + + it "returns a new set containing all the elements of self and other" do + @set.send(cmd, Set[:b, :d, :e]).should == Set[:a, :b, :c, :d, :e] + end + + it "accepts any enumerable as other" do + @set.send(cmd, [:b, :e]).should == Set[:a, :b, :c, :e] + end + end +end diff --git a/1.8/library/set/size_spec.rb b/1.8/library/set/size_spec.rb new file mode 100644 index 0000000000..2b6266c0d4 --- /dev/null +++ b/1.8/library/set/size_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/length' +require 'set' + +describe "Set#size" do + it_behaves_like :set_length, :size +end diff --git a/1.8/library/set/subset_spec.rb b/1.8/library/set/subset_spec.rb new file mode 100644 index 0000000000..ad1ed9a6f0 --- /dev/null +++ b/1.8/library/set/subset_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#subset?" do + + before :each do + @set = Set[1, 2, 3, 4] + @subset = Set[1, 2, 3] + @empty_set = Set[] + end + + it "returns true if a subset of a set" do + @subset.subset?(@set).should == true + end + + it "returns true when compared to itself" do + @set.subset?(@set).should == true + end + + it "returns true when comparing empty set to a set" do + @empty_set.subset?(@set).should == true + end + + it "returns true when comparing empty set to itself" do + @empty_set.subset?(@empty_set).should == true + end + +end diff --git a/1.8/library/set/subtract_spec.rb b/1.8/library/set/subtract_spec.rb new file mode 100644 index 0000000000..3aac8af951 --- /dev/null +++ b/1.8/library/set/subtract_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#subtract" do + before :each do + @set = Set[:a, :b, :c] + end + + it "deletes any elements contained in other and returns self" do + @set.subtract(Set[:b, :c]).should == @set + @set.should == Set[:a] + end + + it "accepts any enumerable as other" do + @set.subtract([:c]).should == Set[:a, :b] + end +end diff --git a/1.8/library/set/superset_spec.rb b/1.8/library/set/superset_spec.rb new file mode 100644 index 0000000000..6a10a9b1b7 --- /dev/null +++ b/1.8/library/set/superset_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#superset?" do + + before :each do + @set = Set[1, 2, 3, 4] + @superset = Set[1, 2, 3, 4, 5] + @empty_set = Set[] + end + + it "returns true if a superset" do + @superset.superset?(@set).should == true + end + + it "returns true when compared to itself" do + @set.superset?(@set).should == true + end + + it "returns false when non-empty set compared to empty set" do + @empty_set.superset?(@set).should == false + end + + it "returns true then empty set compared to itself" do + @empty_set.superset?(@empty_set).should == true + end + +end diff --git a/1.8/library/set/to_a_spec.rb b/1.8/library/set/to_a_spec.rb new file mode 100644 index 0000000000..a6098676c8 --- /dev/null +++ b/1.8/library/set/to_a_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Set#to_a" do + it "returns an array containing elements of self" do + Set[1, 2, 3].to_a.sort.should == [1, 2, 3] + end +end diff --git a/1.8/library/set/to_set_spec.rb b/1.8/library/set/to_set_spec.rb new file mode 100644 index 0000000000..f4555208e5 --- /dev/null +++ b/1.8/library/set/to_set_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'set' + +describe "Enumerable#to_set" do + it "is added by Set" do + Enumerable.instance_methods.should include("to_set") + end +end diff --git a/1.8/library/set/union_spec.rb b/1.8/library/set/union_spec.rb new file mode 100644 index 0000000000..bb031d2faa --- /dev/null +++ b/1.8/library/set/union_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/union' +require 'set' + +describe "Set#union" do + it_behaves_like :set_union, :union +end + +describe "Set#|" do + it_behaves_like :set_union, :| +end diff --git a/1.8/library/singleton/allocate_spec.rb b/1.8/library/singleton/allocate_spec.rb new file mode 100644 index 0000000000..bf6ac60158 --- /dev/null +++ b/1.8/library/singleton/allocate_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Singleton.allocate" do + it "is a private method" do + lambda { SingletonSpecs::MyClass.allocate }.should raise_error(NoMethodError) + end +end diff --git a/1.8/library/singleton/clone_spec.rb b/1.8/library/singleton/clone_spec.rb new file mode 100644 index 0000000000..cdf72e537f --- /dev/null +++ b/1.8/library/singleton/clone_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Singleton#clone" do + it "is prevented" do + lambda { SingletonSpecs::MyClass.instance.clone }.should raise_error(TypeError) + end +end diff --git a/1.8/library/singleton/dump_spec.rb b/1.8/library/singleton/dump_spec.rb new file mode 100644 index 0000000000..5c6c37c463 --- /dev/null +++ b/1.8/library/singleton/dump_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Singleton#_dump" do + + it "is a private method" do + lambda { SingletonSpecs::MyClass.instance._dump }.should raise_error(NoMethodError) + end + + it "returns an empty string" do + SingletonSpecs::MyClass.instance.send(:_dump).should == "" + end + + it "returns an empty string from a singleton subclass" do + SingletonSpecs::MyClassChild.instance.send(:_dump).should == "" + end + +end \ No newline at end of file diff --git a/1.8/library/singleton/dup_spec.rb b/1.8/library/singleton/dup_spec.rb new file mode 100644 index 0000000000..3e41b189e8 --- /dev/null +++ b/1.8/library/singleton/dup_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Singleton#dup" do + it "is prevented" do + lambda { SingletonSpecs::MyClass.instance.dup }.should raise_error(TypeError) + end +end diff --git a/1.8/library/singleton/fixtures/classes.rb b/1.8/library/singleton/fixtures/classes.rb new file mode 100644 index 0000000000..bf2a684a3d --- /dev/null +++ b/1.8/library/singleton/fixtures/classes.rb @@ -0,0 +1,18 @@ +require 'singleton' + +module SingletonSpecs + class MyClass + attr_accessor :data + include Singleton + end + + class NewSpec + include Singleton + end + + class MyClassChild < MyClass + end + + class NotInstantiated < MyClass + end +end diff --git a/1.8/library/singleton/instance_spec.rb b/1.8/library/singleton/instance_spec.rb new file mode 100644 index 0000000000..ce15cb3246 --- /dev/null +++ b/1.8/library/singleton/instance_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Singleton.instance" do + it "returns an instance of the singleton class" do + SingletonSpecs::MyClass.instance.should be_kind_of(SingletonSpecs::MyClass) + end + + it "returns the same instance for multiple calls to instance" do + SingletonSpecs::MyClass.instance.equal?(SingletonSpecs::MyClass.instance).should == true + end + + it "returns an instance of the singleton's subclasses" do + SingletonSpecs::MyClassChild.instance.should be_kind_of(SingletonSpecs::MyClassChild) + end + + it "returns the same instance for multiple class to instance on subclasses" do + SingletonSpecs::MyClassChild.instance.equal?(SingletonSpecs::MyClassChild.instance).should == true + end + + it "returns an instance of the singleton's clone" do + klone = SingletonSpecs::MyClassChild.clone + klone.instance.should be_kind_of(klone) + end + + it "returns the same instance for multiple class to instance on clones" do + klone = SingletonSpecs::MyClassChild.clone + klone.instance.equal?(klone.instance).should == true + end +end diff --git a/1.8/library/singleton/instantiate_spec.rb b/1.8/library/singleton/instantiate_spec.rb new file mode 100644 index 0000000000..5b15c6f2a1 --- /dev/null +++ b/1.8/library/singleton/instantiate_spec.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Singleton._instantiate?" do + + it "is private" do + lambda { SingletonSpecs::MyClass._instantiate? }.should raise_error(NoMethodError) + end + + # JRuby doesn't support "_instantiate?" intentionally (JRUBY-2239) + not_compliant_on :jruby do + it "returns nil until it is instantiated" do + SingletonSpecs::NotInstantiated.send(:_instantiate?).should == nil + SingletonSpecs::NotInstantiated.instance + SingletonSpecs::NotInstantiated.send(:_instantiate?).eql?(SingletonSpecs::NotInstantiated.instance).should == true + end + end +end diff --git a/1.8/library/singleton/load_spec.rb b/1.8/library/singleton/load_spec.rb new file mode 100644 index 0000000000..bd6084ceed --- /dev/null +++ b/1.8/library/singleton/load_spec.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Singleton._load" do + + it "is a private method" do + lambda { SingletonSpecs::MyClass.instance._load("") }.should raise_error(NoMethodError) + end + + it "returns the singleton instance for anything passed in" do + SingletonSpecs::MyClass.send(:_load, "").equal?(SingletonSpecs::MyClass.instance).should == true + SingletonSpecs::MyClass.send(:_load, "42").equal?(SingletonSpecs::MyClass.instance).should == true + SingletonSpecs::MyClass.send(:_load, 42).equal?(SingletonSpecs::MyClass.instance).should == true + end + + it "returns the singleton instance for anything passed in for a singleton subclass" do + SingletonSpecs::MyClassChild.send(:_load, "").equal?(SingletonSpecs::MyClassChild.instance).should == true + SingletonSpecs::MyClassChild.send(:_load, "42").equal?(SingletonSpecs::MyClassChild.instance).should == true + SingletonSpecs::MyClassChild.send(:_load, 42).equal?(SingletonSpecs::MyClassChild.instance).should == true + end + + it "returns the singleton instance for anything passed in for a singleton clone" do + klone = SingletonSpecs::MyClass.clone + klone.send(:_load, "").equal?(klone.instance).should == true + klone.send(:_load, "42").equal?(klone.instance).should == true + klone.send(:_load, 42).equal?(klone.instance).should == true + end + +end + +describe "Marshal.load on singleton object previously serialised in this process" do + ruby_bug do + # http://rubyforge.org/tracker/index.php?func=detail&aid=19377&group_id=426&atid=1698 + it "returns the singleton instance" do + instance = SingletonSpecs::MyClass.instance + instance.equal?(Marshal.load(Marshal.dump(instance))).should == true + end + end +end diff --git a/1.8/library/singleton/new_spec.rb b/1.8/library/singleton/new_spec.rb new file mode 100644 index 0000000000..d4664059c9 --- /dev/null +++ b/1.8/library/singleton/new_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Singleton.new" do + it "is a private method" do + lambda { SingletonSpecs::NewSpec.new }.should raise_error(NoMethodError) + end +end diff --git a/1.8/library/socket/accept_nonblock_spec.rb b/1.8/library/socket/accept_nonblock_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/accept_nonblock_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/accept_spec.rb b/1.8/library/socket/accept_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/accept_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/basicsocket/close_read_spec.rb b/1.8/library/socket/basicsocket/close_read_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/close_read_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/basicsocket/close_write_spec.rb b/1.8/library/socket/basicsocket/close_write_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/close_write_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/basicsocket/do_not_reverse_lookup_spec.rb b/1.8/library/socket/basicsocket/do_not_reverse_lookup_spec.rb new file mode 100644 index 0000000000..63ad553423 --- /dev/null +++ b/1.8/library/socket/basicsocket/do_not_reverse_lookup_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "BasicSocket#do_not_reverse_lookup" do + before(:each) do + BasicSocket.do_not_reverse_lookup = true + @server = TCPServer.new('127.0.0.1', SocketSpecs.port) + end + + after(:each) do + BasicSocket.do_not_reverse_lookup = false + @server.close if @server + @socket.close if @socket + end + + it "causes 'peeraddr' to avoid name lookups" do + @socket = TCPSocket.new('127.0.0.1', SocketSpecs.port) + @socket.peeraddr.should == ["AF_INET", SocketSpecs.port, "127.0.0.1", "127.0.0.1"] + end +end diff --git a/1.8/library/socket/basicsocket/for_fd_spec.rb b/1.8/library/socket/basicsocket/for_fd_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/for_fd_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/basicsocket/getpeername_spec.rb b/1.8/library/socket/basicsocket/getpeername_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/getpeername_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/basicsocket/getsockname_spec.rb b/1.8/library/socket/basicsocket/getsockname_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/getsockname_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/basicsocket/getsockopt_spec.rb b/1.8/library/socket/basicsocket/getsockopt_spec.rb new file mode 100644 index 0000000000..4e973a2c35 --- /dev/null +++ b/1.8/library/socket/basicsocket/getsockopt_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "BasicSocket#getsockopt" do + + before(:each) do + @sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) + end + + it "gets a socket option" do + n = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE) + n.should == [Socket::SOCK_STREAM].pack("i") + end + + it "raises a SystemCallError with an invalid socket option" do + lambda { @sock.getsockopt Socket::SOL_SOCKET, -1 }.should \ + raise_error(Errno::ENOPROTOOPT) + end + +end + diff --git a/1.8/library/socket/basicsocket/recv_nonblock_spec.rb b/1.8/library/socket/basicsocket/recv_nonblock_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/recv_nonblock_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/basicsocket/recv_spec.rb b/1.8/library/socket/basicsocket/recv_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/recv_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/basicsocket/send_spec.rb b/1.8/library/socket/basicsocket/send_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/send_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/basicsocket/setsockopt_spec.rb b/1.8/library/socket/basicsocket/setsockopt_spec.rb new file mode 100644 index 0000000000..9ca0c7aab2 --- /dev/null +++ b/1.8/library/socket/basicsocket/setsockopt_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "BasicSocket#setsockopt" do + + before(:each) do + @sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) + end + + it "sets the socket linger to 0" do + linger = [0, 0].pack("ii") + @sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, linger).should == 0 + end + +end diff --git a/1.8/library/socket/basicsocket/shutdown_spec.rb b/1.8/library/socket/basicsocket/shutdown_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/basicsocket/shutdown_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/bind_spec.rb b/1.8/library/socket/bind_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/bind_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/connect_nonblock_spec.rb b/1.8/library/socket/connect_nonblock_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/connect_nonblock_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/connect_spec.rb b/1.8/library/socket/connect_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/connect_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/fixtures/classes.rb b/1.8/library/socket/fixtures/classes.rb new file mode 100644 index 0000000000..3c55328c32 --- /dev/null +++ b/1.8/library/socket/fixtures/classes.rb @@ -0,0 +1,12 @@ +require 'socket' + +module SocketSpecs + def self.port + 40001 + end + + def self.sockaddr_in(port, host) + Socket::SockAddr_In.new(Socket.sockaddr_in(port, host)) + end + +end diff --git a/1.8/library/socket/getaddrinfo_spec.rb b/1.8/library/socket/getaddrinfo_spec.rb new file mode 100644 index 0000000000..dfe808ed35 --- /dev/null +++ b/1.8/library/socket/getaddrinfo_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'socket' + +describe "Socket#getaddrinfo" do + it "gets the address information" do + expected = [] + host = Socket.getaddrinfo("127.0.0.1", nil)[0][2] + # The check for AP_INET6's class is needed because ipaddr.rb adds + # fake AP_INET6 even in case when IPv6 is not really supported. + # Without such check, this test might fail when ipaddr was required + # by some other specs. + if (Socket.constants.include? 'AF_INET6') && + (Socket::AF_INET6.class != Object) then + expected.concat [ + ['AF_INET6', 80, host, '::1', Socket::AF_INET6, + Socket::SOCK_DGRAM, Socket::IPPROTO_UDP], + ['AF_INET6', 80, host, '::1', Socket::AF_INET6, + Socket::SOCK_STREAM, Socket::IPPROTO_TCP], + ['AF_INET6', 80, host, '::1', Socket::AF_INET6, + Socket::SOCK_DGRAM, Socket::IPPROTO_UDP], + ['AF_INET6', 80, host, '::1', Socket::AF_INET6, + Socket::SOCK_STREAM, Socket::IPPROTO_TCP], + ] + end + + expected.concat [ + ['AF_INET', 80, host, '127.0.0.1', Socket::AF_INET, + Socket::SOCK_DGRAM, Socket::IPPROTO_UDP], + ['AF_INET', 80, host, '127.0.0.1', Socket::AF_INET, + Socket::SOCK_STREAM, Socket::IPPROTO_TCP], + ] + + addrinfo = Socket.getaddrinfo host, 'http' + addrinfo.each { |a| expected.should include(a) } + end + +end + diff --git a/1.8/library/socket/gethostbyaddr_spec.rb b/1.8/library/socket/gethostbyaddr_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/gethostbyaddr_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/gethostbyname_spec.rb b/1.8/library/socket/gethostbyname_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/gethostbyname_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/gethostname_spec.rb b/1.8/library/socket/gethostname_spec.rb new file mode 100644 index 0000000000..ea4d6693cd --- /dev/null +++ b/1.8/library/socket/gethostname_spec.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Socket.gethostname" do + # This currently works in Unix and Windows. Feel free to add guards + # for other platforms. + it "returns the host name" do + Socket.gethostname.should == `hostname`.strip + end +end diff --git a/1.8/library/socket/getnameinfo_spec.rb b/1.8/library/socket/getnameinfo_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/getnameinfo_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/getservbyname_spec.rb b/1.8/library/socket/getservbyname_spec.rb new file mode 100644 index 0000000000..9fc43e3c8d --- /dev/null +++ b/1.8/library/socket/getservbyname_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Socket#getservbyname" do + + it "identifies service ports " do + Socket.getservbyname('http').should == 80 + Socket.getservbyname('http', 'tcp').should == 80 + Socket.getservbyname('domain', 'udp').should == 53 + Socket.getservbyname('daytime').should == 13 + end + + it "raises a SocketError when the service or port is invalid" do + lambda { Socket.getservbyname('invalid') }.should raise_error(SocketError) + end +end \ No newline at end of file diff --git a/1.8/library/socket/ipsocket/addr_spec.rb b/1.8/library/socket/ipsocket/addr_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/socket/ipsocket/addr_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/socket/ipsocket/getaddress_spec.rb b/1.8/library/socket/ipsocket/getaddress_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/socket/ipsocket/getaddress_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/socket/ipsocket/peeraddr_spec.rb b/1.8/library/socket/ipsocket/peeraddr_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/socket/ipsocket/peeraddr_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/socket/ipsocket/recvfrom_spec.rb b/1.8/library/socket/ipsocket/recvfrom_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/socket/ipsocket/recvfrom_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/socket/listen_spec.rb b/1.8/library/socket/listen_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/listen_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/new_spec.rb b/1.8/library/socket/new_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/new_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/pack_sockaddr_in_spec.rb b/1.8/library/socket/pack_sockaddr_in_spec.rb new file mode 100644 index 0000000000..41211ed3fb --- /dev/null +++ b/1.8/library/socket/pack_sockaddr_in_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/pack_sockaddr' + +describe "Socket#pack_sockaddr_in" do + it_behaves_like :pack_sockaddr_in, :pack_sockaddr_in +end diff --git a/1.8/library/socket/pack_sockaddr_un_spec.rb b/1.8/library/socket/pack_sockaddr_un_spec.rb new file mode 100644 index 0000000000..12c65cc4eb --- /dev/null +++ b/1.8/library/socket/pack_sockaddr_un_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/pack_sockaddr' + +describe "Socket#pack_sockaddr_un" do + it_behaves_like :pack_sockaddr_un, :pack_sockaddr_un +end diff --git a/1.8/library/socket/pair_spec.rb b/1.8/library/socket/pair_spec.rb new file mode 100644 index 0000000000..0cf67a8988 --- /dev/null +++ b/1.8/library/socket/pair_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/socketpair' + +describe "Socket#pair" do + it_behaves_like :socketpair, :pair +end diff --git a/1.8/library/socket/recvfrom_nonblock_spec.rb b/1.8/library/socket/recvfrom_nonblock_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/recvfrom_nonblock_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/recvfrom_spec.rb b/1.8/library/socket/recvfrom_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/recvfrom_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/setsockopt_spec.rb b/1.8/library/socket/setsockopt_spec.rb new file mode 100644 index 0000000000..350bcd9266 --- /dev/null +++ b/1.8/library/socket/setsockopt_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "TCPServer#setsockopt" do + after(:each) do + @server.close if @server + @socket.close if @socket + end +end diff --git a/1.8/library/socket/shared/pack_sockaddr.rb b/1.8/library/socket/shared/pack_sockaddr.rb new file mode 100644 index 0000000000..0d10b1c754 --- /dev/null +++ b/1.8/library/socket/shared/pack_sockaddr.rb @@ -0,0 +1,24 @@ +shared :pack_sockaddr_in do |cmd| + describe "Socket##{cmd}" do + + it "packs and unpacks" do + sockaddr_in = Socket.pack_sockaddr_in 0, '' + Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '0.0.0.0'] + + sockaddr_in = Socket.pack_sockaddr_in 80, '127.0.0.1' + Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1'] + end + end +end + +shared :pack_sockaddr_un do |cmd| + not_supported_on :jruby do + describe "Socket##{cmd}" do + it "packs and unpacks" do + sockaddr_un = Socket.pack_sockaddr_un '/tmp/s' + Socket.unpack_sockaddr_un(sockaddr_un).should == '/tmp/s' + end + end + end +end + diff --git a/1.8/library/socket/shared/socketpair.rb b/1.8/library/socket/shared/socketpair.rb new file mode 100644 index 0000000000..52e88388bf --- /dev/null +++ b/1.8/library/socket/shared/socketpair.rb @@ -0,0 +1,11 @@ +shared :socketpair do |cmd| + not_supported_on :jruby do + describe "Socket##{cmd}" do + it "ensures the returned sockets are connected" do + s1, s2 = Socket.socketpair(Socket::AF_UNIX, 1, 0) + s1.puts("test") + s2.gets.should == "test\n" + end + end + end +end diff --git a/1.8/library/socket/sockaddr_in_spec.rb b/1.8/library/socket/sockaddr_in_spec.rb new file mode 100644 index 0000000000..8ac263b798 --- /dev/null +++ b/1.8/library/socket/sockaddr_in_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/pack_sockaddr' + +describe "Socket#sockaddr_in" do + it_behaves_like :pack_sockaddr_in, :sockaddr_in +end \ No newline at end of file diff --git a/1.8/library/socket/sockaddr_un_spec.rb b/1.8/library/socket/sockaddr_un_spec.rb new file mode 100644 index 0000000000..4f0ca047ca --- /dev/null +++ b/1.8/library/socket/sockaddr_un_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/pack_sockaddr' + +describe "Socket#sockaddr_un" do + it_behaves_like :pack_sockaddr_un, :sockaddr_un +end diff --git a/1.8/library/socket/socket_spec.rb b/1.8/library/socket/socket_spec.rb new file mode 100644 index 0000000000..027cf3c34a --- /dev/null +++ b/1.8/library/socket/socket_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "Socket" do + it "inherits from BasicSocket and IO" do + Socket.superclass.should == BasicSocket + BasicSocket.superclass.should == IO + end +end + +describe "The socket class hierarchy" do + it "has an IPSocket in parallel to Socket" do + Socket.ancestors.include?(IPSocket).should == false + IPSocket.ancestors.include?(Socket).should == false + IPSocket.superclass.should == BasicSocket + end + + it "has TCPSocket and UDPSocket subclasses of IPSocket" do + TCPSocket.superclass.should == IPSocket + UDPSocket.superclass.should == IPSocket + end + + not_supported_on :jruby do + it "has a UNIXSocket in parallel to Socket" do + Socket.ancestors.include?(UNIXSocket).should == false + UNIXSocket.ancestors.include?(Socket).should == false + UNIXSocket.superclass.should == BasicSocket + end + end +end + +not_supported_on :jruby do + describe "Server class hierarchy" do + it "contains UNIXServer" do + UNIXServer.superclass.should == UNIXSocket + end + end +end diff --git a/1.8/library/socket/socketpair_spec.rb b/1.8/library/socket/socketpair_spec.rb new file mode 100644 index 0000000000..5937214ab5 --- /dev/null +++ b/1.8/library/socket/socketpair_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/socketpair' + +describe "Socket#socketpair" do + it_behaves_like :socketpair, :socketpair +end diff --git a/1.8/library/socket/sysaccept_spec.rb b/1.8/library/socket/sysaccept_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/sysaccept_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/tcpserver/accept_nonblock_spec.rb b/1.8/library/socket/tcpserver/accept_nonblock_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/tcpserver/accept_nonblock_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/tcpserver/accept_spec.rb b/1.8/library/socket/tcpserver/accept_spec.rb new file mode 100644 index 0000000000..a57ddf06e5 --- /dev/null +++ b/1.8/library/socket/tcpserver/accept_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "TCPServer#accept" do + it "accepts what is written by the client" do + server = TCPServer.new('127.0.0.1', SocketSpecs.port) + data = nil + t = Thread.new do + client = server.accept + data = client.read(5) + client << "goodbye" + client.close + end + Thread.pass until t.status == "sleep" + + socket = TCPSocket.new('127.0.0.1', SocketSpecs.port) + socket.write('hello') + socket.read.should == 'goodbye' + t.join + data.should == 'hello' + server.close + socket.close + end + + it "can be interrupted by Thread#kill" do + server = TCPServer.new(nil, SocketSpecs.port) + t = Thread.new { + server.accept + } + Thread.pass until t.status == "sleep" + + # kill thread, ensure it dies in a reasonable amount of time + t.kill + a = 1 + while a < 1000 + break unless t.alive? + Thread.pass + a += 1 + end + a.should < 1000 + server.close + end + + it "can be interrupted by Thread#raise" do + server = TCPServer.new(nil, SocketSpecs.port) + t = Thread.new { + server.accept + } + Thread.pass until t.status == "sleep" + + # raise in thread, ensure the raise happens + ex = Exception.new + t.raise ex + lambda { t.join }.should raise_error(Exception) + server.close + end +end diff --git a/1.8/library/socket/tcpserver/close_spec.rb b/1.8/library/socket/tcpserver/close_spec.rb new file mode 100644 index 0000000000..c6d4735a5e --- /dev/null +++ b/1.8/library/socket/tcpserver/close_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "TCPServer#close" do + it "returns nil" do + server = TCPServer.new('127.0.0.1', SocketSpecs.port) + lambda { server.close.should == nil }.should_not raise_error + end + + it "should raise an error if closed twice" do + server = TCPServer.new('127.0.0.1', SocketSpecs.port) + server.close + lambda { server.close }.should raise_error(IOError) + end +end diff --git a/1.8/library/socket/tcpserver/listen_spec.rb b/1.8/library/socket/tcpserver/listen_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/tcpserver/listen_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/tcpserver/new_spec.rb b/1.8/library/socket/tcpserver/new_spec.rb new file mode 100644 index 0000000000..9bec876e71 --- /dev/null +++ b/1.8/library/socket/tcpserver/new_spec.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "TCPServer.new" do + before(:each) do + @hostname = Socket.getaddrinfo("127.0.0.1", nil)[0][2] + end + after(:each) do + @server.close if @server && !@server.closed? + end + + it "binds to a host and a port" do + @server = TCPServer.new('127.0.0.1', SocketSpecs.port) + addr = @server.addr + addr[0].should == 'AF_INET' + addr[1].be_kind_of Fixnum + # on some platforms (Mac), MRI + # returns comma at the end. + addr[2].should =~ /^#{@hostname}\b/ + addr[3].should == '127.0.0.1' + end + + it "binds to localhost and a port with either IPv4 or IPv6" do + @server = TCPServer.new("localhost", SocketSpecs.port) + addr = @server.addr + if addr[0] == 'AF_INET' + addr[1].be_kind_of Fixnum + addr[2].should =~ /^#{@hostname}\b/ + addr[3].should == '127.0.0.1' + else + addr[1].be_kind_of Fixnum + addr[2].should =~ /^#{@hostname}\b/ + addr[3].should == '::1' + end + end + + it "coerces port to string, then determines port from that number or service name" do + t = Object.new + lambda { TCPServer.new('localhost', t) }.should raise_error(TypeError) + + def t.to_str; SocketSpecs.port.to_s; end + + @server = TCPServer.new(@hostname, t) + addr = @server.addr + addr[1].should == SocketSpecs.port + + # TODO: This should also accept strings like 'https', but I don't know how to + # pick such a service port that will be able to reliably bind... + end +end diff --git a/1.8/library/socket/tcpserver/output_spec.rb b/1.8/library/socket/tcpserver/output_spec.rb new file mode 100644 index 0000000000..a07defd90d --- /dev/null +++ b/1.8/library/socket/tcpserver/output_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "TCPServer#<<" do + after(:each) do + @server.close if @server + @socket.close if @socket + end +end diff --git a/1.8/library/socket/tcpserver/readpartial_spec.rb b/1.8/library/socket/tcpserver/readpartial_spec.rb new file mode 100644 index 0000000000..329ef093aa --- /dev/null +++ b/1.8/library/socket/tcpserver/readpartial_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "TCPServer#readpartial" do + after(:each) do + @server.close if @server + @socket.close if @socket + end +end diff --git a/1.8/library/socket/tcpserver/sysaccept_spec.rb b/1.8/library/socket/tcpserver/sysaccept_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/tcpserver/sysaccept_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/tcpsocket/gethostbyname_spec.rb b/1.8/library/socket/tcpsocket/gethostbyname_spec.rb new file mode 100644 index 0000000000..44124e0c9d --- /dev/null +++ b/1.8/library/socket/tcpsocket/gethostbyname_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "TCPSocket#gethostbyname" do + it "should resolve a hostname to an address" do + a = TCPSocket.gethostbyname("localhost") + # on some platforms (Mac), MRI + # returns comma at the end. + a.first.should =~ /^localhost,?$/ + end +end diff --git a/1.8/library/socket/tcpsocket/new_spec.rb b/1.8/library/socket/tcpsocket/new_spec.rb new file mode 100644 index 0000000000..9f6436c11a --- /dev/null +++ b/1.8/library/socket/tcpsocket/new_spec.rb @@ -0,0 +1,45 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "TCPSocket.new" do + before :each do + @hostname = Socket.getaddrinfo("127.0.0.1", nil)[0][2] + end + it "requires a hostname and a port as arguments" do + lambda { TCPSocket.new }.should raise_error(ArgumentError) + end + + it "refuses the connection when there is no server to connect to" do + lambda { TCPSocket.new('127.0.0.1', SocketSpecs.port) }.should raise_error(Errno::ECONNREFUSED) + end + + it "connects to a listening server" do + thread = Thread.new do + server = TCPServer.new(SocketSpecs.port) + server.accept + server.close + end + Thread.pass until thread.status == 'sleep' + lambda { TCPSocket.new(@hostname, SocketSpecs.port) }.should_not raise_error(Errno::ECONNREFUSED) + thread.join + end + + it "has an address once it has connected to a listening server" do + thread = Thread.new do + server = TCPServer.new('127.0.0.1', SocketSpecs.port) + server.accept + server.close + end + Thread.pass until thread.status == 'sleep' + sock = TCPSocket.new('127.0.0.1', SocketSpecs.port) + sock.addr[0].should == "AF_INET" + sock.addr[1].should be_kind_of Fixnum + # on some platforms (Mac), MRI + # returns comma at the end. Other + # platforms such as OpenBSD setup the + # localhost as localhost.domain.com + sock.addr[2].should =~ /^#{@hostname}/ + sock.addr[3].should == "127.0.0.1" + thread.join + end +end diff --git a/1.8/library/socket/udpsocket/bind_spec.rb b/1.8/library/socket/udpsocket/bind_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/udpsocket/bind_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/udpsocket/connect_spec.rb b/1.8/library/socket/udpsocket/connect_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/udpsocket/connect_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/udpsocket/new_spec.rb b/1.8/library/socket/udpsocket/new_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/udpsocket/new_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/udpsocket/open_spec.rb b/1.8/library/socket/udpsocket/open_spec.rb new file mode 100644 index 0000000000..fa9ac9f622 --- /dev/null +++ b/1.8/library/socket/udpsocket/open_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "UDPSocket.open" do + after(:each) do + @socket.close if @socket && !@socket.closed? + @server.close if @server && !@server.closed? + end + + it "allows calls to open without arguments" do + @socket = UDPSocket.open + end +end diff --git a/1.8/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/1.8/library/socket/udpsocket/recvfrom_nonblock_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/udpsocket/recvfrom_nonblock_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/udpsocket/send_spec.rb b/1.8/library/socket/udpsocket/send_spec.rb new file mode 100644 index 0000000000..6794674fb3 --- /dev/null +++ b/1.8/library/socket/udpsocket/send_spec.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' + +describe "UDPSocket.send" do + before :each do + @ready = false + @server_thread = Thread.new do + @server = UDPSocket.open + @server.bind(nil, SocketSpecs.port) + @ready = true + @msg = @server.recvfrom(64) + @server.close + end + Thread.pass while @server_thread.status and !@ready + end + + it "sends data in ad hoc mode" do + @socket = UDPSocket.open + @socket.send("ad hoc", 0, 'localhost',SocketSpecs.port) + @socket.close + @server_thread.join + + @msg[0].should == "ad hoc" + @msg[1][0].should == "AF_INET" + @msg[1][1].should be_kind_of(Fixnum) + @msg[1][3].should == "127.0.0.1" + end + + it "sends data in connection mode" do + @socket = UDPSocket.open + @socket.connect('localhost',SocketSpecs.port) + @socket.send("connection-based", 0) + @socket.close + @server_thread.join + + @msg[0].should == "connection-based" + @msg[1][0].should == "AF_INET" + @msg[1][1].should be_kind_of(Fixnum) + @msg[1][3].should == "127.0.0.1" + end +end diff --git a/1.8/library/socket/unixserver/accept_nonblock_spec.rb b/1.8/library/socket/unixserver/accept_nonblock_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/unixserver/accept_nonblock_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/unixserver/accept_spec.rb b/1.8/library/socket/unixserver/accept_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/unixserver/accept_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/unixserver/listen_spec.rb b/1.8/library/socket/unixserver/listen_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/unixserver/listen_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/unixserver/new_spec.rb b/1.8/library/socket/unixserver/new_spec.rb new file mode 100644 index 0000000000..2662da6f6b --- /dev/null +++ b/1.8/library/socket/unixserver/new_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' +require 'tempfile' + +describe UNIXServer do + it "#new should create a new UNIXServer" do + temp = Tempfile.new 'unixserver_spec' + path = temp.path.dup + temp.unlink + unix = UNIXServer.new(path) + unix.path.should == path + unix.addr.should == ["AF_UNIX", path] + lambda {unix.peeraddr}.should raise_error(Errno::ENOTCONN) + end +end diff --git a/1.8/library/socket/unixserver/sysaccept_spec.rb b/1.8/library/socket/unixserver/sysaccept_spec.rb new file mode 100644 index 0000000000..63bcd9ba05 --- /dev/null +++ b/1.8/library/socket/unixserver/sysaccept_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require File.dirname(__FILE__) + '/../fixtures/classes' diff --git a/1.8/library/socket/unpack_sockaddr_in_spec.rb b/1.8/library/socket/unpack_sockaddr_in_spec.rb new file mode 100644 index 0000000000..8d8828b89a --- /dev/null +++ b/1.8/library/socket/unpack_sockaddr_in_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'socket' + +describe "Socket#unpack_sockaddr_in" do + + it "decodes the host name and port number of a packed sockaddr_in" do + sockaddr = Socket.sockaddr_in 80, '127.0.0.1' + Socket.unpack_sockaddr_in(sockaddr).should == [80, '127.0.0.1'] + end + + it "raises an ArgumentError when the sin_family is not AF_INET" do + sockaddr = Socket.sockaddr_un '/tmp/x' + + lambda { Socket.unpack_sockaddr_in sockaddr }.should raise_error(ArgumentError) + end + +end diff --git a/1.8/library/socket/unpack_sockaddr_un_spec.rb b/1.8/library/socket/unpack_sockaddr_un_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/socket/unpack_sockaddr_un_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/socket/write_spec.rb b/1.8/library/socket/write_spec.rb new file mode 100644 index 0000000000..7e87d91364 --- /dev/null +++ b/1.8/library/socket/write_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "TCPServer#write" do + after(:each) do + @server.close if @server + @socket.close if @socket + end +end diff --git a/1.8/library/stringio/append_spec.rb b/1.8/library/stringio/append_spec.rb new file mode 100644 index 0000000000..55cf873c43 --- /dev/null +++ b/1.8/library/stringio/append_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#<<" do + it "appends to the string when in append mode" do + @io = StringIO.new("example", 'a') + (@io << "x").should == @io + @io.string.should == "examplex" + end + + it "writes to the string when in default mode" do + @io = StringIO.new("example") + (@io << "x").should == @io + @io.string.should == "xxample" + end +end diff --git a/1.8/library/stringio/binmode_spec.rb b/1.8/library/stringio/binmode_spec.rb new file mode 100644 index 0000000000..5477a63dbf --- /dev/null +++ b/1.8/library/stringio/binmode_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#binmode" do + it "returns the IO object" do + @io = StringIO.new("example") + @io.binmode.should == @io + end +end diff --git a/1.8/library/stringio/close_read_spec.rb b/1.8/library/stringio/close_read_spec.rb new file mode 100644 index 0000000000..91dd281104 --- /dev/null +++ b/1.8/library/stringio/close_read_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#close_read" do + before(:each) do + @io = StringIO.new("example") + @io.close_read + end + + it "prevents further reading" do + @io.closed_read?.should == true + @io.closed_write?.should == false + lambda { @io.read(1) }.should raise_error(IOError) + end + + it "allows further writing" do + @io.write("x").should == 1 + end +end diff --git a/1.8/library/stringio/close_spec.rb b/1.8/library/stringio/close_spec.rb new file mode 100644 index 0000000000..52e4ba31b7 --- /dev/null +++ b/1.8/library/stringio/close_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#close" do + before(:each) do + @io = StringIOSpecs.build + end + it "prevents further operations" do + @io.close.should == nil + @io.closed?.should == true + @io.closed_read?.should == true + @io.closed_write?.should == true + lambda { @io << 'x' }.should raise_error(IOError) + end +end diff --git a/1.8/library/stringio/close_write_spec.rb b/1.8/library/stringio/close_write_spec.rb new file mode 100644 index 0000000000..72171f6b7c --- /dev/null +++ b/1.8/library/stringio/close_write_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#close_write" do + before(:each) do + @io = StringIO.new("example") + @io.close_write + end + + it "prevents further writing" do + @io.closed_read?.should == false + @io.closed_write?.should == true + lambda { @io.write('x') }.should raise_error(IOError) + end + + it "allows further reading" do + @io.read(1).should == 'e' + end +end diff --git a/1.8/library/stringio/closed_read_spec.rb b/1.8/library/stringio/closed_read_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/stringio/closed_read_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/stringio/closed_spec.rb b/1.8/library/stringio/closed_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/stringio/closed_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/stringio/closed_write_spec.rb b/1.8/library/stringio/closed_write_spec.rb new file mode 100644 index 0000000000..f87b662e05 --- /dev/null +++ b/1.8/library/stringio/closed_write_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' diff --git a/1.8/library/stringio/each_byte_spec.rb b/1.8/library/stringio/each_byte_spec.rb new file mode 100644 index 0000000000..39c996a2e0 --- /dev/null +++ b/1.8/library/stringio/each_byte_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#each_byte" do + before(:each) do + @io = StringIO.new("xyz") + end + + it "yields each character code in turn" do + seen = [] + @io.each_byte {|b| seen << b}.should == nil + seen.should == [120, 121, 122] + end + + it "raises an IOError unless the IO is open for reading" do + @io.close_read + lambda { @io.each_byte {|b| b } }.should raise_error(IOError) + end +end diff --git a/1.8/library/stringio/each_line_spec.rb b/1.8/library/stringio/each_line_spec.rb new file mode 100644 index 0000000000..46a176f026 --- /dev/null +++ b/1.8/library/stringio/each_line_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/each' + +describe "StringIO#each_line" do + it_behaves_like :stringio_each, :each_line +end diff --git a/1.8/library/stringio/each_spec.rb b/1.8/library/stringio/each_spec.rb new file mode 100644 index 0000000000..c921d795a3 --- /dev/null +++ b/1.8/library/stringio/each_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/each' + +describe "StringIO#each_line" do + it_behaves_like :stringio_each, :each +end diff --git a/1.8/library/stringio/eof_spec.rb b/1.8/library/stringio/eof_spec.rb new file mode 100644 index 0000000000..56356289d6 --- /dev/null +++ b/1.8/library/stringio/eof_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/eof' + +describe "StringIO#eof?" do + it_behaves_like :stringio_eof, :eof? +end + +describe "StringIO#eof" do + it_behaves_like :stringio_eof, :eof +end diff --git a/1.8/library/stringio/fcntl_spec.rb b/1.8/library/stringio/fcntl_spec.rb new file mode 100644 index 0000000000..d1755616f4 --- /dev/null +++ b/1.8/library/stringio/fcntl_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#fcntl" do + it "raises a NotImplementedError" do + @io = StringIO.new("boom") + lambda { @io.fcntl }.should raise_error(NotImplementedError) + end +end diff --git a/1.8/library/stringio/fileno_spec.rb b/1.8/library/stringio/fileno_spec.rb new file mode 100644 index 0000000000..39404f1277 --- /dev/null +++ b/1.8/library/stringio/fileno_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#fileno" do + it "is nil" do + @io = StringIO.new("nuffin") + @io.fileno.should == nil + end +end diff --git a/1.8/library/stringio/fixtures/classes.rb b/1.8/library/stringio/fixtures/classes.rb new file mode 100644 index 0000000000..bb8dc354cc --- /dev/null +++ b/1.8/library/stringio/fixtures/classes.rb @@ -0,0 +1,15 @@ +require 'stringio' + +class StringSubclass < String; end + +module StringIOSpecs + def self.build + str = <<-EOS + each + peach + pear + plum + EOS + StringIO.new(str) + end +end diff --git a/1.8/library/stringio/flush_spec.rb b/1.8/library/stringio/flush_spec.rb new file mode 100644 index 0000000000..184af25ec8 --- /dev/null +++ b/1.8/library/stringio/flush_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#flush" do + it "returns itself" do + @io = StringIO.new("flush") + @io.flush.should == @io + end +end diff --git a/1.8/library/stringio/fsync_spec.rb b/1.8/library/stringio/fsync_spec.rb new file mode 100644 index 0000000000..5a520c3152 --- /dev/null +++ b/1.8/library/stringio/fsync_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#fsync" do + it "returns zero" do + @io = StringIO.new("fsync") + @io.fsync.should == 0 + end +end diff --git a/1.8/library/stringio/getc_spec.rb b/1.8/library/stringio/getc_spec.rb new file mode 100644 index 0000000000..9b820675d5 --- /dev/null +++ b/1.8/library/stringio/getc_spec.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#getc" do + before(:each) do + @io = StringIO.new("getc") + end + + it "returns the next character code" do + @io.getc.should == ?g + @io.getc.should == ?e + @io.getc.should == ?t + @io.getc.should == ?c + @io.getc.should == nil + @io.getc.should == nil + end +end diff --git a/1.8/library/stringio/gets_spec.rb b/1.8/library/stringio/gets_spec.rb new file mode 100644 index 0000000000..9df4d8b8ae --- /dev/null +++ b/1.8/library/stringio/gets_spec.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#gets" do + before(:each) do + @io = StringIO.new("g e t s") + end + + after(:each) do + $/ = "\n" + end + + it "returns the next 'line'" do + @io.gets.should == 'g e t s' + @io.gets.should == nil + end + + it "raises an IOError when it is not open for reading" do + @io.close_read + lambda { @io.gets }.should raise_error(IOError) + end + + it "supports separator strings" do + @io.gets('e').should == 'g e' + @io.gets('e').should == ' t s' + end + + it "honors the $/ global separator" do + $/ = ' ' + @io.gets.should == 'g ' + @io.gets.should == 'e ' + @io.gets.should == 't ' + @io.gets.should == 's' + end +end diff --git a/1.8/library/stringio/isatty_spec.rb b/1.8/library/stringio/isatty_spec.rb new file mode 100644 index 0000000000..8a067f0094 --- /dev/null +++ b/1.8/library/stringio/isatty_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/isatty' + +describe "StringIO#tty?" do + it_behaves_like :stringio_isatty, :isatty +end diff --git a/1.8/library/stringio/length_spec.rb b/1.8/library/stringio/length_spec.rb new file mode 100644 index 0000000000..733f75a3bc --- /dev/null +++ b/1.8/library/stringio/length_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/length' + +describe "StringIO#length" do + it_behaves_like :stringio_length, :length +end diff --git a/1.8/library/stringio/lineno_spec.rb b/1.8/library/stringio/lineno_spec.rb new file mode 100644 index 0000000000..83d7f0dbb8 --- /dev/null +++ b/1.8/library/stringio/lineno_spec.rb @@ -0,0 +1,45 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#lineno" do + before(:each) do + @io = StringIOSpecs.build + end + + it "only counts lines that have been read 'line-wise'" do + @io.read(@io.size) + @io.lineno.should == 0 + end + + it "matches the newline count after each_line" do + @io.each_line {|l| l } + @io.lineno.should == 4 + end + + it "matches the number of 'lines' read, even if they are not lines" do + @io.gets('a') + @io.gets('c') + @io.gets('h') + 6.times { @io.gets } + @io.lineno.should == 7 + end + + it "updates the line number after readline, as well as gets" do + @io.readline + @io.readline + @io.readline + @io.lineno.should == 3 + end +end + +describe "StringIO#lineno=" do + before(:each) do + @io = StringIOSpecs.build + end + + it "updates the current line number but not advance the position" do + @io.lineno = 2 + @io.gets.should == " each\n" + @io.lineno.should == 3 + end +end diff --git a/1.8/library/stringio/new_spec.rb b/1.8/library/stringio/new_spec.rb new file mode 100644 index 0000000000..81ea9e873c --- /dev/null +++ b/1.8/library/stringio/new_spec.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO.new" do + it "contains an empty string if no argument is provided" do + StringIO.new.string.should == "" + end + + it "calls to_str on the first argument if it is not a String" do + obj = mock('hello') + def obj.to_str; "hello"; end + io = StringIO.new(obj) + io.string.should == "hello" + end + + it "raises a TypeError if the argument cannot be converted" do + obj = mock('x') + lambda { StringIO.new(obj) }.should raise_error(TypeError) + end + + it "initializes in read-only mode when given a 'read' mode flag" do + io = StringIO.new('hi', 'r') + io.closed_write?.should == true + io.closed_read?.should == false + io = StringIO.new('bye', 'rb') + io.closed_write?.should == true + io.closed_read?.should == false + lambda { io.write('!') }.should raise_error(IOError) + end + + it "does not call to_str on String subclasses" do + str = StringSubclass.new('keep') + io = StringIO.new(str) + io.string.class.should == StringSubclass + io.write('!') + io.string.class.should == StringSubclass + end +end diff --git a/1.8/library/stringio/open_spec.rb b/1.8/library/stringio/open_spec.rb new file mode 100644 index 0000000000..00ee863d27 --- /dev/null +++ b/1.8/library/stringio/open_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO.open" do + it "contains an empty string if no argument is provided" do + StringIO.open.string.should == "" + end + + it "yields the IO object to the block" do + sio = nil + StringIO.open("abc") do |io| + io.string.should == 'abc' + io.read(2).should == 'ab' + io.closed?.should == false + sio = io + end + sio.closed?.should == true + end + + it "calls to_str on the first argument if it is not a String" do + obj = mock('hello') + def obj.to_str; "hello"; end + StringIO.open(obj) do |io| + io.string.should == "hello" + end + end + + it "raises a TypeError if the argument cannot be converted" do + obj = mock('x') + lambda { StringIO.open(obj) }.should raise_error(TypeError) + end +end diff --git a/1.8/library/stringio/path_spec.rb b/1.8/library/stringio/path_spec.rb new file mode 100644 index 0000000000..7fb8b2f50d --- /dev/null +++ b/1.8/library/stringio/path_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#path" do + it "returns nil" do + StringIO.new("path").path.should == nil + end +end diff --git a/1.8/library/stringio/pid_spec.rb b/1.8/library/stringio/pid_spec.rb new file mode 100644 index 0000000000..36c4178807 --- /dev/null +++ b/1.8/library/stringio/pid_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#pid" do + it "returns nil" do + StringIO.new("pid").pid.should == nil + end +end diff --git a/1.8/library/stringio/pos_spec.rb b/1.8/library/stringio/pos_spec.rb new file mode 100644 index 0000000000..9f1edf844b --- /dev/null +++ b/1.8/library/stringio/pos_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/tell' + +describe "StringIO#pos" do + it_behaves_like :stringio_tell, :pos +end + +describe "StringIO#pos=" do + before(:each) do + @io = StringIOSpecs.build + end + + it "updates the current byte offset" do + @io.pos = 26 + @io.read(1).should == "r" + end + + it "raises an EINVAL if given a negative argument" do + lambda { @io.pos = -10 }.should raise_error(Errno::EINVAL) + end +end diff --git a/1.8/library/stringio/print_spec.rb b/1.8/library/stringio/print_spec.rb new file mode 100644 index 0000000000..6dc096a15f --- /dev/null +++ b/1.8/library/stringio/print_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#print" do + before(:each) do + @io = StringIO.new('') + end + after(:each) do + $\ = nil + end + + it "prints multiple items to the output" do + @io.print(5,6,7,8).should == nil + @io.string.should == '5678' + end + + it "honors the output record separator global" do + $\ = 'x' + @io.print(5,6,7,8).should == nil + @io.string.should == '5678x' + end +end diff --git a/1.8/library/stringio/printf_spec.rb b/1.8/library/stringio/printf_spec.rb new file mode 100644 index 0000000000..75f6a278fb --- /dev/null +++ b/1.8/library/stringio/printf_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#printf" do + before(:each) do + @io = StringIO.new('') + end + + it "performs format conversion" do + @io.printf("%d %04x", 123, 123).should == nil + @io.string.should == "123 007b" + end +end diff --git a/1.8/library/stringio/putc_spec.rb b/1.8/library/stringio/putc_spec.rb new file mode 100644 index 0000000000..fa5eaa60c3 --- /dev/null +++ b/1.8/library/stringio/putc_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#putc" do + before(:each) do + @io = StringIO.new('') + end + + it "handles characters and character codes" do + @io.pos.should == 0 + + @io.putc(65).should == 65 + @io.pos.should == 1 + + @io.putc('B').should == 'B' + @io.pos.should == 2 + + @io.putc('CD').should == 'CD' + @io.pos.should == 3 + + @io.string.should == 'ABC' + end +end diff --git a/1.8/library/stringio/puts_spec.rb b/1.8/library/stringio/puts_spec.rb new file mode 100644 index 0000000000..6bce2819a9 --- /dev/null +++ b/1.8/library/stringio/puts_spec.rb @@ -0,0 +1,63 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#puts" do + before(:each) do + @io = StringIO.new('') + end + + after(:each) do + $/ = "\n" + end + + it "writes a newline after objects that do not end in newlines" do + @io.puts(5).should == nil + @io.string.should == "5\n" + end + + it "does not write a newline after objects that end in newlines" do + @io.puts("5\n").should == nil + @io.string.should == "5\n" + end + + it "calls to_s before writing non-string objects" do + object = mock('hola') + object.should_receive(:to_s).and_return("hola") + + @io.puts(object).should == nil + @io.string.should == "hola\n" + end + + it "writes each arg if given several" do + @io.puts(1, "two", 3).should == nil + @io.string.should == "1\ntwo\n3\n" + end + + it "flattens a nested array before writing it" do + @io.puts([1, 2, [3, [4, [5]]]]).should == nil + @io.string.should == "1\n2\n3\n4\n5\n" + end + + it "writes [...] for a recursive array arg" do + x = [] + x << 2 << x + @io.puts(x).should == nil + @io.string.should == "2\n[...]\n" + end + + it "writes a newline after objects that do not end in newlines" do + @io.puts(5).should == nil + @io.string.should == "5\n" + end + + it "does not write a newline after objects that end in newlines" do + @io.puts("5\n").should == nil + @io.string.should == "5\n" + end + + it "ignores the $/ separator global" do + $/ = ":" + @io.puts(5,6) + @io.string.should == "5\n6\n" + end +end diff --git a/1.8/library/stringio/read_spec.rb b/1.8/library/stringio/read_spec.rb new file mode 100644 index 0000000000..f5ca442cd8 --- /dev/null +++ b/1.8/library/stringio/read_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#read" do + before(:each) do + @io = StringIOSpecs.build + end + + it "reads at most 'length' bytes" do + @io.read(666).should == @io.string + end + + it "reads to the end of the string if length is omitted" do + @io.read.should == @io.string + @io.read.should == "" + @io.read(nil).should == "" + @io.read(50).should == nil + end + + it "only supports String buffers" do + lambda { @io.read(5, []) }.should raise_error(TypeError) + @io.pos.should == 0 + end + + it "reads data into a buffer string if provided" do + @io = StringIO.new('buffered') + buf = "" + @io.read(5, buf).object_id.should == buf.object_id + buf.should == "buffe" + @io.read(1, buf) + buf.should == 'r' + end +end diff --git a/1.8/library/stringio/readchar_spec.rb b/1.8/library/stringio/readchar_spec.rb new file mode 100644 index 0000000000..1e548b1c43 --- /dev/null +++ b/1.8/library/stringio/readchar_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#readchar" do + before(:each) do + @io = StringIO.new('abc') + end + + it "returns character codes one at a time" do + @io.readchar.should == ?a + @io.readchar.should == ?b + @io.readchar.should == ?c + end + + it "raises an EOFError at the end of the string" do + 3.times { @io.readchar } + lambda { @io.readchar }.should raise_error(EOFError) + end +end diff --git a/1.8/library/stringio/readline_spec.rb b/1.8/library/stringio/readline_spec.rb new file mode 100644 index 0000000000..c547105060 --- /dev/null +++ b/1.8/library/stringio/readline_spec.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#readline" do + before(:each) do + @io = StringIO.new("r e a d") + end + + it "returns the next 'line'" do + @io.readline.should == 'r e a d' + end + + it "raises an EOFError at the end" do + @io.readline + lambda { @io.readline }.should raise_error(EOFError) + end + + it "raises an IOError when it is not open for reading" do + @io.close_read + lambda { @io.readline }.should raise_error(IOError) + end + + it "support separator strings" do + @io.gets('e').should == 'r e' + @io.gets('e').should == ' a d' + end +end diff --git a/1.8/library/stringio/readlines_spec.rb b/1.8/library/stringio/readlines_spec.rb new file mode 100644 index 0000000000..21776138aa --- /dev/null +++ b/1.8/library/stringio/readlines_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#readlines" do + before(:each) do + @io = StringIO.new("line1\nline2\nline3\n") + end + + it "returns an array of lines" do + @io.readlines.should == ["line1\n", "line2\n", "line3\n"] + end + + it "raises an IOError when it is not open for reading" do + @io.close_read + lambda { @io.readlines }.should raise_error(IOError) + end + + it "returns the rest of the stream when separator is nil" do + @io.read(4) + @io.readlines(nil).should == ["1\nline2\nline3\n"] + end + + it "optionally accepts a separator string" do + @io.readlines('line').should == ["line", "1\nline", "2\nline", "3\n"] + end +end diff --git a/1.8/library/stringio/reopen_spec.rb b/1.8/library/stringio/reopen_spec.rb new file mode 100644 index 0000000000..8769bc02db --- /dev/null +++ b/1.8/library/stringio/reopen_spec.rb @@ -0,0 +1,78 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +# NOTE: Some reopen specs disabled due to MRI bugs. See: +# http://rubyforge.org/tracker/index.php?func=detail&aid=13919&group_id=426&atid=1698 +# for details. +describe "StringIO#reopen" do + before(:each) do + @io = StringIO.new('hello','a') + end + + # TODO: find out if this is really a bug + ruby_bug do + it "reopens a stream when given a String argument" do + @io.reopen('goodbye').should == @io + @io.string.should == 'goodbye' + @io << 'x' + @io.string.should == 'xoodbye' + end + + it "reopens a stream in append mode when flagged as such" do + @io.reopen('goodbye', 'a').should == @io + @io.string.should == 'goodbye' + @io << 'x' + @io.string.should == 'goodbyex' + end + + it "reopens and truncate when reopened in write mode" do + @io.reopen('goodbye', 'wb').should == @io + @io.string.should == '' + @io << 'x' + @io.string.should == 'x' + end + + it "truncates the given string, not a copy" do + str = 'goodbye' + @io.reopen(str, 'w') + @io.string.should == '' + str.should == '' + end + end + + compliant_on :ruby, :jruby do + it "denies access to prevent truncation of a frozen string" do + @io = StringIO.new("ice") + lambda { @io.reopen("burn".freeze, 'w') }.should raise_error(Errno::EACCES) + lambda { @io.reopen("burn".freeze, 'a') }.should raise_error(Errno::EACCES) + end + + it "does not raise IOError if a frozen string is passed in read mode" do + @io.reopen("burn".freeze, 'r') + @io.string.should == "burn" + end + end + + # MRI refuses to convert objects that support to_str, JRuby and Rubinius can + deviates_on(:jruby, :rubinius) do + it "calls to_str on the first argument if it is not a String" do + obj = mock('reopen') + def obj.to_str; "reopen"; end + @io.reopen(obj) + @io.string.should == "reopen" + end + end + + it "raises a TypeError if the argument cannot be converted" do + obj = mock('x') + lambda { @io.reopen(obj) }.should raise_error(TypeError) + end + + it "reopens a stream when given a new StringIO object" do + @io.close + nio = StringIO.new('goodbye') + @io.reopen(nio) + @io.closed?.should == false + @io.string.should == 'goodbye' + end +end diff --git a/1.8/library/stringio/rewind_spec.rb b/1.8/library/stringio/rewind_spec.rb new file mode 100644 index 0000000000..6d8542773a --- /dev/null +++ b/1.8/library/stringio/rewind_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#rewind" do + before(:each) do + @io = StringIO.new("hello\nworld") + end + + it "resets the position" do + @io.gets + @io.pos.should == 6 + @io.rewind + @io.pos.should == 0 + end + + it "resets the line number" do + @io.gets + @io.lineno.should == 1 + @io.rewind + @io.lineno.should == 0 + end + + it "should make the contents of the stream accessible again when stream was read beyond its end" do + str = @io.string + + @io.read(@io.string.length + 1).should == str + @io.rewind + @io.read(@io.string.length + 1).should == str + end +end diff --git a/1.8/library/stringio/seek_spec.rb b/1.8/library/stringio/seek_spec.rb new file mode 100644 index 0000000000..210f92d3e9 --- /dev/null +++ b/1.8/library/stringio/seek_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#seek" do + before(:each) do + @io = StringIO.new("12345678") + end + + it "seeks to an absolute position" do + @io.seek(5).should == 0 + @io.read(1).should == '6' + end + + it "seeks from the current position" do + @io.read(1) + @io.seek(1, IO::SEEK_CUR) + @io.read(1).should == '3' + end + + it "seeks from the end of the IO" do + @io.seek(1, IO::SEEK_END) + @io.read(1).should == nil + @io.seek(-2, IO::SEEK_END) + @io.read(1).should == '7' + end + + it "can handle any numerical argument" do + @io.seek(1.2).should == 0 + @io.seek(@io.string.size * 2).should == 0 + @io.seek(1.23423423432e5).should == 0 + @io.seek(0.00000000000000000000001).should == 0 + lambda { @io.seek(2**128) }.should raise_error(RangeError, /bignum too big/) + end +end diff --git a/1.8/library/stringio/shared/each.rb b/1.8/library/stringio/shared/each.rb new file mode 100644 index 0000000000..a425ee97c8 --- /dev/null +++ b/1.8/library/stringio/shared/each.rb @@ -0,0 +1,19 @@ +shared :stringio_each do |cmd| + describe "StringIO##{cmd}" do + before(:each) do + @io = StringIO.new("a b c d e") + end + + it "yields each line by default" do + seen = [] + @io.send(cmd) {|s| seen << s}.should == @io + seen.should == ["a b c d e"] + end + + it "supports a separator argument" do + seen = [] + @io.send(cmd, ' ') {|s| seen << s}.should == @io + seen.should == ["a ", "b ", "c ", "d ", "e"] + end + end +end diff --git a/1.8/library/stringio/shared/eof.rb b/1.8/library/stringio/shared/eof.rb new file mode 100644 index 0000000000..023fd631af --- /dev/null +++ b/1.8/library/stringio/shared/eof.rb @@ -0,0 +1,42 @@ +shared :stringio_eof do |cmd| + describe "StringIO##{cmd}" do + before(:each) do + @io = StringIO.new("eof") + end + + it "is false for a new StringIO" do + @io.send(cmd).should == false + end + + it "is true once the IO has been read" do + @io.read(3) + @io.send(cmd).should == true + end + + it "is true after gets returns nil" do + @io.gets.should == 'eof' + @io.gets.should == nil + @io.send(cmd).should == true + end + + it "is true after seeking to the end" do + @io.seek(3) + @io.send(cmd).should == true + end + + it "is true after seeking beyond the end" do + @io.seek(5) + @io.send(cmd).should == true + end + + it "is true after setting the position to the end" do + @io.pos = 3 + @io.send(cmd).should == true + end + + it "is true after setting the position beyond the end" do + @io.pos = 5 + @io.send(cmd).should == true + end + end +end diff --git a/1.8/library/stringio/shared/isatty.rb b/1.8/library/stringio/shared/isatty.rb new file mode 100644 index 0000000000..fcf76f83e2 --- /dev/null +++ b/1.8/library/stringio/shared/isatty.rb @@ -0,0 +1,11 @@ +shared :stringio_isatty do |cmd| + describe "StringIO##{cmd}" do + before(:each) do + @io = StringIO.new('tty') + end + + it "is false" do + @io.send(cmd).should == false + end + end +end diff --git a/1.8/library/stringio/shared/length.rb b/1.8/library/stringio/shared/length.rb new file mode 100644 index 0000000000..829cbce20b --- /dev/null +++ b/1.8/library/stringio/shared/length.rb @@ -0,0 +1,11 @@ +shared :stringio_length do |cmd| + describe "StringIO##{cmd}" do + before(:each) do + @io = StringIOSpecs.build + end + + it "returns the length of the wrapped string" do + @io.send(cmd).should == 37 + end + end +end diff --git a/1.8/library/stringio/shared/tell.rb b/1.8/library/stringio/shared/tell.rb new file mode 100644 index 0000000000..ef1807a1e5 --- /dev/null +++ b/1.8/library/stringio/shared/tell.rb @@ -0,0 +1,14 @@ +shared :stringio_tell do |cmd| + describe "StringIO##{cmd}" do + before(:each) do + @io = StringIOSpecs.build + end + + it "returns the current byte offset" do + @io.getc + @io.send(cmd).should == 1 + @io.read(7) + @io.send(cmd).should == 8 + end + end +end diff --git a/1.8/library/stringio/shared/write.rb b/1.8/library/stringio/shared/write.rb new file mode 100644 index 0000000000..624aa35a09 --- /dev/null +++ b/1.8/library/stringio/shared/write.rb @@ -0,0 +1,30 @@ +shared :stringio_write do |cmd| + describe "StringIO##{cmd}" do + before(:each) do + @io = StringIO.new('12345') + end + + it "writes at the current buffer position" do + @io.read(2) + @io.send(cmd, 'x').should == 1 + @io.string.should == '12x45' + @io.send(cmd, 7).should == 1 + @io.string.should == '12x75' + end + + it "pads with null bytes if the position is after the end" do + @io.pos = 8 + @io.send(cmd, 'x') + @io.string.should == "12345\000\000\000x" + @io.send(cmd, 9) + @io.string.should == "12345\000\000\000x9" + end + + it "returns the number of bytes written" do + @io.send(cmd, '').should == 0 + @io.send(cmd, nil).should == 0 + str = "1" * 100 + @io.send(cmd, str).should == 100 + end + end +end diff --git a/1.8/library/stringio/size_spec.rb b/1.8/library/stringio/size_spec.rb new file mode 100644 index 0000000000..af9ae67c78 --- /dev/null +++ b/1.8/library/stringio/size_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/length' + +describe "StringIO#size" do + it_behaves_like :stringio_length, :size +end diff --git a/1.8/library/stringio/string_spec.rb b/1.8/library/stringio/string_spec.rb new file mode 100644 index 0000000000..5b602daf65 --- /dev/null +++ b/1.8/library/stringio/string_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#string" do + it "returns the underlying string" do + str = "hello" + @io = StringIO.new(str) + @io.string.should == str + @io.string.object_id.should == str.object_id + end +end + +describe "StringIO#string=" do + before(:each) do + @io = StringIO.new("example\nstring") + end + + it "changes the underlying string" do + str = "hello" + @io.string = str + @io.string.should == str + @io.string.object_id.should == str.object_id + end + + it "resets the position" do + @io.read(1) + @io.pos.should == 1 + @io.string = "other" + @io.pos.should == 0 + @io.read(1).should == 'o' + end + + it "resets the line number" do + @io.gets + @io.lineno.should == 1 + @io.string = "other" + @io.lineno.should == 0 + @io.gets.should == "other" + end +end diff --git a/1.8/library/stringio/sync_spec.rb b/1.8/library/stringio/sync_spec.rb new file mode 100644 index 0000000000..6c7c0712f2 --- /dev/null +++ b/1.8/library/stringio/sync_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#sync" do + before(:each) do + @io = StringIO.new('') + end + + it "is true" do + @io.sync.should == true + end +end + +describe "StringIO#sync=" do + before(:each) do + @io = StringIO.new('') + end + + it "does not change 'sync' status" do + @io.sync = false + @io.sync.should == true + end +end diff --git a/1.8/library/stringio/sysread_spec.rb b/1.8/library/stringio/sysread_spec.rb new file mode 100644 index 0000000000..2b98d17de3 --- /dev/null +++ b/1.8/library/stringio/sysread_spec.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#sysread" do + before(:each) do + @io = StringIOSpecs.build + end + + it "reads at most 'length' bytes" do + @io.sysread(666).should == @io.string + end + + it "reads to the end of the string if length is omitted" do + @io.sysread.should == @io.string + end + + it "raises an EOFError after the end of the string" do + @io.sysread + lambda { @io.sysread }.should raise_error(EOFError) + lambda { @io.sysread(5) }.should raise_error(EOFError) + end + + it "only supports String buffers" do + lambda { @io.sysread(5, []) }.should raise_error(TypeError) + @io.pos.should == 0 + end + + it "reads data into a buffer string if provided" do + @io = StringIO.new('buffered') + buf = "" + @io.sysread(5, buf).object_id.should == buf.object_id + buf.should == "buffe" + end +end diff --git a/1.8/library/stringio/syswrite_spec.rb b/1.8/library/stringio/syswrite_spec.rb new file mode 100644 index 0000000000..2e7d923259 --- /dev/null +++ b/1.8/library/stringio/syswrite_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/write' + +describe "StringIO#write" do + it_behaves_like :stringio_write, :syswrite +end diff --git a/1.8/library/stringio/tell_spec.rb b/1.8/library/stringio/tell_spec.rb new file mode 100644 index 0000000000..f3b35f4304 --- /dev/null +++ b/1.8/library/stringio/tell_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/tell' + +describe "StringIO#tell" do + it_behaves_like :stringio_tell, :tell +end diff --git a/1.8/library/stringio/truncate_spec.rb b/1.8/library/stringio/truncate_spec.rb new file mode 100644 index 0000000000..c5df4d1fb1 --- /dev/null +++ b/1.8/library/stringio/truncate_spec.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#truncate" do + before(:each) do + @io = StringIO.new('123456789') + end + + # TODO - ri error - says truncate always returns 0 + it "truncates the underlying string" do + @io.truncate(4).should == 4 + @io.string.should == '1234' + end + + it "does not update the position" do + @io.read(5) + @io.truncate(3) + @io.pos.should == 5 + end +end diff --git a/1.8/library/stringio/tty_spec.rb b/1.8/library/stringio/tty_spec.rb new file mode 100644 index 0000000000..6a75d561a0 --- /dev/null +++ b/1.8/library/stringio/tty_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/isatty' + +describe "StringIO#tty?" do + it_behaves_like :stringio_isatty, :tty? +end diff --git a/1.8/library/stringio/ungetc_spec.rb b/1.8/library/stringio/ungetc_spec.rb new file mode 100644 index 0000000000..598a7ce5d7 --- /dev/null +++ b/1.8/library/stringio/ungetc_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' + +describe "StringIO#ungetc" do + before(:each) do + @io = StringIO.new('1234') + end + + it "writes a character before the current position" do + @io.read(1) + @io.ungetc(65) + @io.string.should == 'A234' + end + + it "rewinds the current position by one" do + @io.read(2) + @io.pos.should == 2 + @io.ungetc(65) + @io.pos.should == 1 + end + + it "does nothing when pos == 0" do + @io.ungetc(65) + @io.string.should == '1234' + end + + it "does not accept strings" do + lambda { @io.ungetc('A') }.should raise_error(TypeError) + end +end diff --git a/1.8/library/stringio/write_spec.rb b/1.8/library/stringio/write_spec.rb new file mode 100644 index 0000000000..1fc6503c90 --- /dev/null +++ b/1.8/library/stringio/write_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/classes' +require File.dirname(__FILE__) + '/shared/write' + +describe "StringIO#write" do + it_behaves_like :stringio_write, :write +end diff --git a/1.8/library/syslog/constants_spec.rb b/1.8/library/syslog/constants_spec.rb new file mode 100755 index 0000000000..6817bfbdb0 --- /dev/null +++ b/1.8/library/syslog/constants_spec.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Syslog::Constants" do + before :all do + require 'syslog' + end + + it 'should be included' do + Syslog::Constants::LOG_USER.should == Syslog::LOG_USER + Syslog::Constants::LOG_EMERG.should == Syslog::LOG_EMERG + Syslog::Constants::LOG_CRIT.should == Syslog::LOG_CRIT + Syslog::Constants::LOG_ERR.should == Syslog::LOG_ERR + Syslog::Constants::LOG_MAIL.should == Syslog::LOG_MAIL + Syslog::Constants::LOG_WARNING.should == Syslog::LOG_WARNING + end +end \ No newline at end of file diff --git a/1.8/library/syslog/open_close_spec.rb b/1.8/library/syslog/open_close_spec.rb new file mode 100755 index 0000000000..2389b83109 --- /dev/null +++ b/1.8/library/syslog/open_close_spec.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Syslog::open" do + before :all do + require 'syslog' + end + + it 'should return Syslog' do + Syslog.open.should == Syslog + Syslog.close # Closing the log + Syslog.open("Rubinius").should == Syslog + Syslog.close # Closing the log + Syslog.open("Rubinius", 5, 9).should == Syslog + Syslog.close + end + + it 'should be able to take a block' do + Syslog.open {|s| s.should == Syslog } + Syslog.open("Rubinius") {|s| s.should == Syslog } + Syslog.open("r", 5, 10) {|s| s.should == Syslog } + lambda { Syslog.open; Syslog.close }.should_not raise_error + end + + it 'should raise an error if the log is opened' do + Syslog.open + lambda { Syslog.open }.should raise_error + lambda { Syslog.close; Syslog.open }.should_not raise_error + Syslog.close # So we can do more tests! + end +end \ No newline at end of file diff --git a/1.8/library/syslog/vars_spec.rb b/1.8/library/syslog/vars_spec.rb new file mode 100755 index 0000000000..e1c13b4e2b --- /dev/null +++ b/1.8/library/syslog/vars_spec.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../../spec_helper' + +describe "Syslog::ident" do + before :all do + require 'syslog' + end + + it 'should return the value of the last ident passed to open' do + Syslog.open {|s| s.ident.should == $0 } + Syslog.open("Rubinius") {|s| s.ident.should == "Rubinius" } + Syslog.open("4") {|s| s.ident.should == "4" } + Syslog.open("google") {|s| s.ident.should == "google" } + Syslog.open("I should do my homework") {|s| s.ident.should == "I should do my homework" } + end +end + +describe "Syslog::options" do + before :all do + require 'syslog' + end + + it 'should default to (LOG_PID | LOG_CONS)' do + Syslog.open {|s| s.options.should == (Syslog::LOG_PID | Syslog::LOG_CONS) } + end + + it 'should return the value of the last "option" passed to open' do + Syslog.open("Rubinius", 90) {|s| s.options.should == 90 } + Syslog.open("Rubinius", 5) {|s| s.options.should == 5 } + end +end + +describe "Syslog::facility" do + before :all do + require 'syslog' + end + + it 'should default to LOG_USER' do + Syslog.open {|s| s.facility.should == Syslog::LOG_USER } + end + + it 'should return the value of the last "facility" passed to open' do + Syslog.open("Rubinius", 5, 10) {|s| s.facility.should == 10 } + Syslog.open("monkey", 99, 1) {|s| s.facility.should == 1 } + end +end + +describe "Syslog::mask" do + before :all do + require 'syslog' + end + + # TODO - This spec doesn't really check much. Figure out how to check the + # real mask value set in the OS for this syslog + it 'should default to 255' do + Syslog.open { |s| s.mask.should == 255 } + end +end diff --git a/1.8/library/time/httpdate_spec.rb b/1.8/library/time/httpdate_spec.rb new file mode 100644 index 0000000000..aa7bceeaa0 --- /dev/null +++ b/1.8/library/time/httpdate_spec.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'time' + +describe "Time.httpdate" do + it "parses RFC-2616 strings" do + t = Time.utc(1994, 11, 6, 8, 49, 37) + t.should == Time.httpdate("Sun, 06 Nov 1994 08:49:37 GMT") + + # relies on Time.parse (not yet implemented) + # t.should == Time.httpdate("Sunday, 06-Nov-94 08:49:37 GMT") + + t.should == Time.httpdate("Sun Nov 6 08:49:37 1994") + Time.utc(1995, 11, 15, 6, 25, 24).should == Time.httpdate("Wed, 15 Nov 1995 06:25:24 GMT") + Time.utc(1995, 11, 15, 4, 58, 8).should == Time.httpdate("Wed, 15 Nov 1995 04:58:08 GMT") + Time.utc(1994, 11, 15, 8, 12, 31).should == Time.httpdate("Tue, 15 Nov 1994 08:12:31 GMT") + Time.utc(1994, 12, 1, 16, 0, 0).should == Time.httpdate("Thu, 01 Dec 1994 16:00:00 GMT") + Time.utc(1994, 10, 29, 19, 43, 31).should == Time.httpdate("Sat, 29 Oct 1994 19:43:31 GMT") + Time.utc(1994, 11, 15, 12, 45, 26).should == Time.httpdate("Tue, 15 Nov 1994 12:45:26 GMT") + Time.utc(1999, 12, 31, 23, 59, 59).should == Time.httpdate("Fri, 31 Dec 1999 23:59:59 GMT") + end +end diff --git a/1.8/library/time/iso8601_spec.rb b/1.8/library/time/iso8601_spec.rb new file mode 100644 index 0000000000..af9447292e --- /dev/null +++ b/1.8/library/time/iso8601_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/xmlschema' +require 'time' + +describe "Time.xmlschema" do + it_behaves_like :time_xmlschema, :iso8601 +end diff --git a/1.8/library/time/rfc2822_spec.rb b/1.8/library/time/rfc2822_spec.rb new file mode 100644 index 0000000000..ef0f2496f1 --- /dev/null +++ b/1.8/library/time/rfc2822_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/rfc2822' +require 'time' + +describe "Time.rfc2822" do + it_behaves_like :time_rfc2822, :rfc2822 +end diff --git a/1.8/library/time/rfc822_spec.rb b/1.8/library/time/rfc822_spec.rb new file mode 100644 index 0000000000..1176cd64ec --- /dev/null +++ b/1.8/library/time/rfc822_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/rfc2822' +require 'time' + +describe "Time.rfc822" do + it_behaves_like :time_rfc2822, :rfc822 +end diff --git a/1.8/library/time/shared/rfc2822.rb b/1.8/library/time/shared/rfc2822.rb new file mode 100644 index 0000000000..018a54e4b9 --- /dev/null +++ b/1.8/library/time/shared/rfc2822.rb @@ -0,0 +1,67 @@ +shared :time_rfc2822 do |cmd| + describe "Time.#{cmd}" do + it "parses RFC-822 strings" do + t1 = (Time.utc(1976, 8, 26, 14, 30) + 4 * 3600) + t2 = Time.rfc2822("26 Aug 76 14:30 EDT") + t1.should == t2 + + t3 = Time.utc(1976, 8, 27, 9, 32) + 7 * 3600 + t4 = Time.rfc2822("27 Aug 76 09:32 PDT") + t3.should == t4 + end + + it "parses RFC-2822 strings" do + t1 = Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600 + t2 = Time.rfc2822("Fri, 21 Nov 1997 09:55:06 -0600") + t1.should == t2 + + t3 = Time.utc(2003, 7, 1, 10, 52, 37) - 2 * 3600 + t4 = Time.rfc2822("Tue, 1 Jul 2003 10:52:37 +0200") + t3.should == t4 + + t5 = Time.utc(1997, 11, 21, 10, 1, 10) + 6 * 3600 + t6 = Time.rfc2822("Fri, 21 Nov 1997 10:01:10 -0600") + t5.should == t6 + + t7 = Time.utc(1997, 11, 21, 11, 0, 0) + 6 * 3600 + t8 = Time.rfc2822("Fri, 21 Nov 1997 11:00:00 -0600") + t7.should == t8 + + t9 = Time.utc(1997, 11, 24, 14, 22, 1) + 8 * 3600 + t10 = Time.rfc2822("Mon, 24 Nov 1997 14:22:01 -0800") + t9.should == t10 + + begin + Time.at(-1) + rescue ArgumentError + # ignore + else + t11 = Time.utc(1969, 2, 13, 23, 32, 54) + 3 * 3600 + 30 * 60 + t12 = Time.rfc2822("Thu, 13 Feb 1969 23:32:54 -0330") + t11.should == t12 + + t13 = Time.utc(1969, 2, 13, 23, 32, 0) + 3 * 3600 + 30 * 60 + t14 = Time.rfc2822(" Thu, + 13 + Feb + 1969 + 23:32 + -0330 (Newfoundland Time)") + t13.should == t14 + end + + t15 = Time.utc(1997, 11, 21, 9, 55, 6) + t16 = Time.rfc2822("21 Nov 97 09:55:06 GMT") + t15.should == t16 + + t17 = Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600 + t18 = Time.rfc2822("Fri, 21 Nov 1997 09 : 55 : 06 -0600") + t17.should == t18 + + lambda { + # inner comment is not supported. + Time.rfc2822("Fri, 21 Nov 1997 09(comment): 55 : 06 -0600") + }.should raise_error(ArgumentError) + end + end +end diff --git a/1.8/library/time/shared/xmlschema.rb b/1.8/library/time/shared/xmlschema.rb new file mode 100644 index 0000000000..8513f3f3d2 --- /dev/null +++ b/1.8/library/time/shared/xmlschema.rb @@ -0,0 +1,55 @@ +shared :time_xmlschema do |cmd| + describe "Time.#{cmd}" do + it "parses ISO-8601 strings" do + t = Time.utc(1985, 4, 12, 23, 20, 50, 520000) + s = "1985-04-12T23:20:50.52Z" + t.should == Time.xmlschema(s) + #s.should == t.xmlschema(2) + + t = Time.utc(1996, 12, 20, 0, 39, 57) + s = "1996-12-19T16:39:57-08:00" + t.should == Time.xmlschema(s) + # There is no way to generate time string with arbitrary timezone. + s = "1996-12-20T00:39:57Z" + t.should == Time.xmlschema(s) + #assert_equal(s, t.xmlschema) + + t = Time.utc(1990, 12, 31, 23, 59, 60) + s = "1990-12-31T23:59:60Z" + t.should == Time.xmlschema(s) + # leap second is representable only if timezone file has it. + s = "1990-12-31T15:59:60-08:00" + t.should == Time.xmlschema(s) + + begin + Time.at(-1) + rescue ArgumentError + # ignore + else + t = Time.utc(1937, 1, 1, 11, 40, 27, 870000) + s = "1937-01-01T12:00:27.87+00:20" + t.should == Time.xmlschema(s) + end + + # more + + # (Time.utc(1999, 5, 31, 13, 20, 0) + 5 * 3600).should == Time.xmlschema("1999-05-31T13:20:00-05:00") + # (Time.local(2000, 1, 20, 12, 0, 0)).should == Time.xmlschema("2000-01-20T12:00:00") + # (Time.utc(2000, 1, 20, 12, 0, 0)).should == Time.xmlschema("2000-01-20T12:00:00Z") + # (Time.utc(2000, 1, 20, 12, 0, 0) - 12 * 3600).should == Time.xmlschema("2000-01-20T12:00:00+12:00") + # (Time.utc(2000, 1, 20, 12, 0, 0) + 13 * 3600).should == Time.xmlschema("2000-01-20T12:00:00-13:00") + # (Time.utc(2000, 3, 4, 23, 0, 0) - 3 * 3600).should == Time.xmlschema("2000-03-04T23:00:00+03:00") + # (Time.utc(2000, 3, 4, 20, 0, 0)).should == Time.xmlschema("2000-03-04T20:00:00Z") + # (Time.local(2000, 1, 15, 0, 0, 0)).should == Time.xmlschema("2000-01-15T00:00:00") + # (Time.local(2000, 2, 15, 0, 0, 0)).should == Time.xmlschema("2000-02-15T00:00:00") + # (Time.local(2000, 1, 15, 12, 0, 0)).should == Time.xmlschema("2000-01-15T12:00:00") + # (Time.utc(2000, 1, 16, 12, 0, 0)).should == Time.xmlschema("2000-01-16T12:00:00Z") + # (Time.local(2000, 1, 1, 12, 0, 0)).should == Time.xmlschema("2000-01-01T12:00:00") + # (Time.utc(1999, 12, 31, 23, 0, 0)).should == Time.xmlschema("1999-12-31T23:00:00Z") + # (Time.local(2000, 1, 16, 12, 0, 0)).should == Time.xmlschema("2000-01-16T12:00:00") + # (Time.local(2000, 1, 16, 0, 0, 0)).should == Time.xmlschema("2000-01-16T00:00:00") + # (Time.utc(2000, 1, 12, 12, 13, 14)).should == Time.xmlschema("2000-01-12T12:13:14Z") + # (Time.utc(2001, 4, 17, 19, 23, 17, 300000)).should == Time.xmlschema("2001-04-17T19:23:17.3Z") + end + end +end diff --git a/1.8/library/time/xmlschema_spec.rb b/1.8/library/time/xmlschema_spec.rb new file mode 100644 index 0000000000..4299843c7d --- /dev/null +++ b/1.8/library/time/xmlschema_spec.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/shared/xmlschema' +require 'time' + +describe "Time.xmlschema" do + it_behaves_like :time_xmlschema, :xmlschema +end diff --git a/1.8/library/timeout/timeout_spec.rb b/1.8/library/timeout/timeout_spec.rb new file mode 100644 index 0000000000..afe7a36d62 --- /dev/null +++ b/1.8/library/timeout/timeout_spec.rb @@ -0,0 +1,44 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'timeout' + +describe "Timeout.timeout" do + it "raises Timeout::Error when it times out" do + lambda { + Timeout::timeout(1) do + sleep 3 + end + }.should raise_error(Timeout::Error) + end + + it "shouldn't wait too long" do + before_time = Time.now + begin + Timeout::timeout(1) do + sleep 3 + end + rescue Timeout::Error + (Time.now - before_time).should < 1.2 + else + 1.should == 0 # I can't think of a better way to say "shouldn't get here" + end + end + + it "shouldn't return too quickly" do + before_time = Time.now + begin + Timeout::timeout(2) do + sleep 3 + end + rescue Timeout::Error + (Time.now - before_time).should > 1.9 + else + 1.should == 0 # I can't think of a better way to say "shouldn't get here" + end + end + + it "should return back the last value in the block" do + Timeout::timeout(1) do + 42 + end.should == 42 + end +end diff --git a/1.8/library/yaml/add_builtin_type_spec.rb b/1.8/library/yaml/add_builtin_type_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/add_builtin_type_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/add_domain_type_spec.rb b/1.8/library/yaml/add_domain_type_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/add_domain_type_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/add_private_type_spec.rb b/1.8/library/yaml/add_private_type_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/add_private_type_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/add_ruby_type_spec.rb b/1.8/library/yaml/add_ruby_type_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/add_ruby_type_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/detect_implicit_spec.rb b/1.8/library/yaml/detect_implicit_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/detect_implicit_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/dump_spec.rb b/1.8/library/yaml/dump_spec.rb new file mode 100644 index 0000000000..97c583aa93 --- /dev/null +++ b/1.8/library/yaml/dump_spec.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "YAML.dump" do + after :each do + File.delete $test_file if File.exist? $test_file + end + + it "converts an object to YAML and write result to io when io provided" do + File.open($test_file, 'w' ) do |io| + YAML.dump( ['badger', 'elephant', 'tiger'], io ) + end + YAML.load_file($test_file).should == ['badger', 'elephant', 'tiger'] + end + + it "returns a string containing dumped YAML when no io provided" do + YAML.dump( :locked ) == "--- :locked" + end +end diff --git a/1.8/library/yaml/dump_stream_spec.rb b/1.8/library/yaml/dump_stream_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/dump_stream_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/each_document_spec.rb b/1.8/library/yaml/each_document_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/each_document_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/each_node_spec.rb b/1.8/library/yaml/each_node_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/each_node_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/emitter_spec.rb b/1.8/library/yaml/emitter_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/emitter_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/fixtures/common.rb b/1.8/library/yaml/fixtures/common.rb new file mode 100644 index 0000000000..1c59b8c2af --- /dev/null +++ b/1.8/library/yaml/fixtures/common.rb @@ -0,0 +1,2 @@ +require 'yaml' +$test_file = "/tmp/yaml_test.yml" diff --git a/1.8/library/yaml/generic_parser_spec.rb b/1.8/library/yaml/generic_parser_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/generic_parser_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/load_documents_spec.rb b/1.8/library/yaml/load_documents_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/load_documents_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/load_file_spec.rb b/1.8/library/yaml/load_file_spec.rb new file mode 100644 index 0000000000..8a0af98941 --- /dev/null +++ b/1.8/library/yaml/load_file_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "YAML.load_file" do + after :each do + File.delete $test_file if File.exist? $test_file + end + + it "returns a hash" do + File.open($test_file,'w' ){|io| YAML.dump( {"bar"=>2, "car"=>1}, io ) } + YAML.load_file($test_file).should == {"bar"=>2, "car"=>1} + end +end diff --git a/1.8/library/yaml/load_spec.rb b/1.8/library/yaml/load_spec.rb new file mode 100644 index 0000000000..e93a63aba0 --- /dev/null +++ b/1.8/library/yaml/load_spec.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "YAML.load" do + after :each do + File.delete $test_file if File.exist? $test_file + end + + it "returns a document from current io stream when io provided" do + File.open($test_file, 'w') do |io| + YAML.dump( ['badger', 'elephant', 'tiger'], io ) + end + File.open($test_file) { |yf| YAML.load( yf ) }.should == ['badger', 'elephant', 'tiger'] + end + + it "accepts a string argument" do + YAML.load( "--- :locked" ).should == :locked + end + + it "cleans strings when loading" do + YAML.load("--- \nstring").should == "string" + YAML.load("--- \"string\"").should == "string" + end +end diff --git a/1.8/library/yaml/load_stream_spec.rb b/1.8/library/yaml/load_stream_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/load_stream_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/object_maker_spec.rb b/1.8/library/yaml/object_maker_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/object_maker_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/parse_documents_spec.rb b/1.8/library/yaml/parse_documents_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/parse_documents_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/parse_file_spec.rb b/1.8/library/yaml/parse_file_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/parse_file_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/parse_spec.rb b/1.8/library/yaml/parse_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/parse_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/parser_spec.rb b/1.8/library/yaml/parser_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/parser_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/quick_emit_spec.rb b/1.8/library/yaml/quick_emit_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/quick_emit_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/read_type_class_spec.rb b/1.8/library/yaml/read_type_class_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/read_type_class_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/tag_class_spec.rb b/1.8/library/yaml/tag_class_spec.rb new file mode 100644 index 0000000000..ada692430e --- /dev/null +++ b/1.8/library/yaml/tag_class_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "YAML.tag_class" do + it "associates a taguri tag with a ruby class" do + YAML.tag_class('rubini.us','rubinius').should == "rubinius" + end +end diff --git a/1.8/library/yaml/tagged_classes_spec.rb b/1.8/library/yaml/tagged_classes_spec.rb new file mode 100644 index 0000000000..1cf0289b58 --- /dev/null +++ b/1.8/library/yaml/tagged_classes_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "YAML.tagged_classes" do + it "returns a complete dictionary of taguris paired with classes" do + YAML.tagged_classes["tag:yaml.org,2002:int"].should == Integer + end +end diff --git a/1.8/library/yaml/tagurize_spec.rb b/1.8/library/yaml/tagurize_spec.rb new file mode 100644 index 0000000000..a3eeed957f --- /dev/null +++ b/1.8/library/yaml/tagurize_spec.rb @@ -0,0 +1,9 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "YAML.tagurize" do + it "converts a type_id to a taguri" do + YAML.tagurize('wtf').should == "tag:yaml.org,2002:wtf" + YAML.tagurize(1).should == 1 + end +end diff --git a/1.8/library/yaml/to_yaml_spec.rb b/1.8/library/yaml/to_yaml_spec.rb new file mode 100644 index 0000000000..b0a94a06c7 --- /dev/null +++ b/1.8/library/yaml/to_yaml_spec.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' + +describe "Object#to_yaml" do + it "returns the YAML representation of a Symbol" do + :symbol.to_yaml.should == "--- :symbol\n" + end +end diff --git a/1.8/library/yaml/transfer_spec.rb b/1.8/library/yaml/transfer_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/transfer_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/yaml/try_implicit_spec.rb b/1.8/library/yaml/try_implicit_spec.rb new file mode 100644 index 0000000000..eec2922936 --- /dev/null +++ b/1.8/library/yaml/try_implicit_spec.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/fixtures/common' diff --git a/1.8/library/zlib/adler32_spec.rb b/1.8/library/zlib/adler32_spec.rb new file mode 100644 index 0000000000..29af57c511 --- /dev/null +++ b/1.8/library/zlib/adler32_spec.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'zlib' + +describe "Zlib.adler32" do + it "calculates Adler checksum for string" do + Zlib.adler32("").should == 1 + Zlib.adler32(" ").should == 2162721 + Zlib.adler32("123456789").should == 152961502 + Zlib.adler32("!@#\{$\}%^&**()").should == 365495023 + Zlib.adler32("to be or not to be" * 22).should == 3979904837 + Zlib.adler32("0").should == 3211313 + Zlib.adler32((2**32).to_s).should == 193331739 + Zlib.adler32((2**64).to_s).should == 723452953 + end + + it "calculates Adler checksum for string and initial Adler value" do + test_string = "This is a test string! How exciting!%?" + Zlib.adler32(test_string, 0).should == 63900955 + Zlib.adler32(test_string, 1).should == 66391324 + Zlib.adler32(test_string, 2**8).should == 701435419 + Zlib.adler32(test_string, 2**16).should == 63966491 + lambda { Zlib.adler32(test_string, 2**128) }.should raise_error(RangeError) + end + + it "calculates the Adler checksum for string and initial Adler value for Bignums" do + test_string = "This is a test string! How exciting!%?" + Zlib.adler32(test_string, 2**30).should == 1137642779 + end + + it "assumes that the initial value is given to adler, if adler is omitted" do + orig_crc = Zlib.adler32 + Zlib.adler32("").should == Zlib.adler32("", orig_crc) + Zlib.adler32(" ").should == Zlib.adler32(" ", orig_crc) + Zlib.adler32("123456789").should == Zlib.adler32("123456789", orig_crc) + Zlib.adler32("!@#\{$\}%^&**()").should == Zlib.adler32("!@#\{$\}%^&**()", orig_crc) + Zlib.adler32("to be or not to be" * 22).should == Zlib.adler32("to be or not to be" * 22, orig_crc) + Zlib.adler32("0").should == Zlib.adler32("0", orig_crc) + Zlib.adler32((2**32).to_s).should == Zlib.adler32((2**32).to_s, orig_crc) + Zlib.adler32((2**64).to_s).should == Zlib.adler32((2**64).to_s, orig_crc) + end + + it "it returns the CRC initial value, if string is omitted" do + Zlib.adler32.should == 1 + end + +end diff --git a/1.8/library/zlib/crc32_spec.rb b/1.8/library/zlib/crc32_spec.rb new file mode 100644 index 0000000000..3359da62d5 --- /dev/null +++ b/1.8/library/zlib/crc32_spec.rb @@ -0,0 +1,52 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'zlib' + +describe "Zlib.crc32" do + it "calculates CRC checksum for string" do + Zlib.crc32("").should == 0 + Zlib.crc32(" ").should == 3916222277 + Zlib.crc32("123456789").should == 3421780262 + Zlib.crc32("!@#\{$\}%^&**()").should == 2824518887 + Zlib.crc32("to be or not to be" * 22).should == 1832379978 + Zlib.crc32("0").should == 4108050209 + Zlib.crc32((2**32).to_s).should == 3267533297 + Zlib.crc32((2**64).to_s).should == 653721760 + end + + it "calculates CRC checksum for string and initial CRC value" do + test_string = "This is a test string! How exciting!%?" + # Zlib.crc32(test_string, -2**28).should == 3230195786 + # Zlib.crc32(test_string, -2**20).should == 2770207303 + # Zlib.crc32(test_string, -2**16).should == 2299432960 + # Zlib.crc32(test_string, -2**8).should == 861809849 + # Zlib.crc32(test_string, -1).should == 2170124077 + Zlib.crc32(test_string, 0).should == 3864990561 + Zlib.crc32(test_string, 1).should == 1809313411 + Zlib.crc32(test_string, 2**8).should == 1722745982 + Zlib.crc32(test_string, 2**16).should == 1932511220 + lambda { Zlib.crc32(test_string, 2**128) }.should raise_error(RangeError) + end + + it "calculates the CRC checksum for string and initial CRC value for Bignums" do + test_string = "This is a test string! How exciting!%?" + # Zlib.crc32(test_string, -2**30).should == 277228695 + Zlib.crc32(test_string, 2**30).should == 46597132 + end + + it "assumes that the initial value is given to crc, if crc is omitted" do + orig_crc = Zlib.crc32 + Zlib.crc32("").should == Zlib.crc32("", orig_crc) + Zlib.crc32(" ").should == Zlib.crc32(" ", orig_crc) + Zlib.crc32("123456789").should == Zlib.crc32("123456789", orig_crc) + Zlib.crc32("!@#\{$\}%^&**()").should == Zlib.crc32("!@#\{$\}%^&**()", orig_crc) + Zlib.crc32("to be or not to be" * 22).should == Zlib.crc32("to be or not to be" * 22, orig_crc) + Zlib.crc32("0").should == Zlib.crc32("0", orig_crc) + Zlib.crc32((2**32).to_s).should == Zlib.crc32((2**32).to_s, orig_crc) + Zlib.crc32((2**64).to_s).should == Zlib.crc32((2**64).to_s, orig_crc) + end + + it "it returns the CRC initial value, if string is omitted" do + Zlib.crc32.should == 0 + end + +end diff --git a/1.8/library/zlib/crc_table_spec.rb b/1.8/library/zlib/crc_table_spec.rb new file mode 100644 index 0000000000..7602ec9c71 --- /dev/null +++ b/1.8/library/zlib/crc_table_spec.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require "zlib" + +describe "Zlib.crc_table" do + + it "should return the same value as zlib's get_crc_table()" do + Zlib.crc_table.should == + [0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 936918000, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117] + end + +end \ No newline at end of file diff --git a/1.8/library/zlib/deflate/append_spec.rb b/1.8/library/zlib/deflate/append_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/deflate/append_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/deflate/deflate_spec.rb b/1.8/library/zlib/deflate/deflate_spec.rb new file mode 100644 index 0000000000..de5cbd4dfe --- /dev/null +++ b/1.8/library/zlib/deflate/deflate_spec.rb @@ -0,0 +1,49 @@ +require 'zlib' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe 'Zlib::Deflate#deflate' do + + before :each do + @deflator = Zlib::Deflate.new + end + + it 'deflates some data' do + data = "\000" * 10 + + zipped = @deflator.deflate data, Zlib::FINISH + @deflator.finish + + zipped.should == "x\234c`\200\001\000\000\n\000\001" + end + + it 'deflates lots of data' do + data = "\000" * 32 * 1024 + + zipped = @deflator.deflate data, Zlib::FINISH + @deflator.finish + + zipped.should == "x\234\355\301\001\001\000\000\000\200\220\376\257\356\b\n#{"\000" * 31}\030\200\000\000\001" + end + +end + +describe 'Zlib::Deflate::deflate' do + + it 'deflates some data' do + data = "\000" * 10 + + zipped = Zlib::Deflate.deflate data + + zipped.should == "x\234c`\200\001\000\000\n\000\001" + end + + it 'deflates lots of data' do + data = "\000" * 32 * 1024 + + zipped = Zlib::Deflate.deflate data + + zipped.should == "x\234\355\301\001\001\000\000\000\200\220\376\257\356\b\n#{"\000" * 31}\030\200\000\000\001" + end + +end + diff --git a/1.8/library/zlib/deflate/flush_spec.rb b/1.8/library/zlib/deflate/flush_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/deflate/flush_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/deflate/initialize_copy_spec.rb b/1.8/library/zlib/deflate/initialize_copy_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/deflate/initialize_copy_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/deflate/new_spec.rb b/1.8/library/zlib/deflate/new_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/deflate/new_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/deflate/params_spec.rb b/1.8/library/zlib/deflate/params_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/deflate/params_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/deflate/set_dictionary_spec.rb b/1.8/library/zlib/deflate/set_dictionary_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/deflate/set_dictionary_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/close_spec.rb b/1.8/library/zlib/gzipfile/close_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/close_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/closed_spec.rb b/1.8/library/zlib/gzipfile/closed_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/closed_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/comment_spec.rb b/1.8/library/zlib/gzipfile/comment_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/comment_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/crc_spec.rb b/1.8/library/zlib/gzipfile/crc_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/crc_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/finish_spec.rb b/1.8/library/zlib/gzipfile/finish_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/finish_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/level_spec.rb b/1.8/library/zlib/gzipfile/level_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/level_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/mtime_spec.rb b/1.8/library/zlib/gzipfile/mtime_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/mtime_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/orig_name_spec.rb b/1.8/library/zlib/gzipfile/orig_name_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/orig_name_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/os_code_spec.rb b/1.8/library/zlib/gzipfile/os_code_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/os_code_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/sync_spec.rb b/1.8/library/zlib/gzipfile/sync_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/sync_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/to_io_spec.rb b/1.8/library/zlib/gzipfile/to_io_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/to_io_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipfile/wrap_spec.rb b/1.8/library/zlib/gzipfile/wrap_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipfile/wrap_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/each_byte_spec.rb b/1.8/library/zlib/gzipreader/each_byte_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/each_byte_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/each_line_spec.rb b/1.8/library/zlib/gzipreader/each_line_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/each_line_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/each_spec.rb b/1.8/library/zlib/gzipreader/each_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/each_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/eof_spec.rb b/1.8/library/zlib/gzipreader/eof_spec.rb new file mode 100644 index 0000000000..1903152af2 --- /dev/null +++ b/1.8/library/zlib/gzipreader/eof_spec.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'stringio' +require 'zlib' + +describe "GzipReader#eof?" do + + before :each do + @data = '12345abcde' + @zip = "\037\213\b\000,\334\321G\000\00334261MLJNI\005\000\235\005\000$\n\000\000\000" + @io = StringIO.new @zip + end + + it "returns true when at EOF" do + gz = Zlib::GzipReader.new @io + + gz.eof?.should == false + gz.read + gz.eof?.should == true + end + +end + diff --git a/1.8/library/zlib/gzipreader/getc_spec.rb b/1.8/library/zlib/gzipreader/getc_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/getc_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/gets_spec.rb b/1.8/library/zlib/gzipreader/gets_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/gets_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/lineno_spec.rb b/1.8/library/zlib/gzipreader/lineno_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/lineno_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/new_spec.rb b/1.8/library/zlib/gzipreader/new_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/new_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/open_spec.rb b/1.8/library/zlib/gzipreader/open_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/open_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/pos_spec.rb b/1.8/library/zlib/gzipreader/pos_spec.rb new file mode 100644 index 0000000000..665d20dbdb --- /dev/null +++ b/1.8/library/zlib/gzipreader/pos_spec.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'stringio' +require 'zlib' + +describe "GzipReader#pos" do + + before :each do + @data = '12345abcde' + @zip = "\037\213\b\000,\334\321G\000\00334261MLJNI\005\000\235\005\000$\n\000\000\000" + @io = StringIO.new @zip + end + + it "returns the position" do + gz = Zlib::GzipReader.new @io + + gz.pos.should == 0 + + gz.read 5 + gz.pos.should == 5 + + gz.read + gz.pos.should == @data.length + end + +end + diff --git a/1.8/library/zlib/gzipreader/read_spec.rb b/1.8/library/zlib/gzipreader/read_spec.rb new file mode 100644 index 0000000000..ffcef3411c --- /dev/null +++ b/1.8/library/zlib/gzipreader/read_spec.rb @@ -0,0 +1,28 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'stringio' +require 'zlib' + +describe "GzipReader#read" do + + before :each do + @data = '12345abcde' + @zip = "\037\213\b\000,\334\321G\000\00334261MLJNI\005\000\235\005\000$\n\000\000\000" + @io = StringIO.new @zip + end + + it "reads the contents of a gzip file" do + gz = Zlib::GzipReader.new @io + + gz.read.should == @data + end + + it "reads the contents up to a certain size" do + gz = Zlib::GzipReader.new @io + + gz.read(5).should == @data[0...5] + + gz.read(5).should == @data[5...10] + end + +end + diff --git a/1.8/library/zlib/gzipreader/readchar_spec.rb b/1.8/library/zlib/gzipreader/readchar_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/readchar_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/readline_spec.rb b/1.8/library/zlib/gzipreader/readline_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/readline_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/readlines_spec.rb b/1.8/library/zlib/gzipreader/readlines_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/readlines_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/rewind_spec.rb b/1.8/library/zlib/gzipreader/rewind_spec.rb new file mode 100644 index 0000000000..54ab16b707 --- /dev/null +++ b/1.8/library/zlib/gzipreader/rewind_spec.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'stringio' +require 'zlib' + +describe "GzipReader#rewind" do + + before :each do + @data = '12345abcde' + @zip = "\037\213\b\000,\334\321G\000\00334261MLJNI\005\000\235\005\000$\n\000\000\000" + @io = StringIO.new @zip + end + + it "resets the position of the file pointer" do + gz = Zlib::GzipReader.new @io + gz.read + gz.pos.should == @data.length + + gz.rewind + gz.pos.should == 0 + end + + it "invokes seek method on the associated IO object" do + # first, prepare the mock object: + (obj = mock("io")).should_receive(:get_io).any_number_of_times.and_return(@io) + def obj.read(args); get_io.read(args); end + obj.should_receive(:seek).and_return(0) + + gz = Zlib::GzipReader.new(obj) + gz.rewind() + gz.pos.should == 0 + end +end diff --git a/1.8/library/zlib/gzipreader/tell_spec.rb b/1.8/library/zlib/gzipreader/tell_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/tell_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/ungetc_spec.rb b/1.8/library/zlib/gzipreader/ungetc_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/ungetc_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipreader/unused_spec.rb b/1.8/library/zlib/gzipreader/unused_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipreader/unused_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/append_spec.rb b/1.8/library/zlib/gzipwriter/append_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/append_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/comment_spec.rb b/1.8/library/zlib/gzipwriter/comment_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/comment_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/flush_spec.rb b/1.8/library/zlib/gzipwriter/flush_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/flush_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/mtime_spec.rb b/1.8/library/zlib/gzipwriter/mtime_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/mtime_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/new_spec.rb b/1.8/library/zlib/gzipwriter/new_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/new_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/open_spec.rb b/1.8/library/zlib/gzipwriter/open_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/open_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/orig_name_spec.rb b/1.8/library/zlib/gzipwriter/orig_name_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/orig_name_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/pos_spec.rb b/1.8/library/zlib/gzipwriter/pos_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/pos_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/print_spec.rb b/1.8/library/zlib/gzipwriter/print_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/print_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/printf_spec.rb b/1.8/library/zlib/gzipwriter/printf_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/printf_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/putc_spec.rb b/1.8/library/zlib/gzipwriter/putc_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/putc_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/puts_spec.rb b/1.8/library/zlib/gzipwriter/puts_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/puts_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/tell_spec.rb b/1.8/library/zlib/gzipwriter/tell_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/gzipwriter/tell_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/gzipwriter/write_spec.rb b/1.8/library/zlib/gzipwriter/write_spec.rb new file mode 100644 index 0000000000..aa8395cc1b --- /dev/null +++ b/1.8/library/zlib/gzipwriter/write_spec.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'stringio' +require 'zlib' + +describe "GzipReader#write" do + + before :each do + @data = '12345abcde' + @zip = "\037\213\b\000,\334\321G\000\00334261MLJNI\005\000\235\005\000$\n\000\000\000" + @io = StringIO.new + end + + it "writes some compressed data" do + gz = Zlib::GzipWriter.new @io + gz.write @data + gz.close + + # skip gzip header for now + @io.string[10..-1].should == @zip[10..-1] + end + +end + diff --git a/1.8/library/zlib/inflate/append_spec.rb b/1.8/library/zlib/inflate/append_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/inflate/append_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/inflate/inflate_spec.rb b/1.8/library/zlib/inflate/inflate_spec.rb new file mode 100644 index 0000000000..4a34aeb9ae --- /dev/null +++ b/1.8/library/zlib/inflate/inflate_spec.rb @@ -0,0 +1,49 @@ +require 'zlib' +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe 'Zlib::Inflate#inflate' do + + before :each do + @inflator = Zlib::Inflate.new + end + + it 'inflates some data' do + data = "x\234c`\200\001\000\000\n\000\001" + + unzipped = @inflator.inflate data + @inflator.finish + + unzipped.should == "\000" * 10 + end + + it 'inflates lots of data' do + data = "x\234\355\301\001\001\000\000\000\200\220\376\257\356\b\n#{"\000" * 31}\030\200\000\000\001" + + unzipped = @inflator.inflate data + @inflator.finish + + unzipped.should == "\000" * 32 * 1024 + end + +end + +describe 'Zlib::Inflate::inflate' do + + it 'inflates some data' do + data = "x\234c`\200\001\000\000\n\000\001" + + unzipped = Zlib::Inflate.inflate data + + unzipped.should == "\000" * 10 + end + + it 'inflates lots of data' do + data = "x\234\355\301\001\001\000\000\000\200\220\376\257\356\b\n#{"\000" * 31}\030\200\000\000\001" + + zipped = Zlib::Inflate.inflate data + + zipped.should == "\000" * 32 * 1024 + end + +end + diff --git a/1.8/library/zlib/inflate/new_spec.rb b/1.8/library/zlib/inflate/new_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/inflate/new_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/inflate/set_dictionary_spec.rb b/1.8/library/zlib/inflate/set_dictionary_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/inflate/set_dictionary_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/inflate/sync_point_spec.rb b/1.8/library/zlib/inflate/sync_point_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/inflate/sync_point_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/inflate/sync_spec.rb b/1.8/library/zlib/inflate/sync_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/inflate/sync_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zlib_version_spec.rb b/1.8/library/zlib/zlib_version_spec.rb new file mode 100644 index 0000000000..76f71251bd --- /dev/null +++ b/1.8/library/zlib/zlib_version_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../spec_helper' diff --git a/1.8/library/zlib/zstream/adler_spec.rb b/1.8/library/zlib/zstream/adler_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/adler_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/avail_in_spec.rb b/1.8/library/zlib/zstream/avail_in_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/avail_in_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/avail_out_spec.rb b/1.8/library/zlib/zstream/avail_out_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/avail_out_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/close_spec.rb b/1.8/library/zlib/zstream/close_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/close_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/closed_spec.rb b/1.8/library/zlib/zstream/closed_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/closed_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/data_type_spec.rb b/1.8/library/zlib/zstream/data_type_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/data_type_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/end_spec.rb b/1.8/library/zlib/zstream/end_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/end_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/ended_spec.rb b/1.8/library/zlib/zstream/ended_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/ended_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/finish_spec.rb b/1.8/library/zlib/zstream/finish_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/finish_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/finished_spec.rb b/1.8/library/zlib/zstream/finished_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/finished_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/flush_next_in_spec.rb b/1.8/library/zlib/zstream/flush_next_in_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/flush_next_in_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/flush_next_out_spec.rb b/1.8/library/zlib/zstream/flush_next_out_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/flush_next_out_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/reset_spec.rb b/1.8/library/zlib/zstream/reset_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/reset_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/stream_end_spec.rb b/1.8/library/zlib/zstream/stream_end_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/stream_end_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/total_in_spec.rb b/1.8/library/zlib/zstream/total_in_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/total_in_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/library/zlib/zstream/total_out_spec.rb b/1.8/library/zlib/zstream/total_out_spec.rb new file mode 100644 index 0000000000..0ec1016caa --- /dev/null +++ b/1.8/library/zlib/zstream/total_out_spec.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../spec_helper' diff --git a/1.8/shared/file/blockdev.rb b/1.8/shared/file/blockdev.rb new file mode 100644 index 0000000000..6046dd2335 --- /dev/null +++ b/1.8/shared/file/blockdev.rb @@ -0,0 +1,7 @@ +shared :file_blockdev do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns true/false depending if the named file is a block device" do + klass.send(cmd, "/tmp").should == false + end + end +end diff --git a/1.8/shared/file/chardev.rb b/1.8/shared/file/chardev.rb new file mode 100644 index 0000000000..8cfaa91efd --- /dev/null +++ b/1.8/shared/file/chardev.rb @@ -0,0 +1,7 @@ +shared :file_chardev do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns true/false depending if the named file is a char device" do + klass.send(cmd, "/tmp").should == false + end + end +end diff --git a/1.8/shared/file/directory.rb b/1.8/shared/file/directory.rb new file mode 100644 index 0000000000..1387fb3068 --- /dev/null +++ b/1.8/shared/file/directory.rb @@ -0,0 +1,33 @@ +shared :file_directory do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + platform_is :windows do + @dir = "C:\\" + @file = "C:\\winnt\\notepad.exe" + end + + platform_is_not :windows do + @dir = "/" + @file = "/bin/ls" + end + end + + after :each do + @dir = nil + end + + it "return true if dir is a directory, otherwise return false" do + klass.send(cmd, @dir).should == true + klass.send(cmd, @file).should == false + end + + it "raises an ArgumentError if not passed one argument" do + lambda { klass.send(cmd) }.should raise_error(ArgumentError) + lambda { klass.send(cmd, @dir, @file) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { klass.send(cmd, nil) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/shared/file/executable.rb b/1.8/shared/file/executable.rb new file mode 100644 index 0000000000..9562a03332 --- /dev/null +++ b/1.8/shared/file/executable.rb @@ -0,0 +1,52 @@ +shared :file_executable do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @file1 = 'temp1.txt' + @file2 = 'temp2.txt' + + File.open(@file1, "w"){} # touch + File.open(@file2, "w"){} # touch + + File.chmod(0755, @file1) + end + + after :each do + File.delete(@file1) if File.exist?(@file1) + File.delete(@file2) if File.exist?(@file2) + + @file1 = nil + @file2 = nil + end + + it "returns true if named file is executable by the effective user id of the process, otherwise false" do + klass.send(cmd, '/etc/passwd').should == false + klass.send(cmd, @file1).should == true + klass.send(cmd, @file2).should == false + end + + platform_is_not :windows do + it "return true if the argument is an executable file" do + klass.send(cmd, @file1).should == true + klass.send(cmd, @file2).should == false + end + end + + it "raises an ArgumentError if not passed one argument" do + lambda { klass.send(cmd) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { klass.send(cmd, 1) }.should raise_error(TypeError) + lambda { klass.send(cmd, nil) }.should raise_error(TypeError) + lambda { klass.send(cmd, false) }.should raise_error(TypeError) + end + end +end + +shared :file_executable_missing do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns false if the file does not exist" do + klass.send(cmd, 'fake_file').should == false + end + end +end diff --git a/1.8/shared/file/executable_real.rb b/1.8/shared/file/executable_real.rb new file mode 100644 index 0000000000..639a21df1e --- /dev/null +++ b/1.8/shared/file/executable_real.rb @@ -0,0 +1,50 @@ +shared :file_executable_real do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @file1 = File.join(Dir.pwd, 'temp1.txt') + @file2 = File.join(Dir.pwd, 'temp2.txt') + + File.open(@file1, "w") {} # touch + File.open(@file2, "w") {} + + File.chmod(0755, @file1) + end + + after :each do + File.delete(@file1) if File.exist?(@file1) + File.delete(@file2) if File.exist?(@file2) + + @file1 = nil + @file2 = nil + end + + platform_is_not :windows do + it "returns true if the file its an executable" do + klass.send(cmd, @file1).should == true + klass.send(cmd, @file2).should == false + end + end + + it "returns true if named file is readable by the real user id of the process, otherwise false" do + klass.send(cmd, @file1).should == true + end + + it "raises an ArgumentError if not passed one argument" do + lambda { klass.send(cmd) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { klass.send(cmd, 1) }.should raise_error(TypeError) + lambda { klass.send(cmd, nil) }.should raise_error(TypeError) + lambda { klass.send(cmd, false) }.should raise_error(TypeError) + end + end +end + +shared :file_executable_real_missing do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns false if the file does not exist" do + klass.send(cmd, 'fake_file').should == false + end + end +end diff --git a/1.8/shared/file/exist.rb b/1.8/shared/file/exist.rb new file mode 100644 index 0000000000..4ae812d894 --- /dev/null +++ b/1.8/shared/file/exist.rb @@ -0,0 +1,22 @@ +shared :file_exist do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "return true if the file exist" do + klass.send(cmd, __FILE__).should == true + klass.send(cmd, 'a_fake_file').should == false + end + + it "return true if the file exist using the alias exists?" do + klass.send(cmd, __FILE__).should == true + klass.send(cmd, 'a_fake_file').should == false + end + + it "raises an ArgumentError if not passed one argument" do + lambda { klass.send(cmd) }.should raise_error(ArgumentError) + lambda { klass.send(cmd, __FILE__, __FILE__) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { klass.send(cmd, nil) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/shared/file/file.rb b/1.8/shared/file/file.rb new file mode 100644 index 0000000000..040c35d76a --- /dev/null +++ b/1.8/shared/file/file.rb @@ -0,0 +1,40 @@ +shared :file_file do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + platform_is :windows do + @null = "NUL" + @dir = "C:\\" + end + + platform_is_not :windows do + @null = "/dev/null" + @dir = "/bin" + end + + @file = "test.txt" + File.open(@file, "w"){} # touch + end + + after :each do + File.delete(@file) rescue nil + @null = nil + @file = nil + end + + it "returns true if the named file exists and is a regular file." do + klass.send(cmd, @file).should == true + klass.send(cmd, @dir).should == false + klass.send(cmd, @null).should == false # May fail on MS Windows + end + + it "raises an ArgumentError if not passed one argument" do + lambda { klass.send(cmd) }.should raise_error(ArgumentError) + lambda { klass.send(cmd, @null, @file) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { klass.send(cmd, nil) }.should raise_error(TypeError) + lambda { klass.send(cmd, 1) }.should raise_error(TypeError) + end + end +end diff --git a/1.8/shared/file/grpowned.rb b/1.8/shared/file/grpowned.rb new file mode 100644 index 0000000000..413df24b7d --- /dev/null +++ b/1.8/shared/file/grpowned.rb @@ -0,0 +1,18 @@ +shared :file_grpowned do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + + before :each do + @file = '/tmp/i_exist' + File.open(@file,'w'){|f| f.write 'rubinius'} + File.chown(nil, Process.gid, @file) + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "return true if the file exist" do + klass.send(cmd, @file).should == true + end + end +end diff --git a/1.8/shared/file/identical.rb b/1.8/shared/file/identical.rb new file mode 100644 index 0000000000..fcb369f8c1 --- /dev/null +++ b/1.8/shared/file/identical.rb @@ -0,0 +1,57 @@ +shared :file_identical do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @file1 = 'test.txt' + @file2 = 'test2.txt' + @file3 = 'test.lnk' + File.delete(@file3) if File.exists?(@file3) + + File.open(@file1,"w+") { |f| f.puts "file1" } + File.open(@file2,"w+") { |f| f.puts "file2" } + File.link(@file1, @file3) + end + + after :each do + File.unlink(@file3) + File.delete(@file1) if File.exists?(@file1) + File.delete(@file2) if File.exists?(@file2) + @file1 = nil + @file1 = nil + @file1 = nil + end + + it "return a Boolean class" do + klass.send(cmd, @file1, @file2).class.should == FalseClass + klass.send(cmd, @file1, @file1).class.should == TrueClass + end + + it "return true if they are identical" do + klass.send(cmd, @file1, @file1).should == true + klass.send(cmd, @file1, @file2).should == false + klass.send(cmd, @file1, @file3).should == true + end + + it "raises an ArgumentError if not passed two arguments" do + lambda { klass.send(cmd, @file1, @file2, @file3) }.should raise_error(ArgumentError) + lambda { klass.send(cmd, @file1) }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed String types" do + lambda { klass.send(cmd, 1,1) }.should raise_error(TypeError) + end + + it "identical? should return true if both named files are identical" do + begin + file = '/tmp/i_exist' + file2 = '/tmp/i_exist_too' + File.open(file,'w'){|f| f.write 'rubinius'} + File.open(file2,'w'){|f| f.write 'ruby'} + klass.send(cmd, file,file).should == true + klass.send(cmd, file,file2).should == false + ensure + File.delete(file) rescue nil + File.delete(file2) rescue nil + end + end + end +end diff --git a/1.8/shared/file/owned.rb b/1.8/shared/file/owned.rb new file mode 100644 index 0000000000..857b8b7f41 --- /dev/null +++ b/1.8/shared/file/owned.rb @@ -0,0 +1,4 @@ +shared :file_owned do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + end +end diff --git a/1.8/shared/file/pipe.rb b/1.8/shared/file/pipe.rb new file mode 100644 index 0000000000..10b421899c --- /dev/null +++ b/1.8/shared/file/pipe.rb @@ -0,0 +1,4 @@ +shared :file_pipe do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + end +end diff --git a/1.8/shared/file/readable.rb b/1.8/shared/file/readable.rb new file mode 100644 index 0000000000..e5a3d4725f --- /dev/null +++ b/1.8/shared/file/readable.rb @@ -0,0 +1,24 @@ +shared :file_readable do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @file = '/tmp/i_exist' + end + + after :each do + File.delete(@file) if File.exists?(@file) + end + + it "returns true if named file is readable by the effective user id of the process, otherwise false" do + klass.send(cmd, '/etc/passwd').should == true + File.open(@file,'w') { klass.send(cmd, @file).should == true } + end + end +end + +shared :file_readable_missing do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns false if the file does not exist" do + klass.send(cmd, 'fake_file').should == false + end + end +end diff --git a/1.8/shared/file/readable_real.rb b/1.8/shared/file/readable_real.rb new file mode 100644 index 0000000000..ec24ae07e1 --- /dev/null +++ b/1.8/shared/file/readable_real.rb @@ -0,0 +1,23 @@ +shared :file_readable_real do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @file = '/tmp/i_exist' + end + + after :each do + File.delete(@file) if File.exists?(@file) + end + + it "returns true if named file is readable by the real user id of the process, otherwise false" do + File.open(@file,'w') { klass.send(cmd, @file).should == true } + end + end +end + +shared :file_readable_real_missing do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns false if the file does not exist" do + klass.send(cmd, 'fake_file').should == false + end + end +end diff --git a/1.8/shared/file/setgid.rb b/1.8/shared/file/setgid.rb new file mode 100644 index 0000000000..eaf0276230 --- /dev/null +++ b/1.8/shared/file/setgid.rb @@ -0,0 +1,4 @@ +shared :file_setgid do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + end +end diff --git a/1.8/shared/file/setuid.rb b/1.8/shared/file/setuid.rb new file mode 100644 index 0000000000..a4571ade29 --- /dev/null +++ b/1.8/shared/file/setuid.rb @@ -0,0 +1,4 @@ +shared :file_setuid do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + end +end diff --git a/1.8/shared/file/size.rb b/1.8/shared/file/size.rb new file mode 100644 index 0000000000..3fbdd135a2 --- /dev/null +++ b/1.8/shared/file/size.rb @@ -0,0 +1,38 @@ +shared :file_size do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @empty = "i_am_empty" + File.delete @empty if File.exist? @empty + File.open(@empty,'w') { } + + @exists = '/tmp/i_exist' + File.open(@exists,'w') { |f| f.write 'rubinius' } + end + + after :each do + File.delete @empty if File.exist? @empty + File.delete @exists if File.exist? @exists + end + + it "returns nil if the file has zero size" do + klass.send(cmd, @empty).should == nil + end + + it "returns the size of the file if it exists and is not empty" do + klass.send(cmd, @exists).should == 8 + end + end +end + +shared :file_size_missing do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @missing = "i_dont_exist" + File.delete @missing if File.exists? @missing + end + + it "returns nil if file_name doesn't exist" do + klass.send(cmd, @missing).should == nil + end + end +end diff --git a/1.8/shared/file/socket.rb b/1.8/shared/file/socket.rb new file mode 100644 index 0000000000..2cb092f93c --- /dev/null +++ b/1.8/shared/file/socket.rb @@ -0,0 +1,4 @@ +shared :file_socket do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + end +end diff --git a/1.8/shared/file/sticky.rb b/1.8/shared/file/sticky.rb new file mode 100644 index 0000000000..5dcc35a053 --- /dev/null +++ b/1.8/shared/file/sticky.rb @@ -0,0 +1,4 @@ +shared :file_sticky do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + end +end diff --git a/1.8/shared/file/symlink.rb b/1.8/shared/file/symlink.rb new file mode 100644 index 0000000000..9e98c66157 --- /dev/null +++ b/1.8/shared/file/symlink.rb @@ -0,0 +1,24 @@ +shared :file_symlink do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @file = "test.txt" + @link = "test.lnk" + File.delete(@link) if File.exist?(@link) + File.delete(@file) if File.exist?(@file) + File.open(@file,"w+") + end + + after :each do + File.unlink(@link) if File.exist?(@link) + File.delete(@file) if File.exist?(@file) + @link = nil + end + + platform_is_not :windows do + it "returns true if the file is a link" do + File.symlink(@file, @link) + klass.send(cmd, @link).should == true + end + end + end +end diff --git a/1.8/shared/file/writable.rb b/1.8/shared/file/writable.rb new file mode 100644 index 0000000000..14286320c7 --- /dev/null +++ b/1.8/shared/file/writable.rb @@ -0,0 +1,24 @@ +shared :file_writable do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @file = '/tmp/i_exist' + end + + after :each do + File.delete(@file) if File.exists?(@file) + end + + it "returns true if named file is writable by the effective user id of the process, otherwise false" do + klass.send(cmd, '/etc/passwd').should == false + File.open(@file,'w') { klass.send(cmd, @file).should == true } + end + end +end + +shared :file_writable_missing do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns false if the file does not exist" do + klass.send(cmd, 'fake_file').should == false + end + end +end diff --git a/1.8/shared/file/writable_real.rb b/1.8/shared/file/writable_real.rb new file mode 100644 index 0000000000..4324651570 --- /dev/null +++ b/1.8/shared/file/writable_real.rb @@ -0,0 +1,33 @@ +shared :file_writable_real do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @file = '/tmp/i_exist' + end + + after :each do + File.delete(@file) if File.exist?(@file) + end + + it "returns true if named file is writable by the real user id of the process, otherwise false" do + File.open(@file,'w') { klass.send(cmd, @file).should == true } + end + + it "raises an ArgumentError if not passed one argument" do + lambda { File.writable_real? }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { klass.send(cmd, 1) }.should raise_error(TypeError) + lambda { klass.send(cmd, nil) }.should raise_error(TypeError) + lambda { klass.send(cmd, false) }.should raise_error(TypeError) + end + end +end + +shared :file_writable_real_missing do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns false if the file does not exist" do + klass.send(cmd, 'fake_file').should == false + end + end +end diff --git a/1.8/shared/file/zero.rb b/1.8/shared/file/zero.rb new file mode 100644 index 0000000000..b66c4a74e5 --- /dev/null +++ b/1.8/shared/file/zero.rb @@ -0,0 +1,62 @@ +shared :file_zero do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + before :each do + @zero_file = 'test.txt' + @nonzero_file = 'test2.txt' + + File.open(@zero_file, "w") {} # Touch + File.open(@nonzero_file, "w") { |f| f.puts "hello" } + end + + after :each do + File.delete(@zero_file) if File.exists?(@zero_file) + File.delete(@nonzero_file) if File.exists?(@nonzero_file) + @zero_file = nil + @nonzero_file = nil + end + + it "return true if the length of a file its zero, otherwise true" do + klass.send(cmd, @zero_file).should == true + klass.send(cmd, @nonzero_file).should == false + end + + platform_is :windows do + it "returns true for NUL" do + klass.send(cmd, 'NUL').should == true + end + end + + platform_is_not :windows do + it "returns true for /dev/null" do + klass.send(cmd, '/dev/null').should == true + end + end + + it "raises an ArgumentError if not passed one argument" do + lambda { File.zero? }.should raise_error(ArgumentError) + end + + it "raises a TypeError if not passed a String type" do + lambda { klass.send(cmd, nil) }.should raise_error(TypeError) + lambda { klass.send(cmd, true) }.should raise_error(TypeError) + lambda { klass.send(cmd, false) }.should raise_error(TypeError) + end + + it "zero? should return true if the named file exists and has a zero size." do + begin + file = '/tmp/i_exist' + File.open(file,'w') { klass.send(cmd, file).should == true } + ensure + File.delete(file) rescue nil + end + end + end +end + +shared :file_zero_missing do |cmd, klass, name| + describe "#{name || "#{klass}.#{cmd}"}" do + it "returns false if the file does not exist" do + klass.send(cmd, 'fake_file').should == false + end + end +end diff --git a/1.8/spec_helper.rb b/1.8/spec_helper.rb new file mode 100644 index 0000000000..3859db2fed --- /dev/null +++ b/1.8/spec_helper.rb @@ -0,0 +1,31 @@ +$:.push File.dirname(__FILE__) + '/../' + +# Prefer included mspec source over a gem version +mspec_dir = File.dirname(__FILE__) + '/../../../mspec/lib' +if File.exist? mspec_dir + $:.unshift mspec_dir +else + require 'rubygems' +end + +if ENV['MSPEC_RUNNER'] == '1' + require 'mspec' + require 'pp' +else + require 'mspec/helpers' + require 'mspec/guards' + require 'mspec/runner/shared' + require 'mspec/matchers/be_ancestor_of' + require 'mspec/matchers/output' + require 'mspec/matchers/output_to_fd' + require 'mspec/matchers/complain' + + TOLERANCE = 0.00003 unless Object.const_defined?(:TOLERANCE) +end + +unless ENV['OUTPUT_WARNINGS'] == '1' + $verbose = $VERBOSE + $VERBOSE = nil + + at_exit { $VERBOSE = $verbose } +end diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..bd0979be43 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2008 Brian Ford + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE.