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+ . Concat ( new [ ] { $ "d={ ( forward ? 'F' : 'B' ) } &M=20&P=0{ ( prefetch ? "&E" : string . Empty ) } " } )
69+ where $ "{ _ . streamId } ?{ queryString } " != canonicalUri
70+ select ( $ "{ _ . path } ?{ queryString } ", new Uri (
71+ canonicalUri ,
72+ UriKind . Relative ) ) ;
73+ }
74+
75+ public static IEnumerable < object [ ] > NonCanonicalUriCases ( )
76+ => NonCanonical ( )
77+ . Select ( x => new object [ ] { x . Item1 , x . Item2 } )
78+ . ToArray ( ) ;
79+
80+ [ Theory , MemberData ( nameof ( NonCanonicalUriCases ) ) ]
81+ public async Task non_canonical_uri ( string requestUri , Uri expectedLocation )
82+ {
83+ using ( var response = await _fixture . HttpClient . GetAsync ( requestUri ) )
84+ {
85+ response . StatusCode . ShouldBe ( HttpStatusCode . PermanentRedirect ) ;
86+ response . Headers . Location . ShouldBe ( expectedLocation ) ;
87+ }
88+ }
89+ }
90+ }
0 commit comments