Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions temporal/t.info/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# SPDX-License-Identifier: GPL-2.0-or-later
"""Fixture for t.info tests

Creates one project holding every dataset type t.info can report on, so that
the reported metadata can be compared against known values.
"""

import os
from types import SimpleNamespace

import pytest

import grass.script as gs
from grass.grassdb.create import create_mapset
from grass.tools import Tools

MAPSET = "tinfo_mapset"


@pytest.fixture(scope="session")
def temporal_data(tmp_path_factory):
"""Start a session with space time datasets of all types and their maps"""
tmp_path = tmp_path_factory.mktemp("t_info")
project = tmp_path / "test_project"
gs.create_project(project)
create_mapset(project / MAPSET)

with gs.setup.init(project / MAPSET, env=os.environ.copy()) as session:
tools = Tools(session=session)
tools.g_region(s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10, tbres=10)

# Maps with constant values keep the min and max metadata predictable.
for i in range(1, 4):
tools.r_mapcalc(expression=f"prec_{i} = {i}")
for i in range(1, 3):
tools.r3_mapcalc(expression=f"vol_{i} = {i}")
tools.v_random(output=f"vect_{i}", npoints=20, seed=i)
tools.r_mapcalc(expression=f"rel_{i} = {i}")

tools.t_create(
type="strds",
temporaltype="absolute",
output="precip_abs1",
title="A test",
description="A test",
)
tools.t_register(
type="raster",
flags="i",
input="precip_abs1",
maps="prec_1,prec_2,prec_3",
start="2001-01-01",
increment="1 months",
)

# A map can be registered in more than one dataset, which t.info
# reports for the map.
tools.t_create(
type="strds",
temporaltype="absolute",
output="precip_abs2",
title="A second test",
description="A second test",
)
tools.t_register(
type="raster",
input="precip_abs2",
maps="prec_2",
)

tools.t_create(
type="str3ds",
temporaltype="absolute",
output="volume_abs1",
title="A 3D test",
description="A 3D test",
)
tools.t_register(
type="raster_3d",
flags="i",
input="volume_abs1",
maps="vol_1,vol_2",
start="2001-01-01",
increment="1 months",
)

tools.t_create(
type="stvds",
temporaltype="absolute",
output="vect_abs1",
title="A vector test",
description="A vector test",
)
tools.t_register(
type="vector",
flags="i",
input="vect_abs1",
maps="vect_1,vect_2",
start="2001-01-01",
increment="1 months",
)

# Relative time datasets need their own maps because a map can hold
# only one time stamp.
tools.t_create(
type="strds",
temporaltype="relative",
output="precip_rel1",
title="A relative test",
description="A relative test",
)
tools.t_register(
type="raster",
flags="i",
input="precip_rel1",
maps="rel_1,rel_2",
start=1,
increment=1,
unit="days",
)

# A dataset without registered maps reports empty metadata fields.
tools.t_create(
type="strds",
temporaltype="absolute",
output="empty_ds",
title="An empty test",
description="An empty test",
)

# Non-ASCII text has to survive the round trip through the database.
tools.t_create(
type="strds",
temporaltype="absolute",
output="accent_ds",
title="Précipitation totale",
description="Précipitation mensuelle",
)

yield SimpleNamespace(session=session, mapset=MAPSET, tools=tools)
69 changes: 69 additions & 0 deletions temporal/t.info/tests/test_t_info_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# SPDX-License-Identifier: GPL-2.0-or-later
"""Test the t.info report about the temporal database backend (-d flag)

The expected values capture the output of t.info as it is now, so that later
changes to the interface can be checked against the established behavior.
"""

import re

import grass.script as gs
from grass.tools import Tools

BACKEND_SHELL_KEYS = [
"dbmi_python_interface",
"dbmi_string",
"sql_template_path",
"tgis_version",
"tgis_db_version",
"creation_time",
]


def test_backend_plain(temporal_data):
"""The -d flag reports the backend in a human readable table"""
tools = Tools(session=temporal_data.session)
text = tools.t_info(flags="d").text
lines = text.splitlines()

assert "Temporal DBMI backend information" in lines[0]
assert " | DBMI Python interface:...... sqlite3" in lines
assert any(line.startswith(" | Temporal database string:...") for line in lines)
assert any(line.startswith(" | SQL template path:..........") for line in lines)
assert any(line.startswith(" | tgis_version ..........") for line in lines)
assert any(line.startswith(" | tgis_db_version ..........") for line in lines)
assert any(line.startswith(" | creation_time ..........") for line in lines)
assert lines[-1].startswith(" +---------")
assert "" not in [line.strip() for line in lines]


def test_backend_shell(temporal_data):
"""The -d flag together with -g reports the backend as key value pairs"""
tools = Tools(session=temporal_data.session)
text = tools.t_info(flags="dg").text
info = gs.parse_key_val(text)

assert list(info.keys()) == BACKEND_SHELL_KEYS
assert info["dbmi_python_interface"] == "'sqlite3'"
assert info["dbmi_string"].endswith("sqlite.db'")
assert info["tgis_version"] == "'2'"
assert info["tgis_db_version"] == "'3'"


def test_backend_shell_values_are_quoted(temporal_data):
"""All values of the backend information are quoted in the shell output"""
tools = Tools(session=temporal_data.session)
text = tools.t_info(flags="dg").text

for line in text.splitlines():
assert re.fullmatch(r"\w+='.*'", line), line


