require File.dirname(__FILE__) + "/../spec_helper"

module IceCube
  describe DailyRule, "interval validation" do
    it "converts a string integer to an actual int when using the interval method" do
      rule = Rule.daily.interval("2")
      expect(rule.validations_for(:interval).first.interval).to eq(2)
    end

    it "converts a string integer to an actual int when using the initializer" do
      rule = Rule.daily("3")
      expect(rule.validations_for(:interval).first.interval).to eq(3)
    end

    it "raises an argument error when a bad value is passed using the interval method" do
      expect {
        Rule.daily.interval("invalid")
      }.to raise_error(ArgumentError, "'invalid' is not a valid input for interval. Please pass a postive integer.")
    end

    it "raises an argument error when a bad value is passed" do
      expect {
        Rule.daily("invalid")
      }.to raise_error(ArgumentError, "'invalid' is not a valid input for interval. Please pass a postive integer.")
    end
  end

  describe DailyRule do
    describe "in Vancouver time", system_time_zone: "America/Vancouver" do
      it "should include nearest time in DST start hour" do
        schedule = Schedule.new(Time.local(2013, 3, 9, 2, 30, 0))
        schedule.add_recurrence_rule Rule.daily
        expect(schedule.first(3)).to eq([
          Time.local(2013, 3, 9, 2, 30, 0), # -0800
          Time.local(2013, 3, 10, 3, 30, 0), # -0700
          Time.local(2013, 3, 11, 2, 30, 0) # -0700
        ])
      end

      it "should not skip times in DST end hour" do
        schedule = Schedule.new(Time.local(2013, 11, 2, 2, 30, 0))
        schedule.add_recurrence_rule Rule.daily
        expect(schedule.first(3)).to eq([
          Time.local(2013, 11, 2, 2, 30, 0), # -0700
          Time.local(2013, 11, 3, 2, 30, 0), # -0800
          Time.local(2013, 11, 4, 2, 30, 0) # -0800
        ])
      end

      it "should include nearest time to DST start when locking hour_of_day" do
        schedule = Schedule.new(Time.local(2013, 3, 9, 2, 0, 0))
        schedule.add_recurrence_rule Rule.daily.hour_of_day(2)
        expect(schedule.first(3)).to eq([
          Time.local(2013, 3, 9, 2, 0, 0), # -0800
          Time.local(2013, 3, 10, 3, 0, 0), # -0700
          Time.local(2013, 3, 11, 2, 0, 0) # -0700
        ])
      end

      it "should not skip days where DST changes" do
        start_time = Time.local(2013, 3, 10, 0, 0, 0)
        schedule = Schedule.new(start_time)
        schedule.add_recurrence_rule Rule.daily.hour_of_day(19)
        expect(schedule.occurrences_between(start_time, start_time + ONE_DAY)).to eq([
          Time.local(2013, 3, 10, 19, 0, 0)
        ])
      end
    end

    it "should update previous interval" do
      t0 = Time.now
      rule = Rule.daily(7)
      rule.interval(5)
      expect(rule.next_time(t0 + 1, t0, nil)).to eq(t0 + 5 * ONE_DAY)
    end

    it "should produce the correct days for @interval = 1" do
      schedule = Schedule.new(t0 = Time.now)
      schedule.add_recurrence_rule Rule.daily
      # check assumption
      times = schedule.occurrences(t0 + 2 * ONE_DAY)
      expect(times.size).to eq(3)
      expect(times).to eq([t0, t0 + ONE_DAY, t0 + 2 * ONE_DAY])
    end

    it "should produce the correct days for @interval = 2" do
      schedule = Schedule.new(t0 = Time.now)
      schedule.add_recurrence_rule Rule.daily(2)
      # check assumption (3) -- (1) 2 (3) 4 (5) 6
      times = schedule.occurrences(t0 + 5 * ONE_DAY)
      expect(times.size).to eq(3)
      expect(times).to eq([t0, t0 + 2 * ONE_DAY, t0 + 4 * ONE_DAY])
    end

    it "should produce the correct days for @interval = 2 when crossing into a new year" do
      schedule = Schedule.new(t0 = Time.utc(2011, 12, 29))
      schedule.add_recurrence_rule Rule.daily(2)
      # check assumption (3) -- (1) 2 (3) 4 (5) 6
      times = schedule.occurrences(t0 + 5 * ONE_DAY)
      expect(times.size).to eq(3)
      expect(times).to eq([t0, t0 + 2 * ONE_DAY, t0 + 4 * ONE_DAY])
    end

    it "should produce the correct days for interval of 4 day with hour and minute of day set" do
      schedule = Schedule.new(t0 = Time.local(2010, 3, 1))
      schedule.add_recurrence_rule Rule.daily(4).hour_of_day(5).minute_of_hour(45)
      # check assumption 2 -- 1 (2) (3) (4) 5 (6)
      times = schedule.occurrences(t0 + 5 * ONE_DAY)
      expect(times).to eq([
        t0 + 5 * ONE_HOUR + 45 * ONE_MINUTE,
        t0 + 4 * ONE_DAY + 5 * ONE_HOUR + 45 * ONE_MINUTE
      ])
    end

    describe "day validation" do
      it "allows multiples of 7" do
        expect { IceCube::Rule.daily(21).day(2, 4) }.to_not raise_error
      end

      it "raises errors for misaligned interval and day (wday) values" do
        expect {
          IceCube::Rule.daily(2).day(2, 4)
        }.to raise_error(ArgumentError, "day can only be used with multiples of interval(7)")
      end

      it "raises errors for misaligned hour_of_day values when changing interval" do
        expect {
          IceCube::Rule.daily.day(3, 6).interval(5)
        }.to raise_error(ArgumentError, "day can only be used with multiples of interval(7)")
      end
    end

    describe "day_of_month validation" do
      it "raises errors for misaligned interval and day_of_month values" do
        expect {
          IceCube::Rule.daily(2).day_of_month(2, 4)
        }.to raise_error(ArgumentError, "day_of_month can only be used with interval(1)")
      end

      it "raises errors for misaligned day_of_month values when changing interval" do
        expect {
          IceCube::Rule.daily.day_of_month(3, 6).interval(5)
        }.to raise_error(ArgumentError, "day_of_month can only be used with interval(1)")
      end
    end
  end
end
