Skip to content

Commit 49e67c7

Browse files
committed
Generalize array metadata spec verification test
1 parent 935ac71 commit 49e67c7

File tree

1 file changed

+59
-19
lines changed

1 file changed

+59
-19
lines changed

tests/test_properties.py

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import dataclasses
22
import json
3+
from numbers import Real
34

45
import numpy as np
56
import pytest
@@ -230,24 +231,63 @@ def test_roundtrip_array_metadata_from_json(data: st.DataObject, zarr_format: in
230231
# assert_array_equal(nparray, zarray[:])
231232

232233

233-
@given(npst.from_dtype(dtype=np.dtype("float64"), allow_nan=True, allow_infinity=True))
234-
def test_v2meta_nan_and_infinity(fill_value):
235-
metadata = ArrayV2Metadata(
236-
shape=[10],
237-
dtype=np.dtype("float64"),
238-
chunks=[5],
239-
fill_value=fill_value,
240-
order="C",
241-
)
234+
def serialized_float_is_valid(serialized):
235+
"""
236+
Validate that the serialized representation of a float conforms to the spec.
242237
243-
buffer_dict = metadata.to_buffer_dict(prototype=default_buffer_prototype())
244-
zarray_dict = json.loads(buffer_dict[ZARRAY_JSON].to_bytes().decode())
245-
246-
if np.isnan(fill_value):
247-
assert zarray_dict["fill_value"] == "NaN"
248-
elif np.isinf(fill_value) and fill_value > 0:
249-
assert zarray_dict["fill_value"] == "Infinity"
250-
elif np.isinf(fill_value):
251-
assert zarray_dict["fill_value"] == "-Infinity"
238+
The specification requires that a serialized float must be either:
239+
- A JSON number, or
240+
- One of the strings "NaN", "Infinity", or "-Infinity".
241+
242+
Args:
243+
serialized: The value produced by JSON serialization for a floating point number.
244+
245+
Returns:
246+
bool: True if the serialized value is valid according to the spec, False otherwise.
247+
"""
248+
if isinstance(serialized, Real):
249+
return True
250+
return serialized in ("NaN", "Infinity", "-Infinity")
251+
252+
253+
@given(meta=array_metadata()) # type: ignore[misc]
254+
def test_array_metadata_meets_spec(meta: ArrayV2Metadata | ArrayV3Metadata) -> None:
255+
"""
256+
Validate that the array metadata produced by the library conforms to the relevant spec (V2 vs V3).
257+
258+
For ArrayV2Metadata:
259+
- Ensures that 'zarr_format' is 2.
260+
- Verifies that 'filters' is either None or a tuple (and not an empty tuple).
261+
For ArrayV3Metadata:
262+
- Ensures that 'zarr_format' is 3.
263+
264+
For both versions:
265+
- If the dtype is a floating point of some kind, verifies of fill values:
266+
* NaN is serialized as the string "NaN"
267+
* Positive Infinity is serialized as the string "Infinity"
268+
* Negative Infinity is serialized as the string "-Infinity"
269+
* Other fill values are preserved as-is.
270+
- If the dtype is a complex number of some kind, verifies that each component of the fill
271+
value (real and imaginary) satisfies the serialization rules for floating point numbers.
272+
273+
Note:
274+
This test validates spec-compliance for array metadata serialization.
275+
It is a work-in-progress and should be expanded as further edge cases are identified.
276+
"""
277+
asdict_dict = meta.to_dict()
278+
279+
# version-specific validations
280+
if isinstance(meta, ArrayV2Metadata):
281+
assert asdict_dict["filters"] != ()
282+
assert asdict_dict["filters"] is None or isinstance(asdict_dict["filters"], tuple)
283+
assert asdict_dict["zarr_format"] == 2
252284
else:
253-
assert zarray_dict["fill_value"] == fill_value
285+
assert asdict_dict["zarr_format"] == 3
286+
287+
# version-agnostic validations
288+
if meta.dtype.kind == "f":
289+
assert serialized_float_is_valid(asdict_dict["fill_value"])
290+
if meta.dtype.kind == "c":
291+
# fill_value should be a two-element array [real, imag].
292+
assert serialized_float_is_valid(asdict_dict["fill_value"].real)
293+
assert serialized_float_is_valid(asdict_dict["fill_value"].imag)

0 commit comments

Comments
 (0)