From 122be1920ed33916f12fd2041a0fa0186d599a8c Mon Sep 17 00:00:00 2001
From: Aaron Zuspan <50475791+aazuspan@users.noreply.github.com>
Date: Fri, 29 Nov 2024 12:10:39 -0800
Subject: [PATCH] Replace manual HTML tests with regression tests (#37)
Also add more example objects and a script for viewing rendered
HTML.
---
.gitignore | 4 +-
CONTRIBUTING.md | 16 +-
pyproject.toml | 2 +
tests/cache.py | 2 +-
tests/data/.gitignore | 2 +
tests/data/test_regression_array_.yml | 6 +
tests/data/test_regression_band_dict_.yml | 10 +
tests/data/test_regression_classifier_.yml | 3 +
tests/data/test_regression_clusterer_.yml | 4 +
.../test_regression_confusion_matrix_.yml | 6 +
.../data/test_regression_constant_image_.yml | 16 +
tests/data/test_regression_date_.yml | 4 +
tests/data/test_regression_daterange_.yml | 6 +
tests/data/test_regression_dict_.yml | 3 +
tests/data/test_regression_feature_.yml | 8 +
.../test_regression_feature_collection_.yml | 15 +
tests/data/test_regression_filter_.yml | 4 +
.../test_regression_image_collection_.yml | 40 +++
tests/data/test_regression_kernel_.yml | 19 ++
tests/data/test_regression_linearring_.yml | 13 +
tests/data/test_regression_linestring_.yml | 11 +
tests/data/test_regression_long_list_.yml | 16 +
.../data/test_regression_multilinestring_.yml | 9 +
tests/data/test_regression_multipoint_.yml | 8 +
tests/data/test_regression_multipolygon_.yml | 26 ++
tests/data/test_regression_null_feature_.yml | 4 +
tests/data/test_regression_number_.yml | 2 +
tests/data/test_regression_pixel_custom_.yml | 5 +
tests/data/test_regression_pixel_double_.yml | 4 +
tests/data/test_regression_pixel_float_.yml | 4 +
tests/data/test_regression_pixel_int16_.yml | 5 +
tests/data/test_regression_pixel_int32_.yml | 5 +
tests/data/test_regression_pixel_int64_.yml | 6 +
tests/data/test_regression_pixel_int8_.yml | 5 +
tests/data/test_regression_pixel_uint16_.yml | 5 +
tests/data/test_regression_pixel_uint32_.yml | 5 +
tests/data/test_regression_pixel_uint8_.yml | 5 +
tests/data/test_regression_point_.yml | 5 +
tests/data/test_regression_polygon_.yml | 14 +
tests/data/test_regression_projection_.yml | 8 +
tests/data/test_regression_reducer_.yml | 4 +
tests/data/test_regression_short_list_.yml | 5 +
tests/data/test_regression_string_.yml | 2 +
tests/data/test_regression_type_dict_.yml | 4 +
.../test_regression_unbounded_band_dict_.yml | 6 +
tests/preview_html.py | 27 ++
tests/test_html.py | 315 ++++++------------
47 files changed, 470 insertions(+), 228 deletions(-)
create mode 100644 tests/data/.gitignore
create mode 100644 tests/data/test_regression_array_.yml
create mode 100644 tests/data/test_regression_band_dict_.yml
create mode 100644 tests/data/test_regression_classifier_.yml
create mode 100644 tests/data/test_regression_clusterer_.yml
create mode 100644 tests/data/test_regression_confusion_matrix_.yml
create mode 100644 tests/data/test_regression_constant_image_.yml
create mode 100644 tests/data/test_regression_date_.yml
create mode 100644 tests/data/test_regression_daterange_.yml
create mode 100644 tests/data/test_regression_dict_.yml
create mode 100644 tests/data/test_regression_feature_.yml
create mode 100644 tests/data/test_regression_feature_collection_.yml
create mode 100644 tests/data/test_regression_filter_.yml
create mode 100644 tests/data/test_regression_image_collection_.yml
create mode 100644 tests/data/test_regression_kernel_.yml
create mode 100644 tests/data/test_regression_linearring_.yml
create mode 100644 tests/data/test_regression_linestring_.yml
create mode 100644 tests/data/test_regression_long_list_.yml
create mode 100644 tests/data/test_regression_multilinestring_.yml
create mode 100644 tests/data/test_regression_multipoint_.yml
create mode 100644 tests/data/test_regression_multipolygon_.yml
create mode 100644 tests/data/test_regression_null_feature_.yml
create mode 100644 tests/data/test_regression_number_.yml
create mode 100644 tests/data/test_regression_pixel_custom_.yml
create mode 100644 tests/data/test_regression_pixel_double_.yml
create mode 100644 tests/data/test_regression_pixel_float_.yml
create mode 100644 tests/data/test_regression_pixel_int16_.yml
create mode 100644 tests/data/test_regression_pixel_int32_.yml
create mode 100644 tests/data/test_regression_pixel_int64_.yml
create mode 100644 tests/data/test_regression_pixel_int8_.yml
create mode 100644 tests/data/test_regression_pixel_uint16_.yml
create mode 100644 tests/data/test_regression_pixel_uint32_.yml
create mode 100644 tests/data/test_regression_pixel_uint8_.yml
create mode 100644 tests/data/test_regression_point_.yml
create mode 100644 tests/data/test_regression_polygon_.yml
create mode 100644 tests/data/test_regression_projection_.yml
create mode 100644 tests/data/test_regression_reducer_.yml
create mode 100644 tests/data/test_regression_short_list_.yml
create mode 100644 tests/data/test_regression_string_.yml
create mode 100644 tests/data/test_regression_type_dict_.yml
create mode 100644 tests/data/test_regression_unbounded_band_dict_.yml
create mode 100644 tests/preview_html.py
diff --git a/.gitignore b/.gitignore
index 2fdc256..f794d2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,4 @@ __pycache__/
htmlcov/
dist/
*.egg-info/
-.tox/
-
-tests/data/
\ No newline at end of file
+.tox/
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b3aa822..2655a35 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -56,11 +56,13 @@ Additional arguments can be passed to `pytest` after the script name, e.g.:
hatch run test:all -k feature
```
+Rendered HTML is tested using [pytest-regressions](https://pytest-regressions.readthedocs.io/en/latest/overview.html), which compares the current HTML output for each object to the previously recorded output. Tests will fail if the HTML output changes. If the change is correct (i.e. an update to the HTML formatting or a difference in object representations in Earth Engine), use the `--force-regen` argument to regenerate a new "reference" HTML output.
+
### Building New Tests
New features should have unit tests. If your test needs to use `getInfo` to retrieve data from an Earth Engine object, you'll need to use the caching system described below.
-Using `getInfo` to retrieve data from an Earth Engine object can be slow and network-dependent. To speed up tests, `eerepr` uses a caching function `tests.cache.get_info` to load data. This function takes an Earth Engine object and either 1) retrieves its info from a local cache file if it has been used before, or 2) retrieves it from the server and adds it to the cache. The cache directory and file (`tests/data/data.json`) will be created automatically the first time tests are run.
+Using `getInfo` to retrieve data from an Earth Engine object can be slow and network-dependent. To speed up tests, `eerepr` uses a caching function `tests.cache.get_info` to load data. This function takes an Earth Engine object and either 1) retrieves its info from a local cache file if it has been used before, or 2) retrieves it from the server and adds it to the cache. The cache directory and file (`tests/data/.cache.json`) will be created automatically the first time tests are run.
To demonstrate, let's write a new dummy test that checks the properties of a custom `ee.Image`.
@@ -75,6 +77,14 @@ def test_my_image():
assert "custom_property" in info["properties"]
```
-The first time the test is run, `getInfo` will be used to retrieve the image metadata and store it in `tests/data/data.json`. Subsequent runs will pull the data directly from the cache.
+The first time the test is run, `getInfo` will be used to retrieve the image metadata and store it in `tests/data/.cache.json`. Subsequent runs will pull the data directly from the cache. Caches are kept locally and are not version-controlled.
+
+When a new object is added to regression testing, the first run will fail and generate a new reference file. Subsequent tests will pass. Output from regression testing *is* version controlled, so new outputs should be committed.
+
+### Previewing HTML Output
-Caches are kept locally and are not version-controlled, so there's no need to commit newly added objects.
\ No newline at end of file
+Running the command below renders an HTML repr with a variety of different EE objects and opens it in the default web browser. Use this to visually compare results with outputs from the Code Editor.
+
+```bash
+hatch run test:html
+```
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index e718d68..ff4bea8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -38,11 +38,13 @@ dependencies = ["pre-commit"]
dependencies = [
"pytest",
"pytest-cov",
+ "pytest-regressions",
]
[tool.hatch.envs.test.scripts]
all = "pytest . {args}"
cov = "pytest . --cov=eerepr {args}"
+html = "python tests/preview_html.py"
[tool.ruff.lint]
select = ["E", "I", "F", "B", "FA", "UP", "ISC", "PT", "Q", "RET", "SIM", "PERF"]
diff --git a/tests/cache.py b/tests/cache.py
index 2172564..df54d4c 100644
--- a/tests/cache.py
+++ b/tests/cache.py
@@ -4,7 +4,7 @@
import ee
CACHE_DIR = Path(__file__).parent / "data/"
-CACHE_PATH = CACHE_DIR / "data.json"
+CACHE_PATH = CACHE_DIR / ".cache.json"
def get_info(obj: ee.ComputedObject) -> dict:
diff --git a/tests/data/.gitignore b/tests/data/.gitignore
new file mode 100644
index 0000000..397fff6
--- /dev/null
+++ b/tests/data/.gitignore
@@ -0,0 +1,2 @@
+.cache.json
+.preview.html
\ No newline at end of file
diff --git a/tests/data/test_regression_array_.yml b/tests/data/test_regression_array_.yml
new file mode 100644
index 0000000..00c5558
--- /dev/null
+++ b/tests/data/test_regression_array_.yml
@@ -0,0 +1,6 @@
+'
0:1
1:2
0:3
1:4
'
diff --git a/tests/data/test_regression_band_dict_.yml b/tests/data/test_regression_band_dict_.yml
new file mode 100644
index 0000000..2c2f5d8
--- /dev/null
+++ b/tests/data/test_regression_band_dict_.yml
@@ -0,0 +1,10 @@
+'
id:B1
crs:EPSG:32610
type:PixelType
max:65535
min:0
precision:int
0:1830
1:1830
'
diff --git a/tests/data/test_regression_classifier_.yml b/tests/data/test_regression_classifier_.yml
new file mode 100644
index 0000000..0f13815
--- /dev/null
+++ b/tests/data/test_regression_classifier_.yml
@@ -0,0 +1,3 @@
+
type:Classifier.smileKNN
+...
diff --git a/tests/data/test_regression_clusterer_.yml b/tests/data/test_regression_clusterer_.yml
new file mode 100644
index 0000000..5d4dc76
--- /dev/null
+++ b/tests/data/test_regression_clusterer_.yml
@@ -0,0 +1,4 @@
+
type:Clusterer.wekaKMeans
nClusters:2
+...
diff --git a/tests/data/test_regression_confusion_matrix_.yml b/tests/data/test_regression_confusion_matrix_.yml
new file mode 100644
index 0000000..00c5558
--- /dev/null
+++ b/tests/data/test_regression_confusion_matrix_.yml
@@ -0,0 +1,6 @@
+'
0:1
1:2
0:3
1:4
'
diff --git a/tests/data/test_regression_constant_image_.yml b/tests/data/test_regression_constant_image_.yml
new file mode 100644
index 0000000..dd036fb
--- /dev/null
+++ b/tests/data/test_regression_constant_image_.yml
@@ -0,0 +1,16 @@
+'
type:Image
id:foo
id:constant
crs:EPSG:4326
0:1
1:0
2:0
3:0
4:1
5:0
type:PixelType
max:0
min:0
precision:int
'
diff --git a/tests/data/test_regression_date_.yml b/tests/data/test_regression_date_.yml
new file mode 100644
index 0000000..5c0a907
--- /dev/null
+++ b/tests/data/test_regression_date_.yml
@@ -0,0 +1,4 @@
+
type:Date
value:1616853667000
+...
diff --git a/tests/data/test_regression_daterange_.yml b/tests/data/test_regression_daterange_.yml
new file mode 100644
index 0000000..bb8a44b
--- /dev/null
+++ b/tests/data/test_regression_daterange_.yml
@@ -0,0 +1,6 @@
+'
type:DateRange
0:1577912470000
1:1646145131000
'
diff --git a/tests/data/test_regression_dict_.yml b/tests/data/test_regression_dict_.yml
new file mode 100644
index 0000000..fac8c43
--- /dev/null
+++ b/tests/data/test_regression_dict_.yml
@@ -0,0 +1,3 @@
+
foo:bar
+...
diff --git a/tests/data/test_regression_feature_.yml b/tests/data/test_regression_feature_.yml
new file mode 100644
index 0000000..75e43bd
--- /dev/null
+++ b/tests/data/test_regression_feature_.yml
@@ -0,0 +1,8 @@
+'
type:Feature
type:Point
0:0
1:0
foo:bar
'
diff --git a/tests/data/test_regression_feature_collection_.yml b/tests/data/test_regression_feature_collection_.yml
new file mode 100644
index 0000000..231be8a
--- /dev/null
+++ b/tests/data/test_regression_feature_collection_.yml
@@ -0,0 +1,15 @@
+'
type:FeatureCollection
foo:String
system:index:String
type:Feature
id:0
type:Point
0:0
1:0
foo:bar
'
diff --git a/tests/data/test_regression_filter_.yml b/tests/data/test_regression_filter_.yml
new file mode 100644
index 0000000..c89e309
--- /dev/null
+++ b/tests/data/test_regression_filter_.yml
@@ -0,0 +1,4 @@
+
type:Filter.eq
leftField:foo
rightValue:bar
+...
diff --git a/tests/data/test_regression_image_collection_.yml b/tests/data/test_regression_image_collection_.yml
new file mode 100644
index 0000000..580d791
--- /dev/null
+++ b/tests/data/test_regression_image_collection_.yml
@@ -0,0 +1,40 @@
+'
type:ImageCollection
test_prop:42
type:Image
id:constant
crs:EPSG:4326
0:1
1:0
2:0
3:0
4:1
5:0
type:PixelType
max:0
min:0
precision:int
system:index:0
type:Image
id:constant
crs:EPSG:4326
0:1
1:0
2:0
3:0
4:1
5:0
type:PixelType
max:1
min:1
precision:int
system:index:1
'
diff --git a/tests/data/test_regression_kernel_.yml b/tests/data/test_regression_kernel_.yml
new file mode 100644
index 0000000..2ca6636
--- /dev/null
+++ b/tests/data/test_regression_kernel_.yml
@@ -0,0 +1,19 @@
+"