Skip to content

Commit

Permalink
V0.13.0
Browse files Browse the repository at this point in the history
  • Loading branch information
domhnallmorr committed Dec 22, 2024
1 parent 46a8b19 commit 27ca6cf
Show file tree
Hide file tree
Showing 13 changed files with 506 additions and 28 deletions.
Binary file modified src/1998_Roster/roster.db
Binary file not shown.
2 changes: 1 addition & 1 deletion src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def main(page: ft.Page):

page.window.maximized = True

version = "0.12.0"
version = "0.13.0"
page.title = f"Pitwall {version}"

run_directory = os.path.dirname(os.path.join(os.path.abspath(__file__)))
Expand Down
45 changes: 32 additions & 13 deletions src/pw_model/load_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,24 +165,43 @@ def save_commercial_managers(model: Model, save_file: sqlite3.Connection) -> Non
"Age" INTEGER,
"Skill" INTEGER,
"Salary" INTEGER,
"ContractLength" INTEGER
"ContractLength" INTEGER,
"RetiringAge" INTEGER,
"Retiring" INTEGER,
"Retired" INTEGER
)'''
)

cursor.execute("DELETE FROM commercial_managers") # clear existing data

for commercial_manager in model.commercial_managers:
cursor.execute('''
INSERT INTO commercial_managers (year, name, age, skill, salary, contractlength)
VALUES (?, ?, ?, ?, ?, ?)
''', (
"default",
commercial_manager.name,
commercial_manager.age,
commercial_manager.skill,
commercial_manager.contract.salary,
commercial_manager.contract.contract_length,
))
for idx, list_type in enumerate([model.commercial_managers, model.future_managers]):
for commercial_manager in list_type:
process = False
if idx == 0:
year = "default"
process = True
elif idx == 1:
if commercial_manager[1].role == StaffRoles.COMMERCIAL_MANAGER:
year = commercial_manager[0]
commercial_manager = commercial_manager[1]
process = True

if process is True:

cursor.execute('''
INSERT INTO commercial_managers (year, name, age, skill, salary, contractlength, retiringage, retiring, retired)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
year,
commercial_manager.name,
commercial_manager.age,
commercial_manager.skill,
commercial_manager.contract.salary,
commercial_manager.contract.contract_length,
commercial_manager.retiring_age,
commercial_manager.retiring,
commercial_manager.retired,
))

def save_technical_directors(model : Model, save_file: sqlite3.Connection) -> None:
cursor = save_file.cursor()
Expand Down
7 changes: 5 additions & 2 deletions src/pw_view/race_weekend/results_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,11 @@ def update_page(self, data: dict) -> None:
self.update_buttons_row(timed_session)
self.setup_classification_table(standings_df, current_session)

self.classification_list_view = ft.ListView(expand=True, spacing=10, padding=20, auto_scroll=True)
self.classification_list_view.controls.append(self.classification_container)

self.content_column = ft.Column(
controls=[self.buttons_container, self.classification_container, self.continue_container],
controls=[self.buttons_container, self.classification_list_view, self.continue_container],
expand=True,
spacing=20
)
Expand Down Expand Up @@ -257,7 +260,7 @@ def display_classification(self, e: Optional[ft.ControlEvent]=None) -> None:
self.reset_tab_buttons()
self.classification_btn.style = self.view.clicked_button_style

self.content_column.controls=[self.buttons_container, self.classification_container, self.continue_container]
self.content_column.controls=[self.buttons_container, self.classification_list_view, self.continue_container]
self.view.main_app.update()

def display_pitstops(self, e: ft.ControlEvent) -> None:
Expand Down
10 changes: 5 additions & 5 deletions src/pw_view/staff_page/staff_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,11 @@ def display_drivers(self, e: ft.ControlEvent) -> None:
spacing=20
)

self.controls = [
ft.Text("Staff", theme_style=self.view.page_header_style),
self.buttons_row,
self.driver_row,
]
# self.controls = [
# ft.Text("Staff", theme_style=self.view.page_header_style),
# self.buttons_row,
# self.driver_row,
# ]

