Wednesday, July 15, 2026 3:58:07 AM
> cooldown_spec.rb
# frozen_string_literal: true

require "timecop"

RSpec.describe ESM::Cooldown do
  before do
    Time.zone = "UTC"
    Timecop.freeze(Time.zone.parse("1990-01-01"))
  end

  after do
    Timecop.return
  end

  describe "#active?" do
    it "is active (seconds)" do
      cooldown = build(:cooldown, :active)
      expect(cooldown.active?).to be(true)
    end

    it "is not active (seconds)" do
      cooldown = build(:cooldown, :inactive)
      expect(cooldown.active?).to be(false)
    end

    it "is active (times)" do
      cooldown = build(:cooldown, expires_at: nil, cooldown_type: "times", cooldown_quantity: 2, cooldown_amount: 2)
      expect(cooldown.active?).to be(true)
    end

    it "is not active (times) when amount is zero" do
      cooldown = build(:cooldown, expires_at: nil, cooldown_type: "times", cooldown_quantity: 2, cooldown_amount: 0)
      expect(cooldown.active?).to be(false)
    end

    it "is not active (times) when amount is less than quantity" do
      cooldown = build(:cooldown, expires_at: nil, cooldown_type: "times", cooldown_quantity: 2, cooldown_amount: 1)
      expect(cooldown.active?).to be(false)
    end
  end

  describe "#to_s" do
    it "shows time left" do
      cooldown = build(:cooldown, :active)
      expect(cooldown.to_s).to match(/less than|second/i)
    end

    it "shows longer time periods" do
      cooldown = build(:cooldown, :active, delay: 2.days)
      expect(cooldown.to_s).to match(/day/i)
    end

    context "singular time units" do
      it "shows seconds range" do
        cooldown = build(:cooldown, :active, delay: 2.seconds)
        expect(cooldown.to_s).to match(/second/i)
      end

      it "shows 1 minute" do
        cooldown = build(:cooldown, :active, delay: (1.minute + 1.second))
        expect(cooldown.to_s).to eq("1 minute")
      end

      it "shows about 1 hour" do
        cooldown = build(:cooldown, :active, delay: (1.hour + 1.second))
        expect(cooldown.to_s).to match(/1 hour/i)
      end

      it "shows 1 day" do
        cooldown = build(:cooldown, :active, delay: (1.day + 1.second))
        expect(cooldown.to_s).to eq("1 day")
      end

      it "shows days for 1 week" do
        cooldown = build(:cooldown, :active, delay: (1.week + 1.second))
        expect(cooldown.to_s).to match(/day/i)
      end

      it "shows about 1 month" do
        cooldown = build(:cooldown, :active, delay: (1.month + 1.second))
        expect(cooldown.to_s).to match(/1 month/i)
      end

      it "shows about 1 year" do
        cooldown = build(:cooldown, :active, delay: (1.year + 1.second))
        expect(cooldown.to_s).to match(/1 year/i)
      end
    end
  end

  describe "#reset!" do
    let!(:community) { create(:community) }
    let!(:server) { create(:server, community: community) }
    let!(:user) { create(:user) }

    it "resets the cooldown" do
      cooldown = create(:cooldown, :active, user: user, server: server, community: community)
      expect(cooldown.active?).to be(true)

      cooldown.reset!
      expect(cooldown.active?).to be(false)
    end
  end

  describe "#update_expiry!" do
    let!(:community) { create(:community) }
    let!(:server) { create(:server, community: community) }
    let!(:user) { create(:user) }

    it "accepts times (1.times, 2.times, etc.)" do
      cooldown = create(:cooldown, user: user, server: server, community: community, cooldown_amount: 0, cooldown_quantity: 1, cooldown_type: "times")

      cooldown.update_expiry!(nil, 1)
      expect(cooldown.cooldown_amount).to eq(1)
      expect(cooldown.active?).to be(true)

      cooldown.update_expiry!(nil, 5.times)
      expect(cooldown.cooldown_amount).to eq(2)
      expect(cooldown.cooldown_quantity).to eq(5)
      expect(cooldown.active?).to be(false)
    end

    it "accepts durations (1.second, 5.minutes, etc.)" do
      cooldown = create(:cooldown, :inactive, user: user, server: server, community: community)

      cooldown.update_expiry!(Time.current, 5.minutes)
      expect(cooldown.cooldown_quantity).to eq(5)
      expect(cooldown.cooldown_type).to eq("minutes")
      expect(cooldown.expires_at).to be_within(6.minutes).of(Time.current)
      expect(cooldown.active?).to be(true)
    end
  end

  describe "#adjust_for_community_changes" do
    let!(:community) { create(:community) }
    let!(:server) { create(:server, community: community) }
    let!(:user) { create(:user) }
    let!(:configuration) { create(:command_configuration, community: community, command_name: "player_command", cooldown_type: "seconds", cooldown_quantity: 2) }
    let(:expires_at) { Time.now.utc + 1.day }

    let(:cooldown_defaults) do
      {
        user_id: user.id,
        community_id: community.id,
        server_id: server.id,
        command_name: "player_command",
        expires_at: expires_at
      }
    end

    it "does not crash when community_id is nil" do
      expect {
        create(:cooldown, cooldown_defaults.merge(community_id: nil, server_id: nil, cooldown_type: "seconds", cooldown_quantity: 2)).reload
      }.not_to raise_error
    end

    it "does not change when configuration matches (seconds)" do
      cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "seconds", cooldown_quantity: 2)).reload
      expect(cooldown.expires_at.to_s).to eq(expires_at.to_s)
    end

    it "does not change when configuration matches (times)" do
      configuration.update!(cooldown_type: "times", cooldown_quantity: 1)
      cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "times", cooldown_quantity: 1)).reload
      expect(cooldown.expires_at.to_s).to eq(expires_at.to_s)
      expect(cooldown.cooldown_amount).to eq(0)
    end

    it "resets when changing from seconds to times" do
      configuration.update!(cooldown_type: "times", cooldown_quantity: 1)
      cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "seconds", cooldown_quantity: 2)).reload
      expect(cooldown.expires_at.to_s).not_to eq(expires_at.to_s)
      expect(cooldown.cooldown_amount).to eq(0)
    end

    it "resets when changing from times to seconds" do
      configuration.update!(cooldown_type: "seconds", cooldown_quantity: 2)
      cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "times", cooldown_quantity: 1)).reload
      expect(cooldown.expires_at.to_s).not_to eq(expires_at.to_s)
      expect(cooldown.cooldown_amount).to eq(0)
    end

    it "does not change when new value is greater than current" do
      configuration.update!(cooldown_type: "seconds", cooldown_quantity: 5)
      cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "seconds", cooldown_quantity: 2)).reload
      expect(cooldown.expires_at.to_s).to eq(expires_at.to_s)
    end

    context "when new value is less than current" do
      let(:expires_at) { Time.parse("2040-01-01 00:00:00 UTC") }

      it "compensates from 5 seconds to 2 seconds" do
        configuration.update!(cooldown_type: "seconds", cooldown_quantity: 2)
        cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "seconds", cooldown_quantity: 5, expires_at: expires_at)).reload
        expect(cooldown.expires_at.to_s).to eq("2039-12-31 23:59:57 UTC")
      end

      it "compensates from 1 minute to 30 seconds" do
        configuration.update!(cooldown_type: "seconds", cooldown_quantity: 30)
        cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "minutes", cooldown_quantity: 1, expires_at: expires_at)).reload
        expect(cooldown.expires_at.to_s).to eq("2039-12-31 23:59:30 UTC")
      end

      it "compensates from 1 hour to 15 seconds" do
        configuration.update!(cooldown_type: "seconds", cooldown_quantity: 15)
        cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "hour", cooldown_quantity: 1, expires_at: expires_at)).reload
        expect(cooldown.expires_at.to_s).to eq("2039-12-31 23:00:15 UTC")
      end

      it "compensates from 1 day to 2 minutes" do
        configuration.update!(cooldown_type: "minutes", cooldown_quantity: 2)
        cooldown = create(:cooldown, cooldown_defaults.merge(cooldown_type: "days", cooldown_quantity: 1, expires_at: expires_at)).reload
        expect(cooldown.expires_at.to_s).to eq("2039-12-31 00:02:00 UTC")
      end
    end
  end
end
All opinions represented herein are my own
- © 2024 - 2026 itsthedevman
- build 43aa0d7