Compare commits
9 commits
b061e14b53
...
1c75c5c5fe
Author | SHA1 | Date | |
---|---|---|---|
1c75c5c5fe |
|||
39feba7d1d |
|||
9639525ddd | |||
b25f76dde8 |
|||
aa7cf00ebb |
|||
bd1d8f8339 | |||
|
3e1c15e023 | ||
|
78b8f4696c | ||
|
b7a8627bcf |
5 changed files with 271 additions and 4 deletions
15
.gitea/workflows/stale.yml
Normal file
15
.gitea/workflows/stale.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
name: "Close stale issues and PRs"
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "@hourly"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v9
|
||||||
|
with:
|
||||||
|
stale-pr-message: "Will be closed in x days bc yo mom is a bitch. im not telling you when it will be closed fuckface"
|
||||||
|
days-before-pr-stale: 2
|
||||||
|
days-before-pr-close: 3
|
|
@ -4,8 +4,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||||
import de.szut.casino.user.UserEntity;
|
import de.szut.casino.user.UserEntity;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import jakarta.validation.constraints.Positive;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
|
@ -5,12 +5,14 @@ import jakarta.validation.constraints.DecimalMax;
|
||||||
import jakarta.validation.constraints.DecimalMin;
|
import jakarta.validation.constraints.DecimalMin;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
public class DiceDto extends BetDto {
|
public class DiceDto extends BetDto {
|
||||||
private boolean rollOver;
|
private boolean rollOver;
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,11 @@ import java.util.Random;
|
||||||
@Service
|
@Service
|
||||||
public class DiceService {
|
public class DiceService {
|
||||||
private static final int MAX_DICE_VALUE = 100;
|
private static final int MAX_DICE_VALUE = 100;
|
||||||
private final Random random = new Random();
|
private final Random random;
|
||||||
private final BalanceService balanceService;
|
private final BalanceService balanceService;
|
||||||
|
|
||||||
public DiceService(BalanceService balanceService) {
|
public DiceService(Random random, BalanceService balanceService) {
|
||||||
|
this.random = random;
|
||||||
this.balanceService = balanceService;
|
this.balanceService = balanceService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
251
backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
Normal file
251
backend/src/test/java/de/szut/casino/dice/DiceServiceTest.java
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
package de.szut.casino.dice;
|
||||||
|
|
||||||
|
import de.szut.casino.shared.service.BalanceService;
|
||||||
|
import de.szut.casino.user.UserEntity;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class DiceServiceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private BalanceService balanceService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Random random;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private DiceService diceService;
|
||||||
|
|
||||||
|
private UserEntity user;
|
||||||
|
private DiceDto diceDto;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
user = new UserEntity();
|
||||||
|
user.setId(1L);
|
||||||
|
user.setBalance(BigDecimal.valueOf(1000));
|
||||||
|
|
||||||
|
diceDto = new DiceDto();
|
||||||
|
diceDto.setBetAmount(BigDecimal.valueOf(10));
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_win() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(55);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(56), result.getRolledValue());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_lose() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(49);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(50), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_win() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(48);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(49), result.getRolledValue());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_lose() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(50));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(50);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(51), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_targetValueOne_rolledOne_lose() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(1));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(0);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(1), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_targetValueOne_rolledTwo_win() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(1));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(1);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(2), result.getRolledValue());
|
||||||
|
// Win chance for target 1 (roll over) is 99. Multiplier = (100-1)/99 = 1
|
||||||
|
assertEquals(diceDto.getBetAmount().stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_targetValueOne_alwaysLose_winChanceZero() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(1));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(0);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(1), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_targetValueNinetyNine_rolledHundred_win() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(99));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(99);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(100), result.getRolledValue());
|
||||||
|
// Win chance for target 99 (roll over) is 1. Multiplier = (100-1)/1 = 99
|
||||||
|
assertEquals(diceDto.getBetAmount().multiply(BigDecimal.valueOf(99)).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_targetValueNinetyNine_rolledNinetyEight_win() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(99));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(97);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(98), result.getRolledValue());
|
||||||
|
// Win chance for target 99 (roll under) is 98. Multiplier = (100-1)/98 = 99/98
|
||||||
|
assertEquals(diceDto.getBetAmount().multiply(BigDecimal.valueOf(99).divide(BigDecimal.valueOf(98), 4, RoundingMode.HALF_UP)), result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollOver_targetValueOneHundred_alwaysLose_winChanceZero() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(100));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(99);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertFalse(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(100), result.getRolledValue());
|
||||||
|
assertEquals(BigDecimal.ZERO, result.getPayout());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, never()).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_rollUnder_targetValueOneHundred_rolledNinetyNine_win() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(100));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(98);
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(99), result.getRolledValue());
|
||||||
|
// Win chance for target 100 (roll under) is 99. Multiplier = (100-1)/99 = 1
|
||||||
|
assertEquals(diceDto.getBetAmount().stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
verify(balanceService, times(1)).addFunds(eq(user), any(BigDecimal.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_payoutCalculationCorrect() {
|
||||||
|
diceDto.setRollOver(true);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(75));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(75);
|
||||||
|
|
||||||
|
// Multiplier for win chance 25: (100-1)/25 = 99/25 = 3.96
|
||||||
|
// Payout: 10 * 3.96 = 39.6
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(39.6).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_payoutCalculationCorrect_rollUnder() {
|
||||||
|
diceDto.setRollOver(false);
|
||||||
|
diceDto.setTargetValue(BigDecimal.valueOf(25));
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(0);
|
||||||
|
|
||||||
|
// Multiplier for win chance 24: (100-1)/24 = 99/24 = 4.125
|
||||||
|
// Payout: 10 * 4.125 = 41.25
|
||||||
|
|
||||||
|
DiceResult result = diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
assertTrue(result.isWin());
|
||||||
|
assertEquals(BigDecimal.valueOf(41.25).stripTrailingZeros(), result.getPayout().stripTrailingZeros());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void play_betAmountSubtracted() {
|
||||||
|
when(random.nextInt(anyInt())).thenReturn(50);
|
||||||
|
|
||||||
|
diceService.play(user, diceDto);
|
||||||
|
|
||||||
|
verify(balanceService, times(1)).subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue