mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
Merge branch 'v5-dev' into v5-dev
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package cn.hutool.core.date;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class IssueIC00HGTest {
|
||||
@Test
|
||||
@Disabled
|
||||
void dateToStringTest(){
|
||||
Console.log(DateUtil.date().toString());
|
||||
}
|
||||
}
|
@@ -66,7 +66,11 @@ public class FileUtilTest {
|
||||
final String parseSmbPath = FileUtil.getAbsolutePath(smbPath);
|
||||
assertEquals(smbPath, parseSmbPath);
|
||||
assertTrue(FileUtil.isAbsolutePath(smbPath));
|
||||
assertTrue(Paths.get(smbPath).isAbsolute());
|
||||
if(FileUtil.isWindows()){
|
||||
// 在Windows下`\`路径是绝对路径,也表示SMB路径
|
||||
// 但是在Linux下,`\`表示转义字符,并不被识别为路径
|
||||
assertTrue(Paths.get(smbPath).isAbsolute());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -480,21 +484,26 @@ public class FileUtilTest {
|
||||
final List<String> list = ListUtil.of("text/javascript", "application/x-javascript");
|
||||
assertTrue(list.contains(mimeType));
|
||||
|
||||
// office03
|
||||
mimeType = FileUtil.getMimeType("test.doc");
|
||||
assertEquals("application/msword", mimeType);
|
||||
mimeType = FileUtil.getMimeType("test.xls");
|
||||
assertEquals("application/vnd.ms-excel", mimeType);
|
||||
mimeType = FileUtil.getMimeType("test.ppt");
|
||||
assertEquals("application/vnd.ms-powerpoint", mimeType);
|
||||
if(FileUtil.isWindows()){
|
||||
// Linux下的OpenJDK无法正确识别
|
||||
|
||||
// office03
|
||||
mimeType = FileUtil.getMimeType("test.doc");
|
||||
assertEquals("application/msword", mimeType);
|
||||
mimeType = FileUtil.getMimeType("test.xls");
|
||||
assertEquals("application/vnd.ms-excel", mimeType);
|
||||
mimeType = FileUtil.getMimeType("test.ppt");
|
||||
assertEquals("application/vnd.ms-powerpoint", mimeType);
|
||||
|
||||
// office07+
|
||||
mimeType = FileUtil.getMimeType("test.docx");
|
||||
assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document", mimeType);
|
||||
mimeType = FileUtil.getMimeType("test.xlsx");
|
||||
assertEquals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", mimeType);
|
||||
mimeType = FileUtil.getMimeType("test.pptx");
|
||||
assertEquals("application/vnd.openxmlformats-officedocument.presentationml.presentation", mimeType);
|
||||
}
|
||||
|
||||
// office07+
|
||||
mimeType = FileUtil.getMimeType("test.docx");
|
||||
assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document", mimeType);
|
||||
mimeType = FileUtil.getMimeType("test.xlsx");
|
||||
assertEquals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", mimeType);
|
||||
mimeType = FileUtil.getMimeType("test.pptx");
|
||||
assertEquals("application/vnd.openxmlformats-officedocument.presentationml.presentation", mimeType);
|
||||
|
||||
// pr#2617@Github
|
||||
mimeType = FileUtil.getMimeType("test.wgt");
|
||||
|
@@ -1,13 +1,16 @@
|
||||
package cn.hutool.core.io.file;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class PathUtilTest {
|
||||
|
||||
@Test
|
||||
@@ -82,7 +85,10 @@ public class PathUtilTest {
|
||||
@Test
|
||||
public void issue3179Test() {
|
||||
final String mimeType = PathUtil.getMimeType(Paths.get("xxxx.jpg"));
|
||||
assertEquals("image/jpeg", mimeType);
|
||||
if(FileUtil.isWindows()){
|
||||
// Linux下,OpenJDK可能报路径不存在
|
||||
assertEquals("image/jpeg", mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,4 +99,11 @@ public class PathUtilTest {
|
||||
public void moveTest2(){
|
||||
PathUtil.move(Paths.get("D:\\project\\test1.txt"), Paths.get("D:\\project\\test2.txt"), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void delNullDirTest() {
|
||||
Path path = null;
|
||||
assertTrue(PathUtil.del(path));
|
||||
}
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ public class SimpleCacheTest {
|
||||
@Test
|
||||
public void getConcurrencyTest(){
|
||||
final SimpleCache<String, String> cache = new SimpleCache<>();
|
||||
final ConcurrencyTester tester = new ConcurrencyTester(9000);
|
||||
final ConcurrencyTester tester = new ConcurrencyTester(500);
|
||||
tester.test(()-> cache.get("aaa", ()-> {
|
||||
ThreadUtil.sleep(200);
|
||||
return "aaaValue";
|
||||
|
@@ -1,9 +1,10 @@
|
||||
package cn.hutool.core.swing;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import cn.hutool.core.swing.clipboard.ClipboardUtil;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import cn.hutool.core.swing.clipboard.ClipboardUtil;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* 剪贴板工具类单元测试
|
||||
@@ -14,6 +15,7 @@ import cn.hutool.core.swing.clipboard.ClipboardUtil;
|
||||
public class ClipboardUtilTest {
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void setAndGetStrTest() {
|
||||
try {
|
||||
ClipboardUtil.setStr("test");
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package cn.hutool.core.text.csv;
|
||||
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -19,10 +18,7 @@ public class Issue3705Test {
|
||||
csvWriter.flush();
|
||||
}
|
||||
|
||||
String lineSeparator = new String(new char[]{CharUtil.CR, CharUtil.LF});
|
||||
|
||||
Assertions.assertEquals(
|
||||
"\"2024-08-20 14:24:35,\"" + lineSeparator + "最后一行",
|
||||
stringWriter.toString());
|
||||
// CsvWriteConfig中默认为`\r\n`
|
||||
Assertions.assertEquals("\"2024-08-20 14:24:35,\"\r\n最后一行", stringWriter.toString());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,209 @@
|
||||
package cn.hutool.core.thread;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.thread.lock.SegmentLock;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* SegmentLock 单元测试类
|
||||
*/
|
||||
public class SegmentLockTest {
|
||||
|
||||
private static final int SEGMENT_COUNT = 4;
|
||||
private SegmentLock<Lock> strongLock;
|
||||
private SegmentLock<Lock> weakLock;
|
||||
private SegmentLock<Semaphore> semaphore;
|
||||
private SegmentLock<ReadWriteLock> readWriteLock;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
strongLock = SegmentLock.lock(SEGMENT_COUNT);
|
||||
weakLock = SegmentLock.lazyWeakLock(SEGMENT_COUNT);
|
||||
semaphore = SegmentLock.semaphore(SEGMENT_COUNT, 2);
|
||||
readWriteLock = SegmentLock.readWriteLock(SEGMENT_COUNT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSize() {
|
||||
assertEquals(SEGMENT_COUNT, strongLock.size());
|
||||
assertEquals(SEGMENT_COUNT, weakLock.size());
|
||||
assertEquals(SEGMENT_COUNT, semaphore.size());
|
||||
assertEquals(SEGMENT_COUNT, readWriteLock.size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringOperationCanBeSimplified")
|
||||
@Test
|
||||
public void testGetWithSameKey() {
|
||||
// 相同 key 应返回相同锁
|
||||
String key1 = "testKey";
|
||||
String key2 = new String("testKey"); // equals 但不同对象
|
||||
Lock lock1 = strongLock.get(key1);
|
||||
Lock lock2 = strongLock.get(key2);
|
||||
assertSame(lock1, lock2, "相同 key 应返回同一锁对象");
|
||||
|
||||
Lock weakLock1 = weakLock.get(key1);
|
||||
Lock weakLock2 = weakLock.get(key2);
|
||||
assertSame(weakLock1, weakLock2, "弱引用锁相同 key 应返回同一锁对象");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAt() {
|
||||
for (int i = 0; i < SEGMENT_COUNT; i++) {
|
||||
Lock lock = strongLock.getAt(i);
|
||||
assertNotNull(lock, "getAt 返回的锁不应为 null");
|
||||
}
|
||||
assertThrows(IllegalArgumentException.class, () -> strongLock.getAt(SEGMENT_COUNT),
|
||||
"超出段数的索引应抛出异常");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBulkGet() {
|
||||
List<String> keys = CollUtil.newArrayList("key1", "key2", "key3");
|
||||
Iterable<Lock> locks = strongLock.bulkGet(keys);
|
||||
List<Lock> lockList = CollUtil.newArrayList(locks);
|
||||
|
||||
assertEquals(3, lockList.size(), "bulkGet 返回的锁数量应与 key 数量一致");
|
||||
|
||||
// 检查顺序性
|
||||
int prevIndex = -1;
|
||||
for (Lock lock : lockList) {
|
||||
int index = findIndex(strongLock, lock);
|
||||
assertTrue(index >= prevIndex, "bulkGet 返回的锁应按索引升序");
|
||||
prevIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockConcurrency() throws InterruptedException {
|
||||
int threadCount = SEGMENT_COUNT * 2;
|
||||
CountDownLatch startLatch = new CountDownLatch(1);
|
||||
CountDownLatch endLatch = new CountDownLatch(threadCount);
|
||||
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
||||
List<String> keys = new ArrayList<>();
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
keys.add("key" + i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
final String key = keys.get(i);
|
||||
executor.submit(() -> {
|
||||
try {
|
||||
startLatch.await();
|
||||
Lock lock = strongLock.get(key);
|
||||
lock.lock();
|
||||
try {
|
||||
Thread.sleep(100); // 模拟工作
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
endLatch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
startLatch.countDown();
|
||||
assertTrue(endLatch.await(2000, java.util.concurrent.TimeUnit.MILLISECONDS),
|
||||
"并发锁测试应在 2 秒内完成");
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSemaphore() {
|
||||
Semaphore sem = semaphore.get("testKey");
|
||||
assertEquals(2, sem.availablePermits(), "信号量初始许可应为 2");
|
||||
|
||||
sem.acquireUninterruptibly(2);
|
||||
assertEquals(0, sem.availablePermits(), "获取所有许可后应为 0");
|
||||
|
||||
sem.release(1);
|
||||
assertEquals(1, sem.availablePermits(), "释放一个许可后应为 1");
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
@Test
|
||||
public void testReadWriteLock() throws InterruptedException {
|
||||
ReadWriteLock rwLock = readWriteLock.get("testKey");
|
||||
Lock readLock = rwLock.readLock();
|
||||
Lock writeLock = rwLock.writeLock();
|
||||
|
||||
// 测试读锁可重入
|
||||
readLock.lock();
|
||||
assertTrue(readLock.tryLock(), "读锁应允许多个线程同时持有");
|
||||
readLock.unlock();
|
||||
readLock.unlock();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
AtomicBoolean readLockAcquired = new AtomicBoolean(false);
|
||||
|
||||
writeLock.lock();
|
||||
executor.submit(() -> {
|
||||
readLockAcquired.set(readLock.tryLock());
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
latch.await(500, TimeUnit.MILLISECONDS);
|
||||
assertFalse(readLockAcquired.get(), "写锁持有时读锁应失败");
|
||||
writeLock.unlock();
|
||||
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWeakReferenceCleanup() throws InterruptedException {
|
||||
SegmentLock<Lock> weakLockLarge = SegmentLock.lazyWeakLock(1024); // 超过 LARGE_LAZY_CUTOFF
|
||||
Lock lock = weakLockLarge.get("testKey");
|
||||
|
||||
System.gc();
|
||||
Thread.sleep(100);
|
||||
|
||||
// 弱引用锁未被其他引用,应仍可获取
|
||||
Lock lockAgain = weakLockLarge.get("testKey");
|
||||
assertSame(lock, lockAgain, "弱引用锁未被回收时应返回同一对象");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidSegmentCount() {
|
||||
assertThrows(IllegalArgumentException.class, () -> SegmentLock.lock(0),
|
||||
"段数为 0 应抛出异常");
|
||||
assertThrows(IllegalArgumentException.class, () -> SegmentLock.lock(-1),
|
||||
"负段数应抛出异常");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashDistribution() {
|
||||
SegmentLock<Lock> lock = SegmentLock.lock(4);
|
||||
int[] counts = new int[4];
|
||||
for (int i = 0; i < 100; i++) {
|
||||
int index = findIndex(lock, lock.get("key" + i));
|
||||
counts[index]++;
|
||||
}
|
||||
for (int count : counts) {
|
||||
assertTrue(count > 0, "每个段都应至少被分配到一个 key");
|
||||
}
|
||||
}
|
||||
|
||||
private int findIndex(SegmentLock<Lock> lock, Lock target) {
|
||||
for (int i = 0; i < lock.size(); i++) {
|
||||
if (lock.getAt(i) == target) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
@@ -144,43 +144,43 @@ public class NumberUtilTest {
|
||||
@Test
|
||||
public void roundStrTest() {
|
||||
final String roundStr = NumberUtil.roundStr(2.647, 2);
|
||||
assertEquals(roundStr, "2.65");
|
||||
assertEquals("2.65", roundStr);
|
||||
|
||||
final String roundStr1 = NumberUtil.roundStr(0, 10);
|
||||
assertEquals(roundStr1, "0.0000000000");
|
||||
assertEquals("0.0000000000", roundStr1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundHalfEvenTest() {
|
||||
String roundStr = NumberUtil.roundHalfEven(4.245, 2).toString();
|
||||
assertEquals(roundStr, "4.24");
|
||||
assertEquals("4.24", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(4.2450, 2).toString();
|
||||
assertEquals(roundStr, "4.24");
|
||||
assertEquals("4.24", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(4.2451, 2).toString();
|
||||
assertEquals(roundStr, "4.25");
|
||||
assertEquals("4.25", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(4.2250, 2).toString();
|
||||
assertEquals(roundStr, "4.22");
|
||||
assertEquals("4.22", roundStr);
|
||||
|
||||
roundStr = NumberUtil.roundHalfEven(1.2050, 2).toString();
|
||||
assertEquals(roundStr, "1.20");
|
||||
assertEquals("1.20", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2150, 2).toString();
|
||||
assertEquals(roundStr, "1.22");
|
||||
assertEquals("1.22", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2250, 2).toString();
|
||||
assertEquals(roundStr, "1.22");
|
||||
assertEquals("1.22", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2350, 2).toString();
|
||||
assertEquals(roundStr, "1.24");
|
||||
assertEquals("1.24", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2450, 2).toString();
|
||||
assertEquals(roundStr, "1.24");
|
||||
assertEquals("1.24", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2550, 2).toString();
|
||||
assertEquals(roundStr, "1.26");
|
||||
assertEquals("1.26", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2650, 2).toString();
|
||||
assertEquals(roundStr, "1.26");
|
||||
assertEquals("1.26", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2750, 2).toString();
|
||||
assertEquals(roundStr, "1.28");
|
||||
assertEquals("1.28", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2850, 2).toString();
|
||||
assertEquals(roundStr, "1.28");
|
||||
assertEquals("1.28", roundStr);
|
||||
roundStr = NumberUtil.roundHalfEven(1.2950, 2).toString();
|
||||
assertEquals(roundStr, "1.30");
|
||||
assertEquals("1.30", roundStr);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -673,4 +673,10 @@ public class NumberUtilTest {
|
||||
final double result = NumberUtil.add(v1, v2);
|
||||
assertEquals(91007279.3545, result, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void issueIC1MXETest(){
|
||||
final boolean equals = NumberUtil.equals(104557543L, 104557544);
|
||||
assertFalse(equals);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user