165 lines
6.4 KiB
C#
165 lines
6.4 KiB
C#
using HSchool.Content;
|
|
using HSchool.Server.Api;
|
|
using HSchool.Server.Game;
|
|
|
|
namespace HSchool.Server.Tests;
|
|
|
|
public class PortraitPromptBuilderTests
|
|
{
|
|
[Fact]
|
|
public void Build_DescribesAppearanceAndClothingInProse()
|
|
{
|
|
var profile = SamplePreset().ToProfile(PortraitKind.Avatar);
|
|
|
|
var card = SampleCard();
|
|
var (positive, _) = PortraitPromptBuilder.Build(card, profile, PortraitKind.Avatar);
|
|
|
|
Assert.Contains("12 years old", positive, StringComparison.Ordinal);
|
|
Assert.Contains("with black hair", positive, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("wearing a white shirt", positive, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("Head and shoulders.", positive, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("age 12", positive, StringComparison.OrdinalIgnoreCase);
|
|
Assert.DoesNotContain("Hair colour", positive, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("wearing shirt in white", positive, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_FullBody_AddsFullBodyPreset()
|
|
{
|
|
var preset = SamplePreset();
|
|
var (avatarPositive, _) = PortraitPromptBuilder.Build(SampleCard(), preset.ToProfile(PortraitKind.Avatar), PortraitKind.Avatar);
|
|
var (fullPositive, _) = PortraitPromptBuilder.Build(SampleCard(), preset.ToProfile(PortraitKind.Full), PortraitKind.Full);
|
|
|
|
Assert.Contains("Head and shoulders.", avatarPositive, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("Standing full body.", avatarPositive, StringComparison.Ordinal);
|
|
Assert.Contains("Standing full body.", fullPositive, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_Custom_KeepsShotTypeAndAppendsPromptExtra()
|
|
{
|
|
var profile = SamplePreset().ToProfile(PortraitKind.Custom);
|
|
const string extra = "standing in a school hallway, soft window light";
|
|
var (customPositive, _) = PortraitPromptBuilder.Build(
|
|
SampleCard(),
|
|
profile,
|
|
PortraitKind.Custom,
|
|
extra);
|
|
|
|
Assert.Contains("School photo.", customPositive, StringComparison.Ordinal);
|
|
Assert.Contains("Hallway light.", customPositive, StringComparison.Ordinal);
|
|
Assert.Contains(extra, customPositive, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("Head and shoulders.", customPositive, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("Standing full body.", customPositive, StringComparison.Ordinal);
|
|
Assert.True(
|
|
customPositive.IndexOf("Hallway light.", StringComparison.Ordinal)
|
|
< customPositive.IndexOf(extra, StringComparison.Ordinal));
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_OrdersLayers_ModelStyleShotAppearanceClothing()
|
|
{
|
|
var preset = SamplePreset();
|
|
var model = new SwarmUiModelDefinition { Id = preset.Model, Positive = "Model base." };
|
|
var profile = preset.ToProfile(PortraitKind.Avatar, model);
|
|
var (positive, _) = PortraitPromptBuilder.Build(SampleCard(), profile, PortraitKind.Avatar);
|
|
|
|
var modelAt = positive.IndexOf("Model base.", StringComparison.Ordinal);
|
|
var styleAt = positive.IndexOf("School photo.", StringComparison.Ordinal);
|
|
var shotAt = positive.IndexOf("Head and shoulders.", StringComparison.Ordinal);
|
|
var subjectAt = positive.IndexOf("teenage girl", StringComparison.OrdinalIgnoreCase);
|
|
var clothesAt = positive.IndexOf("wearing a white shirt", StringComparison.OrdinalIgnoreCase);
|
|
|
|
Assert.True(modelAt >= 0 && styleAt > modelAt && shotAt > styleAt && subjectAt > shotAt && clothesAt > subjectAt);
|
|
Assert.DoesNotContain("pose", positive, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_ChildAge_UsesChildSubjectDescriptor()
|
|
{
|
|
var profile = SamplePreset().ToProfile(PortraitKind.Avatar);
|
|
var child = SampleCard() with { Age = 8 };
|
|
var (positive, _) = PortraitPromptBuilder.Build(child, profile, PortraitKind.Avatar);
|
|
|
|
Assert.Contains("young girl", positive, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("8 years old", positive, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_TornClothing_PrefixesCondition()
|
|
{
|
|
var profile = SamplePreset().ToProfile(PortraitKind.Avatar);
|
|
var card = SampleCard() with
|
|
{
|
|
Worn =
|
|
[
|
|
new WornItemResponse(
|
|
"Shirt",
|
|
"Shirt",
|
|
"White",
|
|
"White",
|
|
[new DefLabelResponse(ApparelLayers.Top, "Top")],
|
|
0.2f,
|
|
"torn",
|
|
[ApparelLayers.Underwear]),
|
|
],
|
|
};
|
|
var (positive, _) = PortraitPromptBuilder.Build(card, profile, PortraitKind.Avatar);
|
|
|
|
Assert.Contains("wearing a torn white shirt", positive, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private static SwarmUiPresetDefinition SamplePreset()
|
|
{
|
|
var preset = SwarmUiPresetDefinition.CreateDefault();
|
|
preset.Style = "School photo.";
|
|
preset.Avatar = new SwarmUiKindPreset
|
|
{
|
|
Width = 512,
|
|
Height = 512,
|
|
ShotType = "Head and shoulders.",
|
|
};
|
|
preset.Custom = new SwarmUiKindPreset
|
|
{
|
|
Width = 512,
|
|
Height = 768,
|
|
ShotType = "Hallway light.",
|
|
};
|
|
preset.FullBody = new SwarmUiKindPreset
|
|
{
|
|
Width = 512,
|
|
Height = 768,
|
|
ShotType = "Standing full body.",
|
|
};
|
|
return preset;
|
|
}
|
|
|
|
private static PersonCardResponse SampleCard() =>
|
|
new(
|
|
"f0.c0",
|
|
"Maria Ivanova",
|
|
"Ivanova",
|
|
"Maria",
|
|
"",
|
|
true,
|
|
12,
|
|
new DateTime(2000, 3, 14, 0, 0, 0, DateTimeKind.Utc),
|
|
["student"],
|
|
5,
|
|
"A",
|
|
"class-1",
|
|
null,
|
|
null,
|
|
[new LabeledStatResponse("HairColor", "Hair colour", "Black")],
|
|
[],
|
|
[],
|
|
[],
|
|
null,
|
|
null,
|
|
new PersonFamilyResponse([], [], [], []),
|
|
[new WornItemResponse("Shirt", "Shirt", "White", "White", [new DefLabelResponse(ApparelLayers.Top, "Top")], 1f, "new", [ApparelLayers.Underwear])],
|
|
[],
|
|
0f,
|
|
0f);
|
|
}
|