More negative tests, pylint work. #175

This commit is contained in:
jevans 2014-02-23 12:37:47 -05:00
commit 16ce2ef883
3 changed files with 72 additions and 27 deletions

View file

@ -124,7 +124,7 @@ class Jp2kBox(object):
fptr.write(struct.pack('>I', end_pos - orig_pos)) fptr.write(struct.pack('>I', end_pos - orig_pos))
fptr.seek(end_pos) fptr.seek(end_pos)
def parse_this_box(self, fptr, box_id, start, num_bytes): def _parse_this_box(self, fptr, box_id, start, num_bytes):
"""Parse the current box. """Parse the current box.
Parameters Parameters
@ -214,7 +214,7 @@ class Jp2kBox(object):
# The box_length value really is the length of the box! # The box_length value really is the length of the box!
num_bytes = box_length num_bytes = box_length
box = self.parse_this_box(fptr, box_id, start, num_bytes) box = self._parse_this_box(fptr, box_id, start, num_bytes)
superbox.append(box) superbox.append(box)
@ -560,7 +560,8 @@ class ChannelDefinitionBox(Jp2kBox):
def _validate(self): def _validate(self):
"""Verify that the box obeys the specifications.""" """Verify that the box obeys the specifications."""
# channel type and association must be specified. # channel type and association must be specified.
if not (len(self.index) == len(self.channel_type) == len(self.association)): if not ((len(self.index) == len(self.channel_type)) and
(len(self.channel_type) == len(self.association))):
msg = "Length of channel definition box inputs must be the same." msg = "Length of channel definition box inputs must be the same."
raise IOError(msg) raise IOError(msg)
@ -953,10 +954,18 @@ class DataReferenceBox(Jp2kBox):
msg += 'entry URL boxes.' msg += 'entry URL boxes.'
raise IOError(msg) raise IOError(msg)
def _write_validate(self):
"""Verify that the box obeys the specifications for writing.
"""
if len(self.DR) == 0:
msg = "A data reference box cannot be empty when written to a file."
raise IOError(msg)
self._validate()
def write(self, fptr): def write(self, fptr):
"""Write a Data Reference box to file. """Write a Data Reference box to file.
""" """
self._validate() self._write_validate()
# Very similar to the say a superbox is written. # Very similar to the say a superbox is written.
orig_pos = fptr.tell() orig_pos = fptr.tell()

View file

@ -1110,6 +1110,10 @@ def _validate_nonzero_image_size(nrows, ncols, component_index):
raise IOError(msg) raise IOError(msg)
JP2_IDS = ['colr', 'cdef', 'cmap', 'jp2c', 'ftyp', 'ihdr', 'jp2h', 'jP ',
'pclr', 'res ', 'resc', 'resd', 'xml ', 'ulst', 'uinf', 'url ',
'uuid']
def _validate_jp2_box_sequence(boxes): def _validate_jp2_box_sequence(boxes):
"""Run through series of tests for JP2 box legality. """Run through series of tests for JP2 box legality.
@ -1118,6 +1122,18 @@ def _validate_jp2_box_sequence(boxes):
_validate_signature_compatibility(boxes) _validate_signature_compatibility(boxes)
_validate_jp2h(boxes) _validate_jp2h(boxes)
_validate_jp2c(boxes) _validate_jp2c(boxes)
if boxes[1].brand == 'jpx ':
_validate_jpx_box_sequence(boxes)
else:
count = _collect_box_count(boxes)
for id in count.keys():
if id not in JP2_IDS:
msg = "The presence of a '{0}' box requires that the file type "
msg += "brand be set to 'jpx '."
raise IOError(msg.format(id))
def _validate_jpx_box_sequence(boxes):
"""Run through series of tests for JPX box legality."""
_validate_association(boxes) _validate_association(boxes)
_validate_label(boxes) _validate_label(boxes)
_validate_jpx_brand(boxes, boxes[1].brand) _validate_jpx_brand(boxes, boxes[1].brand)
@ -1125,7 +1141,6 @@ def _validate_jp2_box_sequence(boxes):
_validate_singletons(boxes) _validate_singletons(boxes)
_validate_top_level(boxes) _validate_top_level(boxes)
def _validate_signature_compatibility(boxes): def _validate_signature_compatibility(boxes):
"""Validate the file signature and compatibility status.""" """Validate the file signature and compatibility status."""
# Check for a bad sequence of boxes. # Check for a bad sequence of boxes.

View file

