mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
171 lines
6.2 KiB
C#
171 lines
6.2 KiB
C#
#nullable enable
|
|
using System.Text;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace UnitTests_Parallelizable.DriverTests;
|
|
|
|
public class Osc8UrlLinkerTests (ITestOutputHelper output)
|
|
{
|
|
private readonly ITestOutputHelper _output = output;
|
|
|
|
[Theory]
|
|
[InlineData ("<https://example.com>", "<", "https://example.com", ">")]
|
|
[InlineData ("\"https://example.com\"", "\"", "https://example.com", "\"")]
|
|
public void WrapOsc8_Does_Not_Cross_Delimiters (string input, string prefix, string url, string suffix)
|
|
{
|
|
string actual = Wrap (input);
|
|
string expected = prefix + LinkWrappedWithOSCs (url) + suffix;
|
|
Assert.Equal (expected, actual);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData ("No url here")]
|
|
[InlineData ("http://")]
|
|
[InlineData ("://missing-scheme.com")]
|
|
public void WrapOsc8_Leaves_Text_Unchanged_Without_Urls (string input)
|
|
{
|
|
StringBuilder sb = new (input);
|
|
StringBuilder result = Osc8UrlLinker.WrapOsc8 (sb);
|
|
|
|
Assert.Same (sb, result);
|
|
Assert.Equal (input, result.ToString ());
|
|
}
|
|
|
|
[Fact]
|
|
public void WrapOsc8_Stops_At_Ansi_Escape_Sequence ()
|
|
{
|
|
var esc = "\x1B[38;2;173m";
|
|
string input = "https://example.com" + esc + "/more";
|
|
|
|
string wrapped = Wrap (input);
|
|
string expected = LinkWrappedWithOSCs ("https://example.com") + esc + "/more";
|
|
Assert.Equal (expected, wrapped);
|
|
|
|
// Verify that the hyperlinked visible content contains no ESC
|
|
string start = EscSeqUtils.OSC_StartHyperlink ("https://example.com");
|
|
string end = EscSeqUtils.OSC_EndHyperlink ();
|
|
int s = wrapped.IndexOf (start, StringComparison.Ordinal);
|
|
Assert.True (s >= 0);
|
|
|
|
int e = wrapped.IndexOf (end, s + start.Length, StringComparison.Ordinal);
|
|
Assert.True (e > s);
|
|
|
|
int contentStart = s + start.Length;
|
|
int contentLength = e - contentStart;
|
|
string visible = wrapped.Substring (contentStart, contentLength);
|
|
|
|
Assert.DoesNotContain ('\x1B', visible);
|
|
Assert.Equal ("https://example.com", visible);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData ("See https://example.com/path.", "See ", "https://example.com/path", ".")]
|
|
[InlineData ("See https://example.com/file.tar.gz,", "See ", "https://example.com/file.tar.gz", ",")]
|
|
[InlineData ("See https://example.com/path_(with)_parens)", "See ", "https://example.com/path_(with)_parens", ")")]
|
|
public void WrapOsc8_Trims_Trailing_Punctuation (string input, string prefix, string url, string suffix)
|
|
{
|
|
string actual = Wrap (input);
|
|
string expected = prefix + LinkWrappedWithOSCs (url) + suffix;
|
|
Assert.Equal (expected, actual);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData (
|
|
"Multiple: https://a.com, https://b.com!",
|
|
"Multiple: ",
|
|
"https://a.com",
|
|
", ",
|
|
"https://b.com",
|
|
"!")]
|
|
[InlineData (
|
|
"List https://one.com https://two.com https://three.com",
|
|
"List ",
|
|
"https://one.com",
|
|
" ",
|
|
"https://two.com",
|
|
" ",
|
|
"https://three.com",
|
|
"")]
|
|
public void WrapOsc8_Wraps_Multiple_Urls (string input, params string [] segments)
|
|
{
|
|
// segments: text0, url1, text1, [url2, text2]...
|
|
string expected = BuildExpected (segments);
|
|
|
|
string actual = Wrap (input);
|
|
Assert.Equal (expected, actual);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData ("https://github.com", "https://github.com")]
|
|
[InlineData ("http://example.com", "http://example.com")]
|
|
[InlineData ("ftp://ftp.example.com/file.zip", "ftp://ftp.example.com/file.zip")]
|
|
[InlineData ("https://example.com:8080/path", "https://example.com:8080/path")]
|
|
[InlineData ("https://example.com/path#anchor", "https://example.com/path#anchor")]
|
|
[InlineData ("https://example.com/path?query=value&other=123", "https://example.com/path?query=value&other=123")]
|
|
[InlineData ("https://commons.wikimedia.org/wiki/File:Spinning_globe.gif", "https://commons.wikimedia.org/wiki/File:Spinning_globe.gif")]
|
|
public void WrapOsc8_Wraps_Standalone_Url (string input, string expectedUrl)
|
|
{
|
|
string actual = Wrap (input);
|
|
string expected = LinkWrappedWithOSCs (expectedUrl);
|
|
Assert.Equal (expected, actual);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData (
|
|
"Visit https://github.com for more info",
|
|
"Visit ",
|
|
"https://github.com",
|
|
" for more info")]
|
|
[InlineData (
|
|
"Check out https://commons.wikimedia.org/wiki/File:Spinning_globe.gif!",
|
|
"Check out ",
|
|
"https://commons.wikimedia.org/wiki/File:Spinning_globe.gif",
|
|
"!")]
|
|
[InlineData (
|
|
"URLs: https://example.com and http://other.com",
|
|
"URLs: ",
|
|
"https://example.com",
|
|
" and ",
|
|
"http://other.com",
|
|
"")]
|
|
public void WrapOsc8_Wraps_Urls_In_Text (string input, params string [] segments)
|
|
{
|
|
// segments: text0, url1, text1, [url2, text2]...
|
|
string expected = BuildExpected (segments);
|
|
|
|
string actual = Wrap (input);
|
|
Assert.Equal (expected, actual);
|
|
}
|
|
|
|
private static string BuildExpected (string [] segments)
|
|
{
|
|
// segments must be: text0, url1, text1, url2, text2, ...
|
|
string expected = segments.Length > 0 ? segments [0] : string.Empty;
|
|
|
|
for (var i = 1; i + 1 < segments.Length; i += 2)
|
|
{
|
|
string url = segments [i];
|
|
string textAfter = segments [i + 1];
|
|
|
|
expected += LinkWrappedWithOSCs (url);
|
|
expected += textAfter;
|
|
}
|
|
|
|
return expected;
|
|
}
|
|
|
|
private static string LinkWrappedWithOSCs (string url, string? display = null)
|
|
{
|
|
display ??= url;
|
|
|
|
return EscSeqUtils.OSC_StartHyperlink (url) + display + EscSeqUtils.OSC_EndHyperlink ();
|
|
}
|
|
|
|
private static string Wrap (string input)
|
|
{
|
|
StringBuilder sb = new (input);
|
|
|
|
return Osc8UrlLinker.WrapOsc8 (sb).ToString ();
|
|
}
|
|
}
|