1+ namespace SqlStreamStore . HAL . Tests
2+ {
3+ using System ;
4+ using System . Collections . Generic ;
5+ using System . Linq ;
6+ using System . Net ;
7+ using System . Threading . Tasks ;
8+ using Shouldly ;
9+ using SqlStreamStore . HAL . Resources ;
10+ using Xunit ;
11+
12+ public class CanonicalUrlTests
13+ {
14+ private const string StreamId = "a-stream" ;
15+ private readonly SqlStreamStoreHalMiddlewareFixture _fixture ;
16+
17+ public CanonicalUrlTests ( )
18+ {
19+ _fixture = new SqlStreamStoreHalMiddlewareFixture ( ) ;
20+ }
21+
22+ private static IEnumerable < string > GetQueryStrings ( bool forward , bool prefetch )
23+ {
24+ IEnumerable < string [ ] > GetPermutations ( string [ ] items , int length )
25+ => length == 1
26+ ? items . Select ( item => new [ ] { item } )
27+ : GetPermutations ( items , length - 1 )
28+ . SelectMany ( permutation => items . Where ( item => ! permutation . Contains ( item ) ) ,
29+ ( t1 , t2 ) => t1 . Concat ( new [ ] { t2 } ) . ToArray ( ) )
30+ ;
31+
32+ var d = $ "d={ ( forward ? 'f' : 'b' ) } ";
33+ var m = "m=20" ;
34+ var e = prefetch ? "e" : null ;
35+ var p = "p=0" ;
36+
37+ var parameters = new [ ]
38+ {
39+ d , m , e , p
40+ } ;
41+
42+ return
43+ from set in GetPermutations ( parameters , 4 )
44+ select string . Join ( '&' , set . Where ( x => x != null ) ) ;
45+ }
46+
47+ private static IEnumerable < ( string , Uri ) > NonCanonical ( )
48+ {
49+ var formatters = new Dictionary < bool , Func < string , int , long , bool , string > >
50+ {
51+ [ true ] = LinkFormatter . FormatForwardLink ,
52+ [ false ] = LinkFormatter . FormatBackwardLink
53+ } ;
54+
55+ ( string streamId , string path ) [ ] streams =
56+ {
57+ ( StreamId , $ "/streams/{ StreamId } ") ,
58+ ( Constants . Streams . All , Constants . Streams . All )
59+ } ;
60+
61+ return
62+ from _ in streams
63+ from prefetch in new [ ] { true , false }
64+ from forward in new [ ] { true , false }
65+ let format = formatters [ forward ]
66+ let canonicalUri = format ( _ . streamId , 20 , 0 , prefetch )
67+ from queryString in GetQueryStrings ( forward , prefetch )
68+ // query strings are supposed to be case sensitive!!
69+ //.Concat(new[] { $"d={(forward ? 'F' : 'B')}&M=20&P=0{(prefetch ? "&E" : string.Empty)}" })
70+ where $ "{ _ . streamId } ?{ queryString } " != canonicalUri
71+ select ( $ "{ _ . path } ?{ queryString } ", new Uri (
72+ canonicalUri ,
73+ UriKind . Relative ) ) ;
74+ }
75+
76+ public static IEnumerable < object [ ] > NonCanonicalUriCases ( )
77+ => NonCanonical ( )
78+ . Select ( x => new object [ ] { x . Item1 , x . Item2 } )
79+ . ToArray ( ) ;
80+
81+ [ Theory , MemberData ( nameof ( NonCanonicalUriCases ) ) ]
82+ public async Task non_canonical_uri ( string requestUri , Uri expectedLocation )
83+ {
84+ using ( var response = await _fixture . HttpClient . GetAsync ( requestUri ) )
85+ {
86+ response . StatusCode . ShouldBe ( HttpStatusCode . PermanentRedirect ) ;
87+ response . Headers . Location . ShouldBe ( expectedLocation ) ;
88+ }
89+ }
90+ }
91+ }
0 commit comments