first commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package com.xuezhanmaster.game.event;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class GameEventTest {
|
||||
|
||||
@Test
|
||||
void shouldBuildResponseActionPayloadForFutureResponseEvents() {
|
||||
GameEvent event = GameEvent.responseActionDeclared(
|
||||
"game-1",
|
||||
GameEventType.PENG_DECLARED,
|
||||
2,
|
||||
1,
|
||||
"三万"
|
||||
);
|
||||
|
||||
assertThat(event.eventType()).isEqualTo(GameEventType.PENG_DECLARED);
|
||||
assertThat(event.seatNo()).isEqualTo(2);
|
||||
assertThat(event.payload())
|
||||
.containsEntry("actionType", "PENG")
|
||||
.containsEntry("sourceSeatNo", 1)
|
||||
.containsEntry("tile", "三万");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBuildStandardPublicTableEvents() {
|
||||
GameEvent started = GameEvent.gameStarted("game-1", "room-1");
|
||||
GameEvent phaseChanged = GameEvent.phaseChanged("game-1", "PLAYING");
|
||||
GameEvent switched = GameEvent.turnSwitched("game-1", 3);
|
||||
|
||||
assertThat(started.eventType()).isEqualTo(GameEventType.GAME_STARTED);
|
||||
assertThat(started.payload()).containsEntry("roomId", "room-1");
|
||||
|
||||
assertThat(phaseChanged.eventType()).isEqualTo(GameEventType.GAME_PHASE_CHANGED);
|
||||
assertThat(phaseChanged.payload()).containsEntry("phase", "PLAYING");
|
||||
|
||||
assertThat(switched.eventType()).isEqualTo(GameEventType.TURN_SWITCHED);
|
||||
assertThat(switched.payload()).containsEntry("currentSeatNo", 3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.xuezhanmaster.game.service;
|
||||
|
||||
import com.xuezhanmaster.game.domain.Tile;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DeckFactoryTest {
|
||||
|
||||
private final DeckFactory deckFactory = new DeckFactory();
|
||||
|
||||
@Test
|
||||
void shouldCreate108TilesForSichuanVariant() {
|
||||
List<Tile> wall = deckFactory.createShuffledWall();
|
||||
|
||||
assertThat(wall).hasSize(108);
|
||||
Map<Tile, Long> counts = wall.stream()
|
||||
.collect(Collectors.groupingBy(tile -> tile, Collectors.counting()));
|
||||
assertThat(counts.values()).allMatch(count -> count == 4L);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.xuezhanmaster.game.service;
|
||||
|
||||
import com.xuezhanmaster.game.dto.GameTableSnapshot;
|
||||
import com.xuezhanmaster.game.engine.GameEngine;
|
||||
import com.xuezhanmaster.strategy.service.StrategyService;
|
||||
import com.xuezhanmaster.teaching.dto.TeachingAdviceResponse;
|
||||
import com.xuezhanmaster.teaching.service.PlayerVisibilityService;
|
||||
import com.xuezhanmaster.teaching.service.TeachingService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DemoGameServiceTest {
|
||||
|
||||
private final DemoGameService demoGameService = new DemoGameService(
|
||||
new GameEngine(new DeckFactory()),
|
||||
new StrategyService(),
|
||||
new PlayerVisibilityService(),
|
||||
new TeachingService()
|
||||
);
|
||||
|
||||
@Test
|
||||
void shouldCreateDemoTableSnapshot() {
|
||||
GameTableSnapshot snapshot = demoGameService.createDemoTableSnapshot();
|
||||
|
||||
assertThat(snapshot.seats()).hasSize(4);
|
||||
assertThat(snapshot.remainingWallCount()).isEqualTo(55);
|
||||
assertThat(snapshot.seats().get(0).handTiles()).hasSize(14);
|
||||
assertThat(snapshot.seats().get(1).handTiles()).hasSize(13);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnAdviceCandidates() {
|
||||
TeachingAdviceResponse advice = demoGameService.createDemoTeachingAdvice();
|
||||
|
||||
assertThat(advice.recommendedAction()).isNotBlank();
|
||||
assertThat(advice.candidates()).hasSizeLessThanOrEqualTo(3);
|
||||
assertThat(advice.explanation()).isNotBlank();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.xuezhanmaster.game.service;
|
||||
|
||||
import com.xuezhanmaster.common.exception.BusinessException;
|
||||
import com.xuezhanmaster.game.dto.GameActionRequest;
|
||||
import com.xuezhanmaster.game.domain.TileSuit;
|
||||
import com.xuezhanmaster.game.dto.GameStateResponse;
|
||||
import com.xuezhanmaster.game.service.GameActionProcessor;
|
||||
import com.xuezhanmaster.strategy.service.StrategyService;
|
||||
import com.xuezhanmaster.teaching.service.PlayerVisibilityService;
|
||||
import com.xuezhanmaster.teaching.service.TeachingService;
|
||||
import com.xuezhanmaster.room.dto.CreateRoomRequest;
|
||||
import com.xuezhanmaster.room.dto.RoomSummaryResponse;
|
||||
import com.xuezhanmaster.room.dto.ToggleReadyRequest;
|
||||
import com.xuezhanmaster.room.service.RoomService;
|
||||
import com.xuezhanmaster.game.engine.GameEngine;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
|
||||
import com.xuezhanmaster.ws.service.GameMessagePublisher;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class GameSessionServiceTest {
|
||||
|
||||
private final RoomService roomService = new RoomService();
|
||||
private final GameSessionService gameSessionService = new GameSessionService(
|
||||
roomService,
|
||||
new GameEngine(new DeckFactory()),
|
||||
new GameActionProcessor(),
|
||||
new StrategyService(),
|
||||
new PlayerVisibilityService(),
|
||||
new TeachingService(),
|
||||
new GameMessagePublisher(mock(SimpMessagingTemplate.class))
|
||||
);
|
||||
|
||||
@Test
|
||||
void shouldStartGameAndEnterPlayingAfterHumanSelectsLackSuit() {
|
||||
RoomSummaryResponse room = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
roomService.toggleReady(room.roomId(), new ToggleReadyRequest("host-1", true));
|
||||
|
||||
GameStateResponse started = gameSessionService.startGame(room.roomId(), "host-1");
|
||||
assertThat(started.phase()).isEqualTo("LACK_SELECTION");
|
||||
assertThat(started.seats()).hasSize(4);
|
||||
assertThat(started.selfSeat().handTiles()).hasSize(14);
|
||||
|
||||
GameStateResponse afterLack = gameSessionService.selectLackSuit(
|
||||
started.gameId(),
|
||||
"host-1",
|
||||
TileSuit.WAN.name()
|
||||
);
|
||||
|
||||
assertThat(afterLack.phase()).isEqualTo("PLAYING");
|
||||
assertThat(afterLack.selfSeat().lackSuit()).isEqualTo(TileSuit.WAN.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDiscardAndLoopBackToHumanAfterBotsAutoPlay() {
|
||||
RoomSummaryResponse room = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
roomService.toggleReady(room.roomId(), new ToggleReadyRequest("host-1", true));
|
||||
|
||||
GameStateResponse started = gameSessionService.startGame(room.roomId(), "host-1");
|
||||
GameStateResponse playing = gameSessionService.selectLackSuit(started.gameId(), "host-1", TileSuit.WAN.name());
|
||||
String discardTile = playing.selfSeat().handTiles().get(0);
|
||||
|
||||
GameStateResponse afterDiscard = gameSessionService.discardTile(playing.gameId(), "host-1", discardTile);
|
||||
|
||||
assertThat(afterDiscard.phase()).isEqualTo("PLAYING");
|
||||
assertThat(afterDiscard.currentSeatNo()).isEqualTo(0);
|
||||
assertThat(afterDiscard.selfSeat().handTiles()).hasSize(14);
|
||||
assertThat(afterDiscard.remainingWallCount()).isEqualTo(51);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRouteNewActionTypesThroughUnifiedActionEntry() {
|
||||
RoomSummaryResponse room = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
roomService.toggleReady(room.roomId(), new ToggleReadyRequest("host-1", true));
|
||||
|
||||
GameStateResponse started = gameSessionService.startGame(room.roomId(), "host-1");
|
||||
gameSessionService.selectLackSuit(started.gameId(), "host-1", TileSuit.WAN.name());
|
||||
|
||||
assertThatThrownBy(() -> gameSessionService.performAction(
|
||||
started.gameId(),
|
||||
new GameActionRequest("host-1", "PENG", "三万", 1)
|
||||
))
|
||||
.isInstanceOf(BusinessException.class)
|
||||
.extracting(throwable -> ((BusinessException) throwable).getCode())
|
||||
.isEqualTo("GAME_ACTION_UNSUPPORTED");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectResponseActionWithoutSourceSeatNo() {
|
||||
RoomSummaryResponse room = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
roomService.toggleReady(room.roomId(), new ToggleReadyRequest("host-1", true));
|
||||
|
||||
GameStateResponse started = gameSessionService.startGame(room.roomId(), "host-1");
|
||||
gameSessionService.selectLackSuit(started.gameId(), "host-1", TileSuit.WAN.name());
|
||||
|
||||
assertThatThrownBy(() -> gameSessionService.performAction(
|
||||
started.gameId(),
|
||||
new GameActionRequest("host-1", "PENG", "三万", null)
|
||||
))
|
||||
.isInstanceOf(BusinessException.class)
|
||||
.extracting(throwable -> ((BusinessException) throwable).getCode())
|
||||
.isEqualTo("GAME_ACTION_PARAM_INVALID");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectResponseActionOutsidePlayingPhase() {
|
||||
RoomSummaryResponse room = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
roomService.toggleReady(room.roomId(), new ToggleReadyRequest("host-1", true));
|
||||
|
||||
GameStateResponse started = gameSessionService.startGame(room.roomId(), "host-1");
|
||||
|
||||
assertThatThrownBy(() -> gameSessionService.performAction(
|
||||
started.gameId(),
|
||||
new GameActionRequest("host-1", "PASS", null, 1)
|
||||
))
|
||||
.isInstanceOf(BusinessException.class)
|
||||
.extracting(throwable -> ((BusinessException) throwable).getCode())
|
||||
.isEqualTo("GAME_PHASE_INVALID");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectResponseActionFromSelfSeat() {
|
||||
RoomSummaryResponse room = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
roomService.toggleReady(room.roomId(), new ToggleReadyRequest("host-1", true));
|
||||
|
||||
GameStateResponse started = gameSessionService.startGame(room.roomId(), "host-1");
|
||||
gameSessionService.selectLackSuit(started.gameId(), "host-1", TileSuit.WAN.name());
|
||||
|
||||
assertThatThrownBy(() -> gameSessionService.performAction(
|
||||
started.gameId(),
|
||||
new GameActionRequest("host-1", "PASS", null, 0)
|
||||
))
|
||||
.isInstanceOf(BusinessException.class)
|
||||
.extracting(throwable -> ((BusinessException) throwable).getCode())
|
||||
.isEqualTo("GAME_ACTION_PARAM_INVALID");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectUnknownActionTypeFromUnifiedActionEntry() {
|
||||
RoomSummaryResponse room = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
roomService.toggleReady(room.roomId(), new ToggleReadyRequest("host-1", true));
|
||||
|
||||
GameStateResponse started = gameSessionService.startGame(room.roomId(), "host-1");
|
||||
|
||||
assertThatThrownBy(() -> gameSessionService.performAction(
|
||||
started.gameId(),
|
||||
new GameActionRequest("host-1", "UNKNOWN_ACTION", null, null)
|
||||
))
|
||||
.isInstanceOf(BusinessException.class)
|
||||
.extracting(throwable -> ((BusinessException) throwable).getCode())
|
||||
.isEqualTo("GAME_ACTION_INVALID");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.xuezhanmaster.room.service;
|
||||
|
||||
import com.xuezhanmaster.room.dto.CreateRoomRequest;
|
||||
import com.xuezhanmaster.room.dto.JoinRoomRequest;
|
||||
import com.xuezhanmaster.room.dto.RoomSummaryResponse;
|
||||
import com.xuezhanmaster.room.dto.ToggleReadyRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class RoomServiceTest {
|
||||
|
||||
private final RoomService roomService = new RoomService();
|
||||
|
||||
@Test
|
||||
void shouldCreateAndQueryRoomFromMemory() {
|
||||
RoomSummaryResponse created = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
RoomSummaryResponse queried = roomService.getRoomSummary(created.roomId());
|
||||
|
||||
assertThat(queried.roomId()).isEqualTo(created.roomId());
|
||||
assertThat(queried.seats()).hasSize(1);
|
||||
assertThat(queried.allowBotFill()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldJoinRoomAndBecomeReady() {
|
||||
RoomSummaryResponse created = roomService.createRoom(new CreateRoomRequest("host-1", true));
|
||||
roomService.toggleReady(created.roomId(), new ToggleReadyRequest("host-1", true));
|
||||
RoomSummaryResponse joined = roomService.joinRoom(created.roomId(), new JoinRoomRequest("player-2", "Player-2"));
|
||||
RoomSummaryResponse ready = roomService.toggleReady(created.roomId(), new ToggleReadyRequest("player-2", true));
|
||||
|
||||
assertThat(joined.seats()).hasSize(2);
|
||||
assertThat(ready.status()).isEqualTo("READY");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user