• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / smartsprites / 555

21 May 2026 03:26PM UTC coverage: 87.799%. Remained the same
555

push

github

hazendaz
[tests] Fix tests that were looking at size of original license before spdx change

557 of 670 branches covered (83.13%)

Branch coverage included in aggregate %.

1350 of 1502 relevant lines covered (89.88%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.04
/src/main/java/org/carrot2/util/PathUtils.java
1
/*
2
 * SPDX-License-Identifier: BSD-3-Clause
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2021-2026 Hazendaz
6
 * Copyright (C) 2007-2009, Stanisław Osiński.
7
 */
8
package org.carrot2.util;
9

10
import com.google.common.base.Strings;
11

12
import java.io.File;
13
import java.nio.file.Path;
14
import java.util.StringTokenizer;
15

16
/**
17
 * This class defines utilities methods helping to determine path-related information such as relative paths.
18
 * <p>
19
 * The original code comes from <b>org.codehaus.plexus.util.PathTool</b>.
20
 *
21
 * @author Ibrahim Chaehoi
22
 * @author <a href="mailto:pete-apache-dev@kazmier.com">Pete Kazmier</a>
23
 * @author <a href="mailto:vmassol@apache.org">Vincent Massol</a>
24
 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
25
 */
26
public class PathUtils {
27

28
    /**
29
     * Instantiates a new path utils.
30
     */
31
    private PathUtils() {
32
        // Prevent Instantiation
33
    }
34

35
    /**
36
     * This method can calculate the relative path between two pathes on a file system.
37
     *
38
     * <pre>
39
     * PathUtils.getRelativeFilePath( null, null )                                   = ""
40
     * PathUtils.getRelativeFilePath( null, "/usr/local/java/bin" )                  = ""
41
     * PathUtils.getRelativeFilePath( "/usr/local", null )                           = ""
42
     * PathUtils.getRelativeFilePath( "/usr/local", "/usr/local/java/bin" )          = "java/bin"
43
     * PathUtils.getRelativeFilePath( "/usr/local", "/usr/local/java/bin/" )         = "java/bin"
44
     * PathUtils.getRelativeFilePath( "/usr/local/java/bin", "/usr/local/" )         = "../.."
45
     * PathUtils.getRelativeFilePath( "/usr/local/", "/usr/local/java/bin/java.sh" ) = "java/bin/java.sh"
46
     * PathUtils.getRelativeFilePath( "/usr/local/java/bin/java.sh", "/usr/local/" ) = "../../.."
47
     * PathUtils.getRelativeFilePath( "/usr/local/", "/bin" )                        = "../../bin"
48
     * PathUtils.getRelativeFilePath( "/bin", "/usr/local/" )                        = "../usr/local"
49
     * </pre>
50
     *
51
     * Note: On Windows based system, the <code>/</code> character should be replaced by <code>\</code> character.
52
     *
53
     * @param oldPath
54
     *            the old path
55
     * @param newPath
56
     *            the new path
57
     *
58
     * @return a relative file path from <code>oldPath</code>.
59
     */
60
    public static final String getRelativeFilePath(final String oldPath, final String newPath) {
61
        if (Strings.isNullOrEmpty(oldPath) || Strings.isNullOrEmpty(newPath)) {
1✔
62
            return "";
1✔
63
        }
64

65
        // Normalize the path delimiters
66
        String fromPath = Path.of(oldPath).toString();
1✔
67
        String toPath = Path.of(newPath).toString();
1✔
68

69
        // strip any leading slashes if its a windows path
70
        if (toPath.matches("^\\[a-zA-Z]:")) {
1!
71
            toPath = toPath.substring(1);
×
72
        }
73
        if (fromPath.matches("^\\[a-zA-Z]:")) {
1!
74
            fromPath = fromPath.substring(1);
×
75
        }
76

77
        // lowercase windows drive letters.
78
        if (fromPath.startsWith(":", 1)) {
1!
79
            fromPath = Character.toLowerCase(fromPath.charAt(0)) + fromPath.substring(1);
×
80
        }
81
        if (toPath.startsWith(":", 1)) {
1!
82
            toPath = Character.toLowerCase(toPath.charAt(0)) + toPath.substring(1);
×
83
        }
84

85
        // check for the presence of windows drives. No relative way of
86
        // traversing from one to the other.
87
        if (toPath.startsWith(":", 1) && fromPath.startsWith(":", 1)
1!
88
                && !toPath.substring(0, 1).equals(fromPath.substring(0, 1))) {
×
89
            // they both have drive path element but they dont match, no relative path
90
            return null;
×
91
        }
92

93
        if ((toPath.startsWith(":", 1) && !fromPath.startsWith(":", 1))
1!
94
                || (!toPath.startsWith(":", 1) && fromPath.startsWith(":", 1))) {
1!
95
            // one has a drive path element and the other doesn't, no relative path.
96
            return null;
×
97
        }
98

99
        String resultPath = buildRelativePath(toPath, fromPath, File.separatorChar);
1✔
100

101
        if (newPath.endsWith(File.separator) && !resultPath.endsWith(File.separator)) {
1!
102
            return resultPath + File.separator;
1✔
103
        }
104

105
        return resultPath;
1✔
106
    }
107

108
    // ----------------------------------------------------------------------
109
    // Private methods
110
    // ----------------------------------------------------------------------
111

112
    /**
113
     * Builds the relative path.
114
     *
115
     * @param toPath
116
     *            the to path
117
     * @param fromPath
118
     *            the from path
119
     * @param separatorChar
120
     *            the separator char
121
     *
122
     * @return the string
123
     */
124
    private static String buildRelativePath(String toPath, String fromPath, final char separatorChar) {
125
        // use tokenizer to traverse paths and for lazy checking
126
        StringTokenizer toTokenizer = new StringTokenizer(toPath, String.valueOf(separatorChar));
1✔
127
        StringTokenizer fromTokenizer = new StringTokenizer(fromPath, String.valueOf(separatorChar));
1✔
128

129
        int count = 0;
1✔
130

131
        // walk along the to path looking for divergence from the from path
132
        while (toTokenizer.hasMoreTokens() && fromTokenizer.hasMoreTokens()) {
1✔
133
            if (separatorChar == '\\') {
1!
134
                if (!fromTokenizer.nextToken().equalsIgnoreCase(toTokenizer.nextToken())) {
×
135
                    break;
×
136
                }
137
            } else if (!fromTokenizer.nextToken().equals(toTokenizer.nextToken())) {
1✔
138
                break;
1✔
139
            }
140

141
            count++;
1✔
142
        }
143

144
        // Reinitialize the tokenizers to count positions to retrieve the
145
        // gobbled token
146

147
        toTokenizer = new StringTokenizer(toPath, String.valueOf(separatorChar));
1✔
148
        fromTokenizer = new StringTokenizer(fromPath, String.valueOf(separatorChar));
1✔
149

150
        while (count-- > 0) {
1✔
151
            fromTokenizer.nextToken();
1✔
152
            toTokenizer.nextToken();
1✔
153
        }
154

155
        StringBuilder relativePath = new StringBuilder();
1✔
156

157
        // add back refs for the rest of from location.
158
        while (fromTokenizer.hasMoreTokens()) {
1✔
159
            fromTokenizer.nextToken();
1✔
160

161
            relativePath.append("..");
1✔
162

163
            if (fromTokenizer.hasMoreTokens()) {
1✔
164
                relativePath.append(separatorChar);
1✔
165
            }
166
        }
167

168
        if (relativePath.length() != 0 && toTokenizer.hasMoreTokens()) {
1✔
169
            relativePath.append(separatorChar);
1✔
170
        }
171

172
        // add fwd fills for whatevers left of newPath.
173
        while (toTokenizer.hasMoreTokens()) {
1✔
174
            relativePath.append(toTokenizer.nextToken());
1✔
175

176
            if (toTokenizer.hasMoreTokens()) {
1✔
177
                relativePath.append(separatorChar);
1✔
178
            }
179
        }
180
        return relativePath.toString();
1✔
181
    }
182
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc