package thinking import ( "testing" ) func TestExtractThinking(t *testing.T) { tests := []struct { in, wantContent, wantThink string }{ { in: " internal world", wantThink: "internal ", wantContent: "world", }, { in: "abc", wantThink: "a", wantContent: "bc", }, { in: "no think", wantThink: "", wantContent: "no think", }, } for i, tt := range tests { parser := Parser{ OpeningTag: "", ClosingTag: "", } gotThinking, gotContent := parser.AddContent(tt.in) if gotContent != tt.wantContent || gotThinking != tt.wantThink { t.Errorf("case %d: got (%q,%q), want (%q,%q)", i, gotThinking, gotContent, tt.wantThink, tt.wantContent) } } } func TestThinkingStreaming(t *testing.T) { type step struct { input string wantThinking string wantContent string wantStateAfter thinkingState } cases := []struct { desc string skip bool steps []step }{ { desc: "content without a thinking tag", steps: []step{ { input: " abc", wantThinking: "", wantContent: " abc", wantStateAfter: thinkingState_ThinkingDone, }, }, }, { desc: "content before a thinking tag nerfs the thinking tag", steps: []step{ { input: " abc def ghi", wantThinking: "", wantContent: " abc def ghi", wantStateAfter: thinkingState_ThinkingDone, }, }, }, { desc: "building up a thinking tag partially", steps: []step{ { input: " a", wantThinking: "a", wantContent: "", wantStateAfter: thinkingState_Thinking, }, }, }, { desc: "partial closing tag", steps: []step{ { input: "abcdef", wantThinking: "", wantContent: "def", wantStateAfter: thinkingState_ThinkingDone, }, }, }, { desc: "partial closing tag fakeout", steps: []step{ { input: "abcdef", wantThinking: "def", wantContent: "", wantStateAfter: thinkingState_Thinking, }, { input: "ghijkl", wantThinking: "", wantContent: "jkl", wantStateAfter: thinkingState_ThinkingDone, }, }, }, { desc: "whitespace after thinking tag", steps: []step{ { input: " abc\n\ndef", wantThinking: "abc", wantContent: "def", wantStateAfter: thinkingState_ThinkingDone, }, }, }, { desc: "whitespace after thinking tag (incremental)", steps: []step{ { input: " abc", wantThinking: "abc", wantContent: "", wantStateAfter: thinkingState_ThinkingDoneEatingWhitespace, }, { input: "\n\ndef", wantThinking: "", wantContent: "def", wantStateAfter: thinkingState_ThinkingDone, }, }, }, { desc: "whitespace after thinking tag with content and more whitespace", steps: []step{ { input: " abc\n\ndef ", wantThinking: "abc", wantContent: "def ", wantStateAfter: thinkingState_ThinkingDone, }, { input: " ghi", wantThinking: "", wantContent: " ghi", wantStateAfter: thinkingState_ThinkingDone, }, }, }, { desc: "token by token", steps: []step{ { input: "", wantThinking: "", wantContent: "", wantStateAfter: thinkingState_ThinkingStartedEatingWhitespace, }, { input: "\n", wantThinking: "", wantContent: "", wantStateAfter: thinkingState_ThinkingStartedEatingWhitespace, }, { input: "", wantThinking: "", wantContent: "", wantStateAfter: thinkingState_ThinkingDoneEatingWhitespace, }, { input: "\n\n", wantThinking: "", wantContent: "", wantStateAfter: thinkingState_ThinkingDoneEatingWhitespace, }, { input: "Hi", wantThinking: "", wantContent: "Hi", wantStateAfter: thinkingState_ThinkingDone, }, { input: " there", wantThinking: "", wantContent: " there", wantStateAfter: thinkingState_ThinkingDone, }, }, }, { desc: "leading thinking whitespace", steps: []step{ { input: " \t ", wantThinking: "", wantContent: "", wantStateAfter: thinkingState_ThinkingStartedEatingWhitespace, }, { input: " these are some ", wantThinking: "these are some ", wantContent: "", wantStateAfter: thinkingState_Thinking, }, { input: "thoughts ", wantThinking: "thoughts ", wantContent: "", wantStateAfter: thinkingState_ThinkingDoneEatingWhitespace, }, { input: " more content", wantThinking: "", wantContent: "more content", wantStateAfter: thinkingState_ThinkingDone, }, }, }, } for _, c := range cases { parser := Parser{ OpeningTag: "", ClosingTag: "", } if c.skip { continue } for i, step := range c.steps { thinking, content := parser.AddContent(step.input) if content != step.wantContent || thinking != step.wantThinking { t.Errorf("case %q (step %d): got (%q,%q), want (%q,%q)", c.desc, i, content, thinking, step.wantContent, step.wantThinking) } if parser.state != step.wantStateAfter { t.Errorf("case %q (step %d): got state %s, want %s", c.desc, i, parser.state, step.wantStateAfter) } } } }