noaa-goes-visualization/tests/test_paths.py

115 lines
4 KiB
Python

import datetime
import os
import pytest
from suvi import paths
GOOD = "dr_suvi-l2-ci171_g16_s20240510T000000Z_e20240510T000400Z_v1-0-2.fits"
def test_parses_a_real_filename():
frame = paths.parse_frame_filename(GOOD)
assert frame.satellite == 16
assert frame.wavelength == 171
assert frame.version == "1-0-2"
assert frame.label is None
assert frame.t_end - frame.t_start == paths.CADENCE
assert frame.t_start == int(
datetime.datetime(2024, 5, 10, tzinfo=datetime.timezone.utc).timestamp()
)
@pytest.mark.parametrize("label", [None, "f", "e"])
def test_filename_round_trips(label):
name = GOOD if label is None else GOOD.replace(".fits", f"_{label}.fits")
frame = paths.parse_frame_filename(name)
assert frame.label == label
assert frame.filename(label) == name
def test_double_suffix_keeps_outermost_label():
"""Re-processing an already-labelled file produced '..._f_f.fits' in the archive."""
frame = paths.parse_frame_filename(GOOD.replace(".fits", "_f_e.fits"))
assert frame.label == "e"
assert frame.filename() == GOOD
def test_relpath_files_under_the_start_date():
"""A frame opening at 23:58 belongs to that day, not the day it ends on."""
name = "dr_suvi-l2-ci304_g18_s20241231T235800Z_e20250101T000200Z_v1-0-2.fits"
frame = paths.parse_frame_filename(name)
assert frame.relpath() == (
"goes18/l2/data/suvi-l2-ci304/2024/12/31/" + name
)
def test_slot_identifies_the_observation():
frame = paths.parse_frame_filename(GOOD)
labelled = paths.parse_frame_filename(GOOD.replace(".fits", "_e.fits"))
assert frame.slot == labelled.slot == (16, 171, frame.t_start)
def test_error_plot_name_matches_legacy_filter_output():
frame = paths.parse_frame_filename(GOOD)
assert frame.error_plot_name() == GOOD.replace(".fits", "_e.jpg")
@pytest.mark.parametrize(
"name",
[
"",
"x" * 300,
"README.txt",
"dr_suvi-l2-ci171_g16_s20240510T000000Z_e20240510T000400Z_v1-0-2.fits.bak",
"dr_suvi-l2-ci999_g16_s20240510T000000Z_e20240510T000400Z_v1-0-2.fits", # bad band
"dr_suvi-l2-ci171_g17_s20240510T000000Z_e20240510T000400Z_v1-0-2.fits", # excluded sat
"dr_suvi-l2-ci171_g16_s20241310T000000Z_e20240510T000400Z_v1-0-2.fits", # month 13
"dr_suvi-l2-ci171_g16_s20240510T000400Z_e20240510T000000Z_v1-0-2.fits", # end <= start
"dr_suvi-l2-ci171_g16_s20240510T000000Z_e20240510T000400Z_v1-0-2_x.fits", # bad label
"../dr_suvi-l2-ci171_g16_s20240510T000000Z_e20240510T000400Z_v1-0-2.fits",
"sub/dr_suvi-l2-ci171_g16_s20240510T000000Z_e20240510T000400Z_v1-0-2.fits",
],
)
def test_rejects_malformed_names(name):
assert paths.parse_frame_filename(name) is None
def test_rejects_non_string_input():
for value in (None, 42, b"bytes", ["list"]):
assert paths.parse_frame_filename(value) is None
def test_filename_rejects_unknown_label():
frame = paths.parse_frame_filename(GOOD)
with pytest.raises(ValueError):
frame.filename("q")
def test_abspath_resolves_within_the_root(tmp_path):
frame = paths.parse_frame_filename(GOOD)
resolved = paths.abspath(frame.relpath(), root=str(tmp_path))
assert resolved.startswith(str(tmp_path) + os.sep)
assert resolved.endswith(GOOD)
@pytest.mark.parametrize("hostile", ["../../etc/passwd", "goes16/../../../etc/passwd"])
def test_abspath_refuses_to_escape_the_root(tmp_path, hostile):
with pytest.raises(ValueError):
paths.abspath(hostile, root=str(tmp_path))
def test_data_root_honours_the_environment(archive):
assert paths.data_root() == str(archive)
def test_default_db_path_honours_the_environment(monkeypatch, tmp_path):
target = tmp_path / "scratch.sqlite"
monkeypatch.setenv("SUVI_DB", str(target))
assert paths.default_db_path() == str(target)
def test_wavelength_dirs_covers_every_combination(tmp_path):
dirs = paths.wavelength_dirs(str(tmp_path))
assert len(dirs) == len(paths.SATELLITES) * len(paths.WAVELENGTHS)
assert len(set(dirs)) == len(dirs)