Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions ModernUO.Serialization.Generator.Tests/DiagnosticTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public void MarkDirty() { }
}

[Fact]
public void SG3009_StructWithoutDeserialize_ReportsDiagnostic()
public void SG3009_StructWithDeserialize_ReportsDiagnostic()
{
const string source = """
using ModernUO.Serialization;
Expand All @@ -181,10 +181,14 @@ public void SG3009_StructWithoutDeserialize_ReportsDiagnostic()
namespace TestNamespace
{
[SerializationGenerator(0)]
public partial struct MissingDeserializeStruct
public partial struct ConflictingDeserializeStruct
{
[SerializableField(0)]
private int _value;

public void Deserialize(IGenericReader reader)
{
}
}
}
""";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using ModernUO.Serialization.Generator.Tests.Helpers;
using Xunit;

namespace ModernUO.Serialization.Generator.Tests;

public class MigrationFileDiagnosticTests
{
private const string Source = """
using System;
using ModernUO.Serialization;
using Server;

namespace Server.TestContent
{
[SerializationGenerator(1)]
public partial class MigratingItem : ISerializable
{
[SerializableField(0)]
private string _name;

public DateTime Created { get; set; }
public Serial Serial { get; }
public bool Deleted => false;
public void Delete() { }

private void MigrateFrom(V0Content content)
{
_name = content.Name;
}
}
}
""";

private const string MigrationJson = """
{
"version": 0,
"type": "Server.TestContent.MigratingItem",
"properties": [
{
"name": "Name",
"type": "string",
"rule": "PrimitiveTypeMigrationRule"
}
]
}
""";

// Two files with the same class and version (e.g. nested migration folders): only one can
// win, and silently ignoring the other loses data. SG3011 makes the conflict visible.
[Fact]
public void DuplicateMigrationFile_ReportsDiagnostic()
{
var (diagnostics, _) = SourceGeneratorTestHelper.RunGenerator(
Source,
additionalTexts:
[
("a/Server.TestContent.MigratingItem.v0.json", MigrationJson),
("b/Server.TestContent.MigratingItem.v0.json", MigrationJson)
]
);

Assert.True(
SourceGeneratorTestHelper.HasDiagnostic(diagnostics, "SG3011"),
"A duplicate migration file for the same version must be reported."
);
}

// A migration file above the current version is dead data - usually a version that was
// rolled back without deleting the file. The file at the current version is the schema
// record the migration tool maintains and must not be flagged.
[Fact]
public void StaleMigrationFile_ReportsDiagnostic()
{
var currentJson = MigrationJson.Replace("\"version\": 0", "\"version\": 1");
var staleJson = MigrationJson.Replace("\"version\": 0", "\"version\": 2");

var (diagnostics, _) = SourceGeneratorTestHelper.RunGenerator(
Source,
additionalTexts:
[
("Server.TestContent.MigratingItem.v0.json", MigrationJson),
("Server.TestContent.MigratingItem.v1.json", currentJson),
("Server.TestContent.MigratingItem.v2.json", staleJson)
]
);

Assert.Equal(
1,
diagnostics.Count(d => d.Id == "SG3012")
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,40 @@
namespace Server.TestContent
{
[System.CodeDom.Compiler.GeneratedCode("ModernUO.Serialization.Generator", "{VERSION}")]
public partial struct InstanceStruct
public partial class CustomDirtyItem
{
private const int SerializationVersion = 0;

public int Value
public string Name
{
get => _value;
get => _name;
set
{
if (value != _value)
if (value != _name)
{
_value = value;
_name = value;
MarkDirty();
}
}
}

public CustomDirtyItem(Server.Serial serial)
{
Serial = serial;
}

public virtual void Serialize(Server.IGenericWriter writer)
{
writer.WriteEncodedInt(SerializationVersion);

writer.Write(_value);
writer.Write(_name);
}

public virtual void Deserialize(Server.IGenericReader reader)
{
var version = reader.ReadEncodedInt();

_value = reader.ReadInt();
_name = reader.ReadString();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using ModernUO.Serialization;
using Server;

namespace Server.TestContent
{
[SerializationGenerator(0)]
public partial class CustomDirtyItem : ISerializable
{
[SerializableField(0)]
private string _name;

public DateTime Created { get; set; }
public Serial Serial { get; }
public bool Deleted => false;
public void Delete() { }

public void MarkDirty() { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// <auto-generated>
// This code was generated by the ModernUO Serialization Generator tool.
// Version: {VERSION}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>

#pragma warning disable

namespace Server.TestContent
{
[System.CodeDom.Compiler.GeneratedCode("ModernUO.Serialization.Generator", "{VERSION}")]
public partial class KeyValuePairItem
{
private const int SerializationVersion = 0;

public System.Collections.Generic.KeyValuePair<int, string> Selected
{
get => _selected;
set
{
if (!System.Collections.Generic.EqualityComparer<System.Collections.Generic.KeyValuePair<int, string>>.Default.Equals(value, _selected))
{
_selected = value;
Server.ISerializableExtensions.MarkDirty(this);
}
}
}

public KeyValuePairItem(Server.Serial serial)
{
Serial = serial;
}

public virtual void Serialize(Server.IGenericWriter writer)
{
writer.WriteEncodedInt(SerializationVersion);

writer.Write(_selected.Key);
writer.Write(_selected.Value);
}

public virtual void Deserialize(Server.IGenericReader reader)
{
var version = reader.ReadEncodedInt();

int _selectedKey;
string _selectedValue;
_selectedKey = reader.ReadInt();
_selectedValue = reader.ReadString();
_selected = new System.Collections.Generic.KeyValuePair<int, string>(_selectedKey, _selectedValue);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using ModernUO.Serialization;
using Server;

namespace Server.TestContent
{
[SerializationGenerator(0)]
public partial class KeyValuePairItem : ISerializable
{
[SerializableField(0)]
private KeyValuePair<int, string> _selected;

public DateTime Created { get; set; }
public Serial Serial { get; }
public bool Deleted => false;
public void Delete() { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// <auto-generated>
// This code was generated by the ModernUO Serialization Generator tool.
// Version: {VERSION}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>

#pragma warning disable

namespace TestContent
{
[System.CodeDom.Compiler.GeneratedCode("ModernUO.Serialization.Generator", "{VERSION}")]
public partial class ExternalItem
{
private const int SerializationVersion = 1;

public string Name
{
get => _name;
set
{
if (value != _name)
{
_name = value;
Server.ISerializableExtensions.MarkDirty(this);
}
}
}

public Server.Timer RefreshTimer
{
get => _refreshTimer;
set
{
if (value != _refreshTimer)
{
_refreshTimer = value;
Server.ISerializableExtensions.MarkDirty(this);
}
}
}

public ExternalItem(Server.Serial serial)
{
Serial = serial;
}

ref struct V0Content
{
internal readonly string Name;
internal V0Content(Server.IGenericReader reader, TestContent.ExternalItem entity)
{
Name = reader.ReadString();
}
}

public virtual void Serialize(Server.IGenericWriter writer)
{
writer.WriteEncodedInt(SerializationVersion);

writer.Write(_name);

writer.Write(RefreshTimer?.Next ?? System.DateTime.MinValue);
}

public virtual void Deserialize(Server.IGenericReader reader)
{
var version = reader.ReadEncodedInt();

if (version == 0)
{
MigrateFrom(new V0Content(reader, this));
Server.ISerializableExtensions.MarkDirty(this);
return;
}

_name = reader.ReadString();

var RefreshTimerNext = reader.ReadDateTime();
var RefreshTimerDelay = RefreshTimerNext == System.DateTime.MinValue ? System.TimeSpan.MinValue : RefreshTimerNext - Server.Core.Now;
DeserializeRefreshTimer(RefreshTimerDelay);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using ModernUO.Serialization;
using Server;

namespace TestContent
{
[SerializationGenerator(1)]
public partial class ExternalItem : ISerializable
{
[SerializableField(0)]
private string _name;

[SerializableField(1)]
private Timer _refreshTimer;

[DeserializeTimerField(1)]
private void DeserializeRefreshTimer(TimeSpan delay)
{
_refreshTimer = new Timer();
}

public DateTime Created { get; set; }
public Serial Serial { get; }
public bool Deleted => false;
public void Delete() { }

private void MigrateFrom(V0Content content)
{
_name = content.Name;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": 0,
"type": "TestContent.ExternalItem",
"properties": [
{
"name": "Name",
"type": "string",
"rule": "PrimitiveTypeMigrationRule"
}
]
}
Loading
Loading