public void all_kind_of_root(string p, NormalizedPathRootKind o, string path)
        {
            var n = new NormalizedPath(p);

            n.RootKind.Should().Be(o);
            n.Path.Should().Be(path);
        }
Exemple #2
0
 NormalizedPath(string[]?parts, string path, NormalizedPathRootKind o)
 {
     Debug.Assert(path != null);
     Debug.Assert(parts != null || o != NormalizedPathRootKind.RootedByFirstPart, "parts == null ==> option != RootedByFirstPart");
     _parts  = parts;
     _path   = path;
     _option = o;
 }
Exemple #3
0
        static string BuildNonEmptyPath(string[] parts, NormalizedPathRootKind o)
        {
            var path = parts.Concatenate(DirectorySeparatorString);

            switch (o)
            {
            case NormalizedPathRootKind.RootedBySeparator: return(DirectorySeparatorChar + path);

            case NormalizedPathRootKind.RootedByDoubleSeparator: return(DoubleDirectorySeparatorString + path);

            default: return(path);
            }
        }
Exemple #4
0
 NormalizedPath(NormalizedPathRootKind o)
 {
     if (o == NormalizedPathRootKind.RootedByFirstPart)
     {
         o = NormalizedPathRootKind.None;
     }
     _parts = null;
     _path  = o == NormalizedPathRootKind.RootedBySeparator
             ? DirectorySeparatorString
             : (o == NormalizedPathRootKind.RootedByDoubleSeparator
                ? DoubleDirectorySeparatorString
                : String.Empty);
     _option = o;
 }
 public void changing_RootKind(string p, NormalizedPathRootKind newKind, string result)
 {
     if (result == "ArgumentException")
     {
         new NormalizedPath(p).Invoking(sut => sut.With(newKind))
         .Should().Throw <ArgumentException>();
     }
     else
     {
         var r = new NormalizedPath(p).With(newKind);
         r.RootKind.Should().Be(newKind);
         r.Should().Be(new NormalizedPath(result));
     }
 }
Exemple #6
0
 /// <summary>
 /// Explicitly builds a new <see cref="NormalizedPath"/> struct from a string (that can be null or empty).
 /// </summary>
 /// <param name="path">The path as a string (can be null or empty).</param>
 public NormalizedPath(string path)
 {
     _parts = path?.Split(_separators, StringSplitOptions.RemoveEmptyEntries);
     if (_parts == null || _parts.Length == 0)
     {
         _parts  = null;
         _path   = String.Empty;
         _option = NormalizedPathRootKind.None;
         if (path != null && path.Length > 0)
         {
             if (path[0] == DirectorySeparatorChar || path[0] == AltDirectorySeparatorChar)
             {
                 if (path.Length > 1 &&
                     (path[1] == DirectorySeparatorChar || path[1] == AltDirectorySeparatorChar))
                 {
                     _path   = DoubleDirectorySeparatorString;
                     _option = NormalizedPathRootKind.RootedByDoubleSeparator;
                 }
                 else
                 {
                     _path   = DirectorySeparatorString;
                     _option = NormalizedPathRootKind.RootedBySeparator;
                 }
             }
         }
     }
     else
     {
         Debug.Assert(path != null);
         var c = path[0];
         if (c == DirectorySeparatorChar || c == AltDirectorySeparatorChar)
         {
             _path = DirectorySeparatorChar + _parts.Concatenate(DirectorySeparatorString);
             if (path.Length > 1)
             {
                 c = path[1];
                 if (c == DirectorySeparatorChar || c == AltDirectorySeparatorChar)
                 {
                     _path   = DirectorySeparatorChar + _path;
                     _option = NormalizedPathRootKind.RootedByDoubleSeparator;
                 }
                 else
                 {
                     _option = NormalizedPathRootKind.RootedBySeparator;
                 }
             }
             else
             {
                 _option = NormalizedPathRootKind.None;
             }
         }
         else if (c == '~')
         {
             _option = NormalizedPathRootKind.RootedByFirstPart;
             _path   = _parts.Concatenate(DirectorySeparatorString);
         }
         else
         {
             _option = NormalizedPathRootKind.None;
             _path   = _parts.Concatenate(DirectorySeparatorString);
             var first = _parts[0];
             if (first.Length > 0 && first[first.Length - 1] == ':')
             {
                 _option = NormalizedPathRootKind.RootedByFirstPart;
             }
         }
     }
     Debug.Assert(_parts != null || _option != NormalizedPathRootKind.RootedByFirstPart, "parts == null ==> option != RootedByFirstPart");
 }
