Skip to content

Commit

Permalink
Update test and requirements to pin Numpy version and use pytest
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobbieker committed Jul 19, 2024
1 parent 9089dd1 commit 4f3c384
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 77 deletions.
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
numcodecs
numcodecs==1.26.4
blosc2
pytest
83 changes: 7 additions & 76 deletions tests/test_ocf_blosc2.py
Original file line number Diff line number Diff line change
@@ -1,83 +1,14 @@
"""Unit tests for ocf_blosc2"""

import unittest

import numpy as np

import ocf_blosc2


class TestBlosc2(unittest.TestCase):
"""Test class for unittest for the class methods and the functions.
We only test our home-written functions.
The two similarly named class functions encode and decode are mostly wrappers
around our home-written function output piped into an external library.
Testing the functionality of the external functions is out of scope.
"""

def setUp(self) -> None: # noqa D102
# Define synthetic input array and the expected target array:
self.buf = np.asarray([np.nan, 0.0, 0.5, 1.0], dtype=np.float32)
self.encoded = np.asarray(
[np.nan, 0.0, 0.5, 1.0],
dtype=np.float32,
)

self.jpegxl = ocf_blosc2.Blosc2()

return super().setUp()

def test_encode(self):
"""Tests the encoding function.
After encoding the raw array, the nan-values should be gone and the
real values should be transformed to the range specified by the
constants imported from the source code. See there for more details.
"""
# Check that the enconded buffer matches the expected target
# (attention: use a copy of the originals!):
self.assertTrue(np.isclose(encode_nans(self.buf.copy()), self.encoded).all())

def test_decode(self):
"""Tests the decoding function.
When taking what was previously the encoded array and decode it,
we expect to get the original buf-array back again.
"""
# As np.nan != np.nan (!) and thus np.isclose or array comparison do not consider
# two nan-values to be close or equal, we have to replace all nan-values with
# a numeric value before comparison. This numeric value should be one that
# can not be created via decoding (e.g. a negative number).
nan_replacement = -3.14
self.assertTrue(
np.isclose(
np.nan_to_num(self.buf, nan_replacement),
np.nan_to_num(decode_nans(self.encoded.copy()), nan_replacement),
).all()
)

def test_class_roundtrip(self):
"""Tests the class-defined wrappers around our home-written functions.
We test whether a back-and-forth transformation (nested encode-decode)
will give us back our original input value.
"""
reshaped_buf = self.buf.copy().reshape((1, -1, 1))

roundtrip_result = self.jpegxl.decode(self.jpegxl.encode(reshaped_buf.copy()))

# For reasons explained in the decoding test, we have to manually replace
# the nan-values to make them comparable:
nan_replacement = -3.14
reshaped_buf = np.nan_to_num(reshaped_buf, nan_replacement)
roundtrip_result = np.nan_to_num(roundtrip_result, nan_replacement)

# When we do the comparison, we have to be very lenient, as the external library
# will have worked its compression magic, so values will not completely align.
# Also, going back and forth removes the information about the channel number
# in our test case (presumably b/c we here only have one channel for simplicity's sake).
# So we have to reshape both:
self.assertTrue(
np.isclose(reshaped_buf.reshape((-1)), roundtrip_result.reshape((-1)), atol=0.1).all()
)
def test_roundtrip():
buf = np.asarray([np.nan, 0.0, 0.5, 1.0], dtype=np.float32)
blosc2 = ocf_blosc2.Blosc2()
comp_arr = blosc2.encode(buf)
dest = np.empty(buf.shape, buf.dtype)
blosc2.decode(comp_arr, out=dest)
assert np.allclose(buf, dest, equal_nan=True)

0 comments on commit 4f3c384

Please sign in to comment.