fix(tmux): strict integer parsing and isActive validation in pane-state-parser

- parseInteger() now rejects malformed input like '120oops' using /^\d+$/ regex
- New parseActiveValue() validates active flag is exactly '0' or '1'
- Added regression tests for malformed integers, negative values, empty fields, non-binary active flags
This commit is contained in:
YeonGyu-Kim
2026-03-11 21:45:30 +09:00
parent d4232c9eac
commit 599ce0c283
2 changed files with 83 additions and 1 deletions

View File

@@ -0,0 +1,72 @@
/// <reference path="../../../bun-test.d.ts" />
import { describe, expect, it } from "bun:test"
import { parsePaneStateOutput } from "./pane-state-parser"
describe("parsePaneStateOutput", () => {
it("rejects malformed integer fields", () => {
// given
const stdout = "%0\t120oops\t40\t0\t0\t1\t120\t40\n"
// when
const result = parsePaneStateOutput(stdout)
// then
expect(result).toBe(null)
})
it("rejects negative integer fields", () => {
// given
const stdout = "%0\t-1\t40\t0\t0\t1\t120\t40\n"
// when
const result = parsePaneStateOutput(stdout)
// then
expect(result).toBe(null)
})
it("rejects empty integer fields", () => {
// given
const stdout = "%0\t\t40\t0\t0\t1\t120\t40\n"
// when
const result = parsePaneStateOutput(stdout)
// then
expect(result).toBe(null)
})
it("rejects non-binary active flags", () => {
// given
const stdout = "%0\t120\t40\t0\t0\tx\t120\t40\n"
// when
const result = parsePaneStateOutput(stdout)
// then
expect(result).toBe(null)
})
it("rejects numeric active flags other than zero or one", () => {
// given
const stdout = "%0\t120\t40\t0\t0\t2\t120\t40\n"
// when
const result = parsePaneStateOutput(stdout)
// then
expect(result).toBe(null)
})
it("rejects empty active flags", () => {
// given
const stdout = "%0\t120\t40\t0\t0\t\t120\t40\n"
// when
const result = parsePaneStateOutput(stdout)
// then
expect(result).toBe(null)
})
})

View File

@@ -60,6 +60,7 @@ function parsePaneLine(line: string): ParsedPaneLine | null {
const height = parseInteger(heightString)
const left = parseInteger(leftString)
const top = parseInteger(topString)
const isActive = parseActiveValue(activeString)
const windowWidth = parseInteger(windowWidthString)
const windowHeight = parseInteger(windowHeightString)
@@ -68,6 +69,7 @@ function parsePaneLine(line: string): ParsedPaneLine | null {
height === null ||
left === null ||
top === null ||
isActive === null ||
windowWidth === null ||
windowHeight === null
) {
@@ -82,7 +84,7 @@ function parsePaneLine(line: string): ParsedPaneLine | null {
left,
top,
title: fields.slice(MANDATORY_PANE_FIELD_COUNT).join("\t"),
isActive: activeString === "1",
isActive,
},
windowWidth,
windowHeight,
@@ -120,6 +122,14 @@ function getMandatoryPaneFields(fields: string[]): MandatoryPaneFields | null {
}
function parseInteger(value: string): number | null {
if (!/^\d+$/.test(value)) return null
const parsedValue = Number.parseInt(value, 10)
return Number.isNaN(parsedValue) ? null : parsedValue
}
function parseActiveValue(value: string): boolean | null {
if (value === "1") return true
if (value === "0") return false
return null
}