From f8f9376d59f3540fa416253a636a438db0a6840e Mon Sep 17 00:00:00 2001 From: Jonathan Gamba Date: Fri, 23 Feb 2024 14:24:01 -0600 Subject: [PATCH] fix(CLI): Issue 26879 cli pushing files whose name contain whitespaces fail (#27696) * #26879 Change methods to use URI's raw path and improve URL encoding The `AssetPathResolver` has been updated to use the URI's raw path rather than the path. Additionally, the `resolveAssetAndFolder` method now takes a `decodedRawPath` parameter rather than decoding the raw path within the method. Similarly, the `encodePath` method in `LocationUtils` has been significantly revised which now encodes the URL path segment by segment and maintains both single and double slashes at the beginning of URLs. * #27423 Related init command missing changes #26879 Better handling for white spaces and uncommon characters in names * #26879 Adding IT --- .../rest/api/v1/asset/AssetPathResolver.java | 15 ++--- .../action/.github/workflows/main.yml | 12 ++-- .../.github/workflows/scripts/run-push.sh | 17 ++---- .../java/com/dotcms/common/LocationUtils.java | 32 +++++++++-- .../api/client/files/PullServiceIT.java | 53 ++++++++---------- .../api/client/files/PushServiceIT.java | 18 +++--- .../traversal/RemoteTraversalServiceIT.java | 44 ++++++++------- .../cli/common/FilesTestHelperService.java | 8 ++- .../cli/src/test/resources/image (7)+.png | Bin 0 -> 395 bytes ...\347\232\204\346\203\263\345\203\2176.png" | Bin 0 -> 263 bytes 10 files changed, 111 insertions(+), 88 deletions(-) create mode 100644 tools/dotcms-cli/cli/src/test/resources/image (7)+.png create mode 100644 "tools/dotcms-cli/cli/src/test/resources/\351\200\231\345\260\261\346\230\257\346\210\221\347\232\204\346\203\263\345\203\2176.png" diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/asset/AssetPathResolver.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/asset/AssetPathResolver.java index ec2dca19620d..9ae106df5ac3 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/asset/AssetPathResolver.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/asset/AssetPathResolver.java @@ -77,7 +77,7 @@ public ResolvedAssetAndPath resolve(final String url, final User user, final boo } final Host host = siteByName.get(); - final String path = BLANK.equals(uri.getPath()) ? FORWARD_SLASH : uri.getPath(); + final String path = BLANK.equals(uri.getRawPath()) ? FORWARD_SLASH : uri.getRawPath(); if (null == path) { throw new IllegalArgumentException(String.format("Unable to determine path: [%s].", url)); } @@ -87,7 +87,8 @@ public ResolvedAssetAndPath resolve(final String url, final User user, final boo final Optional folder = resolveExistingFolder(decodedPath, host, user); if(folder.isEmpty()){ //if we've got this far we need to verify if the path is an asset. The folder will be expected to be the parent folder - Optional folderAndAsset = resolveAssetAndFolder(uri.getPath(), host, user, createMissingFolders); + Optional folderAndAsset = resolveAssetAndFolder(decodedPath, host, + user, createMissingFolders); if(folderAndAsset.isEmpty()){ throw new NotFoundInDbException(String.format("Unable to determine a valid folder or asset from uri: [%s].", url)); } @@ -102,7 +103,8 @@ public ResolvedAssetAndPath resolve(final String url, final User user, final boo } //if we succeed to determine a valid folder from the path then we resolve the last bit as an asset name - final String resource = uri.getRawQuery() != null ? uri.getPath() + "?" + uri.getRawQuery() : uri.getPath(); + final String resource = uri.getRawQuery() != null ? + uri.getRawPath() + "?" + uri.getRawQuery() : uri.getRawPath(); final Optional asset = asset(folder.get(), resource); final ResolvedAssetAndPath.Builder builder = ResolvedAssetAndPath.builder(); @@ -160,18 +162,17 @@ Optional resolveExistingFolder(final String rawPath, final Host host, fi /** * here we test a specific case we try to resolve anything that matches a pattern like forward slash followed by a string * - * @param rawPath + * @param decodedRawPath the decoded raw path * @param host * @param user * @return * @throws DotDataException * @throws DotSecurityException */ - Optional resolveAssetAndFolder(final String rawPath, final Host host, final User user, final boolean createMissingFolder) + Optional resolveAssetAndFolder(final String decodedRawPath, final Host host, + final User user, final boolean createMissingFolder) throws DotDataException, DotSecurityException { - final var decodedRawPath = URLDecoder.decode(rawPath, StandardCharsets.UTF_8); - final String startsWithForwardSlash = "^\\/[a-zA-Z0-9\\.\\-]+$"; // if our path starts with / followed by a string then we're looking at file asset in the root folder if (decodedRawPath.matches(startsWithForwardSlash)) { diff --git a/tools/dotcms-cli/action/.github/workflows/main.yml b/tools/dotcms-cli/action/.github/workflows/main.yml index 5dc3bbdd8b95..eeb2b35b3241 100644 --- a/tools/dotcms-cli/action/.github/workflows/main.yml +++ b/tools/dotcms-cli/action/.github/workflows/main.yml @@ -35,15 +35,15 @@ jobs: echo "$GITHUB_ENV" - name: Get changes - id: changed-files run: | - echo "changed_files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_OUTPUT + git diff --name-only ${{ github.event.before }} ${{ github.event.after }} > changed_files.txt - name: List changed files run: | - for file in ${{ steps.changed-files.outputs.changed_files }}; do - echo "$file was changed" - done + while IFS= read -r line + do + echo "\"$line\" was changed" + done < changed_files.txt - name: Github Event Context properties run: | @@ -90,7 +90,7 @@ jobs: run: | chmod +x ./.github/workflows/scripts/run-push.sh source ./.github/workflows/scripts/run-push.sh - install_cli "${{env.DOT_CLI_JAR_DOWNLOAD_URL}}" "${{env.DOT_FORCE_DOWNLOAD}}" "${{env.DOT_API_URL}}" + install_cli "${{env.DOT_CLI_JAR_DOWNLOAD_URL}}" "${{env.DOT_FORCE_DOWNLOAD}}" run_cli_push "${{github.workspace}}${{env.DOT_REPO_BASE_PATH}}" "${{ secrets.DOT_TOKEN }}" "${{ env.DOT_CLI_OPTS }}" echo "exit-code=$exit_code" >> "$GITHUB_OUTPUT" print_log diff --git a/tools/dotcms-cli/action/.github/workflows/scripts/run-push.sh b/tools/dotcms-cli/action/.github/workflows/scripts/run-push.sh index 19a44d228994..c2e824608f5b 100644 --- a/tools/dotcms-cli/action/.github/workflows/scripts/run-push.sh +++ b/tools/dotcms-cli/action/.github/workflows/scripts/run-push.sh @@ -5,10 +5,11 @@ DOT_SERVICE_YML="dot-service.yml" RUN_JAVA_VERSION=1.3.8 -SERVICES_FILE_CONTENT=' -- name: "default" +SERVICES_FILE_CONTENT=" +- name: \"default\" active: true -' + url: \"$DOT_API_URL\" +" _make_home(){ if [ ! -d "$DOT_CLI_HOME" ]; then @@ -52,7 +53,6 @@ _get_run_java_script(){ } _setup_CLI(){ - API_URL=$1 #Lets create the services file dot-service.yml #the services yml is used to store the server configurations or profiles if you Will DOT_SERVICES_HOME=$HOME/.dotcms/ @@ -69,13 +69,7 @@ _setup_CLI(){ # Now generate the file echo "$SERVICES_FILE_CONTENT" >> "$SERVICE_FILE"; - #Tell the CLI to use the demo server through the profile "default" - #The suffix value used to create the environment value must match the name on dot-service.yml file in this case we are using default - #dotcms.client.servers.default=https://demo.dotcms.com/api - - export DOTCMS_CLIENT_SERVERS_DEFAULT=$API_URL export QUARKUS_LOG_FILE_PATH=$DOT_CLI_HOME"dotcms-cli.log" - } print_log(){ @@ -105,12 +99,11 @@ _run_cli_push(){ install_cli(){ cli_release_download_url=$1 force_download=$2 - dotApiURL=$3 _make_home _get_CLI "$cli_release_download_url" "$force_download" _get_run_java_script "$force_download" - _setup_CLI "$dotApiURL" + _setup_CLI } run_cli_push(){ diff --git a/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/common/LocationUtils.java b/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/common/LocationUtils.java index dd68b45fc06c..be4a7c3b1329 100644 --- a/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/common/LocationUtils.java +++ b/tools/dotcms-cli/api-data-model/src/main/java/com/dotcms/common/LocationUtils.java @@ -71,14 +71,36 @@ public static Path localPathFromAssetData(final String workspace, final String s } /** - * Encodes the given path by replacing spaces with URL-encoded spaces. + * Encodes a URL path by URL encoding each path segment. * - * @param path the path to be encoded - * @return the encoded path + * @param path the URL path to encode + * @return the encoded URL path */ public static String encodePath(final String path) { - return path.replaceAll(" ", - URLEncoder.encode(" ", StandardCharsets.UTF_8)); + + var url = path; + boolean startsWithDoubleSlash = url.startsWith("//"); + + // If it starts with double slash, remove them + if (startsWithDoubleSlash) { + url = url.substring(2); + } + + // Split the URL into individual parts/segments based on "/" separator + String[] parts = url.split("/"); + + StringBuilder encodedUrlBuilder = new StringBuilder(); + for (String part : parts) { + String encodedPart = URLEncoder.encode(part, StandardCharsets.UTF_8); + encodedUrlBuilder.append('/').append(encodedPart); + } + + // If the original URL started with a double slash, we add a slash back at the beginning + if (startsWithDoubleSlash) { + encodedUrlBuilder.insert(0, "/"); + } + + return encodedUrlBuilder.toString(); } } diff --git a/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PullServiceIT.java b/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PullServiceIT.java index c5c32a9bbb90..879938d2b408 100644 --- a/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PullServiceIT.java +++ b/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PullServiceIT.java @@ -23,8 +23,6 @@ import io.quarkus.test.junit.TestProfile; import java.io.IOException; import java.net.URL; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -146,12 +144,9 @@ void validateSite(final Path tempFolder, final String testSiteName) } try (final Stream walk = Files.walk(tempFolder)) { walk.filter(Files::isRegularFile) - .forEach(path -> { - String decodedPath = URLDecoder.decode( - tempFolder.relativize(path).toString(), - StandardCharsets.UTF_8); - collectedFiles.add(decodedPath); - }); + .forEach(path -> collectedFiles.add( + tempFolder.relativize(path).toString() + )); } //Let's remove the workspace folder from the list List existingFolders = collectedFolders.stream() @@ -180,7 +175,7 @@ void validateSite(final Path tempFolder, final String testSiteName) Map.entry(basePath + "/folder2", Arrays.asList("subFolder2-1", "subFolder2-2", "subFolder2-3")), Map.entry(basePath + "/folder2/subFolder2-1", - Arrays.asList("subFolder2-1-1", "subFolder2-1-2", + Arrays.asList("subFolder2-1-1-子資料夾", "subFolder2-1-2", "subFolder2-1-3")), Map.entry(basePath + "/folder2/subFolder2-2", Collections.emptyList()), @@ -197,8 +192,8 @@ void validateSite(final Path tempFolder, final String testSiteName) basePath, Collections.emptyList(), basePath + "/folder1/subFolder1-1/subFolder1-1-1", Arrays.asList("image1.png", "image4.jpg"), - basePath + "/folder2/subFolder2-1/subFolder2-1-1", - Arrays.asList("image2.png"), + basePath + "/folder2/subFolder2-1/subFolder2-1-1-子資料夾", + Arrays.asList("image2.png", "這就是我的想像6.png", "image (7)+.png"), basePath + "/folder3", Arrays.asList("image 3.png"), basePath + "/folder4 withSpace", Arrays.asList("image5.jpg") ); @@ -329,11 +324,8 @@ void Test_Folders_Check() throws IOException { } try (final Stream walk = Files.walk(tempFolder)) { walk.filter(Files::isRegularFile) - .forEach(path -> { - String decodedPath = URLDecoder.decode( - tempFolder.relativize(path).toString(), StandardCharsets.UTF_8); - collectedFiles.add(decodedPath); - }); + .forEach( + path -> collectedFiles.add(tempFolder.relativize(path).toString())); } //Let's remove the workspace folder from the list List existingFolders = collectedFolders.stream().map(folder -> folder.replaceAll( @@ -357,7 +349,8 @@ void Test_Folders_Check() throws IOException { Map.entry(basePath + "/folder2", Arrays.asList("subFolder2-1", "subFolder2-2", "subFolder2-3")), Map.entry(basePath + "/folder2/subFolder2-1", - Arrays.asList("subFolder2-1-1", "subFolder2-1-2", "subFolder2-1-3")), + Arrays.asList("subFolder2-1-1-子資料夾", "subFolder2-1-2", + "subFolder2-1-3")), Map.entry(basePath + "/folder2/subFolder2-2", Collections.emptyList()), Map.entry(basePath + "/folder2/subFolder2-3", @@ -372,7 +365,8 @@ void Test_Folders_Check() throws IOException { Map> expectedFiles = Map.of( basePath, Collections.emptyList(), basePath + "/folder1/subFolder1-1/subFolder1-1-1", Arrays.asList("image1.png", "image4.jpg"), - basePath + "/folder2/subFolder2-1/subFolder2-1-1", Arrays.asList("image2.png"), + basePath + "/folder2/subFolder2-1/subFolder2-1-1-子資料夾", + Arrays.asList("image2.png", "這就是我的想像6.png", "image (7)+.png"), basePath + "/folder3", Arrays.asList("image 3.png"), basePath + "/folder4 withSpace", Arrays.asList("image5.jpg") ); @@ -494,11 +488,9 @@ void Test_Asset_Check() throws IOException { } try (final Stream walk = Files.walk(tempFolder)) { walk.filter(Files::isRegularFile) - .forEach(path -> { - String decodedPath = URLDecoder.decode( - tempFolder.relativize(path).toString(), StandardCharsets.UTF_8); - collectedFiles.add(decodedPath); - }); + .forEach( + path -> collectedFiles.add(tempFolder.relativize(path).toString()) + ); } //Let's remove the workspace folder from the list List existingFolders = collectedFolders.stream() @@ -594,7 +586,7 @@ void Test_Asset_Check2() throws IOException { final var testSiteName = filesTestHelper.prepareData(); final var folderPath = String.format( - "//%s/folder2/subFolder2-1/subFolder2-1-1/image2.png", testSiteName); + "//%s/folder2/subFolder2-1/subFolder2-1-1-子資料夾/image2.png", testSiteName); // Pulling the content OutputOptionMixin outputOptions = new MockOutputOptionMixin(); @@ -638,11 +630,9 @@ void Test_Asset_Check2() throws IOException { } try (final Stream walk = Files.walk(tempFolder)) { walk.filter(Files::isRegularFile) - .forEach(path -> { - String decodedPath = URLDecoder.decode( - tempFolder.relativize(path).toString(), StandardCharsets.UTF_8); - collectedFiles.add(decodedPath); - }); + .forEach( + path -> collectedFiles.add(tempFolder.relativize(path).toString()) + ); } //Let's remove the workspace folder from the list List existingFolders = collectedFolders.stream() @@ -656,13 +646,14 @@ void Test_Asset_Check2() throws IOException { Map> expectedFolders = Map.of( basePath, Arrays.asList("folder2"), basePath + "/folder2", Arrays.asList("subFolder2-1"), - basePath + "/folder2/subFolder2-1", Arrays.asList("subFolder2-1-1") + basePath + "/folder2/subFolder2-1", Arrays.asList("subFolder2-1-1-子資料夾") ); // Expected folder structure based on the treeNode object Map> expectedFiles = Map.of( basePath, Collections.emptyList(), - basePath + "/folder2/subFolder2-1/subFolder2-1-1", Arrays.asList("image2.png") + basePath + "/folder2/subFolder2-1/subFolder2-1-1-子資料夾", + Arrays.asList("image2.png") ); // Validate the actual folders against the expected folders diff --git a/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PushServiceIT.java b/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PushServiceIT.java index a0fadd9456ab..1801284381a0 100644 --- a/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PushServiceIT.java +++ b/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/PushServiceIT.java @@ -263,8 +263,8 @@ void Test_Push_New_Site() throws IOException { var treeNodePushInfo = treeNode.collectPushInfo(); // Should be nothing to push as we are pushing the same folder we pull - Assertions.assertEquals(5, treeNodePushInfo.assetsToPushCount()); - Assertions.assertEquals(5, treeNodePushInfo.assetsNewCount()); + Assertions.assertEquals(7, treeNodePushInfo.assetsToPushCount()); + Assertions.assertEquals(7, treeNodePushInfo.assetsNewCount()); Assertions.assertEquals(0, treeNodePushInfo.assetsModifiedCount()); Assertions.assertEquals(0, treeNodePushInfo.assetsToDeleteCount()); Assertions.assertEquals(9, treeNodePushInfo.foldersToPushCount()); @@ -309,8 +309,10 @@ void Test_Push_New_Site() throws IOException { //Validating the tree // subFolder1-1-1 (has 2 asset) Assertions.assertEquals(2, newSiteTreeNode.children().get(0).children().get(0).children().get(0).assets().size()); - // subFolder2-1-1 (has 1 asset) - Assertions.assertEquals(1, newSiteTreeNode.children().get(1).children().get(0).children().get(0).assets().size()); + // subFolder2-1-1-子資料夾 (has 3 asset) + Assertions.assertEquals(3, + newSiteTreeNode.children().get(1). + children().get(0).children().get(0).assets().size()); // Folder 3 (has 1 asset) Assertions.assertEquals(1, newSiteTreeNode.children().get(2).assets().size()); @@ -381,7 +383,8 @@ void Test_Push_Modified_Data() throws IOException { //If we want a folder to be removed from the remote instance it needs to be removed from all our folder branches for good Path workingFolderToRemove = Paths.get(absolutePath.toString(),"working","en-us",testSiteName,"folder3"); // Removing an asset - Path assetToRemove = Paths.get(absolutePath.toString(),"live","en-us",testSiteName,"folder2","subFolder2-1","subFolder2-1-1","image2.png"); + Path assetToRemove = Paths.get(absolutePath.toString(), "live", "en-us", testSiteName, + "folder2", "subFolder2-1", "subFolder2-1-1-子資料夾", "image2.png"); FileUtils.deleteDirectory(liveFolderToRemove.toFile()); FileUtils.deleteDirectory(workingFolderToRemove.toFile()); @@ -477,8 +480,9 @@ void Test_Push_Modified_Data() throws IOException { //Validating the tree // subFolder1-1-1 (has 2 asset) Assertions.assertEquals(2, updatedTreeNode.children().get(0).children().get(0).children().get(0).assets().size()); - // subFolder2-1-1 (has 0 asset) - Assertions.assertEquals(0, updatedTreeNode.children().get(1).children().get(0).children().get(0).assets().size()); + // subFolder2-1-1-子資料夾 (has 2 assets) -> 1 was removed + Assertions.assertEquals(2, updatedTreeNode.children(). + get(1).children().get(0).children().get(0).assets().size()); // Folder 4 withSpace (has 1 asset) Assertions.assertEquals(1, updatedTreeNode.children().get(2).assets().size()); // Folder 5 (has 1 asset) diff --git a/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/traversal/RemoteTraversalServiceIT.java b/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/traversal/RemoteTraversalServiceIT.java index 9a4cf969fbde..18142f266cea 100644 --- a/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/traversal/RemoteTraversalServiceIT.java +++ b/tools/dotcms-cli/cli/src/test/java/com/dotcms/api/client/files/traversal/RemoteTraversalServiceIT.java @@ -123,8 +123,9 @@ void Test_Folders_Check() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has 1 asset) - Assertions.assertEquals(1, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); + // subFolder2-1-1-子資料夾 (has 3 asset) + Assertions.assertEquals(3, + treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); // SubFolder2-3 @@ -196,7 +197,8 @@ void Test_Asset_Check2() throws IOException { // Preparing the data for the test final var testSiteName = filesTestHelper.prepareData(); - final var folderPath = String.format("//%s/folder2/subFolder2-1/subFolder2-1-1/image2.png", + final var folderPath = String.format( + "//%s/folder2/subFolder2-1/subFolder2-1-1-子資料夾/image2.png", testSiteName); var result = remoteTraversalService.traverseRemoteFolder( @@ -213,11 +215,11 @@ void Test_Asset_Check2() throws IOException { // ============================ //Validating the tree // ============================ - // subFolder2-1-1 (Root) + // subFolder2-1-1-子資料夾 (Root) Assertions.assertEquals(0, treeNode.children().size()); - // subFolder2-1-1 (has 1 asset) - Assertions.assertEquals(1, treeNode.assets().size()); + // subFolder2-1-1-子資料夾 (has 3 asset) + Assertions.assertEquals(3, treeNode.assets().size()); } @Test @@ -511,8 +513,9 @@ void Test_Include_Assets() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has 1 asset) - Assertions.assertEquals(1, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); + // subFolder2-1-1-子資料夾 (has 3 asset) + Assertions.assertEquals(3, + treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); // SubFolder2-3 @@ -576,7 +579,7 @@ void Test_Include_Assets2() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has no asset) + // subFolder2-1-1-子資料夾 (has no asset) Assertions.assertEquals(0, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); @@ -641,8 +644,9 @@ void Test_Include_Assets3() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has 1 asset) - Assertions.assertEquals(1, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); + // subFolder2-1-1-子資料夾 (has 3 asset) + Assertions.assertEquals(3, + treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); // SubFolder2-3 @@ -706,7 +710,7 @@ void Test_Include_Assets4() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has 1 asset) + // subFolder2-1-1-子資料夾 (has 1 asset) Assertions.assertEquals(1, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); @@ -771,7 +775,7 @@ void Test_Include_Assets5() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has 0 asset) + // subFolder2-1-1-子資料夾 (has 0 asset) Assertions.assertEquals(0, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); @@ -1046,7 +1050,7 @@ void Test_Exclude_Assets() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has no asset) + // subFolder2-1-1-子資料夾 (has no asset) Assertions.assertEquals(0, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); @@ -1111,8 +1115,9 @@ void Test_Exclude_Assets2() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has 1 asset) - Assertions.assertEquals(1, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); + // subFolder2-1-1-子資料夾 (has 3 asset) + Assertions.assertEquals(3, + treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); // SubFolder2-3 @@ -1176,7 +1181,7 @@ void Test_Exclude_Assets3() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has 0 asset) + // subFolder2-1-1-子資料夾 (has 0 asset) Assertions.assertEquals(0, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); @@ -1241,8 +1246,9 @@ void Test_Exclude_Assets4() throws IOException { Assertions.assertEquals(3, treeNode.children().get(1).children().size()); // SubFolder2-1 Assertions.assertEquals(3, treeNode.children().get(1).children().get(0).children().size()); - // subFolder2-1-1 (has 1 asset) - Assertions.assertEquals(1, treeNode.children().get(1).children().get(0).children().get(0).assets().size()); + // subFolder2-1-1-子資料夾 (has 3 asset) + Assertions.assertEquals(3, + treeNode.children().get(1).children().get(0).children().get(0).assets().size()); // SubFolder2-2 Assertions.assertEquals(0, treeNode.children().get(1).children().get(1).children().size()); // SubFolder2-3 diff --git a/tools/dotcms-cli/cli/src/test/java/com/dotcms/cli/common/FilesTestHelperService.java b/tools/dotcms-cli/cli/src/test/java/com/dotcms/cli/common/FilesTestHelperService.java index 33a8bc131528..cb123cd0036e 100644 --- a/tools/dotcms-cli/cli/src/test/java/com/dotcms/cli/common/FilesTestHelperService.java +++ b/tools/dotcms-cli/cli/src/test/java/com/dotcms/cli/common/FilesTestHelperService.java @@ -91,7 +91,7 @@ public String prepareData(final boolean includeAssets) throws IOException { final String subfolder1_2_3 = "subFolder1-2-3"; // subfolder2_1 children - final String subfolder2_1_1 = "subFolder2-1-1"; + final String subfolder2_1_1 = "subFolder2-1-1-子資料夾"; final String subfolder2_1_2 = "subFolder2-1-2"; final String subfolder2_1_3 = "subFolder2-1-3"; @@ -131,6 +131,12 @@ public String prepareData(final boolean includeAssets) throws IOException { pushFile(true, "en-us", newSiteName, String.format("/%s/%s/%s", folder2, subfolder2_1, subfolder2_1_1), "image2.png"); + pushFile(true, "en-us", newSiteName, + String.format("/%s/%s/%s", folder2, subfolder2_1, subfolder2_1_1), + "這就是我的想像6.png"); + pushFile(true, "en-us", newSiteName, + String.format("/%s/%s/%s", folder2, subfolder2_1, subfolder2_1_1), + "image (7)+.png"); pushFile(true, "en-us", newSiteName, String.format("/%s", folder3), "image 3.png"); diff --git a/tools/dotcms-cli/cli/src/test/resources/image (7)+.png b/tools/dotcms-cli/cli/src/test/resources/image (7)+.png new file mode 100644 index 0000000000000000000000000000000000000000..704bc208416cfd966d0cf069bd1824c5dd122511 GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?I3?vN&YJLDI=>VS)*E46%0GU2MJ~L;|+_Y(v zv9YnFq-0uJT77+e?X7iZ85kI~JzX3_G8*4bGW0)eAmHZjc|dYy$BC$mmn@ks-CQ*3 zXoP4~sf$WSk50+ChEKaKZ|4R+Ju-DRr2ZJ+h#KUQ%8nhypC{tMopnOG?QZn3xC z)7w_h6Sv>8Y5$cHS~yo=rJ-w%wd6C;+K}JpdPMk>WS%{4`^IZC?bjir6O$(#Z+m;5 zZ_$HK25Ha_M4rW1ef@m?retv)ky)yywd>JIzMSA9KGqUsy< zbC2`|(e{~|e>is?dOWw`N=y9fwR$K1F&CP?x!W+;a^tK|VY>cGv8NK>vm8-YTb{D* lo(=17VX;r;axm}R|G>-p()rAHKbKyRkf*Dk%Q~loCII48vSk1O literal 0 HcmV?d00001 diff --git "a/tools/dotcms-cli/cli/src/test/resources/\351\200\231\345\260\261\346\230\257\346\210\221\347\232\204\346\203\263\345\203\2176.png" "b/tools/dotcms-cli/cli/src/test/resources/\351\200\231\345\260\261\346\230\257\346\210\221\347\232\204\346\203\263\345\203\2176.png" new file mode 100644 index 0000000000000000000000000000000000000000..f9bac1f4d9c5c76b6edfcca8da6f931f5f026f09 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKx3?xrnI^qbVqyv0HT+f_217z0M*ZcVR%$zxM z)22<5l9Fj@X~xFJn^y@R1IjJ;ba4!^=uJ+LU|pObBEaTzjF0D?+YXk9%RSsPTFy#6 z*tCM_%t{`f95x-Lg3J)cZ9<}L4(x3u3$}^08L+1?3UK&j=M?ZHWUv`=$4(Apb+BO$ zD^ys|d?H2M*g=%xqlm;TS=j?!k*u--tPKr;jf#>QN_;78GrJdXHOR~o(mOO!N{8#p zoHGG08gv-Gr7fPpB+%TWn~>ln%FxW9k#<1SfXnUR1U7~hVX8N@uTSp+I+?-K)z4*} HQ$iB}c{EbV literal 0 HcmV?d00001