@@ -132,6 +132,70 @@ public void CanEnumerateRepositorySubmodules()
132132 }
133133 }
134134
135+ [ Fact ]
136+ public void CanAddSubmodule ( )
137+ {
138+ var path = SandboxStandardTestRepo ( ) ;
139+ var pathSubRepoOrigin = SandboxStandardTestRepo ( ) ;
140+
141+ string submoduleSubPath = "submodule_target_wd" ;
142+ string expectedSubmodulePath = Path . GetFullPath ( Path . Combine ( path , submoduleSubPath ) ) ;
143+ string expectedSubmoduleUrl = pathSubRepoOrigin . Replace ( '\\ ' , '/' ) ;
144+ ObjectId expectedCommitId = ( ObjectId ) "32eab9cb1f450b5fe7ab663462b77d7f4b703344" ;
145+
146+ using ( var repo = new Repository ( path ) )
147+ {
148+ // setup config with dummy user so we can commit
149+ CreateConfigurationWithDummyUser ( repo , Constants . Identity ) ;
150+
151+ // check on adding config entry
152+ var configEntryBeforeAdd = repo . Config . Get < string > ( string . Format ( "submodule.{0}.url" , submoduleSubPath ) ) ;
153+ Assert . Null ( configEntryBeforeAdd ) ;
154+
155+ // first step is cloning the repository to where it goes
156+ Repository . Clone ( pathSubRepoOrigin , expectedSubmodulePath ) ;
157+
158+ // add submodule
159+ repo . Submodules . Add ( pathSubRepoOrigin , submoduleSubPath , 1 ) ;
160+ Submodule submodule = repo . Submodules [ submoduleSubPath ] ;
161+ Assert . NotNull ( submodule ) ;
162+
163+ // check that the expected commit is checked out, but not set in parent repo until committed
164+ Assert . Equal ( expectedCommitId , repo . Submodules [ submoduleSubPath ] . WorkDirCommitId ) ;
165+ Assert . Null ( repo . Submodules [ submoduleSubPath ] . HeadCommitId ) ;
166+
167+ // check status
168+ var submoduleStatus = submodule . RetrieveStatus ( ) ;
169+ Assert . True ( ( submoduleStatus & SubmoduleStatus . InIndex ) == SubmoduleStatus . InIndex ) ;
170+ Assert . True ( ( submoduleStatus & SubmoduleStatus . InConfig ) == SubmoduleStatus . InConfig ) ;
171+ Assert . True ( ( submoduleStatus & SubmoduleStatus . InWorkDir ) == SubmoduleStatus . InWorkDir ) ;
172+ Assert . True ( ( submoduleStatus & SubmoduleStatus . IndexAdded ) == SubmoduleStatus . IndexAdded ) ;
173+
174+ // check that config entry was added with the correct url
175+ var configEntryAfterAdd = repo . Config . Get < string > ( string . Format ( "submodule.{0}.url" , submoduleSubPath ) ) ;
176+ Assert . NotNull ( configEntryAfterAdd ) ;
177+ Assert . Equal ( expectedSubmoduleUrl , configEntryAfterAdd . Value ) ;
178+
179+ // check on directory being added and repository directory
180+ Assert . True ( Directory . Exists ( expectedSubmodulePath ) ) ;
181+ Assert . True ( Directory . Exists ( Path . Combine ( expectedSubmodulePath , ".git" ) ) ) ;
182+
183+ // manually check commit by opening submodule as a repository
184+ using ( var repo2 = new Repository ( expectedSubmodulePath ) )
185+ {
186+ Assert . False ( repo2 . Info . IsHeadDetached ) ;
187+ Assert . False ( repo2 . Info . IsHeadUnborn ) ;
188+ Commit headCommit = repo2 . Head . Tip ;
189+ Assert . Equal ( headCommit . Id , expectedCommitId ) ;
190+ }
191+
192+ // commit parent repository, then verify it reports the correct CommitId for the submodule
193+ Signature signature = repo . Config . BuildSignature ( DateTimeOffset . Now ) ;
194+ repo . Commit ( "Added submodule " + submoduleSubPath , signature , signature ) ;
195+ Assert . Equal ( expectedCommitId , repo . Submodules [ submoduleSubPath ] . HeadCommitId ) ;
196+ }
197+ }
198+
135199 [ Theory ]
136200 [ InlineData ( "sm_changed_head" ) ]
137201 [ InlineData ( "sm_changed_head/" ) ]
@@ -322,6 +386,8 @@ public void CanReadSubmoduleProperties()
322386
323387 using ( var repo = new Repository ( path ) )
324388 {
389+ CreateConfigurationWithDummyUser ( repo , Constants . Identity ) ;
390+
325391 var submodule = repo . Submodules [ submoduleName ] ;
326392
327393 Assert . Equal ( SubmoduleUpdate . Checkout , submodule . UpdateRule ) ;
0 commit comments