| // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| @TestOn('vm') |
| |
| import 'dart:convert'; |
| import 'dart:io'; |
| |
| import 'package:archive/archive.dart'; |
| import 'package:async/async.dart'; |
| import 'package:path/path.dart' as p; |
| import 'package:test/test.dart'; |
| import 'package:test_descriptor/test_descriptor.dart' as d; |
| |
| import 'utils.dart'; |
| |
| void main() { |
| group("create()", () { |
| test("creates an empty archive", () async { |
| await d.archive("test.tar").create(); |
| |
| var archive = |
| TarDecoder().decodeBytes(File(d.path("test.tar")).readAsBytesSync()); |
| expect(archive.files, isEmpty); |
| }); |
| |
| test("creates an archive with files", () async { |
| await d.archive("test.tar", [ |
| d.file("file1.txt", "contents 1"), |
| d.file("file2.txt", "contents 2") |
| ]).create(); |
| |
| var files = TarDecoder() |
| .decodeBytes(File(d.path("test.tar")).readAsBytesSync()) |
| .files; |
| expect(files.length, equals(2)); |
| _expectFile(files[0], "file1.txt", "contents 1"); |
| _expectFile(files[1], "file2.txt", "contents 2"); |
| }); |
| |
| test("creates an archive with files in a directory", () async { |
| await d.archive("test.tar", [ |
| d.dir("dir", [ |
| d.file("file1.txt", "contents 1"), |
| d.file("file2.txt", "contents 2") |
| ]) |
| ]).create(); |
| |
| var files = TarDecoder() |
| .decodeBytes(File(d.path("test.tar")).readAsBytesSync()) |
| .files; |
| expect(files.length, equals(2)); |
| _expectFile(files[0], "dir/file1.txt", "contents 1"); |
| _expectFile(files[1], "dir/file2.txt", "contents 2"); |
| }); |
| |
| test("creates an archive with files in a nested directory", () async { |
| await d.archive("test.tar", [ |
| d.dir("dir", [ |
| d.dir("subdir", [ |
| d.file("file1.txt", "contents 1"), |
| d.file("file2.txt", "contents 2") |
| ]) |
| ]) |
| ]).create(); |
| |
| var files = TarDecoder() |
| .decodeBytes(File(d.path("test.tar")).readAsBytesSync()) |
| .files; |
| expect(files.length, equals(2)); |
| _expectFile(files[0], "dir/subdir/file1.txt", "contents 1"); |
| _expectFile(files[1], "dir/subdir/file2.txt", "contents 2"); |
| }); |
| |
| group("creates a file in", () { |
| test("zip format", () async { |
| await d.archive("test.zip", [d.file("file.txt", "contents")]).create(); |
| |
| var archive = ZipDecoder() |
| .decodeBytes(File(d.path("test.zip")).readAsBytesSync()); |
| _expectFile(archive.files.single, "file.txt", "contents"); |
| }); |
| |
| group("gzip tar format", () { |
| for (var extension in [".tar.gz", ".tar.gzip", ".tgz"]) { |
| test("with $extension", () async { |
| await d.archive( |
| "test$extension", [d.file("file.txt", "contents")]).create(); |
| |
| var archive = TarDecoder().decodeBytes(GZipDecoder() |
| .decodeBytes(File(d.path("test$extension")).readAsBytesSync())); |
| _expectFile(archive.files.single, "file.txt", "contents"); |
| }); |
| } |
| }); |
| |
| group("bzip2 tar format", () { |
| for (var extension in [".tar.bz2", ".tar.bzip2"]) { |
| test("with $extension", () async { |
| await d.archive( |
| "test$extension", [d.file("file.txt", "contents")]).create(); |
| |
| var archive = TarDecoder().decodeBytes(BZip2Decoder() |
| .decodeBytes(File(d.path("test$extension")).readAsBytesSync())); |
| _expectFile(archive.files.single, "file.txt", "contents"); |
| }); |
| } |
| }); |
| }); |
| |
| group("gracefully rejects", () { |
| test("an uncreatable descriptor", () async { |
| await expectLater( |
| d.archive("test.tar", [d.filePattern(RegExp(r"^foo-"))]).create(), |
| throwsUnsupportedError); |
| await d.nothing("test.tar").validate(); |
| }); |
| |
| test("a non-file non-directory descriptor", () async { |
| await expectLater( |
| d.archive("test.tar", [d.nothing("file.txt")]).create(), |
| throwsUnsupportedError); |
| await d.nothing("test.tar").validate(); |
| }); |
| |
| test("an unknown file extension", () async { |
| await expectLater( |
| d.archive("test.asdf", [d.nothing("file.txt")]).create(), |
| throwsUnsupportedError); |
| }); |
| }); |
| }); |
| |
| group("validate()", () { |
| group("with an empty archive", () { |
| test("succeeds if an empty archive exists", () async { |
| File(d.path("test.tar")) |
| .writeAsBytesSync(TarEncoder().encode(Archive())); |
| await d.archive("test.tar").validate(); |
| }); |
| |
| test("succeeds if a non-empty archive exists", () async { |
| File(d.path("test.tar")).writeAsBytesSync( |
| TarEncoder().encode(Archive()..addFile(_file("file.txt")))); |
| await d.archive("test.tar").validate(); |
| }); |
| |
| test("fails if no archive exists", () { |
| expect(d.archive("test.tar").validate(), |
| throwsA(toString(startsWith('File not found: "test.tar".')))); |
| }); |
| |
| test("fails if an invalid archive exists", () { |
| d.file("test.tar", "not a valid tar file").create(); |
| expect( |
| d.archive("test.tar").validate(), |
| throwsA(toString( |
| startsWith('File "test.tar" is not a valid archive.')))); |
| }); |
| }); |
| |
| test("succeeds if an archive contains a matching file", () async { |
| File(d.path("test.tar")).writeAsBytesSync(TarEncoder() |
| .encode(Archive()..addFile(_file("file.txt", "contents")))); |
| await d.archive("test.tar", [d.file("file.txt", "contents")]).validate(); |
| }); |
| |
| test("fails if an archive doesn't contain a file", () async { |
| File(d.path("test.tar")).writeAsBytesSync(TarEncoder().encode(Archive())); |
| expect( |
| d.archive("test.tar", [d.file("file.txt", "contents")]).validate(), |
| throwsA( |
| toString(startsWith('File not found: "test.tar/file.txt".')))); |
| }); |
| |
| test("fails if an archive contains a non-matching file", () async { |
| File(d.path("test.tar")).writeAsBytesSync(TarEncoder() |
| .encode(Archive()..addFile(_file("file.txt", "wrong contents")))); |
| expect( |
| d.archive("test.tar", [d.file("file.txt", "contents")]).validate(), |
| throwsA(toString( |
| startsWith('File "test.tar/file.txt" should contain:')))); |
| }); |
| |
| test("succeeds if an archive contains a file matching a pattern", () async { |
| File(d.path("test.tar")).writeAsBytesSync(TarEncoder() |
| .encode(Archive()..addFile(_file("file.txt", "contents")))); |
| await d.archive("test.tar", |
| [d.filePattern(RegExp(r"f..e\.txt"), "contents")]).validate(); |
| }); |
| |
| group("validates a file in", () { |
| test("zip format", () async { |
| File(d.path("test.zip")).writeAsBytesSync(ZipEncoder() |
| .encode(Archive()..addFile(_file("file.txt", "contents")))); |
| |
| await d |
| .archive("test.zip", [d.file("file.txt", "contents")]).validate(); |
| }); |
| |
| group("gzip tar format", () { |
| for (var extension in [".tar.gz", ".tar.gzip", ".tgz"]) { |
| test("with $extension", () async { |
| File(d.path("test$extension")).writeAsBytesSync(GZipEncoder() |
| .encode(TarEncoder().encode( |
| Archive()..addFile(_file("file.txt", "contents"))))); |
| |
| await d.archive( |
| "test$extension", [d.file("file.txt", "contents")]).validate(); |
| }); |
| } |
| }); |
| |
| group("bzip2 tar format", () { |
| for (var extension in [".tar.bz2", ".tar.bzip2"]) { |
| test("with $extension", () async { |
| File(d.path("test$extension")).writeAsBytesSync(BZip2Encoder() |
| .encode(TarEncoder().encode( |
| Archive()..addFile(_file("file.txt", "contents"))))); |
| |
| await d.archive( |
| "test$extension", [d.file("file.txt", "contents")]).validate(); |
| }); |
| } |
| }); |
| }); |
| |
| test("gracefully rejects an unknown file format", () { |
| expect(d.archive("test.asdf").validate(), throwsUnsupportedError); |
| }); |
| }); |
| |
| test("read() is unsupported", () { |
| expect(d.archive("test.tar").read(), throwsUnsupportedError); |
| }); |
| |
| test("readAsBytes() returns the contents of the archive", () async { |
| var descriptor = d.archive("test.tar", |
| [d.file("file1.txt", "contents 1"), d.file("file2.txt", "contents 2")]); |
| |
| var files = TarDecoder() |
| .decodeBytes(await collectBytes(descriptor.readAsBytes())) |
| .files; |
| expect(files.length, equals(2)); |
| _expectFile(files[0], "file1.txt", "contents 1"); |
| _expectFile(files[1], "file2.txt", "contents 2"); |
| }); |
| |
| test("archive returns the in-memory contents", () async { |
| var archive = await d.archive("test.tar", [ |
| d.file("file1.txt", "contents 1"), |
| d.file("file2.txt", "contents 2") |
| ]).archive; |
| |
| var files = archive.files; |
| expect(files.length, equals(2)); |
| _expectFile(files[0], "file1.txt", "contents 1"); |
| _expectFile(files[1], "file2.txt", "contents 2"); |
| }); |
| |
| test("io refers to the file within the sandbox", () { |
| expect(d.file('test.tar').io.path, equals(p.join(d.sandbox, 'test.tar'))); |
| }); |
| } |
| |
| /// Asserts that [file] has the given [name] and [contents]. |
| void _expectFile(ArchiveFile file, String name, String contents) { |
| expect(file.name, equals(name)); |
| expect(utf8.decode(file.content as List<int>), equals(contents)); |
| } |
| |
| /// Creates an [ArchiveFile] with the given [name] and [contents]. |
| ArchiveFile _file(String name, [String contents]) { |
| var bytes = utf8.encode(contents ?? ""); |
| return ArchiveFile(name, bytes.length, bytes) |
| // Setting the mode and mod time are necessary to work around |
| // brendan-duncan/archive#76. |
| ..mode = 428 |
| ..lastModTime = DateTime.now().millisecondsSinceEpoch ~/ 1000; |
| } |