From 459470be02c78424b9a6a054f23f8f39179f2991 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sun, 2 Oct 2022 02:18:26 +0800 Subject: [PATCH] =?UTF-8?q?common=20=E5=B7=A5=E5=85=B7=E5=8C=85=E6=94=B9?= =?UTF-8?q?=E5=8A=A8=E4=BA=86=E4=B8=80=E4=BA=9B=E5=AE=9E=E7=8E=B0=E5=92=8C?= =?UTF-8?q?=E8=A1=A5=E5=85=85=20javadoc=EF=BC=8C=E5=B9=B6=E4=B8=BA?= =?UTF-8?q?=E5=85=B6=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=8D=95=E5=85=83=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Commons 工具组的一些实现改动 - _Convert.byteToHex 的实现从手动处理字母改为使用 java Integer.toHexString 方法(同时删除了私有的 hexArray 常量数组) - (WARN:breaking-changes) _Encrypt 中的命名从 encryptByX 改为 hashX - 添加了 junit 的 params 组件 (org.junit.jupiter:junit-jupiter-params) - 为 Commons 工具组的每个方法添加了其单元测试 - 单元测试添加了一个名为 MornyCLI 的执行 程序 main 方法 的程序入口包装... --- .gitignore | 3 +- build.gradle | 1 + gradle.properties | 2 +- .../cono/morny/GradleProjectConfigures.java | 4 +- .../sukazyo/cono/morny/bot/query/RawText.java | 4 +- .../cc/sukazyo/cono/morny/data/MornyJrrp.java | 2 +- .../cono/morny/util/CommonConvert.java | 24 ++++----- .../cono/morny/util/CommonEncrypt.java | 34 +++++++++---- .../java/cc/sukazyo/cono/morny/MornyCLI.java | 18 +++++++ .../cono/morny/util/TestCommonConvert.java | 50 +++++++++++++++++++ .../cono/morny/util/TestCommonEncrypt.java | 23 +++++++++ .../cono/morny/util/TestCommonFormat.java | 36 +++++++++++++ 12 files changed, 171 insertions(+), 30 deletions(-) create mode 100644 src/test/java/cc/sukazyo/cono/morny/MornyCLI.java create mode 100644 src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java create mode 100644 src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java create mode 100644 src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java diff --git a/.gitignore b/.gitignore index 8520bdf..881a611 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,8 @@ .vscode/ .gradle/ .settings/ -/src/test/* +/src/test/java/test/* +/src/test/resources/test/* #build /build/ diff --git a/build.gradle b/build.gradle index 9e60e84..694232a 100644 --- a/build.gradle +++ b/build.gradle @@ -35,6 +35,7 @@ dependencies { implementation "com.github.pengrad:java-telegram-bot-api:${libJavaTelegramBotApiVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${libJunitVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-params:${libJunitVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${libJunitVersion}" } diff --git a/gradle.properties b/gradle.properties index 3fa9e53..eca4732 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ ## Core -VERSION = 0.8.0.0 +VERSION = 0.8.0.1 CODENAME = fuzhou diff --git a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java b/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java index 1d1528b..27b871d 100644 --- a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java +++ b/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java @@ -4,7 +4,7 @@ package cc.sukazyo.cono.morny; * the final field that will be updated by gradle automatically. */ 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 long COMPILE_TIMESTAMP = 1664615965858L; + public static final long COMPILE_TIMESTAMP = 1664648280419L; } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/query/RawText.java b/src/main/java/cc/sukazyo/cono/morny/bot/query/RawText.java index f9f9d4f..655d03a 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/query/RawText.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/query/RawText.java @@ -9,7 +9,7 @@ import com.pengrad.telegrambot.model.request.InlineQueryResultArticle; import com.pengrad.telegrambot.model.request.InputTextMessageContent; 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 { @@ -21,7 +21,7 @@ public class RawText implements ITelegramQuery { public InlineQueryUnit query (Update event) { if (event.inlineQuery().query() == null || "".equals(event.inlineQuery().query())) return null; return new InlineQueryUnit<>(new InlineQueryResultArticle( - ID_PREFIX + byteArrayToHex(encryptByMD5(event.inlineQuery().query())), + ID_PREFIX + byteArrayToHex(hashMd5(event.inlineQuery().query())), TITLE, new InputTextMessageContent(event.inlineQuery().query()) )); diff --git a/src/main/java/cc/sukazyo/cono/morny/data/MornyJrrp.java b/src/main/java/cc/sukazyo/cono/morny/data/MornyJrrp.java index f3b2db1..029e476 100644 --- a/src/main/java/cc/sukazyo/cono/morny/data/MornyJrrp.java +++ b/src/main/java/cc/sukazyo/cono/morny/data/MornyJrrp.java @@ -40,7 +40,7 @@ public class MornyJrrp { * @return 算法得到的 jrrp 值,取值为 {@code [0.00. 100.00]} */ 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; } } diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java index eddf5fa..9fc02cf 100644 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java +++ b/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java @@ -2,14 +2,16 @@ package cc.sukazyo.cono.morny.util; import javax.annotation.Nonnull; +/** + * 进行简单类型转换等工作的类. + */ public class CommonConvert { - private final static String[] hexArray = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; - /** - * 将字节数组转换成十六进制,并以字符串的形式返回 - * 128位是指二进制位。二进制太长,所以一般都改写成16进制, - * 每一位16进制数可以代替4位二进制数,所以128位二进制数写成16进制就变成了128/4=32位。 + * 将字节数组转换成 hex 字符串. + * @param b 字节数组 + * @return String 格式的字节数组的 hex 值(每个字节当中没有分隔符) + * @see #byteToHex(byte) */ @Nonnull public static String byteArrayToHex(@Nonnull byte[] b){ @@ -21,16 +23,14 @@ public class CommonConvert { } /** - * 将一个字节转换成十六进制,并以字符串的形式返回 + * 将一个字节转换成十六进制 hex 字符串. + * @param b 字节值 + * @return String 格式的字节的 hex 值(小写) */ @Nonnull public static String byteToHex(byte b) { - int n = b; - if (n < 0) - n = n + 256; - int d1 = n / 16; - int d2 = n % 16; - return hexArray[d1]+hexArray[d2]; + final String hex = Integer.toHexString(b & 0xff); + return hex.length()<2?"0"+hex:hex; } } diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java index 7bcf21d..f0dcedd 100644 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java +++ b/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java @@ -7,22 +7,25 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** - * 用于数据加密或编码的工具类
- * 显然大部分代码是抄来的
- * + * 用于数据加密或编解码的工具类. */ public class CommonEncrypt { + /** + * 在使用加密算法处理字符串时默认会使用的字符串编码. + *

+ * Morny 使用 UTF-8 编码因为这是一般而言加解密工具的默认行为 + */ public static final Charset ENCRYPT_STANDARD_CHARSET = StandardCharsets.UTF_8; - /*** - * 对指定的字符串进行MD5加密 + /** + * 取得数据的 md5 散列值. + * + * @param data byte 数组形式的数据体 + * @return 二进制(byte数组)格式的数据的 md5 散列值 */ - @Nonnull - public static byte[] encryptByMD5(@Nonnull byte[] data) { + public static byte[] hashMd5 (@Nonnull byte[] data) { try { return MessageDigest.getInstance("md5").digest(data); } catch (NoSuchAlgorithmException e) { @@ -30,9 +33,18 @@ public class CommonEncrypt { } } + + /** + * 取得一个字符串的 md5 散列值. + *

+ * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 + * + * @param originString 要进行散列的字符串 + * @return 二进制(byte数组)格式的 md5 散列值 + */ @Nonnull - public static byte[] encryptByMD5(String originString) { - return encryptByMD5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); + public static byte[] hashMd5 (String originString) { + return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); } } diff --git a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java new file mode 100644 index 0000000..f844d71 --- /dev/null +++ b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java @@ -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)); + + } + +} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java new file mode 100644 index 0000000..8fd9ed7 --- /dev/null +++ b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java @@ -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 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)); + } + +} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java new file mode 100644 index 0000000..429b163 --- /dev/null +++ b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java @@ -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))); + } + +} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java new file mode 100644 index 0000000..d7b67fe --- /dev/null +++ b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java @@ -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)); + } + +}