blob: a413fb96dec409c828abe9153bd2b746ff4c270e [file] [log] [blame]
// 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;
}