Exemple #7
0
        /// <summary>
        /// Returns a path where '.' and '..' parts are resolved under a root part.
        /// When <paramref name="throwOnAboveRoot"/> is true (the default), any '..' that would
        /// lead to a path above the root throws an <see cref="InvalidOperationException"/>.
        /// When false, the root acts as an absorbing element.
        /// </summary>
        /// <param name="rootPartsCount">
        /// By default, the resolution can reach the empty root.
        /// By specifying a positive number, any prefix length can be locked.
        /// Dotted parts in this locked prefix will be ignored and left as-is in the result.
        /// </param>
        /// <param name="throwOnAboveRoot">
        /// By default any attempt to resolve above the root will throw an <see cref="InvalidOperationException"/>.
        /// By specifying false, the root acts as an absorbing element.
        /// </param>
        /// <returns>The resolved normalized path.</returns>
        public NormalizedPath ResolveDots(int rootPartsCount = 0, bool throwOnAboveRoot = true)
        {
            int len = _parts != null ? _parts.Length : 0;

            if (rootPartsCount > len)
            {
                throw new ArgumentOutOfRangeException(nameof(rootPartsCount));
            }
            if (rootPartsCount == 0 && _option == NormalizedPathRootKind.RootedByFirstPart)
            {
                rootPartsCount = 1;
            }
            if (rootPartsCount == len)
            {
                return(this);
            }
            Debug.Assert(!IsEmptyPath);
            string[] newParts        = null;
            int      current         = 0;
            NormalizedPathRootKind o = _option;

            for (int i = rootPartsCount; i < len; ++i)
            {
                string curPart  = _parts[i];
                bool   isDot    = curPart == ".";
                bool   isDotDot = !isDot && curPart == "..";
                if (isDot || isDotDot)
                {
                    if (newParts == null)
                    {
                        newParts = new string[_parts.Length];
                        current  = i;
                        if (isDotDot)
                        {
                            --current;
                        }
                        if (current < rootPartsCount)
                        {
                            if (throwOnAboveRoot)
                            {
                                ThrowAboveRootException(_parts, rootPartsCount, i);
                            }
                            current = rootPartsCount;
                        }
                        Array.Copy(_parts, 0, newParts, 0, current);
                    }
                    else if (isDotDot)
                    {
                        if (current == rootPartsCount)
                        {
                            if (throwOnAboveRoot)
                            {
                                ThrowAboveRootException(_parts, rootPartsCount, i);
                            }
                        }
                        else
                        {
                            --current;
                        }
                    }
                }
                else if (newParts != null)
                {
                    newParts[current++] = curPart;
                }
            }
            if (newParts == null)
            {
                return(this);
            }
            if (current == 0)
            {
                return(new NormalizedPath(_option));
            }
            Array.Resize(ref newParts, current);
            return(new NormalizedPath(newParts, BuildNonEmptyPath(newParts, o), o));
        }
Exemple #8
0
        /// <summary>
        /// Sets the <see cref="RootKind"/> by returning this or a new <see cref="NormalizedPath"/>.
        /// The only forbidden case is to set the <see cref="NormalizedPathRootKind.RootedByFirstPart"/>
        /// when <see cref="HasParts"/> is false: this throws an <see cref="ArgumentException"/>.
        /// </summary>
        /// <param name="kind">The <see cref="NormalizedPathRootKind"/> to set.</param>
        /// <returns>This or a new path.</returns>
        public NormalizedPath With(NormalizedPathRootKind kind)
        {
            if (kind == _option)
            {
                return(this);
            }
            if (_parts == null)
            {
                switch (kind)
                {
                case NormalizedPathRootKind.None:
                {
                    Debug.Assert(_option == NormalizedPathRootKind.RootedBySeparator || _option == NormalizedPathRootKind.RootedByDoubleSeparator);
                    return(new NormalizedPath());
                }

                case NormalizedPathRootKind.RootedByFirstPart:
                {
                    throw new ArgumentException("Invalid RootedByFirstPart on path without any parts.");
                }

                case NormalizedPathRootKind.RootedBySeparator:
                {
                    return(new NormalizedPath(kind));
                }

                case NormalizedPathRootKind.RootedByDoubleSeparator:
                {
                    return(new NormalizedPath(kind));
                }

                default: throw new NotSupportedException();
                }
            }
            if (_option == NormalizedPathRootKind.None || _option == NormalizedPathRootKind.RootedByFirstPart)
            {
                switch (kind)
                {
                case NormalizedPathRootKind.None:
                case NormalizedPathRootKind.RootedByFirstPart: return(new NormalizedPath(_parts, _path, kind));

                case NormalizedPathRootKind.RootedBySeparator: return(new NormalizedPath(_parts, DirectorySeparatorChar + _path, kind));

                case NormalizedPathRootKind.RootedByDoubleSeparator: return(new NormalizedPath(_parts, DoubleDirectorySeparatorString + _path, kind));

                default: throw new NotSupportedException();
                }
            }
            Debug.Assert(_option == NormalizedPathRootKind.RootedBySeparator || _option == NormalizedPathRootKind.RootedByDoubleSeparator);
            switch (kind)
            {
            case NormalizedPathRootKind.None:
            case NormalizedPathRootKind.RootedByFirstPart: return(new NormalizedPath(_parts, _path.Substring(_option == NormalizedPathRootKind.RootedBySeparator ? 1 : 2), kind));

            case NormalizedPathRootKind.RootedBySeparator: return(new NormalizedPath(_parts, _path.Substring(1), kind));

            case NormalizedPathRootKind.RootedByDoubleSeparator: return(new NormalizedPath(_parts, DirectorySeparatorChar + _path, kind));

            default: throw new NotSupportedException();
            }
        }