var test = require('tap').test; var tar = require('../index'); var fixtures = require('./fixtures'); var concat = require('concat-stream'); var fs = require('fs'); var clamp = function(index, len, defaultValue) { if (typeof index !== 'number') return defaultValue; index = ~~index; // Coerce to integer. if (index >= len) return len; if (index >= 0) return index; index += len; if (index >= 0) return index; return 0; }; test('one-file', function(t) { t.plan(3); var extract = tar.extract(); var noEntries = false; extract.on('entry', function(header, stream, callback) { t.deepEqual(header, { name: 'test.txt', mode: 0644, uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.pipe(concat(function(data) { noEntries = true; t.same(data.toString(), 'hello world\n'); callback(); })); }); extract.on('finish', function() { t.ok(noEntries); }); extract.end(fs.readFileSync(fixtures.ONE_FILE_TAR)); }); test('chunked-one-file', function(t) { t.plan(3); var extract = tar.extract(); var noEntries = false; extract.on('entry', function(header, stream, callback) { t.deepEqual(header, { name: 'test.txt', mode: 0644, uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.pipe(concat(function(data) { noEntries = true; t.same(data.toString(), 'hello world\n'); callback(); })); }); extract.on('finish', function() { t.ok(noEntries); }); var b = fs.readFileSync(fixtures.ONE_FILE_TAR); for (var i = 0; i < b.length; i += 321) { extract.write(b.slice(i, clamp(i+321, b.length, b.length))); } extract.end(); }); test('multi-file', function(t) { t.plan(5); var extract = tar.extract(); var noEntries = false; var onfile1 = function(header, stream, callback) { t.deepEqual(header, { name: 'file-1.txt', mode: 0644, uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); extract.on('entry', onfile2); stream.pipe(concat(function(data) { t.same(data.toString(), 'i am file-1\n'); callback(); })); }; var onfile2 = function(header, stream, callback) { t.deepEqual(header, { name: 'file-2.txt', mode: 0644, uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.pipe(concat(function(data) { noEntries = true; t.same(data.toString(), 'i am file-2\n'); callback(); })); }; extract.once('entry', onfile1); extract.on('finish', function() { t.ok(noEntries); }); extract.end(fs.readFileSync(fixtures.MULTI_FILE_TAR)); }); test('chunked-multi-file', function(t) { t.plan(5); var extract = tar.extract(); var noEntries = false; var onfile1 = function(header, stream, callback) { t.deepEqual(header, { name: 'file-1.txt', mode: 0644, uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); extract.on('entry', onfile2); stream.pipe(concat(function(data) { t.same(data.toString(), 'i am file-1\n'); callback(); })); }; var onfile2 = function(header, stream, callback) { t.deepEqual(header, { name: 'file-2.txt', mode: 0644, uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.pipe(concat(function(data) { noEntries = true; t.same(data.toString(), 'i am file-2\n'); callback(); })); }; extract.once('entry', onfile1); extract.on('finish', function() { t.ok(noEntries); }); var b = fs.readFileSync(fixtures.MULTI_FILE_TAR); for (var i = 0; i < b.length; i += 321) { extract.write(b.slice(i, clamp(i+321, b.length, b.length))); } extract.end(); }); test('types', function(t) { t.plan(3); var extract = tar.extract(); var noEntries = false; var ondir = function(header, stream, callback) { t.deepEqual(header, { name: 'directory', mode: 0755, uid: 501, gid: 20, size: 0, mtime: new Date(1387580181000), type: 'directory', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.on('data', function() { t.ok(false); }); extract.once('entry', onlink); callback(); }; var onlink = function(header, stream, callback) { t.deepEqual(header, { name: 'directory-link', mode: 0755, uid: 501, gid: 20, size: 0, mtime: new Date(1387580181000), type: 'symlink', linkname: 'directory', uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.on('data', function() { t.ok(false); }); noEntries = true; callback(); }; extract.once('entry', ondir); extract.on('finish', function() { t.ok(noEntries); }); extract.end(fs.readFileSync(fixtures.TYPES_TAR)); }); test('long-name', function(t) { t.plan(3); var extract = tar.extract(); var noEntries = false; extract.on('entry', function(header, stream, callback) { t.deepEqual(header, { name: 'my/file/is/longer/than/100/characters/and/should/use/the/prefix/header/foobarbaz/foobarbaz/foobarbaz/foobarbaz/foobarbaz/foobarbaz/filename.txt', mode: 0644, uid: 501, gid: 20, size: 16, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.pipe(concat(function(data) { noEntries = true; t.same(data.toString(), 'hello long name\n'); callback(); })); }); extract.on('finish', function() { t.ok(noEntries); }); extract.end(fs.readFileSync(fixtures.LONG_NAME_TAR)); }); test('unicode-bsd', function(t) { // can unpack a bsdtar unicoded tarball t.plan(3); var extract = tar.extract(); var noEntries = false; extract.on('entry', function(header, stream, callback) { t.deepEqual(header, { name: 'høllø.txt', mode: 0644, uid: 501, gid: 20, size: 4, mtime: new Date(1387588646000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.pipe(concat(function(data) { noEntries = true; t.same(data.toString(), 'hej\n'); callback(); })); }); extract.on('finish', function() { t.ok(noEntries); }); extract.end(fs.readFileSync(fixtures.UNICODE_BSD_TAR)); }); test('unicode', function(t) { // can unpack a bsdtar unicoded tarball t.plan(3); var extract = tar.extract(); var noEntries = false; extract.on('entry', function(header, stream, callback) { t.deepEqual(header, { name: 'høstål.txt', mode: 0644, uid: 501, gid: 20, size: 8, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }); stream.pipe(concat(function(data) { noEntries = true; t.same(data.toString(), 'høllø\n'); callback(); })); }); extract.on('finish', function() { t.ok(noEntries); }); extract.end(fs.readFileSync(fixtures.UNICODE_TAR)); }); test('name-is-100', function(t) { t.plan(3); var extract = tar.extract(); extract.on('entry', function(header, stream, callback) { t.same(header.name.length, 100); stream.pipe(concat(function(data) { t.same(data.toString(), 'hello\n'); callback(); })); }); extract.on('finish', function() { t.ok(true); }); extract.end(fs.readFileSync(fixtures.NAME_IS_100_TAR)); }); test('invalid-file', function(t) { t.plan(1); var extract = tar.extract(); extract.on('error', function(err) { t.ok(!!err); extract.destroy(); }); extract.end(fs.readFileSync(fixtures.INVALID_TGZ)); });