// Flags: --experimental-stream-iter 'use strict'; const common = require('../common'); const assert = require('assert'); const { fromSync, pullSync, bytesSync, textSync, } = require('stream/iter'); const { compressGzipSync, compressDeflateSync, compressBrotliSync, compressZstdSync, decompressGzipSync, decompressDeflateSync, decompressBrotliSync, decompressZstdSync, } = require('zlib/iter'); // ============================================================================= // Helper: sync compress then decompress, verify round-trip equality // ============================================================================= function roundTrip(input, compress, decompress) { return textSync(pullSync(pullSync(fromSync(input), compress), decompress)); } function roundTripBytes(inputBuf, compress, decompress) { return bytesSync(pullSync(pullSync(fromSync(inputBuf), compress), decompress)); } // ============================================================================= // Gzip sync round-trip tests // ============================================================================= function testGzipRoundTrip() { const input = 'Hello, sync gzip compression!'; const result = roundTrip(input, compressGzipSync(), decompressGzipSync()); assert.strictEqual(result, input); } function testGzipLargeData() { const input = 'gzip sync large data test. '.repeat(5000); const result = roundTrip(input, compressGzipSync(), decompressGzipSync()); assert.strictEqual(result, input); } function testGzipActuallyCompresses() { const input = 'Repeated data compresses well. '.repeat(1000); const inputBuf = Buffer.from(input); const compressed = bytesSync(pullSync(fromSync(inputBuf), compressGzipSync())); assert.ok(compressed.byteLength < inputBuf.byteLength, `Compressed ${compressed.byteLength} should be < ` + `original ${inputBuf.byteLength}`); } function testGzipBinaryData() { const inputBuf = Buffer.alloc(10000); for (let i = 0; i < inputBuf.length; i++) inputBuf[i] = i & 0xff; const result = roundTripBytes(inputBuf, compressGzipSync(), decompressGzipSync()); assert.deepStrictEqual(result, inputBuf); } // ============================================================================= // Deflate sync round-trip tests // ============================================================================= function testDeflateRoundTrip() { const input = 'Hello, sync deflate compression!'; const result = roundTrip(input, compressDeflateSync(), decompressDeflateSync()); assert.strictEqual(result, input); } function testDeflateLargeData() { const input = 'deflate sync large data test. '.repeat(5000); const result = roundTrip(input, compressDeflateSync(), decompressDeflateSync()); assert.strictEqual(result, input); } // ============================================================================= // Brotli sync round-trip tests // ============================================================================= function testBrotliRoundTrip() { const input = 'Hello, sync brotli compression!'; const result = roundTrip(input, compressBrotliSync(), decompressBrotliSync()); assert.strictEqual(result, input); } function testBrotliLargeData() { const input = 'brotli sync large data test. '.repeat(5000); const result = roundTrip(input, compressBrotliSync(), decompressBrotliSync()); assert.strictEqual(result, input); } // ============================================================================= // Zstd sync round-trip tests // ============================================================================= function testZstdRoundTrip() { const input = 'Hello, sync zstd compression!'; const result = roundTrip(input, compressZstdSync(), decompressZstdSync()); assert.strictEqual(result, input); } function testZstdLargeData() { const input = 'zstd sync large data test. '.repeat(5000); const result = roundTrip(input, compressZstdSync(), decompressZstdSync()); assert.strictEqual(result, input); } // ============================================================================= // Cross-algorithm: compress async-compatible, decompress sync (and vice versa) // The sync transforms should produce output compatible with the standard format // ============================================================================= function testGzipWithOptions() { const input = 'options test data '.repeat(100); const result = roundTrip(input, compressGzipSync({ level: 1 }), decompressGzipSync()); assert.strictEqual(result, input); } function testBrotliWithOptions() { const zlib = require('zlib'); const input = 'brotli options test data '.repeat(100); const result = roundTrip(input, compressBrotliSync({ params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 3, }, }), decompressBrotliSync()); assert.strictEqual(result, input); } // ============================================================================= // Stateless + stateful sync transform pipeline // ============================================================================= function testMixedStatelessAndStateful() { // Uppercase stateless transform + gzip stateful transform const upper = (chunks) => { if (chunks === null) return null; const out = new Array(chunks.length); for (let j = 0; j < chunks.length; j++) { const src = chunks[j]; const buf = Buffer.allocUnsafe(src.length); for (let i = 0; i < src.length; i++) { const b = src[i]; buf[i] = (b >= 0x61 && b <= 0x7a) ? b - 0x20 : b; } out[j] = buf; } return out; }; const input = 'hello world '.repeat(100); const result = textSync( pullSync( pullSync(fromSync(input), upper, compressGzipSync()), decompressGzipSync(), ), ); assert.strictEqual(result, input.toUpperCase()); } // ============================================================================= // Early consumer exit (break from for-of) triggers cleanup // ============================================================================= function testEarlyExit() { const input = 'y'.repeat(100_000); const compressed = pullSync(fromSync(input), compressGzipSync()); // eslint-disable-next-line no-unused-vars for (const batch of compressed) { break; // Early exit - should trigger finally block cleanup } // If we get here without crashing, cleanup worked } // ============================================================================= // Empty input // ============================================================================= function testEmptyInput() { const result = textSync( pullSync( pullSync(fromSync(''), compressGzipSync()), decompressGzipSync(), ), ); assert.strictEqual(result, ''); } // ============================================================================= // Run all tests // ============================================================================= testGzipRoundTrip(); testGzipLargeData(); testGzipActuallyCompresses(); testGzipBinaryData(); testDeflateRoundTrip(); testDeflateLargeData(); testBrotliRoundTrip(); testBrotliLargeData(); testZstdRoundTrip(); testZstdLargeData(); testGzipWithOptions(); testBrotliWithOptions(); testMixedStatelessAndStateful(); testEarlyExit(); testEmptyInput(); common.mustCall()();