summaryrefslogtreecommitdiff
path: root/spec/ruby/core/time/comparison_spec.rb
blob: 866fbea72ef1068e6d46169b7c003a4aa9f30d2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
require_relative '../../spec_helper'

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
  end

  it "returns 1 if the first argument is a point in time after the second argument (down to a millisecond)" do
    (Time.at(0, 1000) <=> Time.at(0, 0)).should == 1
    (Time.at(1202778512, 1000) <=> Time.at(1202778512, 999)).should == 1
  end

  it "returns 1 if the first argument is a point in time after the second argument (down to a microsecond)" do
    (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(100, 100) <=> Time.at(101, 100)).should == -1
  end

  it "returns -1 if the first argument is a point in time before the second argument (down to a millisecond)" do
    (Time.at(0, 0) <=> Time.at(0, 1000)).should == -1
  end

  it "returns -1 if the first argument is a point in time before the second argument (down to a microsecond)" do
    (Time.at(0, 0) <=> Time.at(0, 100)).should == -1
  end

  it "returns 1 if the first argument is a fraction of a microsecond after the second argument" do
    (Time.at(100, Rational(1,1000)) <=> Time.at(100, 0)).should == 1
  end

  it "returns 0 if time is the same as other, including fractional microseconds" do
    (Time.at(100, Rational(1,1000)) <=> Time.at(100, Rational(1,1000))).should == 0
  end

  it "returns -1 if the first argument is a fraction of a microsecond before the second argument" do
    (Time.at(100, 0) <=> Time.at(100, Rational(1,1000))).should == -1
  end

  it "returns nil when compared to an Integer because Time does not respond to #coerce" do
    time = Time.at(1)
    time.respond_to?(:coerce).should == false
    time.should_receive(:respond_to?).exactly(2).and_return(false)
    -> {
      (time <=> 2).should == nil
      (2 <=> time).should == nil
    }.should_not complain
  end

  context "given different timezones" do
    it "returns 0 if time is the same as other" do
      # three timezones, all at the same timestamp
      time_utc = Time.new(2000, 1, 1, 0, 0, 0, 0)
      time_cet = Time.new(2000, 1, 1, 1, 0, 0, '+01:00')
      time_brt = Time.new(1999, 12, 31, 21, 0, 0, '-03:00')
      (time_utc <=> time_cet).should == 0
      (time_utc <=> time_brt).should == 0
      (time_cet <=> time_brt).should == 0
    end

    it "returns -1 if the first argument is before the second argument" do
      # time_brt is later, even though the date is earlier
      time_utc = Time.new(2000, 1, 1, 0, 0, 0, 0)
      time_brt = Time.new(1999, 12, 31, 23, 0, 0, '-03:00')
      (time_utc <=> time_brt).should == -1
    end

    it "returns 1 if the first argument is before the second argument" do
      # time_brt is later, even though the date is earlier
      time_utc = Time.new(2000, 1, 1, 0, 0, 0, 0)
      time_brt = Time.new(1999, 12, 31, 23, 0, 0, '-03:00')
      (time_brt <=> time_utc).should == 1
    end
  end

  describe "given a non-Time argument" do
    it "returns nil if argument <=> self returns nil" do
      t = Time.now
      obj = mock('time')
      obj.should_receive(:<=>).with(t).and_return(nil)
      (t <=> obj).should == nil
    end

    it "returns -1 if argument <=> self is greater than 0" do
      t = Time.now
      r = mock('r')
      r.should_receive(:>).with(0).and_return(true)
      obj = mock('time')
      obj.should_receive(:<=>).with(t).and_return(r)
      (t <=> obj).should == -1
    end

    it "returns 1 if argument <=> self is not greater than 0 and is less than 0" do
      t = Time.now
      r = mock('r')
      r.should_receive(:>).with(0).and_return(false)
      r.should_receive(:<).with(0).and_return(true)
      obj = mock('time')
      obj.should_receive(:<=>).with(t).and_return(r)
      (t <=> obj).should == 1
    end

    it "returns 0 if argument <=> self is neither greater than 0 nor less than 0" do
      t = Time.now
      r = mock('r')
      r.should_receive(:>).with(0).and_return(false)
      r.should_receive(:<).with(0).and_return(false)
      obj = mock('time')
      obj.should_receive(:<=>).with(t).and_return(r)
      (t <=> obj).should == 0
    end

    it "returns nil if argument also uses an inverse comparison for <=>" do
      t = Time.now
      r = mock('r')
      def r.<=>(other); other <=> self; end
      r.should_receive(:<=>).once

      (t <=> r).should be_nil
    end
  end
end