diff --git a/tests/test_export.py b/tests/test_export.py new file mode 100644 index 0000000..ef69eaa --- /dev/null +++ b/tests/test_export.py @@ -0,0 +1,52 @@ +"""Tests of the creation and the export of the scores table.""" + +from pathlib import Path + +import pytest + +pandas = pytest.importorskip("pandas") + +from weather import export # noqa: E402 + + +def test_create_scores_frame_has_the_columns_and_values_of_the_lecture() -> None: + frame = export.create_scores_frame() + + assert isinstance(frame, pandas.DataFrame) + assert list(frame.columns) == ["students", "scores"] + assert frame["students"].to_list() == ["Amy", "James", "Angela"] + assert frame["scores"].to_list() == [76, 56, 65] + + +def test_export_frame_round_trips_through_a_file(tmp_path: Path) -> None: + frame = export.create_scores_frame() + target = tmp_path / "scores.csv" + + export.export_frame(frame, target) + + assert target.is_file() + read_back = pandas.read_csv(target, index_col=0) + pandas.testing.assert_frame_equal(read_back, frame) + + +def test_export_frame_accepts_a_string_path(tmp_path: Path) -> None: + target = tmp_path / "as_text.csv" + + export.export_frame(export.create_scores_frame(), str(target)) + + assert target.is_file() + + +def test_export_frame_default_name_writes_only_new_data_csv_in_the_working_dir( + tmp_path: Path, +) -> None: + # The autouse fixture in conftest.py made tmp_path the working directory. + export.export_frame(export.create_scores_frame()) + + assert [item.name for item in tmp_path.iterdir()] == ["new_data.csv"] + + +def test_create_scores_frame_writes_nothing(tmp_path: Path) -> None: + export.create_scores_frame() + + assert list(tmp_path.iterdir()) == [] diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..ed505ee --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,68 @@ +"""Tests of the command line: the printed results and what is written.""" + +import sys +from pathlib import Path + +import pytest + +from weather.__main__ import main + + +def test_main_without_arguments_prints_the_results_of_the_lectures( + capsys: pytest.CaptureFixture[str], +) -> None: + pytest.importorskip("pandas") + + assert main([]) == 0 + + output = capsys.readouterr().out + assert "17.428" in output + assert "24" in output + assert "Sunny" in output + assert "53.6" in output + assert "Sunday" in output + assert "Angela" in output + + +def test_main_without_the_flag_writes_no_file(tmp_path: Path) -> None: + pytest.importorskip("pandas") + + assert main([]) == 0 + + assert list(tmp_path.iterdir()) == [] + + +def test_main_with_the_export_flag_writes_the_scores_frame( + tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + pandas = pytest.importorskip("pandas") + from weather.export import create_scores_frame + + target = tmp_path / "out.csv" + + assert main(["--export", str(target)]) == 0 + + assert [item.name for item in tmp_path.iterdir()] == ["out.csv"] + read_back = pandas.read_csv(target, index_col=0) + pandas.testing.assert_frame_equal(read_back, create_scores_frame()) + assert str(target) in capsys.readouterr().out + + +def test_main_reports_the_missing_pandas_extra_and_writes_nothing( + tmp_path: Path, + capsys: pytest.CaptureFixture[str], + monkeypatch: pytest.MonkeyPatch, +) -> None: + # None in sys.modules makes "import pandas" raise ImportError; the modules + # that import it are removed so that they are imported again. + monkeypatch.setitem(sys.modules, "pandas", None) + monkeypatch.delitem(sys.modules, "weather.analysis", raising=False) + monkeypatch.delitem(sys.modules, "weather.export", raising=False) + + assert main(["--export", str(tmp_path / "out.csv")]) == 1 + + captured = capsys.readouterr() + assert 'pip install "weather[pandas]"' in captured.err + assert "Sunny" in captured.out + assert "17.428" not in captured.out + assert list(tmp_path.iterdir()) == []