diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateSuffixVersionStrategy.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateSuffixVersionStrategy.cs deleted file mode 100644 index 5dc6d9eb3..000000000 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateSuffixVersionStrategy.cs +++ /dev/null @@ -1,112 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using System.Globalization; -using Microsoft.Extensions.Options; - -namespace Dapr.Workflow.Versioning; - -/// -/// Strategy that derives a date-based version from a trailing suffix -/// (for example, MyWorkflow20260212 with format yyyyMMdd). -/// -public sealed class DateSuffixVersionStrategy(IOptionsMonitor? optionsMonitor = null) - : IWorkflowVersionStrategy, IWorkflowVersionStrategyContextConsumer -{ - private DateSuffixVersionStrategyOptions _options = new(); - - /// - public void Configure(WorkflowVersionStrategyContext context) - { - var optionsName = string.IsNullOrWhiteSpace(context.OptionsName) - ? Options.DefaultName - : context.OptionsName; - - if (optionsMonitor is not null) - { - _options = optionsMonitor.Get(optionsName); - } - } - - /// - public bool TryParse(string typeName, out string canonicalName, out string version) - { - canonicalName = string.Empty; - version = string.Empty; - - if (string.IsNullOrWhiteSpace(typeName)) - return false; - - var format = string.IsNullOrWhiteSpace(_options.DateFormat) ? "yyyyMMdd" : _options.DateFormat; - if (typeName.Length <= format.Length) - return ApplyNoSuffix(typeName, out canonicalName, out version); - - var suffix = typeName.Substring(typeName.Length - format.Length); - if (!TryParseDate(suffix, format, out _)) - return ApplyNoSuffix(typeName, out canonicalName, out version); - - canonicalName = typeName.Substring(0, typeName.Length - format.Length); - if (string.IsNullOrEmpty(canonicalName)) - return false; - - version = suffix; - return true; - } - - /// - public int Compare(string? v1, string? v2) - { - if (ReferenceEquals(v1, v2)) return 0; - if (v1 is null) return -1; - if (v2 is null) return 1; - - var format = string.IsNullOrWhiteSpace(_options.DateFormat) ? "yyyyMMdd" : _options.DateFormat; - var ok1 = TryParseDate(v1.Trim(), format, out var d1); - var ok2 = TryParseDate(v2.Trim(), format, out var d2); - - switch (ok1) - { - case true when ok2: - return d1.CompareTo(d2); - case true: - return 1; - } - - if (ok2) return -1; - - return StringComparer.Ordinal.Compare(v1, v2); - } - - private bool ApplyNoSuffix(string typeName, out string canonicalName, out string version) - { - canonicalName = string.Empty; - version = string.Empty; - - if (!_options.AllowNoSuffix) - return false; - - canonicalName = typeName; - version = string.IsNullOrWhiteSpace(_options.DefaultVersion) ? "0" : _options.DefaultVersion; - return true; - } - - private static bool TryParseDate(string value, string format, out DateTime date) - { - return DateTime.TryParseExact( - value, - format, - CultureInfo.InvariantCulture, - DateTimeStyles.None, - out date); - } -} diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateVersionStrategy.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateVersionStrategy.cs new file mode 100644 index 000000000..ca655830f --- /dev/null +++ b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateVersionStrategy.cs @@ -0,0 +1,177 @@ +// ------------------------------------------------------------------------ +// Copyright 2026 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using System.Globalization; +using Microsoft.Extensions.Options; + +namespace Dapr.Workflow.Versioning; + +/// +/// Strategy that derives a date-based version from a trailing suffix +/// (for example, MyWorkflow20260212 with format yyyyMMdd). +/// +public sealed class DateVersionStrategy(IOptionsMonitor? optionsMonitor = null) + : IWorkflowVersionStrategy, IWorkflowVersionStrategyContextConsumer +{ + private DateVersionStrategyOptions _options = new(); + + /// + public void Configure(WorkflowVersionStrategyContext context) + { + var optionsName = string.IsNullOrWhiteSpace(context.OptionsName) + ? Options.DefaultName + : context.OptionsName; + + if (optionsMonitor is not null) + { + _options = optionsMonitor.Get(optionsName); + } + } + + /// + public bool TryParse(string typeName, out string canonicalName, out string version) + { + canonicalName = string.Empty; + version = string.Empty; + + if (string.IsNullOrWhiteSpace(typeName)) + return false; + + var format = string.IsNullOrWhiteSpace(_options.DateFormat) ? "yyyyMMdd" : _options.DateFormat; + var suffixLength = GetFormattedLength(format); + var prefix = _options.Prefix ?? string.Empty; + var comparison = _options.IgnorePrefixCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + var totalSuffixLength = suffixLength + prefix.Length; + if (typeName.Length <= totalSuffixLength) + return ApplyNoSuffix(typeName, prefix, comparison, out canonicalName, out version); + + var suffixStart = typeName.Length - suffixLength; + var dateSuffix = typeName.Substring(suffixStart, suffixLength); + if (!TryParseDate(dateSuffix, format, _options.IgnorePrefixCase, out _)) + return ApplyNoSuffix(typeName, prefix, comparison, out canonicalName, out version); + + if (!string.IsNullOrEmpty(prefix)) + { + var prefixStart = suffixStart - prefix.Length; + if (prefixStart < 1) + return false; + + var candidatePrefix = typeName.Substring(prefixStart, prefix.Length); + if (!string.Equals(candidatePrefix, prefix, comparison)) + return false; + + canonicalName = typeName.Substring(0, prefixStart); + } + else + { + canonicalName = typeName.Substring(0, suffixStart); + } + + if (string.IsNullOrEmpty(canonicalName)) + return false; + + version = dateSuffix; + return true; + } + + /// + public int Compare(string? v1, string? v2) + { + if (ReferenceEquals(v1, v2)) return 0; + if (v1 is null) return -1; + if (v2 is null) return 1; + + var format = string.IsNullOrWhiteSpace(_options.DateFormat) ? "yyyyMMdd" : _options.DateFormat; + var ok1 = TryParseDate(v1.Trim(), format, _options.IgnorePrefixCase, out var d1); + var ok2 = TryParseDate(v2.Trim(), format, _options.IgnorePrefixCase, out var d2); + + switch (ok1) + { + case true when ok2: + return d1.CompareTo(d2); + case true: + return 1; + } + + if (ok2) return -1; + + return StringComparer.Ordinal.Compare(v1, v2); + } + + private bool ApplyNoSuffix( + string typeName, + string prefix, + StringComparison comparison, + out string canonicalName, + out string version) + { + canonicalName = string.Empty; + version = string.Empty; + + if (!_options.AllowNoSuffix) + return false; + + if (!string.IsNullOrEmpty(prefix) && typeName.EndsWith(prefix, comparison)) + return false; + + canonicalName = typeName; + version = string.IsNullOrWhiteSpace(_options.DefaultVersion) ? "0" : _options.DefaultVersion; + return true; + } + + private static bool TryParseDate(string value, string format, bool ignorePrefixCase, out DateTime date) + { + if (DateTime.TryParseExact( + value, + format, + CultureInfo.InvariantCulture, + DateTimeStyles.None, + out date)) + { + return true; + } + + if (!ignorePrefixCase) + return false; + + var upper = value.ToUpperInvariant(); + if (!string.Equals(upper, value, StringComparison.Ordinal) && + DateTime.TryParseExact( + upper, + format, + CultureInfo.InvariantCulture, + DateTimeStyles.None, + out date)) + { + return true; + } + + var lower = value.ToLowerInvariant(); + if (!string.Equals(lower, value, StringComparison.Ordinal)) + { + return DateTime.TryParseExact( + lower, + format, + CultureInfo.InvariantCulture, + DateTimeStyles.None, + out date); + } + + return false; + } + + private static int GetFormattedLength(string format) + { + return DateTime.UnixEpoch.ToString(format, CultureInfo.InvariantCulture).Length; + } +} diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateSuffixVersionStrategyOptions.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateVersionStrategyOptions.cs similarity index 72% rename from src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateSuffixVersionStrategyOptions.cs rename to src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateVersionStrategyOptions.cs index 454206779..0c3e92a8f 100644 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateSuffixVersionStrategyOptions.cs +++ b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DateVersionStrategyOptions.cs @@ -14,9 +14,9 @@ namespace Dapr.Workflow.Versioning; /// -/// Options for . +/// Options for . /// -public sealed class DateSuffixVersionStrategyOptions +public sealed class DateVersionStrategyOptions { /// /// Gets or sets the date format expected at the end of the workflow type name. @@ -24,6 +24,17 @@ public sealed class DateSuffixVersionStrategyOptions /// public string DateFormat { get; set; } = "yyyyMMdd"; + /// + /// Gets or sets the prefix expected before the date suffix (for example, "V" in MyWorkflowV20260212). + /// Set to an empty string to require no prefix. + /// + public string Prefix { get; set; } = string.Empty; + + /// + /// Gets or sets a value indicating whether prefix matching ignores case. + /// + public bool IgnorePrefixCase { get; set; } + /// /// Gets or sets a value indicating whether names without a date suffix are allowed. /// When enabled, the default version is applied. diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DelimitedSuffixVersionStrategy.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DelimitedSuffixVersionStrategy.cs deleted file mode 100644 index 02dbd17a2..000000000 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DelimitedSuffixVersionStrategy.cs +++ /dev/null @@ -1,104 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using System.Globalization; -using Microsoft.Extensions.Options; - -namespace Dapr.Workflow.Versioning; - -/// -/// Strategy that derives the version from a delimiter-separated suffix (for example, MyWorkflow-1). -/// -public sealed class DelimitedSuffixVersionStrategy( - IOptionsMonitor? optionsMonitor = null) - : IWorkflowVersionStrategy, IWorkflowVersionStrategyContextConsumer -{ - private DelimitedSuffixVersionStrategyOptions _options = new(); - - /// - public void Configure(WorkflowVersionStrategyContext context) - { - var optionsName = string.IsNullOrWhiteSpace(context.OptionsName) - ? Options.DefaultName - : context.OptionsName; - - if (optionsMonitor is not null) - { - _options = optionsMonitor.Get(optionsName); - } - } - - /// - public bool TryParse(string typeName, out string canonicalName, out string version) - { - canonicalName = string.Empty; - version = string.Empty; - - if (string.IsNullOrWhiteSpace(typeName)) - return false; - - var delimiter = _options.Delimiter ?? string.Empty; - if (delimiter.Length == 0) - return false; - - var comparison = _options.IgnoreDelimiterCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; - var delimiterIndex = typeName.LastIndexOf(delimiter, comparison); - - if (delimiterIndex < 0) - { - if (_options.AllowNoSuffix) - { - canonicalName = typeName; - version = string.IsNullOrWhiteSpace(_options.DefaultVersion) ? "0" : _options.DefaultVersion; - return true; - } - - return false; - } - - var versionStart = delimiterIndex + delimiter.Length; - if (delimiterIndex == 0 || versionStart >= typeName.Length) - return false; - - canonicalName = typeName[..delimiterIndex]; - version = typeName[versionStart..]; - - return !string.IsNullOrEmpty(canonicalName) && !string.IsNullOrEmpty(version); - } - - /// - public int Compare(string? v1, string? v2) - { - if (ReferenceEquals(v1, v2)) return 0; - if (v1 is null) return -1; - if (v2 is null) return 1; - - var s1 = v1.Trim(); - var s2 = v2.Trim(); - - var ok1 = long.TryParse(s1, NumberStyles.None, CultureInfo.InvariantCulture, out var n1); - var ok2 = long.TryParse(s2, NumberStyles.None, CultureInfo.InvariantCulture, out var n2); - - switch (ok1) - { - case true when ok2: - return n1.CompareTo(n2); - case true: - return 1; - } - - if (ok2) return -1; - - return StringComparer.Ordinal.Compare(s1, s2); - } -} diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DelimitedSuffixVersionStrategyOptions.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DelimitedSuffixVersionStrategyOptions.cs deleted file mode 100644 index 713ac8778..000000000 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/DelimitedSuffixVersionStrategyOptions.cs +++ /dev/null @@ -1,41 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -namespace Dapr.Workflow.Versioning; - -/// -/// Options for . -/// -public sealed class DelimitedSuffixVersionStrategyOptions -{ - /// - /// Gets or sets the delimiter separating the canonical name from the version. - /// - public string Delimiter { get; set; } = "-"; - - /// - /// Gets or sets a value indicating whether delimiter matching ignores case. - /// - public bool IgnoreDelimiterCase { get; set; } - - /// - /// Gets or sets a value indicating whether names without a delimiter are allowed. - /// When enabled, the default version is applied. - /// - public bool AllowNoSuffix { get; set; } - - /// - /// Gets or sets the default version used when no suffix is present. - /// - public string DefaultVersion { get; set; } = "0"; -} diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ExplicitVersionStrategy.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ExplicitVersionStrategy.cs deleted file mode 100644 index d3a899db9..000000000 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ExplicitVersionStrategy.cs +++ /dev/null @@ -1,63 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using Microsoft.Extensions.Options; - -namespace Dapr.Workflow.Versioning; - -/// -/// Strategy that requires versions to be supplied explicitly via . -/// -public sealed class ExplicitVersionStrategy(IOptionsMonitor? optionsMonitor = null) - : IWorkflowVersionStrategy, IWorkflowVersionStrategyContextConsumer -{ - private ExplicitVersionStrategyOptions _options = new(); - - /// - public void Configure(WorkflowVersionStrategyContext context) - { - var optionsName = string.IsNullOrWhiteSpace(context.OptionsName) - ? Options.DefaultName - : context.OptionsName; - - if (optionsMonitor is not null) - { - _options = optionsMonitor.Get(optionsName); - } - } - - /// - public bool TryParse(string typeName, out string canonicalName, out string version) - { - canonicalName = string.Empty; - version = string.Empty; - - if (!_options.AllowMissingVersion || string.IsNullOrWhiteSpace(typeName)) - return false; - - canonicalName = typeName; - version = string.IsNullOrWhiteSpace(_options.DefaultVersion) ? "0" : _options.DefaultVersion; - return true; - } - - /// - public int Compare(string? v1, string? v2) - { - if (ReferenceEquals(v1, v2)) return 0; - if (v1 is null) return -1; - if (v2 is null) return 1; - - var comparer = _options.IgnoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal; - return comparer.Compare(v1, v2); - } -} diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ExplicitVersionStrategyOptions.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ExplicitVersionStrategyOptions.cs deleted file mode 100644 index 57dd04f82..000000000 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ExplicitVersionStrategyOptions.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -namespace Dapr.Workflow.Versioning; - -/// -/// Options for . -/// -public sealed class ExplicitVersionStrategyOptions -{ - /// - /// Gets or sets a value indicating whether parsing should be allowed when no explicit version is supplied. - /// - public bool AllowMissingVersion { get; set; } - - /// - /// Gets or sets the default version used when no explicit version is supplied and parsing is allowed. - /// - public string DefaultVersion { get; set; } = "0"; - - /// - /// Gets or sets a value indicating whether version comparisons ignore case. - /// - public bool IgnoreCase { get; set; } -} diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/NumericVersionStrategy.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/NumericVersionStrategy.cs index d7e71e864..0af9ef3ed 100644 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/NumericVersionStrategy.cs +++ b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/NumericVersionStrategy.cs @@ -18,7 +18,7 @@ namespace Dapr.Workflow.Versioning; /// /// Strategy that derives a numeric version from a trailing suffix with an optional prefix -/// (for example, MyWorkflowV1 with prefix V). +/// (for example, MyWorkflowV1 with prefix V), with optional zero-padding. /// public sealed class NumericVersionStrategy : IWorkflowVersionStrategy, IWorkflowVersionStrategyContextConsumer { @@ -72,6 +72,10 @@ public bool TryParse(string typeName, out string canonicalName, out string versi return false; } + var digitsLength = typeName.Length - digitsStart; + if (_options.ZeroPad && _options.Width > 0 && digitsLength != _options.Width) + return false; + if (!string.IsNullOrEmpty(prefix)) { var prefixStart = digitsStart - prefix.Length; diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/NumericVersionStrategyOptions.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/NumericVersionStrategyOptions.cs index ca5ed60c5..b589e0c05 100644 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/NumericVersionStrategyOptions.cs +++ b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/NumericVersionStrategyOptions.cs @@ -35,6 +35,18 @@ public sealed class NumericVersionStrategyOptions /// public bool AllowNoSuffix { get; set; } = true; + /// + /// Gets or sets a value indicating whether numeric suffixes must use zero-padding. + /// When enabled, the numeric suffix must match the configured . + /// + public bool ZeroPad { get; set; } + + /// + /// Gets or sets the required width for the numeric suffix when zero-padding is enabled. + /// Set to 0 to allow any width. + /// + public int Width { get; set; } = 4; + /// /// Gets or sets the default version used when no suffix is present. /// diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ZeroPaddedNumericVersionStrategy.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ZeroPaddedNumericVersionStrategy.cs deleted file mode 100644 index 363b84fd9..000000000 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ZeroPaddedNumericVersionStrategy.cs +++ /dev/null @@ -1,133 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using System.Globalization; -using Microsoft.Extensions.Options; - -namespace Dapr.Workflow.Versioning; - -/// -/// Strategy that derives a numeric version from a zero-padded trailing suffix (for example, MyWorkflow0001). -/// -public sealed class ZeroPaddedNumericVersionStrategy( - IOptionsMonitor? optionsMonitor = null) - : IWorkflowVersionStrategy, IWorkflowVersionStrategyContextConsumer -{ - private ZeroPaddedNumericVersionStrategyOptions _options = new(); - - /// - public void Configure(WorkflowVersionStrategyContext context) - { - var optionsName = string.IsNullOrWhiteSpace(context.OptionsName) - ? Options.DefaultName - : context.OptionsName; - - if (optionsMonitor is not null) - { - _options = optionsMonitor.Get(optionsName); - } - } - - /// - public bool TryParse(string typeName, out string canonicalName, out string version) - { - canonicalName = string.Empty; - version = string.Empty; - - if (string.IsNullOrWhiteSpace(typeName)) - return false; - - var prefix = _options.SuffixPrefix ?? string.Empty; - var comparison = _options.IgnorePrefixCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; - - var digitsStart = FindTrailingDigits(typeName); - if (digitsStart < 0) - { - if (_options.AllowNoSuffix && !EndsWithPrefix(typeName, prefix, comparison)) - { - canonicalName = typeName; - version = string.IsNullOrWhiteSpace(_options.DefaultVersion) ? "0" : _options.DefaultVersion; - return true; - } - - return false; - } - - var digitsLength = typeName.Length - digitsStart; - if (_options.Width > 0 && digitsLength != _options.Width) - return false; - - if (!string.IsNullOrEmpty(prefix)) - { - var prefixStart = digitsStart - prefix.Length; - if (prefixStart < 1) - return false; - - var candidatePrefix = typeName.Substring(prefixStart, prefix.Length); - if (!string.Equals(candidatePrefix, prefix, comparison)) - return false; - - canonicalName = typeName.Substring(0, prefixStart); - } - else - { - if (digitsStart < 1) - return false; - - canonicalName = typeName.Substring(0, digitsStart); - } - - version = typeName.Substring(digitsStart); - return !string.IsNullOrEmpty(canonicalName) && !string.IsNullOrEmpty(version); - } - - /// - public int Compare(string? v1, string? v2) - { - if (ReferenceEquals(v1, v2)) return 0; - if (v1 is null) return -1; - if (v2 is null) return 1; - - var s1 = v1.Trim(); - var s2 = v2.Trim(); - - var ok1 = long.TryParse(s1, NumberStyles.None, CultureInfo.InvariantCulture, out var n1); - var ok2 = long.TryParse(s2, NumberStyles.None, CultureInfo.InvariantCulture, out var n2); - - switch (ok1) - { - case true when ok2: - return n1.CompareTo(n2); - case true: - return 1; - } - - if (ok2) return -1; - - return StringComparer.Ordinal.Compare(s1, s2); - } - - private static int FindTrailingDigits(string value) - { - var i = value.Length - 1; - while (i >= 0 && value[i] >= '0' && value[i] <= '9') - { - i--; - } - - return i == value.Length - 1 ? -1 : i + 1; - } - - private static bool EndsWithPrefix(string value, string prefix, StringComparison comparison) => - !string.IsNullOrEmpty(prefix) && value.EndsWith(prefix, comparison); -} diff --git a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ZeroPaddedNumericVersionStrategyOptions.cs b/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ZeroPaddedNumericVersionStrategyOptions.cs deleted file mode 100644 index c64ca9bdb..000000000 --- a/src/Dapr.Workflow.Versioning.Runtime/VersionStrategies/ZeroPaddedNumericVersionStrategyOptions.cs +++ /dev/null @@ -1,47 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -namespace Dapr.Workflow.Versioning; - -/// -/// Options for . -/// -public sealed class ZeroPaddedNumericVersionStrategyOptions -{ - /// - /// Gets or sets the prefix used before the numeric suffix (for example, "V" in MyWorkflowV0001). - /// Set to an empty string to allow a raw numeric suffix. - /// - public string SuffixPrefix { get; set; } = string.Empty; - - /// - /// Gets or sets a value indicating whether prefix matching ignores case. - /// - public bool IgnorePrefixCase { get; set; } - - /// - /// Gets or sets the required width for the numeric suffix. Set to 0 to allow any width. - /// - public int Width { get; set; } = 4; - - /// - /// Gets or sets a value indicating whether names without a numeric suffix are allowed. - /// When enabled, the default version is applied. - /// - public bool AllowNoSuffix { get; set; } - - /// - /// Gets or sets the default version used when no suffix is present. - /// - public string DefaultVersion { get; set; } = "0"; -} diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/DateSuffixVersionStrategyOptionsTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/DateVersionStrategyOptionsTests.cs similarity index 83% rename from test/Dapr.Workflow.Versioning.Runtime.Test/DateSuffixVersionStrategyOptionsTests.cs rename to test/Dapr.Workflow.Versioning.Runtime.Test/DateVersionStrategyOptionsTests.cs index e86bdb9de..1032683a2 100644 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/DateSuffixVersionStrategyOptionsTests.cs +++ b/test/Dapr.Workflow.Versioning.Runtime.Test/DateVersionStrategyOptionsTests.cs @@ -13,14 +13,16 @@ namespace Dapr.Workflow.Versioning.Runtime.Test; -public class DateSuffixVersionStrategyOptionsTests +public class DateVersionStrategyOptionsTests { [Fact] public void Defaults_ShouldMatchExpectedValues() { - var options = new DateSuffixVersionStrategyOptions(); + var options = new DateVersionStrategyOptions(); Assert.Equal("yyyyMMdd", options.DateFormat); + Assert.Equal(string.Empty, options.Prefix); + Assert.False(options.IgnorePrefixCase); Assert.False(options.AllowNoSuffix); Assert.Equal("0", options.DefaultVersion); } diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/DateSuffixVersionStrategyTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/DateVersionStrategyTests.cs similarity index 58% rename from test/Dapr.Workflow.Versioning.Runtime.Test/DateSuffixVersionStrategyTests.cs rename to test/Dapr.Workflow.Versioning.Runtime.Test/DateVersionStrategyTests.cs index 17f67a76f..d8f352b74 100644 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/DateSuffixVersionStrategyTests.cs +++ b/test/Dapr.Workflow.Versioning.Runtime.Test/DateVersionStrategyTests.cs @@ -16,12 +16,12 @@ namespace Dapr.Workflow.Versioning.Runtime.Test; -public class DateSuffixVersionStrategyTests +public class DateVersionStrategyTests { [Fact] public void TryParse_ShouldParseDefaultFormat() { - var strategy = new DateSuffixVersionStrategy(); + var strategy = new DateVersionStrategy(); var parsed = strategy.TryParse("MyWorkflow20260212", out var canonical, out var version); @@ -33,7 +33,7 @@ public void TryParse_ShouldParseDefaultFormat() [Fact] public void TryParse_ShouldRejectNoSuffix_ByDefault() { - var strategy = new DateSuffixVersionStrategy(); + var strategy = new DateVersionStrategy(); Assert.False(strategy.TryParse("MyWorkflow", out _, out _)); } @@ -42,13 +42,13 @@ public void TryParse_ShouldRejectNoSuffix_ByDefault() public void TryParse_ShouldAllowNoSuffix_WhenEnabled() { var services = new ServiceCollection(); - services.AddOptions(Options.DefaultName) + services.AddOptions(Options.DefaultName) .Configure(o => o.AllowNoSuffix = true); using var provider = services.BuildServiceProvider(); var factory = new DefaultWorkflowVersionStrategyFactory(); - var strategy = (DateSuffixVersionStrategy)factory.Create( - typeof(DateSuffixVersionStrategy), + var strategy = (DateVersionStrategy)factory.Create( + typeof(DateVersionStrategy), canonicalName: "Orders", optionsName: null, services: provider); @@ -62,13 +62,13 @@ public void TryParse_ShouldAllowNoSuffix_WhenEnabled() public void TryParse_ShouldUseNamedFormatFromFactory() { var services = new ServiceCollection(); - services.AddOptions("custom") + services.AddOptions("custom") .Configure(o => o.DateFormat = "yyyy-MM-dd"); using var provider = services.BuildServiceProvider(); var factory = new DefaultWorkflowVersionStrategyFactory(); - var strategy = (DateSuffixVersionStrategy)factory.Create( - typeof(DateSuffixVersionStrategy), + var strategy = (DateVersionStrategy)factory.Create( + typeof(DateVersionStrategy), canonicalName: "Orders", optionsName: "custom", services: provider); @@ -78,18 +78,68 @@ public void TryParse_ShouldUseNamedFormatFromFactory() Assert.Equal("2026-02-12", version); } + [Fact] + public void TryParse_ShouldIgnorePrefixCase_WhenConfigured() + { + var services = new ServiceCollection(); + services.AddOptions("custom") + .Configure(o => + { + o.DateFormat = "yyyyMMdd"; + o.Prefix = "v"; + o.IgnorePrefixCase = true; + }); + + using var provider = services.BuildServiceProvider(); + var factory = new DefaultWorkflowVersionStrategyFactory(); + var strategy = (DateVersionStrategy)factory.Create( + typeof(DateVersionStrategy), + canonicalName: "Orders", + optionsName: "custom", + services: provider); + + Assert.True(strategy.TryParse("OrdersV20260212", out var canonical, out var version)); + Assert.Equal("Orders", canonical); + Assert.Equal("20260212", version); + } + + [Fact] + public void TryParse_ShouldRequirePrefix_WhenConfigured() + { + var services = new ServiceCollection(); + services.AddOptions("custom") + .Configure(o => + { + o.DateFormat = "yyyyMMdd"; + o.Prefix = "v"; + }); + + using var provider = services.BuildServiceProvider(); + var factory = new DefaultWorkflowVersionStrategyFactory(); + var strategy = (DateVersionStrategy)factory.Create( + typeof(DateVersionStrategy), + canonicalName: "Orders", + optionsName: "custom", + services: provider); + + Assert.False(strategy.TryParse("Orders20260212", out _, out _)); + Assert.True(strategy.TryParse("Ordersv20260212", out var canonical, out var version)); + Assert.Equal("Orders", canonical); + Assert.Equal("20260212", version); + } + [Fact] public void TryParse_ShouldReadFromDate() { var services = new ServiceCollection(); const string optionsName = "workflow-defaults"; - services.AddOptions(optionsName) + services.AddOptions(optionsName) .Configure(o => o.DateFormat = "yyyyMMddHHmmss"); using var provider = services.BuildServiceProvider(); var factory = new DefaultWorkflowVersionStrategyFactory(); - var strategy = (DateSuffixVersionStrategy)factory.Create( - typeof(DateSuffixVersionStrategy), + var strategy = (DateVersionStrategy)factory.Create( + typeof(DateVersionStrategy), canonicalName: "", optionsName: optionsName, services: provider); @@ -102,7 +152,7 @@ public void TryParse_ShouldReadFromDate() [Fact] public void Compare_ShouldOrderByDate() { - var strategy = new DateSuffixVersionStrategy(); + var strategy = new DateVersionStrategy(); Assert.True(strategy.Compare("20260101", "20261231") < 0); Assert.True(strategy.Compare("20261231", "20260101") > 0); @@ -111,7 +161,7 @@ public void Compare_ShouldOrderByDate() [Fact] public void Compare_ShouldPreferValidDateOverInvalid() { - var strategy = new DateSuffixVersionStrategy(); + var strategy = new DateVersionStrategy(); Assert.True(strategy.Compare("20261231", "not-a-date") > 0); Assert.True(strategy.Compare("bad", "20260101") < 0); diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/DelimitedSuffixVersionStrategyOptionsTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/DelimitedSuffixVersionStrategyOptionsTests.cs deleted file mode 100644 index b922779b7..000000000 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/DelimitedSuffixVersionStrategyOptionsTests.cs +++ /dev/null @@ -1,28 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -namespace Dapr.Workflow.Versioning.Runtime.Test; - -public class DelimitedSuffixVersionStrategyOptionsTests -{ - [Fact] - public void Defaults_ShouldMatchExpectedValues() - { - var options = new DelimitedSuffixVersionStrategyOptions(); - - Assert.Equal("-", options.Delimiter); - Assert.False(options.IgnoreDelimiterCase); - Assert.False(options.AllowNoSuffix); - Assert.Equal("0", options.DefaultVersion); - } -} diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/DelimitedSuffixVersionStrategyTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/DelimitedSuffixVersionStrategyTests.cs deleted file mode 100644 index c008a2b5f..000000000 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/DelimitedSuffixVersionStrategyTests.cs +++ /dev/null @@ -1,60 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace Dapr.Workflow.Versioning.Runtime.Test; - -public class DelimitedSuffixVersionStrategyTests -{ - [Fact] - public void TryParse_ShouldParseDelimitedSuffix() - { - var strategy = new DelimitedSuffixVersionStrategy(); - - var parsed = strategy.TryParse("Orders-2", out var canonical, out var version); - - Assert.True(parsed); - Assert.Equal("Orders", canonical); - Assert.Equal("2", version); - } - - [Fact] - public void TryParse_ShouldRejectNoSuffix_ByDefault() - { - var strategy = new DelimitedSuffixVersionStrategy(); - - Assert.False(strategy.TryParse("Orders", out _, out _)); - } - - [Fact] - public void TryParse_ShouldAllowNoSuffix_WhenConfigured() - { - var services = new ServiceCollection(); - services.AddOptions(Options.DefaultName) - .Configure(o => o.AllowNoSuffix = true); - - using var provider = services.BuildServiceProvider(); - var factory = new DefaultWorkflowVersionStrategyFactory(); - var strategy = (DelimitedSuffixVersionStrategy)factory.Create( - typeof(DelimitedSuffixVersionStrategy), - canonicalName: "Orders", - optionsName: null, - services: provider); - - Assert.True(strategy.TryParse("Orders", out var canonical, out var version)); - Assert.Equal("Orders", canonical); - Assert.Equal("0", version); - } -} diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/ExplicitVersionStrategyOptionsTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/ExplicitVersionStrategyOptionsTests.cs deleted file mode 100644 index e6677762e..000000000 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/ExplicitVersionStrategyOptionsTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -namespace Dapr.Workflow.Versioning.Runtime.Test; - -public class ExplicitVersionStrategyOptionsTests -{ - [Fact] - public void Defaults_ShouldMatchExpectedValues() - { - var options = new ExplicitVersionStrategyOptions(); - - Assert.False(options.AllowMissingVersion); - Assert.Equal("0", options.DefaultVersion); - Assert.False(options.IgnoreCase); - } -} diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/ExplicitVersionStrategyTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/ExplicitVersionStrategyTests.cs deleted file mode 100644 index 6a9662e97..000000000 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/ExplicitVersionStrategyTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace Dapr.Workflow.Versioning.Runtime.Test; - -public class ExplicitVersionStrategyTests -{ - [Fact] - public void TryParse_ShouldRejectMissingVersion_ByDefault() - { - var strategy = new ExplicitVersionStrategy(); - - Assert.False(strategy.TryParse("Orders", out _, out _)); - } - - [Fact] - public void TryParse_ShouldAllowMissingVersion_WhenConfigured() - { - var services = new ServiceCollection(); - services.AddOptions(Options.DefaultName) - .Configure(o => o.AllowMissingVersion = true); - - using var provider = services.BuildServiceProvider(); - var factory = new DefaultWorkflowVersionStrategyFactory(); - var strategy = (ExplicitVersionStrategy)factory.Create( - typeof(ExplicitVersionStrategy), - canonicalName: "Orders", - optionsName: null, - services: provider); - - Assert.True(strategy.TryParse("Orders", out var canonical, out var version)); - Assert.Equal("Orders", canonical); - Assert.Equal("0", version); - } -} diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/NumericVersionStrategyOptionsTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/NumericVersionStrategyOptionsTests.cs index cb7cedd73..2a051d396 100644 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/NumericVersionStrategyOptionsTests.cs +++ b/test/Dapr.Workflow.Versioning.Runtime.Test/NumericVersionStrategyOptionsTests.cs @@ -23,6 +23,8 @@ public void Defaults_ShouldMatchExpectedValues() Assert.Equal("V", options.SuffixPrefix); Assert.False(options.IgnorePrefixCase); Assert.True(options.AllowNoSuffix); + Assert.False(options.ZeroPad); + Assert.Equal(4, options.Width); Assert.Equal("0", options.DefaultVersion); } } diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/NumericVersionStrategyTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/NumericVersionStrategyTests.cs index 67725c2e5..e486a77d7 100644 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/NumericVersionStrategyTests.cs +++ b/test/Dapr.Workflow.Versioning.Runtime.Test/NumericVersionStrategyTests.cs @@ -12,6 +12,7 @@ // ------------------------------------------------------------------------ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; namespace Dapr.Workflow.Versioning.Runtime.Test; @@ -51,6 +52,56 @@ public void TryParse_ShouldRejectMissingPrefix_WhenDigitsPresent() Assert.False(parsed); } + [Fact] + public void TryParse_ShouldParseWithWidth_WhenZeroPadEnabled() + { + var services = new ServiceCollection(); + services.AddOptions(Options.DefaultName) + .Configure(o => + { + o.SuffixPrefix = string.Empty; + o.ZeroPad = true; + o.Width = 4; + o.AllowNoSuffix = false; + }); + + using var provider = services.BuildServiceProvider(); + var factory = new DefaultWorkflowVersionStrategyFactory(); + var strategy = (NumericVersionStrategy)factory.Create( + typeof(NumericVersionStrategy), + canonicalName: "Orders", + optionsName: null, + services: provider); + + Assert.True(strategy.TryParse("Orders0007", out var canonical, out var version)); + Assert.Equal("Orders", canonical); + Assert.Equal("0007", version); + } + + [Fact] + public void TryParse_ShouldRejectWrongWidth_WhenZeroPadEnabled() + { + var services = new ServiceCollection(); + services.AddOptions(Options.DefaultName) + .Configure(o => + { + o.SuffixPrefix = string.Empty; + o.ZeroPad = true; + o.Width = 4; + o.AllowNoSuffix = false; + }); + + using var provider = services.BuildServiceProvider(); + var factory = new DefaultWorkflowVersionStrategyFactory(); + var strategy = (NumericVersionStrategy)factory.Create( + typeof(NumericVersionStrategy), + canonicalName: "Orders", + optionsName: null, + services: provider); + + Assert.False(strategy.TryParse("Orders007", out _, out _)); + } + [Theory] [InlineData("1", "2")] [InlineData("9", "10")] diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/WorkflowVersioningServiceCollectionExtensionsTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/WorkflowVersioningServiceCollectionExtensionsTests.cs index 4c3ffc0a2..51a3949dc 100644 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/WorkflowVersioningServiceCollectionExtensionsTests.cs +++ b/test/Dapr.Workflow.Versioning.Runtime.Test/WorkflowVersioningServiceCollectionExtensionsTests.cs @@ -24,8 +24,8 @@ public void UseDefaultWorkflowStrategy_UsesNamedOptions() services.AddDaprWorkflowVersioning(); const string optionsName = "workflow-defaults"; - services.UseDefaultWorkflowStrategy(optionsName); - services.ConfigureStrategyOptions(optionsName, o => + services.UseDefaultWorkflowStrategy(optionsName); + services.ConfigureStrategyOptions(optionsName, o => { o.DateFormat = "yyyyMMddHHmmss"; }); diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/ZeroPaddedNumericVersionStrategyOptionsTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/ZeroPaddedNumericVersionStrategyOptionsTests.cs deleted file mode 100644 index 233514c07..000000000 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/ZeroPaddedNumericVersionStrategyOptionsTests.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -namespace Dapr.Workflow.Versioning.Runtime.Test; - -public class ZeroPaddedNumericVersionStrategyOptionsTests -{ - [Fact] - public void Defaults_ShouldMatchExpectedValues() - { - var options = new ZeroPaddedNumericVersionStrategyOptions(); - - Assert.Equal(string.Empty, options.SuffixPrefix); - Assert.False(options.IgnorePrefixCase); - Assert.Equal(4, options.Width); - Assert.False(options.AllowNoSuffix); - Assert.Equal("0", options.DefaultVersion); - } -} diff --git a/test/Dapr.Workflow.Versioning.Runtime.Test/ZeroPaddedNumericVersionStrategyTests.cs b/test/Dapr.Workflow.Versioning.Runtime.Test/ZeroPaddedNumericVersionStrategyTests.cs deleted file mode 100644 index 9f3af941e..000000000 --- a/test/Dapr.Workflow.Versioning.Runtime.Test/ZeroPaddedNumericVersionStrategyTests.cs +++ /dev/null @@ -1,58 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2026 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace Dapr.Workflow.Versioning.Runtime.Test; - -public class ZeroPaddedNumericVersionStrategyTests -{ - [Fact] - public void TryParse_ShouldParseWithWidth() - { - var strategy = new ZeroPaddedNumericVersionStrategy(); - - Assert.True(strategy.TryParse("Orders0007", out var canonical, out var version)); - Assert.Equal("Orders", canonical); - Assert.Equal("0007", version); - } - - [Fact] - public void TryParse_ShouldRejectWrongWidth() - { - var strategy = new ZeroPaddedNumericVersionStrategy(); - - Assert.False(strategy.TryParse("Orders007", out _, out _)); - } - - [Fact] - public void TryParse_ShouldAllowNoSuffix_WhenConfigured() - { - var services = new ServiceCollection(); - services.AddOptions(Options.DefaultName) - .Configure(o => o.AllowNoSuffix = true); - - using var provider = services.BuildServiceProvider(); - var factory = new DefaultWorkflowVersionStrategyFactory(); - var strategy = (ZeroPaddedNumericVersionStrategy)factory.Create( - typeof(ZeroPaddedNumericVersionStrategy), - canonicalName: "Orders", - optionsName: null, - services: provider); - - Assert.True(strategy.TryParse("Orders", out var canonical, out var version)); - Assert.Equal("Orders", canonical); - Assert.Equal("0", version); - } -}