diff --git a/docs/commands/add.md b/docs/commands/add.md index 07b2e0e..d07ffb0 100644 --- a/docs/commands/add.md +++ b/docs/commands/add.md @@ -66,36 +66,29 @@ changed files need to be re-added. $ mpqcli add wow-patch.mpq textures/ --update --overwrite [~] Skipping unchanged file: Creature\Bear\Bear.blp [+] Adding file: Creature\Wolf\Wolf.blp -[*] 1 files added, 1 files skipped +[*] For textures: 1 files added, 1 files skipped, 0 files failed. ``` Note: the skip check is size-based only. Files with the same size but different content are not detected as changed. If precise change detection matters, pass `--overwrite` without `--update` to unconditionally replace every file. -## Control where a single file is stored +## Control where files are stored -These options apply to single-file adds only. - -Add a file under a specific name using `-f` or `--filename-in-archive`: - -```bash -$ mpqcli add wow-patch.mpq fta.txt --filename-in-archive "alliance.txt" -[+] Adding file: alliance.txt -``` - -Add a file into a subdirectory using `-d` or `--directory-in-archive`: +For single files, one can specify both directory and filename in one step using `-p` or `--path`: ```bash -$ mpqcli add wow-patch.mpq fts.txt --directory-in-archive texts -[+] Adding file: texts\fts.txt +$ mpqcli add wow-patch.mpq fts.txt --path "texts\swarm.txt" +[+] Adding file: texts\swarm.txt ``` -Specify both directory and filename in one step using `-p` or `--path`: +For directories, one can specify the base directory using `-p` or `--path`: ```bash -$ mpqcli add wow-patch.mpq fts.txt --path "texts\swarm.txt" -[+] Adding file: texts\swarm.txt +$ mpqcli add wow-patch.mpq textures/ --path textures +[+] Adding file: textures\Creature\Bear\Bear.blp +[+] Adding file: textures\Creature\Wolf\Wolf.blp +[*] For textures: 2 files added, 0 files skipped, 0 files failed. ``` ## Overwrite existing files diff --git a/docs/commands/create.md b/docs/commands/create.md index d517e42..cbdb31a 100644 --- a/docs/commands/create.md +++ b/docs/commands/create.md @@ -31,7 +31,22 @@ Create an MPQ file from a single file. $ mpqcli create --game diablo2 ``` -This will put the given file in the root of the MPQ archive. By optionally providing a path in the `--name-in-archive` parameter, the name that the file has in the MPQ archive can be changed, and it can be put in a directory. +## Control where files are stored + +For single files, one can specify both directory and filename in one step using `-p` or `--path`: + +```bash +$ mpqcli create fts.txt --output archive.mpq --path "texts\swarm.txt" +[+] Adding file: texts\swarm.txt +``` + +For directories, one can specify the base directory using `-p` or `--path`: + +```bash +$ mpqcli create textures/ --output archive.mpq --path textures +[+] Adding file: textures\Creature\Bear\Bear.blp +[+] Adding file: textures\Creature\Wolf\Wolf.blp +``` ## Create and sign an MPQ archive diff --git a/src/commands.cpp b/src/commands.cpp index 6565bf9..9b1c744 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -14,6 +14,16 @@ namespace fs = std::filesystem; +std::string ResolveArchiveName(const std::string &f, const std::optional &path, + const bool treatAsDirectory = false) { + fs::path filePath = path.value_or(fs::path(f).filename().u8string()); + if (treatAsDirectory) { + const std::string filename = fs::path(f).filename().u8string(); + filePath = path.value_or("") / fs::path(filename); + } + return WindowsifyFilePath(filePath); +} + int HandleVersion() { std::cout << MPQCLI_VERSION << "-" << GIT_COMMIT_HASH << std::endl; return 0; @@ -42,18 +52,13 @@ int HandleInfo(const std::string &target, const std::optional &prop return 0; } -int HandleCreate(const std::string &target, const std::optional &nameInArchive, +int HandleCreate(const std::string &target, const std::optional &path, const std::optional &output, bool signArchive, const std::optional &locale, const std::optional &gameProfile, int32_t mpqVersion, int64_t streamFlags, int64_t sectorSize, int64_t rawChunkSize, int64_t fileFlags1, int64_t fileFlags2, int64_t fileFlags3, int64_t attrFlags, int64_t fileDwFlags, int64_t fileDwCompression, int64_t fileDwCompressionNext) { - if (!fs::is_regular_file(target) && nameInArchive.has_value()) { - std::cerr << "[!] Cannot specify --name-in-archive when adding a directory." << std::endl; - return 1; - } - fs::path outputFilePath; if (output.has_value()) { outputFilePath = fs::absolute(output.value()); @@ -112,18 +117,19 @@ int HandleCreate(const std::string &target, const std::optional &na if (fileDwCompressionNext >= 0) addOverrides.dwCompressionNext = static_cast(fileDwCompressionNext); - if (fs::is_regular_file(target)) { - // Default: use the filename as path, saves file to root of MPQ - fs::path filePath = fs::path(target); - std::string archivePath = filePath.filename().u8string(); - if (nameInArchive.has_value()) { // Optional: specified filename inside archive - filePath = fs::path(nameInArchive.value()); - archivePath = WindowsifyFilePath(filePath); // Normalise path for MPQ - } + if (fs::is_directory(target)) { + const std::string prefix = path.value_or(""); + result |= AddFiles(hArchive, target, prefix, lcid, gameRules, addOverrides); + + } else if (fs::is_regular_file(target)) { + std::string archivePath = ResolveArchiveName(target, path); result |= AddFile(hArchive, target, archivePath, lcid, gameRules, addOverrides); + } else { - result |= AddFiles(hArchive, target, "", lcid, gameRules, addOverrides); + std::cerr << "[!] Not a file or directory: " << target << std::endl; + result |= 1; } + if (signArchive) { SignMpqArchive(hArchive); } @@ -137,9 +143,7 @@ int HandleCreate(const std::string &target, const std::optional &na } int HandleAdd(const std::vector &files, const std::string &target, - const std::optional &path, - const std::optional &dirInArchive, - const std::optional &nameInArchive, bool overwrite, bool update, + const std::optional &path, bool overwrite, bool update, const std::optional &locale, const std::optional &gameProfile, int64_t fileDwFlags, int64_t fileDwCompression, int64_t fileDwCompressionNext) { @@ -149,37 +153,6 @@ int HandleAdd(const std::vector &files, const std::string &target, return 1; } - bool hasDirectory = false; - for (const auto &f : files) { - if (fs::is_directory(f)) { - hasDirectory = true; - break; - } - } - bool multipleInputs = files.size() > 1; - - if ((hasDirectory || multipleInputs) && - (dirInArchive.has_value() || nameInArchive.has_value())) { - std::cerr << "[!] --directory-in-archive and --filename-in-archive are only valid when " - "adding a single file." - << std::endl; - CloseMpqArchive(hArchive); - return 1; - } - if (multipleInputs && path.has_value()) { - std::cerr << "[!] --path is only valid when adding a single file or directory." - << std::endl; - CloseMpqArchive(hArchive); - return 1; - } - if (path.has_value() && (dirInArchive.has_value() || nameInArchive.has_value())) { - std::cerr << "[!] Cannot specify --path together with --name-in-archive or " - "--directory-in-archive." - << std::endl; - CloseMpqArchive(hArchive); - return 1; - } - LCID lcid = locale.has_value() ? LangToLocale(locale.value()) : defaultLocale; GameProfile profile; @@ -197,6 +170,14 @@ int HandleAdd(const std::vector &files, const std::string &target, if (fileDwCompressionNext >= 0) addOverrides.dwCompressionNext = static_cast(fileDwCompressionNext); + bool hasDirectory = false; + for (const auto &f : files) { + if (fs::is_directory(f)) { + hasDirectory = true; + break; + } + } + if (update && !hasDirectory) { std::cerr << "[!] Warning: --update is only meaningful when adding a directory" << std::endl; @@ -215,20 +196,8 @@ int HandleAdd(const std::vector &files, const std::string &target, AddFiles(hArchive, f, prefix, lcid, gameRules, addOverrides, overwrite, update); } else if (fs::is_regular_file(f)) { - fs::path filePath = fs::path(f); - std::string archivePath = filePath.filename().u8string(); - - if (path.has_value()) { - filePath = fs::path(path.value()); - archivePath = WindowsifyFilePath(filePath); - } else if (dirInArchive.has_value() || nameInArchive.has_value()) { - std::string effectiveDir = - dirInArchive.value_or(fs::path(f).parent_path().u8string()); - std::string effectiveName = nameInArchive.value_or(archivePath); - filePath = fs::path(effectiveDir) / fs::path(effectiveName); - archivePath = WindowsifyFilePath(filePath); - } - + const bool treatAsDirectory = hasDirectory || files.size() > 1; + std::string archivePath = ResolveArchiveName(f, path, treatAsDirectory); result |= AddFile(hArchive, f, archivePath, lcid, gameRules, addOverrides, overwrite); } else { diff --git a/src/commands.h b/src/commands.h index dc3c335..3ba0d20 100644 --- a/src/commands.h +++ b/src/commands.h @@ -9,7 +9,7 @@ int HandleVersion(); int HandleAbout(); int HandleInfo(const std::string &target, const std::optional &property); -int HandleCreate(const std::string &target, const std::optional &nameInArchive, +int HandleCreate(const std::string &target, const std::optional &path, const std::optional &output, bool signArchive, const std::optional &locale, const std::optional &gameProfile, int32_t mpqVersion, @@ -17,9 +17,7 @@ int HandleCreate(const std::string &target, const std::optional &na int64_t fileFlags2, int64_t fileFlags3, int64_t attrFlags, int64_t fileDwFlags, int64_t fileDwCompression, int64_t fileDwCompressionNext); int HandleAdd(const std::vector &files, const std::string &target, - const std::optional &path, - const std::optional &dirInArchive, - const std::optional &nameInArchive, bool overwrite, bool update, + const std::optional &path, bool overwrite, bool update, const std::optional &locale, const std::optional &gameProfile, int64_t fileDwFlags, int64_t fileDwCompression, int64_t fileDwCompressionNext); diff --git a/src/main.cpp b/src/main.cpp index 1855f37..b4140f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,21 +19,21 @@ int main(int argc, char **argv) { // CLI: base // These are reused in multiple subcommands + // clang-format off: preserve column-aligned flag-to-char mappings std::string baseTarget; // all subcommands std::string baseFile; // extract, read std::optional baseLocale; // add, create, extract, read, remove - std::optional baseNameInArchive; // add, create + std::optional basePath; // add, create std::optional baseOutput; // create, extract std::optional baseListfileName; // extract, list std::optional baseGameProfile; // add, create int64_t fileDwFlags = -1; // add, create int64_t fileDwCompression = -1; // add, create int64_t fileDwCompressionNext = -1; // add, create + // clang-format on // CLI: info std::optional infoProperty; // CLI: add - std::optional addBasePath; - std::optional addBaseDirInArchive; bool addOverwrite = false; bool addUpdate = false; std::vector addFiles; @@ -90,7 +90,8 @@ int main(int argc, char **argv) { create->add_option("target", baseTarget, "Directory or file to put in MPQ archive") ->required() ->check(CLI::ExistingPath); - create->add_option("-n,--name-in-archive", baseNameInArchive, "Filename inside MPQ archive"); + create->add_option("-p,--path", basePath, + "Archive path for a single file, or prefix for a directory"); create->add_option("-o,--output", baseOutput, "Output MPQ archive"); create->add_flag("-s,--sign", createSignArchive, "Sign the MPQ archive (default false)"); create->add_option("--locale", baseLocale, "Locale to use for added files")->check(LocaleValid); @@ -140,12 +141,8 @@ int main(int argc, char **argv) { "Files or directories to add; pass - to read paths from stdin") ->required() ->expected(-1); - add->add_option("-p,--path", addBasePath, - "Archive path for a single file, or prefix for a directory add"); - add->add_option("-d,--directory-in-archive", addBaseDirInArchive, - "Directory to put file inside within MPQ archive (single file only)"); - add->add_option("-f,--filename-in-archive", baseNameInArchive, - "Filename inside MPQ archive (single file only)"); + add->add_option("-p,--path", basePath, + "Archive path for a single file, or prefix for a directory"); add->add_flag("-w,--overwrite", addOverwrite, "Overwrite file if it already is in MPQ archive"); add->add_flag("-u,--update", addUpdate, "Skip files whose archived size matches the on-disk size (directory add only)"); @@ -240,11 +237,11 @@ int main(int argc, char **argv) { } if (app.got_subcommand(create)) { - return HandleCreate(baseTarget, baseNameInArchive, baseOutput, createSignArchive, - baseLocale, baseGameProfile, createMpqVersion, createStreamFlags, - createSectorSize, createRawChunkSize, createFileFlags1, - createFileFlags2, createFileFlags3, createAttrFlags, fileDwFlags, - fileDwCompression, fileDwCompressionNext); + return HandleCreate(baseTarget, basePath, baseOutput, createSignArchive, baseLocale, + baseGameProfile, createMpqVersion, createStreamFlags, createSectorSize, + createRawChunkSize, createFileFlags1, createFileFlags2, + createFileFlags3, createAttrFlags, fileDwFlags, fileDwCompression, + fileDwCompressionNext); } if (app.got_subcommand(add)) { @@ -259,9 +256,9 @@ int main(int argc, char **argv) { resolvedAddFiles.push_back(f); } } - return HandleAdd(resolvedAddFiles, baseTarget, addBasePath, addBaseDirInArchive, - baseNameInArchive, addOverwrite, addUpdate, baseLocale, baseGameProfile, - fileDwFlags, fileDwCompression, fileDwCompressionNext); + return HandleAdd(resolvedAddFiles, baseTarget, basePath, addOverwrite, addUpdate, + baseLocale, baseGameProfile, fileDwFlags, fileDwCompression, + fileDwCompressionNext); } if (app.got_subcommand(remove)) { diff --git a/test/test_add.py b/test/test_add.py index 73da66c..299fcfb 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -108,98 +108,81 @@ def test_add_multiple_files_to_mpq_archive(binary_path, generate_test_files): verify_archive_file_content(binary_path, target_file, expected_content) -def test_add_file_with_filenameinarchive_and_directoryinarchive_and_path_to_mpq_archive(binary_path, generate_test_files): +def test_add_file_with_path_to_mpq_archive(binary_path, generate_test_files): _ = generate_test_files script_dir = Path(__file__).parent target_file = script_dir / "data" / "files.mpq" create_mpq_archive_for_test(binary_path, script_dir) - test_file0 = script_dir / "data" / "test0.txt" - test_file0.write_text("This is a test file for MPQ addition.") - test_file1 = script_dir / "data" / "test1.txt" - test_file1.write_text("This is another test file for MPQ addition.") - test_file2 = script_dir / "data" / "test2.txt" - test_file2.write_text("This is yet another test file for MPQ addition.") - test_file3 = script_dir / "data" / "test3.txt" - test_file3.write_text("This is yet yet another test file for MPQ addition.") + test_file = script_dir / "data" / "test.txt" + test_file.write_text("This is a test file for MPQ addition.") - bin_dir = binary_path.parent - test_file1_copy = bin_dir / "test1.txt" - shutil.copy(test_file1, test_file1_copy) + result = subprocess.run( + [str(binary_path), "add", str(target_file), str(test_file), "--path", "important\\message.txt"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" - try: - result = subprocess.run( - [str(binary_path), "add", str(target_file), str(test_file0), "--directory-in-archive", "directory", "--path", "important.txt"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - assert result.returncode == 1, f"mpqcli failed with error: {result.stderr}" + result = subprocess.run( + [str(binary_path), "list", str(target_file)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) - result = subprocess.run( - [str(binary_path), "add", str(target_file), str(test_file0), "--filename-in-archive", "important.txt", "--path", "texts/important.txt"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - assert result.returncode == 1, f"mpqcli failed with error: {result.stderr}" + output_lines = set(result.stdout.splitlines()) - result = subprocess.run( - [str(binary_path), "add", str(target_file), str(test_file0), "--directory-in-archive", "directory"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" + expected_output = { + "cats.txt", + "dogs.txt", + "bytes", + "important\\message.txt", + } + assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" + assert output_lines == expected_output, f"Unexpected output: {output_lines}" - result = subprocess.run( - [str(binary_path), "add", str(target_file), test_file1_copy.name, "--filename-in-archive", "msg.txt"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - cwd=str(bin_dir) - ) - assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" - result = subprocess.run( - [str(binary_path), "add", str(target_file), str(test_file2), "--directory-in-archive", "texts", "--filename-in-archive", "info.txt"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" +def test_add_several_files_with_path_to_mpq_archive(binary_path, generate_test_files): + _ = generate_test_files + script_dir = Path(__file__).parent + target_file = script_dir / "data" / "files.mpq" - result = subprocess.run( - [str(binary_path), "add", str(target_file), str(test_file3), "--path", "important\\message.txt"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" + create_mpq_archive_for_test(binary_path, script_dir) - result = subprocess.run( - [str(binary_path), "list", str(target_file)], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) + test_file0 = script_dir / "data" / "test0.txt" + test_file0.write_text("This is a test file for MPQ addition.") + test_file1 = script_dir / "data" / "test1.txt" + test_file1.write_text("This is another test file for MPQ addition.") - output_lines = set(result.stdout.splitlines()) - - expected_output = { - "cats.txt", - "dogs.txt", - "bytes", - "directory\\test0.txt", - "msg.txt", - "texts\\info.txt", - "important\\message.txt", - } - assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" - assert output_lines == expected_output, f"Unexpected output: {output_lines}" - finally: - test_file1_copy.unlink(missing_ok=True) + result = subprocess.run( + [str(binary_path), "add", str(target_file), str(test_file0), str(test_file1), "--path", "texts"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" + + result = subprocess.run( + [str(binary_path), "list", str(target_file)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + output_lines = set(result.stdout.splitlines()) + + expected_output = { + "cats.txt", + "dogs.txt", + "bytes", + "texts\\test0.txt", + "texts\\test1.txt", + } + assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" + assert output_lines == expected_output, f"Unexpected output: {output_lines}" def test_add_existing_file_without_overwrite_should_fail(binary_path, generate_test_files): @@ -727,38 +710,6 @@ def test_add_directory_without_overwrite_skips_existing(binary_path, generate_te shutil.rmtree(add_dir, ignore_errors=True) -def test_add_dir_with_directory_in_archive_flag_errors(binary_path, generate_test_files): - _ = generate_test_files - script_dir = Path(__file__).parent - target_mpq = script_dir / "data" / "files.mpq" - add_dir = script_dir / "data" / "add_dir_flag_error" - - create_mpq_archive_for_test(binary_path, script_dir) - add_dir.mkdir(parents=True, exist_ok=True) - (add_dir / "x.txt").write_text("x") - - try: - result = subprocess.run( - [str(binary_path), "add", str(target_mpq), str(add_dir), "--directory-in-archive", "subdir"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - assert result.returncode == 1, f"Expected failure but got: {result.returncode}" - assert "--directory-in-archive" in result.stderr - - result = subprocess.run( - [str(binary_path), "add", str(target_mpq), str(add_dir), "--filename-in-archive", "name.txt"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - assert result.returncode == 1, f"Expected failure but got: {result.returncode}" - assert "--filename-in-archive" in result.stderr - finally: - shutil.rmtree(add_dir, ignore_errors=True) - - # ---- --update flag tests ---- def test_add_update_skips_unchanged_files(binary_path, generate_test_files): diff --git a/test/test_create.py b/test/test_create.py index 4f98edb..f62b836 100644 --- a/test/test_create.py +++ b/test/test_create.py @@ -220,12 +220,12 @@ def test_create_mpq_from_file(binary_path, generate_test_files): verify_archive_file_content(binary_path, target_file, {"enUS test.txt"}) -def test_create_mpq_from_file_with_nameinarchive_parameter(binary_path, generate_test_files): +def test_create_mpq_from_file_with_path_parameter(binary_path, generate_test_files): """ - Test MPQ archive creation from a file, with the --name-in-archive parameter. + Test MPQ archive creation from a file, with the --path parameter. This test checks: - MPQ archive creation from a file. - - That the --name-in-archive parameter is correctly handled. + - That the --path parameter is correctly handled. """ _ = generate_test_files script_dir = Path(__file__).parent @@ -240,7 +240,7 @@ def test_create_mpq_from_file_with_nameinarchive_parameter(binary_path, generate # test_create_mpq_already_exists target_file.unlink(missing_ok=True) result = subprocess.run( - [str(binary_path), "create", str(test_file), "--output", str(target_file), "--name-in-archive", "messages\\important.txt"], + [str(binary_path), "create", str(test_file), "--output", str(target_file), "--path", "messages\\important.txt"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True @@ -253,30 +253,44 @@ def test_create_mpq_from_file_with_nameinarchive_parameter(binary_path, generate verify_archive_file_content(binary_path, target_file, {"enUS messages\\important.txt"}) -def test_create_mpq_from_directory_with_nameinarchive_parameter(binary_path, generate_test_files): +def test_create_mpq_from_directory_with_path_parameter(binary_path, generate_test_files): """ - Test MPQ archive creation from a directory, with the --name-in-archive parameter. + Test MPQ archive creation from a directory, with the --path parameter. This test checks: - No MPQ archive is created. """ _ = generate_test_files script_dir = Path(__file__).parent - target_dir = script_dir / "data" / "files" + target_dir = script_dir / "data" / "files2" + # Create test directory with files + target_dir.mkdir(exist_ok=True) - target_file = target_dir.with_name("files_test").with_suffix(".mpq") - # Remove the target file if it exists - # Testing creation when file exists is handled: - # test_create_mpq_already_exists - target_file.unlink(missing_ok=True) - result = subprocess.run( - [str(binary_path), "create", str(target_dir), "--output", str(target_file), "--name-in-archive", "messages\\important.txt"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) + # Create a new test file on the fly + test_file = script_dir / "data" / "files2" / "important.txt" + test_file.write_text("This is a test file for MPQ addition.") - assert result.returncode == 1, f"mpqcli failed with error: {result.stderr}" - assert not target_file.exists(), "MPQ file was created" + try: + target_file = target_dir.with_name("files_test").with_suffix(".mpq") + # Remove the target file if it exists + # Testing creation when file exists is handled: + # test_create_mpq_already_exists + target_file.unlink(missing_ok=True) + result = subprocess.run( + [str(binary_path), "create", str(target_dir), "--output", str(target_file), "--path", "messages"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + assert result.returncode == 0, f"mpqcli failed with error: {result.stderr}" + assert target_file.exists(), "MPQ file was not created" + assert target_file.stat().st_size > 0, "MPQ file is empty" + + verify_archive_file_content(binary_path, target_file, {"enUS messages\\important.txt"}) + finally: + # Clean up + if target_dir.exists(): + shutil.rmtree(target_dir) def test_create_mpq_with_illegal_locale(binary_path, generate_test_files):