378 lines
14 KiB
Ruby

RSpec.describe Play, type: :model do
before(:all) do
@game = setup_game
@play = @game.controlling_player.plays.new
@play.game_id = @game.id
@play.save
end
after(:each) do
#reset game
@game.reload
@game.play_to_beat_id = nil
# reset play
@play.reload
@play.errors[:player_cards].clear
@play.game = @game
end
subject { @play }
it { should respond_to(:game_id) }
it { should respond_to(:game) }
it { should respond_to(:player_id) }
it { should respond_to(:player) }
it { should respond_to(:player_cards) }
it { should respond_to(:hand) }
it { should respond_to(:hand_type) }
it { should respond_to(:to_s) }
it '#game_id returns a game id' do
expect(@play.game).to eq Game.find(@play.game_id)
end
it '#player_id return a player id' do
expect(@play.player).to eq Player.find(@play.player_id)
end
it '#player_cards returns a PlayerCard collection' do
expect(@play.player_cards.class).to eq(PlayerCard::ActiveRecord_Associations_CollectionProxy)
end
it '#hand returns a PlayerCard collection' do
expect(@play.hand.class).to eq(PlayerCard::ActiveRecord_Associations_CollectionProxy)
end
it '#hand_type returns a string' do
@play.player_cards << create_hand(1, 'single')
expect(@play.hand_type).to eq 'single'
end
it '#to_s returns a string of the hand' do
@play.player_cards << create_hand(1, 'single')
expect(@play.to_s).to eq '3 Spade'
end
describe 'validations' do
describe 'first_play' do
it 'valid if it contains the lowest card' do
# expect(@game.plays.count).to eq(1)
# Active player is the lowest card holder
expect(@game.controlling_player).to eq(@game.lowest_card.player)
# Play the lowest card
@cards_to_play = @game.controlling_player.player_cards.order(:value).first
@play.player_cards << @cards_to_play
#@play.save
expect(@play.player_cards.include? @game.lowest_card).to eq true
expect(subject.valid?).to eq(true)
end
end
describe 'wins?' do
context 'it does not beat the hand_to_beat' do
it 'single' do
# Play a high single card
@cards_to_play = @play.player.player_cards.order(:value).last
@play.reload
@play.player_cards << @cards_to_play
@play.save
@game.reload
# Try to play a losing card
@losing_play = Play.new
@losing_play.player = @game.players.where.not(id: @game.controlling_player_id).last
@losing_play.game = @game
@losing_play.player_cards << @losing_play.player.player_cards.order(:value).first
expect(@losing_play.beats? @play).to eq(false)
expect(@losing_play.hand_valid?).to eq(false)
expect(@losing_play.save).to eq(false)
expect(@losing_play.errors[:player_cards].include?('invalid hand')).to eq(true)
expect(@game.play_to_beat.play).to eq(@play)
expect(@game.player_to_beat).to eq(@play.player)
end
it 'double' do
@deck = Deck.new
@cards_to_beat = [
@spade5 = PlayerCard.new(@deck.cards[8].instance_values),
@club5 = PlayerCard.new(@deck.cards[9].instance_values)
]
@play_to_beat = Play.new
@play_to_beat.player = @game.players.where.not(id: @game.controlling_player_id).first
@play_to_beat.player_cards << @cards_to_beat
@play_to_beat.game = @game
#@play_to_beat.save
@play.player_cards = [
@spade4 = PlayerCard.new(@deck.cards[4].instance_values),
@club4 = PlayerCard.new(@deck.cards[5].instance_values)
]
# Shared tests
[@play_to_beat,@play].each do |play|
expect(play.errors[:player_cards]).to eq([])
expect(play.hand_type).to eq('double')
expect(play.player_cards.length).to eq(2)
end
@play.reload
@game.reload
binding.pry unless !@play.valid?
expect(@play.valid?).to eq(false)
expect(@play.beats? @play_to_beat).to eq(false)
end
it 'mismatch type' do
@deck = Deck.new
# Hand to beat is a double
@cards_to_beat = [
@spade4 = PlayerCard.new(@deck.cards[4].instance_values),
@club4 = PlayerCard.new(@deck.cards[5].instance_values)
]
@play_to_beat = Play.new
@play_to_beat.player = @game.players.where.not(id: @game.controlling_player_id).first
@play_to_beat.player_cards << @cards_to_beat
@play_to_beat.game = @game
#@play_to_beat.save
# Attempt to play a single
@play.player_cards = [
@spade5 = PlayerCard.new(@deck.cards[8].instance_values)
]
@play.reload
@game.reload
binding.pry unless !@play.valid?
expect(@play.valid?).to eq(false)
end
end
context 'it beats the hand_to_beat' do
it 'single' do
# current player plays their lowest card
@cards_to_play = @play.player.player_cards.order(:value).first
@play.player_cards << @cards_to_play
@play.save
@game.reload
# next player plays their lowest card and beats the previous play
@cards_to_play = @play.player.player_cards.order(:value).first
@play.player_cards << @cards_to_play
expect(@play.valid?).to eq(true)
@play.save
@game.reload
expect(@game.play_to_beat.play).to eq(@play)
expect(@play.errors[:player_cards]).to eq([])
end
it 'double' do
@deck = Deck.new
# Give 3 of clubs to current player
@club3 = @game.player_cards.find_by(value: 2)
@club3.player_id = @game.controlling_player.id
@club3.save
@cards_to_beat = [
@spade3 = @game.controlling_player.player_cards.order(:value).first,
@club3
]
@play.player_cards << @cards_to_beat
expect(@play.save).to be true
@game.reload
@game.controlling_player_id = @game.next_player_id
@game.save
@game.reload
@winning_play = Play.new
@winning_play.player = @game.controlling_player
@winning_play.game = @game
# Give needed cards to current player
@spade4 = @game.player_cards.find_by(value: 5)
@spade4.player_id = @game.controlling_player.id
@spade4.save
@club4 = @game.player_cards.find_by(value: 6)
@club4.player_id = @game.controlling_player.id
@club4.save
@winning_play.player_cards = [
@spade4,
@club4
]
expect(@winning_play.beats? @play).to eq(true)
expect(@winning_play.save).to be true
end
it 'becomes the new play_to_beat' do
expect(@play.game.play_to_beat).to eq(nil)
# Play the hand
@cards_to_play = @play.player.inventory.first
@play.hand << @cards_to_play
expect(@play.hand_valid?).to eq(true)
expect(@play.save)
expect(@play.game.play_to_beat.play).to eq(@play)
end
end
end
end
describe 'hand_type' do
context 'when a single card is played' do
it 'single' do
@cards_to_play = @game.controlling_player.player_cards.order(:value).first
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('single')
end
end
context 'when two cards are played' do
it 'valid pair' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club3 = PlayerCard.new(rank: "3", suit: "Club")
@cards_to_play = [@spade3, @club3]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('double')
expect(@play.errors[:player_cards]).to eq([])
end
it 'invalid pair' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club4 = PlayerCard.new(rank: "4", suit: "Club")
@cards_to_play = [@spade3, @club4]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('double')
expect(@play.errors[:player_cards]).to eq(['Invalid pair. Rank must match.'])
end
end
context 'when three cards are played' do
it 'valid triple' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club3 = PlayerCard.new(rank: "3", suit: "Club")
@diamond3 = PlayerCard.new(rank: "3", suit: "Diamond")
@cards_to_play = [@spade3, @club3, @diamond3]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('triple')
end
it 'invalid triple' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club3 = PlayerCard.new(rank: "3", suit: "Club")
@diamond4 = PlayerCard.new(rank: "4", suit: "Diamond")
@cards_to_play = [@spade3, @club3, @diamond4]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('triple')
expect(@play.errors[:player_cards]).to eq(['Invalid triple. Rank must match.'])
end
it 'valid run of 3' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club4 = PlayerCard.new(rank: "4", suit: "Club")
@diamond5 = PlayerCard.new(rank: "5", suit: "Diamond")
@cards_to_play = [@spade3, @club4, @diamond5]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('triple run')
end
it 'valid run of 3 suited' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club4 = PlayerCard.new(rank: "4", suit: "Spade")
@diamond5 = PlayerCard.new(rank: "5", suit: "Spade")
@cards_to_play = [@spade3, @club4, @diamond5]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('triple run suited')
end
end
context 'when four cards are played' do
it 'valid bomb' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club3 = PlayerCard.new(rank: "3", suit: "Club")
@diamond3 = PlayerCard.new(rank: "3", suit: "Diamond")
@heart3 = PlayerCard.new(rank: "3", suit: "Heart")
@cards_to_play = [@spade3, @club3, @diamond3, @heart3]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('bomb')
end
it 'valid run of 4' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club4 = PlayerCard.new(rank: "4", suit: "Club")
@diamond5 = PlayerCard.new(rank: "5", suit: "Diamond")
@diamond6 = PlayerCard.new(rank: "6", suit: "Diamond")
@cards_to_play = [@spade3, @club4, @diamond5, @diamond6]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('run of 4')
end
it 'valid run of 4 suited' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club4 = PlayerCard.new(rank: "4", suit: "Spade")
@diamond5 = PlayerCard.new(rank: "5", suit: "Spade")
@diamond6 = PlayerCard.new(rank: "6", suit: "Spade")
@cards_to_play = [@spade3, @club4, @diamond5, @diamond6]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('run of 4 suited')
end
end
context 'when five cards are played' do
it 'valid run of 5' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club4 = PlayerCard.new(rank: "4", suit: "Club")
@diamond5 = PlayerCard.new(rank: "5", suit: "Diamond")
@diamond6 = PlayerCard.new(rank: "6", suit: "Diamond")
@diamond7 = PlayerCard.new(rank: "7", suit: "Diamond")
@cards_to_play = [@spade3, @club4, @diamond5, @diamond6, @diamond7]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('run of 5')
end
it 'invalid run of 5' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club4 = PlayerCard.new(rank: "4", suit: "Club")
@diamond5 = PlayerCard.new(rank: "5", suit: "Diamond")
@diamond6 = PlayerCard.new(rank: "6", suit: "Diamond")
@diamond8 = PlayerCard.new(rank: "8", suit: "Diamond")
@cards_to_play = [@spade3, @club4, @diamond5, @diamond6, @diamond8]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('run of 5')
expect(@play.errors[:player_cards]).to eq(['Invalid run of 5'])
end
it 'valid run of 5 suited' do
@spade3 = PlayerCard.new(rank: "3", suit: "Spade")
@club4 = PlayerCard.new(rank: "4", suit: "Spade")
@diamond5 = PlayerCard.new(rank: "5", suit: "Spade")
@diamond6 = PlayerCard.new(rank: "6", suit: "Spade")
@diamond7 = PlayerCard.new(rank: "7", suit: "Spade")
@cards_to_play = [@spade3, @club4, @diamond5, @diamond6, @diamond7]
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq('run of 5 suited')
end
end
(5..13).each do |i|
context "when #{i} cards are played" do
it "run of #{i}" do
@cards_to_play = create_hand(i, 'run')
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq("run of #{i}")
end
it "run of #{i} suited" do
@cards_to_play = create_hand(i, 'run suited')
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq("run of #{i} suited")
end
if [6, 8, 10].include? i
it "double run of #{i}" do
@cards_to_play = create_hand(i, 'double run')
@play.player_cards << @cards_to_play
expect(@play.hand_type).to eq("double run of #{i}")
expect(@play.errors[:player_cards]).to eq([])
end
end
end
end
end
end