| // Copyright Joyent, Inc. and other Node contributors. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a |
| // copy of this software and associated documentation files (the |
| // "Software"), to deal in the Software without restriction, including |
| // without limitation the rights to use, copy, modify, merge, publish, |
| // distribute, sublicense, and/or sell copies of the Software, and to permit |
| // persons to whom the Software is furnished to do so, subject to the |
| // following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included |
| // in all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| // USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| var common = require('../common.js'); |
| var assert = require('assert'); |
| var zlib = require('zlib'); |
| var path = require('path'); |
| |
| var zlibPairs = |
| [[zlib.Deflate, zlib.Inflate], |
| [zlib.Gzip, zlib.Gunzip], |
| [zlib.Deflate, zlib.Unzip], |
| [zlib.Gzip, zlib.Unzip], |
| [zlib.DeflateRaw, zlib.InflateRaw]]; |
| |
| // how fast to trickle through the slowstream |
| var trickle = [128, 1024, 1024 * 1024]; |
| |
| // tunable options for zlib classes. |
| |
| // several different chunk sizes |
| var chunkSize = [128, 1024, 1024 * 16, 1024 * 1024]; |
| |
| // this is every possible value. |
| var level = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; |
| var windowBits = [8, 9, 10, 11, 12, 13, 14, 15]; |
| var memLevel = [1, 2, 3, 4, 5, 6, 7, 8, 9]; |
| var strategy = [0, 1, 2, 3, 4]; |
| |
| // it's nice in theory to test every combination, but it |
| // takes WAY too long. Maybe a pummel test could do this? |
| if (!process.env.PUMMEL) { |
| trickle = [1024]; |
| chunkSize = [1024 * 16]; |
| level = [6]; |
| memLevel = [8]; |
| windowBits = [15]; |
| strategy = [0]; |
| } |
| |
| var fs = require('fs'); |
| |
| var testFiles = ['person.jpg', 'elipses.txt', 'empty.txt']; |
| |
| if (process.env.FAST) { |
| zlibPairs = [[zlib.Gzip, zlib.Unzip]]; |
| var testFiles = ['person.jpg']; |
| } |
| |
| var tests = {}; |
| testFiles.forEach(function(file) { |
| tests[file] = fs.readFileSync(path.resolve(common.fixturesDir, file)); |
| }); |
| |
| var util = require('util'); |
| var stream = require('stream'); |
| |
| |
| // stream that saves everything |
| function BufferStream() { |
| this.chunks = []; |
| this.length = 0; |
| this.writable = true; |
| this.readable = true; |
| } |
| |
| util.inherits(BufferStream, stream.Stream); |
| |
| BufferStream.prototype.write = function(c) { |
| this.chunks.push(c); |
| this.length += c.length; |
| return true; |
| }; |
| |
| BufferStream.prototype.end = function(c) { |
| if (c) this.write(c); |
| // flatten |
| var buf = new Buffer(this.length); |
| var i = 0; |
| this.chunks.forEach(function(c) { |
| c.copy(buf, i); |
| i += c.length; |
| }); |
| this.emit('data', buf); |
| this.emit('end'); |
| return true; |
| }; |
| |
| |
| function SlowStream(trickle) { |
| this.trickle = trickle; |
| this.offset = 0; |
| this.readable = this.writable = true; |
| } |
| |
| util.inherits(SlowStream, stream.Stream); |
| |
| SlowStream.prototype.write = function() { |
| throw new Error('not implemented, just call ss.end(chunk)'); |
| }; |
| |
| SlowStream.prototype.pause = function() { |
| this.paused = true; |
| this.emit('pause'); |
| }; |
| |
| SlowStream.prototype.resume = function() { |
| var self = this; |
| if (self.ended) return; |
| self.emit('resume'); |
| if (!self.chunk) return; |
| self.paused = false; |
| emit(); |
| function emit() { |
| if (self.paused) return; |
| if (self.offset >= self.length) { |
| self.ended = true; |
| return self.emit('end'); |
| } |
| var end = Math.min(self.offset + self.trickle, self.length); |
| var c = self.chunk.slice(self.offset, end); |
| self.offset += c.length; |
| self.emit('data', c); |
| process.nextTick(emit); |
| } |
| }; |
| |
| SlowStream.prototype.end = function(chunk) { |
| // walk over the chunk in blocks. |
| var self = this; |
| self.chunk = chunk; |
| self.length = chunk.length; |
| self.resume(); |
| return self.ended; |
| }; |
| |
| |
| |
| // for each of the files, make sure that compressing and |
| // decompressing results in the same data, for every combination |
| // of the options set above. |
| var failures = 0; |
| var total = 0; |
| var done = 0; |
| |
| Object.keys(tests).forEach(function(file) { |
| var test = tests[file]; |
| chunkSize.forEach(function(chunkSize) { |
| trickle.forEach(function(trickle) { |
| windowBits.forEach(function(windowBits) { |
| level.forEach(function(level) { |
| memLevel.forEach(function(memLevel) { |
| strategy.forEach(function(strategy) { |
| zlibPairs.forEach(function(pair) { |
| var Def = pair[0]; |
| var Inf = pair[1]; |
| var opts = { level: level, |
| windowBits: windowBits, |
| memLevel: memLevel, |
| strategy: strategy }; |
| |
| total++; |
| |
| var def = new Def(opts); |
| var inf = new Inf(opts); |
| var ss = new SlowStream(trickle); |
| var buf = new BufferStream(); |
| |
| // verify that the same exact buffer comes out the other end. |
| buf.on('data', function(c) { |
| var msg = file + ' ' + |
| chunkSize + ' ' + |
| JSON.stringify(opts) + ' ' + |
| Def.name + ' -> ' + Inf.name; |
| var ok = true; |
| var testNum = ++done; |
| for (var i = 0; i < Math.max(c.length, test.length); i++) { |
| if (c[i] !== test[i]) { |
| ok = false; |
| failures++; |
| break; |
| } |
| } |
| if (ok) { |
| console.log('ok ' + (testNum) + ' ' + msg); |
| } else { |
| console.log('not ok ' + (testNum) + ' ' + msg); |
| console.log(' ...'); |
| console.log(' testfile: ' + file); |
| console.log(' type: ' + Def.name + ' -> ' + Inf.name); |
| console.log(' position: ' + i); |
| console.log(' options: ' + JSON.stringify(opts)); |
| console.log(' expect: ' + test[i]); |
| console.log(' actual: ' + c[i]); |
| console.log(' chunkSize: ' + chunkSize); |
| console.log(' ---'); |
| } |
| }); |
| |
| // the magic happens here. |
| ss.pipe(def).pipe(inf).pipe(buf); |
| ss.end(test); |
| }); |
| }); }); }); }); }); }); // sad stallman is sad. |
| }); |
| |
| process.on('exit', function(code) { |
| console.log('1..' + done); |
| assert.equal(done, total, (total - done) + ' tests left unfinished'); |
| assert.ok(!failures, 'some test failures'); |
| }); |