Skip to content

Commit

Permalink
Add DB backend
Browse files Browse the repository at this point in the history
  • Loading branch information
petr-muller committed Apr 18, 2018
1 parent adbae66 commit dd3406e
Show file tree
Hide file tree
Showing 21 changed files with 497 additions and 254 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache

# Translations
*.mo
Expand Down
14 changes: 7 additions & 7 deletions requirements-tests.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
blessings==1.6.1
colorama==0.3.9
coverage==4.5.1
mypy==0.570
pyfakefs==3.4
pylint==1.8.2
pytest==3.4.2
pytest-bdd==2.20.0
mypy==0.590
peewee==3.2.4
pyfakefs==3.4.1
pylint==1.8.4
pytest==3.5.0
pytest-bdd==2.21.0
pytest-cov==2.5.1
pytest-mypy==0.3.0
pytest-pylint==0.9.0
python-dateutil==2.7.2
tabulate==0.8.2
python-dateutil==2.7.0
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
blessings==1.6.1
colorama==0.3.9
peewee==3.2.4
python-dateutil==2.7.2
tabulate==0.8.2
python-dateutil==2.7.0
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
packages=find_packages(exclude=["tests"]),
setup_requires=['pytest-runner'],
tests_require=['pytest', 'pylint', 'mypy', 'blessings', 'tabulate', 'pyfakefs',
'pytest-bdd', 'pytest-pylint', 'pytest-mypy', 'pytest-cov',
'python-dateutil'],
'pytest-bdd', 'pytest-pylint', 'pytest-cov', 'python-dateutil'],
install_requires=["blessings", "tabulate", 'python-dateutil'],
entry_points={'console_scripts': ['vtes=vtes.run:main']}
)
58 changes: 42 additions & 16 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# missing-docstring, because we do not need docstring for each test method
# redefined-outer-name: fixtures unfortunately trigger this
# pylint: disable=missing-docstring, redefined-outer-name
# pylint: disable=missing-docstring, redefined-outer-name, unused-import

from pytest_bdd import given, when, then
from tests.fixtures.commands import vtes_command
from tests.fixtures.commands import vtes_command, five_games

@when('I submit the command')
def execute(vtes_command):
Expand All @@ -13,19 +13,45 @@ def execute(vtes_command):
def check_command_passed(vtes_command):
assert vtes_command.completed.returncode == 0

@then('command finishes unsuccessfully')
def check_command_failed(vtes_command):
assert vtes_command.completed.returncode != 0

@given('I logged some games')
def log_some_games(tmpdir):
games = (("Zerato(Deck):0", "preston(Deck):1", "Afri(Deck):0", "XZealot(Deck):0",
"bluedevil(Deck):4"),
("Felipe(Deck):0", "Afri(Deck):0", "XZealot(Deck):2", "Cooper(Deck):2"),
("bluedevil(Deck):0", "XZealot(Deck):1", "Narpas(Deck):3", "gNat(Deck):0",
"Afri(Deck):1"),
("Afri(Deck 2):3", "Nebojsa(Deck):2", "ShaneS_A tier(Deck):0", "Blooded(Deck):0",
"Cooper(Deck):0"),
("Afri(Deck 2):2", "sor_garcya(Deck):3", "Cooper(Deck)", "ShaneS_A tier(Deck):0",
"Nebojsa(Deck):0"))
for game in games:
command = vtes_command(tmpdir)
command.add_arguments(("add",) + game)
command.execute()
def log_some_games(tmpdir, five_games):
for game in five_games:
command = vtes_command(tmpdir).add().with_arguments(game).execute()
assert command.completed.returncode == 0

DECKS_5 = ("Pascek Bruise & Vote", "Synesios Summon History", "Malgorzata", "BH Assamite Rush",
"Anarchy in the Wild West")
PLAYERS_5 = ("Zerato", "Vladish", "preston", "XZealot", "Afri")

@when("I specify players with decks")
def x_players_with_decks(vtes_command):
arguments = [f"{player}({deck})" for player, deck in zip(PLAYERS_5, DECKS_5)]
vtes_command.add().with_arguments(arguments)

@then('player rankings are listed')
def listed_player_rankings(vtes_command):
output = vtes_command.completed.stdout.split("\n")
assert output[0].startswith("Player GW VP Games")
assert output[1].startswith("------------- ---- ---- -------")
assert output[2].startswith("Afri 1 6 5")
assert output[3].startswith("bluedevil 1 4 2")
assert output[6].startswith("XZealot 0 3 3")
assert output[7].startswith("Cooper 0 2 3")
assert output[8].startswith("Nebojsa 0 2 2")
assert output[9].startswith("preston 0 1 1")
assert output[10].startswith("ShaneS_A tier 0 0 2")
assert output[15] == ""
assert output[16] == "Overall statistics: 5 games with 13 players"

