Public Access
Establish one invariant across the Drawable hierarchy: x is always a numpy ndarray, y is always a list of per-channel ndarrays, and empty data is the same types with zero length. - Drawable: x starts as empty ndarray; min/max helpers return 0 on empty data instead of raising; drop contradictory isinstance(self.y, list) branches - ADC_Result/Accumulation: empty constructors build ndarray x; full constructors coerce x/y/y_square with numpy.asarray; Accumulation get_ydata/get_yerr return empty ndarrays and no longer crash on empty statistics-less accumulations - MeasurementResult: fix get_lineplotdata to return the accumulated means (previously the never-populated self.y, so the GUI line plot could never draw); remove dead float/int branches in CSV and HDF writers - Error_Result: get_xdata/get_ydata return ndarrays Add unittest coverage for the invariant, empty-state accessors, constructor coercion, line plot data, CSV output and HDF round-trip. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
87 lines
3.1 KiB
Python
87 lines
3.1 KiB
Python
import io
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
|
|
import numpy as np
|
|
import tables
|
|
|
|
from damaris.data.MeasurementResult import MeasurementResult, read_from_hdf
|
|
|
|
|
|
class TestMeasurementResult(unittest.TestCase):
|
|
def test_add_zero_preserves_data(self):
|
|
"""mr + 0 must return a MeasurementResult with identical data."""
|
|
mr = MeasurementResult("test_quantity")
|
|
for i in range(3):
|
|
mr[i] = float(i * i)
|
|
mr2 = mr + 0
|
|
self.assertIsInstance(mr2, MeasurementResult)
|
|
self.assertEqual(mr2.quantity_name, "test_quantity")
|
|
np.testing.assert_array_equal(mr2.get_xdata(), mr.get_xdata())
|
|
np.testing.assert_array_equal(mr2.get_ydata(), mr.get_ydata())
|
|
|
|
def test_add_zero_returns_independent_copy(self):
|
|
"""Changing the copy must not change the original."""
|
|
mr = MeasurementResult("q")
|
|
mr[1.0] = 5.0
|
|
mr2 = mr + 0
|
|
self.assertIsNot(mr2[1.0], mr[1.0])
|
|
mr2[1.0] = mr2[1.0] + 100.0
|
|
self.assertEqual(mr[1.0].mean(), 5.0)
|
|
|
|
def test_add_nonzero_raises(self):
|
|
mr = MeasurementResult("q")
|
|
self.assertRaises(Exception, mr.__add__, 1)
|
|
|
|
def test_get_lineplotdata_returns_means(self):
|
|
"""get_lineplotdata must return the accumulated means, not self.y."""
|
|
mr = MeasurementResult("test_quantity")
|
|
for i in range(3):
|
|
mr[float(i)] = float(i * i)
|
|
k, v = mr.get_lineplotdata()
|
|
self.assertIsInstance(k, np.ndarray)
|
|
self.assertIsInstance(v, np.ndarray)
|
|
self.assertEqual(k.shape, v.shape)
|
|
np.testing.assert_array_equal(v, mr.get_ydata())
|
|
np.testing.assert_array_equal(v, [0.0, 1.0, 4.0])
|
|
|
|
def test_get_lineplotdata_empty(self):
|
|
"""get_lineplotdata of an empty result must return empty arrays."""
|
|
mr = MeasurementResult("q")
|
|
k, v = mr.get_lineplotdata()
|
|
self.assertEqual(k.shape[0], 0)
|
|
self.assertEqual(v.shape[0], 0)
|
|
|
|
def test_write_to_csv(self):
|
|
mr = MeasurementResult("q")
|
|
mr[1.0] = 5.0
|
|
mr[2.0] = 7.0
|
|
buf = io.StringIO()
|
|
mr.write_to_csv(buf)
|
|
lines = buf.getvalue().splitlines()
|
|
self.assertEqual(lines[0], "# quantity:q")
|
|
self.assertEqual(lines[1], "# x y ysigma n")
|
|
self.assertEqual(len(lines), 4)
|
|
self.assertEqual(lines[2].split()[3], "1")
|
|
self.assertEqual(lines[3].split()[3], "1")
|
|
|
|
def test_write_to_hdf_roundtrip(self):
|
|
mr = MeasurementResult("q")
|
|
mr[1.0] = 5.0
|
|
mr[2.0] = 7.0
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
path = os.path.join(tmpdir, "test.h5")
|
|
with tables.open_file(path, mode="w") as h5file:
|
|
mr.write_to_hdf(h5file, "/", "mr", "test result")
|
|
with tables.open_file(path, mode="r") as h5file:
|
|
mr2 = read_from_hdf(h5file.get_node("/mr"))
|
|
self.assertIsNotNone(mr2)
|
|
self.assertEqual(mr2.quantity_name, "q")
|
|
np.testing.assert_array_equal(mr2.get_xdata(), mr.get_xdata())
|
|
np.testing.assert_array_equal(mr2.get_ydata(), mr.get_ydata())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|