Add prototype serialization tests. (#18458)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -40,7 +40,7 @@ public sealed class PrototypeSaveTest
|
||||
[Test]
|
||||
public async Task UninitializedSaveTest()
|
||||
{
|
||||
// Apparently SpawnTest fails to clean up properly. Due to the similarities, I'll assume this also fails.
|
||||
// Apparently SpawnTest fails to clean up properly. Due to the similarities, I'll assume this also fails.
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var server = pairTracker.Pair.Server;
|
||||
|
||||
@@ -190,14 +190,14 @@ public sealed class PrototypeSaveTest
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
private sealed class TestEntityUidContext : ISerializationContext,
|
||||
public sealed class TestEntityUidContext : ISerializationContext,
|
||||
ITypeSerializer<EntityUid, ValueDataNode>
|
||||
{
|
||||
public SerializationManager.SerializerProvider SerializerProvider { get; }
|
||||
public bool WritingReadingPrototypes { get; set; }
|
||||
|
||||
public string WritingComponent = string.Empty;
|
||||
public EntityPrototype Prototype = default!;
|
||||
public EntityPrototype? Prototype;
|
||||
|
||||
public TestEntityUidContext()
|
||||
{
|
||||
@@ -215,7 +215,7 @@ public sealed class PrototypeSaveTest
|
||||
IDependencyCollection dependencies, bool alwaysWrite = false,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
if (WritingComponent != "Transform" && !Prototype.NoSpawn)
|
||||
if (WritingComponent != "Transform" && (Prototype?.NoSpawn == false))
|
||||
{
|
||||
// Maybe this will be necessary in the future, but at the moment it just indicates that there is some
|
||||
// issue, like a non-nullable entityUid data-field. If a component MUST have an entity uid to work with,
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.UnitTesting;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.PrototypeTests;
|
||||
|
||||
public sealed class PrototypeTests
|
||||
{
|
||||
/// <summary>
|
||||
/// This test writes all known prototypes as yaml files, then validates that the result is valid yaml.
|
||||
/// Can help prevent instances where prototypes have bad C# default values.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestAllPrototypesAreSerializable()
|
||||
{
|
||||
await using var pairTracker = await PoolManager.GetServerClient();
|
||||
var context = new PrototypeSaveTest.TestEntityUidContext();
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Validate(pairTracker.Pair.Server, "server", context);
|
||||
|
||||
// TODO fix client serialization
|
||||
//Validate(pairTracker.Pair.Client, "client", context);
|
||||
});
|
||||
await pairTracker.CleanReturnAsync();
|
||||
}
|
||||
|
||||
public void Validate(RobustIntegrationTest.IntegrationInstance instance, string instanceId,
|
||||
PrototypeSaveTest.TestEntityUidContext ctx)
|
||||
{
|
||||
var protoMan = instance.ResolveDependency<IPrototypeManager>();
|
||||
var errors = protoMan.ValidateAllPrototypesSerializable(ctx);
|
||||
|
||||
if (errors.Count == 0)
|
||||
return;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
foreach (var (kind, ids) in errors)
|
||||
{
|
||||
foreach (var (id, nodes) in ids)
|
||||
{
|
||||
var msg = $"Error when validating {instanceId} prototype ({kind.Name}, {id}). Errors: \n";
|
||||
foreach (var errorNode in nodes)
|
||||
{
|
||||
msg += $" - {errorNode.ErrorReason}\n";
|
||||
}
|
||||
Assert.Fail(msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
// TODO: ECS.
|
||||
|
||||
namespace Content.Server.Arcade.SpaceVillain;
|
||||
|
||||
[RegisterComponent]
|
||||
@@ -93,16 +91,7 @@ public sealed class SpaceVillainArcadeComponent : SharedSpaceVillainArcadeCompon
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("possibleRewards", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
|
||||
public List<string> PossibleRewards = new()
|
||||
{
|
||||
"ToyMouse", "ToyAi", "ToyNuke", "ToyAssistant", "ToyGriffin", "ToyHonk", "ToyIan",
|
||||
"ToyMarauder", "ToyMauler", "ToyGygax", "ToyOdysseus", "ToyOwlman", "ToyDeathRipley",
|
||||
"ToyPhazon", "ToyFireRipley", "ToyReticence", "ToyRipley", "ToySeraph", "ToyDurand", "ToySkeleton",
|
||||
"FoamCrossbow", "RevolverCapGun", "PlushieHampter", "PlushieLizard", "PlushieAtmosian", "PlushieSpaceLizard",
|
||||
"PlushieNuke", "PlushieCarp", "PlushieRatvar", "PlushieNar", "PlushieSnake", "Basketball", "Football",
|
||||
"PlushieRouny", "PlushieBee", "PlushieSlime", "BalloonCorgi", "ToySword", "CrayonBox", "BoxDonkSoftBox", "BoxCartridgeCap",
|
||||
"HarmonicaInstrument", "OcarinaInstrument", "RecorderInstrument", "GunpetInstrument", "BirdToyInstrument", "PlushieXeno", "BeachBall"
|
||||
};
|
||||
public List<string> PossibleRewards = new();
|
||||
|
||||
/// <summary>
|
||||
/// The minimum number of prizes the arcade machine can have.
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
using Content.Server.Holiday.Interfaces;
|
||||
|
||||
namespace Content.Server.Holiday.Celebrate
|
||||
{
|
||||
public sealed class DefaultHolidayCelebrate : IHolidayCelebrate
|
||||
{
|
||||
public void Celebrate(HolidayPrototype holiday)
|
||||
{
|
||||
// Nada.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using Content.Server.Holiday.Interfaces;
|
||||
|
||||
namespace Content.Server.Holiday.Greet
|
||||
{
|
||||
[DataDefinition]
|
||||
public sealed class DefaultHolidayGreet : IHolidayGreet
|
||||
{
|
||||
public string Greet(HolidayPrototype holiday)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Server.Holiday.Celebrate;
|
||||
using Content.Server.Holiday.Greet;
|
||||
using Content.Server.Holiday.Interfaces;
|
||||
using Content.Server.Holiday.ShouldCelebrate;
|
||||
@@ -40,7 +39,7 @@ namespace Content.Server.Holiday
|
||||
private readonly IHolidayGreet _greet = new DefaultHolidayGreet();
|
||||
|
||||
[DataField("celebrate")]
|
||||
private readonly IHolidayCelebrate _celebrate = new DefaultHolidayCelebrate();
|
||||
private readonly IHolidayCelebrate? _celebrate = null;
|
||||
|
||||
public bool ShouldCelebrate(DateTime date)
|
||||
{
|
||||
@@ -57,7 +56,7 @@ namespace Content.Server.Holiday
|
||||
/// </summary>
|
||||
public void Celebrate()
|
||||
{
|
||||
_celebrate.Celebrate(this);
|
||||
_celebrate?.Celebrate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using Content.Server.Holiday.Interfaces;
|
||||
|
||||
namespace Content.Server.Holiday.ShouldCelebrate
|
||||
{
|
||||
[Virtual]
|
||||
[Virtual, DataDefinition]
|
||||
public class DefaultHolidayShouldCelebrate : IHolidayShouldCelebrate
|
||||
{
|
||||
public virtual bool ShouldCelebrate(DateTime date, HolidayPrototype holiday)
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Nutrition;
|
||||
using Microsoft.VisualBasic;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -102,9 +103,8 @@ public sealed class FlavorProfileSystem : EntitySystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var flavor = proto.Flavor;
|
||||
|
||||
flavors.Add(flavor);
|
||||
if (proto.Flavor != null)
|
||||
flavors.Add(proto.Flavor);
|
||||
}
|
||||
|
||||
return flavors;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Alert
|
||||
{
|
||||
@@ -14,22 +16,25 @@ namespace Content.Shared.Alert
|
||||
public string ID { get; } = default!;
|
||||
|
||||
[DataField("order")]
|
||||
private List<(string type, string alert)> Order
|
||||
private (string type, string alert)[] Order
|
||||
{
|
||||
// why would paul do this to me.
|
||||
get
|
||||
{
|
||||
var res = new List<(string, string)>(_typeToIdx.Count + _categoryToIdx.Count);
|
||||
var res = new (string, string)[_typeToIdx.Count + _categoryToIdx.Count];
|
||||
|
||||
foreach (var (type, id) in _typeToIdx)
|
||||
{
|
||||
res.Insert(id, ("alertType", type.ToString()));
|
||||
res[id] = ("alertType", type.ToString());
|
||||
}
|
||||
|
||||
foreach (var (category, id) in _categoryToIdx)
|
||||
{
|
||||
res.Insert(id, ("category", category.ToString()));
|
||||
res[id] = ("category", category.ToString());
|
||||
}
|
||||
|
||||
DebugTools.Assert(res.All(x => x != default));
|
||||
|
||||
return res;
|
||||
}
|
||||
set
|
||||
|
||||
@@ -19,6 +19,7 @@ public sealed class BodyPrototypeSerializer : ITypeReader<BodyPrototype, Mapping
|
||||
{
|
||||
var nodes = new List<ValidationNode>();
|
||||
var prototypes = dependencies.Resolve<IPrototypeManager>();
|
||||
var factory = dependencies.Resolve<IComponentFactory>();
|
||||
|
||||
var connections = new List<string>();
|
||||
if (slot.TryGet("connections", out SequenceDataNode? connectionsNode))
|
||||
@@ -57,7 +58,7 @@ public sealed class BodyPrototypeSerializer : ITypeReader<BodyPrototype, Mapping
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!organPrototype.HasComponent<OrganComponent>())
|
||||
if (!organPrototype.HasComponent<OrganComponent>(factory))
|
||||
{
|
||||
nodes.Add(new ErrorNode(value, $"Organ {organ.Value} does not have a body component"));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reaction;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Nutrition;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -60,8 +61,8 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
[DataField("recognizable")]
|
||||
public bool Recognizable = false;
|
||||
|
||||
[DataField("flavor")]
|
||||
public string Flavor { get; } = default!;
|
||||
[DataField("flavor", customTypeSerializer:typeof(PrototypeIdSerializer<FlavorPrototype>))]
|
||||
public string? Flavor;
|
||||
|
||||
/// <summary>
|
||||
/// There must be at least this much quantity in a solution to be tasted.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Nutrition;
|
||||
namespace Content.Shared.Nutrition;
|
||||
|
||||
[Prototype("flavor")]
|
||||
public sealed class FlavorPrototype : IPrototype
|
||||
@@ -261,7 +261,7 @@
|
||||
- type: FlavorProfile
|
||||
flavors:
|
||||
- meaty
|
||||
- acidic
|
||||
- acid
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: tin
|
||||
@@ -277,7 +277,7 @@
|
||||
- type: FlavorProfile
|
||||
flavors:
|
||||
- meaty
|
||||
- acidic
|
||||
- acid
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: plate-small
|
||||
|
||||
@@ -797,7 +797,7 @@
|
||||
flavors:
|
||||
- bun
|
||||
- meaty
|
||||
- acidic
|
||||
- acid
|
||||
- type: Sprite
|
||||
state: x
|
||||
- type: SolutionContainerManager
|
||||
|
||||
@@ -489,7 +489,7 @@
|
||||
- type: FlavorProfile
|
||||
flavors:
|
||||
- meaty
|
||||
- acidic
|
||||
- acid
|
||||
- type: Tag
|
||||
tags:
|
||||
- Raw
|
||||
@@ -1080,7 +1080,7 @@
|
||||
- type: FlavorProfile
|
||||
flavors:
|
||||
- meaty
|
||||
- acidic
|
||||
- acid
|
||||
- type: Tag
|
||||
tags:
|
||||
- Raw
|
||||
|
||||
@@ -35,6 +35,54 @@
|
||||
components:
|
||||
- type: SpaceVillainArcade
|
||||
rewardAmount: 0
|
||||
possibleRewards:
|
||||
- ToyMouse
|
||||
- ToyAi
|
||||
- ToyNuke
|
||||
- ToyGriffin
|
||||
- ToyHonk
|
||||
- ToyIan
|
||||
- ToyMarauder
|
||||
- ToyMauler
|
||||
- ToyGygax
|
||||
- ToyOdysseus
|
||||
- ToyOwlman
|
||||
- ToyDeathRipley
|
||||
- ToyPhazon
|
||||
- ToyFireRipley
|
||||
- ToyReticence
|
||||
- ToyRipley
|
||||
- ToySeraph
|
||||
- ToyDurand
|
||||
- ToySkeleton
|
||||
- FoamCrossbow
|
||||
- RevolverCapGun
|
||||
- PlushieHampter
|
||||
- PlushieLizard
|
||||
- PlushieAtmosian
|
||||
- PlushieSpaceLizard
|
||||
- PlushieNuke
|
||||
- PlushieCarp
|
||||
- PlushieRatvar
|
||||
- PlushieNar
|
||||
- PlushieSnake
|
||||
- Basketball
|
||||
- Football
|
||||
- PlushieRouny
|
||||
- PlushieBee
|
||||
- PlushieSlime
|
||||
- BalloonCorgi
|
||||
- ToySword
|
||||
- CrayonBox
|
||||
- BoxDonkSoftBox
|
||||
- BoxCartridgeCap
|
||||
- HarmonicaInstrument
|
||||
- OcarinaInstrument
|
||||
- RecorderInstrument
|
||||
- GunpetInstrument
|
||||
- BirdToyInstrument
|
||||
- PlushieXeno
|
||||
- BeachBall
|
||||
- type: WiresPanel
|
||||
- type: Wires
|
||||
LayoutId: Arcade
|
||||
|
||||
@@ -73,7 +73,8 @@
|
||||
group: Foods
|
||||
desc: reagent-desc-ketchunaise
|
||||
physicalDesc: reagent-physical-desc-saucey
|
||||
flavor: piquant
|
||||
#I love it when people just make up fake prototypes.
|
||||
#flavor: piquant
|
||||
color: "#fba399"
|
||||
recognizable: true
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
group: Toxins
|
||||
desc: reagent-desc-polytrinic-acid
|
||||
physicalDesc: reagent-physical-desc-strong-smelling
|
||||
flavor: acidic
|
||||
flavor: acid
|
||||
color: "#a1000b"
|
||||
boilingPoint: 78.2 # This isn't a real chemical...
|
||||
meltingPoint: -19.4
|
||||
@@ -143,7 +143,7 @@
|
||||
group: Toxins
|
||||
desc: reagent-desc-fluorosulfuric-acid
|
||||
physicalDesc: reagent-physical-desc-strong-smelling
|
||||
flavor: acidic
|
||||
flavor: acid
|
||||
color: "#5050ff"
|
||||
boilingPoint: 165
|
||||
meltingPoint: -87
|
||||
@@ -179,7 +179,7 @@
|
||||
group: Toxins
|
||||
desc: reagent-desc-sulfuric-acid
|
||||
physicalDesc: reagent-physical-desc-oily
|
||||
flavor: acidic
|
||||
flavor: acid
|
||||
color: "#BF8C00"
|
||||
recognizable: true
|
||||
boilingPoint: 337.0
|
||||
|
||||
Reference in New Issue
Block a user