| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- using Admin.NET.Plugin.AiDOP.Infrastructure;
- using Xunit;
- namespace Admin.NET.Plugin.AiDOP.Tests.SmartOps;
- public class KpiAchievementEvaluationTests
- {
- private const string Higher = "higher_is_better";
- private const string Lower = "lower_is_better";
- [Theory]
- [InlineData(100, 100, "green", false)]
- [InlineData(99, 100, "yellow", false)]
- [InlineData(95, 100, "yellow", false)]
- [InlineData(94.99, 100, "red", false)]
- [InlineData(80, 100, "red", false)]
- [InlineData(79.99, 100, "red", true)]
- public void Higher_DefaultBoundaries(decimal current, decimal target, string status, bool blink)
- {
- AssertEval(current, target, Higher, status, blink);
- }
- [Theory]
- [InlineData(100, 100, "green", false)]
- [InlineData(100.01, 100, "yellow", false)]
- [InlineData(110, 100, "yellow", false)]
- [InlineData(110.01, 100, "red", false)]
- [InlineData(120, 100, "red", false)]
- [InlineData(120.01, 100, "red", true)]
- public void Lower_DefaultBoundaries(decimal current, decimal target, string status, bool blink)
- {
- AssertEval(current, target, Lower, status, blink);
- }
- [Theory]
- [InlineData(100, 100, "green", false)]
- [InlineData(90, 100, "yellow", false)]
- [InlineData(89.99, 100, "red", false)]
- [InlineData(70, 100, "red", false)]
- [InlineData(69.99, 100, "red", true)]
- [InlineData(80, 100, "red", false)]
- public void Higher_CustomYellow90Red70(decimal current, decimal target, string status, bool blink)
- {
- AssertEval(current, target, Higher, status, blink, 90m, 70m);
- }
- [Theory]
- [InlineData(100, 100, "green", false)]
- [InlineData(115, 100, "yellow", false)]
- [InlineData(115.01, 100, "red", false)]
- [InlineData(130, 100, "red", false)]
- [InlineData(130.01, 100, "red", true)]
- [InlineData(120, 100, "red", false)]
- public void Lower_CustomYellow115Red130(decimal current, decimal target, string status, bool blink)
- {
- AssertEval(current, target, Lower, status, blink, 115m, 130m);
- }
- [Fact]
- public void NullCurrent_SafeYellow() => AssertSafeYellow(null, 100m);
- [Fact]
- public void NullTarget_SafeYellow() => AssertSafeYellow(80m, null);
- [Fact]
- public void ZeroTarget_SafeYellow() => AssertSafeYellow(80m, 0m);
- private static void AssertSafeYellow(decimal? current, decimal? target)
- {
- var e = AidopS4KpiMerge.Evaluate(current, target, Higher);
- Assert.Equal("yellow", e.Status);
- Assert.Null(e.RatioPercent);
- Assert.False(e.IsBeyondRedThreshold);
- Assert.Equal("yellow", AidopS4KpiMerge.AchievementLevel(current, target, Higher));
- }
- [Fact]
- public void IllegalHigher_RedGreaterThanYellow_FallsBackToDefaults()
- {
- var e = AidopS4KpiMerge.Evaluate(94.99m, 100m, Higher, 90m, 95m);
- Assert.Equal("red", e.Status);
- Assert.False(e.IsBeyondRedThreshold);
- Assert.Equal(95m, e.EffectiveYellowThreshold);
- Assert.Equal(80m, e.EffectiveRedThreshold);
- }
- [Fact]
- public void IllegalHigher_YellowAbove100_FallsBackToDefaults()
- {
- var e = AidopS4KpiMerge.Evaluate(96m, 100m, Higher, 101m, 80m);
- Assert.Equal("yellow", e.Status);
- Assert.Equal(95m, e.EffectiveYellowThreshold);
- Assert.Equal(80m, e.EffectiveRedThreshold);
- }
- [Fact]
- public void IllegalLower_YellowBelow100_FallsBackToDefaults()
- {
- var e = AidopS4KpiMerge.Evaluate(105m, 100m, Lower, 90m, 120m);
- Assert.Equal("yellow", e.Status);
- Assert.Equal(110m, e.EffectiveYellowThreshold);
- Assert.Equal(120m, e.EffectiveRedThreshold);
- }
- [Fact]
- public void IllegalLower_RedLessThanYellow_FallsBackToDefaults()
- {
- var e = AidopS4KpiMerge.Evaluate(112m, 100m, Lower, 115m, 110m);
- Assert.Equal("red", e.Status);
- Assert.False(e.IsBeyondRedThreshold);
- Assert.Equal(110m, e.EffectiveYellowThreshold);
- Assert.Equal(120m, e.EffectiveRedThreshold);
- }
- [Fact]
- public void SaveRejects_IllegalHigher_RedGreaterThanYellow()
- {
- Assert.False(AidopS4KpiMerge.TryValidateThresholds(Higher, 90m, 95m, out var error));
- Assert.Equal("higher_is_better 阈值不合法,应满足 0 < RedThreshold <= YellowThreshold <= 100。", error);
- }
- [Fact]
- public void SaveRejects_IllegalHigher_YellowAbove100()
- {
- Assert.False(AidopS4KpiMerge.TryValidateThresholds(Higher, 101m, 80m, out var error));
- Assert.Contains("higher_is_better", error);
- }
- [Fact]
- public void SaveRejects_IllegalLower_YellowBelow100()
- {
- Assert.False(AidopS4KpiMerge.TryValidateThresholds(Lower, 90m, 120m, out var error));
- Assert.Equal("lower_is_better 阈值不合法,应满足 100 <= YellowThreshold <= RedThreshold。", error);
- }
- [Fact]
- public void SaveRejects_IllegalLower_RedLessThanYellow()
- {
- Assert.False(AidopS4KpiMerge.TryValidateThresholds(Lower, 115m, 110m, out var error));
- Assert.Contains("lower_is_better", error);
- }
- [Fact]
- public void SaveAllows_BothThresholdsNull()
- {
- Assert.True(AidopS4KpiMerge.TryValidateThresholds(Higher, null, null, out var error));
- Assert.Null(error);
- }
- [Fact]
- public void SaveAllows_SingleThresholdCombinedWithDefault()
- {
- Assert.True(AidopS4KpiMerge.TryValidateThresholds(Higher, 90m, null, out _));
- Assert.True(AidopS4KpiMerge.TryValidateThresholds(Lower, null, 130m, out _));
- }
- [Fact]
- public void SaveDoesNotSwap_IllegalPair()
- {
- Assert.False(AidopS4KpiMerge.TryValidateThresholds(Higher, 70m, 90m, out _));
- var e = AidopS4KpiMerge.Evaluate(75m, 100m, Higher, 70m, 90m);
- Assert.Equal(95m, e.EffectiveYellowThreshold);
- Assert.Equal(80m, e.EffectiveRedThreshold);
- }
- [Fact]
- public void AchievementLevel_MatchesEvaluateStatus()
- {
- foreach (var (current, target, dir, y, r) in new (decimal, decimal, string, decimal?, decimal?)[]
- {
- (100m, 100m, Higher, null, null),
- (79.99m, 100m, Higher, null, null),
- (120.01m, 100m, Lower, null, null),
- (69.99m, 100m, Higher, 90m, 70m),
- (94.99m, 100m, Higher, 90m, 95m)
- })
- {
- var eval = AidopS4KpiMerge.Evaluate(current, target, dir, y, r);
- Assert.Equal(eval.Status, AidopS4KpiMerge.AchievementLevel(current, target, dir, y, r));
- }
- }
- private static void AssertEval(
- decimal current,
- decimal target,
- string direction,
- string status,
- bool blink,
- decimal? yellow = null,
- decimal? red = null)
- {
- var e = AidopS4KpiMerge.Evaluate(current, target, direction, yellow, red);
- Assert.Equal(status, e.Status);
- Assert.Equal(blink, e.IsBeyondRedThreshold);
- Assert.Equal(status == "red" && blink, e.Status == "red" && e.IsBeyondRedThreshold);
- Assert.Equal(e.Status, AidopS4KpiMerge.AchievementLevel(current, target, direction, yellow, red));
- Assert.Equal(blink, AidopS4KpiMerge.IsBeyondRedThreshold(current, target, direction, yellow, red));
- }
- }
|