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

alunacjones / LSL.HttpMessageHandlers.FileSchemes / 5

15 Dec 2025 02:23AM UTC coverage: 98.81% (+0.06%) from 98.75%
5

push

appveyor

Alun Jones
updates

83 of 84 relevant lines covered (98.81%)

10.62 hits per line

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

95.45
/src/LSL.HttpMessageHandlers.FileSchemes/RelativePathUriExtensions.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using LSL.HttpMessageHandlers.FileSchemes.Infrastructure;
5

6
namespace LSL.HttpMessageHandlers.FileSchemes;
7

8
/// <summary>
9
/// Relative path uri extensions
10
/// </summary>
11
public static class RelativePathUriExtensions
12
{
13
    /// <summary>
14
    /// Set the Uri path relatively to the existing path
15
    /// </summary>
16
    /// <example>
17
    /// new Uri("http://nowhere.com/asd").SetRelativePath("../test/file.txt")
18
    /// </example>
19
    /// <param name="source"></param>
20
    /// <param name="relativePath"></param>
21
    /// <param name="ignoreFileLikeLastSegment"></param>
22
    /// <returns></returns>
23
    public static Uri SetRelativePath(this Uri source, string relativePath, bool ignoreFileLikeLastSegment = true)
24
    {
25
        var builder = new UriBuilder(source.AssertNotNull(nameof(source)));
14✔
26
        var relativePathSegments = relativePath.AssertNotNull(nameof(relativePath)).SplitUriPath();        
14✔
27
        var originalPathSegments = source.AbsolutePath.SplitUriPath();
14✔
28

29
        if (ignoreFileLikeLastSegment && originalPathSegments.TryGetLastItem(out var lastElement) && lastElement.IsLikeAFileName())
14✔
30
        {
31
            originalPathSegments = [.. originalPathSegments.AsEnumerable().Take(originalPathSegments.Length - 1)];
2✔
32
        }
33

34
        var newPaths = relativePathSegments.Aggregate(
14✔
35
            new PathAggregation(originalPathSegments, false, source, relativePath),
14✔
36
            (agg, i) =>
14✔
37
                i switch
55✔
38
                {
55✔
39
                    "." => agg.AssertNotConcatenated(),
60✔
40
                    ".." => agg.AssertNotConcatenated() with { Segments = agg.Segments.Skip(1) },
64✔
41
                    _ => agg with { Segments = agg.Segments.Concat([i]), HasConcatenated = true }
82✔
42
                }
55✔
43
            );
14✔
44

45
        builder.Path = string.Join("/", newPaths.Segments);
13✔
46

47
        return builder.Uri;        
13✔
48
    }
49

50
    internal static string[] SplitUriPath(this string source) => source.Split(['/'], StringSplitOptions.RemoveEmptyEntries);
28✔
51

52
    private readonly record struct PathAggregation(IEnumerable<string> Segments, bool HasConcatenated, Uri SourceUri, string RelativePath)
×
53
    {
54
        public PathAggregation AssertNotConcatenated() => HasConcatenated 
14✔
55
            ? throw new InvalidRelativeUrlException(SourceUri, RelativePath)
14✔
56
            : this;
14✔
57
    }
58
}
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