From a5417099b0f78fd168e827de740a14d07b71260f Mon Sep 17 00:00:00 2001 From: Ruben Verweij Date: Fri, 17 Mar 2017 09:52:28 +0100 Subject: [PATCH] Extend unit tests --- nd2reader/artificial.py | 8 ++++---- nd2reader/common.py | 2 +- nd2reader/legacy.py | 7 +++++-- nd2reader/raw_metadata.py | 17 ++++++++++++----- tests/test_common.py | 15 ++++++++++----- tests/test_parser.py | 9 +++++++++ tests/test_raw_metadata.py | 18 +++++++++++++++++- tests/test_reader.py | 13 +++++++++++++ 8 files changed, 71 insertions(+), 18 deletions(-) diff --git a/nd2reader/artificial.py b/nd2reader/artificial.py index ec45f4d..68b5cdb 100644 --- a/nd2reader/artificial.py +++ b/nd2reader/artificial.py @@ -9,9 +9,9 @@ class ArtificialND2(object): """Artificial ND2 class (for testing purposes) """ - def __init__(self, file): + def __init__(self, file, version=(3, 0)): self._fh = open(file, 'wb') - self.write_version() + self.write_version(version) def __enter__(self): return self @@ -35,14 +35,14 @@ class ArtificialND2(object): if self._fh is not None: self._fh.close() - def write_version(self): + def write_version(self, version=(3, 0)): """Write file header """ # write 16 empty bytes self._fh.write(bytearray(16)) # write version info - version_info = six.b('ND2 FILE SIGNATURE CHUNK NAME01!Ver3.0') + version_info = six.b('ND2 FILE SIGNATURE CHUNK NAME01!Ver%s.%s' % version) self._fh.write(version_info) @staticmethod diff --git a/nd2reader/common.py b/nd2reader/common.py index ec3c574..0e3c129 100644 --- a/nd2reader/common.py +++ b/nd2reader/common.py @@ -54,7 +54,7 @@ def read_chunk(fh, chunk_location): bytes: the data at the chunk location """ - if chunk_location is None: + if chunk_location is None or fh is None: return None fh.seek(chunk_location) # The chunk metadata is always 16 bytes long diff --git a/nd2reader/legacy.py b/nd2reader/legacy.py index 333198c..9b010b8 100644 --- a/nd2reader/legacy.py +++ b/nd2reader/legacy.py @@ -91,7 +91,7 @@ class Nd2(object): int: the pixel height of the image """ - return self.reader.metadata["height"] if self.reader.metadata["height"] is not None else 0 + return self._get_width_or_height("height") @property def width(self): @@ -101,7 +101,10 @@ class Nd2(object): int: the pixel width of the image """ - return self.reader.metadata["width"] if self.reader.metadata["width"] is not None else 0 + return self._get_width_or_height("width") + + def _get_width_or_height(self, key): + return self.reader.metadata[key] if self.reader.metadata[key] is not None else 0 @property def z_levels(self): diff --git a/nd2reader/raw_metadata.py b/nd2reader/raw_metadata.py index 11b04ce..89b574b 100644 --- a/nd2reader/raw_metadata.py +++ b/nd2reader/raw_metadata.py @@ -140,14 +140,21 @@ class RawMetadata(object): textinfo = self.image_text_info[six.b('SLxImageTextInfo')].values() for line in textinfo: - if six.b("Dimensions:") in line: - entries = line.split(six.b("\r\n")) - for entry in entries: - if entry.startswith(six.b("Dimensions:")): - return entry + entry = self._parse_dimension_text_line(line) + if entry is not None: + return entry return dimension_text + @staticmethod + def _parse_dimension_text_line(line): + if six.b("Dimensions:") in line: + entries = line.split(six.b("\r\n")) + for entry in entries: + if entry.startswith(six.b("Dimensions:")): + return entry + return None + def _parse_dimension(self, pattern): dimension_text = self._parse_dimension_text() if dimension_text is None: diff --git a/tests/test_common.py b/tests/test_common.py index ac71516..afee44b 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -1,4 +1,3 @@ -import io import unittest from os import path import six @@ -6,7 +5,7 @@ import struct from nd2reader.artificial import ArtificialND2 from nd2reader.common import get_version, parse_version, parse_date, _add_to_metadata, _parse_unsigned_char, \ - _parse_unsigned_int, _parse_unsigned_long, _parse_double, _parse_string + _parse_unsigned_int, _parse_unsigned_long, _parse_double from nd2reader.exceptions import InvalidVersionError @@ -56,6 +55,12 @@ class TestCommon(unittest.TestCase): result = parse_date(textinfo) self.assertEqual(result.strftime(date_format), date) + def test_parse_date_exception(self): + date = 'i am no date' + textinfo = {six.b('TextInfoItem9'): six.b(date)} + result = parse_date(textinfo) + self.assertIsNone(result) + def test_add_to_meta_simple(self): metadata = {} _add_to_metadata(metadata, 'test', 'value') @@ -72,9 +77,9 @@ class TestCommon(unittest.TestCase): self.assertDictEqual(metadata, {'test': ['value1', 'value2', 'value3']}) @staticmethod - def _prepare_bin_stream(format, value): - file = io.BytesIO() - data = struct.pack(format, value) + def _prepare_bin_stream(binary_format, value): + file = six.BytesIO() + data = struct.pack(binary_format, value) file.write(data) file.seek(0) return file diff --git a/tests/test_parser.py b/tests/test_parser.py index bfb8f81..04ec4f8 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1,6 +1,7 @@ import unittest from os import path from nd2reader.artificial import ArtificialND2 +from nd2reader.exceptions import InvalidVersionError from nd2reader.parser import Parser @@ -12,6 +13,7 @@ class TestParser(unittest.TestCase): def setUp(self): dir_path = path.dirname(path.realpath(__file__)) self.test_file = path.join(dir_path, 'test_data/test.nd2') + self.create_test_nd2() def test_can_open_test_file(self): self.create_test_nd2() @@ -19,3 +21,10 @@ class TestParser(unittest.TestCase): with open(self.test_file, 'rb') as fh: parser = Parser(fh) self.assertTrue(parser.supported) + + def test_cannot_open_wrong_version(self): + with ArtificialND2(self.test_file, version=('a', 'b')) as artificial: + artificial.close() + + with open(self.test_file, 'rb') as fh: + self.assertRaises(InvalidVersionError, Parser, fh) diff --git a/tests/test_raw_metadata.py b/tests/test_raw_metadata.py index 9bb436b..ef9972a 100644 --- a/tests/test_raw_metadata.py +++ b/tests/test_raw_metadata.py @@ -1,10 +1,15 @@ import unittest + +from nd2reader.artificial import ArtificialND2 +from nd2reader.label_map import LabelMap from nd2reader.raw_metadata import RawMetadata class TestRawMetadata(unittest.TestCase): def setUp(self): - self.metadata = RawMetadata(None, None) + self.raw_text, self.locations = ArtificialND2.create_label_map_bytes() + self.label_map = LabelMap(self.raw_text) + self.metadata = RawMetadata(None, self.label_map) def test_parse_roi_shape(self): self.assertEqual(self.metadata._parse_roi_shape(3), 'rectangle') @@ -16,3 +21,14 @@ class TestRawMetadata(unittest.TestCase): self.assertEqual(self.metadata._parse_roi_type(2), 'background') self.assertEqual(self.metadata._parse_roi_type(4), 'stimulation') self.assertIsNone(self.metadata._parse_roi_type(-1)) + + def test_dict(self): + self.assertTrue(type(self.metadata.__dict__) is dict) + + def test_parsed_metadata(self): + metadata = self.metadata.get_parsed_metadata() + self.assertTrue(type(metadata) is dict) + required_keys = ["height", "width", "date", "fields_of_view", "frames", "z_levels", "total_images_per_channel", + "channels", "pixel_microns"] + for required in required_keys: + self.assertTrue(required in metadata) diff --git a/tests/test_reader.py b/tests/test_reader.py index 73fa31e..c7842d7 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -3,6 +3,7 @@ from os import path import numpy as np from nd2reader.artificial import ArtificialND2 +from nd2reader.parser import Parser from nd2reader.reader import ND2Reader @@ -28,3 +29,15 @@ class TestReader(unittest.TestCase): def test_extension(self): self.assertTrue('nd2' in ND2Reader.class_exts()) + + def test_get_metadata_property(self): + self.create_test_nd2() + with ND2Reader(self.test_file) as reader: + self.assertIsNone(reader._get_metadata_property('kljdf')) + self.assertEqual(reader._get_metadata_property('kljdf', 'default'), 'default') + + def test_get_parser(self): + self.create_test_nd2() + with ND2Reader(self.test_file) as reader: + self.assertTrue(type(reader.parser) is Parser) +