diff --git a/packages/opencode/test/config/markdown.test.ts b/packages/opencode/test/config/markdown.test.ts index 865af21077..02851b456f 100644 --- a/packages/opencode/test/config/markdown.test.ts +++ b/packages/opencode/test/config/markdown.test.ts @@ -211,6 +211,102 @@ Always structure your responses using clear markdown formatting: }) }) +describe("ConfigMarkdown.shell", () => { + test("extracts shell commands from template", () => { + const template = "Run !`git status` and then !`npm test`" + const matches = ConfigMarkdown.shell(template) + expect(matches.length).toBe(2) + expect(matches[0][1]).toBe("git status") + expect(matches[1][1]).toBe("npm test") + }) + + test("does not match regular backticks without bang", () => { + const template = "Use `git status` command" + const matches = ConfigMarkdown.shell(template) + expect(matches.length).toBe(0) + }) + + test("does not match empty bang-backtick", () => { + const template = "Empty !`` should not match" + const matches = ConfigMarkdown.shell(template) + expect(matches.length).toBe(0) + }) + + test("extracts command with pipes and flags", () => { + const template = "Run !`cat file.txt | grep error` to find issues" + const matches = ConfigMarkdown.shell(template) + expect(matches.length).toBe(1) + expect(matches[0][1]).toBe("cat file.txt | grep error") + }) +}) + +describe("ConfigMarkdown.fallbackSanitization", () => { + test("converts value with colon to block scalar", () => { + const input = "---\nurl: https://example.com:8080\n---\nContent" + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain("url: |-") + expect(result).toContain(" https://example.com:8080") + }) + + test("preserves already double-quoted values with colons", () => { + const input = '---\nurl: "https://example.com:8080"\n---\nContent' + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain('"https://example.com:8080"') + expect(result).not.toContain("|-") + }) + + test("preserves already single-quoted values with colons", () => { + const input = "---\nurl: 'https://example.com:8080'\n---\nContent" + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain("'https://example.com:8080'") + expect(result).not.toContain("|-") + }) + + test("passes through content without frontmatter unchanged", () => { + const input = "Just some content" + expect(ConfigMarkdown.fallbackSanitization(input)).toBe(input) + }) + + test("preserves comments in frontmatter", () => { + const input = "---\n# comment\nname: John\n---\nContent" + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain("# comment") + expect(result).toContain("name: John") + }) + + test("preserves indented continuation lines", () => { + const input = "---\nsummary: >\n This is multiline\n content\n---\nBody" + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain(" This is multiline") + expect(result).toContain(" content") + }) + + test("preserves block scalar indicators", () => { + const input = "---\nnotes: |\n line1\n line2\n---\nContent" + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain("notes: |") + }) + + test("handles empty frontmatter values", () => { + const input = "---\nempty:\n---\nContent" + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain("empty:") + }) + + test("does not modify content after frontmatter", () => { + const input = "---\nname: John\n---\nContent with url: http://example.com:3000" + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain("Content with url: http://example.com:3000") + }) + + test("handles CRLF line endings in frontmatter regex", () => { + const input = "---\r\nurl: https://example.com:8080\r\n---\r\nContent" + const result = ConfigMarkdown.fallbackSanitization(input) + expect(result).toContain("url: |-") + expect(result).toContain(" https://example.com:8080") + }) +}) + describe("ConfigMarkdown: frontmatter has weird model id", async () => { const result = await ConfigMarkdown.parse(import.meta.dir + "/fixtures/weird-model-id.md") diff --git a/packages/opencode/test/util/wildcard.test.ts b/packages/opencode/test/util/wildcard.test.ts index 56e753d12a..3c675721bd 100644 --- a/packages/opencode/test/util/wildcard.test.ts +++ b/packages/opencode/test/util/wildcard.test.ts @@ -1,4 +1,4 @@ -import { test, expect } from "bun:test" +import { describe, test, expect } from "bun:test" import { Wildcard } from "../../src/util/wildcard" test("match handles glob tokens", () => { @@ -88,3 +88,64 @@ test("match handles case-insensitivity on Windows", () => { expect(Wildcard.match("/users/test/file", "/Users/test/*")).toBe(false) } }) + +// --- Edge cases found during test-discovery audit --- + +describe("Wildcard.match — star crosses path separators", () => { + test("star matches across directory boundaries unlike shell glob", () => { + // Wildcard.match uses .* which crosses /, unlike shell globs where * stops at / + // This is relied on by the permission system: "src/*" must match "src/deep/nested/file.ts" + expect(Wildcard.match("src/deep/nested/file.ts", "src/*")).toBe(true) + expect(Wildcard.match("src/a/b/c/d.ts", "src/*/d.ts")).toBe(true) + }) +}) + +describe("Wildcard.match — special regex characters", () => { + test("dots in pattern are literal, not regex any-char", () => { + expect(Wildcard.match("file.txt", "file.txt")).toBe(true) + expect(Wildcard.match("filextxt", "file.txt")).toBe(false) + }) + + test("parentheses and pipes in pattern are literal", () => { + expect(Wildcard.match("(a|b)", "(a|b)")).toBe(true) + expect(Wildcard.match("a", "(a|b)")).toBe(false) + }) + + test("brackets in pattern are literal", () => { + expect(Wildcard.match("[abc]", "[abc]")).toBe(true) + expect(Wildcard.match("a", "[abc]")).toBe(false) + }) + + test("dollar and caret in pattern are literal", () => { + expect(Wildcard.match("$HOME", "$HOME")).toBe(true) + expect(Wildcard.match("^start", "^start")).toBe(true) + }) +}) + +describe("Wildcard.match — empty and boundary cases", () => { + test("empty pattern matches only empty string", () => { + expect(Wildcard.match("", "")).toBe(true) + expect(Wildcard.match("something", "")).toBe(false) + }) +}) + +describe("Wildcard.allStructured — non-contiguous tail matching", () => { + test("non-contiguous tail tokens match if in correct order", () => { + // matchSequence scans non-contiguously: finds "push" then skips "extra" and finds "--force" + const result = Wildcard.allStructured( + { head: "git", tail: ["push", "extra", "--force"] }, + { "git push --force": "deny" }, + ) + expect(result).toBe("deny") + }) + + test("reversed tail tokens do not match when items exhausted", () => { + // Pattern expects push then --force; tail has them reversed + // "push" found at i=1, but no items remain after for "--force" + const result = Wildcard.allStructured( + { head: "git", tail: ["--force", "push"] }, + { "git push --force": "deny" }, + ) + expect(result).toBeUndefined() + }) +})