using System.Text.Json.Nodes;
using Deal.Ai.Llm;
namespace Deal.Ai.Tests.Support;
///
/// Unit-тесты извлечения JSON из ответа модели
///
public sealed class JsonExtractorTests
{
///
/// Чистая JSON-строка объекта разбирается как есть.
///
[Fact]
public void TryExtractObject_PlainObject_Parses()
{
JsonObject? json = JsonExtractor.TryExtractObject("""{"pass": true, "reason": "ок"}""");
Assert.NotNull(json);
Assert.True((bool)json!["pass"]!);
}
///
/// Markdown-обёртка ```json снимается
///
[Fact]
public void TryExtractObject_JsonFence_Unwraps()
{
JsonObject? json = JsonExtractor.TryExtractObject("```json\n{\"fit\": 1}\n```");
Assert.NotNull(json);
Assert.Equal(1, (int)json!["fit"]!);
}
///
/// Обёртка без метки языка и с прозой вокруг — тоже снимается.
///
[Fact]
public void TryExtractObject_PlainFenceWithProse_Unwraps()
{
const string answer = "Вот результат:\n```\n{\"keywords\": [\"php\"]}\n```\nНадеюсь, поможет.";
JsonObject? json = JsonExtractor.TryExtractObject(answer);
Assert.NotNull(json);
Assert.Single((JsonArray)json!["keywords"]!);
}
///
/// JSON внутри произвольного текста берётся срезом между первой «{» и последней «}».
///
[Fact]
public void TryExtractObject_JsonInsideProse_Slices()
{
JsonObject? json = JsonExtractor.TryExtractObject("модель решила: {\"pass\": false} конец");
Assert.NotNull(json);
Assert.False((bool)json!["pass"]!);
}
///
/// Текст без JSON — null
///
[Fact]
public void TryExtractObject_NoJson_ReturnsNull()
{
Assert.Null(JsonExtractor.TryExtractObject("извините, не могу ответить"));
}
///
/// Незакрытая обёртка и битый JSON — null, а не исключение.
///
[Fact]
public void TryExtractObject_BrokenJson_ReturnsNull()
{
Assert.Null(JsonExtractor.TryExtractObject("```json\n{\"pass\": tru"));
Assert.Null(JsonExtractor.TryExtractObject("{\"pass\": "));
}
///
/// JSON верхнего уровня не объект
///
[Fact]
public void TryExtractObject_NonObjectRoot_ReturnsNull()
{
Assert.Null(JsonExtractor.TryExtractObject("[\"php\", \"c#\"]"));
Assert.Null(JsonExtractor.TryExtractObject("\"просто строка\""));
}
///
/// Пустой/пробельный текст — null.
///
[Fact]
public void TryExtractObject_Empty_ReturnsNull()
{
Assert.Null(JsonExtractor.TryExtractObject(string.Empty));
Assert.Null(JsonExtractor.TryExtractObject(" "));
}
}