Skip to content

Instantly share code, notes, and snippets.

@bhserna
Created April 12, 2018 23:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bhserna/882d5101bdaedcef732a0d078ce4f07e to your computer and use it in GitHub Desktop.
Save bhserna/882d5101bdaedcef732a0d078ce4f07e to your computer and use it in GitHub Desktop.
Example of Test contravariance
require "rspec"
module TicTacToe
def self.start_game
Game.new
end
class Game
def initialize
@board = Board.new
end
def players
["x", "o"]
end
def write(player, opts = {})
handle_turn_for(player) do
board.write(player, opts)
end
end
def get_board
board.to_a
end
def has_winner?
!winner.nil?
end
def winner
players.find { |player| is_winner?(player) }
end
private
attr_reader :board
def is_winner?(player)
board.row_for?(player) ||
board.column_for?(player) ||
board.diagonal_for?(player)
end
def handle_turn_for(player)
raise "Not your turn" if player == @last_player
@last_player = player
yield
end
class Board
def initialize
@board = empty_board
end
def write(mark, opts)
index = opts.fetch(:in)
raise "Taken" unless board[index].empty?
self.board[index] = mark
end
def to_a
board
end
def row_for?(mark)
rows.any? { |row| row.all? { |content| content == mark } }
end
def column_for?(mark)
(0..2).any? { |column| rows.all? { |row| row[column] == mark } }
end
def diagonal_for?(mark)
[[0, 4, 8], [2, 4, 6]].any? do |diagonal|
diagonal.all? { |position| board[position] == mark }
end
end
protected
attr_reader :board
def rows
board.each_slice(3)
end
def empty_board
["", "", "",
"", "", "",
"", "", ""]
end
end
end
end
describe TicTacToe do
def start_game
game = TicTacToe.start_game
end
it "has two players" do
game = start_game
expect(game.players).to eq ["x", "o"]
end
it "starts with an empty board" do
game = start_game
expect(game.get_board).to eq [
"", "", "",
"", "", "",
"", "", ""
]
end
it "can't write on an occupied position" do
game = start_game
game.write "x", in: 0
expect { game.write "o", in: 0 }.to raise_error /Taken/
end
it "can't write the same player twice" do
game = start_game
game.write "x", in: 0
expect { game.write "x", in: 0 }.to raise_error /Not your turn/
end
example "first stage" do
game = start_game
game.write "x", in: 0
expect(game.get_board).to eq [
"x", "", "",
"" , "", "",
"" , "", ""
]
game.write "o", in: 4
expect(game.get_board).to eq [
"x", "" , "",
"" , "o", "",
"" , "" , ""
]
expect(game).not_to have_winner
end
example "second stage" do
game = start_game
game.write "x", in: 0
game.write "o", in: 4
game.write "x", in: 2
expect(game.get_board).to eq [
"x", "" , "x",
"" , "o", "" ,
"" , "" , ""
]
game.write "o", in: 5
expect(game.get_board).to eq [
"x", "" , "x",
"" , "o", "o" ,
"" , "" , ""
]
expect(game).not_to have_winner
end
describe "winner in the top row" do
example do
game = start_game
game.write "x", in: 0
game.write "o", in: 4
game.write "x", in: 2
game.write "o", in: 5
game.write "x", in: 1
expect(game.get_board).to eq [
"x", "x", "x",
"" , "o", "o" ,
"" , "" , ""
]
expect(game).to have_winner
expect(game.winner).to eq "x"
end
example do
game = start_game
game.write "o", in: 0
game.write "x", in: 4
game.write "o", in: 2
game.write "x", in: 5
game.write "o", in: 1
expect(game.get_board).to eq [
"o", "o", "o",
"" , "x", "x" ,
"" , "" , ""
]
expect(game).to have_winner
expect(game.winner).to eq "o"
end
end
example "winner in the middle row" do
game = start_game
game.write "x", in: 0
game.write "o", in: 4
game.write "x", in: 2
game.write "o", in: 5
game.write "x", in: 8
game.write "o", in: 3
expect(game.get_board).to eq [
"x", "" , "x",
"o", "o", "o",
"" , "" , "x"
]
expect(game).to have_winner
expect(game.winner).to eq "o"
end
example "winner in the last row" do
game = start_game
game.write "x", in: 0
game.write "o", in: 6
game.write "x", in: 2
game.write "o", in: 7
game.write "x", in: 4
game.write "o", in: 8
expect(game.get_board).to eq [
"x", "" , "x",
"" , "x", "" ,
"o", "o", "o"
]
expect(game).to have_winner
expect(game.winner).to eq "o"
end
example "winner in the first column" do
game = start_game
game.write "x", in: 0
game.write "o", in: 2
game.write "x", in: 3
game.write "o", in: 7
game.write "x", in: 6
expect(game.get_board).to eq [
"x", "" , "o",
"x" ,"" , "",
"x", "o", ""
]
expect(game).to have_winner
expect(game.winner).to eq "x"
end
example "winner in the second column" do
game = start_game
game.write "x", in: 1
game.write "o", in: 2
game.write "x", in: 4
game.write "o", in: 8
game.write "x", in: 7
expect(game.get_board).to eq [
"", "x", "o",
"", "x", "" ,
"", "x", "o"
]
expect(game).to have_winner
expect(game.winner).to eq "x"
end
example "winner in the third column" do
game = start_game
game.write "x", in: 1
game.write "o", in: 2
game.write "x", in: 4
game.write "o", in: 8
game.write "x", in: 6
game.write "o", in: 5
expect(game.get_board).to eq [
"" , "x", "o",
"" , "x", "o",
"x", "" , "o"
]
expect(game).to have_winner
expect(game.winner).to eq "o"
end
example "winner in diagonal" do
game = start_game
game.write "x", in: 0
game.write "o", in: 2
game.write "x", in: 4
game.write "o", in: 5
game.write "x", in: 8
expect(game.get_board).to eq [
"x", "" , "o",
"" , "x", "o",
"" , "" , "x"
]
expect(game).to have_winner
expect(game.winner).to eq "x"
end
example "winner in diagonal (other)" do
game = start_game
game.write "x", in: 2
game.write "o", in: 0
game.write "x", in: 4
game.write "o", in: 5
game.write "x", in: 6
expect(game.get_board).to eq [
"o", "" , "x",
"" , "x", "o",
"x", "" , ""
]
expect(game).to have_winner
expect(game.winner).to eq "x"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment