彩票助手1.1

This commit is contained in:
lihanqi
2025-08-06 13:52:42 +08:00
parent ef8bcb14a3
commit fed8d868b9
15 changed files with 26 additions and 1773 deletions

View File

@@ -203,6 +203,7 @@ CREATE TABLE IF NOT EXISTS `predict_record` (
`redBall5` INT NOT NULL COMMENT '红5', `redBall5` INT NOT NULL COMMENT '红5',
`redBall6` INT NOT NULL COMMENT '红6', `redBall6` INT NOT NULL COMMENT '红6',
`blueBall` INT NOT NULL COMMENT '蓝球', `blueBall` INT NOT NULL COMMENT '蓝球',
`type` VARCHAR(100) NOT NULL COMMENT '预测类型(双色球/组六/大乐透)',
`predictStatus` VARCHAR(100) default '待开奖' NOT NULL COMMENT '预测状态(待开奖/已开奖)', `predictStatus` VARCHAR(100) default '待开奖' NOT NULL COMMENT '预测状态(待开奖/已开奖)',
`predictResult` VARCHAR(100) default '待开奖' NOT NULL COMMENT '预测结果(未中奖/三等奖/二等奖/一等奖)', `predictResult` VARCHAR(100) default '待开奖' NOT NULL COMMENT '预测结果(未中奖/三等奖/二等奖/一等奖)',
`predictTime` datetime default CURRENT_TIMESTAMP not null comment '预测时间', `predictTime` datetime default CURRENT_TIMESTAMP not null comment '预测时间',
@@ -221,14 +222,9 @@ CREATE TABLE IF NOT EXISTS `vip_code` (
usedUserId bigint null comment '使用人', usedUserId bigint null comment '使用人',
usedUserName varchar(36) null comment '使用人名称', usedUserName varchar(36) null comment '使用人名称',
`createTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '创建时间', `createTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '创建时间',
`updateTime` datetime NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `updateTime` datetime NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
PRIMARY KEY (`id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员码表';
UNIQUE KEY `Order_OrderNo_uindex` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员码表';
INSERT INTO `vip_code` (`id`, `code`, `vipExpireTime`, `vipNumber`, `isUse`, `createTime`, `updateTime`) VALUES
(1, 'A3B4C5D6E7F8G9H1', 1, '000001', 0, NOW(), NOW()),
(2, 'I2J3K4L5M6N7O8P9', 12, '000002', 0, NOW(), NOW());
CREATE TABLE IF NOT EXISTS `vip_exchange_record` ( CREATE TABLE IF NOT EXISTS `vip_exchange_record` (
@@ -241,7 +237,7 @@ CREATE TABLE IF NOT EXISTS `vip_exchange_record` (
`isUse` int NOT NULL COMMENT '是否兑换(未兑换/已兑换)', `isUse` int NOT NULL COMMENT '是否兑换(未兑换/已兑换)',
`exchangeTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '兑换时间', `exchangeTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '兑换时间',
`updateTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' `updateTime` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员兑换表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员兑换表';
CREATE TABLE IF NOT EXISTS `operation_history` ( CREATE TABLE IF NOT EXISTS `operation_history` (
`id` BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY, `id` BIGINT AUTO_INCREMENT COMMENT '唯一标识符' PRIMARY KEY,
@@ -252,7 +248,7 @@ CREATE TABLE IF NOT EXISTS `operation_history` (
`resultMessage` TEXT COMMENT '结果消息', `resultMessage` TEXT COMMENT '结果消息',
`operationTime` DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '操作时间', `operationTime` DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '操作时间',
`updateTime` DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' `updateTime` DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='操作历史记录表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作历史记录表';
CREATE TABLE IF NOT EXISTS `chat_message` CREATE TABLE IF NOT EXISTS `chat_message`

View File

@@ -3,6 +3,7 @@ package com.xy.xyaicpzs.exception;
import com.xy.xyaicpzs.common.ErrorCode; import com.xy.xyaicpzs.common.ErrorCode;
import com.xy.xyaicpzs.common.ResultUtils; import com.xy.xyaicpzs.common.ResultUtils;
import com.xy.xyaicpzs.common.response.ApiResponse; import com.xy.xyaicpzs.common.response.ApiResponse;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -10,7 +11,8 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
/** /**
* 全局异常处理器 * 全局异常处理器
*/ */
//@RestControllerAdvice @Hidden
@RestControllerAdvice
@Slf4j @Slf4j
public class GlobalExceptionHandler { public class GlobalExceptionHandler {

View File

@@ -4,24 +4,32 @@ spring:
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cpzs url: jdbc:mysql://localhost:3306/cpzs
username: root username: cpzs_root
password: root password: cpzs_123456
# datasource: # datasource:
# driver-class-name: com.mysql.cj.jdbc.Driver # driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://47.117.22.239:3306/cpzs # url: jdbc:mysql://47.117.22.239:3306/cpzs?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false&connectTimeout=10000&socketTimeout=30000
# username: cpzs_root # username: cpzs_root
# password: cpzs_123456 # password: cpzs_123456
data: # hikari:
redis: # connection-timeout: 30000 # 连接超时时间(毫秒)
host: localhost # idle-timeout: 600000 # 空闲连接存活最大时间(毫秒)
port: 6379 # maximum-pool-size: 10 # 连接池最大连接数
database: 0 # minimum-idle: 5 # 最小空闲连接数
# max-lifetime: 1800000 # 连接的最大生命周期(毫秒)
# auto-commit: true # 自动提交
# connection-test-query: SELECT 1 # 测试连接是否可用的查询语句
# data: # data:
# redis: # redis:
# host: 47.117.22.239 # host: localhost
# port: 6379 # port: 6379
# database: 0 # database: 0
# password: cpzs_123456 data:
redis:
host: 47.117.22.239
port: 6379
database: 0
password: cpzs_123456
server: server:
port: 8123 port: 8123
servlet: servlet:

View File

@@ -1,173 +0,0 @@
package com.xy.xyaicpzs;
import com.xy.xyaicpzs.mapper.T7Mapper;
import com.xy.xyaicpzs.service.BallAnalysisService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
/**
* 球号分析算法频次筛选测试
* 验证当频次相同的球号超过11个时使用T3表线系数进行二次筛选的功能
*/
@Slf4j
@SpringBootTest
public class BallAnalysisFrequencyTest {
@Autowired
private BallAnalysisService ballAnalysisService;
/**
* 测试高位算法的频次筛选功能
*/
@Test
public void testHighLevelFrequencySelection() {
log.info("=== 测试高位算法的频次筛选功能 ===");
// 输入参数
String level = "H";
List<Integer> redBalls = Arrays.asList(7, 24, 27, 21, 10, 5);
Integer blueBall = 16;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("高位算法结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
}
/**
* 测试中位算法的频次筛选功能
*/
@Test
public void testMiddleLevelFrequencySelection() {
log.info("=== 测试中位算法的频次筛选功能 ===");
// 输入参数
String level = "M";
List<Integer> redBalls = Arrays.asList(2, 9, 14, 20, 25, 32);
Integer blueBall = 12;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("中位算法结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
}
/**
* 测试低位算法的频次筛选功能
*/
@Test
public void testLowLevelFrequencySelection() {
log.info("=== 测试低位算法的频次筛选功能 ===");
// 输入参数
String level = "L";
List<Integer> redBalls = Arrays.asList(3, 7, 11, 17, 22, 29);
Integer blueBall = 8;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("低位算法结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
}
/**
* 测试用户提供的示例场景
* 模拟频次相同导致超过11个球号的情况
*/
@Test
public void testUserExampleScenario() {
log.info("=== 测试用户示例场景 ===");
log.info("模拟场景:");
log.info("26出现了8次 - 直接选择");
log.info("17出现了7次 - 直接选择");
log.info("14出现了7次 - 直接选择");
log.info("7出现了6次 - 直接选择");
log.info("3出现了6次 - 直接选择");
log.info("20出现了6次 - 直接选择");
log.info("2,9,1,22,32,13出现了5次 - 需要T3表线系数筛选");
// 使用特定的红球和蓝球组合来模拟这种情况
String level = "H";
List<Integer> redBalls = Arrays.asList(26, 17, 14, 7, 3, 20);
Integer blueBall = 2;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("示例场景结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("频次筛选测试完成!");
}
/**
* 测试边界情况恰好11个球号
*/
@Test
public void testExactly11Balls() {
log.info("=== 测试边界情况恰好11个球号 ===");
String level = "M";
List<Integer> redBalls = Arrays.asList(5, 10, 15, 18, 24, 30);
Integer blueBall = 6;
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
log.info("边界情况结果:{}", result);
assert result.size() == 11 : "结果应该包含11个球号";
}
/**
* 测试极端情况验证T3表线系数筛选的稳定性
*/
@Test
public void testT3LineCoefficientStability() {
log.info("=== 测试T3表线系数筛选的稳定性 ===");
String level = "H";
List<Integer> redBalls = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer blueBall = 1;
// 多次执行同样的分析,结果应该一致
List<Integer> result1 = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
List<Integer> result2 = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
log.info("第一次结果:{}", result1);
log.info("第二次结果:{}", result2);
assert result1.equals(result2) : "相同输入应该产生相同输出";
log.info("T3表线系数筛选稳定性测试通过");
}
}

View File

@@ -1,232 +0,0 @@
package com.xy.xyaicpzs;
import com.xy.xyaicpzs.service.BallAnalysisService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
/**
* 球号分析多级筛选测试
* 测试analyzeBalls方法的多级筛选功能
*/
@Slf4j
@SpringBootTest
public class BallAnalysisMultiLevelFilteringTest {
@Autowired
private BallAnalysisService ballAnalysisService;
/**
* 测试高位算法的多级筛选
*/
@Test
public void testHighLevelMultiLevelFiltering() {
log.info("=== 测试高位算法的多级筛选 ===");
// 输入参数
String level = "H";
List<Integer> redBalls = Arrays.asList(1, 5, 12, 18, 25, 33);
Integer blueBall = 8;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("高位算法多级筛选结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("高位算法多级筛选测试通过!");
}
/**
* 测试中位算法的多级筛选
*/
@Test
public void testMiddleLevelMultiLevelFiltering() {
log.info("=== 测试中位算法的多级筛选 ===");
// 输入参数
String level = "M";
List<Integer> redBalls = Arrays.asList(2, 8, 15, 22, 28, 31);
Integer blueBall = 12;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("中位算法多级筛选结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("中位算法多级筛选测试通过!");
}
/**
* 测试低位算法的多级筛选
*/
@Test
public void testLowLevelMultiLevelFiltering() {
log.info("=== 测试低位算法的多级筛选 ===");
// 输入参数
String level = "L";
List<Integer> redBalls = Arrays.asList(3, 9, 16, 23, 29, 32);
Integer blueBall = 4;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("低位算法多级筛选结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("低位算法多级筛选测试通过!");
}
/**
* 测试可能触发多级筛选的特殊情况
* 使用容易产生频率冲突的球号组合
*/
@Test
public void testSpecialCaseForMultiLevelFiltering() {
log.info("=== 测试可能触发多级筛选的特殊情况 ===");
// 输入参数 - 使用一些常见的球号,可能会产生更多的频率冲突
String level = "H";
List<Integer> redBalls = Arrays.asList(7, 14, 21, 28, 1, 8);
Integer blueBall = 16;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("特殊情况多级筛选结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("特殊情况多级筛选测试通过!");
}
/**
* 测试多次运行的一致性
* 验证随机选择部分的稳定性
*/
@Test
public void testConsistencyOfMultipleRuns() {
log.info("=== 测试多次运行的一致性 ===");
// 输入参数
String level = "M";
List<Integer> redBalls = Arrays.asList(6, 13, 20, 27, 2, 9);
Integer blueBall = 11;
// 执行多次分析
List<Integer> result1 = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
List<Integer> result2 = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
List<Integer> result3 = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("第1次结果{}", result1);
log.info("第2次结果{}", result2);
log.info("第3次结果{}", result3);
// 断言 - 每次结果都应该是11个不重复的球号
assert result1.size() == 11 : "第1次结果应该包含11个球号";
assert result2.size() == 11 : "第2次结果应该包含11个球号";
assert result3.size() == 11 : "第3次结果应该包含11个球号";
assert result1.stream().distinct().count() == result1.size() : "第1次结果不应该有重复的球号";
assert result2.stream().distinct().count() == result2.size() : "第2次结果不应该有重复的球号";
assert result3.stream().distinct().count() == result3.size() : "第3次结果不应该有重复的球号";
// 注意:由于有随机选择的部分,结果可能不完全相同,但大部分应该是相同的
log.info("多次运行一致性测试通过!");
}
/**
* 测试边界情况:所有球号频率都不同
*/
@Test
public void testBoundaryCase_AllDifferentFrequencies() {
log.info("=== 测试边界情况:所有球号频率都不同 ===");
// 输入参数 - 使用差异较大的球号,减少频率冲突
String level = "H";
List<Integer> redBalls = Arrays.asList(1, 11, 22, 33, 5, 15);
Integer blueBall = 1;
// 执行分析
List<Integer> result = ballAnalysisService.analyzeBalls(level, redBalls, blueBall);
// 验证结果
log.info("边界情况结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 11 : "结果应该包含11个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("边界情况测试通过!");
}
/**
* 测试三种级别算法的对比
*/
@Test
public void testAllLevelsComparison() {
log.info("=== 测试三种级别算法的对比 ===");
// 输入参数
List<Integer> redBalls = Arrays.asList(4, 10, 17, 24, 30, 6);
Integer blueBall = 14;
// 执行三种级别的分析
List<Integer> resultH = ballAnalysisService.analyzeBalls("H", redBalls, blueBall);
List<Integer> resultM = ballAnalysisService.analyzeBalls("M", redBalls, blueBall);
List<Integer> resultL = ballAnalysisService.analyzeBalls("L", redBalls, blueBall);
// 验证结果
log.info("高位算法结果:{}", resultH);
log.info("中位算法结果:{}", resultM);
log.info("低位算法结果:{}", resultL);
// 断言
assert resultH.size() == 11 : "高位算法结果应该包含11个球号";
assert resultM.size() == 11 : "中位算法结果应该包含11个球号";
assert resultL.size() == 11 : "低位算法结果应该包含11个球号";
assert resultH.stream().distinct().count() == resultH.size() : "高位算法结果不应该有重复的球号";
assert resultM.stream().distinct().count() == resultM.size() : "中位算法结果不应该有重复的球号";
assert resultL.stream().distinct().count() == resultL.size() : "低位算法结果不应该有重复的球号";
// 分析结果差异
log.info("高位与中位的交集:{}", resultH.stream().filter(resultM::contains).collect(java.util.stream.Collectors.toList()));
log.info("高位与低位的交集:{}", resultH.stream().filter(resultL::contains).collect(java.util.stream.Collectors.toList()));
log.info("中位与低位的交集:{}", resultM.stream().filter(resultL::contains).collect(java.util.stream.Collectors.toList()));
log.info("三种级别算法对比测试通过!");
}
}

View File

@@ -1,204 +0,0 @@
package com.xy.xyaicpzs;
import com.xy.xyaicpzs.service.BallAnalysisService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
/**
* 蓝球分析算法测试类
*/
@Slf4j
@SpringBootTest
public class BlueBallAnalysisTest {
@Autowired
private BallAnalysisService ballAnalysisService;
@Test
public void testBlueBallAnalysisHigh() {
log.info("=== 测试蓝球分析算法 - 高位算法 ===");
// 测试数据26 20 18 32 10 14
String level = "H";
List<Integer> predictedRedBalls = Arrays.asList(26, 20, 18, 32, 10, 14); // 6个预测红球
List<Integer> predictedBlueBalls = Arrays.asList(5, 8); // 2个预测蓝球
List<Integer> lastRedBalls = Arrays.asList(7, 24, 27, 21, 10, 5); // 6个上期红球
Integer lastBlueBall = 16; // 1个上期蓝球
log.info("输入参数:");
log.info("级别:{}", level);
log.info("预测红球:{}", predictedRedBalls);
log.info("预测蓝球:{}", predictedBlueBalls);
log.info("上期红球:{}", lastRedBalls);
log.info("上期蓝球:{}", lastBlueBall);
List<Integer> result = ballAnalysisService.blueBallAnalysis(
level, predictedRedBalls, predictedBlueBalls, lastRedBalls, lastBlueBall);
log.info("高位算法结果:{}", result);
// 验证结果
assert result != null : "结果不能为空";
assert result.size() <= 4 : "结果数量不能超过4个";
log.info("高位算法测试通过");
}
@Test
public void testBlueBallAnalysisMiddle() {
log.info("=== 测试蓝球分析算法 - 中位算法 ===");
// 测试数据
String level = "M";
List<Integer> predictedRedBalls = Arrays.asList(3, 9, 14, 21, 27, 32); // 6个预测红球
List<Integer> predictedBlueBalls = Arrays.asList(5, 11); // 2个预测蓝球
List<Integer> lastRedBalls = Arrays.asList(4, 10, 16, 22, 29, 30); // 6个上期红球
Integer lastBlueBall = 7; // 1个上期蓝球
log.info("输入参数:");
log.info("级别:{}", level);
log.info("预测红球:{}", predictedRedBalls);
log.info("预测蓝球:{}", predictedBlueBalls);
log.info("上期红球:{}", lastRedBalls);
log.info("上期蓝球:{}", lastBlueBall);
List<Integer> result = ballAnalysisService.blueBallAnalysis(
level, predictedRedBalls, predictedBlueBalls, lastRedBalls, lastBlueBall);
log.info("中位算法结果:{}", result);
// 验证结果
assert result != null : "结果不能为空";
assert result.size() <= 4 : "结果数量不能超过4个";
log.info("中位算法测试通过");
}
@Test
public void testBlueBallAnalysisLow() {
log.info("=== 测试蓝球分析算法 - 低位算法 ===");
// 测试数据
String level = "L";
List<Integer> predictedRedBalls = Arrays.asList(6, 11, 17, 23, 26, 33); // 6个预测红球
List<Integer> predictedBlueBalls = Arrays.asList(2, 14); // 2个预测蓝球
List<Integer> lastRedBalls = Arrays.asList(1, 8, 13, 19, 24, 32); // 6个上期红球
Integer lastBlueBall = 16; // 1个上期蓝球
log.info("输入参数:");
log.info("级别:{}", level);
log.info("预测红球:{}", predictedRedBalls);
log.info("预测蓝球:{}", predictedBlueBalls);
log.info("上期红球:{}", lastRedBalls);
log.info("上期蓝球:{}", lastBlueBall);
List<Integer> result = ballAnalysisService.blueBallAnalysis(
level, predictedRedBalls, predictedBlueBalls, lastRedBalls, lastBlueBall);
log.info("低位算法结果:{}", result);
// 验证结果
assert result != null : "结果不能为空";
assert result.size() <= 4 : "结果数量不能超过4个";
log.info("低位算法测试通过");
}
@Test
public void testBlueBallAnalysisAllLevels() {
log.info("=== 测试蓝球分析算法 - 三种级别对比 ===");
// 相同的测试数据
List<Integer> predictedRedBalls = Arrays.asList(7, 12, 18, 24, 29, 33); // 6个预测红球
List<Integer> predictedBlueBalls = Arrays.asList(4, 9); // 2个预测蓝球
List<Integer> lastRedBalls = Arrays.asList(3, 8, 14, 20, 25, 31); // 6个上期红球
Integer lastBlueBall = 6; // 1个上期蓝球
log.info("使用相同输入测试三种级别算法:");
log.info("预测红球:{}", predictedRedBalls);
log.info("预测蓝球:{}", predictedBlueBalls);
log.info("上期红球:{}", lastRedBalls);
log.info("上期蓝球:{}", lastBlueBall);
// 高位算法
List<Integer> highResult = ballAnalysisService.blueBallAnalysis(
"H", predictedRedBalls, predictedBlueBalls, lastRedBalls, lastBlueBall);
log.info("高位算法结果:{}", highResult);
// 中位算法
List<Integer> middleResult = ballAnalysisService.blueBallAnalysis(
"M", predictedRedBalls, predictedBlueBalls, lastRedBalls, lastBlueBall);
log.info("中位算法结果:{}", middleResult);
// 低位算法
List<Integer> lowResult = ballAnalysisService.blueBallAnalysis(
"L", predictedRedBalls, predictedBlueBalls, lastRedBalls, lastBlueBall);
log.info("低位算法结果:{}", lowResult);
// 验证结果
assert highResult != null && highResult.size() <= 4 : "高位算法结果异常";
assert middleResult != null && middleResult.size() <= 4 : "中位算法结果异常";
assert lowResult != null && lowResult.size() <= 4 : "低位算法结果异常";
log.info("三种级别算法对比测试通过");
}
@Test
public void testBlueBallAnalysisParameterValidation() {
log.info("=== 测试蓝球分析算法 - 参数验证 ===");
// 测试无效级别
try {
ballAnalysisService.blueBallAnalysis(
"X", Arrays.asList(1, 2, 3, 4, 5, 6), Arrays.asList(1, 2),
Arrays.asList(7, 8, 9, 10, 11, 12), 1);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("无效级别测试通过:{}", e.getMessage());
}
// 测试预测红球数量错误
try {
ballAnalysisService.blueBallAnalysis(
"H", Arrays.asList(1, 2, 3, 4, 5), Arrays.asList(1, 2),
Arrays.asList(7, 8, 9, 10, 11, 12), 1);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("预测红球数量错误测试通过:{}", e.getMessage());
}
// 测试预测蓝球数量错误
try {
ballAnalysisService.blueBallAnalysis(
"H", Arrays.asList(1, 2, 3, 4, 5, 6), Arrays.asList(1),
Arrays.asList(7, 8, 9, 10, 11, 12), 1);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("预测蓝球数量错误测试通过:{}", e.getMessage());
}
// 测试红球号码超出范围
try {
ballAnalysisService.blueBallAnalysis(
"H", Arrays.asList(1, 2, 3, 4, 5, 34), Arrays.asList(1, 2),
Arrays.asList(7, 8, 9, 10, 11, 12), 1);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("红球号码超出范围测试通过:{}", e.getMessage());
}
// 测试蓝球号码超出范围
try {
ballAnalysisService.blueBallAnalysis(
"H", Arrays.asList(1, 2, 3, 4, 5, 6), Arrays.asList(1, 17),
Arrays.asList(7, 8, 9, 10, 11, 12), 1);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("蓝球号码超出范围测试通过:{}", e.getMessage());
}
log.info("参数验证测试全部通过");
}
}

View File

@@ -1,77 +0,0 @@
package com.xy.xyaicpzs;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 小数精度处理测试类
*/
@SpringBootTest
public class DecimalPrecisionTest {
/**
* 测试小数位数处理方法
*/
@Test
public void testDecimalPrecision() {
System.out.println("=== 小数位数处理测试 ===");
// 测试数据
double[] testValues = {
123.456789, // 多位小数
12.1, // 一位小数
5.0, // 整数
0.999, // 四舍五入测试
0.001, // 小数点后多位
99.999 // 进位测试
};
for (double value : testValues) {
Double result = roundToTwoDecimalPlaces(value);
System.out.printf("原值:%f → 结果:%.2f%n", value, result);
}
}
/**
* 将数值保留两位小数的辅助方法与ExcelDataImporter中的方法相同
*/
private Double roundToTwoDecimalPlaces(double value) {
if (Double.isNaN(value) || Double.isInfinite(value)) {
return null;
}
try {
BigDecimal bd = new BigDecimal(Double.toString(value));
return bd.setScale(2, RoundingMode.HALF_UP).doubleValue();
} catch (Exception e) {
System.err.println("数值格式化失败:" + value);
return value;
}
}
/**
* 测试边界情况
*/
@Test
public void testEdgeCases() {
System.out.println("=== 边界情况测试 ===");
// 测试特殊值
double[] edgeCases = {
Double.NaN,
Double.POSITIVE_INFINITY,
Double.NEGATIVE_INFINITY,
0.0,
-0.0,
-123.456
};
for (double value : edgeCases) {
Double result = roundToTwoDecimalPlaces(value);
System.out.printf("特殊值:%f → 结果:%s%n", value, result);
}
}
}

View File

@@ -1,63 +0,0 @@
package com.xy.xyaicpzs;
import com.xy.xyaicpzs.service.ExcelImportService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* Excel导入功能测试类
*/
@SpringBootTest
public class ExcelImportTest {
@Autowired
private ExcelImportService excelImportService;
/**
* 测试通过文件路径导入Excel数据
* 需要将kaifa1.xlsx文件放在项目根目录下
* 现在会同时导入T1(红球)和T2(蓝球)的数据
*/
@Test
public void testImportExcelByPath() {
// 假设Excel文件在项目根目录下
String filePath = "kaifa1.xlsx";
try {
String result = excelImportService.importExcelFileByPath(filePath);
System.out.println("导入结果:" + result);
System.out.println("注意系统会自动导入T1红球、T2蓝球、T3红球线系数、T4蓝球组红球线系数、T5蓝球组蓝球线系数、T6红球组蓝球线系数和T7红球组红球面系数七个工作表的数据");
} catch (Exception e) {
System.err.println("导入失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 测试导入绝对路径的Excel文件
* 请根据实际情况修改文件路径
* 现在会同时导入T1(红球)和T2(蓝球)的数据
*/
@Test
public void testImportExcelByAbsolutePath() {
// 请根据实际情况修改文件路径
String filePath = "D:/code/xy-ai-cpzs/kaifa1.xlsx";
try {
String result = excelImportService.importExcelFileByPath(filePath);
System.out.println("导入结果:" + result);
System.out.println("数据导入详情:");
System.out.println("- T1工作表 → 红球数据表history_all, history_100, history_top, history_top_100");
System.out.println("- T2工作表 → 蓝球数据表blue_history_all, blue_history_100, blue_history_top, blue_history_top_100");
System.out.println("- T3工作表 → 红球线系数表t333×33=1089条记录");
System.out.println("- T4工作表 → 蓝球组红球线系数表t416×33=528条记录");
System.out.println("- T5工作表 → 蓝球组蓝球线系数表t516×16=256条记录");
System.out.println("- T6工作表 → 红球组蓝球线系数表t633×16=528条记录");
System.out.println("- T7工作表 → 红球组红球面系数表t733×32=1056条记录排除自己组合");
} catch (Exception e) {
System.err.println("导入失败:" + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -1,245 +0,0 @@
package com.xy.xyaicpzs;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xy.xyaicpzs.common.requset.FallowBallAnalysisRequest;
import com.xy.xyaicpzs.controller.BallAnalysisController;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import java.util.Arrays;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
/**
* 跟随球号分析API接口测试
* 测试REST API的功能和响应
*/
@Slf4j
@SpringBootTest
@AutoConfigureMockMvc
public class FallowBallAnalysisApiTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
/**
* 测试表单参数方式的跟随球号分析接口
*/
@Test
public void testFallowBallAnalysisWithFormParams() throws Exception {
log.info("=== 测试表单参数方式的跟随球号分析接口 ===");
mockMvc.perform(post("/api/ball-analysis/fallow")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("level", "H")
.param("firstThreeRedBalls", "7,24,27")
.param("lastSixRedBalls", "21,10,5,15,23,28")
.param("blueBall", "16"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(8));
log.info("表单参数方式测试通过!");
}
/**
* 测试JSON请求体方式的跟随球号分析接口
*/
@Test
public void testFallowBallAnalysisWithJsonBody() throws Exception {
log.info("=== 测试JSON请求体方式的跟随球号分析接口 ===");
// 构建请求对象
FallowBallAnalysisRequest request =
new FallowBallAnalysisRequest();
request.setLevel("M");
request.setFirstThreeRedBalls(Arrays.asList(26, 31, 28));
request.setLastSixRedBalls(Arrays.asList(7, 24, 27, 21, 10, 5));
request.setBlueBall(16);
String requestJson = objectMapper.writeValueAsString(request);
log.info("请求JSON: {}", requestJson);
mockMvc.perform(post("/api/ball-analysis/fallow-json")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(8));
log.info("JSON请求体方式测试通过");
}
/**
* 测试获取算法说明接口
*/
@Test
public void testGetFallowAlgorithmInfo() throws Exception {
log.info("=== 测试获取算法说明接口 ===");
mockMvc.perform(get("/api/ball-analysis/fallow-info"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data").isString())
.andExpect(jsonPath("$.data").value(org.hamcrest.Matchers.containsString("跟随球号分析算法说明")));
log.info("获取算法说明接口测试通过!");
}
/**
* 测试不同级别的算法
*/
@Test
public void testAllLevelsWithJsonBody() throws Exception {
log.info("=== 测试不同级别的算法 ===");
String[] levels = {"H", "M", "L"};
for (String level : levels) {
log.info("测试{}级别算法", level);
// 构建请求对象
FallowBallAnalysisRequest request =
new FallowBallAnalysisRequest();
request.setLevel(level);
request.setFirstThreeRedBalls(Arrays.asList(1, 15, 23));
request.setLastSixRedBalls(Arrays.asList(28, 31, 33, 2, 8, 12));
request.setBlueBall(8);
String requestJson = objectMapper.writeValueAsString(request);
mockMvc.perform(post("/api/ball-analysis/fallow-json")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(8));
log.info("{}级别算法测试通过!", level);
}
}
/**
* 测试参数验证 - 错误的级别
*/
@Test
public void testInvalidLevel() throws Exception {
log.info("=== 测试参数验证 - 错误的级别 ===");
mockMvc.perform(post("/api/ball-analysis/fallow")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("level", "X") // 错误的级别
.param("firstThreeRedBalls", "7,24,27")
.param("lastSixRedBalls", "21,10,5,15,23,28")
.param("blueBall", "16"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("级别必须为H、M或L")));
log.info("错误级别参数验证测试通过!");
}
/**
* 测试参数验证 - 前3个红球数量错误
*/
@Test
public void testInvalidFirstThreeRedBalls() throws Exception {
log.info("=== 测试参数验证 - 前3个红球数量错误 ===");
mockMvc.perform(post("/api/ball-analysis/fallow")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("level", "H")
.param("firstThreeRedBalls", "7,24") // 只有2个球应该是3个
.param("lastSixRedBalls", "21,10,5,15,23,28")
.param("blueBall", "16"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("前3个红球数量必须为3个")));
log.info("前3个红球数量错误参数验证测试通过");
}
/**
* 测试参数验证 - 后6个红球数量错误
*/
@Test
public void testInvalidLastSixRedBalls() throws Exception {
log.info("=== 测试参数验证 - 后6个红球数量错误 ===");
mockMvc.perform(post("/api/ball-analysis/fallow")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("level", "H")
.param("firstThreeRedBalls", "7,24,27")
.param("lastSixRedBalls", "21,10,5,15,23") // 只有5个球应该是6个
.param("blueBall", "16"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("后6个红球数量必须为6个")));
log.info("后6个红球数量错误参数验证测试通过");
}
/**
* 测试参数验证 - 红球号码超出范围
*/
@Test
public void testRedBallOutOfRange() throws Exception {
log.info("=== 测试参数验证 - 红球号码超出范围 ===");
mockMvc.perform(post("/api/ball-analysis/fallow")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("level", "H")
.param("firstThreeRedBalls", "7,24,35") // 35超出范围
.param("lastSixRedBalls", "21,10,5,15,23,28")
.param("blueBall", "16"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString("前3个红球号码必须在1-33范围内")));
log.info("红球号码超出范围参数验证测试通过!");
}
/**
* 测试边界情况 - 前3个红球和后6个红球有重叠
*/
@Test
public void testOverlappingRedBalls() throws Exception {
log.info("=== 测试边界情况 - 前3个红球和后6个红球有重叠 ===");
// 前3个红球和后6个红球有重叠是允许的
mockMvc.perform(post("/api/ball-analysis/fallow")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("level", "H")
.param("firstThreeRedBalls", "7,24,27")
.param("lastSixRedBalls", "7,24,5,15,23,28") // 7和24重叠
.param("blueBall", "16"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(8));
log.info("前3个红球和后6个红球重叠测试通过");
}
}

View File

@@ -1,250 +0,0 @@
package com.xy.xyaicpzs;
import com.xy.xyaicpzs.service.BallAnalysisService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
/**
* fallowBallAnalysis方法多级筛选功能测试
* 测试T7面系数筛选后的多级筛选机制
* 1. T7面系数总和筛选
* 2. history_top_100排名筛选
* 3. history_top点系数筛选
* 4. 随机选择
*/
@Slf4j
@SpringBootTest
public class FallowBallAnalysisMultiLevelFilteringTest {
@Autowired
private BallAnalysisService ballAnalysisService;
/**
* 测试高级算法的多级筛选
*/
@Test
public void testHighLevelMultiLevelFiltering() {
log.info("=== 测试fallowBallAnalysis高级算法多级筛选 ===");
// 使用可能触发多级筛选的输入
List<Integer> firstThreeRedBalls = Arrays.asList(1, 2, 3);
List<Integer> lastSixRedBalls = Arrays.asList(10, 15, 20, 25, 30, 33);
Integer blueBall = 5;
List<Integer> result = ballAnalysisService.fallowBallAnalysis("H", firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("高级算法结果:{}", result);
// 验证结果
assert result != null : "结果不能为null";
assert result.size() == 8 : "结果应该包含8个球号实际" + result.size();
// 验证球号范围
for (Integer ball : result) {
assert ball >= 1 && ball <= 33 : "球号应该在1-33范围内实际" + ball;
}
// 验证无重复
assert result.stream().distinct().count() == result.size() : "结果不应该有重复球号";
log.info("高级算法多级筛选测试通过");
}
/**
* 测试中级算法的多级筛选
*/
@Test
public void testMiddleLevelMultiLevelFiltering() {
log.info("=== 测试fallowBallAnalysis中级算法多级筛选 ===");
List<Integer> firstThreeRedBalls = Arrays.asList(5, 8, 12);
List<Integer> lastSixRedBalls = Arrays.asList(14, 18, 22, 26, 29, 32);
Integer blueBall = 8;
List<Integer> result = ballAnalysisService.fallowBallAnalysis("M", firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("中级算法结果:{}", result);
// 验证结果
assert result != null : "结果不能为null";
assert result.size() == 8 : "结果应该包含8个球号实际" + result.size();
// 验证球号范围
for (Integer ball : result) {
assert ball >= 1 && ball <= 33 : "球号应该在1-33范围内实际" + ball;
}
// 验证无重复
assert result.stream().distinct().count() == result.size() : "结果不应该有重复球号";
log.info("中级算法多级筛选测试通过");
}
/**
* 测试低级算法的多级筛选
*/
@Test
public void testLowLevelMultiLevelFiltering() {
log.info("=== 测试fallowBallAnalysis低级算法多级筛选 ===");
List<Integer> firstThreeRedBalls = Arrays.asList(7, 11, 16);
List<Integer> lastSixRedBalls = Arrays.asList(19, 21, 24, 27, 31, 33);
Integer blueBall = 12;
List<Integer> result = ballAnalysisService.fallowBallAnalysis("L", firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("低级算法结果:{}", result);
// 验证结果
assert result != null : "结果不能为null";
assert result.size() == 8 : "结果应该包含8个球号实际" + result.size();
// 验证球号范围
for (Integer ball : result) {
assert ball >= 1 && ball <= 33 : "球号应该在1-33范围内实际" + ball;
}
// 验证无重复
assert result.stream().distinct().count() == result.size() : "结果不应该有重复球号";
log.info("低级算法多级筛选测试通过");
}
/**
* 测试可能触发多级筛选的特殊情况
*/
@Test
public void testSpecialCasesForMultiLevelFiltering() {
log.info("=== 测试fallowBallAnalysis特殊情况多级筛选 ===");
// 使用连续数字,可能产生相同的面系数
List<Integer> firstThreeRedBalls = Arrays.asList(1, 2, 3);
List<Integer> lastSixRedBalls = Arrays.asList(4, 5, 6, 7, 8, 9);
Integer blueBall = 1;
List<Integer> result = ballAnalysisService.fallowBallAnalysis("H", firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("特殊情况结果:{}", result);
// 验证结果
assert result != null : "结果不能为null";
assert result.size() == 8 : "结果应该包含8个球号实际" + result.size();
// 验证球号范围
for (Integer ball : result) {
assert ball >= 1 && ball <= 33 : "球号应该在1-33范围内实际" + ball;
}
// 验证无重复
assert result.stream().distinct().count() == result.size() : "结果不应该有重复球号";
log.info("特殊情况多级筛选测试通过");
}
/**
* 测试多次运行的一致性(在相同输入下)
*/
@Test
public void testConsistencyAcrossMultipleRuns() {
log.info("=== 测试fallowBallAnalysis多次运行一致性 ===");
List<Integer> firstThreeRedBalls = Arrays.asList(6, 13, 17);
List<Integer> lastSixRedBalls = Arrays.asList(20, 23, 25, 28, 30, 32);
Integer blueBall = 10;
// 运行多次并比较结果
List<Integer> result1 = ballAnalysisService.fallowBallAnalysis("M", firstThreeRedBalls, lastSixRedBalls, blueBall);
List<Integer> result2 = ballAnalysisService.fallowBallAnalysis("M", firstThreeRedBalls, lastSixRedBalls, blueBall);
List<Integer> result3 = ballAnalysisService.fallowBallAnalysis("M", firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("第1次结果{}", result1);
log.info("第2次结果{}", result2);
log.info("第3次结果{}", result3);
// 验证所有结果都有效
for (List<Integer> result : Arrays.asList(result1, result2, result3)) {
assert result != null : "结果不能为null";
assert result.size() == 8 : "结果应该包含8个球号";
assert result.stream().distinct().count() == result.size() : "结果不应该有重复球号";
}
// 注意:由于最后一级是随机选择,结果可能不完全一致
// 但前面几级的筛选应该是确定性的
log.info("多次运行一致性测试完成(注意:最后一级随机选择可能导致结果不同)");
}
/**
* 测试边界情况
*/
@Test
public void testBoundaryCases() {
log.info("=== 测试fallowBallAnalysis边界情况 ===");
// 测试最小值
List<Integer> firstThreeRedBalls = Arrays.asList(1, 2, 3);
List<Integer> lastSixRedBalls = Arrays.asList(4, 5, 6, 7, 8, 9);
Integer blueBall = 1;
List<Integer> result1 = ballAnalysisService.fallowBallAnalysis("L", firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("最小值边界结果:{}", result1);
// 测试最大值
List<Integer> firstThreeRedBalls2 = Arrays.asList(31, 32, 33);
List<Integer> lastSixRedBalls2 = Arrays.asList(25, 26, 27, 28, 29, 30);
Integer blueBall2 = 16;
List<Integer> result2 = ballAnalysisService.fallowBallAnalysis("H", firstThreeRedBalls2, lastSixRedBalls2, blueBall2);
log.info("最大值边界结果:{}", result2);
// 验证结果
for (List<Integer> result : Arrays.asList(result1, result2)) {
assert result != null : "结果不能为null";
assert result.size() == 8 : "结果应该包含8个球号";
assert result.stream().distinct().count() == result.size() : "结果不应该有重复球号";
for (Integer ball : result) {
assert ball >= 1 && ball <= 33 : "球号应该在1-33范围内实际" + ball;
}
}
log.info("边界情况测试通过");
}
/**
* 测试三种级别算法的比较
*/
@Test
public void testComparisonBetweenLevels() {
log.info("=== 测试fallowBallAnalysis三种级别算法比较 ===");
List<Integer> firstThreeRedBalls = Arrays.asList(9, 14, 18);
List<Integer> lastSixRedBalls = Arrays.asList(21, 24, 26, 29, 31, 33);
Integer blueBall = 7;
List<Integer> highResult = ballAnalysisService.fallowBallAnalysis("H", firstThreeRedBalls, lastSixRedBalls, blueBall);
List<Integer> midResult = ballAnalysisService.fallowBallAnalysis("M", firstThreeRedBalls, lastSixRedBalls, blueBall);
List<Integer> lowResult = ballAnalysisService.fallowBallAnalysis("L", firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("高级算法结果:{}", highResult);
log.info("中级算法结果:{}", midResult);
log.info("低级算法结果:{}", lowResult);
// 验证所有结果都有效
for (List<Integer> result : Arrays.asList(highResult, midResult, lowResult)) {
assert result != null : "结果不能为null";
assert result.size() == 8 : "结果应该包含8个球号";
assert result.stream().distinct().count() == result.size() : "结果不应该有重复球号";
for (Integer ball : result) {
assert ball >= 1 && ball <= 33 : "球号应该在1-33范围内实际" + ball;
}
}
log.info("三种级别算法比较测试通过");
}
}

View File

@@ -1,291 +0,0 @@
package com.xy.xyaicpzs;
import com.xy.xyaicpzs.service.BallAnalysisService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
/**
* 跟随球号分析算法测试
* 验证fallowBallAnalysis方法的功能
*/
@Slf4j
@SpringBootTest
public class FallowBallAnalysisTest {
@Autowired
private BallAnalysisService ballAnalysisService;
/**
* 测试高位算法的跟随球号分析
*/
@Test
public void testHighLevelFallowBallAnalysis() {
log.info("=== 测试高位算法的跟随球号分析 ===");
// 输入参数
String level = "H";
List<Integer> firstThreeRedBalls = Arrays.asList(26, 31, 28); // 前3个红球独立的
List<Integer> lastSixRedBalls = Arrays.asList(7, 24, 27, 21, 10, 5);; // 后6个红球独立的
Integer blueBall = 16;
// 执行分析
List<Integer> result = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
// 验证结果
log.info("高位算法结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 8 : "结果应该包含8个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("高位算法测试通过!");
}
/**
* 测试中位算法的跟随球号分析
*/
@Test
public void testMiddleLevelFallowBallAnalysis() {
log.info("=== 测试中位算法的跟随球号分析 ===");
// 输入参数
String level = "M";
List<Integer> firstThreeRedBalls = Arrays.asList(2, 9, 14); // 前3个红球独立的
List<Integer> lastSixRedBalls = Arrays.asList(20, 25, 32, 1, 15, 23); // 后6个红球独立的
Integer blueBall = 12;
// 执行分析
List<Integer> result = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
// 验证结果
log.info("中位算法结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 8 : "结果应该包含8个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("中位算法测试通过!");
}
/**
* 测试低位算法的跟随球号分析
*/
@Test
public void testLowLevelFallowBallAnalysis() {
log.info("=== 测试低位算法的跟随球号分析 ===");
// 输入参数
String level = "L";
List<Integer> firstThreeRedBalls = Arrays.asList(3, 7, 11); // 前3个红球独立的
List<Integer> lastSixRedBalls = Arrays.asList(17, 22, 29, 4, 8, 13); // 后6个红球独立的
Integer blueBall = 8;
// 执行分析
List<Integer> result = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
// 验证结果
log.info("低位算法结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 8 : "结果应该包含8个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("低位算法测试通过!");
}
/**
* 测试参数验证功能
*/
@Test
public void testParameterValidation() {
log.info("=== 测试参数验证功能 ===");
String level = "H";
List<Integer> validFirstThree = Arrays.asList(1, 2, 3);
List<Integer> validLastSix = Arrays.asList(4, 5, 6, 7, 8, 9);
Integer validBlueBall = 1;
// 测试前3个红球数量错误
try {
ballAnalysisService.fallowBallAnalysis(level, Arrays.asList(1, 2), validLastSix, validBlueBall);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("前3个红球数量验证通过{}", e.getMessage());
}
// 测试后6个红球数量错误
try {
ballAnalysisService.fallowBallAnalysis(level, validFirstThree, Arrays.asList(1, 2, 3, 4, 5), validBlueBall);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("后6个红球数量验证通过{}", e.getMessage());
}
// 测试红球范围错误
try {
ballAnalysisService.fallowBallAnalysis(level, Arrays.asList(1, 2, 34), validLastSix, validBlueBall);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("红球范围验证通过:{}", e.getMessage());
}
// 测试蓝球范围错误
try {
ballAnalysisService.fallowBallAnalysis(level, validFirstThree, validLastSix, 17);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("蓝球范围验证通过:{}", e.getMessage());
}
// 测试前3个红球重复
try {
ballAnalysisService.fallowBallAnalysis(level, Arrays.asList(1, 1, 3), validLastSix, validBlueBall);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("前3个红球重复验证通过{}", e.getMessage());
}
// 测试后6个红球重复
try {
ballAnalysisService.fallowBallAnalysis(level, validFirstThree, Arrays.asList(4, 5, 6, 7, 8, 8), validBlueBall);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("后6个红球重复验证通过{}", e.getMessage());
}
// 测试级别错误
try {
ballAnalysisService.fallowBallAnalysis("X", validFirstThree, validLastSix, validBlueBall);
assert false : "应该抛出异常";
} catch (IllegalArgumentException e) {
log.info("级别验证通过:{}", e.getMessage());
}
log.info("参数验证测试全部通过!");
}
/**
* 测试数据收集的完整性
*/
@Test
public void testDataCollectionCompleteness() {
log.info("=== 测试数据收集的完整性 ===");
String level = "H";
List<Integer> firstThreeRedBalls = Arrays.asList(1, 2, 3);
List<Integer> lastSixRedBalls = Arrays.asList(4, 5, 6, 7, 8, 9);
Integer blueBall = 1;
List<Integer> result = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("数据收集完整性测试结果:{}", result);
// 验证数据收集的逻辑
// 第1个红球从T7表获取10个数字
// 后6个红球每个从T3表获取26个数字共6*26=156个数字
// history_top_100表获取3个数字
// 前3个红球的后两个共2个数字
// 蓝球从T4表获取10个数字
// 总计10 + 156 + 3 + 2 + 10 = 181个数字
log.info("预期数据收集10(T7) + 156(T3) + 3(history_top_100) + 2(前3红球后2个) + 10(T4) = 181个数字");
log.info("数据收集完整性测试通过!");
}
/**
* 测试算法稳定性
*/
@Test
public void testAlgorithmStability() {
log.info("=== 测试算法稳定性 ===");
String level = "M";
List<Integer> firstThreeRedBalls = Arrays.asList(5, 10, 15);
List<Integer> lastSixRedBalls = Arrays.asList(18, 24, 30, 12, 19, 26);
Integer blueBall = 6;
// 多次执行同样的分析,结果应该一致
List<Integer> result1 = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
List<Integer> result2 = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("第一次结果:{}", result1);
log.info("第二次结果:{}", result2);
assert result1.equals(result2) : "相同输入应该产生相同输出";
log.info("算法稳定性测试通过!");
}
/**
* 测试边界情况
*/
@Test
public void testBoundaryConditions() {
log.info("=== 测试边界情况 ===");
// 测试最小值边界
String level = "L";
List<Integer> firstThreeRedBalls = Arrays.asList(1, 2, 3);
List<Integer> lastSixRedBalls = Arrays.asList(4, 5, 6, 7, 8, 9);
Integer blueBall = 1;
List<Integer> result1 = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("最小值边界测试结果:{}", result1);
// 测试最大值边界
firstThreeRedBalls = Arrays.asList(31, 32, 33);
lastSixRedBalls = Arrays.asList(25, 26, 27, 28, 29, 30);
blueBall = 16;
List<Integer> result2 = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
log.info("最大值边界测试结果:{}", result2);
// 验证结果
assert result1.size() == 8 : "最小值边界结果应该包含8个球号";
assert result2.size() == 8 : "最大值边界结果应该包含8个球号";
log.info("边界情况测试通过!");
}
/**
* 测试用户提供的示例场景
* 模拟频次相同导致超过8个球号的情况
*/
@Test
public void testUserExampleScenario() {
log.info("=== 测试用户示例场景 ===");
log.info("模拟场景:");
log.info("当频次相同的球号超过8个时");
log.info("使用T7表面系数总和进行二次筛选");
// 使用特定的红球和蓝球组合来模拟这种情况
String level = "H";
List<Integer> firstThreeRedBalls = Arrays.asList(26, 31, 28);
List<Integer> lastSixRedBalls = Arrays.asList(7, 24, 27, 21, 10, 5);
Integer blueBall = 16;
// 执行分析
List<Integer> result = ballAnalysisService.fallowBallAnalysis(level, firstThreeRedBalls, lastSixRedBalls, blueBall);
// 验证结果
log.info("示例场景结果:{}", result);
log.info("结果数量:{}", result.size());
// 断言
assert result.size() == 8 : "结果应该包含8个球号";
assert result.stream().allMatch(ball -> ball >= 1 && ball <= 33) : "所有球号应该在1-33范围内";
assert result.stream().distinct().count() == result.size() : "不应该有重复的球号";
log.info("频次筛选测试完成!");
}
}

View File

@@ -1,126 +0,0 @@
package com.xy.xyaicpzs;
import com.xy.xyaicpzs.service.VipCodeService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import jakarta.annotation.Resource;
/**
* 生成会员码功能测试
*/
@Slf4j
@SpringBootTest
@ActiveProfiles("test")
public class GenerateVipCodesTest {
@Resource
private VipCodeService vipCodeService;
@Test
public void testGenerateVipCodes() {
try {
// 测试生成10个1个月的会员码
int numCodes = 10;
int vipExpireTime = 1;
log.info("开始测试生成会员码功能,数量:{},有效月数:{}", numCodes, vipExpireTime);
int result = vipCodeService.generateVipCodes(numCodes, vipExpireTime);
log.info("生成会员码测试结果:{}", result);
} catch (Exception e) {
log.error("生成会员码测试失败:{}", e.getMessage(), e);
}
}
@Test
public void testGenerateVipCodesWithLargeQuantity() {
try {
// 测试生成50个12个月的会员码
int numCodes = 50;
int vipExpireTime = 12;
log.info("开始测试大批量生成会员码功能,数量:{},有效月数:{}", numCodes, vipExpireTime);
int result = vipCodeService.generateVipCodes(numCodes, vipExpireTime);
log.info("大批量生成会员码测试结果:{}", result);
} catch (Exception e) {
log.error("大批量生成会员码测试失败:{}", e.getMessage(), e);
}
}
@Test
public void testGenerateVipCodesWithInvalidParams() {
try {
// 测试无效参数
int numCodes = -1;
int vipExpireTime = 1;
log.info("开始测试无效参数的会员码生成,数量:{},有效月数:{}", numCodes, vipExpireTime);
vipCodeService.generateVipCodes(numCodes, vipExpireTime);
} catch (IllegalArgumentException e) {
log.info("预期的异常:{}", e.getMessage());
} catch (Exception e) {
log.error("意外的异常:{}", e.getMessage(), e);
}
}
@Test
public void testGetAvailableVipCode() {
try {
// 测试获取1个月的可用会员码
int vipExpireTime = 1;
log.info("开始测试获取可用会员码功能,有效月数:{}", vipExpireTime);
String code = vipCodeService.getAvailableVipCode(vipExpireTime);
log.info("获取可用会员码测试结果:{}", code);
} catch (Exception e) {
log.error("获取可用会员码测试失败:{}", e.getMessage(), e);
}
}
@Test
public void testGetAvailableVipCodeWith12Months() {
try {
// 测试获取12个月的可用会员码
int vipExpireTime = 12;
log.info("开始测试获取12个月可用会员码功能有效月数{}", vipExpireTime);
String code = vipCodeService.getAvailableVipCode(vipExpireTime);
log.info("获取12个月可用会员码测试结果{}", code);
} catch (Exception e) {
log.error("获取12个月可用会员码测试失败{}", e.getMessage(), e);
}
}
@Test
public void testGetAvailableVipCodeWithInvalidMonth() {
try {
// 测试无效的月数参数
int vipExpireTime = 6;
log.info("开始测试无效月数参数的获取可用会员码,有效月数:{}", vipExpireTime);
vipCodeService.getAvailableVipCode(vipExpireTime);
} catch (IllegalArgumentException e) {
log.info("预期的异常:{}", e.getMessage());
} catch (Exception e) {
log.error("意外的异常:{}", e.getMessage(), e);
}
}
}

View File

@@ -1,76 +0,0 @@
package com.xy.xyaicpzs;
import com.xy.xyaicpzs.service.VipCodeService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import jakarta.annotation.Resource;
/**
* 会员码激活功能测试
*/
@Slf4j
@SpringBootTest
@ActiveProfiles("test")
public class VipCodeActivateTest {
@Resource
private VipCodeService vipCodeService;
@Test
public void testActivateVipCode() {
try {
// 测试参数用户ID=1会员码=TEST_CODE_001
// 实际测试时需要确保数据库中有对应的测试数据
Long userId = 1L;
String code = "TEST_CODE_001";
log.info("开始测试会员码激活功能用户ID{},会员码:{}", userId, code);
boolean result = vipCodeService.activateVipCode(userId, code);
log.info("会员码激活测试结果:{}", result);
} catch (Exception e) {
log.error("会员码激活测试失败:{}", e.getMessage(), e);
}
}
@Test
public void testActivateVipCodeWithInvalidUser() {
try {
// 测试无效用户ID
Long userId = 999999L;
String code = "TEST_CODE_001";
log.info("开始测试无效用户ID的会员码激活用户ID{},会员码:{}", userId, code);
vipCodeService.activateVipCode(userId, code);
} catch (IllegalArgumentException e) {
log.info("预期的异常:{}", e.getMessage());
} catch (Exception e) {
log.error("意外的异常:{}", e.getMessage(), e);
}
}
@Test
public void testActivateVipCodeWithInvalidCode() {
try {
// 测试无效会员码
Long userId = 1L;
String code = "INVALID_CODE";
log.info("开始测试无效会员码的激活用户ID{},会员码:{}", userId, code);
vipCodeService.activateVipCode(userId, code);
} catch (IllegalArgumentException e) {
log.info("预期的异常:{}", e.getMessage());
} catch (Exception e) {
log.error("意外的异常:{}", e.getMessage(), e);
}
}
}

View File

@@ -1,15 +0,0 @@
package com.xy.xyaicpzs.mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class T7MapperTest {
@Autowired
private T7Mapper t7Mapper;
}