Cover ungrouped types, null strings, derived globals and id separators
Stryker survivors on the grouping diff: the no-declaration path, the null-string identity, the inherited [CultGlobal] check and the id separator. GroupLevel takes text and tie as optional arguments so the scalar kinds stop passing constant strings that could be swapped without any effect. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
84c9a79972
commit
30e1f3fb95
2 changed files with 42 additions and 7 deletions
|
|
@ -675,11 +675,11 @@ namespace GameCult.Caching
|
|||
return new GroupLevel(identity, label, CreateRecordRef(member.ValueType, identity), rank, 0m, label, identity);
|
||||
case CultInspectorValueKind.Enum:
|
||||
var number = Convert.ToDecimal(Convert.ChangeType(value, Enum.GetUnderlyingType(member.ValueType)), System.Globalization.CultureInfo.InvariantCulture);
|
||||
return new GroupLevel(identity, Enum.GetName(member.ValueType, value!) ?? identity, value, 1, number, string.Empty, string.Empty);
|
||||
return new GroupLevel(identity, Enum.GetName(member.ValueType, value!) ?? identity, value, 1, number);
|
||||
case CultInspectorValueKind.Integer:
|
||||
return new GroupLevel(identity, identity, value, 1, Convert.ToDecimal(value, System.Globalization.CultureInfo.InvariantCulture), string.Empty, string.Empty);
|
||||
return new GroupLevel(identity, identity, value, 1, Convert.ToDecimal(value, System.Globalization.CultureInfo.InvariantCulture));
|
||||
case CultInspectorValueKind.Bool:
|
||||
return new GroupLevel(identity, identity, value, 1, (bool)value! ? 1m : 0m, string.Empty, string.Empty);
|
||||
return new GroupLevel(identity, identity, value, 1, (bool)value! ? 1m : 0m);
|
||||
default:
|
||||
return new GroupLevel(identity, identity.Length == 0 ? "(empty)" : identity, identity, 1, 0m, identity, identity);
|
||||
}
|
||||
|
|
@ -687,7 +687,7 @@ namespace GameCult.Caching
|
|||
|
||||
private sealed class GroupLevel
|
||||
{
|
||||
public GroupLevel(string identity, string label, object? value, int rank, decimal number, string text, string tie)
|
||||
public GroupLevel(string identity, string label, object? value, int rank, decimal number, string text = "", string tie = "")
|
||||
{
|
||||
Identity = identity;
|
||||
Label = label;
|
||||
|
|
|
|||
|
|
@ -519,6 +519,8 @@ namespace GameCult.Caching.Tests
|
|||
using var cache = OpenGroups();
|
||||
await cache.UpsertAsync(typeof(GroupMixed), new GroupMixed { Kind = "x/Count=1/Flag=True" }, new CultRecordKey("a"));
|
||||
await cache.UpsertAsync(typeof(GroupMixed), new GroupMixed { Kind = "x", Count = 1, Flag = true }, new CultRecordKey("b"));
|
||||
await cache.UpsertAsync(typeof(GroupMixed), new GroupMixed { Kind = "aCount0" }, new CultRecordKey("c"));
|
||||
await cache.UpsertAsync(typeof(GroupMixed), new GroupMixed { Kind = "a" }, new CultRecordKey("d"));
|
||||
|
||||
var ids = new List<string>();
|
||||
void Collect(IEnumerable<CultInspectorRecordGroup> groups)
|
||||
|
|
@ -532,8 +534,8 @@ namespace GameCult.Caching.Tests
|
|||
|
||||
Collect(GroupModel().GroupRecords(typeof(GroupMixed), cache.AllStoredDocuments));
|
||||
|
||||
Assert.That(ids, Has.Count.EqualTo(6));
|
||||
Assert.That(ids.Distinct().Count(), Is.EqualTo(6), "a path never spells another node's id");
|
||||
Assert.That(ids, Has.Count.EqualTo(12));
|
||||
Assert.That(ids.Distinct().Count(), Is.EqualTo(12), "a path never spells another node's id");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
@ -593,6 +595,33 @@ namespace GameCult.Caching.Tests
|
|||
Assert.That(notice, Does.Contain("parameterless constructor"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GroupATypeWithoutADeclarationIsNotGrouped()
|
||||
{
|
||||
var model = GroupModel();
|
||||
|
||||
var grouping = model.GroupingOf(typeof(InspectOther));
|
||||
|
||||
Assert.That(grouping.ListedType, Is.EqualTo(typeof(InspectOther)));
|
||||
Assert.That(grouping.Members, Is.Empty);
|
||||
Assert.That(grouping.Notice, Is.Null);
|
||||
Assert.That(model.GroupRecords(typeof(InspectOther), Array.Empty<CultStoredDocument>()), Is.Empty);
|
||||
Assert.That(() => model.GroupingOf(null!), Throws.ArgumentNullException);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GroupANullStringSharesTheEmptyStringsNode()
|
||||
{
|
||||
using var cache = OpenGroups();
|
||||
await cache.UpsertAsync(typeof(GroupMixed), new GroupMixed { Kind = null! }, new CultRecordKey("n"));
|
||||
await cache.UpsertAsync(typeof(GroupMixed), new GroupMixed { Kind = "" }, new CultRecordKey("e"));
|
||||
|
||||
var roots = GroupModel().GroupRecords(typeof(GroupMixed), cache.AllStoredDocuments);
|
||||
|
||||
Assert.That(roots.Select(group => group.Label), Is.EqualTo(new[] { "(empty)" }));
|
||||
Assert.That(roots.Single().Count, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[TestCase(typeof(GroupUnknown), "Nope")]
|
||||
[TestCase(typeof(GroupFloat), "Mass")]
|
||||
[TestCase(typeof(GroupFlagsEnum), "Traits")]
|
||||
|
|
@ -601,6 +630,7 @@ namespace GameCult.Caching.Tests
|
|||
[TestCase(typeof(GroupDuplicate), "Kind")]
|
||||
[TestCase(typeof(GroupValidThenInvalid), "Mass")]
|
||||
[TestCase(typeof(GroupGlobal), "global")]
|
||||
[TestCase(typeof(GroupGlobalChild), "global")]
|
||||
public void GroupInvalidDeclarationsGiveANoticeAndAFlatList(Type listed, string mentions)
|
||||
{
|
||||
var model = GroupModel();
|
||||
|
|
@ -858,12 +888,17 @@ namespace GameCult.Caching.Tests
|
|||
[CultGlobal]
|
||||
[CultDocument("tests.group_global", "tests.group_global.v1")]
|
||||
[MessagePackObject]
|
||||
public sealed class GroupGlobal
|
||||
public class GroupGlobal
|
||||
{
|
||||
[Key(0)]
|
||||
public string Kind = string.Empty;
|
||||
}
|
||||
|
||||
[CultInspectorGroupBy("Kind")]
|
||||
public sealed class GroupGlobalChild : GroupGlobal
|
||||
{
|
||||
}
|
||||
|
||||
[CultInspectorGroupBy("Kind")]
|
||||
[CultDocument("tests.group_no_ctor", "tests.group_no_ctor.v1")]
|
||||
[MessagePackObject]
|
||||
|
|
|
|||
Loading…
Reference in a new issue