Files
Playa/tests/Volcanic.AgenticCore.Telegram.Tests/FormattingAndOptionsTests.cs

88 lines
3.8 KiB
C#

using Volcanic.AgenticCore.Telegram.Chats;
using Volcanic.AgenticCore.Telegram.Rendering;
namespace Volcanic.AgenticCore.Telegram.Tests;
public sealed class FormattingAndOptionsTests
{
[Theory]
[InlineData("a < b & c > d", "a &lt; b &amp; c &gt; d")]
[InlineData("**bold** and *it* and _it_", "<b>bold</b> and <i>it</i> and <i>it</i>")]
[InlineData("use `x < 1` here", "use <code>x &lt; 1</code> here")]
[InlineData("`**not bold**`", "<code>**not bold**</code>")]
[InlineData("snake_case_name stays", "snake_case_name stays")]
[InlineData("# Title", "<b>Title</b>")]
[InlineData("- item", "• item")]
[InlineData("[docs](https://example.com/a?b=1&c=2)", "<a href=\"https://example.com/a?b=1&amp;c=2\">docs</a>")]
[InlineData("~~gone~~", "<s>gone</s>")]
[InlineData("🆕 Привет \"quoted\" it's", "🆕 Привет \"quoted\" it's")]
public void Markdown_becomes_telegram_html(string markdown, string html) =>
Assert.Equal(html, TelegramFormatter.ToHtml(markdown));
[Fact]
public void Code_blocks_keep_their_content_literal()
{
var html = TelegramFormatter.ToHtml("Run:\n```bash\necho \"<hi>\" **x**\n```\nDone.");
Assert.Equal("Run:\n<pre><code class=\"language-bash\">echo \"&lt;hi&gt;\" **x**</code></pre>\nDone.", html);
}
[Fact]
public void An_unterminated_code_block_while_streaming_is_still_well_formed()
{
Assert.Equal("<pre>partial &lt;</pre>", TelegramFormatter.ToHtml("```\npartial <"));
}
[Fact]
public void Split_prefers_paragraphs_and_reopens_cut_code_blocks()
{
var code = string.Join("\n", Enumerable.Range(0, 40).Select(i => $"line {i}"));
var text = "intro\n\n```python\n" + code + "\n```\nafter";
var chunks = TelegramFormatter.Split(text, limit: 120);
Assert.True(chunks.Count > 2);
Assert.All(chunks, c => Assert.True(c.Length <= 120, $"{c.Length}: {c}"));
Assert.All(chunks, c => Assert.Equal(0, c.Split('\n').Count(l => l.StartsWith("```", StringComparison.Ordinal)) % 2));
Assert.StartsWith("```python\n", chunks[1]);
Assert.Equal(text.Replace("```python\n", "").Replace("```\n", "").Replace("\n", ""),
string.Concat(chunks.Select(c => string.Join("", c.Split('\n').Where(l => !l.StartsWith("```", StringComparison.Ordinal))))));
}
[Fact]
public void Short_text_is_one_chunk() => Assert.Equal(["hi"], TelegramFormatter.Split("hi"));
[Theory]
[InlineData("/stop", "stop", "")]
[InlineData("/resume@my_bot abc", "resume", "abc")]
[InlineData("/Thinking high ", "thinking", "high")]
public void Commands_parse(string text, string name, string args) => Assert.Equal((name, args), ChatCommands.Parse(text));
[Theory]
[InlineData("hello")]
[InlineData("/")]
public void Non_commands_do_not_parse(string text) => Assert.Null(ChatCommands.Parse(text));
[Fact]
public void An_empty_allow_list_is_rejected()
{
var errors = new TelegramOptions { BotToken = "t" }.Validate();
Assert.Contains(errors, e => e.Contains("allowed users", StringComparison.OrdinalIgnoreCase));
}
[Fact]
public void Environment_shortcuts_fill_the_token_and_users()
{
var env = new Dictionary<string, string> { ["TELEGRAM_BOT_TOKEN"] = "123:abc", ["TELEGRAM_ALLOWED_USER_IDS"] = "1, 2;3" };
var options = new TelegramOptions();
options.ApplyEnvironment(k => env.GetValueOrDefault(k));
Assert.Equal("123:abc", options.BotToken);
Assert.Equal([1L, 2L, 3L], options.AllowedUserIds);
Assert.Empty(options.Validate());
Assert.Equal("claude-code/claude-opus-5-5", options.Model);
Assert.True(options.IsAllowed(2));
Assert.False(options.IsAllowed(4));
Assert.False(options.IsAllowed(null));
}
}