* Changed semantics of FileName.resolveName() with 'child' scope. * Fixed a couple of problems in UriParser.normalise(). * Split up LocalFileNameParser into a Windows specifc parser and a generic parser. * More test cases. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271668 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -67,9 +67,8 @@ public interface FileName | |||
| FileName resolveName( String path ) throws FileSystemException; | |||
| /** | |||
| * Resolves a name, relative to the file. Refer to {@link NameScope#CHILD} | |||
| * and {@link NameScope#FILE_SYSTEM} for a description of how names are | |||
| * resolved. | |||
| * Resolves a name, relative to the file. Refer to {@link NameScope} | |||
| * for a description of how names are resolved. | |||
| * | |||
| * @param name | |||
| * The path to resolve. | |||
| @@ -123,9 +123,8 @@ public interface FileObject | |||
| FileObject[] getChildren() throws FileSystemException; | |||
| /** | |||
| * Finds a file, relative to this file. Refer to {@link NameScope#CHILD} | |||
| * and {@link NameScope#FILE_SYSTEM} for a description of how names | |||
| * are resolved in the different scopes. | |||
| * Finds a file, relative to this file. Refer to {@link NameScope} | |||
| * for a description of how names are resolved in the different scopes. | |||
| * | |||
| * @param name | |||
| * The name to resolve. | |||
| @@ -207,7 +206,7 @@ public interface FileObject | |||
| * | |||
| * @see FileContent#close | |||
| * | |||
| * @throws FileSystemEception | |||
| * @throws FileSystemException | |||
| * On error closing the file. | |||
| */ | |||
| void close() throws FileSystemException; | |||
| @@ -16,14 +16,19 @@ package org.apache.aut.vfs; | |||
| public final class NameScope | |||
| { | |||
| /** | |||
| * Resolve against the children of the base file. | |||
| * | |||
| * <p>The supplied name must be a valid element name. That is, it may | |||
| * not be empty, or <code>.</code>, or <code>..</code>, or contain any | |||
| * separator characters. | |||
| * Resolve against the children of the base file. The name is resolved | |||
| * as described by {@link #FILE_SYSTEM}. However, an exception is | |||
| * thrown if the resolved file is not a direct child of the base file. | |||
| */ | |||
| public final static NameScope CHILD = new NameScope( "child" ); | |||
| /** | |||
| * Resolve against the descendents of the base file. The name is resolved | |||
| * as described by {@link #FILE_SYSTEM}. However, an exception is thrown | |||
| * if the resolved file is not a descendent of the base file. | |||
| */ | |||
| public final static NameScope DESCENDENT = new NameScope( "descendent" ); | |||
| /** | |||
| * Resolve against files in the same file system as the base file. | |||
| * | |||
| @@ -18,22 +18,39 @@ import org.apache.aut.vfs.NameScope; | |||
| */ | |||
| public class DefaultFileName implements FileName | |||
| { | |||
| private UriParser m_parser; | |||
| private String m_rootPrefix; | |||
| private String m_absPath; | |||
| private final UriParser m_parser; | |||
| private final String m_rootPrefix; | |||
| private final String m_absPath; | |||
| // Cached stuff | |||
| private String m_uri; | |||
| private String m_baseName; | |||
| public DefaultFileName( UriParser parser, String rootPrefix, String absPath ) | |||
| public DefaultFileName( final UriParser parser, | |||
| final String rootPrefix, | |||
| final String absPath ) | |||
| { | |||
| m_parser = parser; | |||
| m_rootPrefix = rootPrefix; | |||
| m_absPath = absPath; | |||
| } | |||
| // TODO - make these usable as hash keys | |||
| /** | |||
| * Returns the hashcode for this name. | |||
| */ | |||
| public int hashCode() | |||
| { | |||
| return ( m_rootPrefix.hashCode() ^ m_absPath.hashCode() ); | |||
| } | |||
| /** | |||
| * Determines if this object is equal to another. | |||
| */ | |||
| public boolean equals( final Object obj ) | |||
| { | |||
| final DefaultFileName name = (DefaultFileName)obj; | |||
| return ( m_rootPrefix.equals( name.m_rootPrefix ) && m_absPath.equals( m_absPath ) ); | |||
| } | |||
| /** | |||
| * Returns the URI of the file. | |||
| @@ -67,22 +84,12 @@ public class DefaultFileName implements FileName | |||
| /** | |||
| * Returns the name of a child of the file. | |||
| */ | |||
| public FileName resolveName( String name, NameScope scope ) throws FileSystemException | |||
| public FileName resolveName( final String name, | |||
| final NameScope scope ) | |||
| throws FileSystemException | |||
| { | |||
| if( scope == NameScope.CHILD ) | |||
| { | |||
| String childPath = m_parser.getChildPath( m_absPath, name ); | |||
| return new DefaultFileName( m_parser, m_rootPrefix, childPath ); | |||
| } | |||
| else if( scope == NameScope.FILE_SYSTEM ) | |||
| { | |||
| String absPath = m_parser.resolvePath( m_absPath, name ); | |||
| return new DefaultFileName( m_parser, m_rootPrefix, absPath ); | |||
| } | |||
| else | |||
| { | |||
| throw new IllegalArgumentException(); | |||
| } | |||
| final String absPath = m_parser.resolvePath( m_absPath, name, scope ); | |||
| return new DefaultFileName( m_parser, m_rootPrefix, absPath ); | |||
| } | |||
| /** | |||
| @@ -90,7 +97,7 @@ public class DefaultFileName implements FileName | |||
| */ | |||
| public FileName getParent() | |||
| { | |||
| String parentPath = m_parser.getParentPath( m_absPath ); | |||
| final String parentPath = m_parser.getParentPath( m_absPath ); | |||
| if( parentPath == null ) | |||
| { | |||
| return null; | |||
| @@ -104,7 +111,7 @@ public class DefaultFileName implements FileName | |||
| * file system that the file belongs to. If a relative name is supplied, | |||
| * then it is resolved relative to this file name. | |||
| */ | |||
| public FileName resolveName( String path ) throws FileSystemException | |||
| public FileName resolveName( final String path ) throws FileSystemException | |||
| { | |||
| return resolveName( path, NameScope.FILE_SYSTEM ); | |||
| } | |||
| @@ -37,3 +37,4 @@ missing-hostname.error=Hostname missing from URI "{0}". | |||
| missing-port.error=Port number is missing from URI "{0}". | |||
| missing-hostname-path-sep.error=Expecting / to follow the hostname in URI "{0}". | |||
| invalid-childname.error=Invalid file base-name "{0}". | |||
| invalid-descendent-name.error=Invalid descendent file name "{0}". | |||
| @@ -10,6 +10,7 @@ package org.apache.aut.vfs.provider; | |||
| import java.util.HashSet; | |||
| import java.util.Iterator; | |||
| import org.apache.aut.vfs.FileSystemException; | |||
| import org.apache.aut.vfs.NameScope; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| @@ -24,14 +25,14 @@ public class UriParser | |||
| ResourceManager.getPackageResources( UriParser.class ); | |||
| /** The normalised separator to use. */ | |||
| private char m_separatorChar; | |||
| private String m_separator; | |||
| private final char m_separatorChar; | |||
| private final String m_separator; | |||
| /** | |||
| * The set of valid separators. These are all converted to the normalised one. | |||
| * Does <i>not</i> contain the normalised separator | |||
| */ | |||
| private char[] m_separators; | |||
| private final char[] m_separators; | |||
| /** | |||
| * Creates a parser, using '/' and '\' as the path separators. | |||
| @@ -49,12 +50,12 @@ public class UriParser | |||
| * Additional legal separator characters. Any occurrences of | |||
| * these in paths are replaced with the separator char. | |||
| */ | |||
| protected UriParser( char[] separators ) | |||
| protected UriParser( final char[] separators ) | |||
| { | |||
| m_separatorChar = '/'; | |||
| // Remove the separator char from the separators array | |||
| HashSet set = new HashSet(); | |||
| final HashSet set = new HashSet(); | |||
| set.add( new Character( '\\' ) ); | |||
| if( separators != null ) | |||
| { | |||
| @@ -69,10 +70,10 @@ public class UriParser | |||
| } | |||
| } | |||
| m_separators = new char[ set.size() ]; | |||
| Iterator iter = set.iterator(); | |||
| final Iterator iter = set.iterator(); | |||
| for( int i = 0; i < m_separators.length; i++ ) | |||
| { | |||
| Character ch = (Character)iter.next(); | |||
| final Character ch = (Character)iter.next(); | |||
| m_separators[ i ] = ch.charValue(); | |||
| } | |||
| @@ -86,9 +87,9 @@ public class UriParser | |||
| * | |||
| * <p>Sub-classes should override this method. | |||
| */ | |||
| public ParsedUri parseUri( String uriStr ) throws FileSystemException | |||
| public ParsedUri parseUri( final String uriStr ) throws FileSystemException | |||
| { | |||
| ParsedUri retval = new ParsedUri(); | |||
| final ParsedUri retval = new ParsedUri(); | |||
| parseGenericUri( uriStr, retval ); | |||
| return retval; | |||
| } | |||
| @@ -109,9 +110,11 @@ public class UriParser | |||
| * @param uri | |||
| * Used to return the parsed components of the URI. | |||
| */ | |||
| protected void parseGenericUri( String uriStr, ParsedUri uri ) throws FileSystemException | |||
| protected void parseGenericUri( final String uriStr, | |||
| final ParsedUri uri ) | |||
| throws FileSystemException | |||
| { | |||
| StringBuffer name = new StringBuffer(); | |||
| final StringBuffer name = new StringBuffer(); | |||
| // Extract the scheme and authority parts | |||
| extractToPath( uriStr, name, uri ); | |||
| @@ -121,7 +124,7 @@ public class UriParser | |||
| uri.setPath( name.toString() ); | |||
| // Build the root uri | |||
| StringBuffer rootUri = new StringBuffer(); | |||
| final StringBuffer rootUri = new StringBuffer(); | |||
| rootUri.append( uri.getScheme() ); | |||
| rootUri.append( "://" ); | |||
| rootUri.append( uri.getHostName() ); | |||
| @@ -141,11 +144,13 @@ public class UriParser | |||
| * @parsedUri | |||
| * Used to return the extracted components. | |||
| */ | |||
| protected void extractToPath( String uri, StringBuffer name, ParsedUri parsedUri ) | |||
| protected void extractToPath( final String uri, | |||
| final StringBuffer name, | |||
| final ParsedUri parsedUri ) | |||
| throws FileSystemException | |||
| { | |||
| // Extract the scheme | |||
| String scheme = extractScheme( uri, name ); | |||
| final String scheme = extractScheme( uri, name ); | |||
| parsedUri.setScheme( scheme ); | |||
| // Expecting "//" | |||
| @@ -157,11 +162,11 @@ public class UriParser | |||
| name.delete( 0, 2 ); | |||
| // Extract userinfo | |||
| String userInfo = extractUserInfo( name ); | |||
| final String userInfo = extractUserInfo( name ); | |||
| parsedUri.setUserInfo( userInfo ); | |||
| // Extract hostname | |||
| String hostName = extractHostName( name ); | |||
| final String hostName = extractHostName( name ); | |||
| if( hostName == null ) | |||
| { | |||
| final String message = REZ.getString( "missing-hostname.error", uri ); | |||
| @@ -170,7 +175,7 @@ public class UriParser | |||
| parsedUri.setHostName( hostName ); | |||
| // Extract port | |||
| String port = extractPort( name ); | |||
| final String port = extractPort( name ); | |||
| if( port != null && port.length() == 0 ) | |||
| { | |||
| final String message = REZ.getString( "missing-port.error", uri ); | |||
| @@ -190,12 +195,12 @@ public class UriParser | |||
| * Extracts the user info from a URI. The <scheme>:// part has been removed | |||
| * already. | |||
| */ | |||
| protected String extractUserInfo( StringBuffer name ) | |||
| protected String extractUserInfo( final StringBuffer name ) | |||
| { | |||
| int maxlen = name.length(); | |||
| final int maxlen = name.length(); | |||
| for( int pos = 0; pos < maxlen; pos++ ) | |||
| { | |||
| char ch = name.charAt( pos ); | |||
| final char ch = name.charAt( pos ); | |||
| if( ch == '@' ) | |||
| { | |||
| // Found the end of the user info | |||
| @@ -218,13 +223,13 @@ public class UriParser | |||
| * Extracts the hostname from a URI. The <scheme>://<userinfo>@ part has | |||
| * been removed. | |||
| */ | |||
| protected String extractHostName( StringBuffer name ) | |||
| protected String extractHostName( final StringBuffer name ) | |||
| { | |||
| int maxlen = name.length(); | |||
| final int maxlen = name.length(); | |||
| int pos = 0; | |||
| for( ; pos < maxlen; pos++ ) | |||
| { | |||
| char ch = name.charAt( pos ); | |||
| final char ch = name.charAt( pos ); | |||
| if( ch == '/' || ch == ';' || ch == '?' || ch == ':' | |||
| || ch == '@' || ch == '&' || ch == '=' || ch == '+' | |||
| || ch == '$' || ch == ',' ) | |||
| @@ -237,7 +242,7 @@ public class UriParser | |||
| return null; | |||
| } | |||
| String hostname = name.substring( 0, pos ); | |||
| final String hostname = name.substring( 0, pos ); | |||
| name.delete( 0, pos ); | |||
| return hostname; | |||
| } | |||
| @@ -246,23 +251,25 @@ public class UriParser | |||
| * Extracts the port from a URI. The <scheme>://<userinfo>@<hostname> | |||
| * part has been removed. | |||
| */ | |||
| protected String extractPort( StringBuffer name ) | |||
| protected String extractPort( final StringBuffer name ) | |||
| { | |||
| if( name.length() < 1 || name.charAt( 0 ) != ':' ) | |||
| { | |||
| return null; | |||
| } | |||
| int maxlen = name.length(); | |||
| final int maxlen = name.length(); | |||
| int pos = 1; | |||
| for( ; pos < maxlen; pos++ ) | |||
| { | |||
| char ch = name.charAt( pos ); | |||
| final char ch = name.charAt( pos ); | |||
| if( ch < '0' || ch > '9' ) | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| String port = name.substring( 1, pos ); | |||
| final String port = name.substring( 1, pos ); | |||
| name.delete( 0, pos ); | |||
| return port; | |||
| } | |||
| @@ -270,9 +277,9 @@ public class UriParser | |||
| /** | |||
| * Extracts the first element of a path. | |||
| */ | |||
| protected String extractFirstElement( StringBuffer name ) | |||
| protected String extractFirstElement( final StringBuffer name ) | |||
| { | |||
| int len = name.length(); | |||
| final int len = name.length(); | |||
| if( len < 1 ) | |||
| { | |||
| return null; | |||
| @@ -287,14 +294,14 @@ public class UriParser | |||
| if( name.charAt( pos ) == m_separatorChar ) | |||
| { | |||
| // Found a separator | |||
| String elem = name.substring( startPos, pos ); | |||
| final String elem = name.substring( startPos, pos ); | |||
| name.delete( startPos, pos + 1 ); | |||
| return elem; | |||
| } | |||
| } | |||
| // No separator | |||
| String elem = name.substring( startPos ); | |||
| final String elem = name.substring( startPos ); | |||
| name.setLength( 0 ); | |||
| return elem; | |||
| } | |||
| @@ -308,10 +315,11 @@ public class UriParser | |||
| * @param path | |||
| * A <i>normalised</i> path. | |||
| */ | |||
| public String getUri( String rootUri, String path ) | |||
| public String getUri( final String rootUri, | |||
| final String path ) | |||
| { | |||
| StringBuffer uri = new StringBuffer( rootUri ); | |||
| int len = uri.length(); | |||
| final StringBuffer uri = new StringBuffer( rootUri ); | |||
| final int len = uri.length(); | |||
| if( uri.charAt( len - 1 ) == m_separatorChar ) | |||
| { | |||
| uri.delete( len - 1, len ); | |||
| @@ -330,9 +338,9 @@ public class UriParser | |||
| * @param path | |||
| * A <i>normalised</i> path. | |||
| */ | |||
| public String getBaseName( String path ) | |||
| public String getBaseName( final String path ) | |||
| { | |||
| int idx = path.lastIndexOf( m_separatorChar ); | |||
| final int idx = path.lastIndexOf( m_separatorChar ); | |||
| if( idx == -1 ) | |||
| { | |||
| return path; | |||
| @@ -353,9 +361,11 @@ public class UriParser | |||
| * does need to be a path (i.e. not an absolute URI). | |||
| * | |||
| */ | |||
| public String resolvePath( String basePath, String path ) throws FileSystemException | |||
| public String resolvePath( final String basePath, | |||
| final String path ) | |||
| throws FileSystemException | |||
| { | |||
| StringBuffer buffer = new StringBuffer( path ); | |||
| final StringBuffer buffer = new StringBuffer( path ); | |||
| // Adjust separators | |||
| fixSeparators( buffer ); | |||
| @@ -374,47 +384,52 @@ public class UriParser | |||
| } | |||
| /** | |||
| * Returns a child path. | |||
| * Resolved a name, relative to a base file. | |||
| * | |||
| * @param parent | |||
| * @param baseFile | |||
| * A <i>normalised</i> path. | |||
| * | |||
| * @param name | |||
| * The child name. Must be a valid element name (i.e. no separators, etc). | |||
| * @param path | |||
| * The path to resolve. | |||
| * | |||
| * @param scope | |||
| * The scope to resolve and validate the name in. | |||
| */ | |||
| public String getChildPath( String parent, String name ) throws FileSystemException | |||
| public String resolvePath( final String baseFile, | |||
| final String path, | |||
| final NameScope scope ) | |||
| throws FileSystemException | |||
| { | |||
| // Validate the child name | |||
| if( name.length() == 0 | |||
| || name.equals( "." ) | |||
| || name.equals( ".." ) ) | |||
| { | |||
| final String message = REZ.getString( "invalid-childname.error", name ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| // Check for separators | |||
| if( name.indexOf( m_separatorChar ) != -1 ) | |||
| { | |||
| final String message = REZ.getString( "invalid-childname.error", name ); | |||
| throw new FileSystemException( message ); | |||
| final String resolvedPath = resolvePath( baseFile, path ); | |||
| if( scope == NameScope.CHILD ) | |||
| { | |||
| final int baseLen = baseFile.length(); | |||
| if( ! resolvedPath.startsWith( baseFile ) | |||
| || resolvedPath.length() == baseLen | |||
| || resolvedPath.charAt( baseLen ) != m_separatorChar | |||
| || resolvedPath.indexOf( m_separatorChar, baseLen + 1 ) != -1 ) | |||
| { | |||
| final String message = REZ.getString( "invalid-childname.error", path ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| } | |||
| for( int i = 0; i < m_separators.length; i++ ) | |||
| else if( scope == NameScope.DESCENDENT ) | |||
| { | |||
| char separator = m_separators[ i ]; | |||
| if( name.indexOf( separator ) != -1 ) | |||
| final int baseLen = baseFile.length(); | |||
| if( ! resolvedPath.startsWith( baseFile ) | |||
| || resolvedPath.length() == baseLen | |||
| || resolvedPath.charAt( baseLen ) != m_separatorChar ) | |||
| { | |||
| final String message = REZ.getString( "invalid-childname.error", name ); | |||
| final String message = REZ.getString( "invalid-descendent-name.error", path ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| } | |||
| if( parent.endsWith( m_separator ) ) | |||
| else if( scope != NameScope.FILE_SYSTEM ) | |||
| { | |||
| // Either root, or the parent name already ends with the separator | |||
| return parent + name; | |||
| throw new IllegalArgumentException(); | |||
| } | |||
| return parent + m_separatorChar + name; | |||
| return resolvedPath; | |||
| } | |||
| /** | |||
| @@ -423,9 +438,9 @@ public class UriParser | |||
| * @param path | |||
| * A <i>normalised</i> path. | |||
| */ | |||
| public String getParentPath( String path ) | |||
| public String getParentPath( final String path ) | |||
| { | |||
| int idx = path.lastIndexOf( m_separatorChar ); | |||
| final int idx = path.lastIndexOf( m_separatorChar ); | |||
| if( idx == -1 || idx == path.length() - 1 ) | |||
| { | |||
| // No parent | |||
| @@ -448,7 +463,7 @@ public class UriParser | |||
| * <li>Removes trailing separator. | |||
| * </ul> | |||
| */ | |||
| public void normalisePath( StringBuffer path ) throws FileSystemException | |||
| public void normalisePath( final StringBuffer path ) throws FileSystemException | |||
| { | |||
| if( path.length() == 0 ) | |||
| { | |||
| @@ -480,7 +495,7 @@ public class UriParser | |||
| { | |||
| } | |||
| int elemLen = endElem - startElem; | |||
| final int elemLen = endElem - startElem; | |||
| if( elemLen == 0 ) | |||
| { | |||
| // An empty element - axe it | |||
| @@ -503,11 +518,8 @@ public class UriParser | |||
| if( startElem > startFirstElem ) | |||
| { | |||
| int pos = startElem - 2; | |||
| char ch = path.charAt( pos ); | |||
| while( ch != m_separatorChar ) | |||
| for( ; pos >= 0 && path.charAt( pos ) != m_separatorChar; pos -- ) | |||
| { | |||
| pos--; | |||
| ch = path.charAt( pos ); | |||
| } | |||
| startElem = pos + 1; | |||
| } | |||
| @@ -521,7 +533,7 @@ public class UriParser | |||
| } | |||
| // Remove trailing separator | |||
| if( path.charAt( maxlen - 1 ) == m_separatorChar && maxlen > 1 ) | |||
| if( maxlen > 0 && path.charAt( maxlen - 1 ) == m_separatorChar && maxlen > 1 ) | |||
| { | |||
| path.delete( maxlen - 1, maxlen ); | |||
| } | |||
| @@ -530,7 +542,7 @@ public class UriParser | |||
| /** | |||
| * Adjusts the separators in a name. | |||
| */ | |||
| protected boolean fixSeparators( StringBuffer name ) | |||
| protected boolean fixSeparators( final StringBuffer name ) | |||
| { | |||
| if( m_separators.length == 0 ) | |||
| { | |||
| @@ -539,10 +551,10 @@ public class UriParser | |||
| } | |||
| boolean changed = false; | |||
| int maxlen = name.length(); | |||
| final int maxlen = name.length(); | |||
| for( int i = 0; i < maxlen; i++ ) | |||
| { | |||
| char ch = name.charAt( i ); | |||
| final char ch = name.charAt( i ); | |||
| for( int j = 0; j < m_separators.length; j++ ) | |||
| { | |||
| char separator = m_separators[ j ]; | |||
| @@ -566,7 +578,7 @@ public class UriParser | |||
| * @return | |||
| * The scheme name. Returns null if there is no scheme. | |||
| */ | |||
| public static String extractScheme( String uri ) | |||
| public static String extractScheme( final String uri ) | |||
| { | |||
| return extractScheme( uri, null ); | |||
| } | |||
| @@ -583,7 +595,7 @@ public class UriParser | |||
| * @return | |||
| * The scheme name. Returns null if there is no scheme. | |||
| */ | |||
| protected static String extractScheme( String uri, StringBuffer buffer ) | |||
| protected static String extractScheme( final String uri, final StringBuffer buffer ) | |||
| { | |||
| if( buffer != null ) | |||
| { | |||
| @@ -591,15 +603,15 @@ public class UriParser | |||
| buffer.append( uri ); | |||
| } | |||
| int maxPos = uri.length(); | |||
| final int maxPos = uri.length(); | |||
| for( int pos = 0; pos < maxPos; pos++ ) | |||
| { | |||
| char ch = uri.charAt( pos ); | |||
| final char ch = uri.charAt( pos ); | |||
| if( ch == ':' ) | |||
| { | |||
| // Found the end of the scheme | |||
| String scheme = uri.substring( 0, pos ); | |||
| final String scheme = uri.substring( 0, pos ); | |||
| if( buffer != null ) | |||
| { | |||
| buffer.delete( 0, pos + 1 ); | |||
| @@ -0,0 +1,44 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.aut.vfs.provider.local; | |||
| import org.apache.aut.vfs.FileSystemException; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| /** | |||
| * A general-purpose file name parser. | |||
| * | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| class GenericFileNameParser | |||
| extends LocalFileNameParser | |||
| { | |||
| private final static Resources REZ | |||
| = ResourceManager.getPackageResources( GenericFileNameParser.class ); | |||
| /** | |||
| * Pops the root prefix off a URI, which has had the scheme removed. | |||
| */ | |||
| protected String extractRootPrefix( final String uri, | |||
| final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| // TODO - this class isn't generic at all. Need to fix this | |||
| // Looking for <sep> | |||
| if( name.length() == 0 || name.charAt( 0 ) != '/' ) | |||
| { | |||
| final String message = REZ.getString( "not-absolute-file-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| return "/"; | |||
| } | |||
| } | |||
| @@ -23,7 +23,8 @@ import org.apache.avalon.excalibur.i18n.Resources; | |||
| /** | |||
| * A file object implementation which uses direct file access. | |||
| * | |||
| * @author Adam Murdoch | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| final class LocalFile | |||
| extends AbstractFileObject | |||
| @@ -33,7 +34,7 @@ final class LocalFile | |||
| ResourceManager.getPackageResources( LocalFile.class ); | |||
| private File m_file; | |||
| private String m_fileName; | |||
| private final String m_fileName; | |||
| /** | |||
| * Creates a non-root file. | |||
| @@ -11,26 +11,19 @@ import java.io.File; | |||
| import org.apache.aut.vfs.FileSystemException; | |||
| import org.apache.aut.vfs.provider.ParsedUri; | |||
| import org.apache.aut.vfs.provider.UriParser; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| /** | |||
| * A name parser. | |||
| * | |||
| * @author Adam Murdoch | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| class LocalFileNameParser | |||
| abstract class LocalFileNameParser | |||
| extends UriParser | |||
| { | |||
| private final static Resources REZ = | |||
| ResourceManager.getPackageResources( LocalFileNameParser.class ); | |||
| private boolean m_windowsNames; | |||
| public LocalFileNameParser() | |||
| { | |||
| super( new char[]{File.separatorChar, '/', '\\'} ); | |||
| m_windowsNames = ( System.getProperty( "os.name" ).toLowerCase().indexOf( "windows" ) != -1 ); | |||
| } | |||
| /** | |||
| @@ -91,141 +84,8 @@ class LocalFileNameParser | |||
| /** | |||
| * Pops the root prefix off a URI, which has had the scheme removed. | |||
| */ | |||
| private String extractRootPrefix( final String uri, | |||
| final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| // TODO - split this into sub-classes | |||
| if( m_windowsNames ) | |||
| { | |||
| return extractWindowsRootPrefix( uri, name ); | |||
| } | |||
| else | |||
| { | |||
| // Looking for <sep> | |||
| if( name.length() == 0 || name.charAt( 0 ) != '/' ) | |||
| { | |||
| final String message = REZ.getString( "not-absolute-file-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| // TODO - this isn't always true | |||
| return "/"; | |||
| } | |||
| } | |||
| /** | |||
| * Extracts a Windows root prefix from a name. | |||
| */ | |||
| private String extractWindowsRootPrefix( final String uri, | |||
| final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| // Looking for: | |||
| // ('/'){0, 3} <letter> ':' '/' | |||
| // ['/'] '//' <name> '/' <name> ( '/' | <end> ) | |||
| protected abstract String extractRootPrefix( final String uri, | |||
| final StringBuffer name ) | |||
| throws FileSystemException; | |||
| // Skip over first 3 leading '/' chars | |||
| int startPos = 0; | |||
| int maxlen = Math.min( 3, name.length() ); | |||
| for( ; startPos < maxlen && name.charAt( startPos ) == '/'; startPos++ ) | |||
| { | |||
| } | |||
| if( startPos == maxlen ) | |||
| { | |||
| // Too many '/' | |||
| final String message = REZ.getString( "not-absolute-file-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| name.delete( 0, startPos ); | |||
| // Look for drive name | |||
| String driveName = extractDrivePrefix( name ); | |||
| if( driveName != null ) | |||
| { | |||
| return driveName; | |||
| } | |||
| // Look for UNC name | |||
| if( startPos < 2 ) | |||
| { | |||
| final String message = REZ.getString( "not-absolute-file-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| return "//" + extractUNCPrefix( uri, name ); | |||
| } | |||
| /** | |||
| * Extracts a drive prefix from a path. Leading '/' chars have been removed. | |||
| */ | |||
| private String extractDrivePrefix( final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| // Looking for <letter> ':' '/' | |||
| if( name.length() < 3 ) | |||
| { | |||
| // Too short | |||
| return null; | |||
| } | |||
| char ch = name.charAt( 0 ); | |||
| if( ch == '/' || ch == ':' ) | |||
| { | |||
| // Missing drive letter | |||
| return null; | |||
| } | |||
| if( name.charAt( 1 ) != ':' ) | |||
| { | |||
| // Missing ':' | |||
| return null; | |||
| } | |||
| if( name.charAt( 2 ) != '/' ) | |||
| { | |||
| // Missing separator | |||
| return null; | |||
| } | |||
| String prefix = name.substring( 0, 2 ); | |||
| name.delete( 0, 2 ); | |||
| return prefix; | |||
| } | |||
| /** | |||
| * Extracts a UNC name from a path. Leading '/' chars have been removed. | |||
| */ | |||
| private String extractUNCPrefix( final String uri, | |||
| final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| // Looking for <name> '/' <name> ( '/' | <end> ) | |||
| // Look for first separator | |||
| int maxpos = name.length(); | |||
| int pos = 0; | |||
| for( ; pos < maxpos && name.charAt( pos ) != '/'; pos++ ) | |||
| { | |||
| } | |||
| pos++; | |||
| if( pos >= maxpos ) | |||
| { | |||
| final String message = REZ.getString( "missing-share-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| // Now have <name> '/' | |||
| int startShareName = pos; | |||
| for( ; pos < maxpos && name.charAt( pos ) != '/'; pos++ ) | |||
| { | |||
| } | |||
| if( pos == startShareName ) | |||
| { | |||
| final String message = REZ.getString( "missing-share-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| // Now have <name> '/' <name> ( '/' | <end> ) | |||
| String prefix = name.substring( 0, pos ); | |||
| name.delete( 0, pos ); | |||
| return prefix; | |||
| } | |||
| } | |||
| @@ -17,7 +17,8 @@ import org.apache.aut.vfs.provider.FileSystem; | |||
| /** | |||
| * A local file system. | |||
| * | |||
| * @author Adam Murdoch | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| class LocalFileSystem extends AbstractFileSystem implements FileSystem | |||
| { | |||
| @@ -8,6 +8,7 @@ | |||
| package org.apache.aut.vfs.provider.local; | |||
| import java.io.File; | |||
| import org.apache.aut.nativelib.Os; | |||
| import org.apache.aut.vfs.FileObject; | |||
| import org.apache.aut.vfs.FileSystemException; | |||
| import org.apache.aut.vfs.provider.AbstractFileSystemProvider; | |||
| @@ -19,12 +20,25 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||
| /** | |||
| * A file system provider, which uses direct file access. | |||
| * | |||
| * @author Adam Murdoch | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class LocalFileSystemProvider extends AbstractFileSystemProvider | |||
| implements FileSystemProvider | |||
| { | |||
| private final LocalFileNameParser m_parser = new LocalFileNameParser(); | |||
| private final LocalFileNameParser m_parser; | |||
| public LocalFileSystemProvider() | |||
| { | |||
| if( Os.isFamily( Os.OS_FAMILY_WINDOWS ) ) | |||
| { | |||
| m_parser = new WindowsFileNameParser(); | |||
| } | |||
| else | |||
| { | |||
| m_parser = new GenericFileNameParser(); | |||
| } | |||
| } | |||
| /** | |||
| * Determines if a name is an absolute file name. | |||
| @@ -12,9 +12,10 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||
| /** | |||
| * A parsed file URI. | |||
| * | |||
| * @author Adam Murdoch | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class ParsedFileUri extends ParsedUri | |||
| class ParsedFileUri extends ParsedUri | |||
| { | |||
| private String m_rootFile; | |||
| @@ -23,7 +24,7 @@ public class ParsedFileUri extends ParsedUri | |||
| return m_rootFile; | |||
| } | |||
| public void setRootFile( String rootPrefix ) | |||
| public void setRootFile( final String rootPrefix ) | |||
| { | |||
| m_rootFile = rootPrefix; | |||
| } | |||
| @@ -0,0 +1,150 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.aut.vfs.provider.local; | |||
| import org.apache.aut.vfs.FileSystemException; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| /** | |||
| * A parser for Windows file names. | |||
| * | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| class WindowsFileNameParser | |||
| extends LocalFileNameParser | |||
| { | |||
| private final static Resources REZ | |||
| = ResourceManager.getPackageResources( WindowsFileNameParser.class ); | |||
| /** | |||
| * Pops the root prefix off a URI, which has had the scheme removed. | |||
| */ | |||
| protected String extractRootPrefix( final String uri, | |||
| final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| return extractWindowsRootPrefix( uri, name ); | |||
| } | |||
| /** | |||
| * Extracts a Windows root prefix from a name. | |||
| */ | |||
| private String extractWindowsRootPrefix( final String uri, | |||
| final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| // Looking for: | |||
| // ('/'){0, 3} <letter> ':' '/' | |||
| // ['/'] '//' <name> '/' <name> ( '/' | <end> ) | |||
| // Skip over first 3 leading '/' chars | |||
| int startPos = 0; | |||
| int maxlen = Math.min( 3, name.length() ); | |||
| for( ; startPos < maxlen && name.charAt( startPos ) == '/'; startPos++ ) | |||
| { | |||
| } | |||
| if( startPos == maxlen ) | |||
| { | |||
| // Too many '/' | |||
| final String message = REZ.getString( "not-absolute-file-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| name.delete( 0, startPos ); | |||
| // Look for drive name | |||
| String driveName = extractDrivePrefix( name ); | |||
| if( driveName != null ) | |||
| { | |||
| return driveName; | |||
| } | |||
| // Look for UNC name | |||
| if( startPos < 2 ) | |||
| { | |||
| final String message = REZ.getString( "not-absolute-file-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| return "//" + extractUNCPrefix( uri, name ); | |||
| } | |||
| /** | |||
| * Extracts a drive prefix from a path. Leading '/' chars have been removed. | |||
| */ | |||
| private String extractDrivePrefix( final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| // Looking for <letter> ':' '/' | |||
| if( name.length() < 3 ) | |||
| { | |||
| // Too short | |||
| return null; | |||
| } | |||
| char ch = name.charAt( 0 ); | |||
| if( ch == '/' || ch == ':' ) | |||
| { | |||
| // Missing drive letter | |||
| return null; | |||
| } | |||
| if( name.charAt( 1 ) != ':' ) | |||
| { | |||
| // Missing ':' | |||
| return null; | |||
| } | |||
| if( name.charAt( 2 ) != '/' ) | |||
| { | |||
| // Missing separator | |||
| return null; | |||
| } | |||
| String prefix = name.substring( 0, 2 ); | |||
| name.delete( 0, 2 ); | |||
| return prefix; | |||
| } | |||
| /** | |||
| * Extracts a UNC name from a path. Leading '/' chars have been removed. | |||
| */ | |||
| private String extractUNCPrefix( final String uri, | |||
| final StringBuffer name ) | |||
| throws FileSystemException | |||
| { | |||
| // Looking for <name> '/' <name> ( '/' | <end> ) | |||
| // Look for first separator | |||
| int maxpos = name.length(); | |||
| int pos = 0; | |||
| for( ; pos < maxpos && name.charAt( pos ) != '/'; pos++ ) | |||
| { | |||
| } | |||
| pos++; | |||
| if( pos >= maxpos ) | |||
| { | |||
| final String message = REZ.getString( "missing-share-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| // Now have <name> '/' | |||
| int startShareName = pos; | |||
| for( ; pos < maxpos && name.charAt( pos ) != '/'; pos++ ) | |||
| { | |||
| } | |||
| if( pos == startShareName ) | |||
| { | |||
| final String message = REZ.getString( "missing-share-name.error", uri ); | |||
| throw new FileSystemException( message ); | |||
| } | |||
| // Now have <name> '/' <name> ( '/' | <end> ) | |||
| String prefix = name.substring( 0, pos ); | |||
| name.delete( 0, pos ); | |||
| return prefix; | |||
| } | |||
| } | |||
| @@ -15,6 +15,9 @@ import java.util.HashMap; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import org.apache.aut.vfs.impl.DefaultFileSystemManager; | |||
| import org.apache.aut.vfs.provider.AbstractFileObject; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| /** | |||
| @@ -29,6 +32,9 @@ import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| public abstract class AbstractFileSystemTest | |||
| extends AbstractMyrmidonTest | |||
| { | |||
| private final static Resources REZ | |||
| = ResourceManager.getPackageResources( AbstractFileObject.class ); | |||
| protected FileObject m_baseFolder; | |||
| protected DefaultFileSystemManager m_manager; | |||
| @@ -46,12 +52,12 @@ public abstract class AbstractFileSystemTest | |||
| private FileInfo buildExpectedStructure() | |||
| { | |||
| // Build the expected structure | |||
| FileInfo base = new FileInfo( "test", FileType.FOLDER ); | |||
| final FileInfo base = new FileInfo( "test", FileType.FOLDER ); | |||
| base.addChild( new FileInfo( "file1.txt", FileType.FILE ) ); | |||
| base.addChild( new FileInfo( "empty.txt", FileType.FILE ) ); | |||
| base.addChild( new FileInfo( "emptydir", FileType.FOLDER ) ); | |||
| FileInfo dir = new FileInfo( "dir1", FileType.FOLDER ); | |||
| final FileInfo dir = new FileInfo( "dir1", FileType.FOLDER ); | |||
| base.addChild( dir ); | |||
| dir.addChild( new FileInfo( "file1.txt", FileType.FILE ) ); | |||
| dir.addChild( new FileInfo( "file2.txt", FileType.FILE ) ); | |||
| @@ -76,7 +82,7 @@ public abstract class AbstractFileSystemTest | |||
| m_baseFolder = m_manager.resolveFile( getBaseFolderURI() ); | |||
| // Build the expected content of "file1.txt" | |||
| String eol = System.getProperty( "line.separator" ); | |||
| final String eol = System.getProperty( "line.separator" ); | |||
| m_charContent = "This is a test file." + eol + "With 2 lines in it." + eol; | |||
| } | |||
| @@ -86,8 +92,8 @@ public abstract class AbstractFileSystemTest | |||
| public void testAbsoluteURI() throws Exception | |||
| { | |||
| // Try fetching base folder again by its URI | |||
| String uri = m_baseFolder.getName().getURI(); | |||
| FileObject file = m_manager.resolveFile( uri ); | |||
| final String uri = m_baseFolder.getName().getURI(); | |||
| final FileObject file = m_manager.resolveFile( uri ); | |||
| assertSame( "file object", m_baseFolder, file ); | |||
| } | |||
| @@ -123,7 +129,7 @@ public abstract class AbstractFileSystemTest | |||
| public void testRootFileName() throws Exception | |||
| { | |||
| // Locate the root file | |||
| FileName rootName = m_baseFolder.getRoot().getName(); | |||
| final FileName rootName = m_baseFolder.getRoot().getName(); | |||
| // Test that the root path is "/" | |||
| assertEquals( "root path", "/", rootName.getPath() ); | |||
| @@ -140,9 +146,9 @@ public abstract class AbstractFileSystemTest | |||
| */ | |||
| public void testChildName() throws Exception | |||
| { | |||
| FileName baseName = m_baseFolder.getName(); | |||
| String basePath = baseName.getPath(); | |||
| FileName name = baseName.resolveName( "some-child", NameScope.CHILD ); | |||
| final FileName baseName = m_baseFolder.getName(); | |||
| final String basePath = baseName.getPath(); | |||
| final FileName name = baseName.resolveName( "some-child", NameScope.CHILD ); | |||
| // Test path is absolute | |||
| assertTrue( "is absolute", basePath.startsWith( "/" ) ); | |||
| @@ -157,76 +163,95 @@ public abstract class AbstractFileSystemTest | |||
| assertEquals( "parent absolute path", basePath, name.getParent().getPath() ); | |||
| // Try using a compound name to find a child | |||
| try | |||
| { | |||
| name.resolveName( "a/b", NameScope.CHILD ); | |||
| assertTrue( false ); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| } | |||
| assertBadName( name, "a/b", NameScope.CHILD ); | |||
| // Try using a empty name to find a child | |||
| try | |||
| { | |||
| name.resolveName( "", NameScope.CHILD ); | |||
| assertTrue( false ); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| } | |||
| // Try using '.' to find a child | |||
| try | |||
| { | |||
| name.resolveName( ".", NameScope.CHILD ); | |||
| assertTrue( false ); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| } | |||
| // Check other invalid names | |||
| checkDescendentNames( name, NameScope.CHILD ); | |||
| } | |||
| // Try using '..' to find a child | |||
| try | |||
| { | |||
| name.resolveName( "..", NameScope.CHILD ); | |||
| assertTrue( false ); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| } | |||
| /** | |||
| * Name resolution tests that are common for CHILD or DESCENDENT scope. | |||
| */ | |||
| private void checkDescendentNames( final FileName name, | |||
| final NameScope scope ) | |||
| throws Exception | |||
| { | |||
| // Make some assumptions about the name explicit | |||
| assertTrue( !name.getPath().equals( "/" ) ); | |||
| assertTrue( !name.getPath().endsWith( "/a" ) ); | |||
| assertTrue( !name.getPath().endsWith( "/a/b" ) ); | |||
| // Test names with the same prefix | |||
| String path = name.getPath() + "/a"; | |||
| assertSameName( path, name, path, scope ); | |||
| assertSameName( path, name, "../" + name.getBaseName() + "/a", scope ); | |||
| // Test an empty name | |||
| assertBadName( name, "", scope ); | |||
| // Test . name | |||
| assertBadName( name, ".", scope ); | |||
| assertBadName( name, "./", scope ); | |||
| // Test ancestor names | |||
| assertBadName( name, "..", scope ); | |||
| assertBadName( name, "../a", scope ); | |||
| assertBadName( name, "../" + name.getBaseName() + "a", scope ); | |||
| assertBadName( name, "a/..", scope ); | |||
| // Test absolute names | |||
| assertBadName( name, "/", scope ); | |||
| assertBadName( name, "/a", scope ); | |||
| assertBadName( name, "/a/b", scope ); | |||
| assertBadName( name, name.getPath(), scope ); | |||
| assertBadName( name, name.getPath() + "a", scope ); | |||
| } | |||
| /** | |||
| * Checks that a relative name resolves to the expected absolute path. | |||
| * Tests both forward and back slashes. | |||
| */ | |||
| private void assertSameName( String expectedPath, | |||
| FileName baseName, | |||
| String relName ) throws Exception | |||
| private void assertSameName( final String expectedPath, | |||
| final FileName baseName, | |||
| final String relName, | |||
| final NameScope scope ) | |||
| throws Exception | |||
| { | |||
| FileName name = baseName.resolveName( relName ); | |||
| // Try the supplied name | |||
| FileName name = baseName.resolveName( relName, scope ); | |||
| assertEquals( expectedPath, name.getPath() ); | |||
| // Replace the separators | |||
| relName.replace( '\\', '/' ); | |||
| name = baseName.resolveName( relName ); | |||
| name = baseName.resolveName( relName, scope ); | |||
| assertEquals( expectedPath, name.getPath() ); | |||
| // And again | |||
| relName.replace( '/', '\\' ); | |||
| name = baseName.resolveName( relName ); | |||
| name = baseName.resolveName( relName, scope ); | |||
| assertEquals( expectedPath, name.getPath() ); | |||
| } | |||
| /** | |||
| * Checks that a relative name resolves to the expected absolute path. | |||
| * Tests both forward and back slashes. | |||
| */ | |||
| private void assertSameName( String expectedPath, | |||
| FileName baseName, | |||
| String relName ) throws Exception | |||
| { | |||
| assertSameName( expectedPath, baseName, relName, NameScope.FILE_SYSTEM ); | |||
| } | |||
| /** | |||
| * Tests relative name resolution, relative to the base folder. | |||
| */ | |||
| public void testNameResolution() throws Exception | |||
| { | |||
| FileName baseName = m_baseFolder.getName(); | |||
| String parentPath = baseName.getParent().getPath(); | |||
| String path = baseName.getPath(); | |||
| String childPath = path + "/some-child"; | |||
| final FileName baseName = m_baseFolder.getName(); | |||
| final String parentPath = baseName.getParent().getPath(); | |||
| final String path = baseName.getPath(); | |||
| final String childPath = path + "/some-child"; | |||
| // Test empty relative path | |||
| assertSameName( path, baseName, "" ); | |||
| @@ -280,23 +305,78 @@ public abstract class AbstractFileSystemTest | |||
| } | |||
| /** | |||
| * Walks the folder structure, asserting it contains exactly the | |||
| * Tests descendent name resolution. | |||
| */ | |||
| public void testDescendentName() | |||
| throws Exception | |||
| { | |||
| final FileName baseName = m_baseFolder.getName(); | |||
| // Test direct child | |||
| String path = baseName.getPath() + "/some-child"; | |||
| assertSameName( path, baseName, "some-child", NameScope.DESCENDENT ); | |||
| // Test compound name | |||
| path = path + "/grand-child"; | |||
| assertSameName( path, baseName, "some-child/grand-child", NameScope.DESCENDENT ); | |||
| // Test relative names | |||
| assertSameName( path, baseName, "./some-child/grand-child", NameScope.DESCENDENT ); | |||
| assertSameName( path, baseName, "./nada/../some-child/grand-child", NameScope.DESCENDENT ); | |||
| assertSameName( path, baseName, "some-child/./grand-child", NameScope.DESCENDENT ); | |||
| // Test badly formed descendent names | |||
| checkDescendentNames( baseName, NameScope.DESCENDENT ); | |||
| } | |||
| /** | |||
| * Asserts that a particular relative name is invalid for a particular | |||
| * scope. | |||
| */ | |||
| private void assertBadName( final FileName name, | |||
| final String relName, | |||
| final NameScope scope ) | |||
| { | |||
| try | |||
| { | |||
| name.resolveName( relName, scope ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| // TODO - should check error message | |||
| } | |||
| } | |||
| /** | |||
| * Walks the base folder structure, asserting it contains exactly the | |||
| * expected files and folders. | |||
| */ | |||
| public void testStructure() throws Exception | |||
| { | |||
| final FileInfo baseInfo = buildExpectedStructure(); | |||
| assertSameStructure( m_baseFolder, baseInfo ); | |||
| } | |||
| /** | |||
| * Walks a folder structure, asserting it contains exactly the | |||
| * expected files and folders. | |||
| */ | |||
| protected void assertSameStructure( final FileObject folder, | |||
| final FileInfo expected ) | |||
| throws Exception | |||
| { | |||
| // Setup the structure | |||
| List queueExpected = new ArrayList(); | |||
| FileInfo baseInfo = buildExpectedStructure(); | |||
| queueExpected.add( baseInfo ); | |||
| final List queueExpected = new ArrayList(); | |||
| queueExpected.add( expected ); | |||
| List queueActual = new ArrayList(); | |||
| queueActual.add( m_baseFolder ); | |||
| final List queueActual = new ArrayList(); | |||
| queueActual.add( folder ); | |||
| while( queueActual.size() > 0 ) | |||
| { | |||
| FileObject file = (FileObject)queueActual.remove( 0 ); | |||
| FileInfo info = (FileInfo)queueExpected.remove( 0 ); | |||
| final FileObject file = (FileObject)queueActual.remove( 0 ); | |||
| final FileInfo info = (FileInfo)queueExpected.remove( 0 ); | |||
| // Check the type is correct | |||
| assertSame( file.getType(), info._type ); | |||
| @@ -307,7 +387,7 @@ public abstract class AbstractFileSystemTest | |||
| } | |||
| // Check children | |||
| FileObject[] children = file.getChildren(); | |||
| final FileObject[] children = file.getChildren(); | |||
| // Make sure all children were found | |||
| assertNotNull( children ); | |||
| @@ -316,8 +396,8 @@ public abstract class AbstractFileSystemTest | |||
| // Recursively check each child | |||
| for( int i = 0; i < children.length; i++ ) | |||
| { | |||
| FileObject child = children[ i ]; | |||
| FileInfo childInfo = (FileInfo)info._children.get( child.getName().getBaseName() ); | |||
| final FileObject child = children[ i ]; | |||
| final FileInfo childInfo = (FileInfo)info._children.get( child.getName().getBaseName() ); | |||
| // Make sure the child is expected | |||
| assertNotNull( childInfo ); | |||
| @@ -366,16 +446,16 @@ public abstract class AbstractFileSystemTest | |||
| // Test an unknown file | |||
| file = m_baseFolder.resolveFile( "unknown-child" ); | |||
| FileSystemException exc = null; | |||
| try | |||
| { | |||
| file.getType(); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| exc = e; | |||
| final String message = REZ.getString( "get-type-no-exist.error", file ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| assertNotNull( exc ); | |||
| } | |||
| /** | |||
| @@ -419,10 +499,12 @@ public abstract class AbstractFileSystemTest | |||
| try | |||
| { | |||
| file.getChildren(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "list-children-not-folder.error", file ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| // Should be able to get child by name | |||
| @@ -435,10 +517,12 @@ public abstract class AbstractFileSystemTest | |||
| try | |||
| { | |||
| file.getChildren(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "list-children-no-exist.error", file ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| // Should be able to get child by name | |||
| @@ -468,23 +552,33 @@ public abstract class AbstractFileSystemTest | |||
| * a byte stream, and as a char stream, and compares the result with | |||
| * the expected content. Assumes files are encoded using UTF-8. | |||
| */ | |||
| public void assertSameContent( String expected, FileContent content ) throws Exception | |||
| protected void assertSameContent( final String expected, | |||
| final FileContent content ) | |||
| throws Exception | |||
| { | |||
| // Get file content as a binary stream | |||
| byte[] expectedBin = expected.getBytes( "utf-8" ); | |||
| final byte[] expectedBin = expected.getBytes( "utf-8" ); | |||
| // Check lengths | |||
| assertEquals( "same content length", expectedBin.length, content.getSize() ); | |||
| // Read content into byte array | |||
| InputStream instr = content.getInputStream(); | |||
| ByteArrayOutputStream outstr = new ByteArrayOutputStream(); | |||
| byte[] buffer = new byte[ 256 ]; | |||
| int nread = 0; | |||
| while( nread >= 0 ) | |||
| final InputStream instr = content.getInputStream(); | |||
| final ByteArrayOutputStream outstr; | |||
| try | |||
| { | |||
| outstr = new ByteArrayOutputStream(); | |||
| final byte[] buffer = new byte[ 256 ]; | |||
| int nread = 0; | |||
| while( nread >= 0 ) | |||
| { | |||
| outstr.write( buffer, 0, nread ); | |||
| nread = instr.read( buffer ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| outstr.write( buffer, 0, nread ); | |||
| nread = instr.read( buffer ); | |||
| instr.close(); | |||
| } | |||
| // Compare | |||
| @@ -501,10 +595,12 @@ public abstract class AbstractFileSystemTest | |||
| try | |||
| { | |||
| folder.getContent(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "get-folder-content.error", folder ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| // Try getting the content of an unknown file | |||
| @@ -513,18 +609,22 @@ public abstract class AbstractFileSystemTest | |||
| try | |||
| { | |||
| content.getInputStream(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "read-no-exist.error", unknownFile ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| try | |||
| { | |||
| content.getSize(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "get-size-no-exist.error", unknownFile ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| } | |||
| @@ -557,7 +657,7 @@ public abstract class AbstractFileSystemTest | |||
| /** | |||
| * Info about a file. | |||
| */ | |||
| private static final class FileInfo | |||
| protected static final class FileInfo | |||
| { | |||
| String _baseName; | |||
| FileType _type; | |||
| @@ -15,6 +15,9 @@ import java.util.HashMap; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import org.apache.aut.vfs.impl.DefaultFileSystemManager; | |||
| import org.apache.aut.vfs.provider.AbstractFileObject; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| /** | |||
| @@ -29,6 +32,9 @@ import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| public abstract class AbstractFileSystemTest | |||
| extends AbstractMyrmidonTest | |||
| { | |||
| private final static Resources REZ | |||
| = ResourceManager.getPackageResources( AbstractFileObject.class ); | |||
| protected FileObject m_baseFolder; | |||
| protected DefaultFileSystemManager m_manager; | |||
| @@ -46,12 +52,12 @@ public abstract class AbstractFileSystemTest | |||
| private FileInfo buildExpectedStructure() | |||
| { | |||
| // Build the expected structure | |||
| FileInfo base = new FileInfo( "test", FileType.FOLDER ); | |||
| final FileInfo base = new FileInfo( "test", FileType.FOLDER ); | |||
| base.addChild( new FileInfo( "file1.txt", FileType.FILE ) ); | |||
| base.addChild( new FileInfo( "empty.txt", FileType.FILE ) ); | |||
| base.addChild( new FileInfo( "emptydir", FileType.FOLDER ) ); | |||
| FileInfo dir = new FileInfo( "dir1", FileType.FOLDER ); | |||
| final FileInfo dir = new FileInfo( "dir1", FileType.FOLDER ); | |||
| base.addChild( dir ); | |||
| dir.addChild( new FileInfo( "file1.txt", FileType.FILE ) ); | |||
| dir.addChild( new FileInfo( "file2.txt", FileType.FILE ) ); | |||
| @@ -76,7 +82,7 @@ public abstract class AbstractFileSystemTest | |||
| m_baseFolder = m_manager.resolveFile( getBaseFolderURI() ); | |||
| // Build the expected content of "file1.txt" | |||
| String eol = System.getProperty( "line.separator" ); | |||
| final String eol = System.getProperty( "line.separator" ); | |||
| m_charContent = "This is a test file." + eol + "With 2 lines in it." + eol; | |||
| } | |||
| @@ -86,8 +92,8 @@ public abstract class AbstractFileSystemTest | |||
| public void testAbsoluteURI() throws Exception | |||
| { | |||
| // Try fetching base folder again by its URI | |||
| String uri = m_baseFolder.getName().getURI(); | |||
| FileObject file = m_manager.resolveFile( uri ); | |||
| final String uri = m_baseFolder.getName().getURI(); | |||
| final FileObject file = m_manager.resolveFile( uri ); | |||
| assertSame( "file object", m_baseFolder, file ); | |||
| } | |||
| @@ -123,7 +129,7 @@ public abstract class AbstractFileSystemTest | |||
| public void testRootFileName() throws Exception | |||
| { | |||
| // Locate the root file | |||
| FileName rootName = m_baseFolder.getRoot().getName(); | |||
| final FileName rootName = m_baseFolder.getRoot().getName(); | |||
| // Test that the root path is "/" | |||
| assertEquals( "root path", "/", rootName.getPath() ); | |||
| @@ -140,9 +146,9 @@ public abstract class AbstractFileSystemTest | |||
| */ | |||
| public void testChildName() throws Exception | |||
| { | |||
| FileName baseName = m_baseFolder.getName(); | |||
| String basePath = baseName.getPath(); | |||
| FileName name = baseName.resolveName( "some-child", NameScope.CHILD ); | |||
| final FileName baseName = m_baseFolder.getName(); | |||
| final String basePath = baseName.getPath(); | |||
| final FileName name = baseName.resolveName( "some-child", NameScope.CHILD ); | |||
| // Test path is absolute | |||
| assertTrue( "is absolute", basePath.startsWith( "/" ) ); | |||
| @@ -157,76 +163,95 @@ public abstract class AbstractFileSystemTest | |||
| assertEquals( "parent absolute path", basePath, name.getParent().getPath() ); | |||
| // Try using a compound name to find a child | |||
| try | |||
| { | |||
| name.resolveName( "a/b", NameScope.CHILD ); | |||
| assertTrue( false ); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| } | |||
| assertBadName( name, "a/b", NameScope.CHILD ); | |||
| // Try using a empty name to find a child | |||
| try | |||
| { | |||
| name.resolveName( "", NameScope.CHILD ); | |||
| assertTrue( false ); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| } | |||
| // Try using '.' to find a child | |||
| try | |||
| { | |||
| name.resolveName( ".", NameScope.CHILD ); | |||
| assertTrue( false ); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| } | |||
| // Check other invalid names | |||
| checkDescendentNames( name, NameScope.CHILD ); | |||
| } | |||
| // Try using '..' to find a child | |||
| try | |||
| { | |||
| name.resolveName( "..", NameScope.CHILD ); | |||
| assertTrue( false ); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| } | |||
| /** | |||
| * Name resolution tests that are common for CHILD or DESCENDENT scope. | |||
| */ | |||
| private void checkDescendentNames( final FileName name, | |||
| final NameScope scope ) | |||
| throws Exception | |||
| { | |||
| // Make some assumptions about the name explicit | |||
| assertTrue( !name.getPath().equals( "/" ) ); | |||
| assertTrue( !name.getPath().endsWith( "/a" ) ); | |||
| assertTrue( !name.getPath().endsWith( "/a/b" ) ); | |||
| // Test names with the same prefix | |||
| String path = name.getPath() + "/a"; | |||
| assertSameName( path, name, path, scope ); | |||
| assertSameName( path, name, "../" + name.getBaseName() + "/a", scope ); | |||
| // Test an empty name | |||
| assertBadName( name, "", scope ); | |||
| // Test . name | |||
| assertBadName( name, ".", scope ); | |||
| assertBadName( name, "./", scope ); | |||
| // Test ancestor names | |||
| assertBadName( name, "..", scope ); | |||
| assertBadName( name, "../a", scope ); | |||
| assertBadName( name, "../" + name.getBaseName() + "a", scope ); | |||
| assertBadName( name, "a/..", scope ); | |||
| // Test absolute names | |||
| assertBadName( name, "/", scope ); | |||
| assertBadName( name, "/a", scope ); | |||
| assertBadName( name, "/a/b", scope ); | |||
| assertBadName( name, name.getPath(), scope ); | |||
| assertBadName( name, name.getPath() + "a", scope ); | |||
| } | |||
| /** | |||
| * Checks that a relative name resolves to the expected absolute path. | |||
| * Tests both forward and back slashes. | |||
| */ | |||
| private void assertSameName( String expectedPath, | |||
| FileName baseName, | |||
| String relName ) throws Exception | |||
| private void assertSameName( final String expectedPath, | |||
| final FileName baseName, | |||
| final String relName, | |||
| final NameScope scope ) | |||
| throws Exception | |||
| { | |||
| FileName name = baseName.resolveName( relName ); | |||
| // Try the supplied name | |||
| FileName name = baseName.resolveName( relName, scope ); | |||
| assertEquals( expectedPath, name.getPath() ); | |||
| // Replace the separators | |||
| relName.replace( '\\', '/' ); | |||
| name = baseName.resolveName( relName ); | |||
| name = baseName.resolveName( relName, scope ); | |||
| assertEquals( expectedPath, name.getPath() ); | |||
| // And again | |||
| relName.replace( '/', '\\' ); | |||
| name = baseName.resolveName( relName ); | |||
| name = baseName.resolveName( relName, scope ); | |||
| assertEquals( expectedPath, name.getPath() ); | |||
| } | |||
| /** | |||
| * Checks that a relative name resolves to the expected absolute path. | |||
| * Tests both forward and back slashes. | |||
| */ | |||
| private void assertSameName( String expectedPath, | |||
| FileName baseName, | |||
| String relName ) throws Exception | |||
| { | |||
| assertSameName( expectedPath, baseName, relName, NameScope.FILE_SYSTEM ); | |||
| } | |||
| /** | |||
| * Tests relative name resolution, relative to the base folder. | |||
| */ | |||
| public void testNameResolution() throws Exception | |||
| { | |||
| FileName baseName = m_baseFolder.getName(); | |||
| String parentPath = baseName.getParent().getPath(); | |||
| String path = baseName.getPath(); | |||
| String childPath = path + "/some-child"; | |||
| final FileName baseName = m_baseFolder.getName(); | |||
| final String parentPath = baseName.getParent().getPath(); | |||
| final String path = baseName.getPath(); | |||
| final String childPath = path + "/some-child"; | |||
| // Test empty relative path | |||
| assertSameName( path, baseName, "" ); | |||
| @@ -280,23 +305,78 @@ public abstract class AbstractFileSystemTest | |||
| } | |||
| /** | |||
| * Walks the folder structure, asserting it contains exactly the | |||
| * Tests descendent name resolution. | |||
| */ | |||
| public void testDescendentName() | |||
| throws Exception | |||
| { | |||
| final FileName baseName = m_baseFolder.getName(); | |||
| // Test direct child | |||
| String path = baseName.getPath() + "/some-child"; | |||
| assertSameName( path, baseName, "some-child", NameScope.DESCENDENT ); | |||
| // Test compound name | |||
| path = path + "/grand-child"; | |||
| assertSameName( path, baseName, "some-child/grand-child", NameScope.DESCENDENT ); | |||
| // Test relative names | |||
| assertSameName( path, baseName, "./some-child/grand-child", NameScope.DESCENDENT ); | |||
| assertSameName( path, baseName, "./nada/../some-child/grand-child", NameScope.DESCENDENT ); | |||
| assertSameName( path, baseName, "some-child/./grand-child", NameScope.DESCENDENT ); | |||
| // Test badly formed descendent names | |||
| checkDescendentNames( baseName, NameScope.DESCENDENT ); | |||
| } | |||
| /** | |||
| * Asserts that a particular relative name is invalid for a particular | |||
| * scope. | |||
| */ | |||
| private void assertBadName( final FileName name, | |||
| final String relName, | |||
| final NameScope scope ) | |||
| { | |||
| try | |||
| { | |||
| name.resolveName( relName, scope ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| // TODO - should check error message | |||
| } | |||
| } | |||
| /** | |||
| * Walks the base folder structure, asserting it contains exactly the | |||
| * expected files and folders. | |||
| */ | |||
| public void testStructure() throws Exception | |||
| { | |||
| final FileInfo baseInfo = buildExpectedStructure(); | |||
| assertSameStructure( m_baseFolder, baseInfo ); | |||
| } | |||
| /** | |||
| * Walks a folder structure, asserting it contains exactly the | |||
| * expected files and folders. | |||
| */ | |||
| protected void assertSameStructure( final FileObject folder, | |||
| final FileInfo expected ) | |||
| throws Exception | |||
| { | |||
| // Setup the structure | |||
| List queueExpected = new ArrayList(); | |||
| FileInfo baseInfo = buildExpectedStructure(); | |||
| queueExpected.add( baseInfo ); | |||
| final List queueExpected = new ArrayList(); | |||
| queueExpected.add( expected ); | |||
| List queueActual = new ArrayList(); | |||
| queueActual.add( m_baseFolder ); | |||
| final List queueActual = new ArrayList(); | |||
| queueActual.add( folder ); | |||
| while( queueActual.size() > 0 ) | |||
| { | |||
| FileObject file = (FileObject)queueActual.remove( 0 ); | |||
| FileInfo info = (FileInfo)queueExpected.remove( 0 ); | |||
| final FileObject file = (FileObject)queueActual.remove( 0 ); | |||
| final FileInfo info = (FileInfo)queueExpected.remove( 0 ); | |||
| // Check the type is correct | |||
| assertSame( file.getType(), info._type ); | |||
| @@ -307,7 +387,7 @@ public abstract class AbstractFileSystemTest | |||
| } | |||
| // Check children | |||
| FileObject[] children = file.getChildren(); | |||
| final FileObject[] children = file.getChildren(); | |||
| // Make sure all children were found | |||
| assertNotNull( children ); | |||
| @@ -316,8 +396,8 @@ public abstract class AbstractFileSystemTest | |||
| // Recursively check each child | |||
| for( int i = 0; i < children.length; i++ ) | |||
| { | |||
| FileObject child = children[ i ]; | |||
| FileInfo childInfo = (FileInfo)info._children.get( child.getName().getBaseName() ); | |||
| final FileObject child = children[ i ]; | |||
| final FileInfo childInfo = (FileInfo)info._children.get( child.getName().getBaseName() ); | |||
| // Make sure the child is expected | |||
| assertNotNull( childInfo ); | |||
| @@ -366,16 +446,16 @@ public abstract class AbstractFileSystemTest | |||
| // Test an unknown file | |||
| file = m_baseFolder.resolveFile( "unknown-child" ); | |||
| FileSystemException exc = null; | |||
| try | |||
| { | |||
| file.getType(); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| exc = e; | |||
| final String message = REZ.getString( "get-type-no-exist.error", file ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| assertNotNull( exc ); | |||
| } | |||
| /** | |||
| @@ -419,10 +499,12 @@ public abstract class AbstractFileSystemTest | |||
| try | |||
| { | |||
| file.getChildren(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "list-children-not-folder.error", file ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| // Should be able to get child by name | |||
| @@ -435,10 +517,12 @@ public abstract class AbstractFileSystemTest | |||
| try | |||
| { | |||
| file.getChildren(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "list-children-no-exist.error", file ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| // Should be able to get child by name | |||
| @@ -468,23 +552,33 @@ public abstract class AbstractFileSystemTest | |||
| * a byte stream, and as a char stream, and compares the result with | |||
| * the expected content. Assumes files are encoded using UTF-8. | |||
| */ | |||
| public void assertSameContent( String expected, FileContent content ) throws Exception | |||
| protected void assertSameContent( final String expected, | |||
| final FileContent content ) | |||
| throws Exception | |||
| { | |||
| // Get file content as a binary stream | |||
| byte[] expectedBin = expected.getBytes( "utf-8" ); | |||
| final byte[] expectedBin = expected.getBytes( "utf-8" ); | |||
| // Check lengths | |||
| assertEquals( "same content length", expectedBin.length, content.getSize() ); | |||
| // Read content into byte array | |||
| InputStream instr = content.getInputStream(); | |||
| ByteArrayOutputStream outstr = new ByteArrayOutputStream(); | |||
| byte[] buffer = new byte[ 256 ]; | |||
| int nread = 0; | |||
| while( nread >= 0 ) | |||
| final InputStream instr = content.getInputStream(); | |||
| final ByteArrayOutputStream outstr; | |||
| try | |||
| { | |||
| outstr = new ByteArrayOutputStream(); | |||
| final byte[] buffer = new byte[ 256 ]; | |||
| int nread = 0; | |||
| while( nread >= 0 ) | |||
| { | |||
| outstr.write( buffer, 0, nread ); | |||
| nread = instr.read( buffer ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| outstr.write( buffer, 0, nread ); | |||
| nread = instr.read( buffer ); | |||
| instr.close(); | |||
| } | |||
| // Compare | |||
| @@ -501,10 +595,12 @@ public abstract class AbstractFileSystemTest | |||
| try | |||
| { | |||
| folder.getContent(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "get-folder-content.error", folder ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| // Try getting the content of an unknown file | |||
| @@ -513,18 +609,22 @@ public abstract class AbstractFileSystemTest | |||
| try | |||
| { | |||
| content.getInputStream(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "read-no-exist.error", unknownFile ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| try | |||
| { | |||
| content.getSize(); | |||
| assertTrue( false ); | |||
| fail(); | |||
| } | |||
| catch( FileSystemException e ) | |||
| { | |||
| final String message = REZ.getString( "get-size-no-exist.error", unknownFile ); | |||
| assertSameMessage( message, e ); | |||
| } | |||
| } | |||
| @@ -557,7 +657,7 @@ public abstract class AbstractFileSystemTest | |||
| /** | |||
| * Info about a file. | |||
| */ | |||
| private static final class FileInfo | |||
| protected static final class FileInfo | |||
| { | |||
| String _baseName; | |||
| FileType _type; | |||