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>
188 lines
5.0 KiB
Go
188 lines
5.0 KiB
Go
package display_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/tayloree/publix-deals/internal/api"
|
|
"github.com/tayloree/publix-deals/internal/display"
|
|
)
|
|
|
|
func ptr(s string) *string { return &s }
|
|
|
|
func sampleDeals() []api.SavingItem {
|
|
return []api.SavingItem{
|
|
{
|
|
ID: "1",
|
|
Title: ptr("Chicken Breasts"),
|
|
Savings: ptr("$3.99 lb"),
|
|
Description: ptr("USDA Grade A, 97% Fat Free"),
|
|
Department: ptr("Meat"),
|
|
Brand: ptr("Publix"),
|
|
Categories: []string{"meat"},
|
|
AdditionalDealInfo: ptr("SAVE UP TO $1.00 LB"),
|
|
StartFormatted: "2/18",
|
|
EndFormatted: "2/24",
|
|
},
|
|
{
|
|
ID: "2",
|
|
Title: ptr("Nutella & More"),
|
|
Savings: ptr("Buy 1 Get 1 FREE"),
|
|
Department: ptr("Grocery"),
|
|
Categories: []string{"bogo", "grocery"},
|
|
StartFormatted: "2/18",
|
|
EndFormatted: "2/24",
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestPrintDeals_ContainsExpectedContent(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
display.PrintDeals(&buf, sampleDeals())
|
|
output := buf.String()
|
|
|
|
assert.Contains(t, output, "Publix Weekly Deals")
|
|
assert.Contains(t, output, "2 items")
|
|
assert.Contains(t, output, "Chicken Breasts")
|
|
assert.Contains(t, output, "$3.99 lb")
|
|
assert.Contains(t, output, "SAVE UP TO $1.00 LB")
|
|
assert.Contains(t, output, "BOGO") // Nutella is bogo
|
|
// HTML entities should be unescaped
|
|
assert.Contains(t, output, "Nutella & More")
|
|
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())
|
|
require.NoError(t, err)
|
|
assert.NotContains(t, buf.String(), "\n ")
|
|
|
|
var deals []display.DealJSON
|
|
err = json.Unmarshal(buf.Bytes(), &deals)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, deals, 2)
|
|
assert.Equal(t, "Chicken Breasts", deals[0].Title)
|
|
assert.Equal(t, "$3.99 lb", deals[0].Savings)
|
|
assert.Equal(t, "Meat", deals[0].Department)
|
|
assert.False(t, deals[0].IsBogo)
|
|
|
|
// HTML entities should be clean in JSON too
|
|
assert.Equal(t, "Nutella & More", deals[1].Title)
|
|
assert.True(t, deals[1].IsBogo)
|
|
}
|
|
|
|
func TestPrintDealsJSON_NilFields(t *testing.T) {
|
|
items := []api.SavingItem{{ID: "nil-test"}}
|
|
var buf bytes.Buffer
|
|
err := display.PrintDealsJSON(&buf, items)
|
|
require.NoError(t, err)
|
|
|
|
var deals []display.DealJSON
|
|
err = json.Unmarshal(buf.Bytes(), &deals)
|
|
require.NoError(t, err)
|
|
assert.Len(t, deals, 1)
|
|
assert.Equal(t, "", deals[0].Title)
|
|
assert.NotNil(t, deals[0].Categories)
|
|
}
|
|
|
|
func TestPrintStores(t *testing.T) {
|
|
stores := []api.Store{
|
|
{Key: "01425", Name: "Peachers Mill", Addr: "1490 Tiny Town Rd", City: "Clarksville", State: "TN", Zip: "37042", Distance: "5"},
|
|
}
|
|
var buf bytes.Buffer
|
|
display.PrintStores(&buf, stores, "37042")
|
|
output := buf.String()
|
|
|
|
assert.Contains(t, output, "37042")
|
|
assert.Contains(t, output, "#1425")
|
|
assert.Contains(t, output, "Peachers Mill")
|
|
assert.Contains(t, output, "5 miles")
|
|
}
|
|
|
|
func TestPrintStoresJSON(t *testing.T) {
|
|
stores := []api.Store{
|
|
{Key: "01425", Name: "Peachers Mill", Addr: "1490 Tiny Town Rd", City: "Clarksville", State: "TN", Zip: "37042", Distance: "5"},
|
|
}
|
|
var buf bytes.Buffer
|
|
err := display.PrintStoresJSON(&buf, stores)
|
|
require.NoError(t, err)
|
|
assert.NotContains(t, buf.String(), "\n ")
|
|
|
|
var out []display.StoreJSON
|
|
err = json.Unmarshal(buf.Bytes(), &out)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, out, 1)
|
|
assert.Equal(t, "1425", out[0].Number)
|
|
assert.Equal(t, "Peachers Mill", out[0].Name)
|
|
assert.Contains(t, out[0].Address, "Clarksville")
|
|
}
|
|
|
|
func TestPrintCategories(t *testing.T) {
|
|
cats := map[string]int{"bogo": 10, "meat": 5, "produce": 3}
|
|
var buf bytes.Buffer
|
|
display.PrintCategories(&buf, cats, "1425")
|
|
output := buf.String()
|
|
|
|
assert.Contains(t, output, "1425")
|
|
assert.Contains(t, output, "bogo")
|
|
assert.Contains(t, output, "10 deals")
|
|
assert.Contains(t, output, "meat")
|
|
assert.Contains(t, output, "produce")
|
|
}
|
|
|
|
func TestPrintCategoriesJSON(t *testing.T) {
|
|
cats := map[string]int{"bogo": 10, "meat": 5}
|
|
var buf bytes.Buffer
|
|
err := display.PrintCategoriesJSON(&buf, cats)
|
|
require.NoError(t, err)
|
|
assert.NotContains(t, buf.String(), "\n ")
|
|
|
|
var out map[string]int
|
|
err = json.Unmarshal(buf.Bytes(), &out)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 10, out["bogo"])
|
|
assert.Equal(t, 5, out["meat"])
|
|
}
|