diff --git a/.gitattributes b/.gitattributes index b9cb5340b1a941e1d897dab5240b0f820de611dd..8abf9c1f5e1a4108f0bcb7c44be0d3269007aef3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,6 +11,7 @@ lib/std/compress/lzma/testdata/** binary lib/std/compress/xz/testdata/** binary lib/std/crypto/codecs/asn1/der/testdata/** binary lib/std/tar/testdata/** binary +lib/std/zip/testdata/** binary src/Package/Fetch/testdata/** binary src/Package/Fetch/git/testdata/** binary diff --git a/build.zig b/build.zig index 5a89092c75e9e2bdc1c82c225b8d5c5bd011720f..eb0a45a620cdedc9bd35cd232510f36527facc68 100644 --- a/build.zig +++ b/build.zig @@ -153,6 +153,8 @@ pub fn build(b: *std.Build) !void { ".tzif", // exclude files from lib/std/tar/testdata ".tar", + // exclude files from lib/std/zip/testdata + ".zip", // others "README.md", }, diff --git a/lib/std/zip.zig b/lib/std/zip.zig index f234e9c55f286e3d034e536115d4a77edc26ba5b..3784605d0227653b8424dbc5345ff55a481878b0 100644 --- a/lib/std/zip.zig +++ b/lib/std/zip.zig @@ -638,3 +638,85 @@ pub fn extract(dest: Io.Dir, fr: *File.Reader, options: ExtractOptions) !void { } } } + +const testing = std.testing; + +test "extractTo" { + const io = testing.io; + var tmp = testing.tmpDir(.{}); + defer tmp.cleanup(); + + try tmp.dir.writeFile(io, .{ + .sub_path = "test.zip", + .data = @embedFile("zip/testdata/test.zip"), + }); + + var file = try tmp.dir.openFile(io, "test.zip", .{}); + defer file.close(io); + var read_buf: [512]u8 = undefined; + var reader = file.reader(io, &read_buf); + + const Expected = struct { + contents: []const u8, + compression: CompressionMethod, + }; + const expected_map = std.StaticStringMap(Expected).initComptime(.{ + .{ "deflate.txt", Expected{ .contents = "aaaaaaaaaaaaaaaaaaaaaaaa\n", .compression = .deflate } }, + .{ "store.txt", Expected{ .contents = "hello world\n", .compression = .store } }, + .{ "dir/", Expected{ .contents = "", .compression = .store } }, + }); + + var iter = try Iterator.init(&reader); + var num_entries: usize = 0; + while (try iter.next()) |entry| { + var filename_buf: [256]u8 = undefined; + const filename = try entry.getFilename(&reader, &filename_buf, .{}); + const expected = expected_map.get(filename) orelse { + std.debug.print("found unexpected filename: {f}\n", .{std.ascii.hexEscape(filename, .lower)}); + return error.UnexpectedFilename; + }; + var buf: [256]u8 = undefined; + var w: Writer = .fixed(&buf); + try entry.extractTo(&reader, &w); + try testing.expectEqualStrings(expected.contents, w.buffered()); + try testing.expectEqual(expected.compression, entry.compression_method); + num_entries += 1; + } + try testing.expectEqual(expected_map.kvs.len, num_entries); +} + +test "output buffers too small" { + const io = testing.io; + var tmp = testing.tmpDir(.{}); + defer tmp.cleanup(); + + try tmp.dir.writeFile(io, .{ + .sub_path = "test.zip", + .data = @embedFile("zip/testdata/test.zip"), + }); + + var file = try tmp.dir.openFile(io, "test.zip", .{}); + defer file.close(io); + var read_buf: [512]u8 = undefined; + var reader = file.reader(io, &read_buf); + + var iter = try Iterator.init(&reader); + var num_entries: usize = 0; + while (try iter.next()) |entry| { + try testing.expectError( + error.ZipInsufficientBuffer, + entry.getFilename(&reader, &.{}, .{}), + ); + + if (entry.uncompressed_size <= 1) continue; + + var buf: [1]u8 = undefined; + var w: Writer = .fixed(&buf); + try testing.expectError( + error.WriteFailed, + entry.extractTo(&reader, &w), + ); + num_entries += 1; + } + try std.testing.expect(num_entries > 0); +} diff --git a/lib/std/zip/testdata/test.zip b/lib/std/zip/testdata/test.zip new file mode 100644 index 0000000000000000000000000000000000000000..48127af3be38d314f7195e3b4aea166ee3a55805 Binary files /dev/null and b/lib/std/zip/testdata/test.zip differ