require "rails_helper" RSpec.describe Match, type: :model do let(:player1) { User.create!(nickname: "player_one", password: "secret123") } let(:player2) { User.create!(nickname: "player_two", password: "secret123") } let(:valid_attributes) do { player1: player1, player2: player2, status: :ongoing, game_server: "ws://game-server:8080/ws", started_at: Time.current, player1_rating_before: 100, player2_rating_before: 100, player1_rating_change: 0, player2_rating_change: 0 } end it "is valid with valid attributes" do expect(Match.new(valid_attributes)).to be_valid end it "generates a uuid automatically" do match = Match.create!(valid_attributes) expect(match.uuid).to match(/\A[0-9a-f-]{36}\z/) end it "belongs to two players" do match = Match.create!(valid_attributes) expect(match.player1).to eq(player1) expect(match.player2).to eq(player2) end it "does not allow the same player on both sides" do match = Match.new(valid_attributes.merge(player2: player1)) expect(match).not_to be_valid expect(match.errors[:player2]).to be_present end it "requires a game_server" do expect(Match.new(valid_attributes.merge(game_server: nil))).not_to be_valid end it "requires started_at" do expect(Match.new(valid_attributes.merge(started_at: nil))).not_to be_valid end it "allows finished_at and duration_seconds to be nil" do expect(Match.new(valid_attributes)).to be_valid end it "rejects negative duration_seconds" do match = Match.new(valid_attributes.merge(duration_seconds: -1)) expect(match).not_to be_valid end it "rejects nil rating changes" do match = Match.new(valid_attributes.merge(player1_rating_change: nil)) expect(match).not_to be_valid end it "allows zero rating changes" do match = Match.new(valid_attributes.merge(player1_rating_change: 0, player2_rating_change: 0)) expect(match).to be_valid end describe "statuses" do it "defines all statuses" do expect(Match.statuses.keys).to contain_exactly( "ongoing", "player1_won", "player2_won", "draw", "abandoned" ) end it "defaults to ongoing" do match = Match.create!(valid_attributes) expect(match.status).to eq("ongoing") end it "supports transitions to final statuses" do match = Match.create!(valid_attributes) match.player1_won! expect(match.reload.status).to eq("player1_won") end end describe ".finished" do it "returns only matches with finished_at set" do finished = Match.create!(valid_attributes.merge(finished_at: Time.current)) Match.create!(valid_attributes) expect(Match.finished).to contain_exactly(finished) end end describe ".for_user" do it "returns matches where the user is either player" do other = User.create!(nickname: "player_three", password: "secret123") m1 = Match.create!(valid_attributes) m2 = Match.create!(valid_attributes.merge(player1: player2, player2: player1)) Match.create!(valid_attributes.merge(player1: player2, player2: other)) expect(Match.for_user(player1)).to contain_exactly(m1, m2) end end end