mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-10 23:47:21 +00:00
217 lines
10 KiB
C#
217 lines
10 KiB
C#
using AIStudio.Assistants.BeyondFactsLab;
|
|
|
|
namespace AIStudio.Tests.BeyondFactsLab;
|
|
|
|
/// <summary>
|
|
/// Checks how the BeyondFacts Lab reads a work state which a model wrote as Markdown.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The keys of the sections are stored in every work state, so they are pinned here as well.
|
|
/// </remarks>
|
|
[TestFixture]
|
|
public sealed class BflMarkdownSectionsTests
|
|
{
|
|
[Test]
|
|
public void TheSectionsKeepTheirKeys()
|
|
{
|
|
Assert.That(BflWorkStateSections.SECTIONS.Select(section => $"{section.Step}/{section.Key}"), Is.EqualTo(new[]
|
|
{
|
|
"FRAMEWORK/FORMAT", "FRAMEWORK/AUDIENCE", "FRAMEWORK/SPEAKING_TIME", "FRAMEWORK/PARTICIPANTS", "FRAMEWORK/CONFLICTS", "FRAMEWORK/OPEN_POINTS",
|
|
"KNOWLEDGE/ESTABLISHED", "KNOWLEDGE/UNCERTAINTIES", "KNOWLEDGE/WEAK_POINTS", "KNOWLEDGE/CONTROVERSIES", "KNOWLEDGE/EXPERTISE_LIMITS", "KNOWLEDGE/KEY_MESSAGES", "KNOWLEDGE/OPEN_POINTS",
|
|
"GOALS_AND_ROLE/GOAL", "GOALS_AND_ROLE/ROLE", "GOALS_AND_ROLE/REASONS", "GOALS_AND_ROLE/CONSEQUENCES", "GOALS_AND_ROLE/OPEN_POINTS",
|
|
"VALUES_AND_PERSPECTIVES/VALUES", "VALUES_AND_PERSPECTIVES/VALUE_CONFLICTS", "VALUES_AND_PERSPECTIVES/PERSONAL_INVOLVEMENT", "VALUES_AND_PERSPECTIVES/PERSPECTIVES", "VALUES_AND_PERSPECTIVES/CONSEQUENCES", "VALUES_AND_PERSPECTIVES/OPEN_POINTS",
|
|
"STRATEGY/KEY_MESSAGES", "STRATEGY/STRUCTURE", "STRATEGY/LANGUAGE", "STRATEGY/UNCERTAINTY", "STRATEGY/FRAMING", "STRATEGY/COUNTERARGUMENTS", "STRATEGY/WORRIES", "STRATEGY/OPEN_POINTS",
|
|
"TEST_SITUATION/STRENGTHS", "TEST_SITUATION/PRACTICE", "TEST_SITUATION/HARD_QUESTIONS", "TEST_SITUATION/POSITION", "TEST_SITUATION/OPEN_POINTS",
|
|
"RESULTS/CHANGED", "RESULTS/KEPT", "RESULTS/LEFT_OPEN", "RESULTS/NEXT_STEPS",
|
|
}));
|
|
}
|
|
|
|
[Test]
|
|
public void EveryStepHasSectionsWithUniqueKeysAndTitles()
|
|
{
|
|
foreach (var step in BflStep.All)
|
|
{
|
|
var sections = BflWorkStateSections.ForStep(step);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(sections, Is.Not.Empty, step.ToString());
|
|
Assert.That(sections.Select(section => section.Key), Is.Unique, step.ToString());
|
|
Assert.That(sections.Select(section => section.Title), Is.Unique, step.ToString());
|
|
Assert.That(sections.Select(section => section.Title), Has.None.EqualTo(string.Empty), step.ToString());
|
|
Assert.That(sections.Select(section => section.Description), Has.All.Not.Empty, step.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void OnlyThePersonalInvolvementIsPersonal()
|
|
{
|
|
Assert.That(BflWorkStateSections.SECTIONS.Where(section => section.IsPersonalDisclosure).Select(section => section.Key), Is.EqualTo(new[] { "PERSONAL_INVOLVEMENT" }));
|
|
}
|
|
|
|
[TestCase("## [GOAL] Ziel", TestName = "AHeadingOfTheSecondLevelIsASection")]
|
|
[TestCase("### [GOAL] Ziel", TestName = "AHeadingOfAnotherLevelIsASection")]
|
|
[TestCase("##[GOAL]", TestName = "AHeadingWithoutSpaceAndTitleIsASection")]
|
|
[TestCase("## **[GOAL] Ziel**", TestName = "ABoldHeadingIsASection")]
|
|
[TestCase("## [ goal ] Ziel", TestName = "TheKeyIgnoresCaseAndSpaces")]
|
|
[TestCase(" ## [GOAL] Ziel", TestName = "AnIndentedHeadingIsASection")]
|
|
public void TheHeadingOfASectionMayVary(string heading)
|
|
{
|
|
var answer = Read($"{heading}\nWirksam informieren.\n\n## [ROLE]\nEhrliche Maklerin\n## [REASONS]\n## [CONSEQUENCES]\nKurz fassen.\n## [OPEN_POINTS]\n");
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(answer.Problems, Is.Empty);
|
|
Assert.That(answer.Sections["GOAL"], Is.EqualTo("Wirksam informieren."));
|
|
Assert.That(answer.Sections["ROLE"], Is.EqualTo("Ehrliche Maklerin"));
|
|
Assert.That(answer.Sections["REASONS"], Is.Empty);
|
|
Assert.That(answer.Sections["OPEN_POINTS"], Is.Empty);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TextBeforeTheFirstHeadingAndACodeBlockAroundTheAnswerAreLeftOut()
|
|
{
|
|
var answer = Read("Hier ist der Arbeitsstand:\n```markdown\n## [GOAL] Ziel\nInformieren\n- Punkt eins\n- Punkt zwei\n## [ROLE] Rolle\nMaklerin\n## [REASONS] Gründe\n## [CONSEQUENCES] Folgen\n## [OPEN_POINTS] Offen\nKeine\n```");
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(answer.Problems, Is.Empty);
|
|
Assert.That(answer.Sections["GOAL"], Is.EqualTo("Informieren\n- Punkt eins\n- Punkt zwei"));
|
|
Assert.That(answer.Sections["OPEN_POINTS"], Is.EqualTo("Keine"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void AHeadingWithoutKeyBelongsToTheTextOfItsSection()
|
|
{
|
|
var answer = Read("## [GOAL] Ziel\n### Kurz gesagt\nInformieren\n## [ROLE]\n## [REASONS]\n## [CONSEQUENCES]\n## [OPEN_POINTS]");
|
|
|
|
Assert.That(answer.Sections["GOAL"], Is.EqualTo("### Kurz gesagt\nInformieren"));
|
|
}
|
|
|
|
[Test]
|
|
public void AMissingSectionIsAProblem()
|
|
{
|
|
var answer = Read("## [GOAL]\nInformieren\n## [ROLE]\n## [CONSEQUENCES]\n## [OPEN_POINTS]");
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(answer.Problems, Has.Count.EqualTo(1));
|
|
Assert.That(answer.Problems[0], Does.Contain("[REASONS]"));
|
|
Assert.That(answer.Sections.Keys, Is.EquivalentTo(new[] { "GOAL", "ROLE", "CONSEQUENCES", "OPEN_POINTS" }));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ADuplicateSectionIsAProblemAndTheFirstOneCounts()
|
|
{
|
|
var answer = Read("## [GOAL]\nErstens\n## [GOAL]\nZweitens\n## [ROLE]\n## [REASONS]\n## [CONSEQUENCES]\n## [OPEN_POINTS]");
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(answer.Problems, Has.Count.EqualTo(1));
|
|
Assert.That(answer.Problems[0], Does.Contain("[GOAL]"));
|
|
Assert.That(answer.Sections["GOAL"], Is.EqualTo("Erstens"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void AnUnknownSectionIsAProblem()
|
|
{
|
|
var answer = Read("## [GOAL]\n## [ROLE]\n## [REASONS]\n## [CONSEQUENCES]\n## [OPEN_POINTS]\n## [AUDIENCE] Publikum\nStudierende");
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(answer.Problems, Has.Count.EqualTo(1));
|
|
Assert.That(answer.Problems[0], Does.Contain("[AUDIENCE]"));
|
|
Assert.That(answer.Sections.ContainsKey("AUDIENCE"), Is.False);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void AnAnswerWithoutSectionsIsAProblem()
|
|
{
|
|
var answer = Read("Ich habe leider keine Angaben.");
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(answer.Problems, Has.Count.EqualTo(1));
|
|
Assert.That(answer.Sections, Is.Empty);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ASuggestionForAnEmptyTextFieldIsRead()
|
|
{
|
|
var form = new BflStepFormData();
|
|
form.Set(BflFieldCatalog.FORMAT, "Podium");
|
|
|
|
var answer = BflMarkdownSections.Read(FrameworkWithSuggestions("## [FIELD:audience] Zielgruppe\nSchüler*innen\n## [field:EVENT_LINK]\nhttps://example.org/podium"), BflStep.FRAMEWORK, form);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(answer.Problems, Is.Empty);
|
|
Assert.That(answer.FieldSuggestions, Is.EqualTo(new Dictionary<string, string>
|
|
{
|
|
[BflFieldCatalog.AUDIENCE] = "Schüler*innen",
|
|
[BflFieldCatalog.EVENT_LINK] = "https://example.org/podium",
|
|
}));
|
|
}
|
|
}
|
|
|
|
[TestCase("## [FIELD:format]\nInterview", TestName = "AFieldWhichHoldsAValueGetsNoSuggestion")]
|
|
[TestCase("## [FIELD:unknown_field]\nWert", TestName = "AnUnknownFieldGetsNoSuggestion")]
|
|
[TestCase("## [FIELD:core_theses]\nThese", TestName = "AFieldOfAnotherStepGetsNoSuggestion")]
|
|
[TestCase("## [FIELD:event_link]\nexample.org", TestName = "ALinkWithoutSchemeIsNoSuggestion")]
|
|
[TestCase("## [FIELD:event_link]\njavascript:alert(1)", TestName = "ALinkOfAnotherSchemeIsNoSuggestion")]
|
|
[TestCase("## [FIELD:audience]\nErste Zeile\nZweite Zeile", TestName = "ASingleLineFieldGetsNoSuggestionWithSeveralLines")]
|
|
[TestCase("## [FIELD:audience]\n", TestName = "AnEmptySuggestionIsLeftOut")]
|
|
public void ASuggestionWhichDoesNotFitIsLeftOutWithoutAProblem(string suggestion)
|
|
{
|
|
var form = new BflStepFormData();
|
|
form.Set(BflFieldCatalog.FORMAT, "Podium");
|
|
|
|
var answer = BflMarkdownSections.Read(FrameworkWithSuggestions(suggestion), BflStep.FRAMEWORK, form);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(answer.FieldSuggestions, Is.Empty);
|
|
Assert.That(answer.Problems, Is.Empty);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ASuggestionLongerThanItsFieldIsLeftOut()
|
|
{
|
|
var answer = BflMarkdownSections.Read(FrameworkWithSuggestions($"## [FIELD:audience]\n{new string('x', BflFieldKind.SINGLE_LINE.MaxLength + 1)}"), BflStep.FRAMEWORK, new BflStepFormData());
|
|
|
|
Assert.That(answer.FieldSuggestions, Is.Empty);
|
|
}
|
|
|
|
[Test]
|
|
public void TheFirstSuggestionForAFieldCounts()
|
|
{
|
|
var answer = BflMarkdownSections.Read(FrameworkWithSuggestions("## [FIELD:audience]\nErste\n## [FIELD:audience]\nZweite"), BflStep.FRAMEWORK, new BflStepFormData());
|
|
|
|
Assert.That(answer.FieldSuggestions[BflFieldCatalog.AUDIENCE], Is.EqualTo("Erste"));
|
|
}
|
|
|
|
[Test]
|
|
public void OnlyEmptyTextFieldsWhichAreNotPersonalGetSuggestions()
|
|
{
|
|
var values = BflMarkdownSections.SuggestableFields(BflStep.VALUES_AND_PERSPECTIVES, new BflStepFormData()).Select(field => field.Id);
|
|
var test = BflMarkdownSections.SuggestableFields(BflStep.TEST_SITUATION, new BflStepFormData()).Select(field => field.Id);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(values, Is.EqualTo(new[] { BflFieldCatalog.VALUES_AND_CONCERNS, BflFieldCatalog.OTHER_PERSPECTIVES }));
|
|
Assert.That(test, Is.EqualTo(new[] { BflFieldCatalog.TEST_NOTES }));
|
|
}
|
|
}
|
|
|
|
private static BflWorkStateAnswer Read(string answer) => BflMarkdownSections.Read(answer, BflStep.GOALS_AND_ROLE, new BflStepFormData());
|
|
|
|
private static string FrameworkWithSuggestions(string suggestions) => $"## [FORMAT]\n## [AUDIENCE]\n## [SPEAKING_TIME]\n## [PARTICIPANTS]\n## [CONFLICTS]\n## [OPEN_POINTS]\n{suggestions}";
|
|
} |