mirror of
https://github.com/danbee/chess
synced 2025-03-04 08:39:06 +00:00
Compare commits
9 Commits
01471967c8
...
b1451535ca
| Author | SHA1 | Date | |
|---|---|---|---|
| b1451535ca | |||
| e4fc3a1b6f | |||
| 6cecc3005c | |||
| c19f586d13 | |||
| f5641150a0 | |||
| f0ed129028 | |||
| 1a9358d5e0 | |||
| 8f683dd73f | |||
| 69f05a1c5d |
3
.formatter.exs
Normal file
3
.formatter.exs
Normal file
@ -0,0 +1,3 @@
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
35
Dockerfile
Normal file
35
Dockerfile
Normal file
@ -0,0 +1,35 @@
|
||||
FROM --platform=linux/amd64 elixir:1.14.1
|
||||
|
||||
# Create a directory for your application code and set it as the WORKDIR. All following commands will be run in this directory.
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
|
||||
# Update package repo
|
||||
RUN apt-get update
|
||||
|
||||
# Install Chrome
|
||||
RUN wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
|
||||
apt-get -y install ./google-chrome-stable_current_amd64.deb
|
||||
|
||||
# Install ChromeDriver
|
||||
RUN CHROMEDRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \
|
||||
mkdir -p /opt/chromedriver-$CHROMEDRIVER_VERSION && \
|
||||
curl -sS -o /tmp/chromedriver_linux64.zip http://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip && \
|
||||
unzip -qq /tmp/chromedriver_linux64.zip -d /opt/chromedriver-$CHROMEDRIVER_VERSION && \
|
||||
rm /tmp/chromedriver_linux64.zip && \
|
||||
chmod +x /opt/chromedriver-$CHROMEDRIVER_VERSION/chromedriver && \
|
||||
ln -fs /opt/chromedriver-$CHROMEDRIVER_VERSION/chromedriver /usr/local/bin/chromedriver
|
||||
|
||||
# Install Rebar and Hex
|
||||
RUN mix local.rebar --force && mix local.hex --force
|
||||
|
||||
# Install the Phoenix Mix archive
|
||||
RUN mix archive.install --sha512 2a2f5167f5ea30f314500da449dbd8cfb4b6986cc27197c82fa4cc328798814f89a4dbe0183a5f213faed3587e8133ce99c1fab74cf1597978a270bdcc7bf789 --force https://github.com/phoenixframework/archives/raw/master/phx_new.ez
|
||||
|
||||
# COPY mix.exs and mix.lock and install dependencies before adding the full code so the cache only
|
||||
# gets invalidated when dependencies are changed
|
||||
COPY mix.exs mix.lock ./
|
||||
RUN mix deps.get
|
||||
|
||||
# Copy the app source code into the image
|
||||
COPY ./ /app
|
||||
@ -6,8 +6,8 @@ source /dev/stdin <<< "$(curl -sSL https://raw.githubusercontent.com/codeship/sc
|
||||
echo "Installing Elixir"
|
||||
source /dev/stdin <<< "$(curl -sSL https://raw.githubusercontent.com/codeship/scripts/master/languages/elixir.sh)"
|
||||
|
||||
echo "Installing PhantomJS"
|
||||
curl -sSL https://raw.githubusercontent.com/codeship/scripts/master/packages/phantomjs.sh | bash -s
|
||||
echo "Installing ChromeDriver"
|
||||
curl -sSL https://raw.githubusercontent.com/codeship/scripts/master/packages/chromedriver.sh | bash -s
|
||||
|
||||
echo "Installing NodeJS"
|
||||
nvm install $NODE_VERSION
|
||||
|
||||
18
codeship-services.yml
Normal file
18
codeship-services.yml
Normal file
@ -0,0 +1,18 @@
|
||||
# Docker Compose-like syntax, see here for details:
|
||||
# https://documentation.codeship.com/pro/builds-and-configuration/services/
|
||||
app:
|
||||
build:
|
||||
image: danbee/chess
|
||||
dockerfile: Dockerfile
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
PGHOST: db
|
||||
PGUSER: postgres
|
||||
PGPASSWORD: password
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: healthcheck/postgres:alpine
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: password
|
||||
9
codeship-steps.yml
Normal file
9
codeship-steps.yml
Normal file
@ -0,0 +1,9 @@
|
||||
# This is where we define the test steps that would be run in a Codeship Pro build.
|
||||
# The build passes as long as every test step returns with a non-zero exit code.
|
||||
# See here for more: https://documentation.codeship.com/pro/builds-and-configuration/steps/
|
||||
- name: build_assets
|
||||
command: bin/codeship_assets
|
||||
service: app
|
||||
- name: run_mix_test
|
||||
command: /bin/bash -c 'mix ecto.create && mix test'
|
||||
service: app
|
||||
@ -30,6 +30,7 @@ config :chess, Chess.Auth.Guardian,
|
||||
secret_key: "vd2vXkrYTTFKSKmNMoS2/Hk4Fxn8BkyzsVArRkxJazdQ3mr6bI4YgAC6f8ODiWlM"
|
||||
|
||||
config :formulator,
|
||||
validate: false,
|
||||
translate_error_module: ChessWeb.ErrorHelpers
|
||||
|
||||
# Configure esbuild (the version is required)
|
||||
|
||||
@ -18,7 +18,7 @@ config :chess, Chess.Mailer, adapter: Bamboo.TestAdapter
|
||||
config :chess, Chess.Repo,
|
||||
adapter: Ecto.Adapters.Postgres,
|
||||
database: "chess_test",
|
||||
hostname: "localhost",
|
||||
hostname: System.get_env("PGHOST") || "localhost",
|
||||
port: System.get_env("POSTGRES_PORT") || "5432",
|
||||
pool: Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
|
||||
19
docker-compose.yml
Normal file
19
docker-compose.yml
Normal file
@ -0,0 +1,19 @@
|
||||
version: '3'
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
command: /bin/bash -c 'mix ecto.create && mix phx.server'
|
||||
ports:
|
||||
- "4000:4000"
|
||||
environment:
|
||||
MIX_ENV: dev
|
||||
PGHOST: db
|
||||
PGUSER: postgres
|
||||
PGPASSWORD: password
|
||||
links:
|
||||
- db
|
||||
db:
|
||||
image: healthcheck/postgres:alpine
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: password
|
||||
@ -11,7 +11,7 @@ defmodule Chess do
|
||||
{Phoenix.PubSub, [name: Chess.PubSub, adapter: Phoenix.PubSub.PG2]},
|
||||
{Chess.Repo, []},
|
||||
{ChessWeb.Endpoint, []},
|
||||
{ChessWeb.Presence, []},
|
||||
{ChessWeb.Presence, []}
|
||||
]
|
||||
|
||||
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
|
||||
|
||||
@ -12,6 +12,7 @@ defmodule Chess.Auth.ErrorHandler do
|
||||
|> put_flash(:info, "You must be logged in")
|
||||
|> redirect(to: "/")
|
||||
|> halt()
|
||||
|
||||
"json" ->
|
||||
conn
|
||||
|> put_status(403)
|
||||
|
||||
@ -10,8 +10,9 @@ defmodule Chess.Auth.Guardian do
|
||||
end
|
||||
|
||||
def resource_from_claims(claims) do
|
||||
user = claims["sub"]
|
||||
|> Auth.get_user!
|
||||
user =
|
||||
claims["sub"]
|
||||
|> Auth.get_user!()
|
||||
|
||||
{:ok, user}
|
||||
end
|
||||
|
||||
@ -7,11 +7,11 @@ defmodule Chess.Auth.Pipeline do
|
||||
module: Chess.Auth.Guardian
|
||||
|
||||
# If there is a session token, validate it
|
||||
plug Guardian.Plug.VerifySession, claims: %{"typ" => "access"}
|
||||
plug(Guardian.Plug.VerifySession, claims: %{"typ" => "access"})
|
||||
|
||||
# If there is an authorization header, validate it
|
||||
plug Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"}
|
||||
plug(Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"})
|
||||
|
||||
# Load the user if either of the verifications worked
|
||||
plug Guardian.Plug.LoadResource, allow_blank: true
|
||||
plug(Guardian.Plug.LoadResource, allow_blank: true)
|
||||
end
|
||||
|
||||
@ -2,8 +2,8 @@ defmodule Chess.Board do
|
||||
@moduledoc false
|
||||
|
||||
def transform(board) do
|
||||
Enum.map(0..7, fn (rank) ->
|
||||
Enum.map(0..7, fn (file) ->
|
||||
Enum.map(0..7, fn rank ->
|
||||
Enum.map(0..7, fn file ->
|
||||
board
|
||||
|> piece({file, rank})
|
||||
end)
|
||||
@ -12,7 +12,7 @@ defmodule Chess.Board do
|
||||
|
||||
def search(board, %{"type" => type, "colour" => colour}) do
|
||||
board
|
||||
|> Enum.filter(fn({_index, piece}) ->
|
||||
|> Enum.filter(fn {_index, piece} ->
|
||||
match?(%{"type" => ^type, "colour" => ^colour}, piece)
|
||||
end)
|
||||
|> indexes_to_tuples
|
||||
@ -20,7 +20,7 @@ defmodule Chess.Board do
|
||||
|
||||
def search(board, %{"colour" => colour}) do
|
||||
board
|
||||
|> Enum.filter(fn({_index, piece}) ->
|
||||
|> Enum.filter(fn {_index, piece} ->
|
||||
match?(%{"colour" => ^colour}, piece)
|
||||
end)
|
||||
|> indexes_to_tuples
|
||||
@ -31,9 +31,9 @@ defmodule Chess.Board do
|
||||
end
|
||||
|
||||
def move_piece(board, %{
|
||||
"from" => [from_file, from_rank],
|
||||
"to" => [to_file, to_rank]
|
||||
}) do
|
||||
"from" => [from_file, from_rank],
|
||||
"to" => [to_file, to_rank]
|
||||
}) do
|
||||
{piece, board} = Map.pop(board, to_index({from_file, from_rank}))
|
||||
{piece_captured, board} = Map.pop(board, to_index({to_file, to_rank}))
|
||||
board = Map.put(board, to_index({to_file, to_rank}), piece)
|
||||
@ -55,39 +55,40 @@ defmodule Chess.Board do
|
||||
to: %{"file" => to_file, "rank" => to_rank},
|
||||
board: board,
|
||||
piece: piece,
|
||||
piece_captured: piece_captured,
|
||||
piece_captured: piece_captured
|
||||
}
|
||||
end
|
||||
|
||||
def castling_move?(%{"type" => "king"}, 4, to_file) do
|
||||
to_file == 2 || to_file == 6
|
||||
end
|
||||
|
||||
def castling_move?(_, _, _), do: false
|
||||
|
||||
def castling_move(board, %{"from" => [4, rank], "to" => [2, _rank]}) do
|
||||
move_piece(board, %{
|
||||
"from" => [0, rank],
|
||||
"to" => [3, rank],
|
||||
"to" => [3, rank]
|
||||
})
|
||||
end
|
||||
|
||||
def castling_move(board, %{"from" => [4, rank], "to" => [6, _rank]}) do
|
||||
move_piece(board, %{
|
||||
"from" => [7, rank],
|
||||
"to" => [5, rank],
|
||||
"to" => [5, rank]
|
||||
})
|
||||
end
|
||||
|
||||
def default do
|
||||
%{
|
||||
"0,7" => %{"type" => "rook", "colour" => "black"},
|
||||
"0,7" => %{"type" => "rook", "colour" => "black"},
|
||||
"1,7" => %{"type" => "knight", "colour" => "black"},
|
||||
"2,7" => %{"type" => "bishop", "colour" => "black"},
|
||||
"3,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"4,7" => %{"type" => "king", "colour" => "black"},
|
||||
"3,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"4,7" => %{"type" => "king", "colour" => "black"},
|
||||
"5,7" => %{"type" => "bishop", "colour" => "black"},
|
||||
"6,7" => %{"type" => "knight", "colour" => "black"},
|
||||
"7,7" => %{"type" => "rook", "colour" => "black"},
|
||||
|
||||
"7,7" => %{"type" => "rook", "colour" => "black"},
|
||||
"0,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
"1,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
"2,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
@ -96,7 +97,6 @@ defmodule Chess.Board do
|
||||
"5,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
"6,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
"7,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
|
||||
"0,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
"1,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
"2,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
@ -105,15 +105,14 @@ defmodule Chess.Board do
|
||||
"5,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
"6,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
"7,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"1,0" => %{"type" => "knight", "colour" => "white"},
|
||||
"2,0" => %{"type" => "bishop", "colour" => "white"},
|
||||
"3,0" => %{"type" => "queen", "colour" => "white"},
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,0" => %{"type" => "queen", "colour" => "white"},
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"5,0" => %{"type" => "bishop", "colour" => "white"},
|
||||
"6,0" => %{"type" => "knight", "colour" => "white"},
|
||||
"7,0" => %{"type" => "rook", "colour" => "white"}
|
||||
"7,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
end
|
||||
|
||||
@ -123,13 +122,13 @@ defmodule Chess.Board do
|
||||
|
||||
defp indexes_to_tuples(list) do
|
||||
list
|
||||
|> Enum.map(fn({index, _piece}) -> index_to_tuple(index) end)
|
||||
|> Enum.map(fn {index, _piece} -> index_to_tuple(index) end)
|
||||
end
|
||||
|
||||
defp index_to_tuple(index) do
|
||||
index
|
||||
|> String.split(",")
|
||||
|> Enum.map(&(String.to_integer(&1)))
|
||||
|> List.to_tuple
|
||||
|> Enum.map(&String.to_integer(&1))
|
||||
|> List.to_tuple()
|
||||
end
|
||||
end
|
||||
|
||||
@ -12,9 +12,7 @@ defmodule Chess.Emails do
|
||||
new_email()
|
||||
|> to(game.opponent)
|
||||
|> from({"64squares", "games@64squares.club"})
|
||||
|> subject(
|
||||
"[64squares] #{game.user.name} has invited you to play a game of chess."
|
||||
)
|
||||
|> subject("[64squares] #{game.user.name} has invited you to play a game of chess.")
|
||||
|> text_body("""
|
||||
Game link: #{Helpers.game_url(conn, :show, game)}
|
||||
""")
|
||||
@ -27,9 +25,7 @@ defmodule Chess.Emails do
|
||||
new_email()
|
||||
|> to(opponent)
|
||||
|> from({"64squares", "games@64squares.club"})
|
||||
|> subject(
|
||||
"[64squares] #{user.name} has moved."
|
||||
)
|
||||
|> subject("[64squares] #{user.name} has moved.")
|
||||
|> text_body("""
|
||||
Game link: #{Helpers.game_url(socket, :show, game)}
|
||||
""")
|
||||
|
||||
@ -14,11 +14,15 @@ defmodule Chess.GameState do
|
||||
cond do
|
||||
player_checkmated?(board, colour) ->
|
||||
"checkmate"
|
||||
|
||||
player_stalemated?(board, colour) ->
|
||||
"stalemate"
|
||||
|
||||
king_in_check?(board, colour) ->
|
||||
"check"
|
||||
true -> nil
|
||||
|
||||
true ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@ -36,7 +40,7 @@ defmodule Chess.GameState do
|
||||
king =
|
||||
board
|
||||
|> Board.search(%{"type" => "king", "colour" => colour})
|
||||
|> List.first
|
||||
|> List.first()
|
||||
|
||||
if is_nil(king) do
|
||||
raise "There is no #{colour} king!"
|
||||
@ -49,7 +53,7 @@ defmodule Chess.GameState do
|
||||
def player_cannot_move?(board, colour) do
|
||||
board
|
||||
|> Board.search(%{"colour" => colour})
|
||||
|> Enum.all?(fn({file, rank}) ->
|
||||
|> Enum.all?(fn {file, rank} ->
|
||||
board
|
||||
|> piece_cannot_move?({file, rank})
|
||||
end)
|
||||
@ -62,7 +66,7 @@ defmodule Chess.GameState do
|
||||
|
||||
board
|
||||
|> Moves.available({file, rank})
|
||||
|> Enum.all?(fn({to_file, to_rank}) ->
|
||||
|> Enum.all?(fn {to_file, to_rank} ->
|
||||
board
|
||||
|> Board.move_piece(%{"from" => [file, rank], "to" => [to_file, to_rank]})
|
||||
|> Map.get(:board)
|
||||
|
||||
@ -5,7 +5,7 @@ defmodule Chess.MoveList do
|
||||
|
||||
def transform(moves) do
|
||||
moves
|
||||
|> Enum.map(&(Move.transform(&1)))
|
||||
|> Enum.map(&Move.transform(&1))
|
||||
|> Enum.chunk_every(2)
|
||||
end
|
||||
end
|
||||
|
||||
@ -19,10 +19,10 @@ defmodule Chess.Moves do
|
||||
game.board
|
||||
|> Board.move_piece(move_params)
|
||||
|
||||
Multi.new
|
||||
Multi.new()
|
||||
|> Multi.update(:game, Game.move_changeset(game, params))
|
||||
|> Multi.insert(:move, Ecto.build_assoc(game, :moves, params))
|
||||
|> Repo.transaction
|
||||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
def available(board, {file, rank}, move_list \\ []) do
|
||||
@ -33,14 +33,19 @@ defmodule Chess.Moves do
|
||||
case piece do
|
||||
%{"type" => "pawn"} ->
|
||||
Pawn.moves(board, {file, rank})
|
||||
|
||||
%{"type" => "rook"} ->
|
||||
Rook.moves(board, {file, rank})
|
||||
|
||||
%{"type" => "bishop"} ->
|
||||
Bishop.moves(board, {file, rank})
|
||||
|
||||
%{"type" => "knight"} ->
|
||||
Knight.moves(board, {file, rank})
|
||||
|
||||
%{"type" => "king"} ->
|
||||
King.moves(board, {file, rank}, move_list)
|
||||
|
||||
%{"type" => "queen"} ->
|
||||
Queen.moves(board, {file, rank})
|
||||
end
|
||||
|
||||
@ -22,13 +22,17 @@ defmodule Chess.Moves.Generator do
|
||||
defp _moves(_colour, _board, {_file, 0}, {_, -1}), do: []
|
||||
defp _moves(_colour, _board, {7, _rank}, {1, _}), do: []
|
||||
defp _moves(_colour, _board, {_file, 7}, {_, 1}), do: []
|
||||
|
||||
defp _moves(colour, board, {file, rank}, {fv, rv}) do
|
||||
next_square = {file + fv, rank + rv}
|
||||
|
||||
cond do
|
||||
can_capture_piece?(colour, board, next_square) ->
|
||||
[next_square]
|
||||
|
||||
obstruction?(colour, board, next_square) ->
|
||||
[]
|
||||
|
||||
true ->
|
||||
[next_square | _moves(colour, board, next_square, {fv, rv})]
|
||||
end
|
||||
@ -36,14 +40,18 @@ defmodule Chess.Moves.Generator do
|
||||
|
||||
# Move generation for pieces that follow a pattern
|
||||
defp _moves(_colour, _board, {_file, _rank}, []), do: []
|
||||
|
||||
defp _moves(colour, board, {file, rank}, [{fv, rv} | moves]) do
|
||||
move_square = {file + fv, rank + rv}
|
||||
|
||||
cond do
|
||||
outside_board?(move_square) ||
|
||||
obstruction?(colour, board, move_square) ->
|
||||
obstruction?(colour, board, move_square) ->
|
||||
_moves(colour, board, {file, rank}, moves)
|
||||
|
||||
can_capture_piece?(colour, board, move_square) ->
|
||||
[move_square | _moves(colour, board, {file, rank}, moves)]
|
||||
|
||||
true ->
|
||||
[move_square | _moves(colour, board, {file, rank}, moves)]
|
||||
end
|
||||
@ -66,6 +74,7 @@ defmodule Chess.Moves.Generator do
|
||||
piece =
|
||||
board
|
||||
|> Board.piece({file, rank})
|
||||
|
||||
piece && piece["colour"] == colour
|
||||
end
|
||||
end
|
||||
|
||||
@ -28,7 +28,7 @@ defmodule Chess.Moves.Piece do
|
||||
end
|
||||
|
||||
defp attacked_by_knight?(board, {file, rank}) do
|
||||
_attacked?(board, {file, rank}, Knight.pattern, "knight")
|
||||
_attacked?(board, {file, rank}, Knight.pattern(), "knight")
|
||||
end
|
||||
|
||||
defp attacked_by_pawn?(board, {file, rank}) do
|
||||
@ -46,22 +46,24 @@ defmodule Chess.Moves.Piece do
|
||||
board
|
||||
|> Generator.moves({file, rank}, pattern)
|
||||
|
||||
Enum.any?(moves, &(match_piece(board, &1, "pawn")))
|
||||
Enum.any?(moves, &match_piece(board, &1, "pawn"))
|
||||
end
|
||||
|
||||
defp _attacked?(_board, {0, _rank}, {-1, _}, _), do: false
|
||||
defp _attacked?(_board, {_file, 0}, {_, -1}, _), do: false
|
||||
defp _attacked?(_board, {7, _rank}, {1, _}, _), do: false
|
||||
defp _attacked?(_board, {_file, 7}, {_, 1}, _), do: false
|
||||
|
||||
defp _attacked?(board, {file, rank}, {fv, rv}, pieces) do
|
||||
board
|
||||
|> Generator.moves({file, rank}, {fv, rv})
|
||||
|> List.last
|
||||
|> List.last()
|
||||
|> case do
|
||||
{file, rank} ->
|
||||
piece = board["#{file},#{rank}"]
|
||||
|
||||
Enum.any?(pieces, &(match?(%{"type" => ^&1}, piece)))
|
||||
Enum.any?(pieces, &match?(%{"type" => ^&1}, piece))
|
||||
|
||||
nil ->
|
||||
false
|
||||
end
|
||||
@ -72,7 +74,7 @@ defmodule Chess.Moves.Piece do
|
||||
board
|
||||
|> Generator.moves({file, rank}, pattern)
|
||||
|
||||
Enum.any?(moves, &(match_piece(board, &1, piece_type)))
|
||||
Enum.any?(moves, &match_piece(board, &1, piece_type))
|
||||
end
|
||||
|
||||
defp match_piece(board, {file, rank}, piece_type) do
|
||||
|
||||
@ -18,12 +18,13 @@ defmodule Chess.Moves.Pieces.King.Castling do
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def moves(_board, _piece, _move_list), do: []
|
||||
|
||||
def _moves(board, _rank, colour, move_list) do
|
||||
board
|
||||
|> Board.search(%{"type" => "rook", "colour" => colour})
|
||||
|> Enum.map(fn ({file, rank}) ->
|
||||
|> Enum.map(fn {file, rank} ->
|
||||
case file do
|
||||
0 -> queen_side_move(board, rank, colour, move_list)
|
||||
7 -> king_side_move(board, rank, colour, move_list)
|
||||
@ -35,42 +36,48 @@ defmodule Chess.Moves.Pieces.King.Castling do
|
||||
|
||||
defp king_has_moved?(move_list, colour) do
|
||||
move_list
|
||||
|> Enum.any?(fn (move) ->
|
||||
match?(%Move{
|
||||
piece: %{"type" => "king", "colour" => ^colour}
|
||||
}, move)
|
||||
|> Enum.any?(fn move ->
|
||||
match?(
|
||||
%Move{
|
||||
piece: %{"type" => "king", "colour" => ^colour}
|
||||
},
|
||||
move
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
defp queen_side_move(board, rank, colour, move_list) do
|
||||
if queen_side_squares_empty?(board, rank) &&
|
||||
!queen_side_in_check?(board, rank, colour) &&
|
||||
!rook_has_moved?(0, move_list, colour) do
|
||||
!queen_side_in_check?(board, rank, colour) &&
|
||||
!rook_has_moved?(0, move_list, colour) do
|
||||
{2, rank}
|
||||
end
|
||||
end
|
||||
|
||||
defp king_side_move(board, rank, colour, move_list) do
|
||||
if king_side_squares_empty?(board, rank) &&
|
||||
!king_side_in_check?(board, rank, colour) &&
|
||||
!rook_has_moved?(7, move_list, colour) do
|
||||
!king_side_in_check?(board, rank, colour) &&
|
||||
!rook_has_moved?(7, move_list, colour) do
|
||||
{6, rank}
|
||||
end
|
||||
end
|
||||
|
||||
defp rook_has_moved?(file, move_list, colour) do
|
||||
move_list
|
||||
|> Enum.any?(fn (move) ->
|
||||
match?(%Move{
|
||||
piece: %{"type" => "rook", "colour" => ^colour},
|
||||
from: %{"file" => ^file},
|
||||
}, move)
|
||||
|> Enum.any?(fn move ->
|
||||
match?(
|
||||
%Move{
|
||||
piece: %{"type" => "rook", "colour" => ^colour},
|
||||
from: %{"file" => ^file}
|
||||
},
|
||||
move
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
defp queen_side_in_check?(board, rank, colour) do
|
||||
[{2, rank}, {3, rank}]
|
||||
|> Enum.any?(fn ({to_file, to_rank}) ->
|
||||
|> Enum.any?(fn {to_file, to_rank} ->
|
||||
board
|
||||
|> Board.move_piece(%{"from" => [4, rank], "to" => [to_file, to_rank]})
|
||||
|> Map.get(:board)
|
||||
@ -80,7 +87,7 @@ defmodule Chess.Moves.Pieces.King.Castling do
|
||||
|
||||
defp king_side_in_check?(board, rank, colour) do
|
||||
[{5, rank}, {6, rank}]
|
||||
|> Enum.any?(fn ({to_file, to_rank}) ->
|
||||
|> Enum.any?(fn {to_file, to_rank} ->
|
||||
board
|
||||
|> Board.move_piece(%{"from" => [4, rank], "to" => [to_file, to_rank]})
|
||||
|> Map.get(:board)
|
||||
|
||||
@ -37,8 +37,10 @@ defmodule Chess.Moves.Pieces.Pawn do
|
||||
cond do
|
||||
obstruction?(board, {file, rank + 1}) ->
|
||||
[]
|
||||
|
||||
rank == 1 ->
|
||||
[{file, rank + 1} | _moves("white", board, {file, rank + 1})]
|
||||
|
||||
true ->
|
||||
[{file, rank + 1}]
|
||||
end
|
||||
@ -48,16 +50,20 @@ defmodule Chess.Moves.Pieces.Pawn do
|
||||
cond do
|
||||
obstruction?(board, {file, rank - 1}) ->
|
||||
[]
|
||||
|
||||
rank == 6 ->
|
||||
[{file, rank - 1} | _moves("black", board, {file, rank - 1})]
|
||||
|
||||
true ->
|
||||
[{file, rank - 1}]
|
||||
end
|
||||
end
|
||||
|
||||
def _capture_moves(_colour, _board, {_file, _rank}, []), do: []
|
||||
|
||||
def _capture_moves(colour, board, {file, rank}, [{fv, rv} | moves]) do
|
||||
move_square = {file + fv, rank + rv}
|
||||
|
||||
if can_capture_piece?(colour, board, move_square) do
|
||||
[move_square | _capture_moves(colour, board, {file, rank}, moves)]
|
||||
else
|
||||
|
||||
28
lib/chess/release.ex
Normal file
28
lib/chess/release.ex
Normal file
@ -0,0 +1,28 @@
|
||||
defmodule Chess.Release do
|
||||
@moduledoc """
|
||||
Used for executing DB release tasks when run in production without Mix
|
||||
installed.
|
||||
"""
|
||||
@app :chess
|
||||
|
||||
def migrate do
|
||||
load_app()
|
||||
|
||||
for repo <- repos() do
|
||||
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
|
||||
end
|
||||
end
|
||||
|
||||
def rollback(repo, version) do
|
||||
load_app()
|
||||
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
|
||||
end
|
||||
|
||||
defp repos do
|
||||
Application.fetch_env!(@app, :ecto_repos)
|
||||
end
|
||||
|
||||
defp load_app do
|
||||
Application.load(@app)
|
||||
end
|
||||
end
|
||||
@ -23,7 +23,7 @@ defmodule Chess.Repo.Queries do
|
||||
|
||||
def opponents(user, query_string) do
|
||||
user
|
||||
|> User.opponents
|
||||
|> User.opponents()
|
||||
|> User.matches(query_string)
|
||||
end
|
||||
end
|
||||
|
||||
@ -14,14 +14,14 @@ defmodule Chess.Store.Game do
|
||||
alias Chess.Store.User
|
||||
|
||||
schema "games" do
|
||||
field :board, :map, default: Board.default()
|
||||
field :turn, :string, default: "white"
|
||||
field :state, :string
|
||||
field(:board, :map, default: Board.default())
|
||||
field(:turn, :string, default: "white")
|
||||
field(:state, :string)
|
||||
|
||||
belongs_to :user, User
|
||||
belongs_to :opponent, User, references: :id
|
||||
belongs_to(:user, User)
|
||||
belongs_to(:opponent, User, references: :id)
|
||||
|
||||
has_many :moves, Move
|
||||
has_many(:moves, Move)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
@ -55,15 +55,17 @@ defmodule Chess.Store.Game do
|
||||
end
|
||||
|
||||
def for_user_id(user_id) do
|
||||
from game in Game,
|
||||
from(game in Game,
|
||||
where: game.user_id == ^user_id,
|
||||
or_where: game.opponent_id == ^user_id
|
||||
)
|
||||
end
|
||||
|
||||
def check_game_state(changeset) do
|
||||
changeset
|
||||
|> put_change(
|
||||
:state, GameState.state(changeset.changes.board, changeset.changes.turn)
|
||||
:state,
|
||||
GameState.state(changeset.changes.board, changeset.changes.turn)
|
||||
)
|
||||
end
|
||||
|
||||
@ -78,6 +80,7 @@ defmodule Chess.Store.Game do
|
||||
changeset
|
||||
end
|
||||
end
|
||||
|
||||
def validate_king_in_check(changeset, _, _), do: changeset
|
||||
|
||||
def ordered(query) do
|
||||
|
||||
@ -8,13 +8,13 @@ defmodule Chess.Store.Move do
|
||||
alias Chess.Store.Game
|
||||
|
||||
schema "moves" do
|
||||
field :from, :map
|
||||
field :to, :map
|
||||
field(:from, :map)
|
||||
field(:to, :map)
|
||||
|
||||
field :piece, :map
|
||||
field :piece_captured, :map
|
||||
field(:piece, :map)
|
||||
field(:piece_captured, :map)
|
||||
|
||||
belongs_to :game, Game
|
||||
belongs_to(:game, Game)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
@ -31,7 +31,7 @@ defmodule Chess.Store.Move do
|
||||
piece: move.piece,
|
||||
piece_captured: move.piece_captured,
|
||||
from: <<97 + move.from["file"], 49 + move.from["rank"]>>,
|
||||
to: <<97 + move.to["file"], 49 + move.to["rank"]>>,
|
||||
to: <<97 + move.to["file"], 49 + move.to["rank"]>>
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@ -76,6 +76,7 @@ defmodule Chess.Store.User do
|
||||
if password do
|
||||
changeset
|
||||
|> change(Argon2.add_hash(password))
|
||||
|> change(password: nil)
|
||||
else
|
||||
changeset
|
||||
end
|
||||
|
||||
@ -31,8 +31,9 @@ defmodule ChessWeb do
|
||||
|
||||
def view do
|
||||
quote do
|
||||
use Phoenix.View, root: "lib/chess_web/templates",
|
||||
namespace: ChessWeb
|
||||
use Phoenix.View,
|
||||
root: "lib/chess_web/templates",
|
||||
namespace: ChessWeb
|
||||
|
||||
# Import convenience functions from controllers
|
||||
import Phoenix.Controller,
|
||||
|
||||
@ -32,7 +32,7 @@ defmodule ChessWeb.GameChannel do
|
||||
board: Board.transform(game.board),
|
||||
turn: game.turn,
|
||||
state: game.state,
|
||||
moves: MoveList.transform(game.moves),
|
||||
moves: MoveList.transform(game.moves)
|
||||
}
|
||||
|
||||
socket
|
||||
@ -57,6 +57,7 @@ defmodule ChessWeb.GameChannel do
|
||||
update_opponent(socket, game)
|
||||
|
||||
{:noreply, socket}
|
||||
|
||||
{:error, :game, changeset, _} ->
|
||||
{message, _} = changeset.errors[:board]
|
||||
|
||||
@ -65,21 +66,26 @@ defmodule ChessWeb.GameChannel do
|
||||
end
|
||||
|
||||
def handle_in(
|
||||
"game:get_available_moves",
|
||||
%{"square" => [file, rank]},
|
||||
socket
|
||||
) do
|
||||
"game:get_available_moves",
|
||||
%{"square" => [file, rank]},
|
||||
socket
|
||||
) do
|
||||
game =
|
||||
socket.assigns.user_id
|
||||
|> Queries.game_with_moves(socket.assigns.game_id)
|
||||
|
||||
moves = Moves.available(game.board, {
|
||||
String.to_integer(file),
|
||||
String.to_integer(rank)
|
||||
}, game.moves)
|
||||
moves =
|
||||
Moves.available(
|
||||
game.board,
|
||||
{
|
||||
String.to_integer(file),
|
||||
String.to_integer(rank)
|
||||
},
|
||||
game.moves
|
||||
)
|
||||
|
||||
reply = %{
|
||||
moves: Enum.map(moves, &(Tuple.to_list(&1)))
|
||||
moves: Enum.map(moves, &Tuple.to_list(&1))
|
||||
}
|
||||
|
||||
{:reply, {:ok, reply}, socket}
|
||||
@ -88,27 +94,29 @@ defmodule ChessWeb.GameChannel do
|
||||
def update_opponent(socket, game) do
|
||||
opponent_id =
|
||||
opponent(game, socket.assigns.user_id).id
|
||||
|> Integer.to_string
|
||||
|> Integer.to_string()
|
||||
|
||||
send_update(socket)
|
||||
|
||||
"game:#{game.id}"
|
||||
|> Presence.list
|
||||
|> Presence.list()
|
||||
|> case do
|
||||
%{^opponent_id => _} ->
|
||||
nil
|
||||
|
||||
_ ->
|
||||
socket
|
||||
|> Emails.opponent_moved_email(game)
|
||||
|> Mailer.deliver_later
|
||||
|> Mailer.deliver_later()
|
||||
end
|
||||
end
|
||||
|
||||
def track_presence(socket) do
|
||||
{:ok, _} = Presence.track(socket, socket.assigns.user_id, %{
|
||||
user_id: socket.assigns.user_id,
|
||||
online_at: inspect(System.system_time(:second))
|
||||
})
|
||||
{:ok, _} =
|
||||
Presence.track(socket, socket.assigns.user_id, %{
|
||||
user_id: socket.assigns.user_id,
|
||||
online_at: inspect(System.system_time(:second))
|
||||
})
|
||||
|
||||
socket
|
||||
|> push("presence_state", Presence.list(socket))
|
||||
@ -116,8 +124,8 @@ defmodule ChessWeb.GameChannel do
|
||||
|
||||
def convert_params(%{"from" => from, "to" => to}) do
|
||||
%{
|
||||
"from" => Enum.map(from, &(String.to_integer(&1))),
|
||||
"to" => Enum.map(to, &(String.to_integer(&1))),
|
||||
"from" => Enum.map(from, &String.to_integer(&1)),
|
||||
"to" => Enum.map(to, &String.to_integer(&1))
|
||||
}
|
||||
end
|
||||
|
||||
@ -130,7 +138,7 @@ defmodule ChessWeb.GameChannel do
|
||||
board: Board.transform(game.board),
|
||||
turn: game.turn,
|
||||
state: game.state,
|
||||
moves: MoveList.transform(game.moves),
|
||||
moves: MoveList.transform(game.moves)
|
||||
}
|
||||
|
||||
ChessWeb.Endpoint.broadcast("game:#{game.id}", "game:update", payload)
|
||||
|
||||
@ -68,6 +68,7 @@ defmodule ChessWeb.Presence do
|
||||
information, while maintaining the required `:metas` field from the
|
||||
original presence data.
|
||||
"""
|
||||
use Phoenix.Presence, otp_app: :chess,
|
||||
pubsub_server: Chess.PubSub
|
||||
use Phoenix.Presence,
|
||||
otp_app: :chess,
|
||||
pubsub_server: Chess.PubSub
|
||||
end
|
||||
|
||||
@ -4,7 +4,7 @@ defmodule ChessWeb.UserSocket do
|
||||
alias Phoenix.Token
|
||||
|
||||
## Channels
|
||||
channel "game:*", ChessWeb.GameChannel
|
||||
channel("game:*", ChessWeb.GameChannel)
|
||||
|
||||
# Socket params are passed from the client and can
|
||||
# be used to verify and authenticate a user. After
|
||||
@ -21,10 +21,12 @@ defmodule ChessWeb.UserSocket do
|
||||
case Token.verify(socket, "game socket", token, max_age: 1_209_600) do
|
||||
{:ok, user_id} ->
|
||||
{:ok, assign(socket, :user_id, user_id)}
|
||||
|
||||
{:error, _reason} ->
|
||||
:error
|
||||
end
|
||||
end
|
||||
|
||||
def connect(%{}, _socket), do: :error
|
||||
|
||||
# Socket id's are topics that allow you to identify all sockets for a given user:
|
||||
|
||||
@ -10,8 +10,8 @@ defmodule ChessWeb.Api.OpponentsController do
|
||||
conn
|
||||
|> current_user()
|
||||
|> Queries.opponents(query_string)
|
||||
|> Repo.all
|
||||
|> Repo.all()
|
||||
|
||||
render conn, "index.json", %{opponents: opponents}
|
||||
render(conn, "index.json", %{opponents: opponents})
|
||||
end
|
||||
end
|
||||
|
||||
@ -15,9 +15,9 @@ defmodule ChessWeb.GameController do
|
||||
conn
|
||||
|> current_user()
|
||||
|> Game.for_user()
|
||||
|> Game.ordered
|
||||
|> Game.ordered()
|
||||
|> preload([:user, :opponent])
|
||||
|> Repo.all
|
||||
|> Repo.all()
|
||||
|
||||
conn
|
||||
|> render("index.html", games: games, changeset: changeset)
|
||||
@ -42,7 +42,7 @@ defmodule ChessWeb.GameController do
|
||||
|> Repo.preload(:user)
|
||||
|> Repo.preload(:opponent)
|
||||
)
|
||||
|> Mailer.deliver_later
|
||||
|> Mailer.deliver_later()
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "Game created successfully.")
|
||||
@ -53,7 +53,7 @@ defmodule ChessWeb.GameController do
|
||||
conn
|
||||
|> current_user()
|
||||
|> User.opponents()
|
||||
|> Repo.all
|
||||
|> Repo.all()
|
||||
|
||||
conn
|
||||
|> render("new.html", changeset: changeset, opponents: opponents)
|
||||
|
||||
@ -22,6 +22,7 @@ defmodule ChessWeb.PasswordController do
|
||||
conn
|
||||
|> put_flash(:info, gettext("Password updated successfully."))
|
||||
|> redirect(to: page_path(conn, :index))
|
||||
|
||||
{:error, changeset} ->
|
||||
render(conn, "edit.html", changeset: changeset)
|
||||
end
|
||||
|
||||
@ -22,6 +22,7 @@ defmodule ChessWeb.ProfileController do
|
||||
conn
|
||||
|> put_flash(:info, gettext("Profile updated successfully."))
|
||||
|> redirect(to: page_path(conn, :index))
|
||||
|
||||
{:error, changeset} ->
|
||||
render(conn, "edit.html", changeset: changeset)
|
||||
end
|
||||
|
||||
@ -18,6 +18,7 @@ defmodule ChessWeb.RegistrationController do
|
||||
|> Guardian.Plug.sign_in(user)
|
||||
|> put_flash(:info, "Registered successfully.")
|
||||
|> redirect(to: page_path(conn, :index))
|
||||
|
||||
{:error, changeset} ->
|
||||
render(conn, "new.html", changeset: changeset)
|
||||
end
|
||||
|
||||
@ -11,17 +11,19 @@ defmodule ChessWeb.SessionController do
|
||||
end
|
||||
|
||||
def create(
|
||||
conn,
|
||||
%{"user" => %{"email" => email, "password" => password}}
|
||||
) do
|
||||
conn,
|
||||
%{"user" => %{"email" => email, "password" => password}}
|
||||
) do
|
||||
case Auth.authenticate_user(email, password) do
|
||||
{:ok, user} ->
|
||||
conn
|
||||
|> Guardian.Plug.sign_in(user)
|
||||
|> put_flash(:info, "You are logged in")
|
||||
|> redirect(to: game_path(conn, :index))
|
||||
|
||||
{:error, _error} ->
|
||||
changeset = User.changeset(%User{})
|
||||
|
||||
conn
|
||||
|> put_flash(:error, "Bad email or password")
|
||||
|> render("new.html", changeset: changeset)
|
||||
|
||||
@ -4,57 +4,53 @@ defmodule ChessWeb.Router do
|
||||
alias Phoenix.Token
|
||||
|
||||
pipeline :browser do
|
||||
plug :accepts, ["html"]
|
||||
plug :fetch_session
|
||||
plug :fetch_flash
|
||||
plug :protect_from_forgery
|
||||
plug :put_secure_browser_headers
|
||||
plug(:accepts, ["html"])
|
||||
plug(:fetch_session)
|
||||
plug(:fetch_flash)
|
||||
plug(:protect_from_forgery)
|
||||
plug(:put_secure_browser_headers)
|
||||
end
|
||||
|
||||
pipeline :auth do
|
||||
plug Chess.Auth.Pipeline
|
||||
plug(Chess.Auth.Pipeline)
|
||||
end
|
||||
|
||||
pipeline :ensure_auth do
|
||||
plug Guardian.Plug.EnsureAuthenticated
|
||||
plug :put_user_token
|
||||
plug(Guardian.Plug.EnsureAuthenticated)
|
||||
plug(:put_user_token)
|
||||
end
|
||||
|
||||
pipeline :api do
|
||||
plug :fetch_session
|
||||
plug :accepts, ["json"]
|
||||
plug(:fetch_session)
|
||||
plug(:accepts, ["json"])
|
||||
end
|
||||
|
||||
scope "/", ChessWeb do
|
||||
pipe_through [:browser, :auth] # Use the default browser stack
|
||||
# Use the default browser stack
|
||||
pipe_through([:browser, :auth])
|
||||
|
||||
get "/", PageController, :index
|
||||
resources "/session", SessionController,
|
||||
only: [:new, :create, :delete], singleton: true
|
||||
resources "/registration", RegistrationController,
|
||||
only: [:new, :create], singleton: true
|
||||
get("/", PageController, :index)
|
||||
resources("/session", SessionController, only: [:new, :create, :delete], singleton: true)
|
||||
resources("/registration", RegistrationController, only: [:new, :create], singleton: true)
|
||||
end
|
||||
|
||||
scope "/", ChessWeb do
|
||||
pipe_through [:browser, :auth, :ensure_auth]
|
||||
pipe_through([:browser, :auth, :ensure_auth])
|
||||
|
||||
resources "/games", GameController,
|
||||
only: [:index, :new, :create, :show, :delete]
|
||||
resources "/profile", ProfileController,
|
||||
only: [:edit, :update], singleton: true
|
||||
resources "/password", PasswordController,
|
||||
only: [:edit, :update], singleton: true
|
||||
resources("/games", GameController, only: [:index, :new, :create, :show, :delete])
|
||||
resources("/profile", ProfileController, only: [:edit, :update], singleton: true)
|
||||
resources("/password", PasswordController, only: [:edit, :update], singleton: true)
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
scope "/api", as: :api do
|
||||
pipe_through [:api, :auth, :ensure_auth]
|
||||
pipe_through([:api, :auth, :ensure_auth])
|
||||
|
||||
resources "/opponents", ChessWeb.Api.OpponentsController, only: [:index]
|
||||
resources("/opponents", ChessWeb.Api.OpponentsController, only: [:index])
|
||||
end
|
||||
|
||||
if Mix.env == :dev do
|
||||
forward "/sent_emails", Bamboo.SentEmailViewerPlug
|
||||
if Mix.env() == :dev do
|
||||
forward("/sent_emails", Bamboo.SentEmailViewerPlug)
|
||||
end
|
||||
|
||||
defp put_user_token(conn, _) do
|
||||
|
||||
@ -3,16 +3,17 @@ defmodule ChessWeb.Api.OpponentsView do
|
||||
|
||||
def render("index.json", %{opponents: opponents}) do
|
||||
%{
|
||||
opponents: Enum.map(opponents, fn opponent ->
|
||||
opponent_attrs(opponent)
|
||||
end)
|
||||
opponents:
|
||||
Enum.map(opponents, fn opponent ->
|
||||
opponent_attrs(opponent)
|
||||
end)
|
||||
}
|
||||
end
|
||||
|
||||
def opponent_attrs(opponent) do
|
||||
%{
|
||||
id: opponent.id,
|
||||
name: opponent.name,
|
||||
name: opponent.name
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@ -10,7 +10,7 @@ defmodule ChessWeb.ErrorHelpers do
|
||||
"""
|
||||
def error_tag(form, field) do
|
||||
if error = form.errors[field] do
|
||||
content_tag :span, translate_error(error), class: "help-block"
|
||||
content_tag(:span, translate_error(error), class: "help-block")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -2,16 +2,16 @@ defmodule ChessWeb.ErrorView do
|
||||
use ChessWeb, :view
|
||||
|
||||
def render("404.html", _assigns) do
|
||||
gettext "Page not found"
|
||||
gettext("Page not found")
|
||||
end
|
||||
|
||||
def render("500.html", _assigns) do
|
||||
gettext "Internal server error"
|
||||
gettext("Internal server error")
|
||||
end
|
||||
|
||||
# In case no render clause matches or no
|
||||
# template is found, let's render it as 500
|
||||
def template_not_found(_template, assigns) do
|
||||
render "500.html", assigns
|
||||
render("500.html", assigns)
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,8 +7,8 @@ defmodule ChessWeb.GameView do
|
||||
|
||||
def won_lost(conn, game) do
|
||||
if game_over?(game) && game.state == "checkmate" do
|
||||
your_turn?(conn, game) &&
|
||||
gettext("You lost") ||
|
||||
(your_turn?(conn, game) &&
|
||||
gettext("You lost")) ||
|
||||
gettext("You won")
|
||||
end
|
||||
end
|
||||
@ -21,9 +21,12 @@ defmodule ChessWeb.GameView do
|
||||
cond do
|
||||
GameState.game_over?(game) ->
|
||||
states()[game.state]
|
||||
|
||||
your_turn?(conn, game) ->
|
||||
gettext("Your turn")
|
||||
true -> nil
|
||||
|
||||
true ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@ -38,7 +41,7 @@ defmodule ChessWeb.GameView do
|
||||
end
|
||||
|
||||
def player_colour(conn, game) do
|
||||
current_user(conn).id == game.user_id && "white" || "black"
|
||||
(current_user(conn).id == game.user_id && "white") || "black"
|
||||
end
|
||||
|
||||
def player(game, user_id) do
|
||||
@ -61,7 +64,7 @@ defmodule ChessWeb.GameView do
|
||||
%{
|
||||
"checkmate" => gettext("Checkmate!"),
|
||||
"stalemate" => gettext("Stalemate"),
|
||||
"check" => gettext("Check"),
|
||||
"check" => gettext("Check")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@ -76,15 +76,13 @@ defmodule Chess.AuthTest do
|
||||
|
||||
test "authenticate_user/1 returns false on incorrect password " do
|
||||
user_fixture(email: "link@hyrule.com", password: "eyeofsheikah")
|
||||
assert {:error, message} =
|
||||
Auth.authenticate_user("link@hyrule.com", "shadowtemple")
|
||||
assert {:error, message} = Auth.authenticate_user("link@hyrule.com", "shadowtemple")
|
||||
assert message == "invalid password"
|
||||
end
|
||||
|
||||
test "authenticate_user/1 returns true on correct password " do
|
||||
user = user_fixture(email: "link@hyrule.com", password: "eyeofsheikah")
|
||||
assert {:ok, ^user} =
|
||||
Auth.authenticate_user("link@hyrule.com", "eyeofsheikah")
|
||||
assert {:ok, ^user} = Auth.authenticate_user("link@hyrule.com", "eyeofsheikah")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -6,35 +6,62 @@ defmodule Chess.BoardTest do
|
||||
alias Chess.Board
|
||||
|
||||
test "returns a piece from the board" do
|
||||
board = Board.default
|
||||
board = Board.default()
|
||||
|
||||
expected_piece = %{"type" => "pawn", "colour" => "white"}
|
||||
assert Board.piece(board, {4, 1}) == expected_piece
|
||||
end
|
||||
|
||||
test "finds pieces on the board" do
|
||||
board = Board.default
|
||||
board = Board.default()
|
||||
|
||||
piece = %{"type" => "pawn", "colour" => "white"}
|
||||
|
||||
expected_result = [
|
||||
{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1},
|
||||
{0, 1},
|
||||
{1, 1},
|
||||
{2, 1},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1},
|
||||
{6, 1},
|
||||
{7, 1}
|
||||
]
|
||||
|
||||
assert Board.search(board, piece) == expected_result
|
||||
end
|
||||
|
||||
test "finds pieces on the board with a partial search" do
|
||||
board = Board.default
|
||||
board = Board.default()
|
||||
|
||||
piece = %{"colour" => "white"}
|
||||
expected_result = [
|
||||
{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1},
|
||||
{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0},
|
||||
] |> Enum.sort
|
||||
|
||||
expected_result =
|
||||
[
|
||||
{0, 1},
|
||||
{1, 1},
|
||||
{2, 1},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1},
|
||||
{6, 1},
|
||||
{7, 1},
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{5, 0},
|
||||
{6, 0},
|
||||
{7, 0}
|
||||
]
|
||||
|> Enum.sort()
|
||||
|
||||
assert Board.search(board, piece) == expected_result
|
||||
end
|
||||
|
||||
test "finds a single piece on the board" do
|
||||
board = Board.default
|
||||
board = Board.default()
|
||||
|
||||
piece = %{"type" => "king", "colour" => "black"}
|
||||
assert Board.search(board, piece) == [{4, 7}]
|
||||
@ -42,44 +69,41 @@ defmodule Chess.BoardTest do
|
||||
|
||||
test "moves a piece" do
|
||||
board = %{
|
||||
"3,0" => %{"type" => "queen", "colour" => "white"},
|
||||
"3,0" => %{"type" => "queen", "colour" => "white"}
|
||||
}
|
||||
|
||||
%{board: new_board} =
|
||||
Board.move_piece(board, %{"from" => [3, 0], "to" => [5, 2]})
|
||||
%{board: new_board} = Board.move_piece(board, %{"from" => [3, 0], "to" => [5, 2]})
|
||||
|
||||
assert new_board == %{
|
||||
"5,2" => %{"type" => "queen", "colour" => "white"},
|
||||
}
|
||||
"5,2" => %{"type" => "queen", "colour" => "white"}
|
||||
}
|
||||
end
|
||||
|
||||
test "can perform a castling move on the kings side" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"7,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"7,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
%{board: new_board} =
|
||||
Board.move_piece(board, %{"from" => [4, 0], "to" => [6, 0]})
|
||||
%{board: new_board} = Board.move_piece(board, %{"from" => [4, 0], "to" => [6, 0]})
|
||||
|
||||
assert new_board == %{
|
||||
"6,0" => %{"type" => "king", "colour" => "white"},
|
||||
"5,0" => %{"type" => "rook", "colour" => "white"},
|
||||
}
|
||||
"6,0" => %{"type" => "king", "colour" => "white"},
|
||||
"5,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
end
|
||||
|
||||
test "can perform a castling move on the queens side" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
%{board: new_board} =
|
||||
Board.move_piece(board, %{"from" => [4, 0], "to" => [2, 0]})
|
||||
%{board: new_board} = Board.move_piece(board, %{"from" => [4, 0], "to" => [2, 0]})
|
||||
|
||||
assert new_board == %{
|
||||
"2,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,0" => %{"type" => "rook", "colour" => "white"},
|
||||
}
|
||||
"2,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@ -8,7 +8,7 @@ defmodule Chess.GameStateTest do
|
||||
test "king is in check" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"4,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"4,7" => %{"type" => "queen", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert GameState.king_in_check?(board, "white")
|
||||
@ -17,7 +17,7 @@ defmodule Chess.GameStateTest do
|
||||
test "king is not in check" do
|
||||
board = %{
|
||||
"5,0" => %{"type" => "king", "colour" => "white"},
|
||||
"4,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"4,7" => %{"type" => "queen", "colour" => "black"}
|
||||
}
|
||||
|
||||
refute GameState.king_in_check?(board, "white")
|
||||
@ -26,7 +26,7 @@ defmodule Chess.GameStateTest do
|
||||
test "king is in check by a knight" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,2" => %{"type" => "knight", "colour" => "black"},
|
||||
"3,2" => %{"type" => "knight", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert GameState.king_in_check?(board, "white")
|
||||
@ -35,7 +35,7 @@ defmodule Chess.GameStateTest do
|
||||
test "king is in check by a pawn" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,1" => %{"type" => "pawn", "colour" => "black"},
|
||||
"3,1" => %{"type" => "pawn", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert GameState.king_in_check?(board, "white")
|
||||
@ -45,7 +45,7 @@ defmodule Chess.GameStateTest do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "king", "colour" => "white"},
|
||||
"0,4" => %{"type" => "queen", "colour" => "black"},
|
||||
"1,4" => %{"type" => "rook", "colour" => "black"},
|
||||
"1,4" => %{"type" => "rook", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert GameState.player_checkmated?(board, "white")
|
||||
@ -54,7 +54,7 @@ defmodule Chess.GameStateTest do
|
||||
test "king is not in checkmate by a queen" do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "king", "colour" => "white"},
|
||||
"0,4" => %{"type" => "queen", "colour" => "black"},
|
||||
"0,4" => %{"type" => "queen", "colour" => "black"}
|
||||
}
|
||||
|
||||
refute GameState.player_checkmated?(board, "white")
|
||||
@ -64,7 +64,7 @@ defmodule Chess.GameStateTest do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "king", "colour" => "white"},
|
||||
"1,1" => %{"type" => "queen", "colour" => "black"},
|
||||
"2,3" => %{"type" => "knight", "colour" => "black"},
|
||||
"2,3" => %{"type" => "knight", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert GameState.player_checkmated?(board, "white")
|
||||
@ -75,7 +75,7 @@ defmodule Chess.GameStateTest do
|
||||
"0,0" => %{"type" => "king", "colour" => "white"},
|
||||
"2,0" => %{"type" => "knight", "colour" => "white"},
|
||||
"0,5" => %{"type" => "queen", "colour" => "black"},
|
||||
"1,5" => %{"type" => "rook", "colour" => "black"},
|
||||
"1,5" => %{"type" => "rook", "colour" => "black"}
|
||||
}
|
||||
|
||||
refute GameState.player_checkmated?(board, "white")
|
||||
@ -86,7 +86,7 @@ defmodule Chess.GameStateTest do
|
||||
"0,0" => %{"type" => "king", "colour" => "white"},
|
||||
"2,3" => %{"type" => "bishop", "colour" => "white"},
|
||||
"0,5" => %{"type" => "queen", "colour" => "black"},
|
||||
"1,5" => %{"type" => "rook", "colour" => "black"},
|
||||
"1,5" => %{"type" => "rook", "colour" => "black"}
|
||||
}
|
||||
|
||||
refute GameState.player_checkmated?(board, "white")
|
||||
@ -96,7 +96,7 @@ defmodule Chess.GameStateTest do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "king", "colour" => "white"},
|
||||
"1,2" => %{"type" => "rook", "colour" => "black"},
|
||||
"2,1" => %{"type" => "rook", "colour" => "black"},
|
||||
"2,1" => %{"type" => "rook", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert GameState.player_stalemated?(board, "white")
|
||||
|
||||
@ -12,18 +12,18 @@ defmodule Chess.MoveListTest do
|
||||
%Move{
|
||||
piece: %{"type" => "pawn", "colour" => "white"},
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 3},
|
||||
to: %{"file" => 4, "rank" => 3}
|
||||
},
|
||||
%Move{
|
||||
piece: %{"type" => "pawn", "colour" => "black"},
|
||||
from: %{"file" => 4, "rank" => 6},
|
||||
to: %{"file" => 4, "rank" => 4},
|
||||
to: %{"file" => 4, "rank" => 4}
|
||||
},
|
||||
%Move{
|
||||
piece: %{"type" => "knight", "colour" => "white"},
|
||||
from: %{"file" => 1, "rank" => 0},
|
||||
to: %{"file" => 2, "rank" => 2},
|
||||
},
|
||||
to: %{"file" => 2, "rank" => 2}
|
||||
}
|
||||
]
|
||||
|
||||
expected_result = [
|
||||
@ -51,7 +51,7 @@ defmodule Chess.MoveListTest do
|
||||
from: "b1",
|
||||
to: "c3"
|
||||
}
|
||||
],
|
||||
]
|
||||
]
|
||||
|
||||
assert MoveList.transform(moves) == expected_result
|
||||
|
||||
@ -6,7 +6,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece is not being attacked" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"2,1" => %{"type" => "rook", "colour" => "black"},
|
||||
"2,1" => %{"type" => "rook", "colour" => "black"}
|
||||
}
|
||||
|
||||
refute Piece.attacked?(board, {4, 5})
|
||||
@ -15,7 +15,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece on the edge of the board is not being attacked" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"2,7" => %{"type" => "rook", "colour" => "black"},
|
||||
"2,7" => %{"type" => "rook", "colour" => "black"}
|
||||
}
|
||||
|
||||
refute Piece.attacked?(board, {4, 0})
|
||||
@ -25,7 +25,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"4,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
"7,3" => %{"type" => "bishop", "colour" => "black"},
|
||||
"7,3" => %{"type" => "bishop", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert Piece.attacked?(board, {4, 0})
|
||||
@ -34,7 +34,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece is not being attacked by piece of its own colour" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"2,5" => %{"type" => "rook", "colour" => "white"},
|
||||
"2,5" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
refute Piece.attacked?(board, {4, 5})
|
||||
@ -43,7 +43,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece can be attacked by a rook" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"2,5" => %{"type" => "rook", "colour" => "black"},
|
||||
"2,5" => %{"type" => "rook", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert Piece.attacked?(board, {4, 5})
|
||||
@ -52,7 +52,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece can be attacked by a bishop" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"6,7" => %{"type" => "bishop", "colour" => "black"},
|
||||
"6,7" => %{"type" => "bishop", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert Piece.attacked?(board, {4, 5})
|
||||
@ -61,7 +61,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece can be attacked by a queen" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"6,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"6,7" => %{"type" => "queen", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert Piece.attacked?(board, {4, 5})
|
||||
@ -70,7 +70,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece is not attacked by a knight" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"7,7" => %{"type" => "knight", "colour" => "black"},
|
||||
"7,7" => %{"type" => "knight", "colour" => "black"}
|
||||
}
|
||||
|
||||
refute Piece.attacked?(board, {4, 5})
|
||||
@ -79,7 +79,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece can be attacked by a knight" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"5,7" => %{"type" => "knight", "colour" => "black"},
|
||||
"5,7" => %{"type" => "knight", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert Piece.attacked?(board, {4, 5})
|
||||
@ -88,7 +88,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece can be attacked by a pawn" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"5,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
"5,6" => %{"type" => "pawn", "colour" => "black"}
|
||||
}
|
||||
|
||||
assert Piece.attacked?(board, {4, 5})
|
||||
@ -97,7 +97,7 @@ defmodule Chess.Moves.PieceTest do
|
||||
test "piece is not attacked by a pawn directly in front" do
|
||||
board = %{
|
||||
"4,5" => %{"type" => "king", "colour" => "white"},
|
||||
"4,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
"4,6" => %{"type" => "pawn", "colour" => "black"}
|
||||
}
|
||||
|
||||
refute Piece.attacked?(board, {4, 5})
|
||||
|
||||
@ -7,10 +7,21 @@ defmodule Chess.Moves.Pieces.BishopTest do
|
||||
board = %{"4,5" => %{"type" => "bishop", "colour" => "white"}}
|
||||
moves = Moves.available(board, {4, 5})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{0, 1}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {6, 7},
|
||||
{2, 7}, {3, 6}, {5, 4}, {6, 3}, {7, 2},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 3},
|
||||
{3, 4},
|
||||
{5, 6},
|
||||
{6, 7},
|
||||
{2, 7},
|
||||
{3, 6},
|
||||
{5, 4},
|
||||
{6, 3},
|
||||
{7, 2}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -18,39 +29,60 @@ defmodule Chess.Moves.Pieces.BishopTest do
|
||||
board = %{"0,0" => %{"type" => "bishop", "colour" => "white"}}
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{1, 1},
|
||||
{2, 2},
|
||||
{3, 3},
|
||||
{4, 4},
|
||||
{5, 5},
|
||||
{6, 6},
|
||||
{7, 7}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "bishops are blocked by pieces of their own colour" do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "bishop", "colour" => "white"},
|
||||
"5,5" => %{"type" => "king", "colour" => "white"},
|
||||
"5,5" => %{"type" => "king", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{1, 1}, {2, 2}, {3, 3}, {4, 4},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{1, 1},
|
||||
{2, 2},
|
||||
{3, 3},
|
||||
{4, 4}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "bishops can take an opponents piece" do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "bishop", "colour" => "white"},
|
||||
"5,5" => %{"type" => "knight", "colour" => "black"},
|
||||
"5,5" => %{"type" => "knight", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{1, 1},
|
||||
{2, 2},
|
||||
{3, 3},
|
||||
{4, 4},
|
||||
{5, 5}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
def board do
|
||||
Chess.Board.default
|
||||
Chess.Board.default()
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,28 +7,42 @@ defmodule Chess.Moves.Pieces.King.CastlingTest do
|
||||
test "king can move two spaces to castle with the king side rook" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"7,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"7,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1},
|
||||
{6, 0},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 0},
|
||||
{5, 0},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1},
|
||||
{6, 0}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "king can move two spaces to castle with the queen side rook" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1},
|
||||
{2, 0},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 0},
|
||||
{5, 0},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1},
|
||||
{2, 0}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -36,13 +50,19 @@ defmodule Chess.Moves.Pieces.King.CastlingTest do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,0" => %{"type" => "queen", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{5, 0}, {3, 1}, {4, 1}, {5, 1},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{5, 0},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -50,13 +70,20 @@ defmodule Chess.Moves.Pieces.King.CastlingTest do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"2,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"2,7" => %{"type" => "queen", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 0},
|
||||
{5, 0},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -64,88 +91,119 @@ defmodule Chess.Moves.Pieces.King.CastlingTest do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"3,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"3,7" => %{"type" => "queen", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 0},
|
||||
{5, 0},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "cannot castle if the king has moved" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
move_list = [
|
||||
%Move{
|
||||
from: %{"file" => 4, "rank" => 0},
|
||||
to: %{"file" => 4, "rank" => 1},
|
||||
piece: %{"type" => "king", "colour" => "white"}
|
||||
piece: %{"type" => "king", "colour" => "white"}
|
||||
},
|
||||
%Move{
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 0},
|
||||
piece: %{"type" => "king", "colour" => "white"}
|
||||
},
|
||||
piece: %{"type" => "king", "colour" => "white"}
|
||||
}
|
||||
]
|
||||
|
||||
moves = Moves.available(board, {4, 0}, move_list)
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 0},
|
||||
{5, 0},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "cannot castle if the queen side rook has moved" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
move_list = [
|
||||
%Move{
|
||||
from: %{"file" => 0, "rank" => 0},
|
||||
to: %{"file" => 0, "rank" => 1},
|
||||
piece: %{"type" => "rook", "colour" => "white"}
|
||||
piece: %{"type" => "rook", "colour" => "white"}
|
||||
},
|
||||
%Move{
|
||||
from: %{"file" => 0, "rank" => 1},
|
||||
to: %{"file" => 0, "rank" => 0},
|
||||
piece: %{"type" => "rook", "colour" => "white"}
|
||||
},
|
||||
piece: %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
]
|
||||
|
||||
moves = Moves.available(board, {4, 0}, move_list)
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 0},
|
||||
{5, 0},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "cannot castle if the king side rook has moved" do
|
||||
board = %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"7,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"7,0" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
move_list = [
|
||||
%Move{
|
||||
from: %{"file" => 7, "rank" => 0},
|
||||
to: %{"file" => 7, "rank" => 1},
|
||||
piece: %{"type" => "rook", "colour" => "white"}
|
||||
piece: %{"type" => "rook", "colour" => "white"}
|
||||
},
|
||||
%Move{
|
||||
from: %{"file" => 7, "rank" => 1},
|
||||
to: %{"file" => 7, "rank" => 0},
|
||||
piece: %{"type" => "rook", "colour" => "white"}
|
||||
},
|
||||
piece: %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
]
|
||||
|
||||
moves = Moves.available(board, {4, 0}, move_list)
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 0},
|
||||
{5, 0},
|
||||
{3, 1},
|
||||
{4, 1},
|
||||
{5, 1}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,9 +7,18 @@ defmodule Chess.Moves.Pieces.KingTest do
|
||||
board = %{"4,5" => %{"type" => "king", "colour" => "white"}}
|
||||
moves = Moves.available(board, {4, 5})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 4}, {4, 4}, {5, 4}, {5, 5}, {5, 6}, {4, 6}, {3, 6}, {3, 5},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 4},
|
||||
{4, 4},
|
||||
{5, 4},
|
||||
{5, 5},
|
||||
{5, 6},
|
||||
{4, 6},
|
||||
{3, 6},
|
||||
{3, 5}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -17,26 +26,34 @@ defmodule Chess.Moves.Pieces.KingTest do
|
||||
board = %{"0,0" => %{"type" => "king", "colour" => "white"}}
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{0, 1}, {1, 1}, {1, 0},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{0, 1},
|
||||
{1, 1},
|
||||
{1, 0}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "kings are blocked by pieces of the same colour" do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "king", "colour" => "white"},
|
||||
"1,1" => %{"type" => "rook", "colour" => "white"},
|
||||
"1,1" => %{"type" => "rook", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{0, 1}, {1, 0},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{0, 1},
|
||||
{1, 0}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
def board do
|
||||
Chess.Board.default
|
||||
Chess.Board.default()
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,9 +7,18 @@ defmodule Chess.Moves.Pieces.KnightTest do
|
||||
board = %{"4,5" => %{"type" => "knight", "colour" => "white"}}
|
||||
moves = Moves.available(board, {4, 5})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{3, 7}, {5, 7}, {6, 6}, {6, 4}, {5, 3}, {3, 3}, {2, 4}, {2, 6},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{3, 7},
|
||||
{5, 7},
|
||||
{6, 6},
|
||||
{6, 4},
|
||||
{5, 3},
|
||||
{3, 3},
|
||||
{2, 4},
|
||||
{2, 6}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -17,26 +26,32 @@ defmodule Chess.Moves.Pieces.KnightTest do
|
||||
board = %{"0,0" => %{"type" => "knight", "colour" => "white"}}
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{1, 2}, {2, 1}
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{1, 2},
|
||||
{2, 1}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "knights are blocked by other pieces of the same colour" do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "knight", "colour" => "white"},
|
||||
"1,2" => %{"type" => "king", "colour" => "white"},
|
||||
"1,2" => %{"type" => "king", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{2, 1},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{2, 1}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
def board do
|
||||
Chess.Board.default
|
||||
Chess.Board.default()
|
||||
end
|
||||
end
|
||||
|
||||
@ -36,8 +36,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
|
||||
test "pawn is blocked from moving two squares by another piece" do
|
||||
board = %{
|
||||
"4,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
"4,3" => %{"type" => "pawn", "colour" => "black"},
|
||||
"4,3" => %{"type" => "pawn", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 1})
|
||||
|
||||
expected_moves = [{4, 2}]
|
||||
@ -47,8 +48,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
|
||||
test "pawn is blocked from moving one or two squares by another piece" do
|
||||
board = %{
|
||||
"4,1" => %{"type" => "pawn", "colour" => "white"},
|
||||
"4,2" => %{"type" => "pawn", "colour" => "black"},
|
||||
"4,2" => %{"type" => "pawn", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 1})
|
||||
|
||||
expected_moves = []
|
||||
@ -58,8 +60,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
|
||||
test "pawn is blocked from moving one square by another piece" do
|
||||
board = %{
|
||||
"4,2" => %{"type" => "pawn", "colour" => "white"},
|
||||
"4,3" => %{"type" => "pawn", "colour" => "black"},
|
||||
"4,3" => %{"type" => "pawn", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 2})
|
||||
|
||||
expected_moves = []
|
||||
@ -69,8 +72,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
|
||||
test "white pawn can take an opponents piece" do
|
||||
board = %{
|
||||
"4,2" => %{"type" => "pawn", "colour" => "white"},
|
||||
"5,3" => %{"type" => "pawn", "colour" => "black"},
|
||||
"5,3" => %{"type" => "pawn", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {4, 2})
|
||||
|
||||
expected_moves = [{4, 3}, {5, 3}]
|
||||
@ -80,8 +84,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
|
||||
test "black pawn can take an opponents piece" do
|
||||
board = %{
|
||||
"6,6" => %{"type" => "pawn", "colour" => "black"},
|
||||
"5,5" => %{"type" => "pawn", "colour" => "white"},
|
||||
"5,5" => %{"type" => "pawn", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {6, 6})
|
||||
|
||||
expected_moves = [{6, 5}, {6, 4}, {5, 5}]
|
||||
@ -89,6 +94,6 @@ defmodule Chess.Moves.Pieces.PawnTest do
|
||||
end
|
||||
|
||||
def default_board do
|
||||
Chess.Board.default
|
||||
Chess.Board.default()
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,12 +7,35 @@ defmodule Chess.Moves.Pieces.QueenTest do
|
||||
board = %{"4,5" => %{"type" => "queen", "colour" => "white"}}
|
||||
moves = Moves.available(board, {4, 5})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 6}, {4, 7},
|
||||
{0, 5}, {1, 5}, {2, 5}, {3, 5}, {5, 5}, {6, 5}, {7, 5},
|
||||
{0, 1}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {6, 7},
|
||||
{2, 7}, {3, 6}, {5, 4}, {6, 3}, {7, 2},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{4, 0},
|
||||
{4, 1},
|
||||
{4, 2},
|
||||
{4, 3},
|
||||
{4, 4},
|
||||
{4, 6},
|
||||
{4, 7},
|
||||
{0, 5},
|
||||
{1, 5},
|
||||
{2, 5},
|
||||
{3, 5},
|
||||
{5, 5},
|
||||
{6, 5},
|
||||
{7, 5},
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 3},
|
||||
{3, 4},
|
||||
{5, 6},
|
||||
{6, 7},
|
||||
{2, 7},
|
||||
{3, 6},
|
||||
{5, 4},
|
||||
{6, 3},
|
||||
{7, 2}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -20,15 +43,30 @@ defmodule Chess.Moves.Pieces.QueenTest do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "queen", "colour" => "white"},
|
||||
"0,5" => %{"type" => "king", "colour" => "white"},
|
||||
"5,0" => %{"type" => "bishop", "colour" => "white"},
|
||||
"5,0" => %{"type" => "bishop", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{0, 1}, {0, 2}, {0, 3}, {0, 4},
|
||||
{1, 0}, {2, 0}, {3, 0}, {4, 0},
|
||||
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{0, 1},
|
||||
{0, 2},
|
||||
{0, 3},
|
||||
{0, 4},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{1, 1},
|
||||
{2, 2},
|
||||
{3, 3},
|
||||
{4, 4},
|
||||
{5, 5},
|
||||
{6, 6},
|
||||
{7, 7}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -36,19 +74,36 @@ defmodule Chess.Moves.Pieces.QueenTest do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "queen", "colour" => "white"},
|
||||
"0,5" => %{"type" => "knight", "colour" => "black"},
|
||||
"5,0" => %{"type" => "rook", "colour" => "black"},
|
||||
"5,0" => %{"type" => "rook", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5},
|
||||
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0},
|
||||
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{0, 1},
|
||||
{0, 2},
|
||||
{0, 3},
|
||||
{0, 4},
|
||||
{0, 5},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{5, 0},
|
||||
{1, 1},
|
||||
{2, 2},
|
||||
{3, 3},
|
||||
{4, 4},
|
||||
{5, 5},
|
||||
{6, 6},
|
||||
{7, 7}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
def board do
|
||||
Chess.Board.default
|
||||
Chess.Board.default()
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,10 +7,24 @@ defmodule Chess.Moves.Pieces.RookTest do
|
||||
board = %{"4,5" => %{"type" => "rook", "colour" => "white"}}
|
||||
moves = Moves.available(board, {4, 5})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 6}, {4, 7},
|
||||
{0, 5}, {1, 5}, {2, 5}, {3, 5}, {5, 5}, {6, 5}, {7, 5},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{4, 0},
|
||||
{4, 1},
|
||||
{4, 2},
|
||||
{4, 3},
|
||||
{4, 4},
|
||||
{4, 6},
|
||||
{4, 7},
|
||||
{0, 5},
|
||||
{1, 5},
|
||||
{2, 5},
|
||||
{3, 5},
|
||||
{5, 5},
|
||||
{6, 5},
|
||||
{7, 5}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
@ -18,42 +32,81 @@ defmodule Chess.Moves.Pieces.RookTest do
|
||||
board = %{"0,0" => %{"type" => "rook", "colour" => "white"}}
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7},
|
||||
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{0, 1},
|
||||
{0, 2},
|
||||
{0, 3},
|
||||
{0, 4},
|
||||
{0, 5},
|
||||
{0, 6},
|
||||
{0, 7},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{5, 0},
|
||||
{6, 0},
|
||||
{7, 0}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "rooks are blocked by other pieces of the same colour" do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"0,5" => %{"type" => "king", "colour" => "white"},
|
||||
"0,5" => %{"type" => "king", "colour" => "white"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{0, 1}, {0, 2}, {0, 3}, {0, 4},
|
||||
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{0, 1},
|
||||
{0, 2},
|
||||
{0, 3},
|
||||
{0, 4},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{5, 0},
|
||||
{6, 0},
|
||||
{7, 0}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
test "rooks can take an opponents piece" do
|
||||
board = %{
|
||||
"0,0" => %{"type" => "rook", "colour" => "white"},
|
||||
"0,5" => %{"type" => "knight", "colour" => "black"},
|
||||
"0,5" => %{"type" => "knight", "colour" => "black"}
|
||||
}
|
||||
|
||||
moves = Moves.available(board, {0, 0})
|
||||
|
||||
expected_moves = Enum.sort([
|
||||
{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5},
|
||||
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0},
|
||||
])
|
||||
expected_moves =
|
||||
Enum.sort([
|
||||
{0, 1},
|
||||
{0, 2},
|
||||
{0, 3},
|
||||
{0, 4},
|
||||
{0, 5},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{5, 0},
|
||||
{6, 0},
|
||||
{7, 0}
|
||||
])
|
||||
|
||||
assert Enum.sort(moves) == expected_moves
|
||||
end
|
||||
|
||||
def board do
|
||||
Chess.Board.default
|
||||
Chess.Board.default()
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,51 +7,59 @@ defmodule Chess.Repo.QueriesTest do
|
||||
|
||||
describe "opponents" do
|
||||
test "it finds a user on a partial name match" do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
opponent = insert(:user, %{
|
||||
name: "Princess Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganonsucks"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
opponent =
|
||||
insert(:user, %{
|
||||
name: "Princess Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganonsucks"
|
||||
})
|
||||
|
||||
result =
|
||||
user
|
||||
|> Queries.opponents("zelda")
|
||||
|> Repo.one
|
||||
|> Repo.one()
|
||||
|
||||
assert result.id == opponent.id
|
||||
end
|
||||
|
||||
test "it finds a user on a complete email match" do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
opponent = insert(:user, %{
|
||||
name: "Princess Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganonsucks"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
opponent =
|
||||
insert(:user, %{
|
||||
name: "Princess Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganonsucks"
|
||||
})
|
||||
|
||||
result =
|
||||
user
|
||||
|> Queries.opponents("zelda@hyrule.com")
|
||||
|> Repo.one
|
||||
|> Repo.one()
|
||||
|
||||
assert result.id == opponent.id
|
||||
end
|
||||
|
||||
test "it does not find a user on a partial email" do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
insert(:user, %{
|
||||
name: "Princess Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
@ -61,7 +69,7 @@ defmodule Chess.Repo.QueriesTest do
|
||||
result =
|
||||
user
|
||||
|> Queries.opponents("hyrule")
|
||||
|> Repo.one
|
||||
|> Repo.one()
|
||||
|
||||
assert result == nil
|
||||
end
|
||||
|
||||
@ -20,6 +20,7 @@ defmodule Chess.Store.GameTest do
|
||||
opponent_id: opponent.id,
|
||||
turn: "white"
|
||||
}
|
||||
|
||||
changeset = Game.changeset(%Game{}, attrs)
|
||||
|
||||
assert changeset.valid?
|
||||
@ -33,6 +34,7 @@ defmodule Chess.Store.GameTest do
|
||||
opponent_id: 2,
|
||||
turn: "white"
|
||||
}
|
||||
|
||||
changeset = Game.changeset(%Game{}, attrs)
|
||||
|
||||
assert changeset.valid?
|
||||
@ -81,18 +83,20 @@ defmodule Chess.Store.GameTest do
|
||||
user = insert(:user)
|
||||
opponent = insert(:opponent)
|
||||
|
||||
game = insert(:game, %{
|
||||
board: Board.default,
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id,
|
||||
})
|
||||
game =
|
||||
insert(:game, %{
|
||||
board: Board.default(),
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id
|
||||
})
|
||||
|
||||
move_params = %{"from" => [4, 1], "to" => [4, 3]}
|
||||
|
||||
changeset = Game.move_changeset(
|
||||
game,
|
||||
Board.move_piece(game.board, move_params)
|
||||
)
|
||||
changeset =
|
||||
Game.move_changeset(
|
||||
game,
|
||||
Board.move_piece(game.board, move_params)
|
||||
)
|
||||
|
||||
assert {:ok, new_game} = Repo.update(changeset)
|
||||
assert new_game.turn == "black"
|
||||
|
||||
@ -14,29 +14,32 @@ defmodule Chess.Store.MoveTest do
|
||||
user = insert(:user)
|
||||
opponent = insert(:opponent)
|
||||
|
||||
game = insert(:game, %{
|
||||
board: Board.default,
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id,
|
||||
})
|
||||
game =
|
||||
insert(:game, %{
|
||||
board: Board.default(),
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id
|
||||
})
|
||||
|
||||
changeset = Move.changeset(%Move{}, %{
|
||||
game_id: game.id,
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 3},
|
||||
piece: %{"type" => "pawn", "colour" => "white"},
|
||||
})
|
||||
changeset =
|
||||
Move.changeset(%Move{}, %{
|
||||
game_id: game.id,
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 3},
|
||||
piece: %{"type" => "pawn", "colour" => "white"}
|
||||
})
|
||||
|
||||
assert changeset.valid?
|
||||
assert {:ok, _move} = Repo.insert(changeset)
|
||||
end
|
||||
|
||||
test "move is invalid without a game" do
|
||||
changeset = Move.changeset(%Move{}, %{
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 3},
|
||||
piece: %{"type" => "pawn", "colour" => "white"},
|
||||
})
|
||||
changeset =
|
||||
Move.changeset(%Move{}, %{
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 3},
|
||||
piece: %{"type" => "pawn", "colour" => "white"}
|
||||
})
|
||||
|
||||
refute changeset.valid?
|
||||
end
|
||||
@ -45,16 +48,18 @@ defmodule Chess.Store.MoveTest do
|
||||
user = insert(:user)
|
||||
opponent = insert(:opponent)
|
||||
|
||||
game = insert(:game, %{
|
||||
board: Board.default,
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id,
|
||||
})
|
||||
game =
|
||||
insert(:game, %{
|
||||
board: Board.default(),
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id
|
||||
})
|
||||
|
||||
changeset = Move.changeset(%Move{}, %{
|
||||
game_id: game.id,
|
||||
piece: %{"type" => "pawn", "colour" => "white"},
|
||||
})
|
||||
changeset =
|
||||
Move.changeset(%Move{}, %{
|
||||
game_id: game.id,
|
||||
piece: %{"type" => "pawn", "colour" => "white"}
|
||||
})
|
||||
|
||||
refute changeset.valid?
|
||||
end
|
||||
@ -63,17 +68,19 @@ defmodule Chess.Store.MoveTest do
|
||||
user = insert(:user)
|
||||
opponent = insert(:opponent)
|
||||
|
||||
game = insert(:game, %{
|
||||
board: Board.default,
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id,
|
||||
})
|
||||
game =
|
||||
insert(:game, %{
|
||||
board: Board.default(),
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id
|
||||
})
|
||||
|
||||
changeset = Move.changeset(%Move{}, %{
|
||||
game_id: game.id,
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 3},
|
||||
})
|
||||
changeset =
|
||||
Move.changeset(%Move{}, %{
|
||||
game_id: game.id,
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 3}
|
||||
})
|
||||
|
||||
refute changeset.valid?
|
||||
end
|
||||
@ -83,16 +90,16 @@ defmodule Chess.Store.MoveTest do
|
||||
piece: %{"type" => "pawn", "colour" => "white"},
|
||||
piece_captured: %{"type" => "pawn", "colour" => "black"},
|
||||
from: %{"file" => 4, "rank" => 1},
|
||||
to: %{"file" => 4, "rank" => 3},
|
||||
to: %{"file" => 4, "rank" => 3}
|
||||
}
|
||||
|
||||
assert Move.transform(move) == %{
|
||||
id: nil,
|
||||
piece: %{"type" => "pawn", "colour" => "white"},
|
||||
piece_captured: %{"type" => "pawn", "colour" => "black"},
|
||||
from: "e2",
|
||||
to: "e4"
|
||||
}
|
||||
id: nil,
|
||||
piece: %{"type" => "pawn", "colour" => "white"},
|
||||
piece_captured: %{"type" => "pawn", "colour" => "black"},
|
||||
from: "e2",
|
||||
to: "e4"
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -8,10 +8,12 @@ defmodule ChessWeb.GameChannelTest do
|
||||
|
||||
test "assigns game_id to the socket after join" do
|
||||
user = insert(:user)
|
||||
game = insert(:game, %{
|
||||
user_id: user.id,
|
||||
opponent_id: insert(:opponent).id
|
||||
})
|
||||
|
||||
game =
|
||||
insert(:game, %{
|
||||
user_id: user.id,
|
||||
opponent_id: insert(:opponent).id
|
||||
})
|
||||
|
||||
token = Phoenix.Token.sign(@endpoint, "game socket", user.id)
|
||||
{:ok, socket} = connect(UserSocket, %{"token" => token})
|
||||
@ -24,20 +26,22 @@ defmodule ChessWeb.GameChannelTest do
|
||||
test "returns the game state after join" do
|
||||
user = insert(:user)
|
||||
opponent = insert(:opponent, %{name: "Daruk"})
|
||||
game = insert(:game, %{
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id
|
||||
})
|
||||
|
||||
game =
|
||||
insert(:game, %{
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id
|
||||
})
|
||||
|
||||
token = Phoenix.Token.sign(@endpoint, "game socket", user.id)
|
||||
{:ok, socket} = connect(UserSocket, %{"token" => token})
|
||||
|
||||
{:ok, _, _} = subscribe_and_join(socket, "game:#{game.id}", %{})
|
||||
|
||||
assert_push "game:update", %{
|
||||
assert_push("game:update", %{
|
||||
player: "white",
|
||||
opponent: "Daruk",
|
||||
turn: "white",
|
||||
}
|
||||
turn: "white"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
@ -74,25 +74,25 @@ defmodule ChessWeb.GameControllerTest do
|
||||
conn
|
||||
|> login(other_user)
|
||||
|
||||
assert_error_sent 404, fn ->
|
||||
get conn, game_path(conn, :show, game.id)
|
||||
end
|
||||
assert_error_sent(404, fn ->
|
||||
get(conn, game_path(conn, :show, game.id))
|
||||
end)
|
||||
end
|
||||
|
||||
test "renders page not found when id is nonexistent", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
conn = login(conn, user)
|
||||
|
||||
assert_error_sent 404, fn ->
|
||||
get conn, game_path(conn, :show, -1)
|
||||
end
|
||||
assert_error_sent(404, fn ->
|
||||
get(conn, game_path(conn, :show, -1))
|
||||
end)
|
||||
end
|
||||
|
||||
test "deletes game", %{conn: conn} do
|
||||
game = Repo.insert! %Game{}
|
||||
game = Repo.insert!(%Game{})
|
||||
user = insert(:user)
|
||||
conn = login(conn, user)
|
||||
conn = delete conn, game_path(conn, :delete, game)
|
||||
conn = delete(conn, game_path(conn, :delete, game))
|
||||
assert redirected_to(conn) == game_path(conn, :index)
|
||||
refute Repo.get(Game, game.id)
|
||||
end
|
||||
|
||||
@ -2,7 +2,7 @@ defmodule ChessWeb.SessionControllerTest do
|
||||
use ChessWeb.ConnCase
|
||||
|
||||
test "shows log in form", %{conn: conn} do
|
||||
conn = get conn, session_path(conn, :new)
|
||||
conn = get(conn, session_path(conn, :new))
|
||||
assert html_response(conn, 200) =~ "Log in"
|
||||
end
|
||||
end
|
||||
|
||||
@ -40,22 +40,24 @@ defmodule Chess.Features.GamesTest do
|
||||
|> click(button("Create game"))
|
||||
|
||||
session
|
||||
|> assert_has(
|
||||
css(".help-block", text: "can't be blank")
|
||||
)
|
||||
|> assert_has(css(".help-block", text: "can't be blank"))
|
||||
end
|
||||
|
||||
test "can only see own games", %{session: session} do
|
||||
opponent = insert(:user, %{
|
||||
name: "Urbosa",
|
||||
email: "urbosa@gerudo.town",
|
||||
password: "gerudoqueen"
|
||||
})
|
||||
user = insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganonsucks"
|
||||
})
|
||||
opponent =
|
||||
insert(:user, %{
|
||||
name: "Urbosa",
|
||||
email: "urbosa@gerudo.town",
|
||||
password: "gerudoqueen"
|
||||
})
|
||||
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganonsucks"
|
||||
})
|
||||
|
||||
insert(:game, %{user_id: user.id, opponent_id: opponent.id})
|
||||
|
||||
session
|
||||
@ -72,16 +74,20 @@ defmodule Chess.Features.GamesTest do
|
||||
end
|
||||
|
||||
test "can see games as an opponent", %{session: session} do
|
||||
opponent = insert(:user, %{
|
||||
name: "Urbosa",
|
||||
email: "urbosa@gerudo.town",
|
||||
password: "gerudoqueen"
|
||||
})
|
||||
user = insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganonsucks"
|
||||
})
|
||||
opponent =
|
||||
insert(:user, %{
|
||||
name: "Urbosa",
|
||||
email: "urbosa@gerudo.town",
|
||||
password: "gerudoqueen"
|
||||
})
|
||||
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganonsucks"
|
||||
})
|
||||
|
||||
insert(:game, %{user_id: user.id, opponent_id: opponent.id})
|
||||
|
||||
session
|
||||
|
||||
@ -22,27 +22,28 @@ defmodule Chess.Features.MovesTest do
|
||||
|> click(link("New game"))
|
||||
|> select_opponent("Zelda")
|
||||
|> click(button("Create game"))
|
||||
|
||||
|> click(css("#f4-r1"))
|
||||
|> assert_has(square_selected("f4-r1"))
|
||||
|> assert_has(square_containing("f4-r1", %{type: "pawn", colour: "white"}))
|
||||
|
||||
|> click(css("#f4-r3"))
|
||||
|> assert_has(square_containing("f4-r3", %{type: "pawn", colour: "white"}))
|
||||
|> refute_has(square_containing("f4-r1", %{type: "pawn", colour: "white"}))
|
||||
end
|
||||
|
||||
test "opponents recieves an email on move", %{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
opponent = insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganondorfsucks"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
opponent =
|
||||
insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganondorfsucks"
|
||||
})
|
||||
|
||||
session
|
||||
|> login("link@hyrule.com", "ilovezelda")
|
||||
@ -88,6 +89,7 @@ defmodule Chess.Features.MovesTest do
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
@ -101,7 +103,8 @@ defmodule Chess.Features.MovesTest do
|
||||
|> select_opponent("Zelda")
|
||||
|> click(button("Create game"))
|
||||
|
||||
{:ok, session2} = Wallaby.start_session
|
||||
{:ok, session2} = Wallaby.start_session()
|
||||
|
||||
session2
|
||||
|> login("zelda@hyrule.com", "ganondorfsucks")
|
||||
|> click(link("Game with Link"))
|
||||
@ -117,6 +120,7 @@ defmodule Chess.Features.MovesTest do
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
@ -130,7 +134,8 @@ defmodule Chess.Features.MovesTest do
|
||||
|> select_opponent("Zelda")
|
||||
|> click(button("Create game"))
|
||||
|
||||
{:ok, session2} = Wallaby.start_session
|
||||
{:ok, session2} = Wallaby.start_session()
|
||||
|
||||
session2
|
||||
|> login("zelda@hyrule.com", "ganondorfsucks")
|
||||
|> click(link("Game with Link"))
|
||||
@ -147,25 +152,29 @@ defmodule Chess.Features.MovesTest do
|
||||
|
||||
test "cannot move the king into a position that would result in check",
|
||||
%{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
opponent = insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganondorfsucks"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
opponent =
|
||||
insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganondorfsucks"
|
||||
})
|
||||
|
||||
insert(:game, %{
|
||||
board: %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"7,7" => %{"type" => "king", "colour" => "black"},
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"7,7" => %{"type" => "king", "colour" => "black"}
|
||||
},
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id,
|
||||
turn: "white",
|
||||
turn: "white"
|
||||
})
|
||||
|
||||
session
|
||||
@ -182,26 +191,30 @@ defmodule Chess.Features.MovesTest do
|
||||
|
||||
test "cannot make a move that would place the king in check",
|
||||
%{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
opponent = insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganondorfsucks"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
opponent =
|
||||
insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganondorfsucks"
|
||||
})
|
||||
|
||||
insert(:game, %{
|
||||
board: %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"4,1" => %{"type" => "rook", "colour" => "white"},
|
||||
"4,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"7,7" => %{"type" => "king", "colour" => "black"},
|
||||
"7,7" => %{"type" => "king", "colour" => "black"}
|
||||
},
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id,
|
||||
turn: "white",
|
||||
turn: "white"
|
||||
})
|
||||
|
||||
session
|
||||
@ -217,25 +230,29 @@ defmodule Chess.Features.MovesTest do
|
||||
end
|
||||
|
||||
test "user is informed when the game is in check", %{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
opponent = insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganondorfsucks"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
opponent =
|
||||
insert(:user, %{
|
||||
name: "Zelda",
|
||||
email: "zelda@hyrule.com",
|
||||
password: "ganondorfsucks"
|
||||
})
|
||||
|
||||
insert(:game, %{
|
||||
board: %{
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"7,7" => %{"type" => "king", "colour" => "black"},
|
||||
"4,0" => %{"type" => "king", "colour" => "white"},
|
||||
"3,7" => %{"type" => "queen", "colour" => "black"},
|
||||
"7,7" => %{"type" => "king", "colour" => "black"}
|
||||
},
|
||||
user_id: user.id,
|
||||
opponent_id: opponent.id,
|
||||
turn: "black",
|
||||
turn: "black"
|
||||
})
|
||||
|
||||
session
|
||||
|
||||
@ -7,11 +7,12 @@ defmodule Chess.Features.PasswordTest do
|
||||
import Chess.AuthenticationHelpers
|
||||
|
||||
test "user can change their password", %{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
session
|
||||
|> login(user.email, "ilovezelda")
|
||||
@ -26,11 +27,12 @@ defmodule Chess.Features.PasswordTest do
|
||||
end
|
||||
|
||||
test "password cannot be blank", %{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
session
|
||||
|> login(user.email, "ilovezelda")
|
||||
@ -41,8 +43,6 @@ defmodule Chess.Features.PasswordTest do
|
||||
|> click(button("Update Password"))
|
||||
|
||||
session
|
||||
|> assert_has(
|
||||
css("[data-role='password-error']", text: "can't be blank")
|
||||
)
|
||||
|> assert_has(css("[data-role='password-error']", text: "can't be blank"))
|
||||
end
|
||||
end
|
||||
|
||||
@ -7,11 +7,12 @@ defmodule Chess.Features.ProfileTest do
|
||||
import Chess.AuthenticationHelpers
|
||||
|
||||
test "user can update their details", %{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
session
|
||||
|> login(user.email, "ilovezelda")
|
||||
@ -25,11 +26,12 @@ defmodule Chess.Features.ProfileTest do
|
||||
end
|
||||
|
||||
test "name cannot be blank", %{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
session
|
||||
|> login(user.email, "ilovezelda")
|
||||
@ -40,17 +42,16 @@ defmodule Chess.Features.ProfileTest do
|
||||
|> click(button("Update Profile"))
|
||||
|
||||
session
|
||||
|> assert_has(
|
||||
css("[data-role='name-error']", text: "can't be blank")
|
||||
)
|
||||
|> assert_has(css("[data-role='name-error']", text: "can't be blank"))
|
||||
end
|
||||
|
||||
test "email cannot be blank", %{session: session} do
|
||||
user = insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
user =
|
||||
insert(:user, %{
|
||||
name: "Link",
|
||||
email: "link@hyrule.com",
|
||||
password: "ilovezelda"
|
||||
})
|
||||
|
||||
session
|
||||
|> login(user.email, "ilovezelda")
|
||||
@ -61,8 +62,6 @@ defmodule Chess.Features.ProfileTest do
|
||||
|> click(button("Update Profile"))
|
||||
|
||||
session
|
||||
|> assert_has(
|
||||
css("[data-role='email-error']", text: "can't be blank")
|
||||
)
|
||||
|> assert_has(css("[data-role='email-error']", text: "can't be blank"))
|
||||
end
|
||||
end
|
||||
|
||||
@ -25,9 +25,7 @@ defmodule Chess.Features.RegistrationTest do
|
||||
|> click(button("Register"))
|
||||
|
||||
session
|
||||
|> assert_has(
|
||||
css("[data-role='name-error']", text: "can't be blank")
|
||||
)
|
||||
|> assert_has(css("[data-role='name-error']", text: "can't be blank"))
|
||||
end
|
||||
|
||||
test "user cannot register without an email", %{session: session} do
|
||||
@ -39,9 +37,7 @@ defmodule Chess.Features.RegistrationTest do
|
||||
|> click(button("Register"))
|
||||
|
||||
session
|
||||
|> assert_has(
|
||||
css("[data-role='email-error']", text: "can't be blank")
|
||||
)
|
||||
|> assert_has(css("[data-role='email-error']", text: "can't be blank"))
|
||||
end
|
||||
|
||||
test "user cannot register without a password", %{session: session} do
|
||||
@ -53,8 +49,6 @@ defmodule Chess.Features.RegistrationTest do
|
||||
|> click(button("Register"))
|
||||
|
||||
session
|
||||
|> assert_has(
|
||||
css("[data-role='password-error']", text: "can't be blank")
|
||||
)
|
||||
|> assert_has(css("[data-role='password-error']", text: "can't be blank"))
|
||||
end
|
||||
end
|
||||
|
||||
@ -5,7 +5,7 @@ defmodule Chess.FormHelpers do
|
||||
|
||||
import Wallaby.Query
|
||||
|
||||
def select(session, name, [option: option]) do
|
||||
def select(session, name, option: option) do
|
||||
session
|
||||
|> find(css("[name='#{name}']"))
|
||||
|> click(option(option))
|
||||
|
||||
@ -18,7 +18,7 @@ defmodule Chess.Factory do
|
||||
|
||||
%User{}
|
||||
|> User.changeset(params)
|
||||
|> Repo.insert!
|
||||
|> Repo.insert!()
|
||||
end
|
||||
|
||||
def insert(:opponent, new_params) do
|
||||
@ -32,12 +32,12 @@ defmodule Chess.Factory do
|
||||
|
||||
%User{}
|
||||
|> User.changeset(params)
|
||||
|> Repo.insert!
|
||||
|> Repo.insert!()
|
||||
end
|
||||
|
||||
def insert(:game, params) do
|
||||
%Game{}
|
||||
|> Game.changeset(params)
|
||||
|> Repo.insert!
|
||||
|> Repo.insert!()
|
||||
end
|
||||
end
|
||||
|
||||
@ -4,4 +4,4 @@ ExUnit.start()
|
||||
|
||||
Ecto.Adapters.SQL.Sandbox.mode(Chess.Repo, {:shared, self()})
|
||||
|
||||
Application.put_env(:wallaby, :base_url, ChessWeb.Endpoint.url)
|
||||
Application.put_env(:wallaby, :base_url, ChessWeb.Endpoint.url())
|
||||
|
||||
@ -8,16 +8,16 @@ defmodule Chess.ErrorViewTest do
|
||||
|
||||
test "renders 404.html" do
|
||||
assert render_to_string(ErrorView, "404.html", []) ==
|
||||
"Page not found"
|
||||
"Page not found"
|
||||
end
|
||||
|
||||
test "render 500.html" do
|
||||
assert render_to_string(ErrorView, "500.html", []) ==
|
||||
"Internal server error"
|
||||
"Internal server error"
|
||||
end
|
||||
|
||||
test "render any other" do
|
||||
assert render_to_string(ErrorView, "505.html", []) ==
|
||||
"Internal server error"
|
||||
"Internal server error"
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user