@ -4,12 +4,10 @@ Test suite specifically targeting JPX box layout.
""" """
import os import os
import shutil
import struct import struct
import sys import sys
import tempfile import tempfile
import unittest import unittest
import warnings
import xml.etree.cElementTree as ET import xml.etree.cElementTree as ET
import glymur import glymur
@ -41,6 +39,18 @@ class TestJPXWrap(unittest.TestCase):
def tearDown(self): def tearDown(self):
os.unlink(self.xmlfile) os.unlink(self.xmlfile)
def test_jp2_with_jpx_box(self):
"""If the brand is jp2, then no jpx boxes are allowed."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
boxes = jp2.box
boxes.append(glymur.jp2box.AssociationBox())
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
def test_ftbl(self): def test_ftbl(self):
"""Write a fragment table box.""" """Write a fragment table box."""
# Add a negative test where offset < 0 # Add a negative test where offset < 0
@ -128,17 +138,18 @@ class TestJPXWrap(unittest.TestCase):
self.assertEqual(jpx.box[-1].box[2].label, label) self.assertEqual(jpx.box[-1].box[2].label, label)
def test_empty_data_reference(self): def test_empty_data_reference(self):
"""Data reference boxes can be empty.""" """Empty data reference boxes can be created, but not written."""
jp2 = Jp2k(self.jp2file) jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]] boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
boxes[1].brand = 'jpx '
dref = glymur.jp2box.DataReferenceBox() dref = glymur.jp2box.DataReferenceBox()
boxes.append(dref) boxes.append(dref)
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile: with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
jpx = jp2.wrap(tfile.name, boxes=boxes) with self.assertRaises(IOError):
self.assertEqual(jpx.box[-1].box_id, 'dtbl') jp2.wrap(tfile.name, boxes=boxes)
self.assertEqual(len(jpx.box[-1].box), 0)
def test_deurl_child_of_dtbl(self): def test_deurl_child_of_dtbl(self):
"""Data reference boxes can only contain data entry url boxes.""" """Data reference boxes can only contain data entry url boxes."""
@ -157,13 +168,16 @@ class TestJPXWrap(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile: with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError): with self.assertRaises(IOError):
jpx = jp2.wrap(tfile.name, boxes=boxes) jp2.wrap(tfile.name, boxes=boxes)
def test_only_one_data_reference(self): def test_only_one_data_reference(self):
"""Data reference boxes cannot be inside a superbox .""" """Data reference boxes cannot be inside a superbox ."""
jp2 = Jp2k(self.jp2file) jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]] boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# Have to make the ftyp brand jpx.
boxes[1].brand = 'jpx '
flag = 0 flag = 0
version = (0, 0, 0) version = (0, 0, 0)
url = 'file:////usr/local/bin' url = 'file:////usr/local/bin'
@ -174,16 +188,16 @@ class TestJPXWrap(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile: with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError): with self.assertRaises(IOError):
jpx = jp2.wrap(tfile.name, boxes=boxes) jp2.wrap(tfile.name, boxes=boxes)
def test_lbl_at_top_level(self): def test_lbl_at_top_level(self):
"""Label boxes can only be inside a asoc box .""" """Label boxes can only be inside a asoc box ."""
jp2 = Jp2k(self.jp2file) jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]] boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
flag = 0 # Have to make the ftyp brand jpx.
version = (0, 0, 0) boxes[1].brand = 'jpx '
url = 'file:////usr/local/bin'
lblb = glymur.jp2box.LabelBox('hi there') lblb = glymur.jp2box.LabelBox('hi there')
# Put it inside the jp2 header box. # Put it inside the jp2 header box.
@ -191,13 +205,16 @@ class TestJPXWrap(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile: with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError): with self.assertRaises(IOError):
jpx = jp2.wrap(tfile.name, boxes=boxes) jp2.wrap(tfile.name, boxes=boxes)
def test_data_reference_not_at_top_level(self): def test_data_reference_in_subbox(self):
"""Data reference boxes cannot be inside a superbox .""" """Data reference boxes cannot be inside a superbox ."""
jp2 = Jp2k(self.jp2file) jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]] boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# Have to make the ftyp brand jpx.
boxes[1].brand = 'jpx '
flag = 0 flag = 0
version = (0, 0, 0) version = (0, 0, 0)
url = 'file:////usr/local/bin' url = 'file:////usr/local/bin'
@ -209,13 +226,17 @@ class TestJPXWrap(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile: with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(IOError): with self.assertRaises(IOError):
jpx = jp2.wrap(tfile.name, boxes=boxes) jp2.wrap(tfile.name, boxes=boxes)
def test_jp2_to_jpx_sans_jp2_compatibility(self): def test_jp2_to_jpx_sans_jp2_compatibility(self):
"""jp2 wrapped to jpx not including jp2 compatibility is wrong.""" """jp2 wrapped to jpx not including jp2 compatibility is wrong."""
jp2 = Jp2k(self.jp2file) jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]] boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
# Have to make the ftyp brand jpx.
boxes[1].brand = 'jpx '
boxes[1].compatibility_list.append('jp2 ') boxes[1].compatibility_list.append('jp2 ')
numbers = [0, 1] numbers = [0, 1]
nlst = glymur.jp2box.NumberListBox(numbers) nlst = glymur.jp2box.NumberListBox(numbers)
the_xml = ET.fromstring('<?xml version="1.0"?><data>0</data>') the_xml = ET.fromstring('<?xml version="1.0"?><data>0</data>')
@ -225,7 +246,7 @@ class TestJPXWrap(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile: with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
jpx = jp2.wrap(tfile.name, boxes=boxes) jp2.wrap(tfile.name, boxes=boxes)
def test_jp2_to_jpx_sans_jpx_brand(self): def test_jp2_to_jpx_sans_jpx_brand(self):
"""Verify error when jp2 wrapped to jpx does not include jpx brand.""" """Verify error when jp2 wrapped to jpx does not include jpx brand."""
@ -241,7 +262,7 @@ class TestJPXWrap(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile: with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
jpx = jp2.wrap(tfile.name, boxes=boxes) jp2.wrap(tfile.name, boxes=boxes)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@ -262,7 +283,7 @@ class TestJPX(unittest.TestCase):
flst = glymur.jp2box.FragmentListBox(offset, length, reference) flst = glymur.jp2box.FragmentListBox(offset, length, reference)
with self.assertRaises(IOError): with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile: with tempfile.TemporaryFile() as tfile:
flst.write(tfile) flst.write(tfile)
def test_flst_offsets_not_positive(self): def test_flst_offsets_not_positive(self):
"""A fragment list box offsets must be positive.""" """A fragment list box offsets must be positive."""
@ -272,7 +293,7 @@ class TestJPX(unittest.TestCase):
flst = glymur.jp2box.FragmentListBox(offset, length, reference) flst = glymur.jp2box.FragmentListBox(offset, length, reference)
with self.assertRaises(IOError): with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile: with tempfile.TemporaryFile() as tfile:
flst.write(tfile) flst.write(tfile)
def test_flst_lengths_not_positive(self): def test_flst_lengths_not_positive(self):
"""A fragment list box lengths must be positive.""" """A fragment list box lengths must be positive."""
@ -282,14 +303,14 @@ class TestJPX(unittest.TestCase):
flst = glymur.jp2box.FragmentListBox(offset, length, reference) flst = glymur.jp2box.FragmentListBox(offset, length, reference)
with self.assertRaises(IOError): with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile: with tempfile.TemporaryFile() as tfile:
flst.write(tfile) flst.write(tfile)
def test_ftbl_boxes_empty(self): def test_ftbl_boxes_empty(self):
"""A fragment table box must have at least one child box.""" """A fragment table box must have at least one child box."""
ftbl = glymur.jp2box.FragmentTableBox() ftbl = glymur.jp2box.FragmentTableBox()
with self.assertRaises(IOError): with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile: with tempfile.TemporaryFile() as tfile:
ftbl.write(tfile) ftbl.write(tfile)
def test_ftbl_child_not_flst(self): def test_ftbl_child_not_flst(self):
"""A fragment table box can only contain a fragment list.""" """A fragment table box can only contain a fragment list."""
@ -297,7 +318,7 @@ class TestJPX(unittest.TestCase):
ftbl = glymur.jp2box.FragmentTableBox(box=[free]) ftbl = glymur.jp2box.FragmentTableBox(box=[free])
with self.assertRaises(IOError): with self.assertRaises(IOError):
with tempfile.TemporaryFile() as tfile: with tempfile.TemporaryFile() as tfile:
ftbl.write(tfile) ftbl.write(tfile)
def test_jpx_rreq_mask_length_3(self): def test_jpx_rreq_mask_length_3(self):
"""There are some JPX files with rreq mask length of 3.""" """There are some JPX files with rreq mask length of 3."""
@ -314,7 +335,7 @@ class TestJPX(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile: with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile:
with open(self.jpxfile, 'rb') as ifile: with open(self.jpxfile, 'rb') as ifile:
tfile.write(ifile.read()) tfile.write(ifile.read())
# Add the header for an unknwon superbox. # Add the header for an unknwon superbox.
write_buffer = struct.pack('>I4s', 20, 'grp '.encode()) write_buffer = struct.pack('>I4s', 20, 'grp '.encode())
tfile.write(write_buffer) tfile.write(write_buffer)