diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9de8b015303..0102f24df36 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -178,6 +178,7 @@ /modules/regex/tests/ @godotengine/core @godotengine/tests /modules/zip/ @godotengine/core /modules/zip/doc_classes/ @godotengine/core @godotengine/documentation +/modules/zip/tests @godotengine/core @godotengine/tests # Platform diff --git a/modules/zip/SCsub b/modules/zip/SCsub index 0bab3ff5f9a..0ae5ae91093 100644 --- a/modules/zip/SCsub +++ b/modules/zip/SCsub @@ -8,3 +8,7 @@ env_zip = env_modules.Clone() # Module files env_zip.add_source_files(env.modules_sources, "*.cpp") + +if env["tests"]: + env_zip.Append(CPPDEFINES=["TESTS_ENABLED"]) + env_zip.add_source_files(env.modules_sources, "./tests/*.cpp") diff --git a/modules/zip/doc_classes/ZIPPacker.xml b/modules/zip/doc_classes/ZIPPacker.xml index 1d8b613f313..c967ed93594 100644 --- a/modules/zip/doc_classes/ZIPPacker.xml +++ b/modules/zip/doc_classes/ZIPPacker.xml @@ -45,6 +45,13 @@ This must be called before everything else. + + + + + Set the compression level used when [method start_file] is called. + + @@ -72,5 +79,17 @@ Add new files to the existing zip archive at the given path. + + Start a file with no compression. + + + Start a file with the default compression level. + + + Start a file with the the best compression level. + + + Start a file with the the best and fast compression level. + diff --git a/modules/zip/tests/data/test.zip b/modules/zip/tests/data/test.zip new file mode 100644 index 00000000000..632dff1d504 Binary files /dev/null and b/modules/zip/tests/data/test.zip differ diff --git a/modules/zip/tests/test_zip.cpp b/modules/zip/tests/test_zip.cpp new file mode 100644 index 00000000000..0692639c2d3 --- /dev/null +++ b/modules/zip/tests/test_zip.cpp @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* test_zip.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "test_zip.h" + +namespace TestZip { + +void check_file_size(const String &p_path, int p_expected_size) { + Ref f = FileAccess::open(p_path, FileAccess::READ); + CHECK(f.is_valid()); + CHECK(f->get_length() == p_expected_size); +} + +} // namespace TestZip diff --git a/modules/zip/tests/test_zip.h b/modules/zip/tests/test_zip.h new file mode 100644 index 00000000000..347c585abae --- /dev/null +++ b/modules/zip/tests/test_zip.h @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* test_zip.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef TEST_ZIP_H +#define TEST_ZIP_H + +#include "tests/test_macros.h" +#include "tests/test_utils.h" + +#include "../zip_packer.h" +#include "../zip_reader.h" + +namespace TestZip { + +void check_file_size(const String &p_path, int p_expected_size); + +TEST_CASE("[ZIPPacker] default compression") { + const String path = TestUtils::get_temp_path("compressed.zip"); + ZIPPacker packer; + Error open_result = packer.open(path, ZIPPacker::APPEND_CREATE); + CHECK(open_result == OK); + Error start_file_result = packer.start_file("demo.txt"); + CHECK(start_file_result == OK); + String text = "hello world!"; + Error write_file_result = packer.write_file(text.to_utf8_buffer()); + CHECK(write_file_result == OK); + Error close_file_result = packer.close_file(); + CHECK(close_file_result == OK); + Error close_result = packer.close(); + CHECK(close_result == OK); + check_file_size(path, 128); +} + +TEST_CASE("[ZIPPacker] no compression") { + const String path = TestUtils::get_temp_path("uncompressed.zip"); + ZIPPacker packer; + Error open_result = packer.open(path, ZIPPacker::APPEND_CREATE); + CHECK(open_result == OK); + packer.set_compression_level(ZIPPacker::COMPRESSION_NONE); + Error start_file_result = packer.start_file("demo.txt"); + CHECK(start_file_result == OK); + String text = "hello world!"; + Error write_file_result = packer.write_file(text.to_utf8_buffer()); + CHECK(write_file_result == OK); + Error close_file_result = packer.close_file(); + CHECK(close_file_result == OK); + Error close_result = packer.close(); + CHECK(close_result == OK); + check_file_size(path, 131); +} + +TEST_CASE("[ZIPReader] read files") { + String test_data = String("modules/zip/tests/data/").path_join("test.zip"); + ZIPReader reader; + Error open_result = reader.open(test_data); + CHECK(open_result == OK); + + const String hello_path = "hello.txt"; + const String world_path = "world.txt"; + PackedStringArray expected_files; + expected_files.push_back(hello_path); + expected_files.push_back(world_path); + CHECK(reader.get_files() == expected_files); + + const String expected_hello_text = "hello world!"; + const String expected_world_text = "game over!"; + PackedByteArray hello_bytes = reader.read_file(hello_path, false); + PackedByteArray world_bytes = reader.read_file(world_path, true); + CHECK(hello_bytes == expected_hello_text.to_utf8_buffer()); + CHECK(world_bytes == expected_world_text.to_utf8_buffer()); +} + +} // namespace TestZip + +#endif // TEST_ZIP_H diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp index 4e182f97878..8693b3ff910 100644 --- a/modules/zip/zip_packer.cpp +++ b/modules/zip/zip_packer.cpp @@ -55,6 +55,23 @@ Error ZIPPacker::close() { return err; } +void ZIPPacker::set_compression_level(CompressionLevel p_compression_level) { + switch (p_compression_level) { + case COMPRESSION_NONE: + compression_level = Z_NO_COMPRESSION; + break; + case COMPRESSION_BEST_SPEED: + compression_level = Z_BEST_SPEED; + break; + case COMPRESSION_BEST: + compression_level = Z_BEST_COMPRESSION; + break; + case COMPRESSION_DEFAULT: + default: + compression_level = Z_DEFAULT_COMPRESSION; + } +} + Error ZIPPacker::start_file(const String &p_path) { ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker must be opened before use."); @@ -81,7 +98,7 @@ Error ZIPPacker::start_file(const String &p_path) { 0, nullptr, Z_DEFLATED, - Z_DEFAULT_COMPRESSION, + compression_level, 0, -MAX_WBITS, DEF_MEM_LEVEL, @@ -107,6 +124,7 @@ Error ZIPPacker::close_file() { void ZIPPacker::_bind_methods() { ClassDB::bind_method(D_METHOD("open", "path", "append"), &ZIPPacker::open, DEFVAL(Variant(APPEND_CREATE))); + ClassDB::bind_method(D_METHOD("set_compression_level", "compression_level"), &ZIPPacker::set_compression_level); ClassDB::bind_method(D_METHOD("start_file", "path"), &ZIPPacker::start_file); ClassDB::bind_method(D_METHOD("write_file", "data"), &ZIPPacker::write_file); ClassDB::bind_method(D_METHOD("close_file"), &ZIPPacker::close_file); @@ -115,9 +133,16 @@ void ZIPPacker::_bind_methods() { BIND_ENUM_CONSTANT(APPEND_CREATE); BIND_ENUM_CONSTANT(APPEND_CREATEAFTER); BIND_ENUM_CONSTANT(APPEND_ADDINZIP); + + BIND_ENUM_CONSTANT(COMPRESSION_NONE); + BIND_ENUM_CONSTANT(COMPRESSION_DEFAULT); + BIND_ENUM_CONSTANT(COMPRESSION_BEST); + BIND_ENUM_CONSTANT(COMPRESSION_BEST_SPEED); } -ZIPPacker::ZIPPacker() {} +ZIPPacker::ZIPPacker() { + compression_level = Z_DEFAULT_COMPRESSION; +} ZIPPacker::~ZIPPacker() { if (fa.is_valid()) { diff --git a/modules/zip/zip_packer.h b/modules/zip/zip_packer.h index e194f5ebbe3..40affe3bc79 100644 --- a/modules/zip/zip_packer.h +++ b/modules/zip/zip_packer.h @@ -41,6 +41,7 @@ class ZIPPacker : public RefCounted { Ref fa; zipFile zf = nullptr; + int compression_level; protected: static void _bind_methods(); @@ -52,9 +53,18 @@ public: APPEND_ADDINZIP = 2, }; + enum CompressionLevel { + COMPRESSION_DEFAULT = 0, + COMPRESSION_NONE = 1, + COMPRESSION_BEST_SPEED = 2, + COMPRESSION_BEST = 3, + }; + Error open(const String &p_path, ZipAppend p_append); Error close(); + void set_compression_level(CompressionLevel p_compression_level); + Error start_file(const String &p_path); Error write_file(const Vector &p_data); Error close_file(); @@ -64,5 +74,6 @@ public: }; VARIANT_ENUM_CAST(ZIPPacker::ZipAppend) +VARIANT_ENUM_CAST(ZIPPacker::CompressionLevel) #endif // ZIP_PACKER_H