using System.Threading.Tasks; using Xunit; using Yh.Platform.AppAuth; namespace Yh.Platform.AppAuth.Tests; public class SignCanonicalTests { [Theory] [InlineData("b=2&a=1", "a=1&b=2")] [InlineData("a=1", "a=1")] [InlineData("", "")] [InlineData("groupId=9&withSub=true", "groupId=9&withSub=true")] public void SortRawQuery_键值整串排序(string raw, string expected) { Assert.Equal(expected, SignCanonical.SortRawQuery(raw)); } [Fact] public void SortRawQuery_URL解码后排序() { // %20 与 + 均解码为空格,解码后按 "k=v" 整串排序 Assert.Equal("a b=1&a b=2", SignCanonical.SortRawQuery("a%20b=1&a+b=2")); } [Fact] public void BuildTarget_无query只取path() { Assert.Equal("/userbase/oapi/user/byId", SignCanonical.BuildTarget(new Uri("http://host:8080/userbase/oapi/user/byId"))); Assert.Equal("/userbase/oapi/user/byId?id=123", SignCanonical.BuildTarget(new Uri("http://host:8080/userbase/oapi/user/byId?id=123"))); } [Fact] public void BuildTarget_query乱序归一化() { Assert.Equal("/p?a=1&b=2", SignCanonical.BuildTarget(new Uri("http://h/p?b=2&a=1"))); } [Fact] public async Task MemoryReplayGuard_同三元组只放行一次() { var guard = new MemoryReplayGuard(); Assert.True(await guard.TryBeginAsync("100476", "1700000000000", "n1")); Assert.False(await guard.TryBeginAsync("100476", "1700000000000", "n1")); Assert.True(await guard.TryBeginAsync("100476", "1700000000000", "n2")); Assert.True(await guard.TryBeginAsync("100477", "1700000000000", "n1")); } }