@then('deck statistics are listed')
def listed_deck_rankings(vtes_command):
output = vtes_command.completed.stdout.split("\n")
assert output[0].startswith("Deck Player GW VP")
assert output[1].startswith("------ ------------- ---------- ----------")
assert output[2].startswith("Deck Narpas 1/1 (100%) 3/5 (60%)")
assert output[3].startswith("Deck sor_garcya 1/1 (100%) 3/5 (60%)")
assert output[4].startswith("Deck 2 Afri 1/2 (50%) 5/10 (50%)")
64 changes: 55 additions & 9 deletions tests/fixtures/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,65 @@
import subprocess
import pytest

class Executable:
def __init__(self, command=()):
self.command = list(command)
class VTESRunnerProxy():
def __init__(self, tmpdir):
self.base = ("python", "-m", "vtes.run")
self.tmpdir = tmpdir
self._storage = ("--journal-file", str(self.tmpdir / "journal"))
self._vtes_command = []
self.completed = None

def add_arguments(self, arguments):
self.command.extend(arguments)
def with_pickle_file(self):
self._storage = ("--journal-file", str(self.tmpdir / "journal"))
return self

def with_database(self):
self._storage = ("--journal-db", str(self.tmpdir / "journal"))
return self

def add(self):
self._vtes_command = ["add"]
return self

def stats(self):
self._vtes_command = ["stats"]
return self

def gamefix(self):
self._vtes_command = ["game-fix"]
return self

def games(self):
self._vtes_command = ["games"]
return self

def decks(self):
self._vtes_command = ["decks"]
return self

def with_arguments(self, arguments):
self._vtes_command.extend(arguments)
return self

def execute(self):
self.completed = subprocess.run(self.command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, encoding='utf-8')
print(self.base + self._storage + tuple(self._vtes_command))
self.completed = subprocess.run(self.base + self._storage + tuple(self._vtes_command),
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
encoding='utf-8')
return self

@pytest.fixture
def vtes_command(tmpdir):
journal = tmpdir.join('vtes-journal')
return Executable(("python", "-m", "vtes.run", "--journal-file", str(journal)))
return VTESRunnerProxy(tmpdir)

@pytest.fixture
def five_games():
return (("Zerato(Deck):0", "preston(Deck):1", "Afri(Deck):0", "XZealot(Deck):0",
"bluedevil(Deck):4"),
("Felipe(Deck):0", "Afri(Deck):0", "XZealot(Deck):2", "Cooper(Deck):2"),
("bluedevil(Deck):0", "XZealot(Deck):1", "Narpas(Deck):3", "gNat(Deck):0",
"Afri(Deck):1"),
("Afri(Deck 2):3", "Nebojsa(Deck):2", "ShaneS_A tier(Deck):0", "Blooded(Deck):0",
"Cooper(Deck):0"),
("Afri(Deck 2):2", "sor_garcya(Deck):3", "Cooper(Deck)", "ShaneS_A tier(Deck):0",
"Nebojsa(Deck):0"))
42 changes: 42 additions & 0 deletions tests/functional/features/database.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Feature: Store VtES journal in a database

Scenario: Add game to a database
When I invoke vtes add with --journal-db
And I specify players with decks
And I submit the command
Then command finishes successfully

Scenario: List games from a database
Given I logged five games to database
When I invoke vtes games with --journal-db
And I submit the command
Then command finishes successfully
And five games are listed

Scenario: Deck statistics from a database
Given I logged some games to database
When I invoke vtes decks with --journal-db
And I submit the command
Then command finishes successfully
And deck statistics are listed

Scenario: General timeline statistics from a database
Given I logged some games to database
When I invoke vtes stats with --journal-db
And I submit the command
Then command finishes successfully
And player rankings are listed

Scenario: Database and pickle are mutually exclusive
When I invoke vtes add with --journal-db and --journal-file
And I specify players with decks
And I submit the command
Then command finishes unsuccessfully

# This will need Games to have IDs
# Scenario: Fix existing game in a database
# Given I logged some games to database
# When I change game 1 with --journal-db
# And I submit the command
# Then command finishes successfully
# Then game is changed
3 changes: 1 addition & 2 deletions tests/functional/features/gamefix.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ Feature: Game Fix

Scenario: Fix existing game
Given I logged some games
When I invoke vtes game-fix
And I change game 1
When I change game 1
And I submit the command
Then command finishes successfully
Then game is changed
2 changes: 1 addition & 1 deletion tests/functional/features/stats.feature
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Scenario: Game Win Ratio
Then command finishes successfully
And stats contain game win ratio for each player

Scenario: VP Snatch Ratio Given I logged some games
Scenario: VP Snatch Ratio Given
Given I logged some games
When I invoke vtes stats
And I submit the command
Expand Down
37 changes: 10 additions & 27 deletions tests/functional/test_add_games.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@

@when('I invoke vtes add')
def vtes_add(vtes_command):
vtes_command.add_arguments(('add',))
vtes_command.add()

@when("I specify <count> players")
def x_players(count, vtes_command):
vtes_command.add_arguments([f"player_{x}" for x in range(int(count))])
vtes_command.with_arguments([f"player_{x}" for x in range(int(count))])

@when("I specify players with victory points")
def x_players_with_vps(vtes_command):
count = 5
points = [0] * count
points[randrange(count)] = count
vtes_command.add_arguments([f"player_{x}:{points[x]}" for x in range(int(count))])
vtes_command.with_arguments([f"player_{x}:{points[x]}" for x in range(int(count))])

