From 4caa13a9559f4020f52fec56148803497acb9798 Mon Sep 17 00:00:00 2001 From: jevans Date: Thu, 20 Feb 2014 22:34:52 -0500 Subject: [PATCH] More negative tests. #175 --- glymur/jp2box.py | 50 ++++++++++++++++++++++++++-------- glymur/test/test_jp2box.py | 12 +++++++- glymur/test/test_jp2box_jpx.py | 19 +++++++++++++ 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 49cde5d..f3fce20 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -29,6 +29,7 @@ import numpy as np from .codestream import Codestream from .core import _COLORSPACE_MAP_DISPLAY from .core import _COLOR_TYPE_MAP_DISPLAY +from .core import SRGB, GREYSCALE, YCC from .core import ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE from .core import ANY_ICC_PROFILE, VENDOR_COLOR_METHOD from .core import _pretty_print_xml @@ -270,13 +271,6 @@ class ColourSpecificationBox(Jp2kBox): approximation=0, colorspace=None, icc_profile=None, length=0, offset=-1): Jp2kBox.__init__(self, box_id='colr', longname='Colour Specification') - - if colorspace is not None and icc_profile is not None: - raise IOError("colorspace and icc_profile cannot both be set.") - if method not in (1, 2, 3, 4): - raise IOError("Invalid method.") - if approximation not in (0, 1, 2, 3, 4): - raise IOError("Invalid approximation.") self.method = method self.precedence = precedence self.approximation = approximation @@ -284,6 +278,33 @@ class ColourSpecificationBox(Jp2kBox): self.icc_profile = icc_profile self.length = length self.offset = offset + self._validate() + + def _validate(self): + """Verify that the box obeys the specifications.""" + if self.colorspace is not None and self.icc_profile is not None: + raise IOError("colorspace and icc_profile cannot both be set.") + if self.method not in (1, 2, 3, 4): + raise IOError("Invalid method.") + if self.approximation not in (0, 1, 2, 3, 4): + raise IOError("Invalid approximation.") + + def _write_validate(self): + """In addition to constructor validation steps, run validation steps + for writing.""" + if self.colorspace is None: + msg = "Writing Colour Specification boxes without enumerated " + msg += "colorspaces is not supported at this time." + raise IOError(msg) + + if self.icc_profile is None: + if self.colorspace not in [SRGB, GREYSCALE, YCC]: + msg = "Colorspace should correspond to one of SRGB, GREYSCALE, " + msg += "or YCC." + raise IOError(msg) + + self._validate() + def __repr__(self): msg = "glymur.jp2box.ColourSpecificationBox(" @@ -327,10 +348,7 @@ class ColourSpecificationBox(Jp2kBox): def write(self, fptr): """Write an Colour Specification box to file. """ - if self.colorspace is None: - msg = "Writing Colour Specification boxes without enumerated " - msg += "colorspaces is not supported at this time." - raise NotImplementedError(msg) + self._write_validate() length = 15 if self.icc_profile is None else 11 + len(self.icc_profile) fptr.write(struct.pack('>I', length)) fptr.write('colr'.encode()) @@ -923,10 +941,20 @@ class DataReferenceBox(Jp2kBox): self.DR = data_entry_url_boxes self.length = length self.offset = offset + self._validate() + + def _validate(self): + """Verify that the box obeys the specifications.""" + for box in self.DR: + if box.box_id != 'url ': + msg = 'All child boxes of a data reference box must be data ' + msg += 'entry URL boxes.' + raise IOError(msg) def write(self, fptr): """Write a Data Reference box to file. """ + self._validate() # Very similar to the say a superbox is written. orig_pos = fptr.tell() diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 426bf66..b6f0524 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -394,7 +394,7 @@ class TestColourSpecificationBox(unittest.TestCase): boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c] boxes[2].box = [self.ihdr, ColourSpecificationBox(colorspace=None)] with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile: - with self.assertRaises(NotImplementedError): + with self.assertRaises(IOError): j2k.wrap(tfile.name, boxes=boxes) @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @@ -440,6 +440,16 @@ class TestColourSpecificationBox(unittest.TestCase): glymur.jp2box.ColourSpecificationBox(colorspace=colorspace, approximation=approx) + def test_colr_with_bad_color(self): + """colr must have a valid color, strange as though that may sound.""" + colorspace = -1 + approx = 0 + colr = glymur.jp2box.ColourSpecificationBox(colorspace=colorspace, + approximation=approx) + with tempfile.TemporaryFile() as tfile: + with self.assertRaises(IOError): + colr.write(tfile) + class TestAppend(unittest.TestCase): """Tests for append method.""" diff --git a/glymur/test/test_jp2box_jpx.py b/glymur/test/test_jp2box_jpx.py index 5d6cca2..b2916c5 100644 --- a/glymur/test/test_jp2box_jpx.py +++ b/glymur/test/test_jp2box_jpx.py @@ -140,6 +140,25 @@ class TestJPXWrap(unittest.TestCase): self.assertEqual(jpx.box[-1].box_id, 'dtbl') self.assertEqual(len(jpx.box[-1].box), 0) + def test_deurl_child_of_dtbl(self): + """Data reference boxes can only contain data entry url boxes.""" + jp2 = Jp2k(self.jp2file) + boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]] + + ftyp = glymur.jp2box.FileTypeBox() + with self.assertRaises(IOError): + dref = glymur.jp2box.DataReferenceBox([ftyp]) + + # Try to get around it by appending the ftyp box after creation. + dref = glymur.jp2box.DataReferenceBox() + dref.DR.append(ftyp) + + boxes.append(dref) + + with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile: + with self.assertRaises(IOError): + jpx = jp2.wrap(tfile.name, boxes=boxes) + def test_only_one_data_reference(self): """Data reference boxes cannot be inside a superbox .""" jp2 = Jp2k(self.jp2file)