mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-26 09:33:02 +01:00
fix(gacha): prevent infinite loop in getRandomEntries
Add guards for edge cases: - Empty entries with rolls > 0 - Zero or negative rolls - Zero total weight in non-box mode - Box mode with more rolls than available entries Previously these cases caused infinite loops or panics.
This commit is contained in:
@@ -353,10 +353,16 @@ func addGachaItem(s *Session, items []GachaItem) {
|
|||||||
|
|
||||||
func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry, error) {
|
func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry, error) {
|
||||||
var chosen []GachaEntry
|
var chosen []GachaEntry
|
||||||
|
if len(entries) == 0 || rolls <= 0 {
|
||||||
|
return chosen, nil
|
||||||
|
}
|
||||||
var totalWeight float64
|
var totalWeight float64
|
||||||
for i := range entries {
|
for i := range entries {
|
||||||
totalWeight += entries[i].Weight
|
totalWeight += entries[i].Weight
|
||||||
}
|
}
|
||||||
|
if !isBox && totalWeight <= 0 {
|
||||||
|
return chosen, nil
|
||||||
|
}
|
||||||
for {
|
for {
|
||||||
if rolls == len(chosen) {
|
if rolls == len(chosen) {
|
||||||
break
|
break
|
||||||
@@ -371,6 +377,9 @@ func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if len(entries) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
result := rand.Intn(len(entries))
|
result := rand.Intn(len(entries))
|
||||||
chosen = append(chosen, entries[result])
|
chosen = append(chosen, entries[result])
|
||||||
entries[result] = entries[len(entries)-1]
|
entries[result] = entries[len(entries)-1]
|
||||||
|
|||||||
@@ -231,11 +231,9 @@ func TestGachaItemStruct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetRandomEntries_EmptyEntriesZeroRolls(t *testing.T) {
|
func TestGetRandomEntries_EmptyEntries(t *testing.T) {
|
||||||
// Note: getRandomEntries with empty entries and rolls > 0 causes infinite loop.
|
|
||||||
// Only test the valid case of 0 rolls with empty entries.
|
|
||||||
entries := []GachaEntry{}
|
entries := []GachaEntry{}
|
||||||
result, err := getRandomEntries(entries, 0, false)
|
result, err := getRandomEntries(entries, 5, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -244,6 +242,57 @@ func TestGetRandomEntries_EmptyEntriesZeroRolls(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetRandomEntries_EmptyEntriesBoxMode(t *testing.T) {
|
||||||
|
entries := []GachaEntry{}
|
||||||
|
result, err := getRandomEntries(entries, 5, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if len(result) != 0 {
|
||||||
|
t.Errorf("expected empty result, got %d entries", len(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRandomEntries_NegativeRolls(t *testing.T) {
|
||||||
|
entries := []GachaEntry{{ID: 1, Weight: 1.0}}
|
||||||
|
result, err := getRandomEntries(entries, -5, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if len(result) != 0 {
|
||||||
|
t.Errorf("expected empty result, got %d entries", len(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRandomEntries_ZeroTotalWeight(t *testing.T) {
|
||||||
|
entries := []GachaEntry{
|
||||||
|
{ID: 1, Weight: 0},
|
||||||
|
{ID: 2, Weight: 0},
|
||||||
|
}
|
||||||
|
result, err := getRandomEntries(entries, 5, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if len(result) != 0 {
|
||||||
|
t.Errorf("expected empty result with zero weight, got %d entries", len(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRandomEntries_BoxModeMoreRollsThanEntries(t *testing.T) {
|
||||||
|
entries := []GachaEntry{
|
||||||
|
{ID: 1, Weight: 1.0},
|
||||||
|
{ID: 2, Weight: 1.0},
|
||||||
|
}
|
||||||
|
// Request 5 rolls but only 2 entries - should return only 2
|
||||||
|
result, err := getRandomEntries(entries, 5, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if len(result) != 2 {
|
||||||
|
t.Errorf("expected 2 results (all available), got %d", len(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetRandomEntries_ZeroRolls(t *testing.T) {
|
func TestGetRandomEntries_ZeroRolls(t *testing.T) {
|
||||||
entries := []GachaEntry{
|
entries := []GachaEntry{
|
||||||
{ID: 1, Weight: 1.0},
|
{ID: 1, Weight: 1.0},
|
||||||
|
|||||||
Reference in New Issue
Block a user