common 工具包改动了一些实现和补充 javadoc,并为其添加了单元测试

- Commons 工具组的一些实现改动
  - _Convert.byteToHex 的实现从手动处理字母改为使用 java Integer.toHexString 方法(同时删除了私有的 hexArray 常量数组)
  - (WARN:breaking-changes) _Encrypt 中的命名从 encryptByX 改为 hashX
- 添加了 junit 的 params 组件 (org.junit.jupiter:junit-jupiter-params)
- 为 Commons 工具组的每个方法添加了其单元测试
- 单元测试添加了一个名为 MornyCLI 的执行 程序 main 方法 的程序入口包装...
This commit is contained in:
A.C.Sukazyo Eyre 2022-10-02 02:18:26 +08:00
parent 063ca24bf5
commit 459470be02
Signed by: Eyre_S
GPG Key ID: C17CE40291207874
12 changed files with 171 additions and 30 deletions

3
.gitignore vendored
View File

@ -4,7 +4,8 @@
.vscode/ .vscode/
.gradle/ .gradle/
.settings/ .settings/
/src/test/* /src/test/java/test/*
/src/test/resources/test/*
#build #build
/build/ /build/

View File

@ -35,6 +35,7 @@ dependencies {
implementation "com.github.pengrad:java-telegram-bot-api:${libJavaTelegramBotApiVersion}" implementation "com.github.pengrad:java-telegram-bot-api:${libJavaTelegramBotApiVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-api:${libJunitVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${libJunitVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-params:${libJunitVersion}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${libJunitVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${libJunitVersion}"
} }

View File

@ -1,6 +1,6 @@
## Core ## Core
VERSION = 0.8.0.0 VERSION = 0.8.0.1
CODENAME = fuzhou CODENAME = fuzhou

View File

@ -4,7 +4,7 @@ package cc.sukazyo.cono.morny;
* the final field that will be updated by gradle automatically. * the final field that will be updated by gradle automatically.
*/ */
public class GradleProjectConfigures { public class GradleProjectConfigures {
public static final String VERSION = "0.8.0.0"; public static final String VERSION = "0.8.0.1";
public static final String CODENAME = "fuzhou"; public static final String CODENAME = "fuzhou";
public static final long COMPILE_TIMESTAMP = 1664615965858L; public static final long COMPILE_TIMESTAMP = 1664648280419L;
} }

View File

