Fixed the Batch Processing assistant with an output folder above the input folder (#1098)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-10-21 15:51:22 +02:00
1 parent 7fbb894d5b
commit 1c8632bbe0
5 files changed
+260 -45

No files matched your search

@@ -0,0 +1,165 @@
using AIStudio.Assistants.BatchProcessing;
namespace AIStudio.Tests.Assistants;
/// <summary>
/// Checks which files the search of the batch processing assistant leaves out because a batch run
/// wrote them.
/// </summary>
/// <remarks>
/// A run writes everything directly into its output folder. The search comes across any of it only
/// when that folder lies below the input folder or is the input folder itself. An output folder
/// above the input folder once made the search leave out every document.
/// </remarks>
[TestFixture]
public sealed class BatchProcessingOutputFolderTests
{
private const string RESULTS_FILE_NAME = "batch-results.csv";
private static readonly string DESKTOP = Path.Combine(Path.GetTempPath(), "ai-studio-batch-output-folder", "Desktop");
private static readonly string PROJECT_FOLDER = Path.Combine(DESKTOP, "Batch");
private static readonly string INPUT_FOLDER = Path.Combine(PROJECT_FOLDER, "Documents");
[Test]
public void AnOutputFolderAboveTheInputFolderLeavesOutNoDocument()
{
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, PROJECT_FOLDER, RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report.pdf")), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "notes", "minutes.md")), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "log.csv")), Is.False, "The log of a run lies in the output folder, so a file of this name in the input folder is a document.");
Assert.That(outputFolder.Enters(Path.Combine(INPUT_FOLDER, "notes")), Is.True);
});
}
[Test]
public void AnOutputFolderSeveralLevelsAboveTheInputFolderLeavesOutNoDocument()
{
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, DESKTOP, RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report.pdf")), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "notes", "minutes.md")), Is.False);
Assert.That(outputFolder.Enters(Path.Combine(INPUT_FOLDER, "notes")), Is.True);
});
}
[Test]
public void TheDefaultOutputFolderBelowTheInputFolderIsLeftOut()
{
var resultsFolder = Path.Combine(INPUT_FOLDER, "ai-results");
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, resultsFolder, RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(resultsFolder, "report_result.md")), Is.True);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report.pdf")), Is.False);
Assert.That(outputFolder.Enters(resultsFolder), Is.False);
Assert.That(outputFolder.Enters(Path.Combine(INPUT_FOLDER, "notes")), Is.True);
});
}
[Test]
public void AnOutputFolderDeepBelowTheInputFolderIsLeftOutAlone()
{
var parentFolder = Path.Combine(INPUT_FOLDER, "2026", "october");
var resultsFolder = Path.Combine(parentFolder, "results");
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, resultsFolder, RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(resultsFolder, "report_result.md")), Is.True);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(parentFolder, "report.pdf")), Is.False);
Assert.That(outputFolder.Enters(Path.Combine(INPUT_FOLDER, "2026")), Is.True);
Assert.That(outputFolder.Enters(parentFolder), Is.True);
Assert.That(outputFolder.Enters(resultsFolder), Is.False);
});
}
[Test]
public void ADocumentWhoseNameBeginsLikeTheOutputFolderIsNoOutput()
{
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, Path.Combine(INPUT_FOLDER, "out"), RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "output-notes.md")), Is.False);
Assert.That(outputFolder.Enters(Path.Combine(INPUT_FOLDER, "output")), Is.True);
});
}
[Test]
public void AnOutputFolderNextToTheInputFolderWithTheSameBeginningLeavesOutNothing()
{
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, $"{INPUT_FOLDER}-results", RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report.pdf")), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "log.csv")), Is.False);
Assert.That(outputFolder.Enters(Path.Combine(INPUT_FOLDER, "notes")), Is.True);
});
}
[TestCase(false)]
[TestCase(true)]
public void TheInputFolderAsOutputFolderLeavesOutTheLogAndTheResultsTable(bool withTrailingSeparator)
{
var outputDirectory = withTrailingSeparator ? INPUT_FOLDER + Path.DirectorySeparatorChar : INPUT_FOLDER;
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, outputDirectory, RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "log.csv")), Is.True);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, RESULTS_FILE_NAME)), Is.True);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report.pdf")), Is.False);
Assert.That(outputFolder.Enters(Path.Combine(INPUT_FOLDER, "notes")), Is.True, "Leaving out the output folder would leave out the input folder, too.");
});
}
[Test]
public void TheInputFolderAsOutputFolderLeavesOutTheResultFilesOfEveryFormat()
{
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, INPUT_FOLDER, RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report_result.md")), Is.True);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report_result_2.docx")), Is.True, "A second result of the same name gets a counter.");
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "Report_Result.HTML")), Is.True);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report.v2_result.md")), Is.True, "Only the last extension of the document makes way for the suffix.");
});
}
[Test]
public void TheInputFolderAsOutputFolderKeepsDocumentsWithSimilarNames()
{
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, INPUT_FOLDER, RESULTS_FILE_NAME);
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report.md")), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "result.md")), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "my_results.md")), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report_result_draft.md")), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(INPUT_FOLDER, "report_result_.md")), Is.False);
});
}
[Test]
public void TheInputFolderAsOutputFolderKeepsFilesInSubfolders()
{
var outputFolder = new BatchProcessingOutputFolder(INPUT_FOLDER, INPUT_FOLDER, RESULTS_FILE_NAME);
var subfolder = Path.Combine(INPUT_FOLDER, "notes");
Assert.Multiple(() =>
{
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(subfolder, "log.csv")), Is.False, "A run writes into the output folder itself, never into one of its subfolders.");
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(subfolder, RESULTS_FILE_NAME)), Is.False);
Assert.That(outputFolder.IsOutputOfRun(Path.Combine(subfolder, "report_result.md")), Is.False);
});
}
}