package products import ( "encoding/json" "fmt" "strings" "testing" ) func TestOutfitCard(t *testing.T) { h, _ := newHarness(t) local := h.p.byProductID("blue-coat").local h.do("POST", "https://secure.imvu.com/api/xmlrpc/client.php", call("test.avatarInfoForLogin2"), false, false) save := []byte(fmt.Sprintf(`{"outfit_name": "Mine", "products": "80,1,%d"}`, local)) h.do("POST", "https://client-dynamic.imvu.com/api/outfits.php", save, true, false) // The product list has the community product too, not for sale. _, body := h.do("GET", "https://client-dynamic.imvu.com/api/outfit_products.php?outfit_id=555", nil, true, true) var r struct{ Result map[string]map[string]any } if json.Unmarshal(body, &r) != nil || len(r.Result) != 2 { t.Fatalf("products %s", body) } if e := r.Result[fmt.Sprint(local)]; e == nil || e["name"] != "Blue Coat" || e["is_bundleable"] != float64(0) { t.Fatalf("community entry %v", e) } // The bundle check is asked about IMVU's products only (re-signed). h.do("GET", fmt.Sprintf("https://client-dynamic.imvu.com/api/find_bundle.php?pids=80,%d.0,1", local), nil, true, true) if got := h.imvu.asked["find bundle"]; len(got) != 1 || got[0] != "pids=80,1" { t.Fatalf("find_bundle: IMVU got %q", got) } // Removing it in the card: IMVU hears of IMVU's removals only, and the outfit forgets it. h.do("POST", "https://client-dynamic.imvu.com/api/outfits.php", []byte(fmt.Sprintf(`{"outfit_id": "555", "outfit_name": "Mine", "remove_pids": [1, %d]}`, local)), true, false) if got := h.imvu.asked["save outfit"]; len(got) != 2 || !strings.Contains(got[1], `"remove_pids":[1]`) { t.Fatalf("IMVU got %q", got) } if left := h.p.state.outfit("555"); len(left) != 0 { t.Fatalf("outfit still has %v", left) } }