def test_remove_raises_if_no_file( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should raise a PathNotFoundError error if file to remove isn't found.""" path = tmp_path / "foo" with pytest.raises(PathNotFoundError): sync_filesystem.remove(path)
def test_remove_deletes_file(tmp_path: Path, sync_filesystem: SyncFilesystem) -> None: """It should delete a given file.""" path = tmp_path / "foo" path.with_suffix(".json").touch() sync_filesystem.remove(path) assert path.exists() is False
def test_write_json_raises_encode_error( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should raise a FileEncodeError if object cannot be encoded to JSON.""" path = tmp_path / "foo" with pytest.raises(FileEncodeError, match="ellipsis is not JSON serializable"): sync_filesystem.write_json(path, {"nope": ...})
def test_write_json_creates_dirs_if_necessary( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should create directories as necessary to reach the path.""" path = tmp_path / "foo" / "bar" / "baz" sync_filesystem.write_json(path, {"foo": "hello", "bar": 0}) assert path.with_suffix(".json").read_text() == """{"foo": "hello", "bar": 0}"""
def test_read_json_raises_path_does_not_exist_error( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should return a FileNotFoundError if file doesn't exist.""" path = PurePosixPath(tmp_path / "foo") with pytest.raises(PathNotFoundError, match="No such file or directory"): sync_filesystem.read_json(path)
def test_write_json_encodes_and_writes_obj( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should encode and write a JSON object to a file.""" path = tmp_path / "foo" sync_filesystem.write_json(path, {"foo": "hello", "bar": 0}) assert path.with_suffix(".json").read_text() == """{"foo": "hello", "bar": 0}"""
def test_write_json_when_custom_encoder_raises( tmp_path: Path, mock_encode_json: MagicMock, sync_filesystem: SyncFilesystem ) -> None: """It should raise a FileEncodeError if the custom encoder raises.""" path = tmp_path / "foo" obj = {"foo": "hello", "bar": 0} mock_encode_json.side_effect = Exception("oh no") with pytest.raises(FileEncodeError, match="oh no"): sync_filesystem.write_json(path, obj, encode_json=mock_encode_json)
def test_read_json_raises_parse_error( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should raise a FileParseError if file is not valid JSON.""" Path(tmp_path / "foo.json").write_text("""{ "foo": "hello", }""") path = PurePosixPath(tmp_path / "foo") with pytest.raises(FileParseError, match="Expecting property name"): sync_filesystem.read_json(path)
def test_remove_dir_deletes_tree( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should delete a directory and all files in it.""" (tmp_path / "foo.json").touch() (tmp_path / "bar.json").touch() (tmp_path / "baz.json").touch() sync_filesystem.remove_dir(tmp_path) assert tmp_path.exists() is False
def test_ensure_dir_creates_directory( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should ensure a directory exists.""" path = tmp_path / "foo" sync_filesystem.ensure_dir(path) assert path.is_dir() is True # ensure that subsequent calls do not error sync_filesystem.ensure_dir(path) assert path.is_dir() is True
def test_read_json_when_custom_parser_raises( tmp_path: Path, mock_parse_json: MagicMock, sync_filesystem: SyncFilesystem ) -> None: """It should raise a FileParseError if the custom parser raises.""" Path(tmp_path / "foo.json").write_text("""{ "foo": "hello", "bar": 42 }""") error = Exception("oh no") mock_parse_json.side_effect = error path = PurePosixPath(tmp_path / "foo") with pytest.raises(FileParseError): sync_filesystem.read_json(path, parse_json=mock_parse_json)
def test_write_json_with_custom_encoder( tmp_path: Path, mock_encode_json: MagicMock, sync_filesystem: SyncFilesystem ) -> None: """It should encode and write a file using a custom encoder.""" path = tmp_path / "foo" obj = {"foo": "hello", "bar": 0} mock_encode_json.return_value = "I just met you" sync_filesystem.write_json(path, obj, encode_json=mock_encode_json) assert path.with_suffix(".json").read_text() == "I just met you" mock_encode_json.assert_called_with(obj)
def test_read_dir_with_empty_dir( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should return an empty list with read_dir on an empty directory.""" basenames = sync_filesystem.read_dir(tmp_path) assert basenames == []
def test_file_exists_returns_false_if_no_file( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should return False with file_exists if no JSON files exist.""" path = PurePosixPath(tmp_path / "foo") exists = sync_filesystem.file_exists(path) assert exists is False
def test_ensure_dir_noops_when_dir_exists( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should do nothing with ensure_dir if the directory already exists.""" tmp_path.mkdir(exist_ok=True) dir_name = PurePosixPath(tmp_path) result = sync_filesystem.ensure_dir(dir_name) assert dir_name == result
def test_file_exists_returns_true_if_file_exists( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should return True with file_exists if JSON file exists.""" (tmp_path / "foo.json").touch() path = PurePosixPath(tmp_path / "foo") exists = sync_filesystem.file_exists(path) assert exists is True
def test_ensure_dir_creates_dir( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should create a directory with ensure_dir if it doesn't exist.""" dir_name = PurePosixPath(tmp_path) / "the_limit_does_not_exist" result = sync_filesystem.ensure_dir(dir_name) assert result == dir_name assert Path(dir_name).is_dir()
def test_file_exists_returns_false_if_path_is_directory( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should return False with file_exists if path points to directory.""" (tmp_path / "foo.json").mkdir() path = PurePosixPath(tmp_path / "foo") exists = sync_filesystem.file_exists(path) assert exists is False
def test_read_json_loads_json_file_to_dict( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should read a file and load the contents into JSON.""" Path(tmp_path / "foo.json").write_text("""{ "foo": "hello", "bar": 42 }""") path = PurePosixPath(tmp_path / "foo") result: ParsedObj = sync_filesystem.read_json(path) assert result == {"foo": "hello", "bar": 42}
def test_read_dir_with_dir_of_json_files( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should return a list of JSON basenames with read_dir.""" (tmp_path / "foo.json").touch() (tmp_path / "bar.json").touch() (tmp_path / "baz.json").touch() basenames = sync_filesystem.read_dir(tmp_path) assert set(basenames) == set(["foo", "bar", "baz"])
def test_read_dir_walks_directories( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should ignore include files nested in directories in read_dir.""" (tmp_path / "foo.json").touch() (tmp_path / "bar").mkdir() (tmp_path / "bar" / "baz.json").touch() basenames = sync_filesystem.read_dir(tmp_path) assert basenames == ["foo", "bar/baz"]
def test_read_dir_ignores_non_json_and_dotfiles( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should ignore dotfiles and non-JSON files with read_dir.""" (tmp_path / "foo.json").touch() (tmp_path / ".bar.json").touch() (tmp_path / "baz.zip").touch() basenames = sync_filesystem.read_dir(tmp_path) assert basenames == ["foo"]
def test_read_json_with_custom_parser( tmp_path: Path, mock_parse_json: MagicMock, sync_filesystem: SyncFilesystem ) -> None: """It should read a file and parse into JSON using custom parser.""" Path(tmp_path / "foo.json").write_text("""{ "this": "is crazy" }""") mock_parse_json.return_value = {"call me": "maybe"} path = PurePosixPath(tmp_path / "foo") result = sync_filesystem.read_json(path, parse_json=mock_parse_json) assert result == {"call me": "maybe"} mock_parse_json.assert_called_with("""{ "this": "is crazy" }""")
def test_read_json_dir_can_ignore_errors( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should allow reading all directory files while ignoring any errors.""" Path(tmp_path / "foo.json").write_text("""{ "foo": "hello", "bar": 0 }""") Path(tmp_path / "bar.json").write_text("""{ "foo": "from the",}""") path = PurePosixPath(tmp_path) files: List[Entry[ParsedObj]] = sync_filesystem.read_json_dir( path, ignore_errors=True ) assert files == [Entry(path=path / "foo", contents={"foo": "hello", "bar": 0})]
def test_read_json_dir_reads_multiple_files( tmp_path: Path, sync_filesystem: SyncFilesystem ) -> None: """It should read a all files in a directory.""" Path(tmp_path / "foo.json").write_text("""{ "foo": "hello", "bar": 0 }""") Path(tmp_path / "bar.json").write_text("""{ "foo": "from the", "bar": 1 }""") Path(tmp_path / "baz.json").write_text("""{ "foo": "other side", "bar": 2 }""") path = PurePosixPath(tmp_path) files: List[Entry[ParsedObj]] = sync_filesystem.read_json_dir(path) assert len(files) == 3 assert Entry(path=path / "foo", contents={"foo": "hello", "bar": 0}) in files assert Entry(path=path / "bar", contents={"foo": "from the", "bar": 1}) in files assert Entry(path=path / "baz", contents={"foo": "other side", "bar": 2}) in files
def test_read_json_dir_with_custom_parser( tmp_path: Path, mock_parse_json: MagicMock, sync_filesystem: SyncFilesystem ) -> None: """It should read a all files in a directory.""" Path(tmp_path / "foo.json").write_text("""{ "foo": "hello", "bar": 0 }""") Path(tmp_path / "bar.json").write_text("""{ "foo": "from the", "bar": 1 }""") Path(tmp_path / "baz.json").write_text("""{ "foo": "other side", "bar": 2 }""") mock_parse_json.return_value = {"call me": "maybe"} path = PurePosixPath(tmp_path) files = sync_filesystem.read_json_dir(path, parse_json=mock_parse_json) assert len(files) == 3 assert Entry(path=path / "foo", contents={"call me": "maybe"}) in files assert Entry(path=path / "bar", contents={"call me": "maybe"}) in files assert Entry(path=path / "baz", contents={"call me": "maybe"}) in files mock_parse_json.assert_any_call("""{ "foo": "hello", "bar": 0 }""") mock_parse_json.assert_any_call("""{ "foo": "from the", "bar": 1 }""") mock_parse_json.assert_any_call("""{ "foo": "other side", "bar": 2 }""")
def sync_filesystem() -> SyncFilesystem: """Create a real synchronous filesystem.""" return SyncFilesystem()