From b215efdda004487cb1a4b4dba44c033ca6f9c5fc Mon Sep 17 00:00:00 2001 From: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> Date: Wed, 12 Aug 2026 22:02:10 +0300 Subject: [PATCH] Add comprehensive tests for parseResultQuery. (#92) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- src/ui/search.test.ts | 99 +++++++++++++++++++++++++++++++++++++++++++ src/ui/search.ts | 2 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/ui/search.test.ts diff --git a/src/ui/search.test.ts b/src/ui/search.test.ts new file mode 100644 index 0000000..f1cae41 --- /dev/null +++ b/src/ui/search.test.ts @@ -0,0 +1,99 @@ +import { describe, it, expect } from "vitest"; +import { SumEngine } from "../engine"; +import { parseResultQuery } from "./search"; +import Decimal from "decimal.js"; + +describe("parseResultQuery", () => { + const engine = new SumEngine(); + + it("parses '>=' operator correctly", () => { + const res = parseResultQuery(engine, ">= 100"); + expect(res).not.toBeNull(); + expect(res?.op).toBe(">="); + expect(res?.threshold.kind).toBe("quantity"); + if (res?.threshold.kind === "quantity") { + expect(res.threshold.value.eq(new Decimal(100))).toBe(true); + } + }); + + it("parses '<=' operator correctly", () => { + const res = parseResultQuery(engine, "<= 50"); + expect(res).not.toBeNull(); + expect(res?.op).toBe("<="); + expect(res?.threshold.kind).toBe("quantity"); + if (res?.threshold.kind === "quantity") { + expect(res.threshold.value.eq(new Decimal(50))).toBe(true); + } + }); + + it("parses '>' operator correctly", () => { + const res = parseResultQuery(engine, "> 0"); + expect(res).not.toBeNull(); + expect(res?.op).toBe(">"); + expect(res?.threshold.kind).toBe("quantity"); + if (res?.threshold.kind === "quantity") { + expect(res.threshold.value.eq(new Decimal(0))).toBe(true); + } + }); + + it("parses '<' operator correctly", () => { + const res = parseResultQuery(engine, "< -10"); + expect(res).not.toBeNull(); + expect(res?.op).toBe("<"); + expect(res?.threshold.kind).toBe("quantity"); + if (res?.threshold.kind === "quantity") { + expect(res.threshold.value.eq(new Decimal(-10))).toBe(true); + } + }); + + it("parses '=' operator correctly", () => { + const res = parseResultQuery(engine, "= 42.5"); + expect(res).not.toBeNull(); + expect(res?.op).toBe("="); + expect(res?.threshold.kind).toBe("quantity"); + if (res?.threshold.kind === "quantity") { + expect(res.threshold.value.eq(new Decimal(42.5))).toBe(true); + } + }); + + it("parses '~' operator correctly", () => { + const res = parseResultQuery(engine, "~ 3.14"); + expect(res).not.toBeNull(); + expect(res?.op).toBe("~"); + expect(res?.threshold.kind).toBe("quantity"); + if (res?.threshold.kind === "quantity") { + expect(res.threshold.value.eq(new Decimal(3.14))).toBe(true); + } + }); + + it("handles whitespace correctly", () => { + const res = parseResultQuery(engine, " >= 200 "); + expect(res).not.toBeNull(); + expect(res?.op).toBe(">="); + expect(res?.threshold.kind).toBe("quantity"); + if (res?.threshold.kind === "quantity") { + expect(res.threshold.value.eq(new Decimal(200))).toBe(true); + } + }); + + it("returns null for invalid operator", () => { + const res = parseResultQuery(engine, "!= 100"); + expect(res).toBeNull(); + }); + + it("returns null for invalid value string", () => { + // "abc" cannot be evaluated to a quantity + const res = parseResultQuery(engine, ">= abc"); + expect(res).toBeNull(); + }); + + it("returns null for empty string", () => { + const res = parseResultQuery(engine, ""); + expect(res).toBeNull(); + }); + + it("returns null when no expression matches after operator", () => { + const res = parseResultQuery(engine, ">="); + expect(res).toBeNull(); + }); +}); diff --git a/src/ui/search.ts b/src/ui/search.ts index 7b332a0..97f3671 100644 --- a/src/ui/search.ts +++ b/src/ui/search.ts @@ -32,7 +32,7 @@ export interface SearchController { const $ = (sel: string): T => document.querySelector(sel) as T; -function parseResultQuery(engine: SumEngine, q: string): { op: string; threshold: Value } | null { +export function parseResultQuery(engine: SumEngine, q: string): { op: string; threshold: Value } | null { const m = /^(>=|<=|>|<|=|~)\s*(.+)$/.exec(q.trim()); if (!m) return null; const v = engine.evaluateExpression(m[2].trim());