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.