"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Provider_1 = require("@wireio/sdk-core/p2p/Provider");
const P2PProviderEvent = {
    data: "data",
    error: "error",
    close: "close"
};
const MessageLengthPrefixBytes = 4;
const IncomingMessageTooLongError = /Incoming Message too long/;
const PayloadBytes = Uint8Array.from([0x01, 0x02, 0x03]);
const OversizeMessageLength = Provider_1.SimpleEnvelopeP2PProvider.maxReadLength + 1;
const ThrowingErrorHandlerMessage = "throwing test handler";
/**
 * In-memory lower provider used to drive the SimpleEnvelope parser directly.
 */
class MemoryP2PProvider {
    writtenMessages = [];
    destroyedWith;
    ended = false;
    dataHandlers = [];
    errorHandlers = [];
    closeHandlers = [];
    write(encodedMessage, done) {
        this.writtenMessages.push(encodedMessage);
        done?.();
    }
    end(cb) {
        this.ended = true;
        cb?.();
    }
    destroy(err) {
        this.destroyedWith = err;
    }
    on(event, handler) {
        if (event === P2PProviderEvent.data) {
            this.dataHandlers.push(handler);
        }
        else if (event === P2PProviderEvent.error) {
            this.errorHandlers.push(handler);
        }
        else {
            this.closeHandlers.push(handler);
        }
        return this;
    }
    emitData(data) {
        this.dataHandlers.forEach(handler => handler(data));
    }
    emitError(error) {
        this.errorHandlers.forEach(handler => handler(error));
    }
    emitClose() {
        this.closeHandlers.forEach(handler => handler());
    }
}
/**
 * Encodes one SimpleEnvelope frame.
 */
function createFrame(payload) {
    const frame = new Uint8Array(MessageLengthPrefixBytes + payload.byteLength);
    const view = new DataView(frame.buffer);
    view.setUint32(0, payload.byteLength, true);
    frame.set(payload, MessageLengthPrefixBytes);
    return frame;
}
/**
 * Encodes only a SimpleEnvelope length prefix.
 */
function createLengthPrefix(messageLength) {
    const prefix = new Uint8Array(MessageLengthPrefixBytes);
    const view = new DataView(prefix.buffer);
    view.setUint32(0, messageLength, true);
    return prefix;
}
describe("SimpleEnvelopeP2PProvider", () => {
    test("reassembles chunked frames before emitting data", () => {
        const lowerProvider = new MemoryP2PProvider();
        const provider = new Provider_1.SimpleEnvelopeP2PProvider(lowerProvider);
        const messages = [];
        provider.on(P2PProviderEvent.data, message => messages.push(message));
        const frame = createFrame(PayloadBytes);
        lowerProvider.emitData(frame.subarray(0, MessageLengthPrefixBytes + 1));
        lowerProvider.emitData(frame.subarray(MessageLengthPrefixBytes + 1));
        expect(messages.map(message => Array.from(message))).toEqual([
            Array.from(PayloadBytes)
        ]);
        expect(lowerProvider.destroyedWith).toBeUndefined();
    });
    test("destroys the lower provider when a peer declares an oversized frame", () => {
        const lowerProvider = new MemoryP2PProvider();
        const provider = new Provider_1.SimpleEnvelopeP2PProvider(lowerProvider);
        const errors = [];
        const messages = [];
        provider.on(P2PProviderEvent.error, error => errors.push(error));
        provider.on(P2PProviderEvent.data, message => messages.push(message));
        lowerProvider.emitData(createLengthPrefix(OversizeMessageLength));
        expect(errors).toHaveLength(1);
        expect(errors[0]).toEqual(expect.objectContaining({
            message: expect.stringMatching(IncomingMessageTooLongError)
        }));
        expect(lowerProvider.destroyedWith).toBe(errors[0]);
        expect(messages).toEqual([]);
    });
    test("ignores later chunks after closing an oversized frame", () => {
        const lowerProvider = new MemoryP2PProvider();
        const provider = new Provider_1.SimpleEnvelopeP2PProvider(lowerProvider);
        const errors = [];
        const messages = [];
        provider.on(P2PProviderEvent.error, error => errors.push(error));
        provider.on(P2PProviderEvent.data, message => messages.push(message));
        lowerProvider.emitData(createLengthPrefix(OversizeMessageLength));
        lowerProvider.emitData(createFrame(PayloadBytes));
        lowerProvider.emitError(new Error("late lower-provider error"));
        expect(errors).toHaveLength(1);
        expect(messages).toEqual([]);
        expect(lowerProvider.destroyedWith).toBe(errors[0]);
    });
    test("destroys the lower provider when the oversize error handler throws", () => {
        const lowerProvider = new MemoryP2PProvider();
        const provider = new Provider_1.SimpleEnvelopeP2PProvider(lowerProvider);
        let emittedError;
        provider.on(P2PProviderEvent.error, error => {
            emittedError = error;
            throw new Error(ThrowingErrorHandlerMessage);
        });
        expect(() => lowerProvider.emitData(createLengthPrefix(OversizeMessageLength))).toThrow(ThrowingErrorHandlerMessage);
        expect(emittedError).toEqual(expect.objectContaining({
            message: expect.stringMatching(IncomingMessageTooLongError)
        }));
        expect(lowerProvider.destroyedWith).toBe(emittedError);
    });
});
//# sourceMappingURL=Provider.test.js.map