| # Copyright 2020 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| """Tests for the pw_build.zip module.""" |
| |
| import unittest |
| import os |
| import tempfile |
| import pathlib |
| import zipfile |
| |
| from pw_build.zip import zip_up, ZipError |
| |
| DELIMITER = '>' |
| IN_FILENAMES = [ |
| 'file1.txt', |
| 'file2.txt', |
| 'dir1/file3.txt', |
| 'dir1/file4.txt', |
| 'dir1/dir2/file5.txt', |
| 'dir1/dir2/file6.txt', |
| ] |
| |
| |
| def make_directory(parent_path: pathlib.Path, dir_name: str, filenames: list): |
| """Creates a directory and returns a pathlib.Path() of it's root dir. |
| |
| Args: |
| parent_path: Path to directory where the new directory will be made. |
| dir_name: Name of the new directory. |
| filenames: list of file contents of the new directory. Also allows |
| the creation of subdirectories. Example: |
| [ |
| 'file1.txt', |
| 'subdir/file2.txt' |
| ] |
| |
| Returns: pathlib.Path() to the newly created directory. |
| """ |
| root_path = pathlib.Path(parent_path / dir_name) |
| os.mkdir(root_path) |
| for filename in filenames: |
| # Make the sub directories if they don't already exist. |
| directories = filename.split('/')[:-1] |
| for i in range(len(directories)): |
| directory = pathlib.PurePath('/'.join(directories[:i + 1])) |
| if not (root_path / directory).is_dir(): |
| os.mkdir(root_path / directory) |
| |
| # Create a file at the destination. |
| touch(root_path, filename) |
| return root_path |
| |
| |
| def touch(parent_dir: pathlib.Path, filename: str): |
| """Creates an empty file at parent_dir/filename.""" |
| with open(parent_dir / filename, 'a') as touch_file: |
| touch_file.write(filename) |
| |
| |
| def get_directory_contents(path: pathlib.Path): |
| """Iterates through a directory and returns a set of its contents.""" |
| contents = set() |
| for filename in path.glob('**/*'): |
| # Remove the original parent directories to get just the relative path. |
| contents.add(filename.relative_to(path)) |
| return contents |
| |
| |
| class TestZipping(unittest.TestCase): |
| """Tests for the pw_build.zip module.""" |
| def test_zip_up_file(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| tmp_path = pathlib.Path(tmp_dir) |
| in_path = make_directory(tmp_path, 'in', IN_FILENAMES) |
| input_list = [f'{in_path}/file1.txt {DELIMITER} /'] |
| out_filename = f'{tmp_path}/out.zip' |
| |
| # Act. |
| zip_up(input_list, out_filename) |
| out_path = pathlib.Path(f'{tmp_path}/out/') |
| with zipfile.ZipFile(out_filename, 'r') as zip_file: |
| zip_file.extractall(out_path) |
| expected_path = make_directory(tmp_path, 'expected', ['file1.txt']) |
| |
| # Assert. |
| self.assertSetEqual(get_directory_contents(out_path), |
| get_directory_contents(expected_path)) |
| |
| def test_zip_up_dir(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| tmp_path = pathlib.Path(tmp_dir) |
| in_path = make_directory(tmp_path, 'in', IN_FILENAMES) |
| input_list = [f'{in_path}/dir1/ {DELIMITER} /'] |
| out_filename = f'{tmp_path}/out.zip' |
| |
| # Act. |
| zip_up(input_list, out_filename) |
| out_path = pathlib.Path(f'{tmp_path}/out/') |
| with zipfile.ZipFile(out_filename, 'r') as zip_file: |
| zip_file.extractall(out_path) |
| expected_path = make_directory(tmp_path, 'expected', [ |
| 'file3.txt', |
| 'file4.txt', |
| 'dir2/file5.txt', |
| 'dir2/file6.txt', |
| ]) |
| |
| # Assert. |
| self.assertSetEqual(get_directory_contents(out_path), |
| get_directory_contents(expected_path)) |
| |
| def test_file_rename(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| tmp_path = pathlib.Path(tmp_dir) |
| in_path = make_directory(tmp_path, 'in', IN_FILENAMES) |
| input_list = [f'{in_path}/file1.txt {DELIMITER} /renamed.txt'] |
| out_filename = f'{tmp_path}/out.zip' |
| |
| # Act. |
| zip_up(input_list, out_filename) |
| out_path = pathlib.Path(f'{tmp_path}/out/') |
| with zipfile.ZipFile(out_filename, 'r') as zip_file: |
| zip_file.extractall(out_path) |
| expected_path = make_directory(tmp_path, 'expected', |
| ['renamed.txt']) |
| |
| # Assert. |
| self.assertSetEqual(get_directory_contents(out_path), |
| get_directory_contents(expected_path)) |
| |
| def test_file_move(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| tmp_path = pathlib.Path(tmp_dir) |
| in_path = make_directory(tmp_path, 'in', IN_FILENAMES) |
| input_list = [f'{in_path}/file1.txt {DELIMITER} /foo/'] |
| out_filename = f'{tmp_path}/out.zip' |
| |
| # Act. |
| zip_up(input_list, out_filename) |
| out_path = pathlib.Path(f'{tmp_path}/out/') |
| with zipfile.ZipFile(out_filename, 'r') as zip_file: |
| zip_file.extractall(out_path) |
| expected_path = make_directory(tmp_path, 'expected', |
| ['foo/file1.txt']) |
| |
| # Assert. |
| self.assertSetEqual(get_directory_contents(out_path), |
| get_directory_contents(expected_path)) |
| |
| def test_dir_move(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| tmp_path = pathlib.Path(tmp_dir) |
| in_path = make_directory(tmp_path, 'in', IN_FILENAMES) |
| input_list = [f'{in_path}/dir1/ {DELIMITER} /foo/'] |
| out_filename = f'{tmp_path}/out.zip' |
| |
| # Act. |
| zip_up(input_list, out_filename) |
| out_path = pathlib.Path(f'{tmp_path}/out/') |
| with zipfile.ZipFile(out_filename, 'r') as zip_file: |
| zip_file.extractall(out_path) |
| expected_path = make_directory(tmp_path, 'expected', [ |
| 'foo/file3.txt', |
| 'foo/file4.txt', |
| 'foo/dir2/file5.txt', |
| 'foo/dir2/file6.txt', |
| ]) |
| |
| # Assert. |
| self.assertSetEqual(get_directory_contents(out_path), |
| get_directory_contents(expected_path)) |
| |
| def test_change_delimiter(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| tmp_path = pathlib.Path(tmp_dir) |
| in_path = make_directory(tmp_path, 'in', IN_FILENAMES) |
| delimiter = '==>' |
| input_list = [f'{in_path}/file1.txt {delimiter} /'] |
| out_filename = f'{tmp_path}/out.zip' |
| |
| # Act. |
| zip_up(input_list, out_filename, delimiter=delimiter) |
| out_path = pathlib.Path(f'{tmp_path}/out/') |
| with zipfile.ZipFile(out_filename, 'r') as zip_file: |
| zip_file.extractall(out_path) |
| expected_path = make_directory(tmp_path, 'expected', ['file1.txt']) |
| |
| # Assert. |
| self.assertSetEqual(get_directory_contents(out_path), |
| get_directory_contents(expected_path)) |
| |
| def test_wrong_input_syntax_raises_error(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| bad_inputs = [ |
| '', # Empty input |
| f'{tmp_dir}/ /', # No delimiter |
| f'{tmp_dir}/ {DELIMITER} ', # No zip destination |
| f'{tmp_dir} /', # No source |
| f'{tmp_dir}/', # No delimiter or zip destination |
| f'{DELIMITER}', # No source or zip destination |
| f'{tmp_dir} {DELIMITER} /', # No trailing source '/' |
| f'{tmp_dir}/ {DELIMITER} foo/', # No leading zip root '/' |
| f'{tmp_dir}/ {DELIMITER} /foo', # No trailing zip dest '/' |
| f'{tmp_dir}/ {DELIMITER} /{tmp_dir}/ ' |
| f'{DELIMITER} /{tmp_dir}/', # Too many paths on split |
| ] |
| out_filename = f'{tmp_dir}/out.zip' |
| |
| # Act & Assert. |
| for bad_input in bad_inputs: |
| with self.assertRaises(ZipError): |
| zip_up([bad_input], out_filename) |
| |
| def test_nonexistant_file_raises_error(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| input_list = [f'{tmp_dir}/nonexistant-file.txt > /'] |
| out_filename = f'{tmp_dir}/out.zip' |
| |
| # Act & Assert. |
| with self.assertRaises(ZipError): |
| zip_up(input_list, out_filename) |
| |
| def test_nonexistant_dir_raises_error(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| # Arrange. |
| input_list = [f'{tmp_dir}/nonexistant-dir/ > /'] |
| out_filename = f'{tmp_dir}/out.zip' |
| |
| # Act & Assert. |
| with self.assertRaises(ZipError): |
| zip_up(input_list, out_filename) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |