22using System . Linq ;
33using LibGit2Sharp . Tests . TestHelpers ;
44using Xunit ;
5+ using Xunit . Extensions ;
56
67namespace LibGit2Sharp . Tests
78{
@@ -35,6 +36,20 @@ public void CanIterateOverRefSpecs()
3536 }
3637 }
3738
39+ [ Fact ]
40+ public void FetchAndPushRefSpecsComposeRefSpecs ( )
41+ {
42+ var path = CloneStandardTestRepo ( ) ;
43+ using ( var repo = new Repository ( path ) )
44+ {
45+ var remote = repo . Network . Remotes [ "origin" ] ;
46+
47+ var totalRefSpecs = remote . FetchRefSpecs . Concat ( remote . PushRefSpecs ) ;
48+ var orderedRefSpecs = remote . RefSpecs . OrderBy ( r => r . Direction == RefSpecDirection . Fetch ? 0 : 1 ) ;
49+ Assert . Equal ( orderedRefSpecs , totalRefSpecs ) ;
50+ }
51+ }
52+
3853 [ Fact ]
3954 public void CanReadRefSpecDetails ( )
4055 {
@@ -51,5 +66,130 @@ public void CanReadRefSpecDetails()
5166 Assert . Equal ( true , refSpec . ForceUpdate ) ;
5267 }
5368 }
69+
70+ [ Theory ]
71+ [ InlineData ( new string [ ] { "+refs/tags/*:refs/tags/*" } , new string [ ] { "refs/heads/*:refs/remotes/test/*" , "+refs/abc:refs/def" } ) ]
72+ [ InlineData ( new string [ ] { "+refs/abc/x:refs/def/x" , "refs/def:refs/ghi" } , new string [ 0 ] ) ]
73+ [ InlineData ( new string [ 0 ] , new string [ ] { "refs/ghi:refs/jkl/mno" } ) ]
74+ public void CanReplaceRefSpecs ( string [ ] newFetchRefSpecs , string [ ] newPushRefSpecs )
75+ {
76+ var path = CloneStandardTestRepo ( ) ;
77+ using ( var repo = new Repository ( path ) )
78+ {
79+ var remote = repo . Network . Remotes [ "origin" ] ;
80+ var oldRefSpecs = remote . RefSpecs . ToList ( ) ;
81+
82+ var newRemote = repo . Network . Remotes . Update ( remote ,
83+ r => r . FetchRefSpecs = newFetchRefSpecs , r => r . PushRefSpecs = newPushRefSpecs ) ;
84+
85+ Assert . Equal ( oldRefSpecs , remote . RefSpecs . ToList ( ) ) ;
86+
87+ var actualNewFetchRefSpecs = newRemote . RefSpecs
88+ . Where ( s => s . Direction == RefSpecDirection . Fetch )
89+ . Select ( r => r . Specification )
90+ . ToArray ( ) ;
91+ Assert . Equal ( newFetchRefSpecs , actualNewFetchRefSpecs ) ;
92+
93+ var actualNewPushRefSpecs = newRemote . RefSpecs
94+ . Where ( s => s . Direction == RefSpecDirection . Push )
95+ . Select ( r => r . Specification )
96+ . ToArray ( ) ;
97+ Assert . Equal ( newPushRefSpecs , actualNewPushRefSpecs ) ;
98+ }
99+ }
100+
101+ [ Fact ]
102+ public void RemoteUpdaterSavesRefSpecsPermanently ( )
103+ {
104+ var fetchRefSpecs = new string [ ] { "refs/their/heads/*:refs/my/heads/*" , "+refs/their/tag:refs/my/tag" } ;
105+
106+ var path = CloneStandardTestRepo ( ) ;
107+ using ( var repo = new Repository ( path ) )
108+ {
109+ var remote = repo . Network . Remotes [ "origin" ] ;
110+ repo . Network . Remotes . Update ( remote , r => r . FetchRefSpecs = fetchRefSpecs ) ;
111+ }
112+
113+ using ( var repo = new Repository ( path ) )
114+ {
115+ var remote = repo . Network . Remotes [ "origin" ] ;
116+ var actualRefSpecs = remote . RefSpecs
117+ . Where ( r => r . Direction == RefSpecDirection . Fetch )
118+ . Select ( r => r . Specification )
119+ . ToArray ( ) ;
120+ Assert . Equal ( fetchRefSpecs , actualRefSpecs ) ;
121+ }
122+ }
123+
124+ [ Fact ]
125+ public void CanAddAndRemoveRefSpecs ( )
126+ {
127+ string newRefSpec = "+refs/heads/test:refs/heads/other-test" ;
128+
129+ var path = CloneStandardTestRepo ( ) ;
130+ using ( var repo = new Repository ( path ) )
131+ {
132+ var remote = repo . Network . Remotes [ "origin" ] ;
133+
134+ remote = repo . Network . Remotes . Update ( remote ,
135+ r => r . FetchRefSpecs . Add ( newRefSpec ) ,
136+ r => r . PushRefSpecs . Add ( newRefSpec ) ) ;
137+
138+ Assert . Contains ( newRefSpec , remote . FetchRefSpecs . Select ( r => r . Specification ) ) ;
139+ Assert . Contains ( newRefSpec , remote . PushRefSpecs . Select ( r => r . Specification ) ) ;
140+
141+ remote = repo . Network . Remotes . Update ( remote ,
142+ r => r . FetchRefSpecs . Remove ( newRefSpec ) ,
143+ r => r . PushRefSpecs . Remove ( newRefSpec ) ) ;
144+
145+ Assert . DoesNotContain ( newRefSpec , remote . FetchRefSpecs . Select ( r => r . Specification ) ) ;
146+ Assert . DoesNotContain ( newRefSpec , remote . PushRefSpecs . Select ( r => r . Specification ) ) ;
147+ }
148+ }
149+
150+ [ Fact ]
151+ public void CanClearRefSpecs ( )
152+ {
153+ var path = CloneStandardTestRepo ( ) ;
154+ using ( var repo = new Repository ( path ) )
155+ {
156+ var remote = repo . Network . Remotes [ "origin" ] ;
157+
158+ // Push refspec does not exist in cloned repository
159+ remote = repo . Network . Remotes . Update ( remote , r => r . PushRefSpecs . Add ( "+refs/test:refs/test" ) ) ;
160+
161+ remote = repo . Network . Remotes . Update ( remote ,
162+ r => r . FetchRefSpecs . Clear ( ) ,
163+ r => r . PushRefSpecs . Clear ( ) ) ;
164+
165+ Assert . Empty ( remote . FetchRefSpecs ) ;
166+ Assert . Empty ( remote . PushRefSpecs ) ;
167+ Assert . Empty ( remote . RefSpecs ) ;
168+ }
169+ }
170+
171+ [ Theory ]
172+ [ InlineData ( "refs/test:refs//double-slash" ) ]
173+ [ InlineData ( "refs/trailing-slash/:refs/test" ) ]
174+ [ InlineData ( "refs/.dotfile:refs/test" ) ]
175+ [ InlineData ( "refs/.:refs/dotdir" ) ]
176+ [ InlineData ( "refs/asterix:refs/not-matching/*" ) ]
177+ [ InlineData ( "refs/double/*/asterix/*:refs/double/*asterix/*" ) ]
178+ [ InlineData ( "refs/ whitespace:refs/test" ) ]
179+ public void SettingInvalidRefSpecsThrows ( string refSpec )
180+ {
181+ var path = CloneStandardTestRepo ( ) ;
182+ using ( var repo = new Repository ( path ) )
183+ {
184+ var remote = repo . Network . Remotes [ "origin" ] ;
185+ var oldRefSpecs = remote . RefSpecs . Select ( r => r . Specification ) . ToList ( ) ;
186+
187+ Assert . Throws < LibGit2SharpException > ( ( ) =>
188+ repo . Network . Remotes . Update ( remote , r => r . FetchRefSpecs . Add ( refSpec ) ) ) ;
189+
190+ var newRemote = repo . Network . Remotes [ "origin" ] ;
191+ Assert . Equal ( oldRefSpecs , newRemote . RefSpecs . Select ( r => r . Specification ) . ToList ( ) ) ;
192+ }
193+ }
54194 }
55195}
0 commit comments