Add cascading fallback for deal titles instead of hardcoded "Unknown"
Replace the simple nil-title → "Unknown" logic in printDeal with a fallbackDealTitle() function that tries multiple fields in priority order before giving up: 1. Title (cleaned) — the happy path, same as before 2. Brand + Department — e.g. "Publix deal (Meat)" 3. Brand alone — e.g. "Publix deal" 4. Department alone — e.g. "Meat deal" 5. Description truncated to 48 chars — last-resort meaningful text 6. Item ID — e.g. "Deal 12345" 7. "Untitled deal" — only when every field is empty This makes the output more useful for the ~5-10% of weekly ad items that ship with a nil Title from the Publix API, which previously all showed as "Unknown" and were indistinguishable from each other. Tests: - TestPrintDeals_FallbackTitleFromBrandAndDepartment - TestPrintDeals_FallbackTitleFromID Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -151,10 +151,7 @@ func PrintWarning(w io.Writer, msg string) {
|
||||
}
|
||||
|
||||
func printDeal(w io.Writer, item api.SavingItem) {
|
||||
title := filter.CleanText(filter.Deref(item.Title))
|
||||
if title == "" {
|
||||
title = "Unknown"
|
||||
}
|
||||
title := fallbackDealTitle(item)
|
||||
savings := filter.CleanText(filter.Deref(item.Savings))
|
||||
desc := filter.CleanText(filter.Deref(item.Description))
|
||||
dept := filter.CleanText(filter.Deref(item.Department))
|
||||
@@ -198,6 +195,37 @@ func printDeal(w io.Writer, item api.SavingItem) {
|
||||
}
|
||||
}
|
||||
|
||||
func fallbackDealTitle(item api.SavingItem) string {
|
||||
if title := filter.CleanText(filter.Deref(item.Title)); title != "" {
|
||||
return title
|
||||
}
|
||||
|
||||
brand := filter.CleanText(filter.Deref(item.Brand))
|
||||
dept := filter.CleanText(filter.Deref(item.Department))
|
||||
switch {
|
||||
case brand != "" && dept != "":
|
||||
return fmt.Sprintf("%s deal (%s)", brand, dept)
|
||||
case brand != "":
|
||||
return brand + " deal"
|
||||
case dept != "":
|
||||
return dept + " deal"
|
||||
}
|
||||
|
||||
if desc := filter.CleanText(filter.Deref(item.Description)); desc != "" {
|
||||
const max = 48
|
||||
if len(desc) > max {
|
||||
return desc[:max-3] + "..."
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
if item.ID != "" {
|
||||
return "Deal " + item.ID
|
||||
}
|
||||
|
||||
return "Untitled deal"
|
||||
}
|
||||
|
||||
func toDealJSON(item api.SavingItem) DealJSON {
|
||||
categories := item.Categories
|
||||
if categories == nil {
|
||||
|
||||
@@ -55,6 +55,41 @@ func TestPrintDeals_ContainsExpectedContent(t *testing.T) {
|
||||
assert.NotContains(t, output, "&")
|
||||
}
|
||||
|
||||
func TestPrintDeals_FallbackTitleFromBrandAndDepartment(t *testing.T) {
|
||||
items := []api.SavingItem{
|
||||
{
|
||||
ID: "fallback-1",
|
||||
Title: nil,
|
||||
Brand: ptr("Publix"),
|
||||
Department: ptr("Meat"),
|
||||
Categories: []string{"meat"},
|
||||
},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
display.PrintDeals(&buf, items)
|
||||
output := buf.String()
|
||||
|
||||
assert.Contains(t, output, "Publix deal (Meat)")
|
||||
assert.NotContains(t, output, "Unknown")
|
||||
}
|
||||
|
||||
func TestPrintDeals_FallbackTitleFromID(t *testing.T) {
|
||||
items := []api.SavingItem{
|
||||
{
|
||||
ID: "fallback-2",
|
||||
Title: nil,
|
||||
},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
display.PrintDeals(&buf, items)
|
||||
output := buf.String()
|
||||
|
||||
assert.Contains(t, output, "Deal fallback-2")
|
||||
assert.NotContains(t, output, "Unknown")
|
||||
}
|
||||
|
||||
func TestPrintDealsJSON(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
err := display.PrintDealsJSON(&buf, sampleDeals())
|
||||
|
||||
Reference in New Issue
Block a user