diff --git a/Source/SmartMigrations/MigrationAttribute.cs b/Source/SmartMigrations/MigrationAttribute.cs
index ff244e1..472c8e8 100644
--- a/Source/SmartMigrations/MigrationAttribute.cs
+++ b/Source/SmartMigrations/MigrationAttribute.cs
@@ -6,19 +6,6 @@ namespace SmartMigrations;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class MigrationAttribute : Attribute
{
- // The static method holding checks for the shared migration data validity
- private static MigrationAttribute CreateMigrationAttribute(
- int[] fromList,
- bool isRange,
- int to,
- string? fromSchema,
- string? toSchema,
- bool shouldAvoid
- )
- {
- return new MigrationAttribute(fromList, isRange, to, fromSchema, toSchema, shouldAvoid);
- }
-
///
/// Gets the list of versions this migration can migrate from.
///
@@ -34,10 +21,16 @@ bool shouldAvoid
///
public int ToVersion { get; }
- // TODO NEeds docs
+ ///
+ /// Gets the schema this migration can migrate from. Null indicates the default schema.
+ /// Used for cross-schema migration capability.
+ ///
public string? FromSchema { get; }
- // TODO Needs docs
+ ///
+ /// Gets the schema this migration migrates to. Null indicates the default schema.
+ /// Used for cross-schema migration capability.
+ ///
public string? ToSchema { get; }
///
@@ -46,13 +39,17 @@ bool shouldAvoid
///
public bool ShouldAvoid { get; }
-
+ ///
+ /// A private constructor that takes all available values and performs the validation.
+ /// Its purpose is to be used by other, more user-friendly constructors.
+ ///
+ /// When provided values were invalid
private MigrationAttribute(
+ string? fromSchema,
int[] fromList,
bool isRange,
- int to,
- string? fromSchema,
string? toSchema,
+ int to,
bool shouldAvoid
)
{
@@ -67,85 +64,188 @@ bool shouldAvoid
if (fromList.Contains(to)) throw new ArgumentException("TODO To can't be same as from", nameof(to));
- fromSchema = fromSchema?.Trim();
- if (fromSchema != null && string.IsNullOrWhiteSpace(fromSchema))
+ FromSchema = fromSchema?.Trim();
+ if (FromSchema != null && string.IsNullOrWhiteSpace(FromSchema))
throw new ArgumentException("TODO from schema must be defined (null is a valid value)", nameof(fromSchema));
- toSchema = toSchema?.Trim();
- if (toSchema != null && string.IsNullOrWhiteSpace(toSchema))
+ ToSchema = toSchema?.Trim();
+ if (ToSchema != null && string.IsNullOrWhiteSpace(ToSchema))
throw new ArgumentException("TODO to schema must be defined (null is a valid value)", nameof(toSchema));
FromVersions = fromList;
+ if (FromVersions.Length == 0 && FromSchema != ToSchema)
+ {
+ throw new ArgumentException("Migration setting up schema from scratch can't have different 'from' and 'to' schemas.", nameof(fromList));
+ }
+
IsRange = isRange;
ToVersion = to;
- FromSchema = fromSchema;
- ToSchema = toSchema;
ShouldAvoid = shouldAvoid;
}
+ ///
+ /// Initializes a new instance of the class for setting up a specific schema from scratch.
+ /// This constructor creates a migration that can be applied when no version exists in the specified schema (initial setup migration).
+ ///
+ /// The schema this migration operates within. Null indicates the default schema.
+ /// The version this migration migrates to.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ public MigrationAttribute(string? schema, int to, bool shouldAvoid = false)
+ : this(schema, [], false, schema, to, shouldAvoid) {}
///
/// Initializes a new instance of the class for setting up the database schema from scratch.
/// This constructor creates a migration that can be applied when no version exists in the database (initial setup migration).
+ /// Uses the default schema.
///
/// The version this migration migrates to.
/// Whether this migration should be avoided if alternatives exist. Default is false.
public MigrationAttribute(int to, bool shouldAvoid = false)
- : this([], false, to, null, null, shouldAvoid) {}
+ : this(null, [], false, null, to, shouldAvoid) {}
+
+ ///
+ /// Initializes a new instance of the class with cross-schema migration capability.
+ /// Allows migration from one schema to another, enabling schema transitions.
+ ///
+ /// The schema this migration can migrate from. Null indicates the default schema.
+ /// The version this migration can migrate from.
+ /// The schema this migration migrates to. Null indicates the default schema.
+ /// The version this migration migrates to.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ /// Thrown when and are the same value.
+ public MigrationAttribute(string? fromSchema, int from, string? toSchema, int to, bool shouldAvoid = false)
+ : this(fromSchema, [from], false, toSchema, to, shouldAvoid) {}
+
+ ///
+ /// Initializes a new instance of the class within a single schema.
+ ///
+ /// The schema this migration operates within. Null indicates the default schema.
+ /// The version this migration can migrate from.
+ /// The version this migration migrates to.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ /// Thrown when and are the same value.
+ public MigrationAttribute(string? schema, int from, int to, bool shouldAvoid = false)
+ : this(schema, [from], false, schema, to, shouldAvoid) {}
///
/// Initializes a new instance of the class with a single source version.
+ /// Uses the default schema.
///
/// The version this migration can migrate from.
/// The version this migration migrates to.
/// Whether this migration should be avoided if alternatives exist. Default is false.
/// Thrown when and are the same value.
public MigrationAttribute(int from, int to, bool shouldAvoid = false)
- : this([from], false, to, null, null, shouldAvoid) {}
+ : this(null, [from], false, null, to, shouldAvoid) {}
+
+ ///
+ /// Initializes a new instance of the class with multiple source versions and cross-schema capability.
+ ///
+ /// The schema this migration can migrate from. Null indicates the default schema.
+ /// The array of versions this migration can migrate from.
+ /// The schema this migration migrates to. Null indicates the default schema.
+ /// The version this migration migrates to.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ /// Thrown when is null.
+ /// Thrown when contains the same version as .
+ public MigrationAttribute(string? fromSchema, int[] fromList, string? toSchema, int to, bool shouldAvoid = false)
+ : this(fromSchema, fromList, false, toSchema, to, shouldAvoid) {}
+
+ ///
+ /// Initializes a new instance of the class with multiple source versions within a single schema.
+ ///
+ /// The schema this migration operates within. Null indicates the default schema.
+ /// The array of versions this migration can migrate from.
+ /// The version this migration migrates to.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ /// Thrown when is null.
+ /// Thrown when contains the same version as .
+ public MigrationAttribute(string? schema, int[] fromList, int to, bool shouldAvoid = false)
+ : this(schema, fromList, false, schema, to, shouldAvoid) {}
///
/// Initializes a new instance of the class with multiple source versions.
+ /// Uses the default schema.
///
- /// The array of versions this migration can migrate from. Cannot be null.
+ /// The array of versions this migration can migrate from.
/// The version this migration migrates to.
/// Whether this migration should be avoided if alternatives exist. Default is false.
/// Thrown when is null.
/// Thrown when contains the same version as .
public MigrationAttribute(int[] fromList, int to, bool shouldAvoid = false)
- : this(fromList, false, to, null, null, shouldAvoid) {}
+ : this(null, fromList, false, null, to, shouldAvoid) {}
+
+ ///
+ /// Initializes a new instance of the class with a range of source versions and cross-schema capability.
+ ///
+ /// The schema this migration can migrate from. Null indicates the default schema.
+ /// The start of the inclusive range of versions this migration can migrate from.
+ /// The end of the inclusive range of versions this migration can migrate from.
+ /// The schema this migration migrates to. Null indicates the default schema.
+ /// The version this migration migrates to.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ /// Thrown when range start is greater than range end, or when is within the range.
+ public MigrationAttribute(string? fromSchema, int fromRangeStart, int fromRangeEnd, string? toSchema, int to, bool shouldAvoid = false)
+ : this(fromSchema, [fromRangeStart, fromRangeEnd], true, toSchema, to, shouldAvoid) {}
+
+ ///
+ /// Initializes a new instance of the class with a range of source versions within a single schema.
+ ///
+ /// The schema this migration operates within. Null indicates the default schema.
+ /// The start of the inclusive range of versions this migration can migrate from.
+ /// The end of the inclusive range of versions this migration can migrate from.
+ /// The version this migration migrates to.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ /// Thrown when range start is greater than range end, or when is within the range.
+ public MigrationAttribute(string? schema, int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid = false)
+ : this(schema, [fromRangeStart, fromRangeEnd], true, schema, to, shouldAvoid) {}
///
/// Initializes a new instance of the class with a range of source versions.
+ /// Uses the default schema.
///
/// The start of the inclusive range of versions this migration can migrate from.
/// The end of the inclusive range of versions this migration can migrate from.
/// The version this migration migrates to.
/// Whether this migration should be avoided if alternatives exist. Default is false.
- /// Thrown when range start is greater than the range end, or when is within the range.
+ /// Thrown when range start is greater than range end, or when is within the range.
public MigrationAttribute(int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid = false)
- : this([fromRangeStart, fromRangeEnd], true, to, null, null, shouldAvoid) {}
+ : this(null, [fromRangeStart, fromRangeEnd], true, null, to, shouldAvoid) {}
///
- /// Initializes a new instance of the class with string-based version specification.
+ /// Initializes a new instance of the class with string-based version specification and cross-schema capability.
/// Supports single version ("12"), comma-separated list ("3, 6, 12, 7"), or range ("5..10").
///
+ /// The schema this migration can migrate from. Null indicates the default schema.
/// The version specification this migration can migrate from. Can be a single version, comma-separated list, or range. Use null to indicate this migration can be applied from any version.
+ /// The schema this migration migrates to. Null indicates the default schema.
/// The version this migration migrates to as a string.
/// Whether this migration should be avoided if alternatives exist. Default is false.
/// Thrown when is null.
- /// Thrown when or contains an invalid version format, is empty/whitespace, when from and to versions are the same, when to version is within a from range, or when a from list contains the to version.
- public MigrationAttribute(string? from, string to, bool shouldAvoid = false)
+ /// Thrown when schema parameters are empty/whitespace, or contains an invalid version format or is empty/whitespace, when from and to versions are the same, when to version is within a from range, or when a from list contains the to version.
+ public MigrationAttribute(string? fromSchema, string? from, string? toSchema, string to, bool shouldAvoid = false)
{
- ArgumentNullException.ThrowIfNull(to);
+ // Schemas
+ FromSchema = fromSchema?.Trim();
+ if (FromSchema != null && string.IsNullOrWhiteSpace(FromSchema))
+ throw new ArgumentException("TODO from schema must be defined (null is a valid value)", nameof(fromSchema));
+ ToSchema = toSchema?.Trim();
+ if (ToSchema != null && string.IsNullOrWhiteSpace(ToSchema))
+ throw new ArgumentException("TODO to schema must be defined (null is a valid value)", nameof(toSchema));
+ // To
+ ArgumentNullException.ThrowIfNull(to);
if (string.IsNullOrWhiteSpace(to))
throw new ArgumentException("To version cannot be empty or whitespace.", nameof(to));
-
if (!int.TryParse(to.Trim(), out var toVersion))
throw new ArgumentException("To version must be an integer.", nameof(to));
-
ToVersion = toVersion;
+
+ // Should avoid
ShouldAvoid = shouldAvoid;
+
+ // From & IsRange
+
IsRange = false;
// Handle null "from"
@@ -192,12 +292,12 @@ public MigrationAttribute(string? from, string to, bool shouldAvoid = false)
.Select(part =>
{
if (!int.TryParse(part, out var version))
- throw new ArgumentException("All versions in the list must be an integers.",
+ throw new ArgumentException("All versions in the list must be integers.",
nameof(from));
return version;
})
.Distinct()
- .ToList();
+ .ToArray();
if (FromVersions.Contains(ToVersion))
throw new ArgumentException("From version list cannot contain the same version as the to version.", nameof(from));
@@ -211,5 +311,35 @@ public MigrationAttribute(string? from, string to, bool shouldAvoid = false)
throw new ArgumentException("From version cannot be the same as to version.", nameof(from));
FromVersions = [version];
}
+
+ if (FromVersions.Length == 0 && FromSchema != ToSchema)
+ {
+ throw new ArgumentException("Migration setting up schema from scratch can't have different 'from' and 'to' schemas.", nameof(from));
+ }
}
+
+ ///
+ /// Initializes a new instance of the class with string-based version specification within a single schema.
+ /// Supports single version ("12"), comma-separated list ("3, 6, 12, 7"), or range ("5..10").
+ ///
+ /// The schema this migration operates within. Null indicates the default schema.
+ /// The version specification this migration can migrate from. Can be a single version, comma-separated list, or range. Use null to indicate this migration can be applied from any version.
+ /// The version this migration migrates to as a string.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ /// Thrown when is null.
+ /// Thrown when schema parameter is empty/whitespace, or contains an invalid version format or is empty/whitespace, when from and to versions are the same, when to version is within a from range, or when a from list contains the to version.
+ public MigrationAttribute(string? schema, string? from, string to, bool shouldAvoid = false)
+ : this(schema, from, schema, to, shouldAvoid) { }
+
+ ///
+ /// Initializes a new instance of the class with string-based version specification in the default schema.
+ /// Supports single version ("12"), comma-separated list ("3, 6, 12, 7"), or range ("5..10").
+ ///
+ /// The version specification this migration can migrate from. Can be a single version, comma-separated list, or range. Use null to indicate this migration can be applied from any version.
+ /// The version this migration migrates to as a string.
+ /// Whether this migration should be avoided if alternatives exist. Default is false.
+ /// Thrown when is null.
+ /// Thrown when or contains an invalid version format or is empty/whitespace, when from and to versions are the same, when to version is within a from range, or when a from list contains the to version.
+ public MigrationAttribute(string? from, string to, bool shouldAvoid = false)
+ : this(null, from, null, to, shouldAvoid) { }
}
diff --git a/Source/SmartMigrations/SmartMigrations.csproj b/Source/SmartMigrations/SmartMigrations.csproj
index 494393a..8796593 100644
--- a/Source/SmartMigrations/SmartMigrations.csproj
+++ b/Source/SmartMigrations/SmartMigrations.csproj
@@ -10,5 +10,9 @@
database;migration;version;
+
+
+
+
diff --git a/Tests/SmartMigrations.Test/MigrationAttributeListFromTests.cs b/Tests/SmartMigrations.Test/MigrationAttributeListFromTests.cs
new file mode 100644
index 0000000..9e6260a
--- /dev/null
+++ b/Tests/SmartMigrations.Test/MigrationAttributeListFromTests.cs
@@ -0,0 +1,161 @@
+namespace SmartMigrations.Test;
+
+using SmartMigrations;
+using Xunit;
+
+public class MigrationAttributeListFromTests
+{
+ #region Constructor: MigrationAttribute(int[] fromList, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(new int[] { 1 }, 5, false, new int[] { 1 }, 5, false, false)]
+ [InlineData(new int[] { 1, 3, 5 }, 10, true, new int[] { 1, 3, 5 }, 10, false, true)]
+ [InlineData(new int[] { 0, 1, 2 }, 3, false, new int[] { 0, 1, 2 }, 3, false, false)]
+ [InlineData(new int[] { 10, 20, 30, 40 }, 50, true, new int[] { 10, 20, 30, 40 }, 50, false, true)]
+ [InlineData(new int[] { 100 }, 200, false, new int[] { 100 }, 200, false, false)]
+ [InlineData(new int[] { 5, 1, 3 }, 10, false, new int[] { 5, 1, 3 }, 10, false, false)]
+ [InlineData(new int[] { 5, 1, 3, 1, 5 }, 10, true, new int[] { 5, 1, 3 }, 10, false, true)]
+ public void Constructor_DefaultSchema_ListFrom_Success(int[] fromList, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(fromList, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Null(attribute.FromSchema);
+ Assert.Null(attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData(new int[] { 1, 5 }, 5, false)]
+ [InlineData(new int[] { 7, -12 }, 7, false)]
+ [InlineData(new int[] { 7, -12 }, -12, true)]
+ [InlineData(new int[] { 10, 20, 30 }, 20, true)]
+ [InlineData(new int[] { 5 }, 5, false)]
+ public void Constructor_DefaultSchema_ListFrom_ContainsTo_ThrowsException(int[] fromList, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(fromList, to, shouldAvoid));
+ }
+
+ [Fact]
+ public void Constructor_DefaultSchema_ListFrom_NullList_ThrowsException()
+ {
+ Assert.Throws(() => new MigrationAttribute((int[])null!, 5));
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? schema, int[] fromList, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, new int[] { 1 }, 5, false, new int[] { 1 }, 5, false, false)]
+ [InlineData(null, new int[] { 1 }, 5, true, new int[] { 1 }, 5, false, true)]
+ [InlineData("free", new int[] { 1, 2, 3 }, 10, false, new int[] { 1, 2, 3 }, 10, false, false)]
+ [InlineData("free", new int[] { 1, 2, 3 }, 10, true, new int[] { 1, 2, 3 }, 10, false, true)]
+ [InlineData("paid", new int[] { 5, 10, 15, 20 }, 25, false, new int[] { 5, 10, 15, 20 }, 25, false, false)]
+ [InlineData("paid", new int[] { 5, 10, 15, 20 }, 25, true, new int[] { 5, 10, 15, 20 }, 25, false, true)]
+ [InlineData("enterprise", new int[] { -10, -5, 0, 5, 10 }, 15, false, new int[] { -10, -5, 0, 5, 10 }, 15, false, false)]
+ [InlineData("enterprise", new int[] { -10, -5, 0, 5, 10 }, 15, true, new int[] { -10, -5, 0, 5, 10 }, 15, false, true)]
+ public void Constructor_SpecificSchema_ListFrom_Success(string? schema, int[] fromList, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(schema, fromList, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Equal(schema, attribute.FromSchema);
+ Assert.Equal(schema, attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData("", new int[] { 1 }, 5, false)]
+ [InlineData(" ", new int[] { 1 }, 5, false)]
+ [InlineData("\t", new int[] { 1 }, 5, false)]
+ [InlineData("\n", new int[] { 1 }, 5, false)]
+ public void Constructor_SpecificSchema_ListFrom_InvalidSchema_ThrowsException(string schema, int[] fromList, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(schema, fromList, to, shouldAvoid));
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? fromSchema, int[] fromList, string? toSchema, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, new int[] { 1 }, null, 5, false, new int[] { 1 }, 5, false, false)]
+ [InlineData(null, new int[] { 1 }, null, 5, true, new int[] { 1 }, 5, false, true)]
+ [InlineData("free", new int[] { 1, 2, 3 }, "free", 10, false, new int[] { 1, 2, 3 }, 10, false, false)]
+ [InlineData("free", new int[] { 1, 2, 3 }, "free", 10, true, new int[] { 1, 2, 3 }, 10, false, true)]
+ [InlineData("free", new int[] { 5, 10, 15 }, "paid", 1, false, new int[] { 5, 10, 15 }, 1, false, false)]
+ [InlineData("free", new int[] { 5, 10, 15 }, "paid", 1, true, new int[] { 5, 10, 15 }, 1, false, true)]
+ [InlineData("paid", new int[] { 10, 20 }, "enterprise", 1, false, new int[] { 10, 20 }, 1, false, false)]
+ [InlineData("paid", new int[] { 10, 20 }, "enterprise", 1, true, new int[] { 10, 20 }, 1, false, true)]
+ [InlineData(null, new int[] { 5, 10 }, "premium", 1, false, new int[] { 5, 10 }, 1, false, false)]
+ [InlineData("basic", new int[] { 5, 10 }, null, 15, false, new int[] { 5, 10 }, 15, false, false)]
+ public void Constructor_CrossSchema_ListFrom_Success(string? fromSchema, int[] fromList, string? toSchema, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(fromSchema, fromList, toSchema, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Equal(fromSchema, attribute.FromSchema);
+ Assert.Equal(toSchema, attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData("", new int[] { 1 }, "paid", 5, false)]
+ [InlineData(" ", new int[] { 1 }, "paid", 5, false)]
+ [InlineData("free", new int[] { 1 }, "", 5, false)]
+ [InlineData("free", new int[] { 1 }, " ", 5, false)]
+ [InlineData("\t", new int[] { 1 }, "paid", 5, false)]
+ [InlineData("free", new int[] { 1 }, "\n", 5, false)]
+ public void Constructor_CrossSchema_ListFrom_InvalidSchema_ThrowsException(string fromSchema, int[] fromList, string toSchema, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(fromSchema, fromList, toSchema, to, shouldAvoid));
+ }
+
+ #endregion
+
+ #region Edge Cases for List From Migrations
+
+ [Fact]
+ public void Constructor_ListFrom_DuplicatesRemoved()
+ {
+ var attribute = new MigrationAttribute(new int[] { 1, 2, 2, 3, 1, 3 }, 10);
+ Assert.Equal(new int[] { 1, 2, 3 }, attribute.FromVersions);
+ }
+
+ [Fact]
+ public void Constructor_ListFrom_EmptyList()
+ {
+ var attribute = new MigrationAttribute(new int[] { }, 10);
+ Assert.Empty(attribute.FromVersions);
+ Assert.Equal(10, attribute.ToVersion);
+ }
+
+ [Fact]
+ public void Constructor_ListFrom_IsRangeFalse()
+ {
+ var attribute = new MigrationAttribute(new int[] { 1, 2, 3 }, 10);
+ Assert.False(attribute.IsRange);
+ }
+
+ [Fact]
+ public void Constructor_ListFrom_OrderPreserved()
+ {
+ var attribute = new MigrationAttribute(new int[] { 5, 1, 3, 2 }, 10);
+ Assert.Equal(new int[] { 5, 1, 3, 2 }, attribute.FromVersions);
+ }
+
+ [Fact]
+ public void Constructor_ListFrom_LargeList()
+ {
+ var largeList = Enumerable.Range(1, 100).ToArray();
+ var attribute = new MigrationAttribute(largeList, 200);
+ Assert.Equal(largeList, attribute.FromVersions);
+ Assert.Equal(200, attribute.ToVersion);
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/Tests/SmartMigrations.Test/MigrationAttributeNewSchemaTests.cs b/Tests/SmartMigrations.Test/MigrationAttributeNewSchemaTests.cs
new file mode 100644
index 0000000..8ab4824
--- /dev/null
+++ b/Tests/SmartMigrations.Test/MigrationAttributeNewSchemaTests.cs
@@ -0,0 +1,74 @@
+namespace SmartMigrations.Test;
+
+using SmartMigrations;
+using Xunit;
+
+public class MigrationAttributeNewSchemaTests
+{
+ #region Constructor: MigrationAttribute(int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(0, false)]
+ [InlineData(0, true)]
+ [InlineData(1, false)]
+ [InlineData(1, true)]
+ [InlineData(30, null)]
+ [InlineData(30, true)]
+ [InlineData(int.MaxValue, false)]
+ [InlineData(int.MaxValue, true)]
+ public void Constructor_DefaultSchema_InitialSetup_Success(int to, bool? shouldAvoid)
+ {
+ var attribute = shouldAvoid != null
+ ? new MigrationAttribute(to, shouldAvoid.Value)
+ : new MigrationAttribute(to);
+ Assert.Null(attribute.FromSchema);
+ Assert.Empty(attribute.FromVersions);
+ Assert.False(attribute.IsRange);
+ Assert.Null(attribute.ToSchema);
+ Assert.Equal(to, attribute.ToVersion);
+ if (shouldAvoid.HasValue) Assert.Equal(shouldAvoid.Value, attribute.ShouldAvoid);
+ else Assert.False(attribute.ShouldAvoid);
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? schema, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, 0, false, null)]
+ [InlineData(null, 1, true, null)]
+ [InlineData("free", 0, false, "free")]
+ [InlineData("free", 135, true, "free")]
+ [InlineData("paid", 100, false, "paid")]
+ [InlineData("paid", -100, true, "paid")]
+ [InlineData("enterprise", int.MaxValue, false, "enterprise")]
+ [InlineData("enterprise", int.MaxValue, true, "enterprise")]
+ [InlineData("custom_schema", int.MinValue, false, "custom_schema")]
+ [InlineData("custom_schema", int.MinValue, true, "custom_schema")]
+ [InlineData(" a schema ", -315498, false, "a schema")]
+ [InlineData("\n\t\nsomeThing123 \n", 69420, true, "someThing123")]
+ public void Constructor_SpecificSchema_InitialSetup_Success(string? schema, int to, bool shouldAvoid, string? expectedSchema)
+ {
+ var attribute = new MigrationAttribute(schema, to, shouldAvoid);
+ Assert.Equal(expectedSchema, attribute.FromSchema);
+ Assert.Empty(attribute.FromVersions);
+ Assert.False(attribute.IsRange);
+ Assert.Equal(expectedSchema, attribute.ToSchema);
+ Assert.Equal(to, attribute.ToVersion);
+ Assert.Equal(shouldAvoid, attribute.ShouldAvoid);
+ }
+
+ [Theory]
+ [InlineData("", 1, false)]
+ [InlineData(" ", 1, true)]
+ [InlineData("\t", 1, false)]
+ [InlineData("\n", 1, true)]
+ [InlineData("\t \n", 1, false)]
+ [InlineData("\n\n\n \n", 1, true)]
+ public void Constructor_SpecificSchema_InitialSetup_InvalidSchema_ThrowsException(string schema, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(schema, to, shouldAvoid));
+ }
+
+ #endregion
+}
diff --git a/Tests/SmartMigrations.Test/MigrationAttributeRangeFromTests.cs b/Tests/SmartMigrations.Test/MigrationAttributeRangeFromTests.cs
new file mode 100644
index 0000000..0c18096
--- /dev/null
+++ b/Tests/SmartMigrations.Test/MigrationAttributeRangeFromTests.cs
@@ -0,0 +1,174 @@
+namespace SmartMigrations.Test;
+
+using SmartMigrations;
+using Xunit;
+
+public class MigrationAttributeRangeFromTests
+{
+ #region Constructor: MigrationAttribute(int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(1, 3, 10, false, new int[] { 1, 3 }, 10, true, false)]
+ [InlineData(5, 5, 8, true, new int[] { 5, 5 }, 8, true, true)]
+ [InlineData(0, 2, 5, false, new int[] { 0, 2 }, 5, true, false)]
+ [InlineData(-10, 15, 20, true, new int[] { -10, 15 }, 20, true, true)]
+ [InlineData(0, 0, 1, false, new int[] { 0, 0 }, 1, true, false)]
+ [InlineData(100, 200, 300, false, new int[] { 100, 200 }, 300, true, false)]
+ public void Constructor_DefaultSchema_RangeFrom_Success(int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(fromRangeStart, fromRangeEnd, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Null(attribute.FromSchema);
+ Assert.Null(attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData(5, 3, 10, false)]
+ [InlineData(10, 5, 15, true)]
+ [InlineData(-10, -55, 15, true)]
+ [InlineData(100, 50, 200, false)]
+ public void Constructor_DefaultSchema_RangeFrom_InvalidRange_ThrowsException(int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(fromRangeStart, fromRangeEnd, to, shouldAvoid));
+ }
+
+ [Theory]
+ [InlineData(5, 10, 7, false)]
+ [InlineData(1, 5, 3, true)]
+ [InlineData(-10, 20, 15, false)]
+ [InlineData(5, 10, 5, true)]
+ [InlineData(5, 10, 10, false)]
+ public void Constructor_DefaultSchema_RangeFrom_ToInRange_ThrowsException(int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(fromRangeStart, fromRangeEnd, to, shouldAvoid));
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? schema, int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, 1, 5, 10, false, new int[] { 1, 5 }, 10, true, false)]
+ [InlineData(null, 1, 5, 10, true, new int[] { 1, 5 }, 10, true, true)]
+ [InlineData("free", 0, 10, 20, false, new int[] { 0, 10 }, 20, true, false)]
+ [InlineData("free", 0, 10, 20, true, new int[] { 0, 10 }, 20, true, true)]
+ [InlineData("paid", -10, 10, 20, false, new int[] { -10, 10 }, 20, true, false)]
+ [InlineData("paid", -10, 10, 20, true, new int[] { -10, 10 }, 20, true, true)]
+ [InlineData("enterprise", -100, -50, -25, false, new int[] { -100, -50 }, -25, true, false)]
+ [InlineData("enterprise", -100, -50, -25, true, new int[] { -100, -50 }, -25, true, true)]
+ public void Constructor_SpecificSchema_RangeFrom_Success(string? schema, int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(schema, fromRangeStart, fromRangeEnd, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Equal(schema, attribute.FromSchema);
+ Assert.Equal(schema, attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData("", 1, 5, 10, false)]
+ [InlineData(" ", 1, 5, 10, false)]
+ [InlineData("\t", 1, 5, 10, false)]
+ [InlineData("\n", 1, 5, 10, false)]
+ public void Constructor_SpecificSchema_RangeFrom_InvalidSchema_ThrowsException(string schema, int fromRangeStart, int fromRangeEnd, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(schema, fromRangeStart, fromRangeEnd, to, shouldAvoid));
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? fromSchema, int fromRangeStart, int fromRangeEnd, string? toSchema, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, 1, 5, null, 10, false, new int[] { 1, 5 }, 10, true, false)]
+ [InlineData(null, 1, 5, null, 10, true, new int[] { 1, 5 }, 10, true, true)]
+ [InlineData("free", 0, 10, "free", 20, false, new int[] { 0, 10 }, 20, true, false)]
+ [InlineData("free", 0, 10, "free", 20, true, new int[] { 0, 10 }, 20, true, true)]
+ [InlineData("free", 5, 15, "paid", 1, false, new int[] { 5, 15 }, 1, true, false)]
+ [InlineData("free", 5, 15, "paid", 1, true, new int[] { 5, 15 }, 1, true, true)]
+ [InlineData("paid", 10, 20, "enterprise", 1, false, new int[] { 10, 20 }, 1, true, false)]
+ [InlineData("paid", 10, 20, "enterprise", 1, true, new int[] { 10, 20 }, 1, true, true)]
+ [InlineData(null, 5, 10, "premium", 1, false, new int[] { 5, 10 }, 1, true, false)]
+ [InlineData("basic", 5, 10, null, 15, false, new int[] { 5, 10 }, 15, true, false)]
+ public void Constructor_CrossSchema_RangeFrom_Success(string? fromSchema, int fromRangeStart, int fromRangeEnd, string? toSchema, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(fromSchema, fromRangeStart, fromRangeEnd, toSchema, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Equal(fromSchema, attribute.FromSchema);
+ Assert.Equal(toSchema, attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData("", 1, 5, "paid", 10, false)]
+ [InlineData(" ", 1, 5, "paid", 10, false)]
+ [InlineData("free", 1, 5, "", 10, false)]
+ [InlineData("free", 1, 5, " ", 10, false)]
+ [InlineData("\t", 1, 5, "paid", 10, false)]
+ [InlineData("free", 1, 5, "\n", 10, false)]
+ public void Constructor_CrossSchema_RangeFrom_InvalidSchema_ThrowsException(string fromSchema, int fromRangeStart, int fromRangeEnd, string toSchema, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(fromSchema, fromRangeStart, fromRangeEnd, toSchema, to, shouldAvoid));
+ }
+
+ #endregion
+
+ #region Edge Cases for Range From Migrations
+
+ [Fact]
+ public void Constructor_RangeFrom_IsRangeTrue()
+ {
+ var attribute = new MigrationAttribute(1, 10, 20);
+ Assert.True(attribute.IsRange);
+ }
+
+ [Fact]
+ public void Constructor_RangeFrom_FromVersionsContainsTwoElements()
+ {
+ var attribute = new MigrationAttribute(5, 15, 20);
+ Assert.Equal(2, attribute.FromVersions.Length);
+ Assert.Equal(5, attribute.FromVersions[0]);
+ Assert.Equal(15, attribute.FromVersions[1]);
+ }
+
+ [Fact]
+ public void Constructor_RangeFrom_SingleValueRange()
+ {
+ var attribute = new MigrationAttribute(5, 5, 10);
+ Assert.Equal(new int[] { 5, 5 }, attribute.FromVersions);
+ Assert.True(attribute.IsRange);
+ }
+
+ [Fact]
+ public void Constructor_RangeFrom_LargeRange()
+ {
+ var attribute = new MigrationAttribute(1, 10000, 10001);
+ Assert.Equal(new int[] { 1, 10000 }, attribute.FromVersions);
+ Assert.Equal(10001, attribute.ToVersion);
+ }
+
+ [Fact]
+ public void Constructor_RangeFrom_NegativeRange()
+ {
+ var attribute = new MigrationAttribute(-1000, -500, -250);
+ Assert.Equal(new int[] { -1000, -500 }, attribute.FromVersions);
+ Assert.Equal(-250, attribute.ToVersion);
+ }
+
+ [Fact]
+ public void Constructor_RangeFrom_CrossingZeroRange()
+ {
+ var attribute = new MigrationAttribute(-100, 100, 200);
+ Assert.Equal(new int[] { -100, 100 }, attribute.FromVersions);
+ Assert.Equal(200, attribute.ToVersion);
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/Tests/SmartMigrations.Test/MigrationAttributeSingleFromTests.cs b/Tests/SmartMigrations.Test/MigrationAttributeSingleFromTests.cs
new file mode 100644
index 0000000..2b1a77d
--- /dev/null
+++ b/Tests/SmartMigrations.Test/MigrationAttributeSingleFromTests.cs
@@ -0,0 +1,133 @@
+namespace SmartMigrations.Test;
+
+using SmartMigrations;
+using Xunit;
+
+public class MigrationAttributeSingleFromTests
+{
+ #region Constructor: MigrationAttribute(int from, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(0, 1, false, new[] { 0 })]
+ [InlineData(5, 1, true, new[] { 5 })]
+ [InlineData(8, 31, null, new[] { 8 })]
+ [InlineData(8, -105631, true, new[] { 8 })]
+ [InlineData(168, -50, false, new[] { 168 })]
+ [InlineData(-168, 50, true, new[] { -168 })]
+ [InlineData(0, int.MaxValue, false, new[] { 0 })]
+ [InlineData(int.MaxValue, int.MinValue, true, new[] { int.MaxValue })]
+ public void Constructor_DefaultSchema_SingleFrom_Success(int from, int to, bool? shouldAvoid, int[] expectedFromVersions)
+ {
+ var attribute = shouldAvoid.HasValue
+ ? new MigrationAttribute(from, to, shouldAvoid.Value)
+ : new MigrationAttribute(from, to);
+ Assert.Null(attribute.FromSchema);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.False(attribute.IsRange);
+ Assert.Null(attribute.ToSchema);
+ Assert.Equal(to, attribute.ToVersion);
+ if (shouldAvoid.HasValue) Assert.Equal(shouldAvoid.Value, attribute.ShouldAvoid);
+ else Assert.False(attribute.ShouldAvoid);
+ }
+
+ [Theory]
+ [InlineData(0, 0, false)]
+ [InlineData(5, 5, true)]
+ [InlineData(-42, -42, true)]
+ [InlineData(100, 100, false)]
+ [InlineData(int.MaxValue, int.MaxValue, true)]
+ [InlineData(int.MinValue, int.MinValue, true)]
+ public void Constructor_DefaultSchema_SingleFrom_SameFromTo_ThrowsException(int from, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(from, to, shouldAvoid));
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? schema, int from, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, 0, 1, false, new[] { 0 }, null)]
+ [InlineData(null, 0, -1, true, new[] { 0 }, null)]
+ [InlineData("free", 1, 2, false, new[] { 1 }, "free")]
+ [InlineData("fr ee", -6, 2, true, new[] { -6 }, "fr ee")]
+ [InlineData("paid ", 10, 20, false, new[] { 10 }, "paid")]
+ [InlineData(" \npaid", int.MaxValue, 20, true, new[] { int.MaxValue }, "paid")]
+ [InlineData("enterprise", 100, 50, false, new[] { 100 }, "enterprise")]
+ [InlineData("\n enterprise \t\t", int.MinValue, int.MinValue + 1, true, new[] { int.MinValue }, "enterprise")]
+ [InlineData(" 123 How Are You?\n\r", 100, -50, true, new[] { 100 }, "123 How Are You?")]
+ public void Constructor_SpecificSchema_SingleFrom_Success(string? schema, int from, int to, bool shouldAvoid, int[] expectedFromVersions, string? expectedSchema)
+ {
+ var attribute = new MigrationAttribute(schema, from, to, shouldAvoid);
+ Assert.Equal(expectedSchema, attribute.FromSchema);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.False(attribute.IsRange);
+ Assert.Equal(expectedSchema, attribute.ToSchema);
+ Assert.Equal(to, attribute.ToVersion);
+ Assert.Equal(shouldAvoid, attribute.ShouldAvoid);
+ }
+
+ [Theory]
+ [InlineData("", 1, 2)]
+ [InlineData(" ", 1, 2)]
+ [InlineData("\t", 1, 2)]
+ [InlineData("\n", 1, 2)]
+ public void Constructor_SpecificSchema_SingleFrom_InvalidSchema_ThrowsException(string schema, int from, int to)
+ {
+ Assert.Throws(() => new MigrationAttribute(schema, from, to));
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? fromSchema, int from, string? toSchema, int to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, 1, null, 2, true, new[] { 1 }, null, null)]
+ [InlineData(null, -11, null, 2, false, new[] { -11 }, null, null)]
+ [InlineData("free", 1, "free", 200, null, new[] { 1 }, "free", "free")]
+ [InlineData("free", -101, "free", -200, true, new[] { -101 }, "free", "free")]
+ [InlineData("free", 10, "paid", 1, false, new[] { 10 }, "free", "paid")]
+ [InlineData("free ", 10, " paid", 1, null, new[] { 10 }, "free", "paid")]
+ [InlineData("paid\n", 5, "enterprise", 1, true, new[] { 5 }, "paid", "enterprise")]
+ [InlineData("paid", 5, "enterprise", 1, false, new[] { 5 }, "paid", "enterprise")]
+ [InlineData(null, 5, "premium\n\n", 1, null, new[] { 5 }, null, "premium")]
+ [InlineData("basic", 5, null, 10, true, new[] { 5 }, "basic", null)]
+ public void Constructor_CrossSchema_SingleFrom_Success(string? fromSchema, int from, string? toSchema, int to, bool? shouldAvoid, int[] expectedFromVersions, string? expectedFromSchema, string? expectedToSchema)
+ {
+ var attribute = shouldAvoid.HasValue
+ ? new MigrationAttribute(fromSchema, from, toSchema, to, shouldAvoid.Value)
+ : new MigrationAttribute(fromSchema, from, toSchema, to);
+ Assert.Equal(expectedFromSchema, attribute.FromSchema);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.False(attribute.IsRange);
+ Assert.Equal(expectedToSchema, attribute.ToSchema);
+ Assert.Equal(to, attribute.ToVersion);
+ if (shouldAvoid.HasValue) Assert.Equal(shouldAvoid.Value, attribute.ShouldAvoid);
+ else Assert.False(attribute.ShouldAvoid);
+ }
+
+ [Theory]
+ [InlineData("", 1, "paid", 2)]
+ [InlineData(" ", 1, "paid", 2)]
+ [InlineData("free", 1, "", 2)]
+ [InlineData("free", 1, " ", 2)]
+ [InlineData("\t", 1, "paid", 2)]
+ [InlineData("free", 1, "\n", 2)]
+ [InlineData(" ", 1, "\n", 2)]
+ public void Constructor_CrossSchema_SingleFrom_InvalidSchema_ThrowsException(string fromSchema, int from, string toSchema, int to)
+ {
+ Assert.Throws(() => new MigrationAttribute(fromSchema, from, toSchema, to));
+ }
+
+ [Theory]
+ [InlineData("free", 5, "paid", 5, false)]
+ [InlineData("free", 5, "paid ", 5, true)]
+ [InlineData(null, 10, null, 10, false)]
+ [InlineData("\n\nenterprise", -1, " enterprise \t\r\n ", -1, true)]
+ public void Constructor_CrossSchema_SingleFrom_SameFromTo_ThrowsException(string? fromSchema, int from, string? toSchema, int to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(fromSchema, from, toSchema, to, shouldAvoid));
+ }
+
+ #endregion
+}
diff --git a/Tests/SmartMigrations.Test/MigrationAttributeStringTests.cs b/Tests/SmartMigrations.Test/MigrationAttributeStringTests.cs
new file mode 100644
index 0000000..a94fe85
--- /dev/null
+++ b/Tests/SmartMigrations.Test/MigrationAttributeStringTests.cs
@@ -0,0 +1,241 @@
+namespace SmartMigrations.Test;
+
+using SmartMigrations;
+using Xunit;
+
+public class MigrationAttributeStringTests
+{
+ #region Constructor: MigrationAttribute(string? from, string to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, "5", false, new int[0], 5, false, false)]
+ [InlineData(null, "-15", false, new int[0], -15, false, false)]
+ [InlineData("3", "10", true, new int[] { 3 }, 10, false, true)]
+ [InlineData("3", "-11", false, new int[] { 3 }, -11, false, false)]
+ [InlineData("-9", "-8", true, new int[] { -9 }, -8, false, true)]
+ [InlineData("-9", "0", true, new int[] { -9 }, 0, false, true)]
+ [InlineData("-46", "158", true, new int[] { -46 }, 158, false, true)]
+ [InlineData("1,3,5", "8", false, new int[] { 1, 3, 5 }, 8, false, false)]
+ [InlineData("2..5", "10", true, new int[] { 2, 5 }, 10, true, true)]
+ [InlineData("0", "1", false, new int[] { 0 }, 1, false, false)]
+ [InlineData(" 1 , 2 , 3 ", " 10 ", false, new int[] { 1, 2, 3 }, 10, false, false)]
+ [InlineData("1,2,2, 3,1", "15", true, new int[] { 1, 2, 3 }, 15, false, true)]
+ [InlineData("-1, 2,16, -94,-1", "15", true, new int[] { -1, 2, 16, -94 }, 15, false, true)]
+ [InlineData("0..0", "5", false, new int[] { 0, 0 }, 5, true, false)]
+ [InlineData("-670..12", "50", true, new int[] { -670, 12 }, 50, true, true)]
+ [InlineData("-21..-2", "-1", true, new int[] { -21, -2 }, -1, true, true)]
+ [InlineData("-10000..-9800", "-1358", false, new int[] { -10000, -9800 }, -1358, true, false)]
+ [InlineData("100,50,75", "200", true, new int[] { 100, 50, 75 }, 200, false, true)]
+ public void Constructor_DefaultSchema_StringFrom_Success(string? from, string to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(from, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Null(attribute.FromSchema);
+ Assert.Null(attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData("5", "")]
+ [InlineData("5", " ")]
+ [InlineData("", "10")]
+ [InlineData(" ", "10")]
+ [InlineData("abc", "10")]
+ [InlineData("5", "abc")]
+ [InlineData("..", "10")]
+ [InlineData("..8", "10")]
+ [InlineData("8..", "10")]
+ [InlineData("1.5", "10")]
+ [InlineData("8..10..", "30")]
+ [InlineData("8..10..12", "30")]
+ [InlineData("..8..10", "30")]
+ [InlineData("3...5", "10")]
+ [InlineData("5..3", "10")]
+ [InlineData("-12..-17", "10")]
+ [InlineData("1..-117", "10")]
+ [InlineData(",", "10")]
+ [InlineData("1,2,-3", "2")]
+ [InlineData("5", "5")]
+ [InlineData("3..7", "5")]
+ [InlineData("10..20", "15")]
+ [InlineData("-30..20", "-25")]
+ [InlineData("-30..-20", "-21")]
+ [InlineData("5..10", "5")]
+ [InlineData("-5..10", "-5")]
+ [InlineData("5..10", "10")]
+ [InlineData("-25..-10", "-10")]
+ public void Constructor_DefaultSchema_StringFrom_InvalidFormat_ThrowsException(string from, string to)
+ {
+ Assert.ThrowsAny(() => new MigrationAttribute(from, to, false));
+ }
+
+ [Fact]
+ public void Constructor_DefaultSchema_StringFrom_NullTo_ThrowsException()
+ {
+ Assert.Throws(() => new MigrationAttribute("5", null!, false));
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? schema, string? from, string to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, null, "10", false, new int[0], 10, false, false)]
+ [InlineData(null, null, "10", true, new int[0], 10, false, true)]
+ [InlineData("free", "5", "10", false, new int[] { 5 }, 10, false, false)]
+ [InlineData("free", "5", "10", true, new int[] { 5 }, 10, false, true)]
+ [InlineData("paid", "1,2,3", "10", false, new int[] { 1, 2, 3 }, 10, false, false)]
+ [InlineData("paid", "1,2,3", "10", true, new int[] { 1, 2, 3 }, 10, false, true)]
+ [InlineData("enterprise", "5..10", "15", false, new int[] { 5, 10 }, 15, true, false)]
+ [InlineData("enterprise", "5..10", "15", true, new int[] { 5, 10 }, 15, true, true)]
+ public void Constructor_SpecificSchema_StringFrom_Success(string? schema, string? from, string to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(schema, from, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Equal(schema, attribute.FromSchema);
+ Assert.Equal(schema, attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData("", "5", "10", false)]
+ [InlineData(" ", "5", "10", false)]
+ [InlineData("\t", "5", "10", false)]
+ [InlineData("\n", "5", "10", false)]
+ public void Constructor_SpecificSchema_StringFrom_InvalidSchema_ThrowsException(string schema, string from, string to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(schema, from, to, shouldAvoid));
+ }
+
+ #endregion
+
+ #region Constructor: MigrationAttribute(string? fromSchema, string? from, string? toSchema, string to, bool shouldAvoid = false)
+
+ [Theory]
+ [InlineData(null, null, null, "10", false, new int[0], 10, false, false)]
+ [InlineData(null, null, null, "10", true, new int[0], 10, false, true)]
+ [InlineData("free", "5", "free", "10", false, new int[] { 5 }, 10, false, false)]
+ [InlineData("free", "5", "free", "10", true, new int[] { 5 }, 10, false, true)]
+ [InlineData("free", "10,15,20", "paid", "1", false, new int[] { 10, 15, 20 }, 1, false, false)]
+ [InlineData("free", "10,15,20", "paid", "1", true, new int[] { 10, 15, 20 }, 1, false, true)]
+ [InlineData("paid", "5..15", "enterprise", "1", false, new int[] { 5, 15 }, 1, true, false)]
+ [InlineData("paid", "5..15", "enterprise", "1", true, new int[] { 5, 15 }, 1, true, true)]
+ [InlineData(null, "5", "premium", "1", false, new int[] { 5 }, 1, false, false)]
+ [InlineData("basic", "5", null, "10", false, new int[] { 5 }, 10, false, false)]
+ public void Constructor_CrossSchema_StringFrom_Success(string? fromSchema, string? from, string? toSchema, string to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
+ {
+ var attribute = new MigrationAttribute(fromSchema, from, toSchema, to, shouldAvoid);
+ Assert.Equal(expectedFromVersions, attribute.FromVersions);
+ Assert.Equal(expectedTo, attribute.ToVersion);
+ Assert.Equal(expectedIsRange, attribute.IsRange);
+ Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
+ Assert.Equal(fromSchema, attribute.FromSchema);
+ Assert.Equal(toSchema, attribute.ToSchema);
+ }
+
+ [Theory]
+ [InlineData("", "5", "paid", "10", false)]
+ [InlineData(" ", "5", "paid", "10", false)]
+ [InlineData("free", "5", "", "10", false)]
+ [InlineData("free", "5", " ", "10", false)]
+ [InlineData("\t", "5", "paid", "10", false)]
+ [InlineData("free", "5", "\n", "10", false)]
+ public void Constructor_CrossSchema_StringFrom_InvalidSchema_ThrowsException(string fromSchema, string from, string toSchema, string to, bool shouldAvoid)
+ {
+ Assert.Throws(() => new MigrationAttribute(fromSchema, from, toSchema, to, shouldAvoid));
+ }
+
+ #endregion
+
+ #region Edge Cases for String Constructors
+
+ [Fact]
+ public void Constructor_String_SingleVersionParsing()
+ {
+ var attribute = new MigrationAttribute("5", "10");
+ Assert.Equal(new int[] { 5 }, attribute.FromVersions);
+ Assert.Equal(10, attribute.ToVersion);
+ Assert.False(attribute.IsRange);
+ }
+
+ [Fact]
+ public void Constructor_String_ListVersionParsing()
+ {
+ var attribute = new MigrationAttribute("1,2,3", "10");
+ Assert.Equal(new int[] { 1, 2, 3 }, attribute.FromVersions);
+ Assert.Equal(10, attribute.ToVersion);
+ Assert.False(attribute.IsRange);
+ }
+
+ [Fact]
+ public void Constructor_String_RangeVersionParsing()
+ {
+ var attribute = new MigrationAttribute("5..10", "15");
+ Assert.Equal(new int[] { 5, 10 }, attribute.FromVersions);
+ Assert.Equal(15, attribute.ToVersion);
+ Assert.True(attribute.IsRange);
+ }
+
+ [Fact]
+ public void Constructor_String_WhitespaceHandling()
+ {
+ var attribute = new MigrationAttribute(" 5 ", " 10 ");
+ Assert.Equal(new int[] { 5 }, attribute.FromVersions);
+ Assert.Equal(10, attribute.ToVersion);
+ }
+
+ [Fact]
+ public void Constructor_String_ListWithWhitespace()
+ {
+ var attribute = new MigrationAttribute("1, 2, 3", "10");
+ Assert.Equal(new int[] { 1, 2, 3 }, attribute.FromVersions);
+ Assert.Equal(10, attribute.ToVersion);
+ }
+
+ [Fact]
+ public void Constructor_String_ListDuplicatesRemoved()
+ {
+ var attribute = new MigrationAttribute("1,2,2,3,1", "10");
+ Assert.Equal(new int[] { 1, 2, 3 }, attribute.FromVersions);
+ Assert.Equal(10, attribute.ToVersion);
+ }
+
+ [Fact]
+ public void Constructor_String_NegativeVersions()
+ {
+ var attribute = new MigrationAttribute("-5", "-1");
+ Assert.Equal(new int[] { -5 }, attribute.FromVersions);
+ Assert.Equal(-1, attribute.ToVersion);
+ }
+
+ [Fact]
+ public void Constructor_String_NegativeList()
+ {
+ var attribute = new MigrationAttribute("-5,-3,-1", "0");
+ Assert.Equal(new int[] { -5, -3, -1 }, attribute.FromVersions);
+ Assert.Equal(0, attribute.ToVersion);
+ }
+
+ [Fact]
+ public void Constructor_String_NegativeRange()
+ {
+ var attribute = new MigrationAttribute("-10..-5", "0");
+ Assert.Equal(new int[] { -10, -5 }, attribute.FromVersions);
+ Assert.Equal(0, attribute.ToVersion);
+ Assert.True(attribute.IsRange);
+ }
+
+ [Fact]
+ public void Constructor_String_LargeNumbers()
+ {
+ var attribute = new MigrationAttribute("1000000", "2000000");
+ Assert.Equal(new int[] { 1000000 }, attribute.FromVersions);
+ Assert.Equal(2000000, attribute.ToVersion);
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/Tests/SmartMigrations.Test/MigrationAttributeTest.cs b/Tests/SmartMigrations.Test/MigrationAttributeTest.cs
deleted file mode 100644
index 2130068..0000000
--- a/Tests/SmartMigrations.Test/MigrationAttributeTest.cs
+++ /dev/null
@@ -1,297 +0,0 @@
-namespace SmartMigrations.Test;
-
-using SmartMigrations;
-using Xunit;
-
-public class MigrationAttributeTest
-{
- #region Constructor: MigrationAttribute(int to, bool shouldAvoid)
-
- [Theory]
- [InlineData(0, false, new int[0], 0, false, false)]
- [InlineData(0, true, new int[0], 0, false, true)]
- [InlineData(1, false, new int[0], 1, false, false)]
- [InlineData(1, true, new int[0], 1, false, true)]
- [InlineData(30, false, new int[0], 30, false, false)]
- [InlineData(30, true, new int[0], 30, false, true)]
- [InlineData(int.MaxValue, false, new int[0], int.MaxValue, false, false)]
- [InlineData(int.MaxValue, true, new int[0], int.MaxValue, false, true)]
- public void Constructor_ToOnly_Success(int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
- {
- var attribute = new MigrationAttribute(to, shouldAvoid);
- Assert.Equal(expectedFromVersions, attribute.FromVersions);
- Assert.Equal(expectedTo, attribute.ToVersion);
- Assert.Equal(expectedIsRange, attribute.IsRange);
- Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
- }
-
- #endregion
-
- #region Constructor: MigrationAttribute(int from, int to, bool shouldAvoid)
-
- [Theory]
- [InlineData(0, 1, false, new int[] { 0 }, 1, false, false)]
- [InlineData(0, 1, true, new int[] { 0 }, 1, false, true)]
- [InlineData(8, 31, false, new int[] { 8 }, 31, false, false)]
- [InlineData(8, 31, true, new int[] { 8 }, 31, false, true)]
- [InlineData(168, 50, false, new int[] { 168 }, 50, false, false)]
- [InlineData(168, 50, true, new int[] { 168 }, 50, false, true)]
- [InlineData(0, int.MaxValue, false, new int[] { 0 }, int.MaxValue, false, false)]
- [InlineData(0, int.MaxValue, true, new int[] { 0 }, int.MaxValue, false, true)]
- public void Constructor_SingleFrom_Success(int from, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
- {
- var attribute = new MigrationAttribute(from, to, shouldAvoid);
- Assert.Equal(expectedFromVersions, attribute.FromVersions);
- Assert.Equal(expectedTo, attribute.ToVersion);
- Assert.Equal(expectedIsRange, attribute.IsRange);
- Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
- }
-
- [Theory]
- [InlineData(0, 0, false)]
- [InlineData(5, 5, true)]
- [InlineData(-42, -42, true)]
- [InlineData(100, 100, false)]
- [InlineData(int.MaxValue, int.MaxValue, true)]
- public void Constructor_SingleFrom_ThrowsArgumentException(int from, int to, bool shouldAvoid)
- {
- Assert.Throws(() => new MigrationAttribute(from, to, shouldAvoid));
- }
-
- #endregion
-
- #region Constructor: MigrationAttribute(IEnumerable fromList, int to, bool shouldAvoid)
-
- [Theory]
- [InlineData(new int[] { 1 }, 5, false, new int[] { 1 }, 5, false, false)]
- [InlineData(new int[] { 1, 3, 5 }, 10, true, new int[] { 1, 3, 5 }, 10, false, true)]
- [InlineData(new int[] { 0, 1, 2 }, 3, false, new int[] { 0, 1, 2 }, 3, false, false)]
- [InlineData(new int[] { 10, 20, 30, 40 }, 50, true, new int[] { 10, 20, 30, 40 }, 50, false, true)]
- [InlineData(new int[] { 100 }, 200, false, new int[] { 100 }, 200, false, false)]
- [InlineData(new int[] { 5, 1, 3 }, 10, false, new int[] { 5, 1, 3 }, 10, false, false)] // Preserves order, removes duplicates
- [InlineData(new int[] { 5, 1, 3, 1, 5 }, 10, true, new int[] { 5, 1, 3 }, 10, false, true)] // Duplicates removed, order preserved
- public void Constructor_FromList_Success(int[] fromList, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
- {
- var attribute = new MigrationAttribute(fromList, to, shouldAvoid);
- Assert.Equal(expectedFromVersions, attribute.FromVersions);
- Assert.Equal(expectedTo, attribute.ToVersion);
- Assert.Equal(expectedIsRange, attribute.IsRange);
- Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
- }
-
- [Theory]
- [InlineData(new int[] { 1, 5 }, 5, false)] // Contains to version
- [InlineData(new int[] { 7, -12 }, 7, false)] // Contains to version
- [InlineData(new int[] { 7, -12 }, -12, true)] // Contains to version
- [InlineData(new int[] { 10, 20, 30 }, 20, true)] // Contains to version in middle
- [InlineData(new int[] { 5 }, 5, false)] // Single item equals to
- public void Constructor_FromList_WithToVersionInList_ThrowsArgumentException(int[] fromList, int to, bool shouldAvoid)
- {
- Assert.Throws(() => new MigrationAttribute(fromList, to, shouldAvoid));
- }
-
- [Fact]
- public void Constructor_FromList_WithNull_ThrowsArgumentNullException()
- {
- Assert.Throws(() => new MigrationAttribute(null!, 5));
- }
-
- #endregion
-
- #region Constructor: MigrationAttribute((int start, int end) fromRange, int to, bool shouldAvoid)
-
- [Theory]
- [InlineData(1, 3, 10, false, new int[] { 1, 3 }, 10, true, false)] // Note: Range stores [start, end] not full sequence
- [InlineData(5, 5, 8, true, new int[] { 5, 5 }, 8, true, true)] // Single value range
- [InlineData(0, 2, 5, false, new int[] { 0, 2 }, 5, true, false)]
- [InlineData(-10, 15, 20, true, new int[] { -10, 15 }, 20, true, true)]
- [InlineData(0, 0, 1, false, new int[] { 0, 0 }, 1, true, false)]
- [InlineData(100, 200, 300, false, new int[] { 100, 200 }, 300, true, false)]
- public void Constructor_Range_Success(int start, int end, int to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
- {
- var attribute = new MigrationAttribute(start, end, to, shouldAvoid);
- Assert.Equal(expectedFromVersions, attribute.FromVersions);
- Assert.Equal(expectedTo, attribute.ToVersion);
- Assert.Equal(expectedIsRange, attribute.IsRange);
- Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
- }
-
- [Theory]
- [InlineData(5, 3, 10, false)]
- [InlineData(10, 5, 15, true)]
- [InlineData(-10, -55, 15, true)]
- [InlineData(100, 50, 200, false)]
- public void Constructor_Range_WithInvalidRange_ThrowsArgumentException(int start, int end, int to, bool shouldAvoid)
- {
- Assert.Throws(() => new MigrationAttribute(start, end, to, shouldAvoid));
- }
-
- [Theory]
- [InlineData(5, 10, 7, false)]
- [InlineData(1, 5, 3, true)]
- [InlineData(-10, 20, 15, false)]
- [InlineData(5, 10, 5, true)]
- [InlineData(5, 10, 10, false)]
- public void Constructor_Range_WithToVersionInRange_ThrowsArgumentException(int start, int end, int to, bool shouldAvoid)
- {
- Assert.Throws(() => new MigrationAttribute(start, end, to, shouldAvoid));
- }
-
- #endregion
-
- #region Constructor: MigrationAttribute(string? from, string to, bool shouldAvoid)
-
- [Theory]
- [InlineData(null, "5", false, new int[0], 5, false, false)]
- [InlineData(null, "-15", false, new int[0], -15, false, false)]
- [InlineData("3", "10", true, new int[] { 3 }, 10, false, true)]
- [InlineData("3", "-11", false, new int[] { 3 }, -11, false, false)]
- [InlineData("-9", "-8", true, new int[] { -9 }, -8, false, true)]
- [InlineData("-9", "0", true, new int[] { -9 }, 0, false, true)]
- [InlineData("-46", "158", true, new int[] { -46 }, 158, false, true)]
- [InlineData("1,3,5", "8", false, new int[] { 1, 3, 5 }, 8, false, false)]
- [InlineData("2..5", "10", true, new int[] { 2, 5 }, 10, true, true)]
- [InlineData("0", "1", false, new int[] { 0 }, 1, false, false)]
- [InlineData(" 1 , 2 , 3 ", " 10 ", false, new int[] { 1, 2, 3 }, 10, false, false)]
- [InlineData("1,2,2, 3,1", "15", true, new int[] { 1, 2, 3 }, 15, false, true)]
- [InlineData("-1, 2,16, -94,-1", "15", true, new int[] { -1, 2, 16, -94 }, 15, false, true)]
- [InlineData("0..0", "5", false, new int[] { 0, 0 }, 5, true, false)]
- [InlineData("-670..12", "50", true, new int[] { -670, 12 }, 50, true, true)]
- [InlineData("-21..-2", "-1", true, new int[] { -21, -2 }, -1, true, true)]
- [InlineData("-10000..-9800", "-1358", false, new int[] { -10000, -9800 }, -1358, true, false)]
- [InlineData("100,50,75", "200", true, new int[] { 100, 50, 75 }, 200, false, true)]
- public void Constructor_String_Success(string? from, string to, bool shouldAvoid, int[] expectedFromVersions, int expectedTo, bool expectedIsRange, bool expectedShouldAvoid)
- {
- var attribute = new MigrationAttribute(from, to, shouldAvoid);
- Assert.Equal(expectedFromVersions, attribute.FromVersions);
- Assert.Equal(expectedTo, attribute.ToVersion);
- Assert.Equal(expectedIsRange, attribute.IsRange);
- Assert.Equal(expectedShouldAvoid, attribute.ShouldAvoid);
- }
-
- [Theory]
- [InlineData("5", "")] // Empty to
- [InlineData("5", " ")] // Whitespace to
- [InlineData("", "10")] // Empty from
- [InlineData(" ", "10")] // Whitespace from
- [InlineData("abc", "10")] // Invalid from format
- [InlineData("5", "abc")] // Invalid to format
- [InlineData("..", "10")] // Invalid range format
- [InlineData("..8", "10")] // Invalid range format
- [InlineData("8..", "10")] // Invalid range format
- [InlineData("1.5", "10")] // Invalid range format
- [InlineData("8..10..", "30")] // Invalid range format
- [InlineData("8..10..12", "30")] // Invalid range format
- [InlineData("..8..10", "30")] // Invalid range format
- [InlineData("3...5", "10")] // Invalid range format
- [InlineData("5..3", "10")] // Reversed range
- [InlineData("-12..-17", "10")] // Reversed range
- [InlineData("1..-117", "10")] // Reversed range
- [InlineData(",", "10")] // Empty comma list
- [InlineData("1,2,-3", "2")] // From list contains to version
- [InlineData("5", "5")] // Single from equals to
- [InlineData("3..7", "5")] // To within range
- [InlineData("10..20", "15")] // To within range
- [InlineData("-30..20", "-25")] // To within range
- [InlineData("-30..-20", "-21")] // To within range
- [InlineData("5..10", "5")] // To equals range start
- [InlineData("-5..10", "-5")] // To equals range start
- [InlineData("5..10", "10")] // To equals range end
- [InlineData("-25..-10", "-10")] // To equals range end
- public void Constructor_String_ThrowsException(string? from, string to)
- {
- Assert.ThrowsAny(() => new MigrationAttribute(from, to, false));
- }
-
- #endregion
-
- #region Multiple Attributes Per Class
-
- [MigrationAttribute(10)] // Constructor 1: to only
- [MigrationAttribute(5, 15)] // Constructor 2: single from/to
- [MigrationAttribute(new int[] { 1, 3, 7 }, 20)] // Constructor 3: list from/to
- [MigrationAttribute(8, 12, 25, true)] // Constructor 4: range from/to with shouldAvoid
- [MigrationAttribute(null, "30")] // Constructor 5: string - null from
- [MigrationAttribute("2", "35")] // Constructor 6: string - single from
- [MigrationAttribute("4,6,9", "40")] // Constructor 7: string - list from
- [MigrationAttribute("13..17", "45")] // Constructor 8: string - range from
- [MigrationAttribute(18, 50, true)] // Constructor 9: single from/to with shouldAvoid
- [MigrationAttribute(new int[] { 21, 23 }, 55, true)] // Constructor 10: list from/to with shouldAvoid
- private class TestMigrationWithMultipleAttributes { }
-
- [Fact]
- public void MultipleAttributes_OnSingleClass_ShouldAllBeAccessible()
- {
- var attributes = typeof(TestMigrationWithMultipleAttributes)
- .GetCustomAttributes(typeof(MigrationAttribute), false)
- .Cast()
- .ToList();
-
- Assert.Equal(10, attributes.Count);
-
- // Verify each attribute has expected properties
- var sortedByTo = attributes.OrderBy(a => a.ToVersion).ToList();
-
- // Attribute 1: MigrationAttribute(10)
- Assert.Empty(sortedByTo[0].FromVersions);
- Assert.Equal(10, sortedByTo[0].ToVersion);
- Assert.False(sortedByTo[0].IsRange);
- Assert.False(sortedByTo[0].ShouldAvoid);
-
- // Attribute 2: MigrationAttribute(5, 15)
- Assert.Equal(new[] { 5 }, sortedByTo[1].FromVersions);
- Assert.Equal(15, sortedByTo[1].ToVersion);
- Assert.False(sortedByTo[1].IsRange);
- Assert.False(sortedByTo[1].ShouldAvoid);
-
- // Attribute 3: MigrationAttribute(new int[] { 1, 3, 7 }, 20)
- Assert.Equal(new[] { 1, 3, 7 }, sortedByTo[2].FromVersions);
- Assert.Equal(20, sortedByTo[2].ToVersion);
- Assert.False(sortedByTo[2].IsRange);
- Assert.False(sortedByTo[2].ShouldAvoid);
-
- // Attribute 4: MigrationAttribute((8, 12), 25, true)
- Assert.Equal(new[] { 8, 12 }, sortedByTo[3].FromVersions);
- Assert.Equal(25, sortedByTo[3].ToVersion);
- Assert.True(sortedByTo[3].IsRange);
- Assert.True(sortedByTo[3].ShouldAvoid);
-
- // Attribute 5: MigrationAttribute(null, "30")
- Assert.Empty(sortedByTo[4].FromVersions);
- Assert.Equal(30, sortedByTo[4].ToVersion);
- Assert.False(sortedByTo[4].IsRange);
- Assert.False(sortedByTo[4].ShouldAvoid);
-
- // Attribute 6: MigrationAttribute("2", "35")
- Assert.Equal(new[] { 2 }, sortedByTo[5].FromVersions);
- Assert.Equal(35, sortedByTo[5].ToVersion);
- Assert.False(sortedByTo[5].IsRange);
- Assert.False(sortedByTo[5].ShouldAvoid);
-
- // Attribute 7: MigrationAttribute("4,6,9", "40")
- Assert.Equal(new[] { 4, 6, 9 }, sortedByTo[6].FromVersions);
- Assert.Equal(40, sortedByTo[6].ToVersion);
- Assert.False(sortedByTo[6].IsRange);
- Assert.False(sortedByTo[6].ShouldAvoid);
-
- // Attribute 8: MigrationAttribute("13..17", "45")
- Assert.Equal(new[] { 13, 17 }, sortedByTo[7].FromVersions);
- Assert.Equal(45, sortedByTo[7].ToVersion);
- Assert.True(sortedByTo[7].IsRange);
- Assert.False(sortedByTo[7].ShouldAvoid);
-
- // Attribute 9: MigrationAttribute(18, 50, true)
- Assert.Equal(new[] { 18 }, sortedByTo[8].FromVersions);
- Assert.Equal(50, sortedByTo[8].ToVersion);
- Assert.False(sortedByTo[8].IsRange);
- Assert.True(sortedByTo[8].ShouldAvoid);
-
- // Attribute 10: MigrationAttribute(new int[] { 21, 23 }, 55, true)
- Assert.Equal(new[] { 21, 23 }, sortedByTo[9].FromVersions);
- Assert.Equal(55, sortedByTo[9].ToVersion);
- Assert.False(sortedByTo[9].IsRange);
- Assert.True(sortedByTo[9].ShouldAvoid);
- }
-
- #endregion
-}
diff --git a/Tests/SmartMigrations.Test/SmartMigrations.Test.csproj b/Tests/SmartMigrations.Test/SmartMigrations.Test.csproj
index d98741c..e2ddfdb 100644
--- a/Tests/SmartMigrations.Test/SmartMigrations.Test.csproj
+++ b/Tests/SmartMigrations.Test/SmartMigrations.Test.csproj
@@ -10,4 +10,8 @@
+
+
+
+