You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

172 lines
5.3 KiB

package license
import (
cryptorand "crypto/rand"
"fmt"
"math/rand"
"testing"
)
// 生产库里的真实 v1 授权码样本
const legacySampleCode = "0D82F1CCD83D72B78FA9"
// generateV1 复刻 comm.GenerateLicense 的 v1 编码,仅供测试构造老码。
// 生产代码不再生成 v1,只解析。
func generateV1(productid uint16, batch byte, serial uint32) (string, error) {
if batch < 1 {
return "", fmt.Errorf("批次必须 >= 1")
}
if serial > 0xFFFFF {
return "", fmt.Errorf("v1 序号上限 0xFFFFF")
}
seedBytes := make([]byte, 2)
if _, err := cryptorand.Read(seedBytes); err != nil {
return "", err
}
seed := int(seedBytes[0])<<8 | int(seedBytes[1])
rng := rand.New(rand.NewSource(int64(seed)))
confusion := make([]int, 4)
for i := range confusion {
confusion[i] = rng.Intn(65536)
}
confusion[0] ^= int(productid)
confusion[1] ^= (int(batch) << 8) | (int(serial>>12) & 0xFF)
confusion[2] ^= int(serial) & 0xFFF
confusion[3] ^= rng.Intn(65536)
code := fmt.Sprintf("%04X", seed)
for _, c := range confusion {
code += fmt.Sprintf("%04X", c)
}
return code, nil
}
func TestParse_LegacySample(t *testing.T) {
info, err := Parse(legacySampleCode)
if err != nil {
t.Fatalf("解析真实老码失败: %v", err)
}
if info.Version != V1 {
t.Errorf("版本应为 v1, 实际 v%d", info.Version)
}
if info.ProductID != 45069 || info.Batch != 1 || info.Serial != 260 {
t.Errorf("解析结果不符: pid=%d batch=%d serial=%d, 期望 45069/1/260",
info.ProductID, info.Batch, info.Serial)
}
}
// v2 往返:序号必须能占满 uint32
func TestGenerateV2_RoundTrip(t *testing.T) {
pids := []uint16{0, 1, 45058, 45069, 0xFFFF}
serials := []uint32{
0, 1, 15, 16, 0xFFF, 0x1000, 0xFFFFF, 0x100000,
0xFFFFFFF, 0x10000000, 0x12345678, 0xFFFFFFFE, 0xFFFFFFFF,
}
for _, pid := range pids {
for _, serial := range serials {
code, err := GenerateV2(pid, serial)
if err != nil {
t.Fatalf("生成失败 pid=%d serial=%d: %v", pid, serial, err)
}
if len(code) != totalSegments*segmentLength {
t.Fatalf("码长变了: %d, 期望 %d", len(code), totalSegments*segmentLength)
}
info, err := Parse(code)
if err != nil {
t.Fatalf("解析失败 %s: %v", code, err)
}
if info.Version != V2 {
t.Errorf("%s 应识别为 v2, 实际 v%d", code, info.Version)
}
if info.ProductID != pid || info.Serial != serial {
t.Errorf("往返不一致: 写入 pid=%d serial=%d, 读出 pid=%d serial=%d",
pid, serial, info.ProductID, info.Serial)
}
}
}
}
// probatch < 240 的 v1 码不能被误判成 v2,且 batch/serial 必须原样解出
func TestParse_V1NotMisdetected(t *testing.T) {
const pid = 45069
serials := []uint32{0, 1, 4095, 4096, 65535, 0xFFFFF}
for batch := 1; batch < V1ProbatchLimit; batch++ {
for _, serial := range serials {
code, err := generateV1(pid, byte(batch), serial)
if err != nil {
t.Fatalf("v1 生成失败 batch=%d serial=%d: %v", batch, serial, err)
}
info, err := Parse(code)
if err != nil {
t.Fatalf("v1 解析失败 batch=%d serial=%d: %v", batch, serial, err)
}
if info.Version != V1 {
t.Fatalf("batch=%d serial=%d 的 v1 码被误判为 v%d", batch, serial, info.Version)
}
if info.ProductID != pid || info.Batch != byte(batch) || info.Serial != serial {
t.Fatalf("v1 解析不一致 batch=%d serial=%d -> pid=%d batch=%d serial=%d",
batch, serial, info.ProductID, info.Batch, info.Serial)
}
}
}
}
// 文档化约束:batch >= 240 的 v1 码必然被误判为 v2(判别位 = batch>>4 == 0xF)。
// 迁移脚本必须先验证 MAX(probatch) < V1ProbatchLimit,否则老码序号会解出垃圾。
// 本测试若开始失败,说明判别位挪了位置,前提校验需要跟着改。
func TestParse_V1OverLimitIsMisdetected(t *testing.T) {
const pid = 45069
for batch := V1ProbatchLimit; batch <= 0xFF; batch++ {
code, err := generateV1(pid, byte(batch), 1)
if err != nil {
t.Fatalf("v1 生成失败 batch=%d: %v", batch, err)
}
info, err := Parse(code)
if err != nil {
t.Fatalf("解析失败 batch=%d: %v", batch, err)
}
if info.Version != V2 {
t.Errorf("batch=%d 的 v1 码应当被误判为 v2(证明前提校验必要),实际 v%d", batch, info.Version)
}
}
}
// productid 的提取与版本无关,也不受 v1 批次异常影响
func TestProductID_VersionAgnostic(t *testing.T) {
const pid = 45069
v1, err := generateV1(pid, 3, 1234)
if err != nil {
t.Fatalf("v1 生成失败: %v", err)
}
v2, err := GenerateV2(pid, 0xDEADBEEF)
if err != nil {
t.Fatalf("v2 生成失败: %v", err)
}
for _, code := range []string{v1, v2, legacySampleCode} {
got, err := ProductID(code)
if err != nil {
t.Fatalf("%s 提取 pid 失败: %v", code, err)
}
if got != pid {
t.Errorf("%s 提取 pid=%d, 期望 %d", code, got, pid)
}
}
}
// 同产品下连续序号生成的码互不相同(code <-> (seed, pid, serial) 双射)
func TestGenerateV2_Uniqueness(t *testing.T) {
const pid = 45069
seen := make(map[string]uint32, 20000)
for serial := uint32(1); serial <= 20000; serial++ {
code, err := GenerateV2(pid, serial)
if err != nil {
t.Fatalf("生成失败 serial=%d: %v", serial, err)
}
if prev, dup := seen[code]; dup {
t.Fatalf("授权码碰撞: serial=%d 与 serial=%d 都生成 %s", serial, prev, code)
}
seen[code] = serial
}
}