From e466991301293b27439b829370dca6ec403efa30 Mon Sep 17 00:00:00 2001 From: Pranav Manoj <69426276+bossbeagle1509@users.noreply.github.com> Date: Fri, 16 Jan 2026 22:55:50 +0100 Subject: [PATCH] Adding tests --- .gitignore | 8 +++ coverage-report.pdf | Bin 0 -> 51768 bytes diffusion2d.py | 11 +++- requirements.txt | 5 ++ tests/integration/test_diffusion2d.py | 67 +++++++++++++++++++++-- tests/unit/test_diffusion2d_functions.py | 67 ++++++++++++++++++----- tox.toml | 7 +++ 7 files changed, 146 insertions(+), 19 deletions(-) create mode 100644 .gitignore create mode 100644 coverage-report.pdf create mode 100644 requirements.txt create mode 100644 tox.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..646139b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*/__pycache__/* +env/* +.DS_Store +.coverage +*.pyc + + +# coverage run --source=diffusion2d.py,tests/unit/test_diffusion2d_functions.py,tests/integration/test_diffusion2d.py -m pytest && coverage html --include=diffusion2d.py,tests/unit/test_diffusion2d_functions.py,tests/integration/test_diffusion2d.py \ No newline at end of file diff --git a/coverage-report.pdf b/coverage-report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..42f624ab98091fdbb28b8c3fdf2d742ab5f9342a GIT binary patch literal 51768 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 W11I|TQxpy?0ThUxT~=8R^nU;Z!^t85 literal 0 HcmV?d00001 diff --git a/diffusion2d.py b/diffusion2d.py index 51a07f2..8e809cf 100644 --- a/diffusion2d.py +++ b/diffusion2d.py @@ -38,6 +38,10 @@ def __init__(self): self.dt = None def initialize_domain(self, w=10., h=10., dx=0.1, dy=0.1): + assert type(w) == float + assert type(h) == float + assert type(dx) == float + assert type(dy) == float self.w = w self.h = h self.dx = dx @@ -45,7 +49,10 @@ def initialize_domain(self, w=10., h=10., dx=0.1, dy=0.1): self.nx = int(w / dx) self.ny = int(h / dy) - def initialize_physical_parameters(self, d=4., T_cold=300, T_hot=700): + def initialize_physical_parameters(self, d=4., T_cold=300.0, T_hot=700.0): + assert type(d) == float + assert type(T_cold) == float + assert type(T_hot) == float self.D = d self.T_cold = T_cold self.T_hot = T_hot @@ -136,4 +143,4 @@ def main(): if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e6cd51c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +matplotlib +numpy +pytest +coverage + diff --git a/tests/integration/test_diffusion2d.py b/tests/integration/test_diffusion2d.py index fd026b4..d11349d 100644 --- a/tests/integration/test_diffusion2d.py +++ b/tests/integration/test_diffusion2d.py @@ -3,17 +3,76 @@ """ from diffusion2d import SolveDiffusion2D +import pytest +import numpy as np -def test_initialize_physical_parameters(): +@pytest.fixture +def solver(): + return SolveDiffusion2D() + + +def test_initialize_physical_parameters(solver): """ Checks function SolveDiffusion2D.initialize_domain """ - solver = SolveDiffusion2D() + solver.initialize_domain(w=2.0, h=4.0, dx=0.1, dy=0.1) + + assert solver.nx == 20 + assert solver.ny == 40 + assert solver.dx == 0.1 + assert solver.dy == 0.1 + assert solver.w == 2.0 + assert solver.h == 4.0 + + solver.initialize_physical_parameters(d=4.0, T_cold=300.0, T_hot=700.0) + assert solver.D == 4.0 + assert solver.T_cold == 300.0 + assert solver.T_hot == 700.0 -def test_set_initial_condition(): + expected_dt = 0.000625 + + assert pytest.approx(solver.dt) == expected_dt + + +def test_set_initial_condition(solver): """ Checks function SolveDiffusion2D.get_initial_function """ - solver = SolveDiffusion2D() + solver.initialize_domain(w=10.0, h=10.0, dx=0.1, dy=0.1) + + assert solver.dx == 0.1 + assert solver.dy == 0.1 + assert solver.w == 10.0 + assert solver.h == 10.0 + + solver.initialize_physical_parameters(d=4.0, T_cold=300.0, T_hot=700.0) + + assert solver.D == 4.0 + assert solver.T_cold == 300.0 + assert solver.T_hot == 700.0 + + expected_dt = 0.000625 + + assert pytest.approx(solver.dt) == expected_dt + + u = solver.T_cold * np.ones((solver.nx, solver.ny)) + + # Initial conditions - circle of radius r centred at (cx,cy) (mm) + r, cx, cy = 2, 5, 5 + r2 = r ** 2 + for i in range(solver.nx): + for j in range(solver.ny): + p2 = (i * solver.dx - cx) ** 2 + (j * solver.dy - cy) ** 2 + if p2 < r2: + u[i, j] = solver.T_hot + + solver_u = solver.set_initial_condition() + + assert np.allclose(solver_u, u) + assert solver_u.shape == (100, 100) + assert solver_u[0, 0] == 300.0 + assert solver_u[50, 50] == 700.0 + assert np.all((solver_u == 300.0) | (solver_u == 700.0)) + assert np.all(solver_u >= 300.0) and np.all(solver_u <= 700.0) \ No newline at end of file diff --git a/tests/unit/test_diffusion2d_functions.py b/tests/unit/test_diffusion2d_functions.py index c4277ff..53c2d89 100644 --- a/tests/unit/test_diffusion2d_functions.py +++ b/tests/unit/test_diffusion2d_functions.py @@ -3,24 +3,65 @@ """ from diffusion2d import SolveDiffusion2D +import numpy as np +import pytest -def test_initialize_domain(): - """ - Check function SolveDiffusion2D.initialize_domain - """ - solver = SolveDiffusion2D() +@pytest.fixture +def solver(): + """Fixture to provide a fresh instance of the solver for each test.""" + return SolveDiffusion2D() -def test_initialize_physical_parameters(): - """ - Checks function SolveDiffusion2D.initialize_domain - """ - solver = SolveDiffusion2D() +def test_initialize_domain(solver): + """initialize_domain sets attributes and computes nx/ny correctly.""" + solver.initialize_domain(w=2.0, h=4.0, dx=0.1, dy=0.1) + + assert solver.nx == 20 + assert solver.ny == 40 + assert solver.dx == 0.1 + assert solver.dy == 0.1 + assert solver.w == 2.0 + assert solver.h == 4.0 + + +def test_initialize_physical_parameters(solver): + """initialize_physical_parameters stores values and computes stable dt.""" + # Manually setting dependencies to avoid calling initialize_domain + solver.dx = 0.1 + solver.dy = 0.1 + + solver.initialize_physical_parameters(d=4.0, T_cold=300.0, T_hot=700.0) + + expected_dt = 0.000625 + assert solver.D == 4.0 + assert solver.T_cold == 300.0 + assert solver.T_hot == 700.0 + + assert pytest.approx(solver.dt) == expected_dt -def test_set_initial_condition(): +def test_set_initial_condition(solver): """ - Checks function SolveDiffusion2D.get_initial_function + Checks function SolveDiffusion2D.set_initial_function """ - solver = SolveDiffusion2D() + solver.nx = 100 + solver.ny = 100 + solver.dx = 0.1 + solver.dy = 0.1 + solver.T_cold = 300.0 + solver.T_hot = 700.0 + + u = solver.set_initial_condition() + + # Check shape + assert u.shape == (100, 100) + + # Check a corner (should be cold) + assert u[0, 0] == 300.0 + + # Check the center (5, 5) -> index (50, 50) (should be hot) + assert u[50, 50] == 700.0 + + # Check that we actually have both temperatures present + assert np.all((u == 300.0) | (u == 700.0)) \ No newline at end of file diff --git a/tox.toml b/tox.toml new file mode 100644 index 0000000..bcc67f9 --- /dev/null +++ b/tox.toml @@ -0,0 +1,7 @@ +requires = ["tox>=4"] +env_list = ["pytest_testing"] + +[env.pytest_testing] +description = "Run pytest" +deps = ["-r requirements.txt"] +commands = [["python","-m","pytest"]] \ No newline at end of file