#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", ">")] [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 (); } }