| #!/usr/bin/python |
| |
| # Copyright 2016, The Android Open Source Project |
| # |
| # Permission is hereby granted, free of charge, to any person |
| # obtaining a copy of this software and associated documentation |
| # files (the "Software"), to deal in the Software without |
| # restriction, including without limitation the rights to use, copy, |
| # modify, merge, publish, distribute, sublicense, and/or sell copies |
| # of the Software, and to permit persons to whom the Software is |
| # furnished to do so, subject to the following conditions: |
| # |
| # The above copyright notice and this permission notice shall be |
| # included in all copies or substantial portions of the Software. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| # SOFTWARE. |
| |
| |
| """Unit-test for ImageHandler.""" |
| |
| |
| import imp |
| import os |
| import sys |
| import tempfile |
| import unittest |
| |
| sys.dont_write_bytecode = True |
| avbtool = imp.load_source('avbtool', './avbtool') |
| |
| # The file test_file.bin and test_file.bin.sparse are generated using |
| # the following python code: |
| # |
| # with open('test_file.bin', 'w+b') as f: |
| # f.write('Barfoo43'*128*12) |
| # os.system('img2simg test_file.bin test_file.bin.sparse') |
| # image = avbtool.ImageHandler('test_file.bin.sparse') |
| # image.append_dont_care(12*1024) |
| # image.append_fill('\x01\x02\x03\x04', 12*1024) |
| # image.append_raw('Foobar42'*128*12) |
| # image.append_dont_care(12*1024) |
| # del image |
| # os.system('rm -f test_file.bin') |
| # os.system('simg2img test_file.bin.sparse test_file.bin') |
| # |
| # and manually verified to be correct. The content of the raw and |
| # sparse files are as follows (the line with "Fill with 0x04030201" is |
| # a simg_dump.py bug): |
| # |
| # $ hexdump -C test_file.bin |
| # 00000000 42 61 72 66 6f 6f 34 33 42 61 72 66 6f 6f 34 33 |Barfoo43Barfoo43| |
| # * |
| # 00003000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| |
| # * |
| # 00006000 01 02 03 04 01 02 03 04 01 02 03 04 01 02 03 04 |................| |
| # * |
| # 00009000 46 6f 6f 62 61 72 34 32 46 6f 6f 62 61 72 34 32 |Foobar42Foobar42| |
| # * |
| # 0000c000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| |
| # * |
| # 0000f000 |
| # |
| # $ system/core/libsparse/simg_dump.py -v test_file.bin.sparse |
| # test_file.bin.sparse: Total of 15 4096-byte output blocks in 5 input chunks. |
| # input_bytes output_blocks |
| # chunk offset number offset number |
| # 1 40 12288 0 3 Raw data |
| # 2 12340 0 3 3 Don't care |
| # 3 12352 4 6 3 Fill with 0x04030201 |
| # 4 12368 12288 9 3 Raw data |
| # 5 24668 0 12 3 Don't care |
| # 24668 15 End |
| # |
| |
| |
| class ImageHandler(unittest.TestCase): |
| |
| TEST_FILE_SPARSE_PATH = 'test/data/test_file.bin.sparse' |
| TEST_FILE_PATH = 'test/data/test_file.bin' |
| TEST_FILE_SIZE = 61440 |
| TEST_FILE_BLOCK_SIZE = 4096 |
| |
| def _file_contents_equal(self, path1, path2, size): |
| f1 = open(path1, 'r') |
| f2 = open(path2, 'r') |
| if f1.read(size) != f2.read(size): |
| return False |
| return True |
| |
| def _file_size(self, f): |
| old_pos = f.tell() |
| f.seek(0, os.SEEK_END) |
| size = f.tell() |
| f.seek(old_pos) |
| return size |
| |
| def _clone_sparse_file(self): |
| f = tempfile.NamedTemporaryFile() |
| f.write(open(self.TEST_FILE_SPARSE_PATH).read()) |
| f.flush() |
| return f |
| |
| def _unsparsify(self, path): |
| f = tempfile.NamedTemporaryFile() |
| os.system('simg2img {} {}'.format(path, f.name)) |
| return f |
| |
| def testRead(self): |
| """Checks that reading from a sparse file works as intended.""" |
| ih = avbtool.ImageHandler(self.TEST_FILE_SPARSE_PATH) |
| |
| # Check that we start at offset 0. |
| self.assertEqual(ih.tell(), 0) |
| |
| # Check that reading advances the cursor. |
| self.assertEqual(ih.read(14), bytearray('Barfoo43Barfoo')) |
| self.assertEqual(ih.tell(), 14) |
| self.assertEqual(ih.read(2), bytearray('43')) |
| self.assertEqual(ih.tell(), 16) |
| |
| # Check reading in the middle of a fill chunk gets the right data. |
| ih.seek(0x6000 + 1) |
| self.assertEqual(ih.read(4), bytearray('\x02\x03\x04\x01')) |
| |
| # Check we can cross the chunk boundary correctly. |
| ih.seek(0x3000 - 10) |
| self.assertEqual(ih.read(12), bytearray('43Barfoo43\x00\x00')) |
| ih.seek(0x9000 - 3) |
| self.assertEqual(ih.read(5), bytearray('\x02\x03\x04Fo')) |
| |
| # Check reading at end of file is a partial read. |
| ih.seek(0xf000 - 2) |
| self.assertEqual(ih.read(16), bytearray('\x00\x00')) |
| |
| def testTruncate(self): |
| """Checks that we can truncate a sparse file correctly.""" |
| # Check truncation at all possible boundaries (including start and end). |
| for size in range(0, self.TEST_FILE_SIZE + self.TEST_FILE_BLOCK_SIZE, |
| self.TEST_FILE_BLOCK_SIZE): |
| sparse_file = self._clone_sparse_file() |
| ih = avbtool.ImageHandler(sparse_file.name) |
| ih.truncate(size) |
| unsparse_file = self._unsparsify(sparse_file.name) |
| self.assertEqual(self._file_size(unsparse_file), size) |
| self.assertTrue(self._file_contents_equal(unsparse_file.name, |
| self.TEST_FILE_PATH, |
| size)) |
| |
| # Check truncation to grow the file. |
| grow_size = 8192 |
| sparse_file = self._clone_sparse_file() |
| ih = avbtool.ImageHandler(sparse_file.name) |
| ih.truncate(self.TEST_FILE_SIZE + grow_size) |
| unsparse_file = self._unsparsify(sparse_file.name) |
| self.assertEqual(self._file_size(unsparse_file), |
| self.TEST_FILE_SIZE + grow_size) |
| self.assertTrue(self._file_contents_equal(unsparse_file.name, |
| self.TEST_FILE_PATH, |
| self.TEST_FILE_SIZE)) |
| unsparse_file.seek(self.TEST_FILE_SIZE) |
| self.assertEqual(unsparse_file.read(), '\0'*grow_size) |
| |
| def testAppendRaw(self): |
| """Checks that we can append raw data correctly.""" |
| sparse_file = self._clone_sparse_file() |
| ih = avbtool.ImageHandler(sparse_file.name) |
| data = 'SomeData'*4096 |
| ih.append_raw(data) |
| unsparse_file = self._unsparsify(sparse_file.name) |
| self.assertTrue(self._file_contents_equal(unsparse_file.name, |
| self.TEST_FILE_PATH, |
| self.TEST_FILE_SIZE)) |
| unsparse_file.seek(self.TEST_FILE_SIZE) |
| self.assertEqual(unsparse_file.read(), data) |
| |
| def testAppendFill(self): |
| """Checks that we can append fill data correctly.""" |
| sparse_file = self._clone_sparse_file() |
| ih = avbtool.ImageHandler(sparse_file.name) |
| data = 'ABCD'*4096 |
| ih.append_fill('ABCD', len(data)) |
| unsparse_file = self._unsparsify(sparse_file.name) |
| self.assertTrue(self._file_contents_equal(unsparse_file.name, |
| self.TEST_FILE_PATH, |
| self.TEST_FILE_SIZE)) |
| unsparse_file.seek(self.TEST_FILE_SIZE) |
| self.assertEqual(unsparse_file.read(), data) |
| |
| def testDontCare(self): |
| """Checks that we can append DONT_CARE data correctly.""" |
| sparse_file = self._clone_sparse_file() |
| ih = avbtool.ImageHandler(sparse_file.name) |
| data = '\0'*40960 |
| ih.append_dont_care(len(data)) |
| unsparse_file = self._unsparsify(sparse_file.name) |
| self.assertTrue(self._file_contents_equal(unsparse_file.name, |
| self.TEST_FILE_PATH, |
| self.TEST_FILE_SIZE)) |
| unsparse_file.seek(self.TEST_FILE_SIZE) |
| self.assertEqual(unsparse_file.read(), data) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |