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

hazendaz / smartsprites / #43

11 Nov 2023 07:47PM UTC coverage: 88.431%. Remained the same
#43

push

github

hazendaz
[tests] Fix tests given they expected order and now license on everything for +36

1437 of 1625 relevant lines covered (88.43%)

0.88 hits per line

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

76.0
/src/main/java/org/carrot2/util/PathUtils.java
1
/*
2
 * SmartSprites Project
3
 *
4
 * Copyright (C) 2007-2009, Stanisław Osiński.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without modification,
8
 * are permitted provided that the following conditions are met:
9
 *
10
 * - Redistributions of  source code must  retain the above  copyright notice, this
11
 *   list of conditions and the following disclaimer.
12
 *
13
 * - Redistributions in binary form must reproduce the above copyright notice, this
14
 *   list of conditions and the following  disclaimer in  the documentation  and/or
15
 *   other materials provided with the distribution.
16
 *
17
 * - Neither the name of the SmartSprites Project nor the names of its contributors
18
 *   may  be used  to endorse  or  promote  products derived   from  this  software
19
 *   without specific prior written permission.
20
 *
21
 * - We kindly request that you include in the end-user documentation provided with
22
 *   the redistribution and/or in the software itself an acknowledgement equivalent
23
 *   to  the  following: "This product includes software developed by the SmartSprites
24
 *   Project."
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  AND
27
 * ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED  TO, THE IMPLIED
28
 * WARRANTIES  OF  MERCHANTABILITY  AND  FITNESS  FOR  A  PARTICULAR  PURPOSE   ARE
29
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE  FOR
30
 * ANY DIRECT, INDIRECT, INCIDENTAL,  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  DAMAGES
31
 * (INCLUDING, BUT  NOT LIMITED  TO, PROCUREMENT  OF SUBSTITUTE  GOODS OR SERVICES;
32
 * LOSS OF USE, DATA, OR PROFITS;  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND  ON
33
 * ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY,  OR TORT
34
 * (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY WAY  OUT OF THE USE  OF THIS
35
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 */
37
package org.carrot2.util;
38

39
import java.io.File;
40
import java.util.StringTokenizer;
41

42
import com.google.common.base.Strings;
43

44
/**
45
 * This class defines utilities methods helping to determine path-related
46
 * information such as relative paths.
47
 * 
48
 * The original code comes from <b>org.codehaus.plexus.util.PathTool</b>.
49
 * 
50
 * @author Ibrahim Chaehoi
51
 * 
52
 * Original Authors :
53
 * @author <a href="mailto:pete-apache-dev@kazmier.com">Pete Kazmier</a>
54
 * @author <a href="mailto:vmassol@apache.org">Vincent Massol</a>
55
 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
56
 */
57
public class PathUtils {
58

59

60
    private PathUtils()
61
    {
62
        // Prevent Instantiation
63
    }
64

65
    /**
66
     * This method can calculate the relative path between two pathes on a file system.
67
     *
68
     * <pre>
69
     * PathUtils.getRelativeFilePath( null, null )                                   = ""
70
     * PathUtils.getRelativeFilePath( null, "/usr/local/java/bin" )                  = ""
71
     * PathUtils.getRelativeFilePath( "/usr/local", null )                           = ""
72
     * PathUtils.getRelativeFilePath( "/usr/local", "/usr/local/java/bin" )          = "java/bin"
73
     * PathUtils.getRelativeFilePath( "/usr/local", "/usr/local/java/bin/" )         = "java/bin"
74
     * PathUtils.getRelativeFilePath( "/usr/local/java/bin", "/usr/local/" )         = "../.."
75
     * PathUtils.getRelativeFilePath( "/usr/local/", "/usr/local/java/bin/java.sh" ) = "java/bin/java.sh"
76
     * PathUtils.getRelativeFilePath( "/usr/local/java/bin/java.sh", "/usr/local/" ) = "../../.."
77
     * PathUtils.getRelativeFilePath( "/usr/local/", "/bin" )                        = "../../bin"
78
     * PathUtils.getRelativeFilePath( "/bin", "/usr/local/" )                        = "../usr/local"
79
     * </pre>
80
     * Note: On Windows based system, the <code>/</code> character should be replaced by <code>\</code> character.
81
     *
82
     * @param oldPath
83
     * @param newPath
84
     * @return a relative file path from <code>oldPath</code>.
85
     */
86
    public static final String getRelativeFilePath( final String oldPath, final String newPath )
87
    {
88
        if (Strings.isNullOrEmpty(oldPath) || Strings.isNullOrEmpty(newPath))
1✔
89
        {
90
            return "";
×
91
        }
92

93
        // normalise the path delimiters
94
        String fromPath = new File( oldPath ).getPath();
1✔
95
        String toPath = new File( newPath ).getPath();
1✔
96

97
        // strip any leading slashes if its a windows path
98
        if ( toPath.matches( "^\\[a-zA-Z]:" ) )
1✔
99
        {
100
            toPath = toPath.substring( 1 );
×
101
        }
102
        if ( fromPath.matches( "^\\[a-zA-Z]:" ) )
1✔
103
        {
104
            fromPath = fromPath.substring( 1 );
×
105
        }
106

107
        // lowercase windows drive letters.
108
        if ( fromPath.startsWith( ":", 1 ) )
1✔
109
        {
110
            fromPath = Character.toLowerCase( fromPath.charAt( 0 ) ) + fromPath.substring( 1 );
×
111
        }
112
        if ( toPath.startsWith( ":", 1 ) )
1✔
113
        {
114
            toPath = Character.toLowerCase( toPath.charAt( 0 ) ) + toPath.substring( 1 );
×
115
        }
116

117
        // check for the presence of windows drives. No relative way of
118
        // traversing from one to the other.
119
        if ( ( toPath.startsWith( ":", 1 ) && fromPath.startsWith( ":", 1 ) )
1✔
120
                        && ( !toPath.substring( 0, 1 ).equals( fromPath.substring( 0, 1 ) ) ) )
×
121
        {
122
            // they both have drive path element but they dont match, no relative path
123
            return null;
×
124
        }
125

126
        if ( ( toPath.startsWith( ":", 1 ) && !fromPath.startsWith( ":", 1 ) )
1✔
127
                        || ( !toPath.startsWith( ":", 1 ) && fromPath.startsWith( ":", 1 ) ) )
1✔
128
        {
129
            // one has a drive path element and the other doesnt, no relative path.
130
            return null;
×
131
        }
132

133
        String resultPath = buildRelativePath( toPath, fromPath, File.separatorChar );
1✔
134

135
        if ( newPath.endsWith( File.separator ) && !resultPath.endsWith( File.separator ) )
1✔
136
        {
137
            return resultPath + File.separator;
×
138
        }
139

140
        return resultPath;
1✔
141
    }
142

143
    // ----------------------------------------------------------------------
144
    // Private methods
145
    // ----------------------------------------------------------------------
146

147
    private static final String buildRelativePath( String toPath,  String fromPath, final char separatorChar )
148
    {
149
        // use tokenizer to traverse paths and for lazy checking
150
        StringTokenizer toTokenizer = new StringTokenizer( toPath, String.valueOf( separatorChar ) );
1✔
151
        StringTokenizer fromTokenizer = new StringTokenizer( fromPath, String.valueOf( separatorChar ) );
1✔
152

153
        int count = 0;
1✔
154

155
        // walk along the to path looking for divergence from the from path
156
        while ( toTokenizer.hasMoreTokens() && fromTokenizer.hasMoreTokens() )
1✔
157
        {
158
            if ( separatorChar == '\\' )
1✔
159
            {
160
                if ( !fromTokenizer.nextToken().equalsIgnoreCase( toTokenizer.nextToken() ) )
×
161
                {
162
                    break;
×
163
                }
164
            }
165
            else
166
            {
167
                if ( !fromTokenizer.nextToken().equals( toTokenizer.nextToken() ) )
1✔
168
                {
169
                    break;
1✔
170
                }
171
            }
172

173
            count++;
1✔
174
        }
175

176
        // reinitialise the tokenizers to count positions to retrieve the
177
        // gobbled token
178

179
        toTokenizer = new StringTokenizer( toPath, String.valueOf( separatorChar ) );
1✔
180
        fromTokenizer = new StringTokenizer( fromPath, String.valueOf( separatorChar ) );
1✔
181

182
        while ( count-- > 0 )
1✔
183
        {
184
            fromTokenizer.nextToken();
1✔
185
            toTokenizer.nextToken();
1✔
186
        }
187

188
        StringBuilder relativePath = new StringBuilder();
1✔
189

190
        // add back refs for the rest of from location.
191
        while ( fromTokenizer.hasMoreTokens() )
1✔
192
        {
193
            fromTokenizer.nextToken();
1✔
194

195
            relativePath.append("..");
1✔
196

197
            if ( fromTokenizer.hasMoreTokens() )
1✔
198
            {
199
                relativePath.append(separatorChar);
×
200
            }
201
        }
202

203
        if ( relativePath.length() != 0 && toTokenizer.hasMoreTokens() )
1✔
204
        {
205
            relativePath.append(separatorChar);
1✔
206
        }
207

208
        // add fwd fills for whatevers left of newPath.
209
        while ( toTokenizer.hasMoreTokens() )
1✔
210
        {
211
            relativePath.append(toTokenizer.nextToken());
1✔
212

213
            if ( toTokenizer.hasMoreTokens() )
1✔
214
            {
215
                relativePath.append(separatorChar);
1✔
216
            }
217
        }
218
        return relativePath.toString();
1✔
219
    }
220
}
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