@ -9,7 +9,7 @@ import com.pengrad.telegrambot.model.request.InlineQueryResultArticle;
import com.pengrad.telegrambot.model.request.InputTextMessageContent; import com.pengrad.telegrambot.model.request.InputTextMessageContent;
import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex; import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex;
import static cc.sukazyo.cono.morny.util.CommonEncrypt.encryptByMD5; import static cc.sukazyo.cono.morny.util.CommonEncrypt.hashMd5;
public class RawText implements ITelegramQuery<InlineQueryResultArticle> { public class RawText implements ITelegramQuery<InlineQueryResultArticle> {
@ -21,7 +21,7 @@ public class RawText implements ITelegramQuery<InlineQueryResultArticle> {
public InlineQueryUnit<InlineQueryResultArticle> query (Update event) { public InlineQueryUnit<InlineQueryResultArticle> query (Update event) {
if (event.inlineQuery().query() == null || "".equals(event.inlineQuery().query())) return null; if (event.inlineQuery().query() == null || "".equals(event.inlineQuery().query())) return null;
return new InlineQueryUnit<>(new InlineQueryResultArticle( return new InlineQueryUnit<>(new InlineQueryResultArticle(
ID_PREFIX + byteArrayToHex(encryptByMD5(event.inlineQuery().query())), ID_PREFIX + byteArrayToHex(hashMd5(event.inlineQuery().query())),
TITLE, TITLE,
new InputTextMessageContent(event.inlineQuery().query()) new InputTextMessageContent(event.inlineQuery().query())
)); ));

View File

@ -40,7 +40,7 @@ public class MornyJrrp {
* @return 算法得到的 jrrp 取值为 {@code [0.00. 100.00]} * @return 算法得到的 jrrp 取值为 {@code [0.00. 100.00]}
*/ */
public static double calcJrrpXmomi (long userId, long dayStamp) { public static double calcJrrpXmomi (long userId, long dayStamp) {
return (double)Long.parseLong(CommonConvert.byteArrayToHex(CommonEncrypt.encryptByMD5(userId + "@" + dayStamp)).substring(0, 4), 16) / (double)0xffff; return (double)Long.parseLong(CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(userId + "@" + dayStamp)).substring(0, 4), 16) / (double)0xffff;
} }
} }

View File

@ -2,14 +2,16 @@ package cc.sukazyo.cono.morny.util;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/**
* 进行简单类型转换等工作的类.
*/
public class CommonConvert { public class CommonConvert {
private final static String[] hexArray = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
/** /**
* 将字节数组转换成十六进制并以字符串的形式返回 * 将字节数组转换成 hex 字符串.
* 128位是指二进制位二进制太长所以一般都改写成16进制 * @param b 字节数组
* 每一位16进制数可以代替4位二进制数所以128位二进制数写成16进制就变成了128/4=32位 * @return String 格式的字节数组的 hex 每个字节当中没有分隔符
* @see #byteToHex(byte)
*/ */
@Nonnull @Nonnull
public static String byteArrayToHex(@Nonnull byte[] b){ public static String byteArrayToHex(@Nonnull byte[] b){
@ -21,16 +23,14 @@ public class CommonConvert {
} }
/** /**
* 将一个字节转换成十六进制并以字符串的形式返回 * 将一个字节转换成十六进制 hex 字符串.
* @param b 字节值
* @return String 格式的字节的 hex 小写
*/ */
@Nonnull @Nonnull
public static String byteToHex(byte b) { public static String byteToHex(byte b) {
int n = b; final String hex = Integer.toHexString(b & 0xff);
if (n < 0) return hex.length()<2?"0"+hex:hex;
n = n + 256;
int d1 = n / 16;
int d2 = n % 16;
return hexArray[d1]+hexArray[d2];
} }
} }

View File

@ -7,22 +7,25 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
/** /**
* 用于数据加密或编码的工具类<br> * 用于数据加密或编解码的工具类.
* <s>显然大部分代码是抄来的</s><br>
* <ul>
* <li><a href="https://blog.csdn.net/yu540135101/article/details/86765457">{@link #encryptByMD5} 来源</a></li>
* </ul>
*/ */
public class CommonEncrypt { public class CommonEncrypt {
/**
* 在使用加密算法处理字符串时默认会使用的字符串编码.
* <p>
* Morny 使用 UTF-8 编码因为这是一般而言加解密工具的默认行为
*/
public static final Charset ENCRYPT_STANDARD_CHARSET = StandardCharsets.UTF_8; public static final Charset ENCRYPT_STANDARD_CHARSET = StandardCharsets.UTF_8;
/*** /**
* 对指定的字符串进行MD5加密 * 取得数据的 md5 散列值.
*
* @param data byte 数组形式的数据体
* @return 二进制(byte数组)格式的数据的 md5 散列值
*/ */
@Nonnull @Nonnull
public static byte[] encryptByMD5(@Nonnull byte[] data) { public static byte[] hashMd5 (@Nonnull byte[] data) {
try { try {
return MessageDigest.getInstance("md5").digest(data); return MessageDigest.getInstance("md5").digest(data);
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
@ -30,9 +33,18 @@ public class CommonEncrypt {
} }
} }
/**
* 取得一个字符串的 md5 散列值.
* <p>
* 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析
*
* @param originString 要进行散列的字符串
* @return 二进制(byte数组)格式的 md5 散列值
*/
@Nonnull @Nonnull
public static byte[] encryptByMD5(String originString) { public static byte[] hashMd5 (String originString) {
return encryptByMD5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET));
} }
} }

View File

@ -0,0 +1,18 @@
package cc.sukazyo.cono.morny;
import cc.sukazyo.untitled.util.command.CommonCommand;
import java.util.*;
public class MornyCLI {
public static void main (String[] args) {
Scanner line = new Scanner(System.in);
System.out.print("$ java -jar morny-coeur-"+GradleProjectConfigures.VERSION+".jar" );
String x = line.nextLine();
ServerMain.main(CommonCommand.format(x));
}
}

View File

@ -0,0 +1,50 @@
package cc.sukazyo.cono.morny.util;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex;
import static cc.sukazyo.cono.morny.util.CommonConvert.byteToHex;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.params.provider.Arguments.arguments;
public class TestCommonConvert {
@ParameterizedTest
@CsvSource(textBlock = """
0x00, 00
0x01, 01
0x20, 20
0x77, 77
-0x60, a0
0x0a, 0a
-0x01, ff
-0x05, fb
"""
)
void testByteToHex(byte source, String expected) {
assertEquals(expected, byteToHex(source));
}
public static Stream<Arguments> testByteArrayToHexProvider () {
return Stream.of(
arguments(new byte[]{0x00}, "00"),
arguments(new byte[]{(byte)0xff}, "ff"),
arguments(new byte[]{(byte)0xc3}, "c3"),
arguments(new byte[]{}, ""),
arguments(new byte[]{0x30,0x0a,0x00,0x04,(byte)0xb0,0x00}, "300a0004b000"),
arguments(new byte[]{0x00,0x00,0x0a,(byte)0xff,(byte)0xfc,(byte)0xab,(byte)0x00,0x04}, "00000afffcab0004"),
arguments(new byte[]{0x00,0x7c,0x11,0x28,(byte)0x88,(byte)0xa6,(byte)0xfc,0x30}, "007c112888a6fc30")
);
}
@ParameterizedTest
@MethodSource("testByteArrayToHexProvider")
void testByteArrayToHex (byte[] raw, String expected) {
assertEquals(expected, byteArrayToHex(raw));
}
}

View File

@ -0,0 +1,23 @@
package cc.sukazyo.cono.morny.util;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex;
import static cc.sukazyo.cono.morny.util.CommonEncrypt.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestCommonEncrypt {
@ParameterizedTest
@SuppressWarnings("UnnecessaryStringEscape")
@CsvSource(textBlock = """
28be57d368b75051da76c068a6733284, '莲子'
9644c5cbae223013228cd528817ba4f5, '莲子\n'
d41d8cd98f00b204e9800998ecf8427e, ''
""")
void testHashMd5_String (String md5, String text) {
assertEquals(md5, byteArrayToHex(hashMd5(text)));
}
}

View File

@ -0,0 +1,36 @@
package cc.sukazyo.cono.morny.util;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static cc.sukazyo.cono.morny.util.CommonFormat.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestCommonFormat {
@ParameterizedTest
@CsvSource(textBlock = """
1664646870402, 8, 2022-10-02 01:54:30:402
1, 8, 1970-01-01 08:00:00:001
0, -1, 1969-12-31 23:00:00:000
"""
)
void testFormatDate (long timestamp, int utfOffset, String expectedHumanReadableTime) {
assertEquals(expectedHumanReadableTime, formatDate(timestamp, utfOffset));
}
@ParameterizedTest
@CsvSource(textBlock = """
100, '100ms'
3000, '3s 0ms'
326117522, '3d 18h 35min 17s 522ms'
53373805, 14h 49min 33s 805ms
""")
// -1, '-1ms' // WARN: maybe sometime an unexpected usage
// -194271974291, '-291ms' //
// """) //
void testFormatDuration (long durationMillis, String humanReadableDuration) {
assertEquals(humanReadableDuration, formatDuration(durationMillis));
}
}