github.com/purpleclay/gitz@v0.8.2-0.20240515052600-43f80eea2fe1/docs/testing/git-test.md (about) 1 --- 2 icon: material/test-tube 3 title: Testing your interactions with git 4 description: A dedicated package for testing your interactions with git 5 --- 6 7 # Testing your interactions with git 8 9 `gitz` includes a `gittest` package that enables interactions with Git to be unit tested within your projects. Add the following import to any of your test files to get started: 10 11 ```{ .go .no-select } 12 import "github.com/purpleclay/gitz/gittest" 13 ``` 14 15 ## Building a test repository 16 17 Only a single line of code is needed to initialize a test repository. And don't worry; it gets deleted after test execution. 18 19 ```{ .go .select linenums="1" } 20 package git_test 21 22 import ( 23 "testing" 24 25 git "github.com/purpleclay/gitz" 26 "github.com/purpleclay/gitz/gittest" 27 "github.com/stretchr/testify/assert" 28 ) 29 30 func TestInitRepository(t *testing.T) { 31 gittest.InitRepository(t) 32 33 client, _ := git.NewClient() 34 repo, _ := client.Repository() 35 36 assert.Equal(t, "main", repo.DefaultBranch) 37 } 38 ``` 39 40 Where `gittest` shines is in its ability to customize a repository during initialization through a set of options. 41 42 ### With a commit log 43 44 Initialize a repository with a predefined log by using the `WithLog` option. It can contain both commit messages and lightweight tags and is written to the repository in reverse chronological order. The expected format is equivalent to the output from the git command: 45 46 `git log --pretty='format:%d %s'`. 47 48 ```{ .go .select linenums="1" } 49 package git_test 50 51 import ( 52 "testing" 53 54 git "github.com/purpleclay/gitz" 55 "github.com/purpleclay/gitz/gittest" 56 "github.com/stretchr/testify/assert" 57 ) 58 59 func TestInitRepositoryWithLog(t *testing.T) { 60 log := `(tag: 0.1.0) feat: this is a brand new feature 61 docs: write amazing material mkdocs documentation 62 ci: include github release workflow` 63 gittest.InitRepository(t, gittest.WithLog(log)) 64 65 client, _ := git.NewClient() 66 repoLog, _ := client.Log() 67 68 assert.Equal(t, "feat: this is a brand new feature", 69 repoLog.Commits[0].Message) 70 assert.Equal(t, "docs: write amazing material mkdocs documentation", 71 repoLog.Commits[1].Message) 72 assert.Equal(t, "ci: include github release workflow", 73 repoLog.Commits[2].Message) 74 } 75 ``` 76 77 #### Multi-line commits 78 79 Import multi-line commits by prefixing each commit with a `>` token. The expected format is equivalent to the output from the git command: 80 81 `git log --pretty='format:> %d %s%+b%-N'` 82 83 ```{ .text .no-select .no-copy } 84 > (tag: 0.1.0, main, origin/main) feat: multi-line commits is supported 85 > feat(deps): bump github.com/stretchr/testify from 1.8.1 to 1.8.2 86 87 Signed-off-by: dependabot[bot] <support@github.com> 88 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 89 ``` 90 91 ### With a remote log 92 93 Initialize the remote origin of a repository with a predefined log using the `WithRemoteLog` option. Ideal for simulating a delta between the current log and its remote counterpart. 94 95 ```{ .go .select linenums="1" } 96 package git_test 97 98 import ( 99 "testing" 100 101 "github.com/purpleclay/gitz/gittest" 102 "github.com/stretchr/testify/assert" 103 ) 104 105 func TestInitRepositoryRemoteLog(t *testing.T) { 106 log := "(main, origin/main) chore: testing remote log" 107 gittest.InitRepository(t, gittest.WithRemoteLog(log)) 108 require.NotEqual(t, gittest.LastCommit(t).Message, 109 "chore: testing remote log") 110 111 client, _ := git.NewClient() 112 _, err := client.Pull() 113 114 require.NoError(t, err) 115 assert.Equal(t, gittest.LastCommit(t).Message, 116 "chore: testing remote log") 117 } 118 ``` 119 120 ### With untracked files 121 122 Create a set of untracked files within a repository using the `WithFiles` option. File paths can be fully qualified or relative to the repository root. Each created file will contain a sample of `lorem ipsum` text. 123 124 ```{ .go .select linenums="1" } 125 package git_test 126 127 import ( 128 "testing" 129 130 "github.com/purpleclay/gitz/gittest" 131 "github.com/stretchr/testify/assert" 132 ) 133 134 func TestInitRepositoryWithFiles(t *testing.T) { 135 gittest.InitRepository(t, gittest.WithFiles("a.txt", "dir/b.txt")) 136 137 status := gittest.PorcelainStatus(t) 138 assert.Equal(t, "?? a.txt", status[0]) 139 assert.Equal(t, "?? dir/", status[1]) 140 } 141 ``` 142 143 ### With staged files 144 145 Create a set of staged (or tracked) files within a repository using the `WithStagedFiles` option. 146 147 ```{ .go .select linenums="1" } 148 package git_test 149 150 import ( 151 "testing" 152 153 "github.com/purpleclay/gitz/gittest" 154 "github.com/stretchr/testify/assert" 155 ) 156 157 func TestInitRepositoryWithStagedFiles(t *testing.T) { 158 gittest.InitRepository(t, 159 gittest.WithStagedFiles("a.txt", "dir/b.txt")) 160 161 status := gittest.PorcelainStatus(t) 162 assert.Equal(t, "A a.txt", status[0]) 163 assert.Equal(t, "A dir/b.txt", status[1]) 164 } 165 ``` 166 167 ### With committed files 168 169 Create a set of files that will be committed to the repository using the `WithCommittedFiles` option. A single commit of `include test files` will be created. 170 171 ```{ .go .select linenums="1" } 172 package git_test 173 174 import ( 175 "testing" 176 177 "github.com/purpleclay/gitz/gittest" 178 "github.com/stretchr/testify/assert" 179 ) 180 181 func TestInitRepositoryWithCommittedFiles(t *testing.T) { 182 gittest.InitRepository(t, 183 gittest.WithCommittedFiles("a.txt", "dir/b.txt")) 184 185 status := gittest.PorcelainStatus(t) 186 assert.Empty(t, status) 187 } 188 ``` 189 190 ### With file content 191 192 Allows files created with the `WithFiles`, `WithStagedFiles` or `WithCommittedFiles` options to be overwritten with user-defined content. Key value pairs must be provided to the `WithFileContent` option when overriding existing files. 193 194 ```{ .go .select linenums="1" } 195 package git_test 196 197 import ( 198 "testing" 199 200 "github.com/purpleclay/gitz/gittest" 201 "github.com/stretchr/testify/assert" 202 ) 203 204 func TestInitRepositoryWithFileContent(t *testing.T) { 205 gittest.InitRepository(t, 206 gittest.WithCommittedFiles("a.txt", "dir/b.txt"), 207 gittest.WithFileContent("a.txt", "hello", "dir/b.txt", "world!")) 208 209 assert.Equal(t, "hello", gittest.Blob(t, "a.txt")) 210 assert.Equal(t, "world!", gittest.Blob(t, "dir/b.txt")) 211 } 212 ``` 213 214 ### With local commits 215 216 Generate a set of local empty commits, ready to be pushed back to the remote, with the `WithLocalCommits` option. Generated Commits will be in chronological order. 217 218 ```{ .go .select linenums="1" } 219 package git_test 220 221 import ( 222 "testing" 223 224 git "github.com/purpleclay/gitz" 225 "github.com/purpleclay/gitz/gittest" 226 "github.com/stretchr/testify/assert" 227 ) 228 229 func TestInitRepositoryWithLocalCommits(t *testing.T) { 230 commits := []string{ 231 "docs: my first local commit", 232 "fix: my second local commit", 233 "feat: my third local commit", 234 } 235 gittest.InitRepository(t, gittest.WithLocalCommits(commits...)) 236 237 client, _ := git.NewClient() 238 log, _ := client.Log() 239 240 assert.Equal(t, "feat: my third local commit", log.Commits[0].Message) 241 assert.Equal(t, "fix: my second local commit", log.Commits[1].Message) 242 assert.Equal(t, "docs: my first local commit", log.Commits[2].Message) 243 } 244 ``` 245 246 ### With clone depth 247 248 Shallow clone a repository by truncating its history to a set depth. 249 250 ```{ .go .select linenums="1" } 251 package git_test 252 253 import ( 254 "testing" 255 256 git "github.com/purpleclay/gitz" 257 "github.com/purpleclay/gitz/gittest" 258 "github.com/stretchr/testify/assert" 259 ) 260 261 func TestInitRepositoruWithCloneDepth(t *testing.T) { 262 log := `(tag: 0.1.0) feat: this is a brand new feature 263 docs: write amazing material mkdocs documentation 264 ci: include github release workflow` 265 gittest.InitRepository(t, 266 gittest.WithLog(log), gittest.WithCloneDepth(1)) 267 268 client, _ := git.NewClient() 269 repoLog, _ := client.Log() 270 271 require.Len(t, repoLog, 1) 272 assert.Equal(t, "feat: this is a brand new feature", 273 repoLog.Commits[0].Message) 274 } 275 ``` 276 277 ### Option initialization order 278 279 You can use any combination of options during repository initialization, but a strict order is applied. 280 281 1. `WithLog`: log history imported, both local and remote are in sync. 282 1. `WithCloneDepth`: shallow clone at the required depth. 283 1. `WithRemoteLog`: remote log history imported, creating a delta between local and remote. 284 1. `WithLocalCommits`: local commits created and not pushed back to remote. 285 1. `WithFiles`, `WithCommittedFiles` and `WithStagedFiles`: files generated and either committed or staged if needed. 286 1. `WithFileContent`: Overwrites existing files with user-defined content.