blob: 751afdcf776890438164ed23d68e0b20bd4a7341 [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;
}