feat(imitation): accept pasted source content as an alternative to URL
- Make source_url optional and add source_content to the request; the
two are normalized into a source kind ("url" | "content"), URL wins
when both are present, and missing both returns source_required
- Skip web fetching in the generation worker when pasted content is
provided; truncate it to the same 24,000-rune cap
- Label untitled pasted-content jobs with a locale-aware display title
and mark the source kind in wizard state and prompt metadata
- Cover source normalization, truncation, and display title with tests
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNormalizeImitationSourcePrefersURL(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
sourceURL, sourceContent, sourceKind, err := normalizeImitationSource(GenerateImitationRequest{
|
||||
SourceURL: " https://example.com/article ",
|
||||
SourceContent: "pasted content should be ignored",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("normalizeImitationSource() error = %v", err)
|
||||
}
|
||||
if sourceURL != "https://example.com/article" {
|
||||
t.Fatalf("sourceURL = %q, want normalized URL", sourceURL)
|
||||
}
|
||||
if sourceContent != "" {
|
||||
t.Fatalf("sourceContent = %q, want empty when URL is present", sourceContent)
|
||||
}
|
||||
if sourceKind != articleImitationSourceURL {
|
||||
t.Fatalf("sourceKind = %q, want %q", sourceKind, articleImitationSourceURL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeImitationSourceAcceptsPastedContent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
sourceURL, sourceContent, sourceKind, err := normalizeImitationSource(GenerateImitationRequest{
|
||||
SourceContent: " article body ",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("normalizeImitationSource() error = %v", err)
|
||||
}
|
||||
if sourceURL != "" {
|
||||
t.Fatalf("sourceURL = %q, want empty", sourceURL)
|
||||
}
|
||||
if sourceContent != "article body" {
|
||||
t.Fatalf("sourceContent = %q, want trimmed content", sourceContent)
|
||||
}
|
||||
if sourceKind != articleImitationSourceContent {
|
||||
t.Fatalf("sourceKind = %q, want %q", sourceKind, articleImitationSourceContent)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeImitationSourceRejectsMissingSource(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, _, _, err := normalizeImitationSource(GenerateImitationRequest{})
|
||||
if err == nil {
|
||||
t.Fatal("normalizeImitationSource() error = nil, want source_required")
|
||||
}
|
||||
if err.Error() != "source_required" {
|
||||
t.Fatalf("normalizeImitationSource() error = %q, want source_required", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeImitationSourceTruncatesPastedContent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, sourceContent, _, err := normalizeImitationSource(GenerateImitationRequest{
|
||||
SourceContent: strings.Repeat("文", maxImitationSourceContentRunes+100),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("normalizeImitationSource() error = %v", err)
|
||||
}
|
||||
if got := len([]rune(sourceContent)); got != maxImitationSourceContentRunes {
|
||||
t.Fatalf("source content rune count = %d, want %d", got, maxImitationSourceContentRunes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImitationSourceDisplayTitleLabelsUntitledPastedContent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if got := imitationSourceDisplayTitle(articleImitationSourceContent, "", "zh-CN"); got != "粘贴正文" {
|
||||
t.Fatalf("Chinese display title = %q, want 粘贴正文", got)
|
||||
}
|
||||
if got := imitationSourceDisplayTitle(articleImitationSourceContent, "", "en-US"); got != "Pasted content" {
|
||||
t.Fatalf("English display title = %q, want Pasted content", got)
|
||||
}
|
||||
if got := imitationSourceDisplayTitle(articleImitationSourceContent, "Original title", "en-US"); got != "Original title" {
|
||||
t.Fatalf("explicit display title = %q, want Original title", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user