@@ -127,3 +127,92 @@ mod interpolate {
127127 std:: env:: current_dir ( ) . unwrap ( ) . join ( name) . into ( )
128128 }
129129}
130+
131+ mod optional_prefix {
132+ use std:: borrow:: Cow ;
133+
134+ use crate :: { b, cow_str} ;
135+
136+ #[ test]
137+ fn path_without_optional_prefix_is_not_optional ( ) {
138+ let path = gix_config_value:: Path :: from ( Cow :: Borrowed ( b ( "/some/path" ) ) ) ;
139+ assert ! ( !path. is_optional( ) , "path without prefix should not be optional" ) ;
140+ assert_eq ! ( path. value. as_ref( ) , b"/some/path" ) ;
141+ }
142+
143+ #[ test]
144+ fn path_with_optional_prefix_is_optional ( ) {
145+ let path = gix_config_value:: Path :: from ( cow_str ( ":(optional)/some/path" ) ) ;
146+ assert ! ( path. is_optional( ) , "path with :(optional) prefix should be optional" ) ;
147+ assert_eq ! ( path. value. as_ref( ) , b"/some/path" , "prefix should be stripped" ) ;
148+ }
149+
150+ #[ test]
151+ fn optional_prefix_with_relative_path ( ) {
152+ let path = gix_config_value:: Path :: from ( cow_str ( ":(optional)relative/path" ) ) ;
153+ assert ! ( path. is_optional( ) ) ;
154+ assert_eq ! ( path. value. as_ref( ) , b"relative/path" ) ;
155+ }
156+
157+ #[ test]
158+ fn optional_prefix_with_tilde_expansion ( ) {
159+ let path = gix_config_value:: Path :: from ( cow_str ( ":(optional)~/config/file" ) ) ;
160+ assert ! ( path. is_optional( ) ) ;
161+ assert_eq ! ( path. value. as_ref( ) , b"~/config/file" , "tilde should be preserved for interpolation" ) ;
162+ }
163+
164+ #[ test]
165+ fn optional_prefix_with_prefix_substitution ( ) {
166+ let path = gix_config_value:: Path :: from ( cow_str ( ":(optional)%(prefix)/share/git" ) ) ;
167+ assert ! ( path. is_optional( ) ) ;
168+ assert_eq ! ( path. value. as_ref( ) , b"%(prefix)/share/git" , "prefix should be preserved for interpolation" ) ;
169+ }
170+
171+ #[ test]
172+ fn optional_prefix_with_windows_path ( ) {
173+ let path = gix_config_value:: Path :: from ( cow_str ( r":(optional)C:\Users\file" ) ) ;
174+ assert ! ( path. is_optional( ) ) ;
175+ assert_eq ! ( path. value. as_ref( ) , br"C:\Users\file" ) ;
176+ }
177+
178+ #[ test]
179+ fn optional_prefix_followed_by_empty_path ( ) {
180+ let path = gix_config_value:: Path :: from ( cow_str ( ":(optional)" ) ) ;
181+ assert ! ( path. is_optional( ) ) ;
182+ assert_eq ! ( path. value. as_ref( ) , b"" , "empty path after prefix is valid" ) ;
183+ }
184+
185+ #[ test]
186+ fn partial_optional_string_is_not_treated_as_prefix ( ) {
187+ let path = gix_config_value:: Path :: from ( cow_str ( ":(opt)ional/path" ) ) ;
188+ assert ! ( !path. is_optional( ) , "incomplete prefix should not be treated as optional marker" ) ;
189+ assert_eq ! ( path. value. as_ref( ) , b":(opt)ional/path" ) ;
190+ }
191+
192+ #[ test]
193+ fn optional_prefix_case_sensitive ( ) {
194+ let path = gix_config_value:: Path :: from ( cow_str ( ":(OPTIONAL)/some/path" ) ) ;
195+ assert ! ( !path. is_optional( ) , "prefix should be case-sensitive" ) ;
196+ assert_eq ! ( path. value. as_ref( ) , b":(OPTIONAL)/some/path" ) ;
197+ }
198+
199+ #[ test]
200+ fn optional_prefix_with_spaces ( ) {
201+ let path = gix_config_value:: Path :: from ( cow_str ( ":(optional) /path/with/space" ) ) ;
202+ assert ! ( path. is_optional( ) ) ;
203+ assert_eq ! ( path. value. as_ref( ) , b" /path/with/space" , "space after prefix should be preserved" ) ;
204+ }
205+
206+ #[ test]
207+ fn interpolate_preserves_optional_flag ( ) -> crate :: Result {
208+ use gix_config_value:: path;
209+
210+ let path = gix_config_value:: Path :: from ( cow_str ( ":(optional)/absolute/path" ) ) ;
211+ assert ! ( path. is_optional( ) ) ;
212+
213+ let interpolated = path. interpolate ( path:: interpolate:: Context :: default ( ) ) ?;
214+ assert_eq ! ( interpolated. as_ref( ) , std:: path:: Path :: new( "/absolute/path" ) ) ;
215+
216+ Ok ( ( ) )
217+ }
218+ }
0 commit comments