def test_backend_ignores_input(temporal_data):
"""The -d flag reports the backend only, even if a dataset is given"""
tools = Tools(session=temporal_data.session)
with_input = tools.t_info(flags="d", type="strds", input="precip_abs1").text
without_input = tools.t_info(flags="d").text

assert with_input == without_input
assert "precip_abs1" not in with_input
188 changes: 188 additions & 0 deletions temporal/t.info/tests/test_t_info_str3ds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# SPDX-License-Identifier: GPL-2.0-or-later
"""Test t.info with space time 3D raster datasets and 3D raster maps

The expected values capture the output of t.info as it is now, so that later
changes to the interface can be checked against the established behavior.
"""

import grass.script as gs
from grass.tools import Tools

# Keys whose values differ between runs, systems, or users.
VOLATILE_KEYS = ("creation_time", "modification_time", "creator", "raster3d_register")

STR3DS_SHELL_KEYS = [
"id",
"name",
"mapset",
"creator",
"temporal_type",
"creation_time",
"modification_time",
"semantic_type",
"start_time",
"end_time",
"granularity",
"map_time",
"north",
"south",
"east",
"west",
"top",
"bottom",
"raster3d_register",
"tbres_min",
"tbres_max",
"nsres_min",
"nsres_max",
"ewres_min",
"ewres_max",
"min_min",
"min_max",
"max_min",
"max_max",
"aggregation_type",
"number_of_maps",
]

RASTER3D_SHELL_KEYS = [
"id",
"name",
"mapset",
"creator",
"temporal_type",
"creation_time",
"start_time",
"end_time",
"north",
"south",
"east",
"west",
"top",
"bottom",
"datatype",
"cols",
"rows",
"number_of_cells",
"nsres",
"ewres",
"min",
"max",
"depths",
"tbres",
"registered_datasets",
]


def shell_info(tools, **kwargs):
"""Return the shell style output of t.info parsed into a dictionary"""
return gs.parse_key_val(tools.t_info(flags="g", **kwargs).text)


def stable_items(info):
"""Return the parsed shell output without the keys which cannot be compared"""
return {key: value for key, value in info.items() if key not in VOLATILE_KEYS}


def test_shell_keys(temporal_data):
"""Shell output has the expected keys in the expected order"""
tools = Tools(session=temporal_data.session)
info = shell_info(tools, type="str3ds", input="volume_abs1")

assert list(info.keys()) == STR3DS_SHELL_KEYS


def test_shell_values(temporal_data):
"""Shell output reports the metadata of the dataset"""
tools = Tools(session=temporal_data.session)
info = shell_info(tools, type="str3ds", input="volume_abs1")

assert stable_items(info) == {
"id": f"volume_abs1@{temporal_data.mapset}",
"name": "volume_abs1",
"mapset": temporal_data.mapset,
"temporal_type": "absolute",
"semantic_type": "mean",
"start_time": "'2001-01-01 00:00:00'",
"end_time": "'2001-03-01 00:00:00'",
"granularity": "'1 month'",
"map_time": "interval",
"north": "80.0",
"south": "0.0",
"east": "120.0",
"west": "0.0",
"top": "50.0",
"bottom": "0.0",
"tbres_min": "10.0",
"tbres_max": "10.0",
"nsres_min": "10.0",
"nsres_max": "10.0",
"ewres_min": "10.0",
"ewres_max": "10.0",
"min_min": "1.0",
"min_max": "2.0",
"max_min": "1.0",
"max_max": "2.0",
"aggregation_type": "None",
"number_of_maps": "2",
}
assert info["raster3d_register"].startswith("raster3d_map_register_")


def test_plain_info(temporal_data):
"""Plain output reports the metadata in a human readable table"""
tools = Tools(session=temporal_data.session)
text = tools.t_info(type="str3ds", input="volume_abs1").text

assert "Space Time 3D Raster Dataset" in text
assert f"Id: ........................ volume_abs1@{temporal_data.mapset}" in text
assert "Granularity:................ 1 month" in text
assert "Number of registered maps:.. 2" in text
assert "Title:" in text
assert "Command history:" in text


def test_raster3d_map_shell(temporal_data):
"""Shell output for a registered 3D raster map reports the map metadata"""
tools = Tools(session=temporal_data.session)
info = shell_info(tools, type="raster_3d", input="vol_1")

assert list(info.keys()) == RASTER3D_SHELL_KEYS
assert stable_items(info) == {
"id": f"vol_1@{temporal_data.mapset}",
"name": "vol_1",
"mapset": temporal_data.mapset,
"temporal_type": "absolute",
"start_time": "'2001-01-01 00:00:00'",
"end_time": "'2001-02-01 00:00:00'",
"north": "80.0",
"south": "0.0",
"east": "120.0",
"west": "0.0",
"top": "50.0",
"bottom": "0.0",
"datatype": "DCELL",
"cols": "12",
"rows": "8",
"number_of_cells": "480",
"nsres": "10.0",
"ewres": "10.0",
"min": "1.0",
"max": "1.0",
"depths": "5",
"tbres": "10.0",
"registered_datasets": f"volume_abs1@{temporal_data.mapset}",
}


def test_raster3d_map_plain(temporal_data):
"""Plain output for a registered 3D raster map reports the map metadata"""
tools = Tools(session=temporal_data.session)
text = tools.t_info(type="raster_3d", input="vol_1").text

assert "3D Raster Dataset" in text
assert "Datatype:................... DCELL" in text
assert "Number of columns:.......... 12" in text
assert "Number of rows:............. 8" in text
assert "Number of cells:............ 480" in text
assert f"Registered datasets ........ volume_abs1@{temporal_data.mapset}" in text
Loading
Loading