package tv.dyndns.kishibe.qmaclone.server; import static com.google.common.truth.Truth.assertThat; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import tv.dyndns.kishibe.qmaclone.client.constant.Constant; import tv.dyndns.kishibe.qmaclone.client.game.ProblemGenre; import tv.dyndns.kishibe.qmaclone.client.game.ProblemType; import tv.dyndns.kishibe.qmaclone.client.packet.NewAndOldProblems; import tv.dyndns.kishibe.qmaclone.client.packet.PacketProblemMinimum; import tv.dyndns.kishibe.qmaclone.server.testing.QMACloneTestEnv; import com.google.common.collect.Lists; import com.google.guiceberry.junit4.GuiceBerryRule; import com.google.inject.Inject; @RunWith(JUnit4.class) public class NormalModeProblemManagerTest { private static final int LARGE_LOOP = 10000; private static final int SMALL_LOOP = 1000; @Rule public final GuiceBerryRule rule = new GuiceBerryRule(QMACloneTestEnv.class); @Inject private NormalModeProblemManager manager; @Test public final void testSelectProblemStressTest() throws Exception { // 問題選択をLOOP回ランダムに行ってチェック final Random random = new Random(0); ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime() .availableProcessors()); List<Callable<Void>> tasks = Lists.newArrayList(); for (int loop = 0; loop < LARGE_LOOP; ++loop) { tasks.add(new Callable<Void>() { @Override public Void call() throws Exception { Set<Integer> problemIds = new HashSet<Integer>(); Set<Integer> selectedProblemIds = new HashSet<Integer>(); Set<Integer> userCodes = new HashSet<Integer>(); Set<Integer> createrHashes = new HashSet<Integer>(); for (int problemCount = 0; problemCount < Constant.MAX_PROBLEMS_PER_SESSION; ++problemCount) { ProblemGenre genre = ProblemGenre.values()[random.nextInt(ProblemGenre.values().length)]; Set<ProblemGenre> genres = EnumSet.of(genre); ProblemType type = ProblemType.values()[random.nextInt(ProblemType.values().length)]; Set<ProblemType> types = EnumSet.of(type); int classLevel = random.nextInt(Constant.NUMBER_OF_CLASSES + 5); int difficultSelect = random.nextInt(5); PacketProblemMinimum problem = manager.selectProblem(genres, types, classLevel, difficultSelect, problemIds, true, NewAndOldProblems.Both, false, userCodes, createrHashes); assertNotNull(problem); assertEquals(genre, problem.genre); assertEquals(type, problem.type); selectedProblemIds.add(problem.id); } int numberOfProblems = problemIds.size(); assertTrue(numberOfProblems == Constant.MAX_PROBLEMS_PER_SESSION); assertEquals(problemIds, selectedProblemIds); return null; } }); } service.invokeAll(tasks); service.shutdown(); } @Test public void testSelectProblemNewProblem() throws Exception { // 新問のみで新問のみが出題されるかどうか? Random random = new Random(0); for (int loop = 0; loop < SMALL_LOOP; ++loop) { Set<ProblemGenre> genres = EnumSet.of(ProblemGenre.values()[random.nextInt(ProblemGenre .values().length)]); Set<ProblemType> types = EnumSet .of(ProblemType.values()[random.nextInt(ProblemType.values().length)]); int classLevel = random.nextInt(Constant.NUMBER_OF_CLASSES + 5); int difficultSelect = random.nextInt(5); NewAndOldProblems newAndOldProblems = NewAndOldProblems.OnlyNew; PacketProblemMinimum problem = manager.selectProblem(genres, types, classLevel, difficultSelect, new HashSet<Integer>(), true, newAndOldProblems, false, new HashSet<Integer>(), new HashSet<Integer>()); assertNotNull(problem); } } @Test public void selectProblemShouldReturnOnlyNew() throws Exception { // 新問のみで新問のみが出題されるかどうか? for (int loop = 0; loop < SMALL_LOOP; ++loop) { int classLevel = 0; int difficultSelect = Constant.DIFFICULT_SELECT_NORMAL; NewAndOldProblems newAndOldProblems = NewAndOldProblems.OnlyNew; PacketProblemMinimum problem = manager.selectProblem(EnumSet.of(ProblemGenre.Random), EnumSet.of(ProblemType.Random), classLevel, difficultSelect, new HashSet<Integer>(), true, newAndOldProblems, false, new HashSet<Integer>(), new HashSet<Integer>()); assertNotNull(problem); } } @Test public void testSelectProblemOldProblem() throws Exception { // 旧問のみで旧問のみが出題されるかどうか? Random random = new Random(0); int numberOfOld = 0; for (int loop = 0; loop < SMALL_LOOP; ++loop) { Set<ProblemGenre> genres = EnumSet.of(ProblemGenre.values()[random.nextInt(ProblemGenre .values().length)]); Set<ProblemType> types = EnumSet .of(ProblemType.values()[random.nextInt(ProblemType.values().length)]); int classLevel = random.nextInt(Constant.NUMBER_OF_CLASSES + 5); int difficultSelect = random.nextInt(5); NewAndOldProblems newAndOldProblems = NewAndOldProblems.OnlyOld; PacketProblemMinimum problem = manager.selectProblem(genres, types, classLevel, difficultSelect, new HashSet<Integer>(), true, newAndOldProblems, false, new HashSet<Integer>(), new HashSet<Integer>()); assertNotNull(problem); if (!problem.isNew()) { ++numberOfOld; } } assertThat(numberOfOld, greaterThanOrEqualTo(SMALL_LOOP * 9 / 10)); } @Test public void testSelectProblemDuplicatedCreater() throws Exception { // 問題選択をLOOP回ランダムに行ってチェック for (int i = 0; i < SMALL_LOOP; ++i) { Set<Integer> problemIds = new HashSet<Integer>(); Set<Integer> userCodes = new HashSet<Integer>(); Set<Integer> createrHashes = new HashSet<Integer>(); Set<ProblemGenre> genres = EnumSet.of(ProblemGenre.Gakumon); Set<ProblemType> types = EnumSet.of(ProblemType.fromRandomFlag(2)); int classLevel = 0; int difficultSelect = 1 << Constant.DIFFICULT_SELECT_DIFFICULT; boolean first = true; NewAndOldProblems newAndOldProblems = NewAndOldProblems.Both; boolean tegaki = false; for (int numberOfProblems = 0; numberOfProblems < Constant.MAX_PROBLEMS_PER_SESSION; ++numberOfProblems) { PacketProblemMinimum problem = manager .selectProblem(genres, types, classLevel, difficultSelect, problemIds, first, newAndOldProblems, tegaki, userCodes, createrHashes); assertNotNull(problem); problemIds.add(problem.id); } assertEquals(problemIds.size(), Constant.MAX_PROBLEMS_PER_SESSION); assertThat(createrHashes.size()).isGreaterThan(Constant.MAX_PROBLEMS_PER_SESSION - 4); } } @Test public void testSelectProblemGenreType() throws Exception { Random random = new Random(0); for (int loop = 0; loop < SMALL_LOOP; ++loop) { Set<Integer> problemIds = new HashSet<Integer>(); Set<Integer> userCodes = new HashSet<Integer>(); Set<Integer> createrHashes = new HashSet<Integer>(); for (int problemCount = 0; problemCount < Constant.MAX_PROBLEMS_PER_SESSION; ++problemCount) { Set<ProblemGenre> genres; do { genres = ProblemGenre.fromBitFlag(random.nextInt(1 << ProblemGenre.values().length)); genres.remove(ProblemGenre.Random); } while (genres.isEmpty()); Set<ProblemType> types; do { types = ProblemType.fromBitFlag(random .nextInt(1 << ProblemType.numberOfTypesWithoutRandom)); types.remove(ProblemType.Random); } while (types.isEmpty() || types.equals(EnumSet.of(ProblemType.Tegaki))); int classLevel = random.nextInt(Constant.NUMBER_OF_CLASSES + 5); int difficultSelect = random.nextInt(5); PacketProblemMinimum problem = manager.selectProblem(genres, types, classLevel, difficultSelect, problemIds, true, NewAndOldProblems.Both, false, userCodes, createrHashes); assertNotNull(problem); assertTrue(genres.contains(problem.genre)); assertTrue("types=" + types + " should contain type=" + problem.type, types.contains(problem.type)); } } } }