DECKS_5 = ("Pascek Bruise & Vote", "Synesios Summon History", "Malgorzata", "BH Assamite Rush",
"Anarchy in the Wild West")
Expand All @@ -33,25 +33,15 @@ def x_players_with_vps(vtes_command):
def x_players_with_decks_and_vps(vtes_command):
points = (2, 0, 0, 1, 2)
arguments = [f"{player}({deck}):{vp}" for player, deck, vp in zip(PLAYERS_5, DECKS_5, points)]
vtes_command.add_arguments(["add"] + arguments)

@when("I specify players with decks")
def x_players_with_decks(vtes_command):
arguments = [f"{player}({deck})" for player, deck in zip(PLAYERS_5, DECKS_5)]
vtes_command.add_arguments(["add"] + arguments)

@then('command finishes unsuccessfully')
def check_command_failed(vtes_command):
assert vtes_command.completed.returncode != 0
vtes_command.add().with_arguments(arguments)

@then('command emits helpful error message about player count')
def check_error_for_player_count(vtes_command):
assert "three to six players" in vtes_command.completed.stderr

@given('I logged five games')
def log_five_games(tmpdir):
command = vtes_command(tmpdir)
command.add_arguments(("add", "one", "two", "three", "four", "five"))
command = vtes_command(tmpdir).add().with_arguments(("one", "two", "three", "four", "five"))
for _ in range(5):
command.execute()
assert command.completed.returncode == 0
Expand All @@ -61,32 +51,25 @@ def log_game_with_vp(tmpdir, count, winning):
count = int(count)
winning = int(winning)

command = vtes_command(tmpdir)
points = [0] * count
points[winning] = count
players = [f"player_{x}:{points[x]}" for x in range(count)]
command.add_arguments(["add"] + players)
command.execute()
vtes_command(tmpdir).add().with_arguments(players).execute()

@given('I logged game with decks and victory points')
def log_game_with_decks_and_vp(tmpdir):
command = vtes_command(tmpdir)
points = (2, 0, 0, 1, 2)
arguments = [f"{player}({deck}):{vp}" for player, deck, vp in zip(PLAYERS_5, DECKS_5, points)]
command.add_arguments(["add"] + arguments)
command.execute()
vtes_command(tmpdir).add().with_arguments(arguments).execute()

@given('I logged game with decks')
def log_game_with_decks(tmpdir):
command = vtes_command(tmpdir)
arguments = [f"{player}({deck})" for player, deck in zip(PLAYERS_5, DECKS_5)]
command.add_arguments(["add"] + arguments)
command.execute()
vtes_command(tmpdir).add().with_arguments(arguments).execute()

@when('I invoke vtes games')
def vtes_games(vtes_command):
vtes_command.add_arguments(["games"])
vtes_command.execute()
vtes_command.games().execute()

@then('five games are listed')
def five_games_listed(vtes_command):
Expand Down Expand Up @@ -131,4 +114,4 @@ def decks(vtes_command):

@when('I specify game date')
def game_dates(vtes_command):
vtes_command.add_arguments(["--date", "2018-03-22"])
vtes_command.with_arguments(("--date", "2018-03-22"))
46 changes: 46 additions & 0 deletions tests/functional/test_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# missing-docstring, because we do not need docstring for each test method
# redefined-outer-name: fixtures unfortunately trigger this
# pylint: disable=missing-docstring, redefined-outer-name, unused-import

from pytest_bdd import given, when, then, scenarios
from tests.fixtures.commands import vtes_command, five_games

scenarios('features/database.feature')

@when('I invoke vtes add with --journal-db and --journal-file')
def pickle_and_db(tmpdir, vtes_command):
# pylint: disable=protected-access
vtes_command._storage = ('--journal-file', tmpdir / 'file', '--journal-db', tmpdir / 'file.db')

@given('I logged five games to database')
@given('I logged some games to database')
def log_some_games(tmpdir, five_games):
for game in five_games:
command = vtes_command(tmpdir).with_database().add().with_arguments(game).execute()
assert command.completed.returncode == 0

@when('I invoke vtes stats with --journal-db')
def vtes_stats(vtes_command):
vtes_command.with_database().stats()

@when('I invoke vtes add with --journal-db')
def vtes_add_db(vtes_command):
vtes_command.with_database().add()

@when('I invoke vtes games with --journal-db')
def vtes_games(vtes_command):
vtes_command.with_database().games()

@when('I invoke vtes decks with --journal-db')
def vtes_decks(vtes_command):
vtes_command.with_database().decks()

@then('five games are listed')
def five_games_listed(vtes_command):
output = [line for line in vtes_command.completed.stdout.split("\n") if line]
assert len(output) == 5

@when('I change game 1 with --journal-db')
def change_game_1(vtes_command):
vtes_command.with_database().gamefix().with_arguments(("1", "Felipe(dECK):0", "aFRI(Deck):0",
"XZealot(Deck):3", "Cooper(Deck):1"))
Loading

0 comments on commit dd3406e

Please sign in to comment.