diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/classloader/ResourceClassLoader.java b/hutool-core/src/main/java/cn/hutool/v7/core/classloader/ResourceClassLoader.java index 02b4c7b711..5ddbd80966 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/classloader/ResourceClassLoader.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/classloader/ResourceClassLoader.java @@ -57,7 +57,7 @@ public class ResourceClassLoader extends SecureClassLoader { * @return this */ public ResourceClassLoader addResource(final T resource) { - this.resourceMap.put(resource.getName(), resource); + this.resourceMap.put(resource.name(), resource); return this; } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/compress/ZipUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/compress/ZipUtil.java index 0e5119ca54..9d88e8716e 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/compress/ZipUtil.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/compress/ZipUtil.java @@ -432,7 +432,7 @@ public class ZipUtil { * * @param zipFile 生成的Zip文件,包括文件名。注意:zipPath不能是srcPath路径下的子文件夹 * @param charset 编码 - * @param resources 需要压缩的资源,资源的路径为{@link Resource#getName()} + * @param resources 需要压缩的资源,资源的路径为{@link Resource#name()} * @return 压缩文件 * @throws HutoolException IO异常 * @since 5.5.2 diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/compress/ZipWriter.java b/hutool-core/src/main/java/cn/hutool/v7/core/compress/ZipWriter.java index 3c47bba0f4..4ea84c88b0 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/compress/ZipWriter.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/compress/ZipWriter.java @@ -189,14 +189,14 @@ public class ZipWriter implements Closeable { /** * 添加资源到压缩包,添加后关闭资源流 * - * @param resources 需要压缩的资源,资源的路径为{@link Resource#getName()} + * @param resources 需要压缩的资源,资源的路径为{@link Resource#name()} * @return this * @throws IORuntimeException IO异常 */ public ZipWriter add(final Resource... resources) throws IORuntimeException { for (final Resource resource : resources) { if (null != resource) { - add(resource.getName(), resource.getStream()); + add(resource.name(), resource.getStream()); } } return this; diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/file/DelegatePath.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/file/DelegatePath.java index d66c64e63c..6780b8462b 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/file/DelegatePath.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/file/DelegatePath.java @@ -395,7 +395,7 @@ public class DelegatePath extends SimpleWrapper implements Path, Resource } @Override - public String getName() { + public String name() { return PathUtil.getName(this.raw); } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/BytesResource.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/BytesResource.java index 79eed72ad9..173e36f388 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/BytesResource.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/BytesResource.java @@ -67,7 +67,7 @@ public class BytesResource implements Resource, Serializable { } @Override - public String getName() { + public String name() { return this.name; } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileObjectResource.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileObjectResource.java index 13bb253886..20852f7be8 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileObjectResource.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileObjectResource.java @@ -57,7 +57,7 @@ public class FileObjectResource implements Resource { } @Override - public String getName() { + public String name() { return this.fileObject.getName(); } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileResource.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileResource.java index 4444a685ba..5640e887e0 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileResource.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/FileResource.java @@ -94,7 +94,7 @@ public class FileResource implements Resource, Serializable { // ----------------------------------------------------------------------- Constructor end @Override - public String getName() { + public String name() { return this.name; } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/HttpResource.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/HttpResource.java index 382ea70c33..32effff008 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/HttpResource.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/HttpResource.java @@ -54,8 +54,8 @@ public class HttpResource implements Resource, Serializable { } @Override - public String getName() { - return resource.getName(); + public String name() { + return resource.name(); } @Override diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/InputStreamResource.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/InputStreamResource.java index fb5474df6d..f71a648c9a 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/InputStreamResource.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/InputStreamResource.java @@ -74,7 +74,7 @@ public class InputStreamResource implements Resource, Serializable { } @Override - public String getName() { + public String name() { return this.name; } diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/MultiResource.java b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/MultiResource.java index 5c5faa5e03..06ca759f4b 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/MultiResource.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/io/resource/MultiResource.java @@ -48,7 +48,7 @@ public class MultiResource implements Resource, Iterable, Iterator, Iterator, Iterator, Iterator resourceList = new ArrayList<>(); + resourceList.add(testResource1); + resourceList.add(testResource2); + resourceList.add(testResource3); + + multiResource = new MultiResource(resourceList); + } + + /** + * 测试hasNext方法 - 初始状态 + */ + @Test + void testHasNextInitial() { + // 初始游标为-1,有效游标为0,所以应该有下一个元素 + assertTrue(multiResource.hasNext(), "初始状态应该有下一个元素"); + } + + /** + * 测试hasNext方法 - 中间状态 + */ + @Test + void testHasNextMiddle() { + // 调用一次next()后,游标变为0,还有剩余元素 + multiResource.next(); + assertTrue(multiResource.hasNext(), "中间状态应该还有下一个元素"); + + // 再调用两次next(),游标变为2,还应有下一个元素 + multiResource.next(); + multiResource.next(); + assertTrue(multiResource.hasNext(), "接近末尾时应该还有下一个元素"); + } + + /** + * 测试hasNext方法 - 末尾状态 + */ + @Test + void testHasNextEnd() { + // 连续调用next()直到超出范围 + multiResource.next(); // 游标: 0 + multiResource.next(); // 游标: 1 + multiResource.next(); // 游标: 2 + multiResource.next(); // 游标: 3 + + assertFalse(multiResource.hasNext(), "超出范围后不应该有下一个元素"); + } + + /** + * 测试next方法 - 正常遍历 + */ + @Test + void testNextNormalTraversal() { + // 第一次调用next() + final Resource result1 = multiResource.next(); + assertEquals(multiResource, result1, "next()返回的应该是自身实例"); + assertEquals(0, getCursorValue(multiResource), "游标应该更新为0"); + + // 验证getName方法使用的是第一个资源 + assertEquals("resource1", multiResource.name(), "getName应该返回第一个资源名称"); + + // 第二次调用next() + final Resource result2 = multiResource.next(); + assertEquals(multiResource, result2, "next()返回的应该是自身实例"); + assertEquals(1, getCursorValue(multiResource), "游标应该更新为1"); + + // 验证getName方法使用的是第二个资源 + assertEquals("resource2", multiResource.name(), "getName应该返回第二个资源名称"); + } + + /** + * 测试next方法 - 超出边界异常 + */ + @Test + void testNextBoundaryException() { + // 遍历所有资源 + multiResource.next(); // 游标: 0 + multiResource.next(); // 游标: 1 + multiResource.next(); // 游标: 2 + multiResource.next(); // 游标: 3 + + // 再次调用next()应该抛出异常 + assertThrows(ConcurrentModificationException.class, () -> { + multiResource.next(); + }, "超出边界时调用next()应该抛出ConcurrentModificationException"); + } + + /** + * 测试remove方法 + */ + @Test + void testRemove() { + // 先移动游标到第一个位置 + multiResource.next(); // 游标: 0 + assertEquals(3, getInternalSize(multiResource), "初始资源数量应该是3"); + + // 执行删除操作 + multiResource.remove(); + + assertEquals(2, getInternalSize(multiResource), "删除后资源数量应该是2"); + assertEquals("resource2", multiResource.name(), "删除后getName应该返回第二个资源名称"); + } + + /** + * 测试iterator方法 + */ + @Test + void testIterator() { + final var iterator = multiResource.iterator(); + assertNotNull(iterator, "iterator方法不应返回null"); + + // 验证迭代器可以遍历所有资源 + int count = 0; + while (iterator.hasNext()) { + final Resource resource = iterator.next(); + assertNotNull(resource, "迭代器返回的资源不应为null"); + count++; + } + + assertEquals(3, count, "迭代器应该能遍历所有3个资源"); + } + + /** + * 测试reset方法 + */ + @Test + void testReset() { + // 移动游标到中间位置 + multiResource.next(); // 游标: 0 + multiResource.next(); // 游标: 1 + assertEquals(1, getCursorValue(multiResource), "游标应该为1"); + + // 重置游标 + multiResource.reset(); + assertEquals(-1, getCursorValue(multiResource), "重置后游标应该为-1"); + + // 重置后应该能够重新开始遍历 + assertTrue(multiResource.hasNext(), "重置后应该有下一个元素"); + final Resource result = multiResource.next(); + assertEquals(multiResource, result, "重置后next()应该返回自身"); + assertEquals(0, getCursorValue(multiResource), "重置后第一次next()后游标应该为0"); + } + + /** + * 测试并发安全的同步方法 + */ + @Test + void testSynchronizedMethods() { + // 由于无法直接测试同步块,我们验证方法可以正常调用 + assertDoesNotThrow(() -> { + multiResource.reset(); + }, "reset方法应该可以正常调用"); + + assertDoesNotThrow(() -> { + multiResource.next(); + }, "next方法应该可以正常调用"); + } + + /** + * 测试添加资源后的迭代行为 + */ + @Test + void testAddResourceThenIterate() { + final TestResource newResource = new TestResource("newResource", "newContent"); + + // 添加新资源 + multiResource.add(newResource); + + // 验证可以遍历新增的资源 + // 先遍历原有的3个资源 + multiResource.next(); // 游标: 0 + multiResource.next(); // 游标: 1 + multiResource.next(); // 游标: 2 + multiResource.next(); // 游标: 3 + + // 现在应该还有元素(第4个) + assertTrue(multiResource.hasNext(), "添加资源后应该还有元素"); + + multiResource.next(); // 游标: 4 + assertEquals(4, getInternalSize(multiResource), "资源总数应该是4"); + } + + /** + * 测试addAll方法 + */ + @Test + void testAddAllResources() { + final TestResource extraResource1 = new TestResource("extra1", "extraContent1"); + final TestResource extraResource2 = new TestResource("extra2", "extraContent2"); + + final List extraResources = List.of(extraResource1, extraResource2); + + // 添加多个资源 + multiResource.addAll(extraResources); + + assertEquals(5, getInternalSize(multiResource), "添加多个资源后总数应该是5"); + } + + // 辅助方法:通过反射获取私有字段值 + private int getCursorValue(final MultiResource multiResource) { + try { + final var field = MultiResource.class.getDeclaredField("cursor"); + field.setAccessible(true); + return field.getInt(multiResource); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + private int getInternalSize(final MultiResource multiResource) { + try { + final var field = MultiResource.class.getDeclaredField("resources"); + field.setAccessible(true); + final List resources = (List) field.get(multiResource); + return resources.size(); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 测试Resource接口的实现类,用于单元测试 + */ + private record TestResource(String name, String content) implements Resource { + @Override + public URL getUrl() { + try { + return new URL("http://example.com/" + name); + } catch (final MalformedURLException e) { + throw new RuntimeException(e); + } + } + + @Override + public long size() { + return content.getBytes(StandardCharsets.UTF_8).length; + } + + @Override + public InputStream getStream() { + return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public boolean isModified() { + return false; + } + } +} diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/io/resource/ResourceUtilTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/io/resource/ResourceUtilTest.java index 7aa353258b..2913d42436 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/io/resource/ResourceUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/io/resource/ResourceUtilTest.java @@ -38,7 +38,7 @@ public class ResourceUtilTest { @Test public void stringResourceTest(){ final StringResource stringResource = new StringResource("testData", "test"); - Assertions.assertEquals("test", stringResource.getName()); + Assertions.assertEquals("test", stringResource.name()); Assertions.assertArrayEquals("testData".getBytes(), stringResource.readBytes()); Assertions.assertArrayEquals("testData".getBytes(), IoUtil.readBytes(stringResource.getStream())); } @@ -46,7 +46,7 @@ public class ResourceUtilTest { @Test public void fileResourceTest(){ final FileResource resource = new FileResource(FileUtil.file("test.xml")); - Assertions.assertEquals("test.xml", resource.getName()); + Assertions.assertEquals("test.xml", resource.name()); Assertions.assertTrue(StrUtil.isNotEmpty(resource.readUtf8Str())); } diff --git a/hutool-http/src/main/java/cn/hutool/v7/http/client/body/MultipartOutputStream.java b/hutool-http/src/main/java/cn/hutool/v7/http/client/body/MultipartOutputStream.java index 170dd33c98..a992f82406 100644 --- a/hutool-http/src/main/java/cn/hutool/v7/http/client/body/MultipartOutputStream.java +++ b/hutool-http/src/main/java/cn/hutool/v7/http/client/body/MultipartOutputStream.java @@ -162,7 +162,7 @@ public class MultipartOutputStream extends OutputStream { * @throws IORuntimeException IO异常 */ private void appendResource(final String formFieldName, final Resource resource) throws IORuntimeException { - final String fileName = resource.getName(); + final String fileName = resource.name(); // Content-Disposition if (null == fileName) {