import { expect } from "chai";
import { stub } from "sinon";
import { Readable, Writable } from "stream";
import { RpcRequestStatus } from "@itwin/core-common";
import { sendResponse } from "../../rpc/web/response";
import { brotliDecompressSync, unzipSync } from "node:zlib";
/* eslint-disable @typescript-eslint/no-deprecated */
class StubResponse extends Writable {
    chunks = [];
    get buffer() { return Buffer.concat(this.chunks); }
    // eslint-disable-next-line @typescript-eslint/naming-convention
    _write(chunk, _encoding, callback) {
        this.chunks.push(chunk);
        callback();
    }
    send = stub().returns(this);
    status = stub();
    set = stub();
}
describe("sendResponse", () => {
    let protocol;
    let request;
    let fulfillment;
    let req;
    let res;
    beforeEach(() => {
        protocol = { getStatus: () => RpcRequestStatus.Resolved };
        request = { operation: { operationName: "fake-RPC-operation" } };
        fulfillment = {
            allowCompression: true,
            status: 200,
            result: {
                data: [],
            },
        };
        req = { header: () => "gzip, deflate, br" };
        res = new StubResponse();
    });
    it("should compress response using Brotli", async () => {
        // Arrange
        const originalData = generateJson();
        const originalDataSize = Buffer.byteLength(originalData);
        fulfillment.result.objects = originalData;
        // Act
        await sendResponse(protocol, request, fulfillment, req, res);
        // Assert
        expect(res.set.calledWithExactly("Content-Encoding", "br")).to.be.true;
        const compressedData = res.send.getCall(0).args[0];
        expect(compressedData).to.not.be.undefined;
        expect(compressedData.length).to.be.lessThan(originalDataSize);
        expect(brotliDecompressSync(compressedData).toString()).to.be.equal(originalData);
    });
    it("should compress response using Gzip if Brotli is not supported", async () => {
        // Arrange
        const originalData = generateJson();
        const originalDataSize = Buffer.byteLength(originalData);
        fulfillment.result.objects = originalData;
        req.header = () => "gzip, deflate";
        // Act
        await sendResponse(protocol, request, fulfillment, req, res);
        // Assert
        expect(res.set.calledWithExactly("Content-Encoding", "gzip")).to.be.true;
        const compressedData = res.send.getCall(0).args[0];
        expect(compressedData).to.not.be.undefined;
        expect(compressedData.length).to.be.lessThan(originalDataSize);
        expect(unzipSync(compressedData).toString()).to.be.equal(originalData);
    });
    it("should not compress if Brotli and Gzip is not supported", async () => {
        // Arrange
        const originalData = generateJson();
        fulfillment.result.objects = originalData;
        req.header = () => undefined;
        // Act
        await sendResponse(protocol, request, fulfillment, req, res);
        // Assert
        expect(res.set.calledWithMatch("Content-Encoding")).to.be.false;
        expect(res.send.getCall(0).args[0]).to.be.equal(originalData);
    });
    it("should compress stream", async () => {
        // Arrange
        const originalData = generateJson();
        const originalDataSize = Buffer.byteLength(originalData);
        fulfillment.result.stream = Readable.from(originalData);
        // Act
        await sendResponse(protocol, request, fulfillment, req, res);
        await new Promise((resolve) => res.on("finish", resolve));
        // Assert
        const compressedData = res.buffer;
        expect(compressedData).to.not.be.undefined;
        expect(compressedData.length).to.be.lessThan(originalDataSize);
        expect(brotliDecompressSync(compressedData).toString()).to.be.equal(originalData);
    });
    it("should support Accept-Encoding header value format without spaces between values", async () => {
        // Arrange
        fulfillment.result.objects = generateJson();
        req.header = () => "gzip,deflate,br,zstd";
        // Act
        await sendResponse(protocol, request, fulfillment, req, res);
        // Assert
        expect(res.set.calledWithExactly("Content-Encoding", "br")).to.be.true;
    });
});
function generateJson(minimumSize = 2000) {
    let propertyIdx = 0;
    const obj = {};
    while (JSON.stringify(obj).length < minimumSize) {
        obj[`property-${propertyIdx}`] = `value-${propertyIdx}`;
        propertyIdx++;
    }
    return JSON.stringify(obj);
}
//# sourceMappingURL=response.test.js.map