Skip to content

Commit 3ef4b56

Browse files
CodeRabbit Generated Unit Tests: Add unit tests for PR changes
1 parent 478d893 commit 3ef4b56

File tree

1 file changed

+144
-1
lines changed

1 file changed

+144
-1
lines changed

packages/opencode/test/session/processor.test.ts

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,149 @@ describe("plan-agent no-tool-generation detection", () => {
583583
expect(result.event).toBeNull()
584584
}
585585
})
586+
587+
test("event contains all required fields with correct types", () => {
588+
const result = simulateFinishStep({
589+
...baseOpts,
590+
agent: "plan",
591+
finishReason: "stop",
592+
sessionToolCallsMade: 0,
593+
planNoToolWarningEmitted: false,
594+
})
595+
const ev = result.event!
596+
expect(ev.type).toBe("plan_no_tool_generation")
597+
expect(typeof ev.timestamp).toBe("number")
598+
expect(typeof ev.session_id).toBe("string")
599+
expect(typeof ev.message_id).toBe("string")
600+
expect(typeof ev.model_id).toBe("string")
601+
expect(typeof ev.provider_id).toBe("string")
602+
expect(typeof ev.finish_reason).toBe("string")
603+
expect(typeof ev.tokens_output).toBe("number")
604+
})
605+
606+
test("exactly one tool call suppresses the warning (boundary: not only >1)", () => {
607+
const result = simulateFinishStep({
608+
...baseOpts,
609+
agent: "plan",
610+
finishReason: "stop",
611+
sessionToolCallsMade: 1,
612+
planNoToolWarningEmitted: false,
613+
})
614+
expect(result.event).toBeNull()
615+
expect(result.warningEmitted).toBe(false)
616+
})
617+
618+
test("fires with tokens_output=0 (model stopped immediately, produced nothing)", () => {
619+
const result = simulateFinishStep({
620+
...baseOpts,
621+
sessionID: "sess-plan-zero",
622+
messageID: "msg-plan-zero",
623+
agent: "plan",
624+
finishReason: "stop",
625+
sessionToolCallsMade: 0,
626+
planNoToolWarningEmitted: false,
627+
tokensOutput: 0,
628+
})
629+
expect(result.event).not.toBeNull()
630+
expect(result.event?.tokens_output).toBe(0)
631+
})
632+
633+
test("fires with very large tokens_output (model wrote long text plan, still no tools)", () => {
634+
const result = simulateFinishStep({
635+
...baseOpts,
636+
sessionID: "sess-plan-verbose",
637+
messageID: "msg-plan-verbose",
638+
agent: "plan",
639+
finishReason: "stop",
640+
sessionToolCallsMade: 0,
641+
planNoToolWarningEmitted: false,
642+
tokensOutput: 9999,
643+
})
644+
expect(result.event).not.toBeNull()
645+
expect(result.event?.tokens_output).toBe(9999)
646+
})
647+
648+
test("session IDs and model metadata are forwarded correctly to the event", () => {
649+
const result = simulateFinishStep({
650+
agent: "plan",
651+
finishReason: "stop",
652+
sessionToolCallsMade: 0,
653+
planNoToolWarningEmitted: false,
654+
sessionID: "custom-session-abc",
655+
messageID: "custom-message-xyz",
656+
modelID: "gpt-5.4-turbo",
657+
providerID: "openai-proxy",
658+
tokensOutput: 42,
659+
})
660+
expect(result.event?.session_id).toBe("custom-session-abc")
661+
expect(result.event?.message_id).toBe("custom-message-xyz")
662+
expect(result.event?.model_id).toBe("gpt-5.4-turbo")
663+
expect(result.event?.provider_id).toBe("openai-proxy")
664+
expect(result.event?.tokens_output).toBe(42)
665+
})
666+
667+
test("two-step simulation: tool call in step 1 suppresses warning in step 2", () => {
668+
// Simulates a session where step 1 produces a tool call (sessionToolCallsMade goes
669+
// from 0->1) and step 2 ends with finish_reason=stop. The warning should NOT fire
670+
// because the session has already made a tool call.
671+
let sessionToolCallsMade = 0
672+
let planNoToolWarningEmitted = false
673+
674+
// Step 1: a tool call occurs
675+
sessionToolCallsMade++
676+
677+
// Step 2: finish-step fires with stop but no new tool calls
678+
const result = simulateFinishStep({
679+
...baseOpts,
680+
agent: "plan",
681+
finishReason: "stop",
682+
sessionToolCallsMade,
683+
planNoToolWarningEmitted,
684+
})
685+
686+
expect(result.event).toBeNull()
687+
expect(sessionToolCallsMade).toBe(1)
688+
})
689+
690+
test("warning flag transitions from false to true only on first emission", () => {
691+
let planNoToolWarningEmitted = false
692+
693+
// First emission — should fire and flip the flag
694+
const first = simulateFinishStep({
695+
...baseOpts,
696+
agent: "plan",
697+
finishReason: "stop",
698+
sessionToolCallsMade: 0,
699+
planNoToolWarningEmitted,
700+
})
701+
expect(first.event).not.toBeNull()
702+
expect(first.warningEmitted).toBe(true)
703+
704+
// Propagate the new flag state
705+
planNoToolWarningEmitted = first.warningEmitted
706+
707+
// Second call — flag is now true, should be suppressed
708+
const second = simulateFinishStep({
709+
...baseOpts,
710+
agent: "plan",
711+
finishReason: "stop",
712+
sessionToolCallsMade: 0,
713+
planNoToolWarningEmitted,
714+
})
715+
expect(second.event).toBeNull()
716+
expect(second.warningEmitted).toBe(true)
717+
})
718+
719+
test("empty-string agent is not treated as plan agent", () => {
720+
const result = simulateFinishStep({
721+
...baseOpts,
722+
agent: "",
723+
finishReason: "stop",
724+
sessionToolCallsMade: 0,
725+
planNoToolWarningEmitted: false,
726+
})
727+
expect(result.event).toBeNull()
728+
})
586729
})
587730

588731
// ---------------------------------------------------------------------------
@@ -857,4 +1000,4 @@ describe("processor state tracking", () => {
8571000
expect(retryStartTime).toBe(firstRetryStart)
8581001
expect(attempt).toBe(2)
8591002
})
860-
})
1003+
})

0 commit comments

Comments
 (0)