mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-13 19:47:22 +00:00
Added an analyzer which keeps line breaks LF on every system (#1193)
This commit is contained in:
1 parent
b1c1f13993
commit
65d50de033
96 files changed
+741
-393
No files matched your search
@@ -78,5 +78,5 @@ public sealed class AIGeneratedContentDisclosureServiceTests
|
||||
|
||||
private static SettingsManager CreateSettingsManager() => new(NullLogger<SettingsManager>.Instance, null!);
|
||||
|
||||
private static string Lines(params string[] lines) => string.Join(Environment.NewLine, lines);
|
||||
private static string Lines(params string[] lines) => string.Join('\n', lines);
|
||||
}
|
||||
@@ -99,8 +99,8 @@ public sealed class ClassicRagPassagesTests
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(augmentation.UsedContexts.Select(context => context.Context), Is.EqualTo(new IRetrievalContext[] { handbook, manual }), "Without the check, the AI receives every context, in the order it was retrieved.");
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.Contain($"# Retrieval context 1 of 2{Environment.NewLine}"));
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.Contain($"# Retrieval context 2 of 2{Environment.NewLine}"));
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.Contain("# Retrieval context 1 of 2\n"));
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.Contain("# Retrieval context 2 of 2\n"));
|
||||
Assert.That(this.runtime.FilteredBatches, Has.Count.EqualTo(1), "All contexts are filtered together, in one request.");
|
||||
Assert.That(this.runtime.FilteredTexts, Has.Count.EqualTo(4), "Each description and each matched text is filtered once, and nothing a second time on its own.");
|
||||
}
|
||||
@@ -124,9 +124,9 @@ public sealed class ClassicRagPassagesTests
|
||||
{
|
||||
Assert.That(augmentation.UsedContexts.Select(context => context.Context), Is.EqualTo(new IRetrievalContext[] { handbookIntroduction, manual }), "The best passage of each data source fits; the second best of the handbook does not.");
|
||||
Assert.That(augmentation.PassageCounts, Is.EqualTo(new[] { 1, 1 }));
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.Contain($"# Retrieval context 2 of 2{Environment.NewLine}"));
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.Contain("# Retrieval context 2 of 2\n"));
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.Not.Contain("The results of the handbook."));
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.EndWith($"1 did not fit into this request and was left out. An answer based on the data sources may therefore be incomplete.{Environment.NewLine}"), "The model learns that it did not read everything the search found.");
|
||||
Assert.That(augmentation.ChatThread.AugmentedData, Does.EndWith("1 did not fit into this request and was left out. An answer based on the data sources may therefore be incomplete.\n"), "The model learns that it did not read everything the search found.");
|
||||
Assert.That(warnings.Messages, Has.Count.EqualTo(1));
|
||||
Assert.That(warnings.Messages.SingleOrDefault(), Does.Contain("had to do without 1 of them"), "The user learns about it with the answer.");
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ public sealed class FileExportFormatTests
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(found, Is.True);
|
||||
Assert.That(comment.Split(Environment.NewLine), Is.EqualTo(new[] { "% # Sources", "%", "% - [1] A title with 100 % and a_b" }), "LaTeX has no end of a comment, only the end of a line.");
|
||||
Assert.That(comment.Split('\n'), Is.EqualTo(new[] { "% # Sources", "%", "% - [1] A title with 100 % and a_b" }), "LaTeX has no end of a comment, only the end of a line.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,5 +177,5 @@ public sealed class FileExportFormatTests
|
||||
}
|
||||
}
|
||||
|
||||
private static string Lines(params string[] lines) => string.Join(Environment.NewLine, lines);
|
||||
private static string Lines(params string[] lines) => string.Join('\n', lines);
|
||||
}
|
||||
@@ -93,5 +93,5 @@ public sealed class MarkdownTests
|
||||
Assert.That(Markdown.AppendBlock(string.Empty, "**Notice**"), Is.EqualTo("**Notice**"), "With nothing above it, a blank line would only start the text with an empty line.");
|
||||
}
|
||||
|
||||
private static string Lines(params string[] lines) => string.Join(Environment.NewLine, lines);
|
||||
private static string Lines(params string[] lines) => string.Join('\n', lines);
|
||||
}
|
||||
@@ -268,7 +268,7 @@ public sealed class PlainFileExportTests
|
||||
"```");
|
||||
|
||||
var files = PlainFileExport.ExtractFiles(MarkdownRenderPlanner.Build(answer), ',');
|
||||
var partStart = answer.LastIndexOf("$$", StringComparison.Ordinal) + "$$".Length + Environment.NewLine.Length;
|
||||
var partStart = answer.LastIndexOf("$$", StringComparison.Ordinal) + "$$\n".Length;
|
||||
var part = Markdig.Markdown.Parse(answer[partStart..], Markdown.CHAT_MARKDOWN_PIPELINE);
|
||||
var blockOfThePart = part.Descendants<FencedCodeBlock>().Single();
|
||||
|
||||
@@ -280,7 +280,19 @@ public sealed class PlainFileExportTests
|
||||
}
|
||||
}
|
||||
|
||||
private static string Lines(params string[] lines) => string.Join(Environment.NewLine, lines);
|
||||
[Test]
|
||||
public void EveryRowOfATableEndsWithCrLfAsCsvAsksFor()
|
||||
{
|
||||
var files = PlainFileExport.ExtractFiles(MarkdownRenderPlanner.Build(Lines("| Quarter | Revenue |", "|---|---|", "| Q1 | 100 |")), ',');
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(files, Has.Count.EqualTo(1));
|
||||
Assert.That(files.FirstOrDefault()?.Content, Is.EqualTo("Quarter,Revenue\r\nQ1,100\r\n"), "RFC 4180 ends every row with CR LF, on every system.");
|
||||
}
|
||||
}
|
||||
|
||||
private static string Lines(params string[] lines) => string.Join('\n', lines);
|
||||
|
||||
/// <summary>
|
||||
/// Reads a file from the fixtures next to this test.
|
||||
|
||||
@@ -9,6 +9,8 @@ using AIStudio.Tools.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
using SharedTools.Text;
|
||||
|
||||
namespace AIStudio.Tests.Tools.PluginSystem;
|
||||
|
||||
/// <summary>
|
||||
@@ -204,7 +206,7 @@ public sealed class ManagedSettingsCoverageTests
|
||||
""");
|
||||
|
||||
foreach (var setting in ManagedConfiguration.RegisteredSettings)
|
||||
code.AppendLine($"""CONFIG["SETTINGS"]["{setting.SettingName}"] = {ToLuaValue(setting)}""");
|
||||
code.AppendLineLF($"""CONFIG["SETTINGS"]["{setting.SettingName}"] = {ToLuaValue(setting)}""");
|
||||
|
||||
var plugin = await PluginFactory.Load(null, code.ToString());
|
||||
if (plugin is not PluginConfiguration { IsValid: true } configurationPlugin)
|
||||
|
||||
@@ -89,7 +89,7 @@ public sealed class RelativeDataPathsMigrationTests
|
||||
Directory.CreateDirectory(transcriptDirectory);
|
||||
|
||||
var transcriptPath = Path.Combine(transcriptDirectory, "meeting-transcript-0001.md");
|
||||
File.WriteAllText(transcriptPath, $"# Transcription: meeting.mp4{Environment.NewLine}{Environment.NewLine}Hello and welcome.");
|
||||
File.WriteAllText(transcriptPath, $"# Transcription: meeting.mp4\n\nHello and welcome.");
|
||||
var transcript = new ManagedTranscriptAttachment("meeting-transcript-0001.md", transcriptPath, new FileInfo(transcriptPath).Length, "meeting.mp4", false);
|
||||
|
||||
var chat = new ChatThread
|
||||
|
||||
@@ -9,6 +9,8 @@ using AIStudio.Tools.Services;
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
using SharedTools.Text;
|
||||
|
||||
namespace AIStudio.Tests.Tools;
|
||||
|
||||
/// <summary>
|
||||
@@ -87,7 +89,7 @@ public sealed class RetrievalContextPreparationTests
|
||||
"",
|
||||
];
|
||||
|
||||
Assert.That(prepared.Single().ToMarkdown(2, 5), Is.EqualTo(string.Join(Environment.NewLine, expectedLines) + Environment.NewLine), "The model reads the passages in a layout it was prompted for, so preparing them must not change it.");
|
||||
Assert.That(prepared.Single().ToMarkdown(2, 5), Is.EqualTo(string.Join('\n', expectedLines) + "\n"), "The model reads the passages in a layout it was prompted for, so preparing them must not change it.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -97,9 +99,9 @@ public sealed class RetrievalContextPreparationTests
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(prepared.ToMarkdown(3), Does.StartWith($"# Retrieval context 3{Environment.NewLine}Data source name:"), "Semantic Search numbers its passages without knowing how many fit its budget.");
|
||||
Assert.That(prepared.ToMarkdown(), Does.StartWith($"# Retrieval context{Environment.NewLine}Data source name:"), "A context standing alone has no number.");
|
||||
Assert.That(prepared.ToMarkdown(2, 5), Is.EqualTo($"# Retrieval context 2 of 5{Environment.NewLine}{prepared.Body}{Environment.NewLine}"), "Below its header, a context is its body.");
|
||||
Assert.That(prepared.ToMarkdown(3), Does.StartWith("# Retrieval context 3\nData source name:"), "Semantic Search numbers its passages without knowing how many fit its budget.");
|
||||
Assert.That(prepared.ToMarkdown(), Does.StartWith("# Retrieval context\nData source name:"), "A context standing alone has no number.");
|
||||
Assert.That(prepared.ToMarkdown(2, 5), Is.EqualTo($"# Retrieval context 2 of 5\n{prepared.Body}\n"), "Below its header, a context is its body.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,10 +121,10 @@ public sealed class RetrievalContextPreparationTests
|
||||
var prepared = (await this.PrepareAsync(image)).Single();
|
||||
|
||||
var expected = new StringBuilder();
|
||||
expected.AppendLine("# Retrieval context");
|
||||
expected.AppendLineLF("# Retrieval context");
|
||||
RetrievalContextExtensions.AppendContextDescription(expected, image);
|
||||
RetrievalContextExtensions.AppendImageMatch(expected);
|
||||
expected.AppendLine();
|
||||
expected.AppendLineLF();
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
|
||||
@@ -296,7 +296,7 @@ public sealed class SourceExtensionsTests
|
||||
/// <param name="markdown">The Markdown of the sources.</param>
|
||||
/// <returns>The entries, in the order they stand in.</returns>
|
||||
private static IReadOnlyList<string> EntriesOf(string markdown) => markdown
|
||||
.Split(Environment.NewLine, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
|
||||
.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(line => line.StartsWith("- [", StringComparison.Ordinal))
|
||||
.ToList();
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
using SharedTools;
|
||||
using SharedTools.Text;
|
||||
|
||||
namespace AIStudio.Tests.Tools;
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ public sealed class SearchMailsToolTests : ToolRegistryTestBase
|
||||
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
Assert.That(function.DescriptionForLLM, Does.Contain($"- id={WORK.Id}, name='Work'{Environment.NewLine}"));
|
||||
Assert.That(function.DescriptionForLLM, Does.Contain($"- id={WORK.Id}, name='Work'\n"));
|
||||
Assert.That(function.DescriptionForLLM, Does.EndWith($"- id={PRIVATE.Id}, name='Private'"));
|
||||
Assert.That(function.DescriptionForLLM, Does.Not.Contain("per page").And.Not.Contain("last page"), "How many mails a page holds depends on how long they are, so each result tells whether a further page holds more.");
|
||||
Assert.That(properties[MailToolArguments.MAILBOX_IDS_ARGUMENT]!["items"]!["enum"]!.AsArray().Select(id => id!.GetValue<string>()), Is.EqualTo(new[] { WORK.Id, PRIVATE.Id }));
|
||||
|
||||
@@ -132,7 +132,7 @@ public sealed partial class SemanticSearchToolPagingTests
|
||||
{
|
||||
var result = await this.SearchAsync([HANDBOOK], 2, Found(Passages(1, 10, LONG)));
|
||||
|
||||
Assert.That(result.TextContent, Does.StartWith($"# Retrieval context 4{Environment.NewLine}"), "The model reads the fourth passage of the search, not the first one a second time.");
|
||||
Assert.That(result.TextContent, Does.StartWith("# Retrieval context 4\n"), "The model reads the fourth passage of the search, not the first one a second time.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -230,7 +230,7 @@ public sealed partial class SemanticSearchToolPagingTests
|
||||
Assert.That(shown.Text, Is.EqualTo(passage.MatchedText), "The matched text is what the search found, so it is the last to be shortened.");
|
||||
Assert.That(shown.SurroundingContent[0], Is.EqualTo(passage.SurroundingContent[0]));
|
||||
Assert.That(shown.SurroundingContent[^1], Does.StartWith("After ").And.Length.LessThan(LENGTH), "The surrounding content is shortened from its end.");
|
||||
Assert.That(result.TextContent, Does.Contain($"Matched text content:{Environment.NewLine}").And.Contain("Surrounding text content, shortened to fit the size limit:"));
|
||||
Assert.That(result.TextContent, Does.Contain("Matched text content:\n").And.Contain("Surrounding text content, shortened to fit the size limit:"));
|
||||
Assert.That(result.TextContent.Length, Is.LessThanOrEqualTo(SemanticSearchTool.MAX_RESULT_CHARACTERS));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public sealed class SemanticSearchToolRequestTests
|
||||
[Test]
|
||||
public void AQueryOfSeveralLinesIsRefused()
|
||||
{
|
||||
var message = Refusal(() => SemanticSearchTool.ReadRequest(Query($"travel expenses{Environment.NewLine}hotels"), OFFERED));
|
||||
var message = Refusal(() => SemanticSearchTool.ReadRequest(Query("travel expenses\nhotels"), OFFERED));
|
||||
Assert.That(message, Does.Contain("'query'").And.Contain("single line"));
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ public sealed class WorkspaceChatCopyTests
|
||||
Directory.CreateDirectory(transcriptDirectory);
|
||||
|
||||
var path = Path.Combine(transcriptDirectory, $"{stem}-transcript-0001.md");
|
||||
File.WriteAllText(path, $"# Transcription: {stem}.mp4{Environment.NewLine}{Environment.NewLine}Hello and welcome.");
|
||||
File.WriteAllText(path, $"# Transcription: {stem}.mp4\n\nHello and welcome.");
|
||||
return new ManagedTranscriptAttachment(Path.GetFileName(path), path, new FileInfo(path).Length, $"{stem}.mp4", false);
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ public sealed class WorkspaceChatMoveTests
|
||||
|
||||
var fileName = $"{stem}-transcript-{number:D4}.md";
|
||||
var path = Path.Combine(transcriptDirectory, fileName);
|
||||
File.WriteAllText(path, $"# Transcription: {stem}.mp4{Environment.NewLine}{Environment.NewLine}Hello and welcome.");
|
||||
File.WriteAllText(path, $"# Transcription: {stem}.mp4\n\nHello and welcome.");
|
||||
return new ManagedTranscriptAttachment(fileName, path, new FileInfo(path).Length, $"{stem}.mp4", false);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user