CI / build (push) Successful in 34s
- The inventory's Recently Added puts T5 products added to the library in the last 30 days first. - The shop's T5 listing follows its sort menu: Best Match ranks by name, Newest by upload date (oldest first ascending); ratings and prices (T5 products have neither) sort by newest. - Outfit cards: outfit_products.php gets the outfit's community products added (not for sale), find_bundle.php is asked about IMVU's products only, and removing one in the card (remove_pids) keeps it from IMVU and forgets it in the outfit. Co-Authored-By: Claude Opus 5.5 <[email protected]>
85 lines
3.0 KiB
Go
85 lines
3.0 KiB
Go
package products
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.t5de.dev/t5de/t5de-proxy/internal/hub"
|
|
)
|
|
|
|
func TestRecentlyAdded(t *testing.T) {
|
|
h, _ := newHarness(t)
|
|
hubDir := t.TempDir()
|
|
for _, id := range []string{"coatcoat22", "sofasofa22", "oldoldold2", "hairhair22"} {
|
|
writePack(t, hubDir, id, 1)
|
|
}
|
|
h.p.dirs = append(h.p.dirs, hubDir)
|
|
h.p.HubDir = hubDir
|
|
h.p.Owned = func(string) bool { return true }
|
|
h.p.refresh(true)
|
|
now := time.Now()
|
|
clothes := []hub.Category{{ID: 106}, {ID: 40}, {ID: 716}}
|
|
h.p.Library = func() []hub.LibraryEntry {
|
|
return []hub.LibraryEntry{
|
|
{Product: hub.Product{ID: "coatcoat22", Categories: clothes}, AddedAt: now.Add(-2 * time.Hour)},
|
|
{Product: hub.Product{ID: "sofasofa22", Categories: []hub.Category{{ID: 1027}, {ID: 1056}}}, AddedAt: now.Add(-time.Hour)},
|
|
{Product: hub.Product{ID: "oldoldold2", Categories: clothes}, AddedAt: now.Add(-40 * 24 * time.Hour)},
|
|
{Product: hub.Product{ID: "hairhair22"}, AddedAt: now.Add(-time.Hour)}, // no categories known: worn
|
|
}
|
|
}
|
|
local := func(id string) int64 { return h.p.byProductID(id).local }
|
|
get := func(kind string) []int64 {
|
|
_, b := h.do("GET", "http://client-dynamic.imvu.com/api/recently_added_inventory.php?type="+kind, nil, false, false)
|
|
var ids []int64
|
|
if json.Unmarshal(b, &ids) != nil {
|
|
t.Fatalf("%s: %s", kind, b)
|
|
}
|
|
return ids
|
|
}
|
|
if got, want := fmt.Sprint(get("clothing")), fmt.Sprint([]int64{local("hairhair22"), local("coatcoat22"), 31162856, 108363}); got != want {
|
|
t.Errorf("clothing %s, want %s", got, want)
|
|
}
|
|
if got, want := fmt.Sprint(get("furni")), fmt.Sprint([]int64{local("sofasofa22"), 31162856, 108363}); got != want {
|
|
t.Errorf("furni %s, want %s", got, want)
|
|
}
|
|
if got, want := fmt.Sprint(get("scenes")), fmt.Sprint([]int64{31162856, 108363}); got != want {
|
|
t.Errorf("scenes %s, want %s", got, want)
|
|
}
|
|
}
|
|
|
|
func TestShopSorting(t *testing.T) {
|
|
day := func(n int) time.Time { return time.Date(2026, 10, n, 0, 0, 0, 0, time.UTC) }
|
|
list := func() []hub.Product {
|
|
return []hub.Product{
|
|
{ID: "a", Name: "Long Red Coat", CreatedAt: day(5)},
|
|
{ID: "b", Name: "Coat", CreatedAt: day(1)},
|
|
{ID: "c", Name: "Coats & Jackets Pack", CreatedAt: day(2)},
|
|
{ID: "d", Name: "Raincoat", CreatedAt: day(4)},
|
|
{ID: "e", Name: "Hat", Creator: "coat_maker", CreatedAt: day(3)},
|
|
}
|
|
}
|
|
order := func(l []hub.Product) string {
|
|
s := ""
|
|
for _, p := range l {
|
|
s += p.ID
|
|
}
|
|
return s
|
|
}
|
|
for _, c := range []struct{ query, field, dir, want string }{
|
|
{"coat", "conversion_score_b", "desc", "bcade"}, // same name, starts with, word, inside a word, creator
|
|
{"", "conversion_score_b", "desc", "adecb"}, // no search: newest
|
|
{"coat", "id", "desc", "adecb"}, // Newest Products
|
|
{"coat", "id", "asc", "bceda"},
|
|
{"coat", "price", "asc", "adecb"}, // all free: newest
|
|
{"coat", "user_rating", "desc", "adecb"},
|
|
} {
|
|
l := list()
|
|
sortShop(l, c.query, c.field, c.dir)
|
|
if got := order(l); got != c.want {
|
|
t.Errorf("%q %s %s: %s, want %s", c.query, c.field, c.dir, got, c.want)
|
|
}
|
|
}
|
|
}
|