self.background_stack = ft.Stack(
[
Expand Down
8 changes: 2 additions & 6 deletions src/pw_view/standings_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,8 @@ def update_standings(self, drivers_standings_df: pd.DataFrame, constructors_stan
self.drivers_table = ft.DataTable(columns=columns, rows=rows, data_row_max_height=30, data_row_min_height=30,
heading_row_color=ft.Colors.PRIMARY)

self.scrollable_drivers_table = ft.Column(
controls=[self.drivers_table],
# height=self.view.main_app.window.height - self.view.vscroll_buffer,
# expand=True, # Set height to show scrollbar if content exceeds this height
scroll=ft.ScrollMode.AUTO # Automatically show scrollbar when needed
)
self.scrollable_drivers_table = ft.ListView(expand=1, auto_scroll=True)
self.scrollable_drivers_table.controls.append(custom_container.CustomContainer(self.view, self.drivers_table, expand=False))

# CONSTRUCTORS

Expand Down
2 changes: 1 addition & 1 deletion src/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
package-mode = false
name = "Pitwall"
version = "0.12.0"
version = "0.13.0"
description = "A free and open source motorsport manager game"
authors = ["Domhnall Morrissey"]
readme = "README.md"
Expand Down
67 changes: 67 additions & 0 deletions src/tests/test_view/finance_page/test_finance_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import pytest
from unittest.mock import Mock
from flet import Text, Row, Column, Stack
from pw_view.finance_page.finance_page import FinancePage

class MockView:
def __init__(self):
self.background_image = Mock()
self.page_header_style = Mock()
self.dark_grey = "#23232A"

@pytest.fixture
def finance_page():
# Mock the view and create an instance of FinancePage
view = MockView()
return FinancePage(view)

def test_initialization(finance_page):
# Test if the page initializes correctly with the required widgets
assert isinstance(finance_page, Column)
assert len(finance_page.controls) == 2
assert isinstance(finance_page.controls[0], Text) # "Finance" header
assert isinstance(finance_page.controls[1], Stack) # Background stack

def test_setup_widgets(finance_page):
# Check if widgets are set up correctly
assert isinstance(finance_page.sponsor_income_text, Text)
assert finance_page.sponsor_income_text.value == "Sponsorship: $1"

assert isinstance(finance_page.total_income_text, Text)
assert finance_page.total_income_text.value == "Total: $1"

assert isinstance(finance_page.total_expenditure_text, Text)
assert finance_page.total_expenditure_text.value == "Total: $1"

def test_update_page(finance_page):
# Test updating the page with mocked FinanceData
mock_data = {
"total_sponsorship": 500000,
"prize_money": 250000,
"drivers_payments": 100000,
"total_income": 850000,
"total_staff_costs_per_year": 300000,
"drivers_salary": 200000,
"technical_director_salary": 150000,
"commercial_manager_salary": 120000,
"race_costs": 50000,
"car_costs": 80000,
"total_expenditure": 700000,
"balance_history_dates": ["2023-01-01", "2023-02-01"],
"balance_history": [500000, 850000],
}

finance_page.update_page(mock_data)

assert finance_page.sponsor_income_text.value == "Sponsorship: $500,000"
assert finance_page.prize_money_income_text.value == "Prize Money: $250,000"
assert finance_page.total_income_text.value == "Total: $850,000"
assert finance_page.total_expenditure_text.value == "Total: $700,000"

# Simulate chart update (no direct visual assertions, but ensure no errors)
finance_page.update_history_chart(mock_data)

def test_balance_formatter(finance_page):
# Test the custom balance formatter
assert finance_page.balance_formatter(900000, 0) == "$900K"
assert finance_page.balance_formatter(1500000, 0) == "$1M"
75 changes: 75 additions & 0 deletions src/tests/test_view/race_weekend/test_race_weekend_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import pytest
from unittest.mock import MagicMock
from pw_view.race_weekend.race_weekend_window import RaceWeekendWindow, SessionNames


@pytest.fixture
def mock_view():
# Mocking the View dependency
mock = MagicMock()
mock.page_header_style = "default-style"
mock.header2_style = "header2-style"
mock.race_background_image = MagicMock()
mock.main_app = MagicMock()
mock.controller = MagicMock()
return mock


@pytest.fixture
def race_data():
return {
"race_title": "Test Race Weekend"
}


@pytest.fixture
def race_window(mock_view, race_data):
return RaceWeekendWindow(view=mock_view, data=race_data)


def test_initialization(race_window):
assert race_window.header_text.value == "Test Race Weekend"
assert race_window.simulate_buttons[SessionNames.QUALIFYING].disabled is False
assert race_window.simulate_buttons[SessionNames.RACE].disabled is True
assert race_window.continue_btn.disabled is True


def test_simulate_qualifying(race_window):
# Simulate clicking the Qualifying simulate button
session_type = SessionNames.QUALIFYING
mock_event = MagicMock()
mock_event.control.data = session_type

race_window.simulate(mock_event)

# Check that the Qualifying button is disabled and the Race button is enabled
assert race_window.simulate_buttons[session_type].disabled is True
assert race_window.simulate_buttons[SessionNames.RACE].disabled is False
assert session_type in race_window.simulate_btns_clicked


def test_simulate_race(race_window):
# Simulate clicking the Race simulate button
race_window.simulate_btns_clicked = [SessionNames.QUALIFYING]
session_type = SessionNames.RACE
mock_event = MagicMock()
mock_event.control.data = session_type

race_window.simulate(mock_event)

# Check that the Race button is disabled and the Continue button is enabled
assert race_window.simulate_buttons[session_type].disabled is True
assert race_window.continue_btn.disabled is False
assert session_type in race_window.simulate_btns_clicked


def test_return_to_main_window(race_window):
mock_event = MagicMock()

# Trigger the return to main window method
race_window.return_to_main_window(mock_event)

# Check that the Continue button is disabled again
assert race_window.continue_btn.disabled is True
race_window.view.main_app.update.assert_called_once()
race_window.view.controller.post_race_actions.assert_called_once()
83 changes: 83 additions & 0 deletions src/tests/test_view/race_weekend/test_results_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import pytest
from unittest.mock import Mock
import pandas as pd
from pw_view.race_weekend.results_window import ResultsWindow
from race_model.race_model_enums import SessionNames
import flet as ft

@pytest.fixture
def mock_view():
# Create a mock of the View object
view_mock = Mock()
view_mock.page_header_style = "title"
view_mock.results_background_image = ft.Image(src="background.png")
view_mock.clicked_button_style = {"color": "red"}
view_mock.main_app = Mock()
view_mock.main_app.update = Mock()
view_mock.race_weekend_window = ft.View()
return view_mock

@pytest.fixture
def results_window(mock_view):
return ResultsWindow(mock_view)

def test_initialization(results_window):
# Test if the ResultsWindow initializes correctly
assert results_window.header_text.value == "Results"
assert isinstance(results_window.controls, list)
assert len(results_window.controls) > 0

def test_setup_buttons_row(results_window):
results_window.setup_buttons_row()
assert results_window.buttons_row is not None
assert len(results_window.buttons_row.controls) == 2

def test_reset_tab_buttons(results_window):
results_window.setup_buttons_row()
results_window.reset_tab_buttons()
assert results_window.classification_btn.style is None
assert results_window.pitstops_btn.style is None

def test_update_buttons_row_for_race(results_window):
results_window.setup_buttons_row()
results_window.update_buttons_row(timed_session=False)
assert len(results_window.buttons_row.controls) == 4

def test_update_buttons_row_for_timed_session(results_window):
results_window.setup_buttons_row()
results_window.update_buttons_row(timed_session=True)
assert len(results_window.buttons_row.controls) == 1

def gen_dummy_data():
sample_data = {
"Position": [1, 2],
"Driver": ["Driver A", "Driver B"],
"Team": ["Team A", "Team B"],
"Fastest Lap": [90000, 91000],
"Gap to Leader": [0, 1000],
"Lap": [60, 60],
"Status": ["Running", "Running"],
"Lapped Status": [None, None],
"Pit": [2, 1],
"Grid": [1, 2]
}
standings_df = pd.DataFrame(sample_data)

return standings_df

def test_setup_classification_table(results_window):
standings_df = gen_dummy_data()
results_window.setup_classification_table(standings_df, current_session=SessionNames.RACE)
assert results_window.results_table is not None
assert len(results_window.results_table.rows) == len(standings_df)

def test_ms_to_min_sec(results_window):
assert results_window.ms_to_min_sec(65000) == "1:05.000"
assert results_window.ms_to_min_sec(30000, interval=True) == "+30.000"

def test_display_classification(results_window):
standings_df = gen_dummy_data()
results_window.update_page({"current_session": SessionNames.QUALIFYING, "standings_df": standings_df})
results_window.display_classification()
assert results_window.classification_btn.style == results_window.view.clicked_button_style

Loading

0 comments on commit 27ca6cf

Please sign in to comment.