applejuiceteaching
applejuiceteaching

Reputation: 1493

check if attributes includes a certain symbol in RSpec

I have a simple card and deck class

class Card

  attr_accessor :suit, :rank

  def initialize(suit:, rank:)
    @suit = suit
    @rank = case rank
            when :jack then 11
            when :queen then 12
            when :king then 13
            when :ace then 14
            else rank
            end
  end
end

class Deck
  attr_accessor :cards, :suits
  SUITS = [:hearts, :diamonds, :clubs, :spades]

  def initialize
    @cards = []
    (2..14).to_a.product(SUITS).each do |arr|
      @cards << Card.new(rank: arr[0], suit: arr[1])
    end
  end


end

Then a simple RSpec test class

require 'card'


RSpec.describe Card do

  describe 'initialization' do
    let(:card) { Card.new(suit: :hearts, rank: 10) }

    it 'can be made' do
      expect(card.suit).to eq(:spadess).or eq(:hearts).or eq(:diamonds)
    end
  end
end

RSpec.describe Deck do 
  describe 'count' do 
    let(:cards) { Deck.new().cards }
    let(:deck) { Deck.new() }

    it 'is 52' do
      expect(cards.count).to eq(52)
    end

    it 'all has a rank greater than 1' do 
      expect(cards).to all(have_attributes(rank: be >= 1 && be <= 14)).and all(have_attributes(suit: (be == :spades || be == :hearts || be == :diamonds || be ==:clubs) ))
    end

  end
end

I am trying to use Rspec to compare that all the ranks are within a certain range (this works) but whan I am having trouble with is checking if each suit matches one of the 4 suit simples the following produces the error:

object at index 48 failed to match:
  expected #<Card:0x007fbadc0fade0 @suit=:hearts, @rank=14> to have attributes {:suit => (be == spades)}

Upvotes: 0

Views: 255

Answers (1)

Stefan
Stefan

Reputation: 114158

(be == :spades || be == :hearts || be == :diamonds || be ==:clubs)

Is equivalent to

(be == :spades)

Hence the error message

... to have attributes {:suit => (be == spades)}
                                 ^^^^^^^^^^^^^^

You have to use RSpec's or method to chain expectations:

((be == :spades).or (be == :hearts).or (be == :diamonds).or (be == :clubs))

If you implement some predicate methods:

class Card
  # ...

  def hearts?
    suit == :hearts
  end

  # same for spades, diamonds and clubs
end

you can express your intent more naturally:

 it 'contains only hearts, spades, diamonds or clubs' do
   expect(cards).to all(be_hearts.or be_spades.or be_diamonds.or be_clubs)
 end

Upvotes: 2

Related Questions