const createCGIParser = require("../../src/utils/cgiParser.js"); jest.mock("http"); // Mocking HTTP to simulate the response behavior describe("createCGIParser", () => { let req, res, handler, defaultHeaders, software, dataHandler; beforeEach(() => { req = {}; res = { writeHead: jest.fn(), write: jest.fn(), finished: false, error: jest.fn() }; handler = { stdout: { removeAllListeners: jest.fn(), pipe: jest.fn(), on: jest.fn() }, removeAllListeners: jest.fn() }; defaultHeaders = { "X-Test-Header": "TestValue" }; software = "TestSoftware"; }); test("should parse headers and write response correctly", () => { const inputHeaders = "Status: 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\nHello, world!"; const buffer = Buffer.from(inputHeaders, "latin1"); dataHandler = createCGIParser(req, res, handler, defaultHeaders, software); dataHandler(buffer); expect(res.writeHead).toHaveBeenCalledWith(200, "OK", { "Content-Type": "text/plain", "Content-Length": "13", "X-Test-Header": "TestValue" }); expect(res.write).toHaveBeenCalledWith( Buffer.from("Hello, world!", "latin1") ); }); test("should handle status headers without protocol", () => { const inputHeaders = "Status: 200 OK\r\nContent-Type: text/html\r\n\r\nSuccess"; const buffer = Buffer.from(inputHeaders, "latin1"); dataHandler = createCGIParser(req, res, handler, defaultHeaders, software); dataHandler(buffer); expect(res.writeHead).toHaveBeenCalledWith(200, "OK", { "Content-Type": "text/html", "X-Test-Header": "TestValue" }); expect(res.write).toHaveBeenCalledWith( Buffer.from("Success", "latin1") ); }); test("should handle malformed status line", () => { const inputHeaders = "Content-Type: text/plain\r\n\r\nMalformed status line."; const buffer = Buffer.from(inputHeaders, "latin1"); dataHandler = createCGIParser(req, res, handler, defaultHeaders, software); dataHandler(buffer); expect(res.writeHead).toHaveBeenCalledWith(200, "OK", { "Content-Type": "text/plain", "X-Test-Header": "TestValue" }); expect(res.write).toHaveBeenCalledWith( Buffer.from("Malformed status line.", "latin1") ); }); test("should handle redirection logic for Location header", () => { const inputHeaders = "Status: 302 Found\r\nLocation: /new-location\r\n\r\n"; const buffer = Buffer.from(inputHeaders, "latin1"); dataHandler = createCGIParser(req, res, handler, defaultHeaders, software); dataHandler(buffer); expect(res.writeHead).toHaveBeenCalledWith(302, "Found", { Location: "/new-location", "X-Test-Header": "TestValue" }); expect(res.write).toHaveBeenCalledWith(Buffer.from("", "latin1")); }); test("should handle Set-Cookie headers correctly", () => { const inputHeaders = "Status: 200 OK\r\nSet-Cookie: sessionId=abc123; HttpOnly\r\nSet-Cookie: theme=dark; Secure\r\n\r\nBody content"; const buffer = Buffer.from(inputHeaders, "latin1"); dataHandler = createCGIParser(req, res, handler, defaultHeaders, software); dataHandler(buffer); expect(res.writeHead).toHaveBeenCalledWith(200, "OK", { "Set-Cookie": ["sessionId=abc123; HttpOnly", "theme=dark; Secure"], "X-Test-Header": "TestValue" }); expect(res.write).toHaveBeenCalledWith( Buffer.from("Body content", "latin1") ); }); test("should call res.error on failure to writeHead or write", () => { res.writeHead.mockImplementation(() => { throw new Error("writeHead error"); }); const inputHeaders = "Status: 500 Internal Server Error\r\n\r\nError occurred."; const buffer = Buffer.from(inputHeaders, "latin1"); dataHandler = createCGIParser(req, res, handler, defaultHeaders, software); dataHandler(buffer); expect(res.error).toHaveBeenCalledWith( 500, "TestSoftware", expect.any(Error) ); expect(handler.removeAllListeners).toHaveBeenCalled(); expect(handler.stdout.removeAllListeners).toHaveBeenCalled(); }); });