summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2026-01-30 17:18:31 -0700
committermo khan <mo@mokhan.ca>2026-01-30 17:18:31 -0700
commite4ed0342932b0aa741ee78d9e4fe135eba6e9ca7 (patch)
treef1e7f602cb86e78aedf04185b2c2e1428fc5b8f2
parent83be9ddcf82e8a90ea50a9d54c1ebfc3e22ace16 (diff)
initial commit
-rwxr-xr-x.github/scripts/build.mjs33
-rw-r--r--.github/workflows/release.yaml43
-rw-r--r--.github/workflows/test.yaml18
-rw-r--r--Dockerfile24
-rw-r--r--LICENSE21
-rw-r--r--README.md67
-rw-r--r--RELEASE.md7
-rw-r--r--blob.go8
-rw-r--r--branches.go4
-rw-r--r--commit.go8
-rw-r--r--commits_list.go6
-rw-r--r--docs/how-to-self-host-a-git-repository.md67
-rw-r--r--go.mod2
-rw-r--r--img/gitmal-color-logo.webpbin79850 -> 0 bytes
-rw-r--r--img/gitmal-screenshot-code-highlighting.webpbin102206 -> 0 bytes
-rw-r--r--img/gitmal-screenshot-file-tree.webpbin71818 -> 0 bytes
-rw-r--r--img/gitmal-screenshot-files.webpbin75404 -> 0 bytes
-rw-r--r--img/gitmal-smallest-logo.webpbin1402 -> 0 bytes
-rw-r--r--index.go6
-rw-r--r--list.go8
-rw-r--r--main.go2
-rw-r--r--markdown.go2
-rw-r--r--pkg/git/git_test.go64
-rw-r--r--pkg/git/utils_test.go80
-rw-r--r--pkg/gitdiff/README.md1
-rw-r--r--pkg/gitdiff/apply_test.go235
-rw-r--r--pkg/gitdiff/assert_test.go30
-rw-r--r--pkg/gitdiff/base85_test.go118
-rw-r--r--pkg/gitdiff/binary_test.go324
-rw-r--r--pkg/gitdiff/file_header_test.go766
-rw-r--r--pkg/gitdiff/format_roundtrip_test.go157
-rw-r--r--pkg/gitdiff/format_test.go28
-rw-r--r--pkg/gitdiff/gitdiff_test.go161
-rw-r--r--pkg/gitdiff/io_test.go254
-rw-r--r--pkg/gitdiff/parser_test.go511
-rw-r--r--pkg/gitdiff/patch_header_test.go590
-rw-r--r--pkg/gitdiff/patch_identity_test.go127
-rw-r--r--pkg/gitdiff/testdata/apply/bin.go124
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_error.srcbin130 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_error_dst_size.patch5
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_error_incomplete_add.patch5
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_error_incomplete_copy.patch5
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_error_src_size.patch5
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.outbin1084 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.patch13
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.srcbin1024 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.outbin131072 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.patch166
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.srcbin131072 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_literal_create.outbin32 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_literal_create.patch8
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_literal_create.src0
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.outbin32 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.patch8
-rw-r--r--pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.srcbin32 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/file_bin_modify.outbin1084 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/file_bin_modify.patch13
-rw-r--r--pkg/gitdiff/testdata/apply/file_bin_modify.srcbin1024 -> 0 bytes
-rw-r--r--pkg/gitdiff/testdata/apply/file_mode_change.out2
-rw-r--r--pkg/gitdiff/testdata/apply/file_mode_change.patch3
-rw-r--r--pkg/gitdiff/testdata/apply/file_mode_change.src2
-rw-r--r--pkg/gitdiff/testdata/apply/file_text.src200
-rw-r--r--pkg/gitdiff/testdata/apply/file_text_delete.out0
-rw-r--r--pkg/gitdiff/testdata/apply/file_text_delete.patch206
-rw-r--r--pkg/gitdiff/testdata/apply/file_text_error_partial_delete.patch106
-rw-r--r--pkg/gitdiff/testdata/apply/file_text_modify.out195
-rw-r--r--pkg/gitdiff/testdata/apply/file_text_modify.patch62
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_end.out5
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_end.patch9
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_end.src3
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.out5
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.patch11
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.src3
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_middle.out5
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_middle.patch9
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_middle.src3
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_start.out4
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_start.patch8
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_add_start.src3
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_end.out10
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_end.patch9
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_end.src10
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.out3
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.patch10
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.src3
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_exact.out19
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_exact.patch12
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_exact.src30
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_middle.out9
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_middle.patch12
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_middle.src10
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.out1
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.patch8
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.src1
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_start.out4
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_start.patch9
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_change_start.src10
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_delete_all.out0
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_delete_all.patch8
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_delete_all.src4
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_error.src13
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_error_context_conflict.patch12
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_error_delete_conflict.patch12
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_error_new_file.patch7
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_error_short_src.patch12
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_error_short_src_before.patch12
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_new.out3
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_new.patch7
-rw-r--r--pkg/gitdiff/testdata/apply/text_fragment_new.src0
-rw-r--r--pkg/gitdiff/testdata/new_binary_file.patch16
-rw-r--r--pkg/gitdiff/testdata/no_files.patch8
-rw-r--r--pkg/gitdiff/testdata/one_file.patch28
-rw-r--r--pkg/gitdiff/testdata/string/binary_modify.patch9
-rw-r--r--pkg/gitdiff/testdata/string/binary_modify_nodata.patch3
-rw-r--r--pkg/gitdiff/testdata/string/binary_new.patch11
-rw-r--r--pkg/gitdiff/testdata/string/copy.patch4
-rw-r--r--pkg/gitdiff/testdata/string/copy_modify.patch21
-rw-r--r--pkg/gitdiff/testdata/string/delete.patch16
-rw-r--r--pkg/gitdiff/testdata/string/mode.patch3
-rw-r--r--pkg/gitdiff/testdata/string/mode_modify.patch10
-rw-r--r--pkg/gitdiff/testdata/string/modify.patch16
-rw-r--r--pkg/gitdiff/testdata/string/new.patch16
-rw-r--r--pkg/gitdiff/testdata/string/new_empty.patch3
-rw-r--r--pkg/gitdiff/testdata/string/new_mode.patch16
-rw-r--r--pkg/gitdiff/testdata/string/rename.patch4
-rw-r--r--pkg/gitdiff/testdata/string/rename_modify.patch18
-rw-r--r--pkg/gitdiff/testdata/two_files.patch48
-rw-r--r--pkg/gitdiff/text_test.go488
-rw-r--r--pkg/links/links.go2
-rw-r--r--pkg/links/links_test.go228
-rw-r--r--pkg/templates/blob.gohtml2
-rw-r--r--pkg/templates/branches.gohtml2
-rw-r--r--pkg/templates/commit.gohtml2
-rw-r--r--pkg/templates/commits_list.gohtml2
-rw-r--r--pkg/templates/file_tree.gohtml2
-rw-r--r--pkg/templates/header.gohtml2
-rw-r--r--pkg/templates/layout.gohtml3
-rw-r--r--pkg/templates/list.gohtml2
-rw-r--r--pkg/templates/markdown.gohtml2
-rw-r--r--pkg/templates/preview.gohtml2
-rw-r--r--pkg/templates/tags.gohtml2
-rw-r--r--pkg/templates/templates.go2
-rw-r--r--post_process.go2
-rw-r--r--readme.go4
-rw-r--r--tags.go4
-rw-r--r--themes.go2
-rw-r--r--utils.go4
147 files changed, 44 insertions, 6193 deletions
diff --git a/.github/scripts/build.mjs b/.github/scripts/build.mjs
deleted file mode 100755
index 251a036..0000000
--- a/.github/scripts/build.mjs
+++ /dev/null
@@ -1,33 +0,0 @@
-$.verbose = true
-
-const goos = [
- 'linux',
- 'darwin',
- 'windows',
-]
-const goarch = [
- 'amd64',
- 'arm64',
-]
-
-const name = (GOOS, GOARCH) => `gitmal_${GOOS}_${GOARCH}` + (GOOS === 'windows' ? '.exe' : '')
-
-const resp = await fetch('https://api.github.com/repos/antonmedv/gitmal/releases/latest')
-const {tag_name: latest} = await resp.json()
-
-await $`go mod download`
-
-await Promise.all(
- goos.flatMap(GOOS =>
- goarch.map(GOARCH =>
- $`GOOS=${GOOS} GOARCH=${GOARCH} go build -o ${name(GOOS, GOARCH)}`)))
-
-await Promise.all(
- goos.flatMap(GOOS =>
- goarch.map(GOARCH =>
- $`gh release upload ${latest} ${name(GOOS, GOARCH)}`)))
-
-await Promise.all(
- goos.flatMap(GOOS =>
- goarch.map(GOARCH =>
- $`rm ${name(GOOS, GOARCH)}`)))
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
deleted file mode 100644
index 76f5c33..0000000
--- a/.github/workflows/release.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-name: release
-
-on:
- release:
- types: [ created ]
- workflow_dispatch:
-
-jobs:
- docker:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Login to Docker Hub
- uses: docker/login-action@v3
- with:
- username: antonmedv
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Build test image
- uses: docker/build-push-action@v5
- with:
- context: .
- file: ./Dockerfile
- load: true
- tags: antonmedv/gitmal:test
-
- - name: Smoke test - verify binary runs
- run: |
- docker run --rm antonmedv/gitmal:test --help
-
- - name: Build and push
- uses: docker/build-push-action@v5
- with:
- context: .
- file: ./Dockerfile
- push: true
- platforms: linux/amd64,linux/arm64
- tags: antonmedv/gitmal:latest
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
deleted file mode 100644
index 8b20693..0000000
--- a/.github/workflows/test.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: test
-
-on:
- push:
- branches: [ master ]
- pull_request:
- branches: [ master ]
-
-jobs:
- test:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-go@v3
- with:
- go-version: 1.21
- - name: Test
- run: go test ./...
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 6a189a1..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,24 +0,0 @@
-FROM golang:latest as builder
-
-WORKDIR /go
-
-COPY go.mod go.sum ./
-
-RUN go mod download
-
-COPY . .
-
-RUN CGO_ENABLED=0 go build -o gitmal .
-
-
-FROM alpine
-
-RUN apk add --no-cache git
-
-COPY --from=builder /go/gitmal /bin/gitmal
-
-WORKDIR /data
-
-ENV COLORTERM=truecolor
-
-ENTRYPOINT ["/bin/gitmal"]
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index ae6cff9..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2025 Anton Medvedev
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
deleted file mode 100644
index 6e76737..0000000
--- a/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-<p align="center"><img src="img/gitmal-color-logo.webp" alt="Gitmal" width="330" height="330"></p>
-
-# Gitmal
-
-Gitmal is a static page generator for Git repositories. Gitmal generates static HTML pages with files, commits,
-code highlighting, and markdown rendering.
-
-## Installation
-
-```sh
-go install github.com/antonmedv/gitmal@latest
-```
-
-```sh
-docker run --rm -v $(pwd):/repo antonmedv/gitmal /repo
-```
-
-Or download prebuilt binary from [releases](https://github.com/antonmedv/gitmal/releases).
-
-## Usage
-
-Run gitmal in the repository dir. Gitmal will generate pages in _./output_ directory.
-
-```sh
-gitmal .
-```
-
-Run gitmal with `--help` flag, go get a list of available options.
-
-```sh
-gitmal --help
-```
-
-## Screenshots
-
-<p align="center">
- <a href="img/gitmal-screenshot-code-highlighting.webp"><img src="img/gitmal-screenshot-code-highlighting.webp" alt="Gitmal Code Highlighting" width="400"></a>
- <a href="img/gitmal-screenshot-file-tree.webp"><img src="img/gitmal-screenshot-file-tree.webp" alt="Gitmal File Tree" width="400"></a><br>
- <a href="img/gitmal-screenshot-files.webp"><img src="img/gitmal-screenshot-files.webp" alt="Gitmal Files Page" width="400"></a>
-</p>
-
-## Examples
-
-Here are a few examples of repos hosted on my website:
-
-- [git.medv.io/zx/](https://git.medv.io/zx/) โ€” github.com/google/zx
-- [git.medv.io/zig/](https://git.medv.io/zig/) โ€” codeberg.org/ziglang/zig (light theme)
-- [git.medv.io/my-badges/](https://git.medv.io/my-badges/) โ€” github.com/my-badges/my-badges
-
-Gitmal on kubernetes repository works as well. Generation on my MacBook Air M2 with `--minify` and `--gzip` flags
-takes around 25 minutes, and the generated files weigh around 2 GB.
-
-## Themes
-
-Gitmal supports different code highlighting themes. You can customize the theme with `--theme` flag.
-
-```sh
-gitmal --theme github-dark
-```
-
-## Documentation
-
-- [How to Self-Host a Git Repository?](./docs/how-to-self-host-a-git-repository.md)
-
-## License
-
-[MIT](LICENSE)
diff --git a/RELEASE.md b/RELEASE.md
deleted file mode 100644
index ea715eb..0000000
--- a/RELEASE.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Release
-
-1. Create a [release](https://github.com/antonmedv/gitmal/releases/new) on GitHub.
-2. Run [build.mjs](.github/scripts/build.mjs) to build and upload binaries.
- ```sh
- npx zx .github/scripts/build.mjs
- ```
diff --git a/blob.go b/blob.go
index 3739c58..8b52283 100644
--- a/blob.go
+++ b/blob.go
@@ -15,10 +15,10 @@ import (
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/links"
- "github.com/antonmedv/gitmal/pkg/progress_bar"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/links"
+ "mokhan.ca/antonmedv/gitmal/pkg/progress_bar"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
func generateBlobs(files []git.Blob, params Params) error {
diff --git a/branches.go b/branches.go
index 7faf037..d574954 100644
--- a/branches.go
+++ b/branches.go
@@ -6,8 +6,8 @@ import (
"path/filepath"
"sort"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
// generateBranches creates a branches.html page at the root of the output
diff --git a/commit.go b/commit.go
index 028e8a9..442b09c 100644
--- a/commit.go
+++ b/commit.go
@@ -17,10 +17,10 @@ import (
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/gitdiff"
- "github.com/antonmedv/gitmal/pkg/progress_bar"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/gitdiff"
+ "mokhan.ca/antonmedv/gitmal/pkg/progress_bar"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
func generateCommits(commits map[string]git.Commit, params Params) error {
diff --git a/commits_list.go b/commits_list.go
index b09424e..14b3921 100644
--- a/commits_list.go
+++ b/commits_list.go
@@ -6,9 +6,9 @@ import (
"path/filepath"
"slices"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/progress_bar"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/progress_bar"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
const commitsPerPage = 100
diff --git a/docs/how-to-self-host-a-git-repository.md b/docs/how-to-self-host-a-git-repository.md
deleted file mode 100644
index 799dbe3..0000000
--- a/docs/how-to-self-host-a-git-repository.md
+++ /dev/null
@@ -1,67 +0,0 @@
-# How to Self-Host a Git Repository?
-
-**Goal**: self-host a Git repository on your server, allowing read-only clones and a web view.
-
-Create a _git_ user on the server where you want to host the repository. This step is optional, but I like to use a
-dedicated user for repository management to keep the system secure and organized.
-
-Create a `~/public` directory, which will serve as the web root. Configure a web server to serve files from this
-directory.
-
-## Bare repo
-
-Create a bare repository inside `~/public`.
-A [bare repository](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols)
-is a special type of Git repository that doesn't have a working directory. It's used for hosting and sharing code
-without the need for a local working copy.
-
-```sh
-git init --bare repo.git
-```
-
-Create a [post-update](https://git-scm.com/docs/git-receive-pack#_post_update_hook) hook with the following content:
-
-```sh
-#!/bin/sh
-exec git update-server-info
-```
-
-Make the hook executable:
-
-```sh
-chmod +x hooks/post-update
-```
-
-## Gitmal hook
-
-Create a [postโ€‘receive](https://git-scm.com/docs/git-receive-pack#_post_receive_hook) hook with the following content:
-
-```sh
-#!/bin/sh
-exec gitmal --output /home/git/public/repo/
-```
-
-Make the hook executable:
-
-```sh
-chmod +x hooks/post-receive
-```
-
-## Publish
-
-Push your local repository to the bare repository on the server using ssh protocol.
-
-```sh
-git remote add origin git@example.com:public/repo.git
-git push origin master
-```
-
-After pushing, git will run gitmal and generate files under `~/public/repo/` directory.
-
-- Private read-write clone URL: `git@example.com:public/repo.git`
-- Public **read-only** clone URL: `http://example.com/repo.git`
-- Gitmal static web view: `http://example.com/repo/`
-
-```sh
-git clone https://example.com/repo.git
-```
diff --git a/go.mod b/go.mod
index 7048722..8df1efd 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/antonmedv/gitmal
+module mokhan.ca/antonmedv/gitmal
go 1.24.0
diff --git a/img/gitmal-color-logo.webp b/img/gitmal-color-logo.webp
deleted file mode 100644
index f7320e1..0000000
--- a/img/gitmal-color-logo.webp
+++ /dev/null
Binary files differ
diff --git a/img/gitmal-screenshot-code-highlighting.webp b/img/gitmal-screenshot-code-highlighting.webp
deleted file mode 100644
index 7c8b94c..0000000
--- a/img/gitmal-screenshot-code-highlighting.webp
+++ /dev/null
Binary files differ
diff --git a/img/gitmal-screenshot-file-tree.webp b/img/gitmal-screenshot-file-tree.webp
deleted file mode 100644
index 032013c..0000000
--- a/img/gitmal-screenshot-file-tree.webp
+++ /dev/null
Binary files differ
diff --git a/img/gitmal-screenshot-files.webp b/img/gitmal-screenshot-files.webp
deleted file mode 100644
index 57d0c60..0000000
--- a/img/gitmal-screenshot-files.webp
+++ /dev/null
Binary files differ
diff --git a/img/gitmal-smallest-logo.webp b/img/gitmal-smallest-logo.webp
deleted file mode 100644
index da98152..0000000
--- a/img/gitmal-smallest-logo.webp
+++ /dev/null
Binary files differ
diff --git a/index.go b/index.go
index 9ac6164..341cc71 100644
--- a/index.go
+++ b/index.go
@@ -6,9 +6,9 @@ import (
"sort"
"strings"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/links"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/links"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
func generateIndex(files []git.Blob, params Params) error {
diff --git a/list.go b/list.go
index f1651d0..dcee8f0 100644
--- a/list.go
+++ b/list.go
@@ -11,10 +11,10 @@ import (
"strings"
"sync"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/links"
- "github.com/antonmedv/gitmal/pkg/progress_bar"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/links"
+ "mokhan.ca/antonmedv/gitmal/pkg/progress_bar"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
func generateLists(files []git.Blob, params Params) error {
diff --git a/main.go b/main.go
index 0ce64bc..99ae8f9 100644
--- a/main.go
+++ b/main.go
@@ -8,7 +8,7 @@ import (
"runtime/pprof"
"strings"
- "github.com/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
flag "github.com/spf13/pflag"
)
diff --git a/markdown.go b/markdown.go
index 1e5a30b..a2a48b5 100644
--- a/markdown.go
+++ b/markdown.go
@@ -9,7 +9,7 @@ import (
"github.com/yuin/goldmark/parser"
gmhtml "github.com/yuin/goldmark/renderer/html"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
func createMarkdown(style string) goldmark.Markdown {
diff --git a/pkg/git/git_test.go b/pkg/git/git_test.go
deleted file mode 100644
index 7ec0eb1..0000000
--- a/pkg/git/git_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package git
-
-import (
- "testing"
-)
-
-func TestParseRefNames_Empty(t *testing.T) {
- got := parseRefNames("")
- if len(got) != 0 {
- t.Fatalf("expected empty slice, got %v", got)
- }
-}
-
-func TestParseRefNames_Mixed(t *testing.T) {
- input := "HEAD -> main, tag: v1.0.0, origin/HEAD -> origin/main, origin/main, master"
- got := parseRefNames(input)
- if len(got) != 5 {
- t.Fatalf("expected 5 entries, got %d (%v)", len(got), got)
- }
-
- // 1: HEAD pointer
- if got[0].Kind != RefKindHEAD || got[0].Name != "HEAD" || got[0].Target != "main" {
- t.Errorf("unexpected HEAD entry: %+v", got[0])
- }
- // 2: tag
- if got[1].Kind != RefKindTag || got[1].Name != "v1.0.0" || got[1].Target != "" {
- t.Errorf("unexpected Tag entry: %+v", got[1])
- }
- // 3: remote HEAD pointer
- if got[2].Kind != RefKindRemoteHEAD || got[2].Name != "origin/HEAD" || got[2].Target != "origin/main" {
- t.Errorf("unexpected RemoteHEAD entry: %+v", got[2])
- }
- // 4: remote branch
- if got[3].Kind != RefKindRemote || got[3].Name != "origin/main" || got[3].Target != "" {
- t.Errorf("unexpected Remote entry: %+v", got[3])
- }
- // 5: local branch
- if got[4].Kind != RefKindBranch || got[4].Name != "master" || got[4].Target != "" {
- t.Errorf("unexpected Branch entry: %+v", got[4])
- }
-}
-
-func TestParseRefNames_Singles(t *testing.T) {
- cases := []struct {
- in string
- kind RefKind
- name string
- target string
- }{
- {"tag: v2", RefKindTag, "v2", ""},
- {"main", RefKindBranch, "main", ""},
- {"origin/dev", RefKindRemote, "origin/dev", ""},
- {"origin/HEAD -> origin/main", RefKindRemoteHEAD, "origin/HEAD", "origin/main"},
- }
- for _, c := range cases {
- got := parseRefNames(c.in)
- if len(got) != 1 {
- t.Fatalf("%q: expected 1 entry, got %d (%v)", c.in, len(got), got)
- }
- if got[0].Kind != c.kind || got[0].Name != c.name || got[0].Target != c.target {
- t.Errorf("%q: unexpected entry: %+v", c.in, got[0])
- }
- }
-}
diff --git a/pkg/git/utils_test.go b/pkg/git/utils_test.go
deleted file mode 100644
index 4dcebe8..0000000
--- a/pkg/git/utils_test.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package git_test
-
-import (
- "strings"
- "testing"
-
- "github.com/antonmedv/gitmal/pkg/git"
-)
-
-func TestParseFileMode(t *testing.T) {
- tests := []struct {
- mode string
- expected string
- }{
- {"100644", "rw-r--r--"},
- {"100755", "rwxr-xr-x"},
- {"100600", "rw-------"},
- {"100400", "r--------"},
- }
-
- for _, tt := range tests {
- t.Run(tt.mode, func(t *testing.T) {
- result, err := git.ParseFileMode(tt.mode)
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if result != tt.expected {
- t.Errorf("got %q, want %q", result, tt.expected)
- }
- })
- }
-}
-
-func TestParseFileModeInvalid(t *testing.T) {
- tests := []string{
- "",
- "12",
- "abc",
- "10070x",
- }
-
- for _, mode := range tests {
- t.Run(mode, func(t *testing.T) {
- result, err := git.ParseFileMode(mode)
- if err == nil {
- t.Error("expected error, got nil")
- }
- if result != "" {
- t.Errorf("expected empty result, got %q", result)
- }
- if !strings.Contains(err.Error(), "invalid mode") && !strings.Contains(err.Error(), "strconv.Atoi") {
- t.Errorf("unexpected error message: %v", err)
- }
- })
- }
-}
-
-func TestRefToFileName(t *testing.T) {
- tests := []struct {
- in string
- want string
- }{
- {"main", "main"},
- {"master", "master"},
- {"release/v1.0", "release-v1.0"},
- {"feature/add-login", "feature-add-login"},
- {"bugfix\\windows\\path", "bugfix-windows-path"},
- {"1.0.0", "1.0.0"},
- {"1.x", "1.x"},
- }
-
- for _, tt := range tests {
- t.Run(tt.in, func(t *testing.T) {
- got := git.RefToFileName(tt.in)
- if got != tt.want {
- t.Fatalf("refToFileName(%q) = %q, want %q", tt.in, got, tt.want)
- }
- })
- }
-}
diff --git a/pkg/gitdiff/README.md b/pkg/gitdiff/README.md
deleted file mode 100644
index 974bb70..0000000
--- a/pkg/gitdiff/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This is a vendored copy of the [bluekeyes/go-gitdiff](https://github.com/bluekeyes/go-gitdiff) package.
diff --git a/pkg/gitdiff/apply_test.go b/pkg/gitdiff/apply_test.go
deleted file mode 100644
index 05915ba..0000000
--- a/pkg/gitdiff/apply_test.go
+++ /dev/null
@@ -1,235 +0,0 @@
-package gitdiff
-
-import (
- "bytes"
- "errors"
- "io"
- "io/ioutil"
- "path/filepath"
- "testing"
-)
-
-func TestApplyTextFragment(t *testing.T) {
- tests := map[string]applyTest{
- "createFile": {Files: getApplyFiles("text_fragment_new")},
- "deleteFile": {Files: getApplyFiles("text_fragment_delete_all")},
-
- "addStart": {Files: getApplyFiles("text_fragment_add_start")},
- "addMiddle": {Files: getApplyFiles("text_fragment_add_middle")},
- "addEnd": {Files: getApplyFiles("text_fragment_add_end")},
- "addEndNoEOL": {Files: getApplyFiles("text_fragment_add_end_noeol")},
-
- "changeStart": {Files: getApplyFiles("text_fragment_change_start")},
- "changeMiddle": {Files: getApplyFiles("text_fragment_change_middle")},
- "changeEnd": {Files: getApplyFiles("text_fragment_change_end")},
- "changeEndEOL": {Files: getApplyFiles("text_fragment_change_end_eol")},
- "changeExact": {Files: getApplyFiles("text_fragment_change_exact")},
- "changeSingleNoEOL": {Files: getApplyFiles("text_fragment_change_single_noeol")},
-
- "errorShortSrcBefore": {
- Files: applyFiles{
- Src: "text_fragment_error.src",
- Patch: "text_fragment_error_short_src_before.patch",
- },
- Err: &Conflict{},
- },
- "errorShortSrc": {
- Files: applyFiles{
- Src: "text_fragment_error.src",
- Patch: "text_fragment_error_short_src.patch",
- },
- Err: &Conflict{},
- },
- "errorContextConflict": {
- Files: applyFiles{
- Src: "text_fragment_error.src",
- Patch: "text_fragment_error_context_conflict.patch",
- },
- Err: &Conflict{},
- },
- "errorDeleteConflict": {
- Files: applyFiles{
- Src: "text_fragment_error.src",
- Patch: "text_fragment_error_delete_conflict.patch",
- },
- Err: &Conflict{},
- },
- "errorNewFile": {
- Files: applyFiles{
- Src: "text_fragment_error.src",
- Patch: "text_fragment_error_new_file.patch",
- },
- Err: &Conflict{},
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- test.run(t, func(dst io.Writer, src io.ReaderAt, file *File) error {
- if len(file.TextFragments) != 1 {
- t.Fatalf("patch should contain exactly one fragment, but it has %d", len(file.TextFragments))
- }
- applier := NewTextApplier(dst, src)
- return applier.ApplyFragment(file.TextFragments[0])
- })
- })
- }
-}
-
-func TestApplyBinaryFragment(t *testing.T) {
- tests := map[string]applyTest{
- "literalCreate": {Files: getApplyFiles("bin_fragment_literal_create")},
- "literalModify": {Files: getApplyFiles("bin_fragment_literal_modify")},
- "deltaModify": {Files: getApplyFiles("bin_fragment_delta_modify")},
- "deltaModifyLarge": {Files: getApplyFiles("bin_fragment_delta_modify_large")},
-
- "errorIncompleteAdd": {
- Files: applyFiles{
- Src: "bin_fragment_delta_error.src",
- Patch: "bin_fragment_delta_error_incomplete_add.patch",
- },
- Err: "incomplete add",
- },
- "errorIncompleteCopy": {
- Files: applyFiles{
- Src: "bin_fragment_delta_error.src",
- Patch: "bin_fragment_delta_error_incomplete_copy.patch",
- },
- Err: "incomplete copy",
- },
- "errorSrcSize": {
- Files: applyFiles{
- Src: "bin_fragment_delta_error.src",
- Patch: "bin_fragment_delta_error_src_size.patch",
- },
- Err: &Conflict{},
- },
- "errorDstSize": {
- Files: applyFiles{
- Src: "bin_fragment_delta_error.src",
- Patch: "bin_fragment_delta_error_dst_size.patch",
- },
- Err: "insufficient or extra data",
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- test.run(t, func(dst io.Writer, src io.ReaderAt, file *File) error {
- applier := NewBinaryApplier(dst, src)
- return applier.ApplyFragment(file.BinaryFragment)
- })
- })
- }
-}
-
-func TestApplyFile(t *testing.T) {
- tests := map[string]applyTest{
- "textModify": {
- Files: applyFiles{
- Src: "file_text.src",
- Patch: "file_text_modify.patch",
- Out: "file_text_modify.out",
- },
- },
- "textDelete": {
- Files: applyFiles{
- Src: "file_text.src",
- Patch: "file_text_delete.patch",
- Out: "file_text_delete.out",
- },
- },
- "textErrorPartialDelete": {
- Files: applyFiles{
- Src: "file_text.src",
- Patch: "file_text_error_partial_delete.patch",
- },
- Err: &Conflict{},
- },
- "binaryModify": {
- Files: getApplyFiles("file_bin_modify"),
- },
- "modeChange": {
- Files: getApplyFiles("file_mode_change"),
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- test.run(t, func(dst io.Writer, src io.ReaderAt, file *File) error {
- return Apply(dst, src, file)
- })
- })
- }
-}
-
-type applyTest struct {
- Files applyFiles
- Err interface{}
-}
-
-func (at applyTest) run(t *testing.T, apply func(io.Writer, io.ReaderAt, *File) error) {
- src, patch, out := at.Files.Load(t)
-
- files, _, err := Parse(bytes.NewReader(patch))
- if err != nil {
- t.Fatalf("failed to parse patch file: %v", err)
- }
- if len(files) != 1 {
- t.Fatalf("patch should contain exactly one file, but it has %d", len(files))
- }
-
- var dst bytes.Buffer
- err = apply(&dst, bytes.NewReader(src), files[0])
- if at.Err != nil {
- assertError(t, at.Err, err, "applying fragment")
- return
- }
- if err != nil {
- var aerr *ApplyError
- if errors.As(err, &aerr) {
- t.Fatalf("unexpected error applying: at %d: fragment %d at %d: %v", aerr.Line, aerr.Fragment, aerr.FragmentLine, err)
- } else {
- t.Fatalf("unexpected error applying: %v", err)
- }
- }
-
- if !bytes.Equal(out, dst.Bytes()) {
- t.Errorf("incorrect result after apply\nexpected:\n%q\nactual:\n%q", out, dst.Bytes())
- }
-}
-
-type applyFiles struct {
- Src string
- Patch string
- Out string
-}
-
-func getApplyFiles(name string) applyFiles {
- return applyFiles{
- Src: name + ".src",
- Patch: name + ".patch",
- Out: name + ".out",
- }
-}
-
-func (f applyFiles) Load(t *testing.T) (src []byte, patch []byte, out []byte) {
- load := func(name, kind string) []byte {
- d, err := ioutil.ReadFile(filepath.Join("testdata", "apply", name))
- if err != nil {
- t.Fatalf("failed to read %s file: %v", kind, err)
- }
- return d
- }
-
- if f.Src != "" {
- src = load(f.Src, "source")
- }
- if f.Patch != "" {
- patch = load(f.Patch, "patch")
- }
- if f.Out != "" {
- out = load(f.Out, "output")
- }
- return
-}
diff --git a/pkg/gitdiff/assert_test.go b/pkg/gitdiff/assert_test.go
deleted file mode 100644
index 878f13c..0000000
--- a/pkg/gitdiff/assert_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package gitdiff
-
-import (
- "errors"
- "strings"
- "testing"
-)
-
-func assertError(t *testing.T, expected interface{}, actual error, action string) {
- if actual == nil {
- t.Fatalf("expected error %s, but got nil", action)
- }
-
- switch exp := expected.(type) {
- case bool:
- if !exp {
- t.Fatalf("unexpected error %s: %v", action, actual)
- }
- case string:
- if !strings.Contains(actual.Error(), exp) {
- t.Fatalf("incorrect error %s: %q does not contain %q", action, actual.Error(), exp)
- }
- case error:
- if !errors.Is(actual, exp) {
- t.Fatalf("incorrect error %s: expected %T (%v), actual: %T (%v)", action, exp, exp, actual, actual)
- }
- default:
- t.Fatalf("unsupported expected error type: %T", exp)
- }
-}
diff --git a/pkg/gitdiff/base85_test.go b/pkg/gitdiff/base85_test.go
deleted file mode 100644
index 672c471..0000000
--- a/pkg/gitdiff/base85_test.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package gitdiff
-
-import (
- "bytes"
- "testing"
-)
-
-func TestBase85Decode(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output []byte
- Err bool
- }{
- "twoBytes": {
- Input: "%KiWV",
- Output: []byte{0xCA, 0xFE},
- },
- "fourBytes": {
- Input: "007GV",
- Output: []byte{0x0, 0x0, 0xCA, 0xFE},
- },
- "sixBytes": {
- Input: "007GV%KiWV",
- Output: []byte{0x0, 0x0, 0xCA, 0xFE, 0xCA, 0xFE},
- },
- "invalidCharacter": {
- Input: "00'GV",
- Err: true,
- },
- "underpaddedSequence": {
- Input: "007G",
- Err: true,
- },
- "dataUnderrun": {
- Input: "007GV",
- Output: make([]byte, 8),
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- dst := make([]byte, len(test.Output))
- err := base85Decode(dst, []byte(test.Input))
- if test.Err {
- if err == nil {
- t.Fatalf("expected error decoding base85 data, but got nil")
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error decoding base85 data: %v", err)
- }
- for i, b := range test.Output {
- if dst[i] != b {
- t.Errorf("incorrect byte at index %d: expected 0x%X, actual 0x%X", i, b, dst[i])
- }
- }
- })
- }
-}
-
-func TestBase85Encode(t *testing.T) {
- tests := map[string]struct {
- Input []byte
- Output string
- }{
- "zeroBytes": {
- Input: []byte{},
- Output: "",
- },
- "twoBytes": {
- Input: []byte{0xCA, 0xFE},
- Output: "%KiWV",
- },
- "fourBytes": {
- Input: []byte{0x0, 0x0, 0xCA, 0xFE},
- Output: "007GV",
- },
- "sixBytes": {
- Input: []byte{0x0, 0x0, 0xCA, 0xFE, 0xCA, 0xFE},
- Output: "007GV%KiWV",
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- dst := make([]byte, len(test.Output))
- base85Encode(dst, test.Input)
- for i, b := range test.Output {
- if dst[i] != byte(b) {
- t.Errorf("incorrect character at index %d: expected '%c', actual '%c'", i, b, dst[i])
- }
- }
- })
- }
-}
-
-func FuzzBase85Roundtrip(f *testing.F) {
- f.Add([]byte{0x2b, 0x0d})
- f.Add([]byte{0xbc, 0xb4, 0x3f})
- f.Add([]byte{0xfa, 0x62, 0x05, 0x83, 0x24, 0x39, 0xd5, 0x25})
- f.Add([]byte{0x31, 0x59, 0x02, 0xa0, 0x61, 0x12, 0xd9, 0x43, 0xb8, 0x23, 0x1a, 0xb4, 0x02, 0xae, 0xfa, 0xcc, 0x22, 0xad, 0x41, 0xb9, 0xb8})
-
- f.Fuzz(func(t *testing.T, in []byte) {
- n := len(in)
- dst := make([]byte, base85Len(n))
- out := make([]byte, n)
-
- base85Encode(dst, in)
- if err := base85Decode(out, dst); err != nil {
- t.Fatalf("unexpected error decoding base85 data: %v", err)
- }
- if !bytes.Equal(in, out) {
- t.Errorf("decoded data differed from input data:\n input: %x\n output: %x\nencoding: %s\n", in, out, string(dst))
- }
- })
-}
diff --git a/pkg/gitdiff/binary_test.go b/pkg/gitdiff/binary_test.go
deleted file mode 100644
index 64db243..0000000
--- a/pkg/gitdiff/binary_test.go
+++ /dev/null
@@ -1,324 +0,0 @@
-package gitdiff
-
-import (
- "encoding/binary"
- "io"
- "reflect"
- "strings"
- "testing"
-)
-
-func TestParseBinaryMarker(t *testing.T) {
- tests := map[string]struct {
- Input string
- IsBinary bool
- HasData bool
- Err bool
- }{
- "binaryPatch": {
- Input: "GIT binary patch\n",
- IsBinary: true,
- HasData: true,
- },
- "binaryFileNoPatch": {
- Input: "Binary files differ\n",
- IsBinary: true,
- HasData: false,
- },
- "binaryFileNoPatchPaths": {
- Input: "Binary files a/foo.bin and b/foo.bin differ\n",
- IsBinary: true,
- HasData: false,
- },
- "fileNoPatch": {
- Input: "Files differ\n",
- IsBinary: true,
- HasData: false,
- },
- "textFile": {
- Input: "@@ -10,14 +22,31 @@\n",
- IsBinary: false,
- HasData: false,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- isBinary, hasData, err := p.ParseBinaryMarker()
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing binary marker, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing binary marker: %v", err)
- }
- if test.IsBinary != isBinary {
- t.Errorf("incorrect isBinary value: expected %t, actual %t", test.IsBinary, isBinary)
- }
- if test.HasData != hasData {
- t.Errorf("incorrect hasData value: expected %t, actual %t", test.HasData, hasData)
- }
- })
- }
-}
-
-func TestParseBinaryFragmentHeader(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output *BinaryFragment
- Err bool
- }{
- "delta": {
- Input: "delta 1234\n",
- Output: &BinaryFragment{
- Method: BinaryPatchDelta,
- Size: 1234,
- },
- },
- "literal": {
- Input: "literal 1234\n",
- Output: &BinaryFragment{
- Method: BinaryPatchLiteral,
- Size: 1234,
- },
- },
- "unknownMethod": {
- Input: "compressed 1234\n",
- Output: nil,
- },
- "notAHeader": {
- Input: "Binary files differ\n",
- Output: nil,
- },
- "invalidSize": {
- Input: "delta 123abc\n",
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- frag, err := p.ParseBinaryFragmentHeader()
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing binary header, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing binary header: %v", err)
- }
- if !reflect.DeepEqual(test.Output, frag) {
- t.Errorf("incorrect binary fragment\nexpected: %+v\n actual: %+v", test.Output, frag)
- }
- })
- }
-}
-
-func TestParseBinaryChunk(t *testing.T) {
- tests := map[string]struct {
- Input string
- Fragment BinaryFragment
- Output []byte
- Err string
- }{
- "singleline": {
- Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n\n",
- Fragment: BinaryFragment{
- Size: 20,
- },
- Output: fib(5, binary.BigEndian),
- },
- "multiline": {
- Input: "zcmZQzU|?i`U?w2V48*KJ%mKu_Kr9NxN<eH5#F0Qe0f=7$l~*z_FeL$%-)3N7vt?l5\n" +
- "zl3-vE2xVZ9%4J~CI>f->s?WfX|B-=Vs{#X~svra7Ekg#T|4s}nH;WnAZ)|1Y*`&cB\n" +
- "s(sh?X(Uz6L^!Ou&aF*u`J!eibJifSrv0z>$Q%Hd(^HIJ<Y?5`S0gT5UE&u=k\n\n",
- Fragment: BinaryFragment{
- Size: 160,
- },
- Output: fib(40, binary.BigEndian),
- },
- "shortLine": {
- Input: "A00\n\n",
- Err: "corrupt data line",
- },
- "underpaddedLine": {
- Input: "H00000000\n\n",
- Err: "corrupt data line",
- },
- "invalidLengthByte": {
- Input: "!00000\n\n",
- Err: "invalid length byte",
- },
- "miscountedLine": {
- Input: "H00000\n\n",
- Err: "incorrect byte count",
- },
- "invalidEncoding": {
- Input: "TcmZQzU|?i'U?w2V48*Je09XJG\n",
- Err: "invalid base85 byte",
- },
- "noTrailingEmptyLine": {
- Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n",
- Err: "unexpected EOF",
- },
- "invalidCompression": {
- Input: "F007GV%KiWV\n\n",
- Err: "zlib",
- },
- "incorrectSize": {
- Input: "TcmZQzU|?i`U?w2V48*Je09XJG\n\n",
- Fragment: BinaryFragment{
- Size: 16,
- },
- Err: "16 byte fragment inflated to 20",
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- frag := test.Fragment
- err := p.ParseBinaryChunk(&frag)
- if test.Err != "" {
- if err == nil || !strings.Contains(err.Error(), test.Err) {
- t.Fatalf("expected error containing %q parsing binary chunk, but got %v", test.Err, err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing binary chunk: %v", err)
- }
- if !reflect.DeepEqual(test.Output, frag.Data) {
- t.Errorf("incorrect binary chunk\nexpected: %+v\n actual: %+v", test.Output, frag.Data)
- }
- })
- }
-}
-
-func TestParseBinaryFragments(t *testing.T) {
- tests := map[string]struct {
- Input string
- File File
-
- Binary bool
- Fragment *BinaryFragment
- ReverseFragment *BinaryFragment
- Err bool
- }{
- "dataWithReverse": {
- Input: `GIT binary patch
-literal 40
-gcmZQzU|?i` + "`" + `U?w2V48*KJ%mKu_Kr9NxN<eH500b)lkN^Mx
-
-literal 0
-HcmV?d00001
-
-`,
- Binary: true,
- Fragment: &BinaryFragment{
- Method: BinaryPatchLiteral,
- Size: 40,
- Data: fib(10, binary.BigEndian),
- },
- ReverseFragment: &BinaryFragment{
- Method: BinaryPatchLiteral,
- Size: 0,
- Data: []byte{},
- },
- },
- "dataWithoutReverse": {
- Input: `GIT binary patch
-literal 40
-gcmZQzU|?i` + "`" + `U?w2V48*KJ%mKu_Kr9NxN<eH500b)lkN^Mx
-
-`,
- Binary: true,
- Fragment: &BinaryFragment{
- Method: BinaryPatchLiteral,
- Size: 40,
- Data: fib(10, binary.BigEndian),
- },
- },
- "noData": {
- Input: "Binary files differ\n",
- Binary: true,
- },
- "text": {
- Input: `@@ -1 +1 @@
--old line
-+new line
-`,
- Binary: false,
- },
- "missingData": {
- Input: "GIT binary patch\n",
- Err: true,
- },
- "invalidData": {
- Input: `GIT binary patch
-literal 20
-TcmZQzU|?i'U?w2V48*Je09XJG
-
-`,
- Err: true,
- },
- "invalidReverseData": {
- Input: `GIT binary patch
-literal 20
-TcmZQzU|?i` + "`" + `U?w2V48*Je09XJG
-
-literal 0
-zcmV?d00001
-
-`,
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- file := test.File
- _, err := p.ParseBinaryFragments(&file)
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing binary fragments, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing binary fragments: %v", err)
- }
- if test.Binary != file.IsBinary {
- t.Errorf("incorrect binary state: expected %t, actual %t", test.Binary, file.IsBinary)
- }
- if !reflect.DeepEqual(test.Fragment, file.BinaryFragment) {
- t.Errorf("incorrect binary fragment\nexpected: %+v\n actual: %+v", test.Fragment, file.BinaryFragment)
- }
- if !reflect.DeepEqual(test.ReverseFragment, file.ReverseBinaryFragment) {
- t.Errorf("incorrect reverse binary fragment\nexpected: %+v\n actual: %+v", test.ReverseFragment, file.ReverseBinaryFragment)
- }
- })
- }
-}
-
-func fib(n int, ord binary.ByteOrder) []byte {
- buf := make([]byte, 4*n)
- for i := 0; i < len(buf); i += 4 {
- if i < 8 {
- ord.PutUint32(buf[i:], 1)
- } else {
- ord.PutUint32(buf[i:], ord.Uint32(buf[i-4:])+ord.Uint32(buf[i-8:]))
- }
- }
- return buf
-}
diff --git a/pkg/gitdiff/file_header_test.go b/pkg/gitdiff/file_header_test.go
deleted file mode 100644
index ef29833..0000000
--- a/pkg/gitdiff/file_header_test.go
+++ /dev/null
@@ -1,766 +0,0 @@
-package gitdiff
-
-import (
- "io"
- "os"
- "reflect"
- "testing"
-)
-
-func TestParseGitFileHeader(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output *File
- Err bool
- }{
- "fileContentChange": {
- Input: `diff --git a/dir/file.txt b/dir/file.txt
-index 1c23fcc..40a1b33 100644
---- a/dir/file.txt
-+++ b/dir/file.txt
-@@ -2,3 +4,5 @@
-`,
- Output: &File{
- OldName: "dir/file.txt",
- NewName: "dir/file.txt",
- OldMode: os.FileMode(0100644),
- OldOIDPrefix: "1c23fcc",
- NewOIDPrefix: "40a1b33",
- },
- },
- "newFile": {
- Input: `diff --git a/dir/file.txt b/dir/file.txt
-new file mode 100644
-index 0000000..f5711e4
---- /dev/null
-+++ b/dir/file.txt
-`,
- Output: &File{
- NewName: "dir/file.txt",
- NewMode: os.FileMode(0100644),
- OldOIDPrefix: "0000000",
- NewOIDPrefix: "f5711e4",
- IsNew: true,
- },
- },
- "newEmptyFile": {
- Input: `diff --git a/empty.txt b/empty.txt
-new file mode 100644
-index 0000000..e69de29
-`,
- Output: &File{
- NewName: "empty.txt",
- NewMode: os.FileMode(0100644),
- OldOIDPrefix: "0000000",
- NewOIDPrefix: "e69de29",
- IsNew: true,
- },
- },
- "deleteFile": {
- Input: `diff --git a/dir/file.txt b/dir/file.txt
-deleted file mode 100644
-index 44cc321..0000000
---- a/dir/file.txt
-+++ /dev/null
-`,
- Output: &File{
- OldName: "dir/file.txt",
- OldMode: os.FileMode(0100644),
- OldOIDPrefix: "44cc321",
- NewOIDPrefix: "0000000",
- IsDelete: true,
- },
- },
- "changeMode": {
- Input: `diff --git a/file.sh b/file.sh
-old mode 100644
-new mode 100755
-`,
- Output: &File{
- OldName: "file.sh",
- NewName: "file.sh",
- OldMode: os.FileMode(0100644),
- NewMode: os.FileMode(0100755),
- },
- },
- "rename": {
- Input: `diff --git a/foo.txt b/bar.txt
-similarity index 100%
-rename from foo.txt
-rename to bar.txt
-`,
- Output: &File{
- OldName: "foo.txt",
- NewName: "bar.txt",
- Score: 100,
- IsRename: true,
- },
- },
- "copy": {
- Input: `diff --git a/file.txt b/copy.txt
-similarity index 100%
-copy from file.txt
-copy to copy.txt
-`,
- Output: &File{
- OldName: "file.txt",
- NewName: "copy.txt",
- Score: 100,
- IsCopy: true,
- },
- },
- "missingDefaultFilename": {
- Input: `diff --git a/foo.sh b/bar.sh
-old mode 100644
-new mode 100755
-`,
- Err: true,
- },
- "missingNewFilename": {
- Input: `diff --git a/file.txt b/file.txt
-index 1c23fcc..40a1b33 100644
---- a/file.txt
-`,
- Err: true,
- },
- "missingOldFilename": {
- Input: `diff --git a/file.txt b/file.txt
-index 1c23fcc..40a1b33 100644
-+++ b/file.txt
-`,
- Err: true,
- },
- "invalidHeaderLine": {
- Input: `diff --git a/file.txt b/file.txt
-index deadbeef
---- a/file.txt
-+++ b/file.txt
-`,
- Err: true,
- },
- "notGitHeader": {
- Input: `--- file.txt
-+++ file.txt
-@@ -0,0 +1 @@
-`,
- Output: nil,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- f, err := p.ParseGitFileHeader()
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing git file header, got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing git file header: %v", err)
- }
-
- if !reflect.DeepEqual(test.Output, f) {
- t.Errorf("incorrect file\nexpected: %+v\n actual: %+v", test.Output, f)
- }
- })
- }
-}
-
-func TestParseTraditionalFileHeader(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output *File
- Err bool
- }{
- "fileContentChange": {
- Input: `--- dir/file_old.txt 2019-03-21 23:00:00.0 -0700
-+++ dir/file_new.txt 2019-03-21 23:30:00.0 -0700
-@@ -0,0 +1 @@
-`,
- Output: &File{
- OldName: "dir/file_new.txt",
- NewName: "dir/file_new.txt",
- },
- },
- "newFile": {
- Input: `--- /dev/null 1969-12-31 17:00:00.0 -0700
-+++ dir/file.txt 2019-03-21 23:30:00.0 -0700
-@@ -0,0 +1 @@
-`,
- Output: &File{
- NewName: "dir/file.txt",
- IsNew: true,
- },
- },
- "newFileTimestamp": {
- Input: `--- dir/file.txt 1969-12-31 17:00:00.0 -0700
-+++ dir/file.txt 2019-03-21 23:30:00.0 -0700
-@@ -0,0 +1 @@
-`,
- Output: &File{
- NewName: "dir/file.txt",
- IsNew: true,
- },
- },
- "deleteFile": {
- Input: `--- dir/file.txt 2019-03-21 23:30:00.0 -0700
-+++ /dev/null 1969-12-31 17:00:00.0 -0700
-@@ -0,0 +1 @@
-`,
- Output: &File{
- OldName: "dir/file.txt",
- IsDelete: true,
- },
- },
- "deleteFileTimestamp": {
- Input: `--- dir/file.txt 2019-03-21 23:30:00.0 -0700
-+++ dir/file.txt 1969-12-31 17:00:00.0 -0700
-@@ -0,0 +1 @@
-`,
- Output: &File{
- OldName: "dir/file.txt",
- IsDelete: true,
- },
- },
- "useShortestPrefixName": {
- Input: `--- dir/file.txt 2019-03-21 23:00:00.0 -0700
-+++ dir/file.txt~ 2019-03-21 23:30:00.0 -0700
-@@ -0,0 +1 @@
-`,
- Output: &File{
- OldName: "dir/file.txt",
- NewName: "dir/file.txt",
- },
- },
- "notTraditionalHeader": {
- Input: `diff --git a/dir/file.txt b/dir/file.txt
---- a/dir/file.txt
-+++ b/dir/file.txt
-`,
- Output: nil,
- },
- "noUnifiedFragment": {
- Input: `--- dir/file_old.txt 2019-03-21 23:00:00.0 -0700
-+++ dir/file_new.txt 2019-03-21 23:30:00.0 -0700
-context line
-+added line
-`,
- Output: nil,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- f, err := p.ParseTraditionalFileHeader()
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing traditional file header, got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing traditional file header: %v", err)
- }
-
- if !reflect.DeepEqual(test.Output, f) {
- t.Errorf("incorrect file\nexpected: %+v\n actual: %+v", test.Output, f)
- }
- })
- }
-}
-
-func TestCleanName(t *testing.T) {
- tests := map[string]struct {
- Input string
- Drop int
- Output string
- }{
- "alreadyClean": {
- Input: "a/b/c.txt", Output: "a/b/c.txt",
- },
- "doubleSlashes": {
- Input: "a//b/c.txt", Output: "a/b/c.txt",
- },
- "tripleSlashes": {
- Input: "a///b/c.txt", Output: "a/b/c.txt",
- },
- "dropPrefix": {
- Input: "a/b/c.txt", Drop: 2, Output: "c.txt",
- },
- "removeDoublesBeforeDrop": {
- Input: "a//b/c.txt", Drop: 1, Output: "b/c.txt",
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- output := cleanName(test.Input, test.Drop)
- if output != test.Output {
- t.Fatalf("incorrect output: expected %q, actual %q", test.Output, output)
- }
- })
- }
-}
-
-func TestParseName(t *testing.T) {
- tests := map[string]struct {
- Input string
- Term byte
- Drop int
- Output string
- N int
- Err bool
- }{
- "singleUnquoted": {
- Input: "dir/file.txt", Output: "dir/file.txt", N: 12,
- },
- "singleQuoted": {
- Input: `"dir/file.txt"`, Output: "dir/file.txt", N: 14,
- },
- "quotedWithEscape": {
- Input: `"dir/\"quotes\".txt"`, Output: `dir/"quotes".txt`, N: 20,
- },
- "quotedWithSpaces": {
- Input: `"dir/space file.txt"`, Output: "dir/space file.txt", N: 20,
- },
- "tabTerminator": {
- Input: "dir/space file.txt\tfile2.txt", Term: '\t', Output: "dir/space file.txt", N: 18,
- },
- "dropPrefix": {
- Input: "a/dir/file.txt", Drop: 1, Output: "dir/file.txt", N: 14,
- },
- "unquotedWithSpaces": {
- Input: "dir/with spaces.txt", Output: "dir/with spaces.txt", N: 19,
- },
- "unquotedWithTrailingSpaces": {
- Input: "dir/with spaces.space ", Output: "dir/with spaces.space ", N: 23,
- },
- "devNull": {
- Input: "/dev/null", Term: '\t', Drop: 1, Output: "/dev/null", N: 9,
- },
- "newlineSeparates": {
- Input: "dir/file.txt\n", Output: "dir/file.txt", N: 12,
- },
- "emptyString": {
- Input: "", Err: true,
- },
- "emptyQuotedString": {
- Input: `""`, Err: true,
- },
- "unterminatedQuotes": {
- Input: `"dir/file.txt`, Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- output, n, err := parseName(test.Input, test.Term, test.Drop)
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing name, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing name: %v", err)
- }
-
- if output != test.Output {
- t.Errorf("incorrect output: expected %q, actual: %q", test.Output, output)
- }
- if n != test.N {
- t.Errorf("incorrect next position: expected %d, actual %d", test.N, n)
- }
- })
- }
-}
-
-func TestParseGitHeaderData(t *testing.T) {
- tests := map[string]struct {
- InputFile *File
- Line string
- DefaultName string
-
- OutputFile *File
- End bool
- Err bool
- }{
- "fragementEndsParsing": {
- Line: "@@ -12,3 +12,2 @@\n",
- End: true,
- },
- "unknownEndsParsing": {
- Line: "GIT binary file\n",
- End: true,
- },
- "oldFileName": {
- Line: "--- a/dir/file.txt\n",
- OutputFile: &File{
- OldName: "dir/file.txt",
- },
- },
- "oldFileNameDevNull": {
- InputFile: &File{
- IsNew: true,
- },
- Line: "--- /dev/null\n",
- OutputFile: &File{
- IsNew: true,
- },
- },
- "oldFileNameInconsistent": {
- InputFile: &File{
- OldName: "dir/foo.txt",
- },
- Line: "--- a/dir/bar.txt\n",
- Err: true,
- },
- "oldFileNameExistingCreateMismatch": {
- InputFile: &File{
- OldName: "dir/foo.txt",
- IsNew: true,
- },
- Line: "--- /dev/null\n",
- Err: true,
- },
- "oldFileNameParsedCreateMismatch": {
- InputFile: &File{
- IsNew: true,
- },
- Line: "--- a/dir/file.txt\n",
- Err: true,
- },
- "oldFileNameMissing": {
- Line: "--- \n",
- Err: true,
- },
- "newFileName": {
- Line: "+++ b/dir/file.txt\n",
- OutputFile: &File{
- NewName: "dir/file.txt",
- },
- },
- "newFileNameDevNull": {
- InputFile: &File{
- IsDelete: true,
- },
- Line: "+++ /dev/null\n",
- OutputFile: &File{
- IsDelete: true,
- },
- },
- "newFileNameInconsistent": {
- InputFile: &File{
- NewName: "dir/foo.txt",
- },
- Line: "+++ b/dir/bar.txt\n",
- Err: true,
- },
- "newFileNameExistingDeleteMismatch": {
- InputFile: &File{
- NewName: "dir/foo.txt",
- IsDelete: true,
- },
- Line: "+++ /dev/null\n",
- Err: true,
- },
- "newFileNameParsedDeleteMismatch": {
- InputFile: &File{
- IsDelete: true,
- },
- Line: "+++ b/dir/file.txt\n",
- Err: true,
- },
- "newFileNameMissing": {
- Line: "+++ \n",
- Err: true,
- },
- "oldMode": {
- Line: "old mode 100644\n",
- OutputFile: &File{
- OldMode: os.FileMode(0100644),
- },
- },
- "oldModeWithTrailingSpace": {
- Line: "old mode 100644\r\n",
- OutputFile: &File{
- OldMode: os.FileMode(0100644),
- },
- },
- "invalidOldMode": {
- Line: "old mode rw\n",
- Err: true,
- },
- "newMode": {
- Line: "new mode 100755\n",
- OutputFile: &File{
- NewMode: os.FileMode(0100755),
- },
- },
- "newModeWithTrailingSpace": {
- Line: "new mode 100755\r\n",
- OutputFile: &File{
- NewMode: os.FileMode(0100755),
- },
- },
- "invalidNewMode": {
- Line: "new mode rwx\n",
- Err: true,
- },
- "deletedFileMode": {
- Line: "deleted file mode 100644\n",
- DefaultName: "dir/file.txt",
- OutputFile: &File{
- OldName: "dir/file.txt",
- OldMode: os.FileMode(0100644),
- IsDelete: true,
- },
- },
- "newFileMode": {
- Line: "new file mode 100755\n",
- DefaultName: "dir/file.txt",
- OutputFile: &File{
- NewName: "dir/file.txt",
- NewMode: os.FileMode(0100755),
- IsNew: true,
- },
- },
- "newFileModeWithTrailingSpace": {
- Line: "new file mode 100755\r\n",
- DefaultName: "dir/file.txt",
- OutputFile: &File{
- NewName: "dir/file.txt",
- NewMode: os.FileMode(0100755),
- IsNew: true,
- },
- },
- "copyFrom": {
- Line: "copy from dir/file.txt\n",
- OutputFile: &File{
- OldName: "dir/file.txt",
- IsCopy: true,
- },
- },
- "copyTo": {
- Line: "copy to dir/file.txt\n",
- OutputFile: &File{
- NewName: "dir/file.txt",
- IsCopy: true,
- },
- },
- "renameFrom": {
- Line: "rename from dir/file.txt\n",
- OutputFile: &File{
- OldName: "dir/file.txt",
- IsRename: true,
- },
- },
- "renameTo": {
- Line: "rename to dir/file.txt\n",
- OutputFile: &File{
- NewName: "dir/file.txt",
- IsRename: true,
- },
- },
- "similarityIndex": {
- Line: "similarity index 88%\n",
- OutputFile: &File{
- Score: 88,
- },
- },
- "similarityIndexTooBig": {
- Line: "similarity index 9001%\n",
- OutputFile: &File{
- Score: 0,
- },
- },
- "similarityIndexInvalid": {
- Line: "similarity index 12ab%\n",
- Err: true,
- },
- "indexFullSHA1AndMode": {
- Line: "index 79c6d7f7b7e76c75b3d238f12fb1323f2333ba14..04fab916d8f938173cbb8b93469855f0e838f098 100644\n",
- OutputFile: &File{
- OldOIDPrefix: "79c6d7f7b7e76c75b3d238f12fb1323f2333ba14",
- NewOIDPrefix: "04fab916d8f938173cbb8b93469855f0e838f098",
- OldMode: os.FileMode(0100644),
- },
- },
- "indexFullSHA1NoMode": {
- Line: "index 79c6d7f7b7e76c75b3d238f12fb1323f2333ba14..04fab916d8f938173cbb8b93469855f0e838f098\n",
- OutputFile: &File{
- OldOIDPrefix: "79c6d7f7b7e76c75b3d238f12fb1323f2333ba14",
- NewOIDPrefix: "04fab916d8f938173cbb8b93469855f0e838f098",
- },
- },
- "indexAbbrevSHA1AndMode": {
- Line: "index 79c6d7..04fab9 100644\n",
- OutputFile: &File{
- OldOIDPrefix: "79c6d7",
- NewOIDPrefix: "04fab9",
- OldMode: os.FileMode(0100644),
- },
- },
- "indexInvalid": {
- Line: "index 79c6d7f7b7e76c75b3d238f12fb1323f2333ba14\n",
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- var f File
- if test.InputFile != nil {
- f = *test.InputFile
- }
-
- end, err := parseGitHeaderData(&f, test.Line, test.DefaultName)
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing header data, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing header data: %v", err)
- }
-
- if test.OutputFile != nil && !reflect.DeepEqual(test.OutputFile, &f) {
- t.Errorf("incorrect output:\nexpected: %+v\nactual: %+v", test.OutputFile, &f)
- }
- if end != test.End {
- t.Errorf("incorrect end state, expected %t, actual %t", test.End, end)
- }
- })
- }
-}
-
-func TestParseGitHeaderName(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output string
- Err bool
- }{
- "twoMatchingNames": {
- Input: "a/dir/file.txt b/dir/file.txt",
- Output: "dir/file.txt",
- },
- "twoDifferentNames": {
- Input: "a/dir/foo.txt b/dir/bar.txt",
- Output: "",
- },
- "matchingNamesWithSpaces": {
- Input: "a/dir/file with spaces.txt b/dir/file with spaces.txt",
- Output: "dir/file with spaces.txt",
- },
- "matchingNamesWithTrailingSpaces": {
- Input: "a/dir/spaces b/dir/spaces ",
- Output: "dir/spaces ",
- },
- "matchingNamesQuoted": {
- Input: `"a/dir/\"quotes\".txt" "b/dir/\"quotes\".txt"`,
- Output: `dir/"quotes".txt`,
- },
- "matchingNamesFirstQuoted": {
- Input: `"a/dir/file.txt" b/dir/file.txt`,
- Output: "dir/file.txt",
- },
- "matchingNamesSecondQuoted": {
- Input: `a/dir/file.txt "b/dir/file.txt"`,
- Output: "dir/file.txt",
- },
- "noSecondName": {
- Input: "a/dir/foo.txt",
- Output: "",
- },
- "noSecondNameQuoted": {
- Input: `"a/dir/foo.txt"`,
- Output: "",
- },
- "invalidName": {
- Input: `"a/dir/file.txt b/dir/file.txt`,
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- output, err := parseGitHeaderName(test.Input)
- if test.Err {
- if err == nil {
- t.Fatalf("expected error parsing header name, but got nil")
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing header name: %v", err)
- }
-
- if output != test.Output {
- t.Errorf("incorrect output: expected %q, actual %q", test.Output, output)
- }
- })
- }
-}
-
-func TestHasEpochTimestamp(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output bool
- }{
- "utcTimestamp": {
- Input: "+++ file.txt\t1970-01-01 00:00:00 +0000\n",
- Output: true,
- },
- "utcZoneWithColon": {
- Input: "+++ file.txt\t1970-01-01 00:00:00 +00:00\n",
- Output: true,
- },
- "utcZoneWithMilliseconds": {
- Input: "+++ file.txt\t1970-01-01 00:00:00.000000 +00:00\n",
- Output: true,
- },
- "westTimestamp": {
- Input: "+++ file.txt\t1969-12-31 16:00:00 -0800\n",
- Output: true,
- },
- "eastTimestamp": {
- Input: "+++ file.txt\t1970-01-01 04:00:00 +0400\n",
- Output: true,
- },
- "noTab": {
- Input: "+++ file.txt 1970-01-01 00:00:00 +0000\n",
- Output: false,
- },
- "invalidFormat": {
- Input: "+++ file.txt\t1970-01-01T00:00:00Z\n",
- Output: false,
- },
- "notEpoch": {
- Input: "+++ file.txt\t2019-03-21 12:34:56.789 -0700\n",
- Output: false,
- },
- "notTimestamp": {
- Input: "+++ file.txt\trandom text\n",
- Output: false,
- },
- "notTimestampShort": {
- Input: "+++ file.txt\t0\n",
- Output: false,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- output := hasEpochTimestamp(test.Input)
- if output != test.Output {
- t.Errorf("incorrect output: expected %t, actual %t", test.Output, output)
- }
- })
- }
-}
diff --git a/pkg/gitdiff/format_roundtrip_test.go b/pkg/gitdiff/format_roundtrip_test.go
deleted file mode 100644
index a230e91..0000000
--- a/pkg/gitdiff/format_roundtrip_test.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package gitdiff
-
-import (
- "bytes"
- "fmt"
- "os"
- "path/filepath"
- "slices"
- "testing"
-)
-
-func TestFormatRoundtrip(t *testing.T) {
- patches := []struct {
- File string
- SkipTextCompare bool
- }{
- {File: "copy.patch"},
- {File: "copy_modify.patch"},
- {File: "delete.patch"},
- {File: "mode.patch"},
- {File: "mode_modify.patch"},
- {File: "modify.patch"},
- {File: "new.patch"},
- {File: "new_empty.patch"},
- {File: "new_mode.patch"},
- {File: "rename.patch"},
- {File: "rename_modify.patch"},
-
- // Due to differences between Go's 'encoding/zlib' package and the zlib
- // C library, binary patches cannot be compared directly as the patch
- // data is slightly different when re-encoded by Go.
- {File: "binary_modify.patch", SkipTextCompare: true},
- {File: "binary_new.patch", SkipTextCompare: true},
- {File: "binary_modify_nodata.patch"},
- }
-
- for _, patch := range patches {
- t.Run(patch.File, func(t *testing.T) {
- b, err := os.ReadFile(filepath.Join("testdata", "string", patch.File))
- if err != nil {
- t.Fatalf("failed to read patch: %v", err)
- }
-
- original := assertParseSingleFile(t, b, "patch")
- str := original.String()
-
- if !patch.SkipTextCompare {
- if string(b) != str {
- t.Errorf("incorrect patch text\nexpected: %q\n actual: %q\n", string(b), str)
- }
- }
-
- reparsed := assertParseSingleFile(t, []byte(str), "formatted patch")
- assertFilesEqual(t, original, reparsed)
- })
- }
-}
-
-func assertParseSingleFile(t *testing.T, b []byte, kind string) *File {
- files, _, err := Parse(bytes.NewReader(b))
- if err != nil {
- t.Fatalf("failed to parse %s: %v", kind, err)
- }
- if len(files) != 1 {
- t.Fatalf("expected %s to contain a single files, but found %d", kind, len(files))
- }
- return files[0]
-}
-
-func assertFilesEqual(t *testing.T, expected, actual *File) {
- assertEqual(t, expected.OldName, actual.OldName, "OldName")
- assertEqual(t, expected.NewName, actual.NewName, "NewName")
-
- assertEqual(t, expected.IsNew, actual.IsNew, "IsNew")
- assertEqual(t, expected.IsDelete, actual.IsDelete, "IsDelete")
- assertEqual(t, expected.IsCopy, actual.IsCopy, "IsCopy")
- assertEqual(t, expected.IsRename, actual.IsRename, "IsRename")
-
- assertEqual(t, expected.OldMode, actual.OldMode, "OldMode")
- assertEqual(t, expected.NewMode, actual.NewMode, "NewMode")
-
- assertEqual(t, expected.OldOIDPrefix, actual.OldOIDPrefix, "OldOIDPrefix")
- assertEqual(t, expected.NewOIDPrefix, actual.NewOIDPrefix, "NewOIDPrefix")
- assertEqual(t, expected.Score, actual.Score, "Score")
-
- if len(expected.TextFragments) == len(actual.TextFragments) {
- for i := range expected.TextFragments {
- prefix := fmt.Sprintf("TextFragments[%d].", i)
- ef := expected.TextFragments[i]
- af := actual.TextFragments[i]
-
- assertEqual(t, ef.Comment, af.Comment, prefix+"Comment")
-
- assertEqual(t, ef.OldPosition, af.OldPosition, prefix+"OldPosition")
- assertEqual(t, ef.OldLines, af.OldLines, prefix+"OldLines")
-
- assertEqual(t, ef.NewPosition, af.NewPosition, prefix+"NewPosition")
- assertEqual(t, ef.NewLines, af.NewLines, prefix+"NewLines")
-
- assertEqual(t, ef.LinesAdded, af.LinesAdded, prefix+"LinesAdded")
- assertEqual(t, ef.LinesDeleted, af.LinesDeleted, prefix+"LinesDeleted")
-
- assertEqual(t, ef.LeadingContext, af.LeadingContext, prefix+"LeadingContext")
- assertEqual(t, ef.TrailingContext, af.TrailingContext, prefix+"TrailingContext")
-
- if !slices.Equal(ef.Lines, af.Lines) {
- t.Errorf("%sLines: expected %#v, actual %#v", prefix, ef.Lines, af.Lines)
- }
- }
- } else {
- t.Errorf("TextFragments: expected length %d, actual length %d", len(expected.TextFragments), len(actual.TextFragments))
- }
-
- assertEqual(t, expected.IsBinary, actual.IsBinary, "IsBinary")
-
- if expected.BinaryFragment != nil {
- if actual.BinaryFragment == nil {
- t.Errorf("BinaryFragment: expected non-nil, actual is nil")
- } else {
- ef := expected.BinaryFragment
- af := expected.BinaryFragment
-
- assertEqual(t, ef.Method, af.Method, "BinaryFragment.Method")
- assertEqual(t, ef.Size, af.Size, "BinaryFragment.Size")
-
- if !slices.Equal(ef.Data, af.Data) {
- t.Errorf("BinaryFragment.Data: expected %#v, actual %#v", ef.Data, af.Data)
- }
- }
- } else if actual.BinaryFragment != nil {
- t.Errorf("BinaryFragment: expected nil, actual is non-nil")
- }
-
- if expected.ReverseBinaryFragment != nil {
- if actual.ReverseBinaryFragment == nil {
- t.Errorf("ReverseBinaryFragment: expected non-nil, actual is nil")
- } else {
- ef := expected.ReverseBinaryFragment
- af := expected.ReverseBinaryFragment
-
- assertEqual(t, ef.Method, af.Method, "ReverseBinaryFragment.Method")
- assertEqual(t, ef.Size, af.Size, "ReverseBinaryFragment.Size")
-
- if !slices.Equal(ef.Data, af.Data) {
- t.Errorf("ReverseBinaryFragment.Data: expected %#v, actual %#v", ef.Data, af.Data)
- }
- }
- } else if actual.ReverseBinaryFragment != nil {
- t.Errorf("ReverseBinaryFragment: expected nil, actual is non-nil")
- }
-}
-
-func assertEqual[T comparable](t *testing.T, expected, actual T, name string) {
- if expected != actual {
- t.Errorf("%s: expected %#v, actual %#v", name, expected, actual)
- }
-}
diff --git a/pkg/gitdiff/format_test.go b/pkg/gitdiff/format_test.go
deleted file mode 100644
index 3325296..0000000
--- a/pkg/gitdiff/format_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package gitdiff
-
-import (
- "strings"
- "testing"
-)
-
-func TestFormatter_WriteQuotedName(t *testing.T) {
- tests := []struct {
- Input string
- Expected string
- }{
- {"noquotes.txt", `noquotes.txt`},
- {"no quotes.txt", `no quotes.txt`},
- {"new\nline", `"new\nline"`},
- {"escape\x1B null\x00", `"escape\033 null\000"`},
- {"snowman \u2603 snowman", `"snowman \342\230\203 snowman"`},
- {"\"already quoted\"", `"\"already quoted\""`},
- }
-
- for _, test := range tests {
- var b strings.Builder
- newFormatter(&b).WriteQuotedName(test.Input)
- if b.String() != test.Expected {
- t.Errorf("expected %q, got %q", test.Expected, b.String())
- }
- }
-}
diff --git a/pkg/gitdiff/gitdiff_test.go b/pkg/gitdiff/gitdiff_test.go
deleted file mode 100644
index 4f63d51..0000000
--- a/pkg/gitdiff/gitdiff_test.go
+++ /dev/null
@@ -1,161 +0,0 @@
-package gitdiff
-
-import (
- "strings"
- "testing"
-)
-
-func TestTextFragmentValidate(t *testing.T) {
- tests := map[string]struct {
- Fragment TextFragment
- Err string
- }{
- "oldLines": {
- Fragment: TextFragment{
- OldPosition: 1,
- OldLines: 3,
- NewPosition: 1,
- NewLines: 2,
- LeadingContext: 1,
- TrailingContext: 0,
- LinesAdded: 1,
- LinesDeleted: 1,
- Lines: []Line{
- {Op: OpContext, Line: "line 1\n"},
- {Op: OpDelete, Line: "old line 2\n"},
- {Op: OpAdd, Line: "new line 2\n"},
- },
- },
- Err: "2 old lines",
- },
- "newLines": {
- Fragment: TextFragment{
- OldPosition: 1,
- OldLines: 2,
- NewPosition: 1,
- NewLines: 3,
- LeadingContext: 1,
- TrailingContext: 0,
- LinesAdded: 1,
- LinesDeleted: 1,
- Lines: []Line{
- {Op: OpContext, Line: "line 1\n"},
- {Op: OpDelete, Line: "old line 2\n"},
- {Op: OpAdd, Line: "new line 2\n"},
- },
- },
- Err: "2 new lines",
- },
- "leadingContext": {
- Fragment: TextFragment{
- OldPosition: 1,
- OldLines: 2,
- NewPosition: 1,
- NewLines: 2,
- LeadingContext: 0,
- TrailingContext: 0,
- LinesAdded: 1,
- LinesDeleted: 1,
- Lines: []Line{
- {Op: OpContext, Line: "line 1\n"},
- {Op: OpDelete, Line: "old line 2\n"},
- {Op: OpAdd, Line: "new line 2\n"},
- },
- },
- Err: "1 leading context lines",
- },
- "trailingContext": {
- Fragment: TextFragment{
- OldPosition: 1,
- OldLines: 4,
- NewPosition: 1,
- NewLines: 3,
- LeadingContext: 1,
- TrailingContext: 1,
- LinesAdded: 1,
- LinesDeleted: 2,
- Lines: []Line{
- {Op: OpContext, Line: "line 1\n"},
- {Op: OpDelete, Line: "old line 2\n"},
- {Op: OpAdd, Line: "new line 2\n"},
- {Op: OpContext, Line: "line 3\n"},
- {Op: OpDelete, Line: "old line 4\n"},
- },
- },
- Err: "0 trailing context lines",
- },
- "linesAdded": {
- Fragment: TextFragment{
- OldPosition: 1,
- OldLines: 4,
- NewPosition: 1,
- NewLines: 3,
- LeadingContext: 1,
- TrailingContext: 0,
- LinesAdded: 2,
- LinesDeleted: 2,
- Lines: []Line{
- {Op: OpContext, Line: "line 1\n"},
- {Op: OpDelete, Line: "old line 2\n"},
- {Op: OpAdd, Line: "new line 2\n"},
- {Op: OpContext, Line: "line 3\n"},
- {Op: OpDelete, Line: "old line 4\n"},
- },
- },
- Err: "1 added lines",
- },
- "linesDeleted": {
- Fragment: TextFragment{
- OldPosition: 1,
- OldLines: 4,
- NewPosition: 1,
- NewLines: 3,
- LeadingContext: 1,
- TrailingContext: 0,
- LinesAdded: 1,
- LinesDeleted: 1,
- Lines: []Line{
- {Op: OpContext, Line: "line 1\n"},
- {Op: OpDelete, Line: "old line 2\n"},
- {Op: OpAdd, Line: "new line 2\n"},
- {Op: OpContext, Line: "line 3\n"},
- {Op: OpDelete, Line: "old line 4\n"},
- },
- },
- Err: "2 deleted lines",
- },
- "fileCreation": {
- Fragment: TextFragment{
- OldPosition: 0,
- OldLines: 2,
- NewPosition: 1,
- NewLines: 1,
- LeadingContext: 0,
- TrailingContext: 0,
- LinesAdded: 1,
- LinesDeleted: 2,
- Lines: []Line{
- {Op: OpDelete, Line: "old line 1\n"},
- {Op: OpDelete, Line: "old line 2\n"},
- {Op: OpAdd, Line: "new line\n"},
- },
- },
- Err: "creation fragment",
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- err := test.Fragment.Validate()
- if test.Err == "" && err != nil {
- t.Fatalf("unexpected validation error: %v", err)
- }
- if test.Err != "" && err == nil {
- t.Fatal("expected validation error, but got nil")
- }
- if !strings.Contains(err.Error(), test.Err) {
- t.Fatalf("incorrect validation error: %q is not in %q", test.Err, err.Error())
- }
- })
- }
-}
diff --git a/pkg/gitdiff/io_test.go b/pkg/gitdiff/io_test.go
deleted file mode 100644
index bd242a7..0000000
--- a/pkg/gitdiff/io_test.go
+++ /dev/null
@@ -1,254 +0,0 @@
-package gitdiff
-
-import (
- "bytes"
- "fmt"
- "io"
- "math/rand"
- "testing"
-)
-
-func TestLineReaderAt(t *testing.T) {
- const lineTemplate = "generated test line %d\n"
-
- tests := map[string]struct {
- InputLines int
- Offset int64
- Count int
- Err bool
- EOF bool
- EOFCount int
- }{
- "readLines": {
- InputLines: 32,
- Offset: 0,
- Count: 4,
- },
- "readLinesOffset": {
- InputLines: 32,
- Offset: 8,
- Count: 4,
- },
- "readLinesLargeOffset": {
- InputLines: 8192,
- Offset: 4096,
- Count: 64,
- },
- "readSingleLine": {
- InputLines: 4,
- Offset: 2,
- Count: 1,
- },
- "readZeroLines": {
- InputLines: 4,
- Offset: 2,
- Count: 0,
- },
- "readAllLines": {
- InputLines: 64,
- Offset: 0,
- Count: 64,
- },
- "readThroughEOF": {
- InputLines: 16,
- Offset: 12,
- Count: 8,
- EOF: true,
- EOFCount: 4,
- },
- "emptyInput": {
- InputLines: 0,
- Offset: 0,
- Count: 2,
- EOF: true,
- EOFCount: 0,
- },
- "offsetAfterEOF": {
- InputLines: 8,
- Offset: 10,
- Count: 2,
- EOF: true,
- EOFCount: 0,
- },
- "offsetNegative": {
- InputLines: 8,
- Offset: -1,
- Count: 2,
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- var input bytes.Buffer
- for i := 0; i < test.InputLines; i++ {
- fmt.Fprintf(&input, lineTemplate, i)
- }
-
- output := make([][]byte, test.Count)
- for i := 0; i < test.Count; i++ {
- output[i] = []byte(fmt.Sprintf(lineTemplate, test.Offset+int64(i)))
- }
-
- r := &lineReaderAt{r: bytes.NewReader(input.Bytes())}
- lines := make([][]byte, test.Count)
-
- n, err := r.ReadLinesAt(lines, test.Offset)
- if test.Err {
- if err == nil {
- t.Fatal("expected error reading lines, but got nil")
- }
- return
- }
- if err != nil && (!test.EOF || err != io.EOF) {
- t.Fatalf("unexpected error reading lines: %v", err)
- }
-
- count := test.Count
- if test.EOF {
- count = test.EOFCount
- }
-
- if n != count {
- t.Fatalf("incorrect number of lines read: expected %d, actual %d", count, n)
- }
- for i := 0; i < n; i++ {
- if !bytes.Equal(output[i], lines[i]) {
- t.Errorf("incorrect content in line %d:\nexpected: %q\nactual: %q", i, output[i], lines[i])
- }
- }
- })
- }
-
- newlineTests := map[string]struct {
- InputSize int
- }{
- "readLinesNoFinalNewline": {
- InputSize: indexBufferSize + indexBufferSize/2,
- },
- "readLinesNoFinalNewlineBufferMultiple": {
- InputSize: 4 * indexBufferSize,
- },
- }
-
- for name, test := range newlineTests {
- t.Run(name, func(t *testing.T) {
- input := bytes.Repeat([]byte("0"), test.InputSize)
-
- var output [][]byte
- for i := 0; i < len(input); i++ {
- last := i
- i += rand.Intn(80)
- if i < len(input)-1 { // last character of input must not be a newline
- input[i] = '\n'
- output = append(output, input[last:i+1])
- } else {
- output = append(output, input[last:])
- }
- }
-
- r := &lineReaderAt{r: bytes.NewReader(input)}
- lines := make([][]byte, len(output))
-
- n, err := r.ReadLinesAt(lines, 0)
- if err != nil {
- t.Fatalf("unexpected error reading reading lines: %v", err)
- }
-
- if n != len(output) {
- t.Fatalf("incorrect number of lines read: expected %d, actual %d", len(output), n)
- }
-
- for i, line := range lines {
- if !bytes.Equal(output[i], line) {
- t.Errorf("incorrect content in line %d:\nexpected: %q\nactual: %q", i, output[i], line)
- }
- }
- })
- }
-}
-
-func TestCopyFrom(t *testing.T) {
- tests := map[string]struct {
- Bytes int64
- Offset int64
- }{
- "copyAll": {
- Bytes: byteBufferSize / 2,
- },
- "copyPartial": {
- Bytes: byteBufferSize / 2,
- Offset: byteBufferSize / 4,
- },
- "copyLarge": {
- Bytes: 8 * byteBufferSize,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- data := make([]byte, test.Bytes)
- rand.Read(data)
-
- var dst bytes.Buffer
- n, err := copyFrom(&dst, bytes.NewReader(data), test.Offset)
- if err != nil {
- t.Fatalf("unexpected error copying data: %v", err)
- }
- if n != test.Bytes-test.Offset {
- t.Fatalf("incorrect number of bytes copied: expected %d, actual %d", test.Bytes-test.Offset, n)
- }
-
- expected := data[test.Offset:]
- if !bytes.Equal(expected, dst.Bytes()) {
- t.Fatalf("incorrect data copied:\nexpected: %v\nactual: %v", expected, dst.Bytes())
- }
- })
- }
-}
-
-func TestCopyLinesFrom(t *testing.T) {
- tests := map[string]struct {
- Lines int64
- Offset int64
- }{
- "copyAll": {
- Lines: lineBufferSize / 2,
- },
- "copyPartial": {
- Lines: lineBufferSize / 2,
- Offset: lineBufferSize / 4,
- },
- "copyLarge": {
- Lines: 8 * lineBufferSize,
- },
- }
-
- const lineLength = 128
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- data := make([]byte, test.Lines*lineLength)
- for i := range data {
- data[i] = byte(32 + rand.Intn(95)) // ascii letters, numbers, symbols
- if i%lineLength == lineLength-1 {
- data[i] = '\n'
- }
- }
-
- var dst bytes.Buffer
- n, err := copyLinesFrom(&dst, &lineReaderAt{r: bytes.NewReader(data)}, test.Offset)
- if err != nil {
- t.Fatalf("unexpected error copying data: %v", err)
- }
- if n != test.Lines-test.Offset {
- t.Fatalf("incorrect number of lines copied: expected %d, actual %d", test.Lines-test.Offset, n)
- }
-
- expected := data[test.Offset*lineLength:]
- if !bytes.Equal(expected, dst.Bytes()) {
- t.Fatalf("incorrect data copied:\nexpected: %v\nactual: %v", expected, dst.Bytes())
- }
- })
- }
-}
diff --git a/pkg/gitdiff/parser_test.go b/pkg/gitdiff/parser_test.go
deleted file mode 100644
index 15a5d67..0000000
--- a/pkg/gitdiff/parser_test.go
+++ /dev/null
@@ -1,511 +0,0 @@
-package gitdiff
-
-import (
- "bytes"
- "encoding/binary"
- "encoding/json"
- "io"
- "os"
- "reflect"
- "testing"
-)
-
-func TestLineOperations(t *testing.T) {
- const content = "the first line\nthe second line\nthe third line\n"
-
- t.Run("read", func(t *testing.T) {
- p := newTestParser(content, false)
-
- for i, expected := range []string{
- "the first line\n",
- "the second line\n",
- "the third line\n",
- } {
- if err := p.Next(); err != nil {
- t.Fatalf("error advancing parser after line %d: %v", i, err)
- }
- if p.lineno != int64(i+1) {
- t.Fatalf("incorrect line number: expected %d, actual: %d", i+1, p.lineno)
- }
-
- line := p.Line(0)
- if line != expected {
- t.Fatalf("incorrect line %d: expected %q, was %q", i+1, expected, line)
- }
- }
-
- // reading after the last line should return EOF
- if err := p.Next(); err != io.EOF {
- t.Fatalf("expected EOF after end, but got: %v", err)
- }
- if p.lineno != 4 {
- t.Fatalf("incorrect line number: expected %d, actual: %d", 4, p.lineno)
- }
-
- // reading again returns EOF again and does not advance the line
- if err := p.Next(); err != io.EOF {
- t.Fatalf("expected EOF after end, but got: %v", err)
- }
- if p.lineno != 4 {
- t.Fatalf("incorrect line number: expected %d, actual: %d", 4, p.lineno)
- }
- })
-
- t.Run("peek", func(t *testing.T) {
- p := newTestParser(content, false)
- if err := p.Next(); err != nil {
- t.Fatalf("error advancing parser: %v", err)
- }
-
- line := p.Line(1)
- if line != "the second line\n" {
- t.Fatalf("incorrect peek line: %s", line)
- }
-
- if err := p.Next(); err != nil {
- t.Fatalf("error advancing parser after peek: %v", err)
- }
-
- line = p.Line(0)
- if line != "the second line\n" {
- t.Fatalf("incorrect read line: %s", line)
- }
- })
-
- t.Run("emptyInput", func(t *testing.T) {
- p := newTestParser("", false)
- if err := p.Next(); err != io.EOF {
- t.Fatalf("expected EOF on first Next(), but got: %v", err)
- }
- })
-}
-
-func TestParserInvariant_Advancement(t *testing.T) {
- tests := map[string]struct {
- Input string
- Parse func(p *parser) error
- EndLine string
- }{
- "ParseGitFileHeader": {
- Input: `diff --git a/dir/file.txt b/dir/file.txt
-index 9540595..30e6333 100644
---- a/dir/file.txt
-+++ b/dir/file.txt
-@@ -1,2 +1,3 @@
-context line
-`,
- Parse: func(p *parser) error {
- _, err := p.ParseGitFileHeader()
- return err
- },
- EndLine: "@@ -1,2 +1,3 @@\n",
- },
- "ParseTraditionalFileHeader": {
- Input: `--- dir/file.txt
-+++ dir/file.txt
-@@ -1,2 +1,3 @@
-context line
-`,
- Parse: func(p *parser) error {
- _, err := p.ParseTraditionalFileHeader()
- return err
- },
- EndLine: "@@ -1,2 +1,3 @@\n",
- },
- "ParseTextFragmentHeader": {
- Input: `@@ -1,2 +1,3 @@
-context line
-`,
- Parse: func(p *parser) error {
- _, err := p.ParseTextFragmentHeader()
- return err
- },
- EndLine: "context line\n",
- },
- "ParseTextChunk": {
- Input: ` context line
--old line
-+new line
- context line
-@@ -1 +1 @@
-`,
- Parse: func(p *parser) error {
- return p.ParseTextChunk(&TextFragment{OldLines: 3, NewLines: 3})
- },
- EndLine: "@@ -1 +1 @@\n",
- },
- "ParseTextFragments": {
- Input: `@@ -1,2 +1,2 @@
- context line
--old line
-+new line
-@@ -1,2 +1,2 @@
--old line
-+new line
- context line
-diff --git a/file.txt b/file.txt
-`,
- Parse: func(p *parser) error {
- _, err := p.ParseTextFragments(&File{})
- return err
- },
- EndLine: "diff --git a/file.txt b/file.txt\n",
- },
- "ParseNextFileHeader": {
- Input: `not a header
-diff --git a/file.txt b/file.txt
---- a/file.txt
-+++ b/file.txt
-@@ -1,2 +1,2 @@
-`,
- Parse: func(p *parser) error {
- _, _, err := p.ParseNextFileHeader()
- return err
- },
- EndLine: "@@ -1,2 +1,2 @@\n",
- },
- "ParseBinaryMarker": {
- Input: `Binary files differ
-diff --git a/file.txt b/file.txt
-`,
- Parse: func(p *parser) error {
- _, _, err := p.ParseBinaryMarker()
- return err
- },
- EndLine: "diff --git a/file.txt b/file.txt\n",
- },
- "ParseBinaryFragmentHeader": {
- Input: `literal 0
-HcmV?d00001
-`,
- Parse: func(p *parser) error {
- _, err := p.ParseBinaryFragmentHeader()
- return err
- },
- EndLine: "HcmV?d00001\n",
- },
- "ParseBinaryChunk": {
- Input: "TcmZQzU|?i`" + `U?w2V48*Je09XJG
-
-literal 0
-`,
- Parse: func(p *parser) error {
- return p.ParseBinaryChunk(&BinaryFragment{Size: 20})
- },
- EndLine: "literal 0\n",
- },
- "ParseBinaryFragments": {
- Input: `GIT binary patch
-literal 40
-gcmZQzU|?i` + "`" + `U?w2V48*KJ%mKu_Kr9NxN<eH500b)lkN^Mx
-
-literal 0
-HcmV?d00001
-
-diff --git a/file.txt b/file.txt
-`,
- Parse: func(p *parser) error {
- _, err := p.ParseBinaryFragments(&File{})
- return err
- },
- EndLine: "diff --git a/file.txt b/file.txt\n",
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- if err := test.Parse(p); err != nil {
- t.Fatalf("unexpected error while parsing: %v", err)
- }
-
- if test.EndLine != p.Line(0) {
- t.Errorf("incorrect position after parsing\nexpected: %q\n actual: %q", test.EndLine, p.Line(0))
- }
- })
- }
-}
-
-func TestParseNextFileHeader(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output *File
- Preamble string
- Err bool
- }{
- "gitHeader": {
- Input: `commit 1acbae563cd6ef5750a82ee64e116c6eb065cb94
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Tue Apr 2 22:30:00 2019 -0700
-
- This is a sample commit message.
-
-diff --git a/file.txt b/file.txt
-index cc34da1..1acbae5 100644
---- a/file.txt
-+++ b/file.txt
-@@ -1,3 +1,4 @@
-`,
- Output: &File{
- OldName: "file.txt",
- NewName: "file.txt",
- OldMode: os.FileMode(0100644),
- OldOIDPrefix: "cc34da1",
- NewOIDPrefix: "1acbae5",
- },
- Preamble: `commit 1acbae563cd6ef5750a82ee64e116c6eb065cb94
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Tue Apr 2 22:30:00 2019 -0700
-
- This is a sample commit message.
-
-`,
- },
- "traditionalHeader": {
- Input: `
---- file.txt 2019-04-01 22:58:14.833597918 -0700
-+++ file.txt 2019-04-01 22:58:14.833597918 -0700
-@@ -1,3 +1,4 @@
-`,
- Output: &File{
- OldName: "file.txt",
- NewName: "file.txt",
- },
- Preamble: "\n",
- },
- "noHeaders": {
- Input: `
-this is a line
-this is another line
---- could this be a header?
-nope, it's just some dashes
-`,
- Output: nil,
- Preamble: `
-this is a line
-this is another line
---- could this be a header?
-nope, it's just some dashes
-`,
- },
- "detatchedFragmentLike": {
- Input: `
-a wild fragment appears?
-@@ -1,3 +1,4 ~1,5 @@
-`,
- Output: nil,
- Preamble: `
-a wild fragment appears?
-@@ -1,3 +1,4 ~1,5 @@
-`,
- },
- "detatchedFragment": {
- Input: `
-a wild fragment appears?
-@@ -1,3 +1,4 @@
-`,
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- f, pre, err := p.ParseNextFileHeader()
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing next file header, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing next file header: %v", err)
- }
-
- if test.Preamble != pre {
- t.Errorf("incorrect preamble\nexpected: %q\n actual: %q", test.Preamble, pre)
- }
- if !reflect.DeepEqual(test.Output, f) {
- t.Errorf("incorrect file\nexpected: %+v\n actual: %+v", test.Output, f)
- }
- })
- }
-}
-
-func TestParse(t *testing.T) {
- textFragments := []*TextFragment{
- {
- OldPosition: 3,
- OldLines: 6,
- NewPosition: 3,
- NewLines: 8,
- Comment: "fragment 1",
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 1\n"},
- {OpDelete, "old line 2\n"},
- {OpContext, "context line\n"},
- {OpAdd, "new line 1\n"},
- {OpAdd, "new line 2\n"},
- {OpAdd, "new line 3\n"},
- {OpContext, "context line\n"},
- {OpDelete, "old line 3\n"},
- {OpAdd, "new line 4\n"},
- {OpAdd, "new line 5\n"},
- },
- LinesAdded: 5,
- LinesDeleted: 3,
- LeadingContext: 1,
- },
- {
- OldPosition: 31,
- OldLines: 2,
- NewPosition: 33,
- NewLines: 2,
- Comment: "fragment 2",
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 4\n"},
- {OpAdd, "new line 6\n"},
- },
- LinesAdded: 1,
- LinesDeleted: 1,
- LeadingContext: 1,
- },
- }
-
- textPreamble := `commit 5d9790fec7d95aa223f3d20936340bf55ff3dcbe
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Tue Apr 2 22:55:40 2019 -0700
-
- A file with multiple fragments.
-
- The content is arbitrary.
-
-`
-
- binaryPreamble := `commit 5d9790fec7d95aa223f3d20936340bf55ff3dcbe
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Tue Apr 2 22:55:40 2019 -0700
-
- A binary file with the first 10 fibonacci numbers.
-
-`
- tests := map[string]struct {
- InputFile string
- Output []*File
- Preamble string
- Err bool
- }{
- "oneFile": {
- InputFile: "testdata/one_file.patch",
- Output: []*File{
- {
- OldName: "dir/file1.txt",
- NewName: "dir/file1.txt",
- OldMode: os.FileMode(0100644),
- OldOIDPrefix: "ebe9fa54",
- NewOIDPrefix: "fe103e1d",
- TextFragments: textFragments,
- },
- },
- Preamble: textPreamble,
- },
- "twoFiles": {
- InputFile: "testdata/two_files.patch",
- Output: []*File{
- {
- OldName: "dir/file1.txt",
- NewName: "dir/file1.txt",
- OldMode: os.FileMode(0100644),
- OldOIDPrefix: "ebe9fa54",
- NewOIDPrefix: "fe103e1d",
- TextFragments: textFragments,
- },
- {
- OldName: "dir/file2.txt",
- NewName: "dir/file2.txt",
- OldMode: os.FileMode(0100644),
- OldOIDPrefix: "417ebc70",
- NewOIDPrefix: "67514b7f",
- TextFragments: textFragments,
- },
- },
- Preamble: textPreamble,
- },
- "noFiles": {
- InputFile: "testdata/no_files.patch",
- Output: nil,
- Preamble: textPreamble,
- },
- "newBinaryFile": {
- InputFile: "testdata/new_binary_file.patch",
- Output: []*File{
- {
- OldName: "",
- NewName: "dir/ten.bin",
- NewMode: os.FileMode(0100644),
- OldOIDPrefix: "0000000000000000000000000000000000000000",
- NewOIDPrefix: "77b068ba48c356156944ea714740d0d5ca07bfec",
- IsNew: true,
- IsBinary: true,
- BinaryFragment: &BinaryFragment{
- Method: BinaryPatchLiteral,
- Size: 40,
- Data: fib(10, binary.BigEndian),
- },
- ReverseBinaryFragment: &BinaryFragment{
- Method: BinaryPatchLiteral,
- Size: 0,
- Data: []byte{},
- },
- },
- },
- Preamble: binaryPreamble,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- f, err := os.Open(test.InputFile)
- if err != nil {
- t.Fatalf("unexpected error opening input file: %v", err)
- }
-
- files, pre, err := Parse(f)
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing patch, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing patch: %v", err)
- }
-
- if len(test.Output) != len(files) {
- t.Fatalf("incorrect number of parsed files: expected %d, actual %d", len(test.Output), len(files))
- }
- if test.Preamble != pre {
- t.Errorf("incorrect preamble\nexpected: %q\n actual: %q", test.Preamble, pre)
- }
- for i := range test.Output {
- if !reflect.DeepEqual(test.Output[i], files[i]) {
- exp, _ := json.MarshalIndent(test.Output[i], "", " ")
- act, _ := json.MarshalIndent(files[i], "", " ")
- t.Errorf("incorrect file at position %d\nexpected: %s\n actual: %s", i, exp, act)
- }
- }
- })
- }
-}
-
-func newTestParser(input string, init bool) *parser {
- p := newParser(bytes.NewBufferString(input))
- if init {
- _ = p.Next()
- }
- return p
-}
diff --git a/pkg/gitdiff/patch_header_test.go b/pkg/gitdiff/patch_header_test.go
deleted file mode 100644
index c8559b0..0000000
--- a/pkg/gitdiff/patch_header_test.go
+++ /dev/null
@@ -1,590 +0,0 @@
-package gitdiff
-
-import (
- "testing"
- "time"
-)
-
-func TestParsePatchDate(t *testing.T) {
- expected := time.Date(2020, 4, 9, 8, 7, 6, 0, time.UTC)
-
- tests := map[string]struct {
- Input string
- Output time.Time
- Err interface{}
- }{
- "default": {
- Input: "Thu Apr 9 01:07:06 2020 -0700",
- Output: expected,
- },
- "defaultLocal": {
- Input: "Thu Apr 9 01:07:06 2020",
- Output: time.Date(2020, 4, 9, 1, 7, 6, 0, time.Local),
- },
- "iso": {
- Input: "2020-04-09 01:07:06 -0700",
- Output: expected,
- },
- "isoStrict": {
- Input: "2020-04-09T01:07:06-07:00",
- Output: expected,
- },
- "rfc": {
- Input: "Thu, 9 Apr 2020 01:07:06 -0700",
- Output: expected,
- },
- "short": {
- Input: "2020-04-09",
- Output: time.Date(2020, 4, 9, 0, 0, 0, 0, time.Local),
- },
- "raw": {
- Input: "1586419626 -0700",
- Output: expected,
- },
- "unix": {
- Input: "1586419626",
- Output: expected,
- },
- "unknownFormat": {
- Input: "4/9/2020 01:07:06 PDT",
- Err: "unknown date format",
- },
- "empty": {
- Input: "",
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- d, err := ParsePatchDate(test.Input)
- if test.Err != nil {
- assertError(t, test.Err, err, "parsing date")
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing date: %v", err)
- }
- if !test.Output.Equal(d) {
- t.Errorf("incorrect parsed date: expected %v, actual %v", test.Output, d)
- }
- })
- }
-}
-
-func TestParsePatchHeader(t *testing.T) {
- expectedSHA := "61f5cd90bed4d204ee3feb3aa41ee91d4734855b"
- expectedIdentity := &PatchIdentity{
- Name: "Morton Haypenny",
- Email: "mhaypenny@example.com",
- }
- expectedDate := time.Date(2020, 04, 11, 15, 21, 23, 0, time.FixedZone("PDT", -7*60*60))
- expectedTitle := "A sample commit to test header parsing"
- expectedEmojiOneLineTitle := "๐Ÿค– Enabling auto-merging"
- expectedEmojiMultiLineTitle := "[IA64] Put ia64 config files on the Uwe Kleine-Kรถnig diet"
- expectedBody := "The medium format shows the body, which\nmay wrap on to multiple lines.\n\nAnother body line."
- expectedBodyAppendix := "CC: Joe Smith <joe.smith@company.com>"
-
- tests := map[string]struct {
- Input string
- Options []PatchHeaderOption
- Header PatchHeader
- Err interface{}
- }{
- "prettyShort": {
- Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
-Author: Morton Haypenny <mhaypenny@example.com>
-
- A sample commit to test header parsing
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- Title: expectedTitle,
- },
- },
- "prettyMedium": {
- Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Sat Apr 11 15:21:23 2020 -0700
-
- A sample commit to test header parsing
-
- The medium format shows the body, which
- may wrap on to multiple lines.
-
- Another body line.
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Title: expectedTitle,
- Body: expectedBody,
- },
- },
- "prettyFull": {
- Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
-Author: Morton Haypenny <mhaypenny@example.com>
-Commit: Morton Haypenny <mhaypenny@example.com>
-
- A sample commit to test header parsing
-
- The medium format shows the body, which
- may wrap on to multiple lines.
-
- Another body line.
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- Committer: expectedIdentity,
- Title: expectedTitle,
- Body: expectedBody,
- },
- },
- "prettyFuller": {
- Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
-Author: Morton Haypenny <mhaypenny@example.com>
-AuthorDate: Sat Apr 11 15:21:23 2020 -0700
-Commit: Morton Haypenny <mhaypenny@example.com>
-CommitDate: Sat Apr 11 15:21:23 2020 -0700
-
- A sample commit to test header parsing
-
- The medium format shows the body, which
- may wrap on to multiple lines.
-
- Another body line.
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Committer: expectedIdentity,
- CommitterDate: expectedDate,
- Title: expectedTitle,
- Body: expectedBody,
- },
- },
- "prettyAppendix": {
- Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
-Author: Morton Haypenny <mhaypenny@example.com>
-AuthorDate: Sat Apr 11 15:21:23 2020 -0700
-Commit: Morton Haypenny <mhaypenny@example.com>
-CommitDate: Sat Apr 11 15:21:23 2020 -0700
-
- A sample commit to test header parsing
-
- The medium format shows the body, which
- may wrap on to multiple lines.
-
- Another body line.
- ---
- CC: Joe Smith <joe.smith@company.com>
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Committer: expectedIdentity,
- CommitterDate: expectedDate,
- Title: expectedTitle,
- Body: expectedBody + "\n---\n" + expectedBodyAppendix,
- },
- },
- "mailbox": {
- Input: `From 61f5cd90bed4d204ee3feb3aa41ee91d4734855b Mon Sep 17 00:00:00 2001
-From: Morton Haypenny <mhaypenny@example.com>
-Date: Sat, 11 Apr 2020 15:21:23 -0700
-Subject: [PATCH] A sample commit to test header parsing
-
-The medium format shows the body, which
-may wrap on to multiple lines.
-
-Another body line.
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Title: expectedTitle,
- Body: expectedBody,
- },
- },
- "mailboxPatchOnly": {
- Input: `From 61f5cd90bed4d204ee3feb3aa41ee91d4734855b Mon Sep 17 00:00:00 2001
-From: Morton Haypenny <mhaypenny@example.com>
-Date: Sat, 11 Apr 2020 15:21:23 -0700
-Subject: [PATCH] [BUG-123] A sample commit to test header parsing
-
-The medium format shows the body, which
-may wrap on to multiple lines.
-
-Another body line.
-`,
- Options: []PatchHeaderOption{
- WithSubjectCleanMode(SubjectCleanPatchOnly),
- },
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Title: "[BUG-123] " + expectedTitle,
- Body: expectedBody,
- },
- },
- "mailboxEmojiOneLine": {
- Input: `From 61f5cd90bed4d204ee3feb3aa41ee91d4734855b Mon Sep 17 00:00:00 2001
-From: Morton Haypenny <mhaypenny@example.com>
-Date: Sat, 11 Apr 2020 15:21:23 -0700
-Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Enabling=20auto-merging?=
-
-The medium format shows the body, which
-may wrap on to multiple lines.
-
-Another body line.
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Title: expectedEmojiOneLineTitle,
- Body: expectedBody,
- },
- },
- "mailboxEmojiMultiLine": {
- Input: `From 61f5cd90bed4d204ee3feb3aa41ee91d4734855b Mon Sep 17 00:00:00 2001
-From: Morton Haypenny <mhaypenny@example.com>
-Date: Sat, 11 Apr 2020 15:21:23 -0700
-Subject: [PATCH] =?UTF-8?q?[IA64]=20Put=20ia64=20config=20files=20on=20the=20?=
- =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20diet?=
-
-The medium format shows the body, which
-may wrap on to multiple lines.
-
-Another body line.
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Title: expectedEmojiMultiLineTitle,
- Body: expectedBody,
- },
- },
- "mailboxRFC5322SpecialCharacters": {
- Input: `From 61f5cd90bed4d204ee3feb3aa41ee91d4734855b Mon Sep 17 00:00:00 2001
-From: "dependabot[bot]" <12345+dependabot[bot]@users.noreply.github.com>
-Date: Sat, 11 Apr 2020 15:21:23 -0700
-Subject: [PATCH] A sample commit to test header parsing
-
-The medium format shows the body, which
-may wrap on to multiple lines.
-
-Another body line.
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: &PatchIdentity{
- Name: "dependabot[bot]",
- Email: "12345+dependabot[bot]@users.noreply.github.com",
- },
- AuthorDate: expectedDate,
- Title: expectedTitle,
- Body: expectedBody,
- },
- },
- "mailboxAppendix": {
- Input: `From 61f5cd90bed4d204ee3feb3aa41ee91d4734855b Mon Sep 17 00:00:00 2001
-From: Morton Haypenny <mhaypenny@example.com>
-Date: Sat, 11 Apr 2020 15:21:23 -0700
-Subject: [PATCH] A sample commit to test header parsing
-
-The medium format shows the body, which
-may wrap on to multiple lines.
-
-Another body line.
----
-CC: Joe Smith <joe.smith@company.com>
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Title: expectedTitle,
- Body: expectedBody,
- BodyAppendix: expectedBodyAppendix,
- },
- },
- "mailboxMinimalNoName": {
- Input: `From: <mhaypenny@example.com>
-Subject: [PATCH] A sample commit to test header parsing
-
-The medium format shows the body, which
-may wrap on to multiple lines.
-
-Another body line.
-`,
- Header: PatchHeader{
- Author: &PatchIdentity{expectedIdentity.Email, expectedIdentity.Email},
- Title: expectedTitle,
- Body: expectedBody,
- },
- },
- "mailboxMinimal": {
- Input: `From: Morton Haypenny <mhaypenny@example.com>
-Subject: [PATCH] A sample commit to test header parsing
-
-The medium format shows the body, which
-may wrap on to multiple lines.
-
-Another body line.
-`,
- Header: PatchHeader{
- Author: expectedIdentity,
- Title: expectedTitle,
- Body: expectedBody,
- },
- },
- "unwrapTitle": {
- Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Sat Apr 11 15:21:23 2020 -0700
-
- A sample commit to test header parsing with a long
- title that is wrapped.
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Title: expectedTitle + " with a long title that is wrapped.",
- },
- },
- "normalizeBodySpace": {
- Input: `commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Sat Apr 11 15:21:23 2020 -0700
-
- A sample commit to test header parsing
-
-
- The medium format shows the body, which
- may wrap on to multiple lines.
-
-
- Another body line.
-
-
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- AuthorDate: expectedDate,
- Title: expectedTitle,
- Body: expectedBody,
- },
- },
- "ignoreLeadingBlankLines": {
- Input: `
-
-` + " " + `
-commit 61f5cd90bed4d204ee3feb3aa41ee91d4734855b
-Author: Morton Haypenny <mhaypenny@example.com>
-
- A sample commit to test header parsing
-`,
- Header: PatchHeader{
- SHA: expectedSHA,
- Author: expectedIdentity,
- Title: expectedTitle,
- },
- },
- "emptyHeader": {
- Input: "",
- Header: PatchHeader{},
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- h, err := ParsePatchHeader(test.Input, test.Options...)
- if test.Err != nil {
- assertError(t, test.Err, err, "parsing patch header")
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing patch header: %v", err)
- }
- if h == nil {
- t.Fatalf("expected non-nil header, but got nil")
- }
-
- exp := test.Header
- act := *h
-
- if exp.SHA != act.SHA {
- t.Errorf("incorrect parsed SHA: expected %q, actual %q", exp.SHA, act.SHA)
- }
-
- assertPatchIdentity(t, "author", exp.Author, act.Author)
- if !exp.AuthorDate.Equal(act.AuthorDate) {
- t.Errorf("incorrect parsed author date: expected %v, but got %v", exp.AuthorDate, act.AuthorDate)
- }
-
- assertPatchIdentity(t, "committer", exp.Committer, act.Committer)
- if !exp.CommitterDate.Equal(act.CommitterDate) {
- t.Errorf("incorrect parsed committer date: expected %v, but got %v", exp.CommitterDate, act.CommitterDate)
- }
-
- if exp.Title != act.Title {
- t.Errorf("incorrect parsed title:\n expected: %q\n actual: %q", exp.Title, act.Title)
- }
- if exp.Body != act.Body {
- t.Errorf("incorrect parsed body:\n expected: %q\n actual: %q", exp.Body, act.Body)
- }
- if exp.BodyAppendix != act.BodyAppendix {
- t.Errorf("incorrect parsed body appendix:\n expected: %q\n actual: %q",
- exp.BodyAppendix, act.BodyAppendix)
- }
- })
- }
-}
-
-func assertPatchIdentity(t *testing.T, kind string, exp, act *PatchIdentity) {
- switch {
- case exp == nil && act == nil:
- case exp == nil && act != nil:
- t.Errorf("incorrect parsed %s: expected nil, but got %+v", kind, act)
- case exp != nil && act == nil:
- t.Errorf("incorrect parsed %s: expected %+v, but got nil", kind, exp)
- case exp.Name != act.Name || exp.Email != act.Email:
- t.Errorf("incorrect parsed %s, expected %+v, bot got %+v", kind, exp, act)
- }
-}
-
-func TestCleanSubject(t *testing.T) {
- expectedSubject := "A sample commit to test header parsing"
-
- tests := map[string]struct {
- Input string
- Mode SubjectCleanMode
- Prefix string
- Subject string
- }{
- "CleanAll/noPrefix": {
- Input: expectedSubject,
- Mode: SubjectCleanAll,
- Subject: expectedSubject,
- },
- "CleanAll/patchPrefix": {
- Input: "[PATCH] " + expectedSubject,
- Mode: SubjectCleanAll,
- Prefix: "[PATCH] ",
- Subject: expectedSubject,
- },
- "CleanAll/patchPrefixNoSpace": {
- Input: "[PATCH]" + expectedSubject,
- Mode: SubjectCleanAll,
- Prefix: "[PATCH]",
- Subject: expectedSubject,
- },
- "CleanAll/patchPrefixContent": {
- Input: "[PATCH 3/7] " + expectedSubject,
- Mode: SubjectCleanAll,
- Prefix: "[PATCH 3/7] ",
- Subject: expectedSubject,
- },
- "CleanAll/spacePrefix": {
- Input: " " + expectedSubject,
- Mode: SubjectCleanAll,
- Subject: expectedSubject,
- },
- "CleanAll/replyLowerPrefix": {
- Input: "re: " + expectedSubject,
- Mode: SubjectCleanAll,
- Prefix: "re: ",
- Subject: expectedSubject,
- },
- "CleanAll/replyMixedPrefix": {
- Input: "Re: " + expectedSubject,
- Mode: SubjectCleanAll,
- Prefix: "Re: ",
- Subject: expectedSubject,
- },
- "CleanAll/replyCapsPrefix": {
- Input: "RE: " + expectedSubject,
- Mode: SubjectCleanAll,
- Prefix: "RE: ",
- Subject: expectedSubject,
- },
- "CleanAll/replyDoublePrefix": {
- Input: "Re: re: " + expectedSubject,
- Mode: SubjectCleanAll,
- Prefix: "Re: re: ",
- Subject: expectedSubject,
- },
- "CleanAll/noPrefixSubjectHasRe": {
- Input: "Reimplement parsing",
- Mode: SubjectCleanAll,
- Subject: "Reimplement parsing",
- },
- "CleanAll/patchPrefixSubjectHasRe": {
- Input: "[PATCH 1/2] Reimplement parsing",
- Mode: SubjectCleanAll,
- Prefix: "[PATCH 1/2] ",
- Subject: "Reimplement parsing",
- },
- "CleanAll/unclosedPrefix": {
- Input: "[Just to annoy people",
- Mode: SubjectCleanAll,
- Subject: "[Just to annoy people",
- },
- "CleanAll/multiplePrefix": {
- Input: " Re:Re: [PATCH 1/2][DRAFT] " + expectedSubject + " ",
- Mode: SubjectCleanAll,
- Prefix: "Re:Re: [PATCH 1/2][DRAFT] ",
- Subject: expectedSubject,
- },
- "CleanPatchOnly/patchPrefix": {
- Input: "[PATCH] " + expectedSubject,
- Mode: SubjectCleanPatchOnly,
- Prefix: "[PATCH] ",
- Subject: expectedSubject,
- },
- "CleanPatchOnly/mixedPrefix": {
- Input: "[PATCH] [TICKET-123] " + expectedSubject,
- Mode: SubjectCleanPatchOnly,
- Prefix: "[PATCH] ",
- Subject: "[TICKET-123] " + expectedSubject,
- },
- "CleanPatchOnly/multiplePrefix": {
- Input: "Re:Re: [PATCH 1/2][DRAFT] " + expectedSubject,
- Mode: SubjectCleanPatchOnly,
- Prefix: "Re:Re: [PATCH 1/2]",
- Subject: "[DRAFT] " + expectedSubject,
- },
- "CleanWhitespace/leadingSpace": {
- Input: " [PATCH] " + expectedSubject,
- Mode: SubjectCleanWhitespace,
- Subject: "[PATCH] " + expectedSubject,
- },
- "CleanWhitespace/trailingSpace": {
- Input: "[PATCH] " + expectedSubject + " ",
- Mode: SubjectCleanWhitespace,
- Subject: "[PATCH] " + expectedSubject,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- prefix, subject := cleanSubject(test.Input, test.Mode)
- if prefix != test.Prefix {
- t.Errorf("incorrect prefix: expected %q, actual %q", test.Prefix, prefix)
- }
- if subject != test.Subject {
- t.Errorf("incorrect subject: expected %q, actual %q", test.Subject, subject)
- }
- })
- }
-}
diff --git a/pkg/gitdiff/patch_identity_test.go b/pkg/gitdiff/patch_identity_test.go
deleted file mode 100644
index f15fe38..0000000
--- a/pkg/gitdiff/patch_identity_test.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package gitdiff
-
-import (
- "testing"
-)
-
-func TestParsePatchIdentity(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output PatchIdentity
- Err interface{}
- }{
- "simple": {
- Input: "Morton Haypenny <mhaypenny@example.com>",
- Output: PatchIdentity{
- Name: "Morton Haypenny",
- Email: "mhaypenny@example.com",
- },
- },
- "extraWhitespace": {
- Input: "\t Morton Haypenny \r\n<mhaypenny@example.com> ",
- Output: PatchIdentity{
- Name: "Morton Haypenny",
- Email: "mhaypenny@example.com",
- },
- },
- "trailingCharacters": {
- Input: "Morton Haypenny <mhaypenny@example.com> II",
- Output: PatchIdentity{
- Name: "Morton Haypenny II",
- Email: "mhaypenny@example.com",
- },
- },
- "onlyEmail": {
- Input: "mhaypenny@example.com",
- Output: PatchIdentity{
- Name: "mhaypenny@example.com",
- Email: "mhaypenny@example.com",
- },
- },
- "onlyEmailInBrackets": {
- Input: "<mhaypenny@example.com>",
- Output: PatchIdentity{
- Name: "mhaypenny@example.com",
- Email: "mhaypenny@example.com",
- },
- },
- "rfc5322SpecialCharacters": {
- Input: `"dependabot[bot]" <12345+dependabot[bot]@users.noreply.github.com>`,
- Output: PatchIdentity{
- Name: "dependabot[bot]",
- Email: "12345+dependabot[bot]@users.noreply.github.com",
- },
- },
- "rfc5322QuotedPairs": {
- Input: `"Morton \"Old-Timer\" Haypenny" <"mhaypenny\+[1900]"@example.com> (III \(PhD\))`,
- Output: PatchIdentity{
- Name: `Morton "Old-Timer" Haypenny (III (PhD))`,
- Email: "mhaypenny+[1900]@example.com",
- },
- },
- "rfc5322QuotedPairsOutOfContext": {
- Input: `Morton \\Backslash Haypenny <mhaypenny@example.com>`,
- Output: PatchIdentity{
- Name: `Morton \\Backslash Haypenny`,
- Email: "mhaypenny@example.com",
- },
- },
- "emptyEmail": {
- Input: "Morton Haypenny <>",
- Output: PatchIdentity{
- Name: "Morton Haypenny",
- Email: "",
- },
- },
- "unclosedEmail": {
- Input: "Morton Haypenny <mhaypenny@example.com",
- Output: PatchIdentity{
- Name: "Morton Haypenny",
- Email: "mhaypenny@example.com",
- },
- },
- "bogusEmail": {
- Input: "Morton Haypenny <mhaypenny>",
- Output: PatchIdentity{
- Name: "Morton Haypenny",
- Email: "mhaypenny",
- },
- },
- "bogusEmailWithWhitespace": {
- Input: "Morton Haypenny < mhaypenny >",
- Output: PatchIdentity{
- Name: "Morton Haypenny",
- Email: "mhaypenny",
- },
- },
- "missingEmail": {
- Input: "Morton Haypenny",
- Err: "invalid identity",
- },
- "missingNameAndEmptyEmail": {
- Input: "<>",
- Err: "invalid identity",
- },
- "empty": {
- Input: "",
- Err: "invalid identity",
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- id, err := ParsePatchIdentity(test.Input)
- if test.Err != nil {
- assertError(t, test.Err, err, "parsing identity")
- return
- }
- if err != nil {
- t.Fatalf("unexpected error parsing identity: %v", err)
- }
-
- if test.Output != id {
- t.Errorf("incorrect identity: expected %#v, actual %#v", test.Output, id)
- }
- })
- }
-}
diff --git a/pkg/gitdiff/testdata/apply/bin.go b/pkg/gitdiff/testdata/apply/bin.go
deleted file mode 100644
index e34f06b..0000000
--- a/pkg/gitdiff/testdata/apply/bin.go
+++ /dev/null
@@ -1,124 +0,0 @@
-//go:build ignore
-
-// bin.go is a helper CLI to manipulate binary diff data for testing purposes.
-// It can decode patches generated by git using the standard parsing functions
-// or it can encode binary data back into the format expected by Git. It
-// operates on stdin writes results (possibly binary) to stdout.
-
-package main
-
-import (
- "bytes"
- "compress/zlib"
- "encoding/binary"
- "flag"
- "io/ioutil"
- "log"
- "os"
- "strings"
-
- "github.com/bluekeyes/go-gitdiff/gitdiff"
-)
-
-var (
- b85Powers = []uint32{52200625, 614125, 7225, 85, 1}
- b85Alpha = []byte(
- "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "!#$%&()*+-;<=>?@^_`{|}~",
- )
-)
-
-var mode string
-
-func base85Encode(data []byte) []byte {
- chunks, remaining := len(data)/4, len(data)%4
- if remaining > 0 {
- data = append(data, make([]byte, 4-remaining)...)
- chunks++
- }
-
- var n int
- out := make([]byte, 5*chunks)
-
- for i := 0; i < len(data); i += 4 {
- v := binary.BigEndian.Uint32(data[i : i+4])
- for j := 0; j < 5; j++ {
- p := v / b85Powers[j]
- out[n+j] = b85Alpha[p]
- v -= b85Powers[j] * p
- }
- n += 5
- }
-
- return out
-}
-
-func compress(data []byte) ([]byte, error) {
- var b bytes.Buffer
- w := zlib.NewWriter(&b)
-
- if _, err := w.Write(data); err != nil {
- return nil, err
- }
- if err := w.Close(); err != nil {
- return nil, err
- }
-
- return b.Bytes(), nil
-}
-
-func wrap(data []byte) string {
- var s strings.Builder
- for i := 0; i < len(data); i += 52 {
- c := 52
- if c > len(data)-i {
- c = len(data) - i
- }
- b := (c / 5) * 4
-
- if b <= 26 {
- s.WriteByte(byte('A' + b - 1))
- } else {
- s.WriteByte(byte('a' + b - 27))
- }
- s.Write(data[i : i+c])
- s.WriteByte('\n')
- }
- return s.String()
-}
-
-func init() {
- flag.StringVar(&mode, "mode", "parse", "operation mode, one of 'parse' or 'encode'")
-}
-
-func main() {
- flag.Parse()
-
- switch mode {
- case "parse":
- files, _, err := gitdiff.Parse(os.Stdin)
- if err != nil {
- log.Fatalf("failed to parse file: %v", err)
- }
- if len(files) != 1 {
- log.Fatalf("patch contains more than one file: %d", len(files))
- }
- if files[0].BinaryFragment == nil {
- log.Fatalf("patch file does not contain a binary fragment")
- }
- os.Stdout.Write(files[0].BinaryFragment.Data)
-
- case "encode":
- data, err := ioutil.ReadAll(os.Stdin)
- if err != nil {
- log.Fatalf("failed to read input: %v", err)
- }
- data, err = compress(data)
- if err != nil {
- log.Fatalf("failed to compress data: %v", err)
- }
- os.Stdout.WriteString(wrap(base85Encode(data)))
-
- default:
- log.Fatalf("unknown mode: %s", mode)
- }
-}
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error.src b/pkg/gitdiff/testdata/apply/bin_fragment_delta_error.src
deleted file mode 100644
index d4edf89..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error.src
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_dst_size.patch b/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_dst_size.patch
deleted file mode 100644
index 6d5bb42..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_dst_size.patch
+++ /dev/null
@@ -1,5 +0,0 @@
-diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
-GIT binary patch
-delta 18
-fc${itY+{<=z`_4AtEhVK$zKyatN;N30RR6$D+j^=
-
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_incomplete_add.patch b/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_incomplete_add.patch
deleted file mode 100644
index b8c1835..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_incomplete_add.patch
+++ /dev/null
@@ -1,5 +0,0 @@
-diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
-GIT binary patch
-delta 11
-Xc${itY+{_?z`_4As|XMP0RR6K8UwQc
-
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_incomplete_copy.patch b/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_incomplete_copy.patch
deleted file mode 100644
index 8db8f84..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_incomplete_copy.patch
+++ /dev/null
@@ -1,5 +0,0 @@
-diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
-GIT binary patch
-delta 17
-fc${itY+{_?z`_4AtEhVK$zKya00961|Nl5!2ZsOv
-
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_src_size.patch b/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_src_size.patch
deleted file mode 100644
index 29cb26b..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_error_src_size.patch
+++ /dev/null
@@ -1,5 +0,0 @@
-diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
-GIT binary patch
-delta 18
-fc${itYGRz=z`_4AtEhVK$zKyatN;N30RR6$EeFB?
-
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.out b/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.out
deleted file mode 100644
index f3386d1..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.out
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.patch b/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.patch
deleted file mode 100644
index 1801ef2..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/gitdiff/testdata/apply/bin_fragment_delta_modify.src b/gitdiff/testdata/apply/bin_fragment_delta_modify.src
-GIT binary patch
-delta 172
-zcmV;d08{^f2)qc8AP{I3VQ>J`s>wb0HU+h#6w8q?tUO~cHmDjZi2<8yZ9XmKhhMdo
-zWu(4bg|8QwzZ|1e*rL4P#)`Fen<n~ik=E?$qG6?hzJ6$u{l5W#?uwHb0q6w)00000
-zlLZ3%0RfW%1N%UMJ{~Z~0@X${&1Kk#98tb3==a{J7A;`O`v&<T@514_mvMTz72b#n
-atf$#NLoPbNe?RPFJVt1aCFGoQbiKD!OHgJ2
-
-delta 112
-zcmV-$0FVE?2!IHXAP~DY<7&llQfwqYA%tL<sR@xVtUMD;+4ZG>XTQ5=J2y;^BfB}4
-zWkisH791|vOVl5e-@^VLX0s~Ky_UyN!3;CgPr>Edj0j+0gOSwSsFsr$0q6zUJph<q
-SlLZ3%0XmZb1N#I__7UCuR5Dxu
-
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.src b/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.src
deleted file mode 100644
index fb85478..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify.src
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.out b/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.out
deleted file mode 100644
index f0f7f14..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.out
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.patch b/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.patch
deleted file mode 100644
index 093936b..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.patch
+++ /dev/null
@@ -1,166 +0,0 @@
-diff --git a/gitdiff/testdata/apply/bin_fragment_delta_modify_large.src b/gitdiff/testdata/apply/bin_fragment_delta_modify_large.src
-GIT binary patch
-delta 4145
-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
-
-delta 4145
-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
-
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.src b/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.src
deleted file mode 100644
index 90a9f6d..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_delta_modify_large.src
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.out b/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.out
deleted file mode 100644
index c62cba2..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.out
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.patch b/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.patch
deleted file mode 100644
index b3b846a..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-diff --git a/gitdiff/testdata/apply/bin_fragment_literal_create.src b/gitdiff/testdata/apply/bin_fragment_literal_create.src
-GIT binary patch
-literal 32
-ocmZQzU`lR_IpTEv<rOIzfy0`|3>L*`JUiBtu5<US@-j_*0M$he#sB~S
-
-literal 0
-HcmV?d00001
-
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.src b/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.src
deleted file mode 100644
index e69de29..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_literal_create.src
+++ /dev/null
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.out b/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.out
deleted file mode 100644
index 0bf736e..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.out
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.patch b/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.patch
deleted file mode 100644
index c3da024..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-diff --git a/gitdiff/testdata/apply/bin_fragment_literal_modify.src b/gitdiff/testdata/apply/bin_fragment_literal_modify.src
-GIT binary patch
-literal 32
-ocmZQzU`lR_IpTEv<rOIzfy0_p?@r&O@$6Vny3XCR%F8tM0pJ`CjQ{`u
-
-literal 32
-ocmZQzU`lR_IpTEv<rOIzfy0`|3>L*`JUiBtu5<US@-j_*0M$he#sB~S
-
diff --git a/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.src b/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.src
deleted file mode 100644
index c62cba2..0000000
--- a/pkg/gitdiff/testdata/apply/bin_fragment_literal_modify.src
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/file_bin_modify.out b/pkg/gitdiff/testdata/apply/file_bin_modify.out
deleted file mode 100644
index f3386d1..0000000
--- a/pkg/gitdiff/testdata/apply/file_bin_modify.out
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/file_bin_modify.patch b/pkg/gitdiff/testdata/apply/file_bin_modify.patch
deleted file mode 100644
index af38f36..0000000
--- a/pkg/gitdiff/testdata/apply/file_bin_modify.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/gitdiff/testdata/apply/file_bin_modify.src b/gitdiff/testdata/apply/file_bin_modify.src
-GIT binary patch
-delta 172
-zcmV;d08{^f2)qc8AP{I3VQ>J`s>wb0HU+h#6w8q?tUO~cHmDjZi2<8yZ9XmKhhMdo
-zWu(4bg|8QwzZ|1e*rL4P#)`Fen<n~ik=E?$qG6?hzJ6$u{l5W#?uwHb0q6w)00000
-zlLZ3%0RfW%1N%UMJ{~Z~0@X${&1Kk#98tb3==a{J7A;`O`v&<T@514_mvMTz72b#n
-atf$#NLoPbNe?RPFJVt1aCFGoQbiKD!OHgJ2
-
-delta 112
-zcmV-$0FVE?2!IHXAP~DY<7&llQfwqYA%tL<sR@xVtUMD;+4ZG>XTQ5=J2y;^BfB}4
-zWkisH791|vOVl5e-@^VLX0s~Ky_UyN!3;CgPr>Edj0j+0gOSwSsFsr$0q6zUJph<q
-SlLZ3%0XmZb1N#I__7UCuR5Dxu
-
diff --git a/pkg/gitdiff/testdata/apply/file_bin_modify.src b/pkg/gitdiff/testdata/apply/file_bin_modify.src
deleted file mode 100644
index fb85478..0000000
--- a/pkg/gitdiff/testdata/apply/file_bin_modify.src
+++ /dev/null
Binary files differ
diff --git a/pkg/gitdiff/testdata/apply/file_mode_change.out b/pkg/gitdiff/testdata/apply/file_mode_change.out
deleted file mode 100644
index ec3b7fd..0000000
--- a/pkg/gitdiff/testdata/apply/file_mode_change.out
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-echo "this file is executable"
diff --git a/pkg/gitdiff/testdata/apply/file_mode_change.patch b/pkg/gitdiff/testdata/apply/file_mode_change.patch
deleted file mode 100644
index b1f6859..0000000
--- a/pkg/gitdiff/testdata/apply/file_mode_change.patch
+++ /dev/null
@@ -1,3 +0,0 @@
-diff --git a/gitdiff/testdata/apply/file_mode_change.src b/gitdiff/testdata/apply/file_mode_change.src
-old mode 100644
-new mode 100755
diff --git a/pkg/gitdiff/testdata/apply/file_mode_change.src b/pkg/gitdiff/testdata/apply/file_mode_change.src
deleted file mode 100644
index ec3b7fd..0000000
--- a/pkg/gitdiff/testdata/apply/file_mode_change.src
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-echo "this file is executable"
diff --git a/pkg/gitdiff/testdata/apply/file_text.src b/pkg/gitdiff/testdata/apply/file_text.src
deleted file mode 100644
index 3805ad4..0000000
--- a/pkg/gitdiff/testdata/apply/file_text.src
+++ /dev/null
@@ -1,200 +0,0 @@
-this is line 1
-this is line 2
-this is line 3
-this is line 4
-this is line 5
-this is line 6
-this is line 7
-this is line 8
-this is line 9
-this is line 10
-this is line 11
-this is line 12
-this is line 13
-this is line 14
-this is line 15
-this is line 16
-this is line 17
-this is line 18
-this is line 19
-this is line 20
-this is line 21
-this is line 22
-this is line 23
-this is line 24
-this is line 25
-this is line 26
-this is line 27
-this is line 28
-this is line 29
-this is line 30
-this is line 31
-this is line 32
-this is line 33
-this is line 34
-this is line 35
-this is line 36
-this is line 37
-this is line 38
-this is line 39
-this is line 40
-this is line 41
-this is line 42
-this is line 43
-this is line 44
-this is line 45
-this is line 46
-this is line 47
-this is line 48
-this is line 49
-this is line 50
-this is line 51
-this is line 52
-this is line 53
-this is line 54
-this is line 55
-this is line 56
-this is line 57
-this is line 58
-this is line 59
-this is line 60
-this is line 61
-this is line 62
-this is line 63
-this is line 64
-this is line 65
-this is line 66
-this is line 67
-this is line 68
-this is line 69
-this is line 70
-this is line 71
-this is line 72
-this is line 73
-this is line 74
-this is line 75
-this is line 76
-this is line 77
-this is line 78
-this is line 79
-this is line 80
-this is line 81
-this is line 82
-this is line 83
-this is line 84
-this is line 85
-this is line 86
-this is line 87
-this is line 88
-this is line 89
-this is line 90
-this is line 91
-this is line 92
-this is line 93
-this is line 94
-this is line 95
-this is line 96
-this is line 97
-this is line 98
-this is line 99
-this is line 100
-this is line 101
-this is line 102
-this is line 103
-this is line 104
-this is line 105
-this is line 106
-this is line 107
-this is line 108
-this is line 109
-this is line 110
-this is line 111
-this is line 112
-this is line 113
-this is line 114
-this is line 115
-this is line 116
-this is line 117
-this is line 118
-this is line 119
-this is line 120
-this is line 121
-this is line 122
-this is line 123
-this is line 124
-this is line 125
-this is line 126
-this is line 127
-this is line 128
-this is line 129
-this is line 130
-this is line 131
-this is line 132
-this is line 133
-this is line 134
-this is line 135
-this is line 136
-this is line 137
-this is line 138
-this is line 139
-this is line 140
-this is line 141
-this is line 142
-this is line 143
-this is line 144
-this is line 145
-this is line 146
-this is line 147
-this is line 148
-this is line 149
-this is line 150
-this is line 151
-this is line 152
-this is line 153
-this is line 154
-this is line 155
-this is line 156
-this is line 157
-this is line 158
-this is line 159
-this is line 160
-this is line 161
-this is line 162
-this is line 163
-this is line 164
-this is line 165
-this is line 166
-this is line 167
-this is line 168
-this is line 169
-this is line 170
-this is line 171
-this is line 172
-this is line 173
-this is line 174
-this is line 175
-this is line 176
-this is line 177
-this is line 178
-this is line 179
-this is line 180
-this is line 181
-this is line 182
-this is line 183
-this is line 184
-this is line 185
-this is line 186
-this is line 187
-this is line 188
-this is line 189
-this is line 190
-this is line 191
-this is line 192
-this is line 193
-this is line 194
-this is line 195
-this is line 196
-this is line 197
-this is line 198
-this is line 199
-this is line 200
diff --git a/pkg/gitdiff/testdata/apply/file_text_delete.out b/pkg/gitdiff/testdata/apply/file_text_delete.out
deleted file mode 100644
index e69de29..0000000
--- a/pkg/gitdiff/testdata/apply/file_text_delete.out
+++ /dev/null
diff --git a/pkg/gitdiff/testdata/apply/file_text_delete.patch b/pkg/gitdiff/testdata/apply/file_text_delete.patch
deleted file mode 100644
index 9ac710b..0000000
--- a/pkg/gitdiff/testdata/apply/file_text_delete.patch
+++ /dev/null
@@ -1,206 +0,0 @@
-diff --git a/gitdiff/testdata/apply/file_text.src.src b/gitdiff/testdata/apply/file_text.src
-deleted file mode 100644
-index 3805ad4..0000000
---- a/gitdiff/testdata/apply/file_text.src.src
-+++ /dev/null
-@@ -1,200 +0,0 @@
--this is line 1
--this is line 2
--this is line 3
--this is line 4
--this is line 5
--this is line 6
--this is line 7
--this is line 8
--this is line 9
--this is line 10
--this is line 11
--this is line 12
--this is line 13
--this is line 14
--this is line 15
--this is line 16
--this is line 17
--this is line 18
--this is line 19
--this is line 20
--this is line 21
--this is line 22
--this is line 23
--this is line 24
--this is line 25
--this is line 26
--this is line 27
--this is line 28
--this is line 29
--this is line 30
--this is line 31
--this is line 32
--this is line 33
--this is line 34
--this is line 35
--this is line 36
--this is line 37
--this is line 38
--this is line 39
--this is line 40
--this is line 41
--this is line 42
--this is line 43
--this is line 44
--this is line 45
--this is line 46
--this is line 47
--this is line 48
--this is line 49
--this is line 50
--this is line 51
--this is line 52
--this is line 53
--this is line 54
--this is line 55
--this is line 56
--this is line 57
--this is line 58
--this is line 59
--this is line 60
--this is line 61
--this is line 62
--this is line 63
--this is line 64
--this is line 65
--this is line 66
--this is line 67
--this is line 68
--this is line 69
--this is line 70
--this is line 71
--this is line 72
--this is line 73
--this is line 74
--this is line 75
--this is line 76
--this is line 77
--this is line 78
--this is line 79
--this is line 80
--this is line 81
--this is line 82
--this is line 83
--this is line 84
--this is line 85
--this is line 86
--this is line 87
--this is line 88
--this is line 89
--this is line 90
--this is line 91
--this is line 92
--this is line 93
--this is line 94
--this is line 95
--this is line 96
--this is line 97
--this is line 98
--this is line 99
--this is line 100
--this is line 101
--this is line 102
--this is line 103
--this is line 104
--this is line 105
--this is line 106
--this is line 107
--this is line 108
--this is line 109
--this is line 110
--this is line 111
--this is line 112
--this is line 113
--this is line 114
--this is line 115
--this is line 116
--this is line 117
--this is line 118
--this is line 119
--this is line 120
--this is line 121
--this is line 122
--this is line 123
--this is line 124
--this is line 125
--this is line 126
--this is line 127
--this is line 128
--this is line 129
--this is line 130
--this is line 131
--this is line 132
--this is line 133
--this is line 134
--this is line 135
--this is line 136
--this is line 137
--this is line 138
--this is line 139
--this is line 140
--this is line 141
--this is line 142
--this is line 143
--this is line 144
--this is line 145
--this is line 146
--this is line 147
--this is line 148
--this is line 149
--this is line 150
--this is line 151
--this is line 152
--this is line 153
--this is line 154
--this is line 155
--this is line 156
--this is line 157
--this is line 158
--this is line 159
--this is line 160
--this is line 161
--this is line 162
--this is line 163
--this is line 164
--this is line 165
--this is line 166
--this is line 167
--this is line 168
--this is line 169
--this is line 170
--this is line 171
--this is line 172
--this is line 173
--this is line 174
--this is line 175
--this is line 176
--this is line 177
--this is line 178
--this is line 179
--this is line 180
--this is line 181
--this is line 182
--this is line 183
--this is line 184
--this is line 185
--this is line 186
--this is line 187
--this is line 188
--this is line 189
--this is line 190
--this is line 191
--this is line 192
--this is line 193
--this is line 194
--this is line 195
--this is line 196
--this is line 197
--this is line 198
--this is line 199
--this is line 200
diff --git a/pkg/gitdiff/testdata/apply/file_text_error_partial_delete.patch b/pkg/gitdiff/testdata/apply/file_text_error_partial_delete.patch
deleted file mode 100644
index 01d2a6f..0000000
--- a/pkg/gitdiff/testdata/apply/file_text_error_partial_delete.patch
+++ /dev/null
@@ -1,106 +0,0 @@
-diff --git a/gitdiff/testdata/apply/file_text.src.src b/gitdiff/testdata/apply/file_text.src
-deleted file mode 100644
-index 3805ad4..0000000
---- a/gitdiff/testdata/apply/file_text.src.src
-+++ /dev/null
-@@ -1,100 +0,0 @@
--this is line 1
--this is line 2
--this is line 3
--this is line 4
--this is line 5
--this is line 6
--this is line 7
--this is line 8
--this is line 9
--this is line 10
--this is line 11
--this is line 12
--this is line 13
--this is line 14
--this is line 15
--this is line 16
--this is line 17
--this is line 18
--this is line 19
--this is line 20
--this is line 21
--this is line 22
--this is line 23
--this is line 24
--this is line 25
--this is line 26
--this is line 27
--this is line 28
--this is line 29
--this is line 30
--this is line 31
--this is line 32
--this is line 33
--this is line 34
--this is line 35
--this is line 36
--this is line 37
--this is line 38
--this is line 39
--this is line 40
--this is line 41
--this is line 42
--this is line 43
--this is line 44
--this is line 45
--this is line 46
--this is line 47
--this is line 48
--this is line 49
--this is line 50
--this is line 51
--this is line 52
--this is line 53
--this is line 54
--this is line 55
--this is line 56
--this is line 57
--this is line 58
--this is line 59
--this is line 60
--this is line 61
--this is line 62
--this is line 63
--this is line 64
--this is line 65
--this is line 66
--this is line 67
--this is line 68
--this is line 69
--this is line 70
--this is line 71
--this is line 72
--this is line 73
--this is line 74
--this is line 75
--this is line 76
--this is line 77
--this is line 78
--this is line 79
--this is line 80
--this is line 81
--this is line 82
--this is line 83
--this is line 84
--this is line 85
--this is line 86
--this is line 87
--this is line 88
--this is line 89
--this is line 90
--this is line 91
--this is line 92
--this is line 93
--this is line 94
--this is line 95
--this is line 96
--this is line 97
--this is line 98
--this is line 99
--this is line 100
diff --git a/pkg/gitdiff/testdata/apply/file_text_modify.out b/pkg/gitdiff/testdata/apply/file_text_modify.out
deleted file mode 100644
index dc20c07..0000000
--- a/pkg/gitdiff/testdata/apply/file_text_modify.out
+++ /dev/null
@@ -1,195 +0,0 @@
-the first line is different
-this is line 2
-this is line 3
-this is line 4
-this is line 5
-this is line 6
-this is line 7
-this is line 8
-this is line 9
-this is line 10
-this is line 11
-this is line 12
-this is line 13
-this is line 14
-this is line 15
-this is line 16
-this is line 17
-this is line 18
-this is line 19
-this line offsets all the line numbers!
-this is line 20
-this is line 21
-until here, now we're back on track!
-this is line 24
-this is line 25
-this is line 26
-this is line 27
-this is line 28
-this is line 29
-this is line 30
-this is line 31
-this is line 32
-this is line 33
-this is line 34
-this is line 35
-this is line 36
-this is line 37
-this is line 38
-this is line 39
-this is line 40
-this is line 41
-this is line 42
-this is line 43
-this is line 44
-this is line 45
-this is line 46
-this is line 47
-this is line 48
-this is line 49
-this is line 50
-this is line 51
-this is line 52
-this is line 53
-this is line 54
-this is line 55
-once upon a time, a line
- in a text
- file
- changed
-this is line 60
-this is line 61
-this is line 62
-this is line 63
-this is line 64
-this is line 65
-this is line 66
-this is line 67
-this is line 68
-this is line 69
-this is line 70
-this is line 71
-this is line 72
-this is line 73
-this is line 74
-this is line 75
-this is line 76
-this is line 77
-this is line 78
-this is line 79
-this is line 80
-this is line 81
-this is line 82
-this is line 83
-this is line 84
-this is line 85
-this is line 86
-this is line 87
-this is line 88
-this is line 89
-this is line 90
-this is line 91
-this is line 92
-this is line 93
-this is line 94
-this is line 95
-this is line 96
-this is line 97
-this is line 98
-this is line 99
-this is line 100
-this is line 101
-this is line 102
-this is line 103
-this is line 104
-this is line 105
-this is line 106
-this is line 107
-this is line 108
-this is line 109
-this is line 110
-this is line 111
-this is line 112
-this is line 113
-this is line 114
-this is line 115
-this is line 116
-this is line 117
-this is line 118
-this is line 119
-this is line 120
-this is line 121
-this is line 122
-this is line 123
-this is line 124
-this is line 125
-this is line 126
-this is line 127
-this is line 128
-this is line 129
-this is line 130
-this is line 131
-this is line 132
-this line was bad and has been removed
-this line was REDACTED and has been REDACTED
-this is line 135
-this is line 136
-this is line 137
-this is line 138
-this is line 139
-this is line 140
-this is line 141
-this is line 142
-this is line 143
-this is line 144
-this is line 145
-this is line 146
-this is line 147
-this is line 148
-this is line 149
-this is line 150
-this is line 151
-this is line 152
-this is line 153
-this is line 154
-this is line 155
-this is line 156
-this is line 157
-this is line 158
-this is line 159
-this is line 160
-this is line 161
-this is line 162
-this is line 163
-the number on the remaining lines is 5 ahead of their actual position in the file
-this is line 170
-this is line 171
-this is line 172
-this is line 173
-this is line 174
-this is line 175
-this is line 176
-this is line 177
-this is line 178
-this is line 179
-this is line 180
-this is line 181
-this is line 182
-this is line 183
-this is line 184
-this is line 185
-this is line 186
-this is line 187
-this is line 188
-this is line 189
-this is line 190
-this is line 191
-this is line 192
-this is line 193
-this is line 194
-this is line 195
-this is line 196
-this is line 197
-this is line 198
-this is line 199
-this is line 200
diff --git a/pkg/gitdiff/testdata/apply/file_text_modify.patch b/pkg/gitdiff/testdata/apply/file_text_modify.patch
deleted file mode 100644
index 362d9a9..0000000
--- a/pkg/gitdiff/testdata/apply/file_text_modify.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-diff --git a/gitdiff/testdata/apply/file_text.src b/gitdiff/testdata/apply/file_text.src
---- a/gitdiff/testdata/apply/file_text.src
-+++ b/gitdiff/testdata/apply/file_text.src
-@@ -1,4 +1,4 @@
--this is line 1
-+the first line is different
- this is line 2
- this is line 3
- this is line 4
-@@ -17,10 +17,10 @@ this is line 16
- this is line 17
- this is line 18
- this is line 19
-+this line offsets all the line numbers!
- this is line 20
- this is line 21
--this is line 22
--this is line 23
-+until here, now we're back on track!
- this is line 24
- this is line 25
- this is line 26
-@@ -53,10 +53,10 @@ this is line 52
- this is line 53
- this is line 54
- this is line 55
--this is line 56
--this is line 57
--this is line 58
--this is line 59
-+once upon a time, a line
-+ in a text
-+ file
-+ changed
- this is line 60
- this is line 61
- this is line 62
-@@ -130,8 +130,8 @@ this is line 129
- this is line 130
- this is line 131
- this is line 132
--this is line 133
--this is line 134
-+this line was bad and has been removed
-+this line was REDACTED and has been REDACTED
- this is line 135
- this is line 136
- this is line 137
-@@ -161,12 +161,7 @@ this is line 160
- this is line 161
- this is line 162
- this is line 163
--this is line 164
--this is line 165
--this is line 166
--this is line 167
--this is line 168
--this is line 169
-+the number on the remaining lines is 5 ahead of their actual position in the file
- this is line 170
- this is line 171
- this is line 172
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_end.out b/pkg/gitdiff/testdata/apply/text_fragment_add_end.out
deleted file mode 100644
index 648fd44..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_end.out
+++ /dev/null
@@ -1,5 +0,0 @@
-line 1
-line 2
-line 3
-new line a
-new line b
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_end.patch b/pkg/gitdiff/testdata/apply/text_fragment_add_end.patch
deleted file mode 100644
index de708be..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_end.patch
+++ /dev/null
@@ -1,9 +0,0 @@
-diff --git a/gitdiff/testdata/apply/fragment_add_end.src b/gitdiff/testdata/apply/fragment_add_end.src
---- a/gitdiff/testdata/apply/fragment_add_end.src
-+++ b/gitdiff/testdata/apply/fragment_add_end.src
-@@ -1,3 +1,5 @@
- line 1
- line 2
- line 3
-+new line a
-+new line b
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_end.src b/pkg/gitdiff/testdata/apply/text_fragment_add_end.src
deleted file mode 100644
index a92d664..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_end.src
+++ /dev/null
@@ -1,3 +0,0 @@
-line 1
-line 2
-line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.out b/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.out
deleted file mode 100644
index 94c99a3..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.out
+++ /dev/null
@@ -1,5 +0,0 @@
-line 1
-line 2
-line 3
-line 4
-line 5
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.patch b/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.patch
deleted file mode 100644
index ec3cea4..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_add_end_noeol.src b/gitdiff/testdata/apply/text_fragment_add_end_noeol.src
---- a/gitdiff/testdata/apply/text_fragment_add_end_noeol.src
-+++ b/gitdiff/testdata/apply/text_fragment_add_end_noeol.src
-@@ -1,3 +1,5 @@
- line 1
- line 2
--line 3
-\ No newline at end of file
-+line 3
-+line 4
-+line 5
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.src b/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.src
deleted file mode 100644
index 8cf2f17..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_end_noeol.src
+++ /dev/null
@@ -1,3 +0,0 @@
-line 1
-line 2
-line 3 \ No newline at end of file
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_middle.out b/pkg/gitdiff/testdata/apply/text_fragment_add_middle.out
deleted file mode 100644
index ded20d8..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_middle.out
+++ /dev/null
@@ -1,5 +0,0 @@
-line 1
-line 2
-new line a
-new line b
-line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_middle.patch b/pkg/gitdiff/testdata/apply/text_fragment_add_middle.patch
deleted file mode 100644
index 43aee3b..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_middle.patch
+++ /dev/null
@@ -1,9 +0,0 @@
-diff --git a/gitdiff/testdata/apply/fragment_add_middle.src b/gitdiff/testdata/apply/fragment_add_middle.src
---- a/gitdiff/testdata/apply/fragment_add_middle.src
-+++ b/gitdiff/testdata/apply/fragment_add_middle.src
-@@ -1,3 +1,5 @@
- line 1
- line 2
-+new line a
-+new line b
- line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_middle.src b/pkg/gitdiff/testdata/apply/text_fragment_add_middle.src
deleted file mode 100644
index a92d664..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_middle.src
+++ /dev/null
@@ -1,3 +0,0 @@
-line 1
-line 2
-line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_start.out b/pkg/gitdiff/testdata/apply/text_fragment_add_start.out
deleted file mode 100644
index b153f60..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_start.out
+++ /dev/null
@@ -1,4 +0,0 @@
-new line a
-line 1
-line 2
-line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_start.patch b/pkg/gitdiff/testdata/apply/text_fragment_add_start.patch
deleted file mode 100644
index 5218764..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_start.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-diff --git a/gitdiff/testdata/apply/fragment_add_start.src b/gitdiff/testdata/apply/fragment_add_start.src
---- a/gitdiff/testdata/apply/fragment_add_start.src
-+++ b/gitdiff/testdata/apply/fragment_add_start.src
-@@ -1,3 +1,4 @@
-+new line a
- line 1
- line 2
- line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_add_start.src b/pkg/gitdiff/testdata/apply/text_fragment_add_start.src
deleted file mode 100644
index a92d664..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_add_start.src
+++ /dev/null
@@ -1,3 +0,0 @@
-line 1
-line 2
-line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_end.out b/pkg/gitdiff/testdata/apply/text_fragment_change_end.out
deleted file mode 100644
index e3cbece..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_end.out
+++ /dev/null
@@ -1,10 +0,0 @@
-line 1
-line 2
-line 3
-line 4
-line 5
-line 6
-line 7
-line 8
-line 9
-new line a
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_end.patch b/pkg/gitdiff/testdata/apply/text_fragment_change_end.patch
deleted file mode 100644
index 5655880..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_end.patch
+++ /dev/null
@@ -1,9 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_change_end.src b/gitdiff/testdata/apply/text_fragment_change_end.src
---- a/gitdiff/testdata/apply/text_fragment_change_end.src
-+++ b/gitdiff/testdata/apply/text_fragment_change_end.src
-@@ -7,4 +7,4 @@ line 6
- line 7
- line 8
- line 9
--line 10
-+new line a
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_end.src b/pkg/gitdiff/testdata/apply/text_fragment_change_end.src
deleted file mode 100644
index fa2da6e..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_end.src
+++ /dev/null
@@ -1,10 +0,0 @@
-line 1
-line 2
-line 3
-line 4
-line 5
-line 6
-line 7
-line 8
-line 9
-line 10
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.out b/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.out
deleted file mode 100644
index 8cf2f17..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.out
+++ /dev/null
@@ -1,3 +0,0 @@
-line 1
-line 2
-line 3 \ No newline at end of file
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.patch b/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.patch
deleted file mode 100644
index f1c9477..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.patch
+++ /dev/null
@@ -1,10 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_remove_last_eol.src b/gitdiff/testdata/apply/text_fragment_remove_last_eol.src
-index a92d664..8cf2f17 100644
---- a/gitdiff/testdata/apply/text_fragment_remove_last_eol.src
-+++ b/gitdiff/testdata/apply/text_fragment_remove_last_eol.src
-@@ -1,3 +1,3 @@
- line 1
- line 2
--line 3
-+line 3
-\ No newline at end of file
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.src b/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.src
deleted file mode 100644
index a92d664..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_end_eol.src
+++ /dev/null
@@ -1,3 +0,0 @@
-line 1
-line 2
-line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_exact.out b/pkg/gitdiff/testdata/apply/text_fragment_change_exact.out
deleted file mode 100644
index 4655a0a..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_exact.out
+++ /dev/null
@@ -1,19 +0,0 @@
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-new line a
-line
-line
-line
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_exact.patch b/pkg/gitdiff/testdata/apply/text_fragment_change_exact.patch
deleted file mode 100644
index 395de4d..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_exact.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_change_exact.src b/gitdiff/testdata/apply/text_fragment_change_exact.src
---- a/gitdiff/testdata/apply/text_fragment_change_exact.src
-+++ b/gitdiff/testdata/apply/text_fragment_change_exact.src
-@@ -13,7 +13,7 @@ line
- line
- line
- line
--line
-+new line a
- line
- line
- line
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_exact.src b/pkg/gitdiff/testdata/apply/text_fragment_change_exact.src
deleted file mode 100644
index 316a8f0..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_exact.src
+++ /dev/null
@@ -1,30 +0,0 @@
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
-line
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_middle.out b/pkg/gitdiff/testdata/apply/text_fragment_change_middle.out
deleted file mode 100644
index fd0a9ad..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_middle.out
+++ /dev/null
@@ -1,9 +0,0 @@
-line 1
-line 2
-line 3
-line 4
-line 5
-new line a
-line 7
-line 8
-line 9
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_middle.patch b/pkg/gitdiff/testdata/apply/text_fragment_change_middle.patch
deleted file mode 100644
index 139a0fe..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_middle.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_change_middle.src b/gitdiff/testdata/apply/text_fragment_change_middle.src
---- a/gitdiff/testdata/apply/text_fragment_change_middle.src
-+++ b/gitdiff/testdata/apply/text_fragment_change_middle.src
-@@ -3,7 +3,7 @@ line 2
- line 3
- line 4
- line 5
--line 6
-+new line a
- line 7
- line 8
- line 9
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_middle.src b/pkg/gitdiff/testdata/apply/text_fragment_change_middle.src
deleted file mode 100644
index fa2da6e..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_middle.src
+++ /dev/null
@@ -1,10 +0,0 @@
-line 1
-line 2
-line 3
-line 4
-line 5
-line 6
-line 7
-line 8
-line 9
-line 10
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.out b/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.out
deleted file mode 100644
index ed59e08..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.out
+++ /dev/null
@@ -1 +0,0 @@
-new line a \ No newline at end of file
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.patch b/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.patch
deleted file mode 100644
index f945234..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_change_single_noeol.src b/gitdiff/testdata/apply/text_fragment_change_single_noeol.src
---- a/gitdiff/testdata/apply/text_fragment_change_single_noeol.src
-+++ b/gitdiff/testdata/apply/text_fragment_change_single_noeol.src
-@@ -1 +1 @@
--line 1
-\ No newline at end of file
-+new line a
-\ No newline at end of file
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.src b/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.src
deleted file mode 100644
index dcf168c..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_single_noeol.src
+++ /dev/null
@@ -1 +0,0 @@
-line 1 \ No newline at end of file
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_start.out b/pkg/gitdiff/testdata/apply/text_fragment_change_start.out
deleted file mode 100644
index 5156941..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_start.out
+++ /dev/null
@@ -1,4 +0,0 @@
-new line a
-line 2
-line 3
-line 4
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_start.patch b/pkg/gitdiff/testdata/apply/text_fragment_change_start.patch
deleted file mode 100644
index d0a6653..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_start.patch
+++ /dev/null
@@ -1,9 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_change_start.src b/gitdiff/testdata/apply/text_fragment_change_start.src
---- a/gitdiff/testdata/apply/text_fragment_change_start.src
-+++ b/gitdiff/testdata/apply/text_fragment_change_start.src
-@@ -1,4 +1,4 @@
--line 1
-+new line a
- line 2
- line 3
- line 4
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_change_start.src b/pkg/gitdiff/testdata/apply/text_fragment_change_start.src
deleted file mode 100644
index fa2da6e..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_change_start.src
+++ /dev/null
@@ -1,10 +0,0 @@
-line 1
-line 2
-line 3
-line 4
-line 5
-line 6
-line 7
-line 8
-line 9
-line 10
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_delete_all.out b/pkg/gitdiff/testdata/apply/text_fragment_delete_all.out
deleted file mode 100644
index e69de29..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_delete_all.out
+++ /dev/null
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_delete_all.patch b/pkg/gitdiff/testdata/apply/text_fragment_delete_all.patch
deleted file mode 100644
index 8a2fb9c..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_delete_all.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-diff --git a/gitdiff/testdata/apply/fragment_delete_all.src b/gitdiff/testdata/apply/fragment_delete_all.src
---- a/gitdiff/testdata/apply/fragment_delete_all.src
-+++ b/gitdiff/testdata/apply/fragment_delete_all.src
-@@ -1,4 +0,0 @@
--line a
--line b
--line c
--line d
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_delete_all.src b/pkg/gitdiff/testdata/apply/text_fragment_delete_all.src
deleted file mode 100644
index 47d03ac..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_delete_all.src
+++ /dev/null
@@ -1,4 +0,0 @@
-line a
-line b
-line c
-line d
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_error.src b/pkg/gitdiff/testdata/apply/text_fragment_error.src
deleted file mode 100644
index f8b6f0a..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_error.src
+++ /dev/null
@@ -1,13 +0,0 @@
-line 1
-line 2
-line 3
-line 4
-line 5
-line 6
-line 7
-line 8
-line 9
-line 10
-line 11
-line 12
-line 13
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_error_context_conflict.patch b/pkg/gitdiff/testdata/apply/text_fragment_error_context_conflict.patch
deleted file mode 100644
index a262796..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_error_context_conflict.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_error.src b/gitdiff/testdata/apply/text_fragment_error.src
---- a/gitdiff/testdata/apply/text_fragment_error.src
-+++ b/gitdiff/testdata/apply/text_fragment_error.src
-@@ -4,7 +4,7 @@ line 3
- line 4
- line 5
- line conflict
--line 7
-+new line a
- line 8
- line 9
- line 10
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_error_delete_conflict.patch b/pkg/gitdiff/testdata/apply/text_fragment_error_delete_conflict.patch
deleted file mode 100644
index 17ea166..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_error_delete_conflict.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_error.src b/gitdiff/testdata/apply/text_fragment_error.src
---- a/gitdiff/testdata/apply/text_fragment_error.src
-+++ b/gitdiff/testdata/apply/text_fragment_error.src
-@@ -4,7 +4,7 @@ line 3
- line 4
- line 5
- line 6
--line conflict
-+new line a
- line 8
- line 9
- line 10
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_error_new_file.patch b/pkg/gitdiff/testdata/apply/text_fragment_error_new_file.patch
deleted file mode 100644
index f4fbee6..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_error_new_file.patch
+++ /dev/null
@@ -1,7 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_error.src b/gitdiff/testdata/apply/text_fragment_error.src
---- a/gitdiff/testdata/apply/text_fragment_error.src
-+++ b/gitdiff/testdata/apply/text_fragment_error.src
-@@ -0,0 +1,3 @@
-+line 1
-+line 2
-+line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_error_short_src.patch b/pkg/gitdiff/testdata/apply/text_fragment_error_short_src.patch
deleted file mode 100644
index bfe7b96..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_error_short_src.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_error.src b/gitdiff/testdata/apply/text_fragment_error.src
---- a/gitdiff/testdata/apply/text_fragment_error.src
-+++ b/gitdiff/testdata/apply/text_fragment_error.src
-@@ -9,7 +9,7 @@ line 8
- line 9
- line 10
- line 11
--line 12
-+new line a
- line 13
- line 14
- line 15
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_error_short_src_before.patch b/pkg/gitdiff/testdata/apply/text_fragment_error_short_src_before.patch
deleted file mode 100644
index 0a96018..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_error_short_src_before.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/gitdiff/testdata/apply/text_fragment_error.src b/gitdiff/testdata/apply/text_fragment_error.src
---- a/gitdiff/testdata/apply/text_fragment_error.src
-+++ b/gitdiff/testdata/apply/text_fragment_error.src
-@@ -15,7 +15,7 @@ line 14
- line 15
- line 16
- line 17
--line 18
-+new line a
- line 19
- line 20
- line 21
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_new.out b/pkg/gitdiff/testdata/apply/text_fragment_new.out
deleted file mode 100644
index a92d664..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_new.out
+++ /dev/null
@@ -1,3 +0,0 @@
-line 1
-line 2
-line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_new.patch b/pkg/gitdiff/testdata/apply/text_fragment_new.patch
deleted file mode 100644
index c87487b..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_new.patch
+++ /dev/null
@@ -1,7 +0,0 @@
-diff --git a/gitdiff/testdata/apply/fragment_new.src b/gitdiff/testdata/apply/fragment_new.src
---- a/gitdiff/testdata/apply/fragment_new.src
-+++ b/gitdiff/testdata/apply/fragment_new.src
-@@ -0,0 +1,3 @@
-+line 1
-+line 2
-+line 3
diff --git a/pkg/gitdiff/testdata/apply/text_fragment_new.src b/pkg/gitdiff/testdata/apply/text_fragment_new.src
deleted file mode 100644
index e69de29..0000000
--- a/pkg/gitdiff/testdata/apply/text_fragment_new.src
+++ /dev/null
diff --git a/pkg/gitdiff/testdata/new_binary_file.patch b/pkg/gitdiff/testdata/new_binary_file.patch
deleted file mode 100644
index e9ad45d..0000000
--- a/pkg/gitdiff/testdata/new_binary_file.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-commit 5d9790fec7d95aa223f3d20936340bf55ff3dcbe
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Tue Apr 2 22:55:40 2019 -0700
-
- A binary file with the first 10 fibonacci numbers.
-
-diff --git a/dir/ten.bin b/dir/ten.bin
-new file mode 100644
-index 0000000000000000000000000000000000000000..77b068ba48c356156944ea714740d0d5ca07bfec
-GIT binary patch
-literal 40
-gcmZQzU|?i`U?w2V48*KJ%mKu_Kr9NxN<eH500b)lkN^Mx
-
-literal 0
-HcmV?d00001
-
diff --git a/pkg/gitdiff/testdata/no_files.patch b/pkg/gitdiff/testdata/no_files.patch
deleted file mode 100644
index 9eea12d..0000000
--- a/pkg/gitdiff/testdata/no_files.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-commit 5d9790fec7d95aa223f3d20936340bf55ff3dcbe
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Tue Apr 2 22:55:40 2019 -0700
-
- A file with multiple fragments.
-
- The content is arbitrary.
-
diff --git a/pkg/gitdiff/testdata/one_file.patch b/pkg/gitdiff/testdata/one_file.patch
deleted file mode 100644
index 1aefec3..0000000
--- a/pkg/gitdiff/testdata/one_file.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-commit 5d9790fec7d95aa223f3d20936340bf55ff3dcbe
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Tue Apr 2 22:55:40 2019 -0700
-
- A file with multiple fragments.
-
- The content is arbitrary.
-
-diff --git a/dir/file1.txt b/dir/file1.txt
-index ebe9fa54..fe103e1d 100644
---- a/dir/file1.txt
-+++ b/dir/file1.txt
-@@ -3,6 +3,8 @@ fragment 1
- context line
--old line 1
--old line 2
- context line
-+new line 1
-+new line 2
-+new line 3
- context line
--old line 3
-+new line 4
-+new line 5
-@@ -31,2 +33,2 @@ fragment 2
- context line
--old line 4
-+new line 6
diff --git a/pkg/gitdiff/testdata/string/binary_modify.patch b/pkg/gitdiff/testdata/string/binary_modify.patch
deleted file mode 100644
index 12ddad5..0000000
--- a/pkg/gitdiff/testdata/string/binary_modify.patch
+++ /dev/null
@@ -1,9 +0,0 @@
-diff --git a/file.bin b/file.bin
-index a7f4d5d6975ec021016c02b6d58345ebf434f38c..bdc9a70f055892146612dcdb413f0e339faaa0df 100644
-GIT binary patch
-delta 66
-QcmeZhVVvM$!$1K50C&Ox;s5{u
-
-delta 5
-McmZo+^qAlQ00i9urT_o{
-
diff --git a/pkg/gitdiff/testdata/string/binary_modify_nodata.patch b/pkg/gitdiff/testdata/string/binary_modify_nodata.patch
deleted file mode 100644
index 833a534..0000000
--- a/pkg/gitdiff/testdata/string/binary_modify_nodata.patch
+++ /dev/null
@@ -1,3 +0,0 @@
-diff --git a/file.bin b/file.bin
-index a7f4d5d..bdc9a70 100644
-Binary files a/file.bin and b/file.bin differ
diff --git a/pkg/gitdiff/testdata/string/binary_new.patch b/pkg/gitdiff/testdata/string/binary_new.patch
deleted file mode 100644
index c56f35e..0000000
--- a/pkg/gitdiff/testdata/string/binary_new.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff --git a/file.bin b/file.bin
-new file mode 100644
-index 0000000000000000000000000000000000000000..a7f4d5d6975ec021016c02b6d58345ebf434f38c
-GIT binary patch
-literal 72
-zcmV-O0Jr~td-`u6JcK&{KDK=<a#;v1^LR5&K)zQ0=Goz82(?nJ6_nD`f#8O9p}}{P
-eiXim+rDI+BDadMQmMsO5Sw@;DbrCA+PamP;Ng_@F
-
-literal 0
-HcmV?d00001
-
diff --git a/pkg/gitdiff/testdata/string/copy.patch b/pkg/gitdiff/testdata/string/copy.patch
deleted file mode 100644
index f002f07..0000000
--- a/pkg/gitdiff/testdata/string/copy.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-diff --git a/file.txt b/numbers.txt
-similarity index 100%
-copy from file.txt
-copy to numbers.txt
diff --git a/pkg/gitdiff/testdata/string/copy_modify.patch b/pkg/gitdiff/testdata/string/copy_modify.patch
deleted file mode 100644
index 558a511..0000000
--- a/pkg/gitdiff/testdata/string/copy_modify.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-diff --git a/file.txt b/numbers.txt
-similarity index 57%
-copy from file.txt
-copy to numbers.txt
-index c9e9e05..6c4a3e0 100644
---- a/file.txt
-+++ b/numbers.txt
-@@ -1,6 +1,6 @@
- one
- two
--three
-+three three three
- four
- five
- six
-@@ -8,3 +8,5 @@ seven
- eight
- nine
- ten
-+eleven
-+twelve
diff --git a/pkg/gitdiff/testdata/string/delete.patch b/pkg/gitdiff/testdata/string/delete.patch
deleted file mode 100644
index f32dc25..0000000
--- a/pkg/gitdiff/testdata/string/delete.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/file.txt b/file.txt
-deleted file mode 100644
-index c9e9e05..0000000
---- a/file.txt
-+++ /dev/null
-@@ -1,10 +0,0 @@
--one
--two
--three
--four
--five
--six
--seven
--eight
--nine
--ten
diff --git a/pkg/gitdiff/testdata/string/mode.patch b/pkg/gitdiff/testdata/string/mode.patch
deleted file mode 100644
index 953ab25..0000000
--- a/pkg/gitdiff/testdata/string/mode.patch
+++ /dev/null
@@ -1,3 +0,0 @@
-diff --git a/file.txt b/file.txt
-old mode 100644
-new mode 100755
diff --git a/pkg/gitdiff/testdata/string/mode_modify.patch b/pkg/gitdiff/testdata/string/mode_modify.patch
deleted file mode 100644
index f1554a7..0000000
--- a/pkg/gitdiff/testdata/string/mode_modify.patch
+++ /dev/null
@@ -1,10 +0,0 @@
-diff --git a/script.sh b/script.sh
-old mode 100644
-new mode 100755
-index 7a870bd..68d501e
---- a/script.sh
-+++ b/script.sh
-@@ -1,2 +1,2 @@
- #!/bin/bash
--echo "Hello World"
-+echo "Hello, World!"
diff --git a/pkg/gitdiff/testdata/string/modify.patch b/pkg/gitdiff/testdata/string/modify.patch
deleted file mode 100644
index 9d89753..0000000
--- a/pkg/gitdiff/testdata/string/modify.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/file.txt b/file.txt
-index c9e9e05..7d5fdc6 100644
---- a/file.txt
-+++ b/file.txt
-@@ -3,8 +3,10 @@ two
- three
- four
- five
--six
-+six six six six six six
- seven
- eight
- nine
- ten
-+eleven
-+twelve
diff --git a/pkg/gitdiff/testdata/string/new.patch b/pkg/gitdiff/testdata/string/new.patch
deleted file mode 100644
index 941fe25..0000000
--- a/pkg/gitdiff/testdata/string/new.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/file.txt b/file.txt
-new file mode 100644
-index 0000000..c9e9e05
---- /dev/null
-+++ b/file.txt
-@@ -0,0 +1,10 @@
-+one
-+two
-+three
-+four
-+five
-+six
-+seven
-+eight
-+nine
-+ten
diff --git a/pkg/gitdiff/testdata/string/new_empty.patch b/pkg/gitdiff/testdata/string/new_empty.patch
deleted file mode 100644
index 5cc7cf7..0000000
--- a/pkg/gitdiff/testdata/string/new_empty.patch
+++ /dev/null
@@ -1,3 +0,0 @@
-diff --git a/file.txt b/file.txt
-new file mode 100644
-index 0000000..e69de29
diff --git a/pkg/gitdiff/testdata/string/new_mode.patch b/pkg/gitdiff/testdata/string/new_mode.patch
deleted file mode 100644
index f9d7f1f..0000000
--- a/pkg/gitdiff/testdata/string/new_mode.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/file.sh b/file.sh
-new file mode 100755
-index 0000000..c9e9e05
---- /dev/null
-+++ b/file.sh
-@@ -0,0 +1,10 @@
-+one
-+two
-+three
-+four
-+five
-+six
-+seven
-+eight
-+nine
-+ten
diff --git a/pkg/gitdiff/testdata/string/rename.patch b/pkg/gitdiff/testdata/string/rename.patch
deleted file mode 100644
index 3c0ca6f..0000000
--- a/pkg/gitdiff/testdata/string/rename.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-diff --git a/file.txt b/numbers.txt
-similarity index 100%
-rename from file.txt
-rename to numbers.txt
diff --git a/pkg/gitdiff/testdata/string/rename_modify.patch b/pkg/gitdiff/testdata/string/rename_modify.patch
deleted file mode 100644
index 52a32af..0000000
--- a/pkg/gitdiff/testdata/string/rename_modify.patch
+++ /dev/null
@@ -1,18 +0,0 @@
-diff --git a/file.txt b/numbers.txt
-similarity index 77%
-rename from file.txt
-rename to numbers.txt
-index c9e9e05..a6b31d6 100644
---- a/file.txt
-+++ b/numbers.txt
-@@ -3,8 +3,9 @@ two
- three
- four
- five
--six
-+ six
- seven
- eight
- nine
- ten
-+eleven
diff --git a/pkg/gitdiff/testdata/two_files.patch b/pkg/gitdiff/testdata/two_files.patch
deleted file mode 100644
index dd14421..0000000
--- a/pkg/gitdiff/testdata/two_files.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-commit 5d9790fec7d95aa223f3d20936340bf55ff3dcbe
-Author: Morton Haypenny <mhaypenny@example.com>
-Date: Tue Apr 2 22:55:40 2019 -0700
-
- A file with multiple fragments.
-
- The content is arbitrary.
-
-diff --git a/dir/file1.txt b/dir/file1.txt
-index ebe9fa54..fe103e1d 100644
---- a/dir/file1.txt
-+++ b/dir/file1.txt
-@@ -3,6 +3,8 @@ fragment 1
- context line
--old line 1
--old line 2
- context line
-+new line 1
-+new line 2
-+new line 3
- context line
--old line 3
-+new line 4
-+new line 5
-@@ -31,2 +33,2 @@ fragment 2
- context line
--old line 4
-+new line 6
-diff --git a/dir/file2.txt b/dir/file2.txt
-index 417ebc70..67514b7f 100644
---- a/dir/file2.txt
-+++ b/dir/file2.txt
-@@ -3,6 +3,8 @@ fragment 1
- context line
--old line 1
--old line 2
- context line
-+new line 1
-+new line 2
-+new line 3
- context line
--old line 3
-+new line 4
-+new line 5
-@@ -31,2 +33,2 @@ fragment 2
- context line
--old line 4
-+new line 6
diff --git a/pkg/gitdiff/text_test.go b/pkg/gitdiff/text_test.go
deleted file mode 100644
index 990b3bc..0000000
--- a/pkg/gitdiff/text_test.go
+++ /dev/null
@@ -1,488 +0,0 @@
-package gitdiff
-
-import (
- "io"
- "reflect"
- "testing"
-)
-
-func TestParseTextFragmentHeader(t *testing.T) {
- tests := map[string]struct {
- Input string
- Output *TextFragment
- Err bool
- }{
- "shortest": {
- Input: "@@ -1 +1 @@\n",
- Output: &TextFragment{
- OldPosition: 1,
- OldLines: 1,
- NewPosition: 1,
- NewLines: 1,
- },
- },
- "standard": {
- Input: "@@ -21,5 +28,9 @@\n",
- Output: &TextFragment{
- OldPosition: 21,
- OldLines: 5,
- NewPosition: 28,
- NewLines: 9,
- },
- },
- "trailingComment": {
- Input: "@@ -21,5 +28,9 @@ func test(n int) {\n",
- Output: &TextFragment{
- Comment: "func test(n int) {",
- OldPosition: 21,
- OldLines: 5,
- NewPosition: 28,
- NewLines: 9,
- },
- },
- "incomplete": {
- Input: "@@ -12,3 +2\n",
- Err: true,
- },
- "badNumbers": {
- Input: "@@ -1a,2b +3c,4d @@\n",
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- frag, err := p.ParseTextFragmentHeader()
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing header, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("error parsing header: %v", err)
- }
-
- if !reflect.DeepEqual(test.Output, frag) {
- t.Errorf("incorrect fragment\nexpected: %+v\nactual: %+v", test.Output, frag)
- }
- })
- }
-}
-
-func TestParseTextChunk(t *testing.T) {
- tests := map[string]struct {
- Input string
- Fragment TextFragment
-
- Output *TextFragment
- Err bool
- }{
- "addWithContext": {
- Input: ` context line
-+new line 1
-+new line 2
- context line
-`,
- Fragment: TextFragment{
- OldLines: 2,
- NewLines: 4,
- },
- Output: &TextFragment{
- OldLines: 2,
- NewLines: 4,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpAdd, "new line 1\n"},
- {OpAdd, "new line 2\n"},
- {OpContext, "context line\n"},
- },
- LinesAdded: 2,
- LeadingContext: 1,
- TrailingContext: 1,
- },
- },
- "deleteWithContext": {
- Input: ` context line
--old line 1
--old line 2
- context line
-`,
- Fragment: TextFragment{
- OldLines: 4,
- NewLines: 2,
- },
- Output: &TextFragment{
- OldLines: 4,
- NewLines: 2,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 1\n"},
- {OpDelete, "old line 2\n"},
- {OpContext, "context line\n"},
- },
- LinesDeleted: 2,
- LeadingContext: 1,
- TrailingContext: 1,
- },
- },
- "replaceWithContext": {
- Input: ` context line
--old line 1
-+new line 1
- context line
-`,
- Fragment: TextFragment{
- OldLines: 3,
- NewLines: 3,
- },
- Output: &TextFragment{
- OldLines: 3,
- NewLines: 3,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 1\n"},
- {OpAdd, "new line 1\n"},
- {OpContext, "context line\n"},
- },
- LinesDeleted: 1,
- LinesAdded: 1,
- LeadingContext: 1,
- TrailingContext: 1,
- },
- },
- "middleContext": {
- Input: ` context line
--old line 1
- context line
-+new line 1
- context line
-`,
- Fragment: TextFragment{
- OldLines: 4,
- NewLines: 4,
- },
- Output: &TextFragment{
- OldLines: 4,
- NewLines: 4,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 1\n"},
- {OpContext, "context line\n"},
- {OpAdd, "new line 1\n"},
- {OpContext, "context line\n"},
- },
- LinesDeleted: 1,
- LinesAdded: 1,
- LeadingContext: 1,
- TrailingContext: 1,
- },
- },
- "deleteFinalNewline": {
- Input: ` context line
--old line 1
-+new line 1
-\ No newline at end of file
-`,
- Fragment: TextFragment{
- OldLines: 2,
- NewLines: 2,
- },
- Output: &TextFragment{
- OldLines: 2,
- NewLines: 2,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 1\n"},
- {OpAdd, "new line 1"},
- },
- LinesDeleted: 1,
- LinesAdded: 1,
- LeadingContext: 1,
- },
- },
- "addFinalNewline": {
- Input: ` context line
--old line 1
-\ No newline at end of file
-+new line 1
-`,
- Fragment: TextFragment{
- OldLines: 2,
- NewLines: 2,
- },
- Output: &TextFragment{
- OldLines: 2,
- NewLines: 2,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 1"},
- {OpAdd, "new line 1\n"},
- },
- LinesDeleted: 1,
- LinesAdded: 1,
- LeadingContext: 1,
- },
- },
- "addAll": {
- Input: `+new line 1
-+new line 2
-+new line 3
-`,
- Fragment: TextFragment{
- OldLines: 0,
- NewLines: 3,
- },
- Output: &TextFragment{
- OldLines: 0,
- NewLines: 3,
- Lines: []Line{
- {OpAdd, "new line 1\n"},
- {OpAdd, "new line 2\n"},
- {OpAdd, "new line 3\n"},
- },
- LinesAdded: 3,
- },
- },
- "deleteAll": {
- Input: `-old line 1
--old line 2
--old line 3
-`,
- Fragment: TextFragment{
- OldLines: 3,
- NewLines: 0,
- },
- Output: &TextFragment{
- OldLines: 3,
- NewLines: 0,
- Lines: []Line{
- {OpDelete, "old line 1\n"},
- {OpDelete, "old line 2\n"},
- {OpDelete, "old line 3\n"},
- },
- LinesDeleted: 3,
- },
- },
- "emptyContextLine": {
- Input: ` context line
-
-+new line
- context line
-`,
- Fragment: TextFragment{
- OldLines: 3,
- NewLines: 4,
- },
- Output: &TextFragment{
- OldLines: 3,
- NewLines: 4,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpContext, "\n"},
- {OpAdd, "new line\n"},
- {OpContext, "context line\n"},
- },
- LinesAdded: 1,
- LeadingContext: 2,
- TrailingContext: 1,
- },
- },
- "emptyChunk": {
- Input: "",
- Err: true,
- },
- "invalidOperation": {
- Input: ` context line
-?wat line
- context line
-`,
- Fragment: TextFragment{
- OldLines: 3,
- NewLines: 3,
- },
- Err: true,
- },
- "unbalancedHeader": {
- Input: ` context line
--old line 1
-+new line 1
- context line
-`,
- Fragment: TextFragment{
- OldLines: 2,
- NewLines: 5,
- },
- Err: true,
- },
- "onlyContext": {
- Input: ` context line
- context line
-`,
- Fragment: TextFragment{
- OldLines: 2,
- NewLines: 2,
- },
- Err: true,
- },
- "unexpectedNoNewlineMarker": {
- Input: `\ No newline at end of file`,
- Fragment: TextFragment{
- OldLines: 1,
- NewLines: 1,
- },
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- frag := test.Fragment
- err := p.ParseTextChunk(&frag)
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing text chunk, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("error parsing text chunk: %v", err)
- }
-
- if !reflect.DeepEqual(test.Output, &frag) {
- t.Errorf("incorrect fragment\nexpected: %+v\nactual: %+v", test.Output, &frag)
- }
- })
- }
-}
-
-func TestParseTextFragments(t *testing.T) {
- tests := map[string]struct {
- Input string
- File File
-
- Fragments []*TextFragment
- Err bool
- }{
- "multipleChanges": {
- Input: `@@ -1,3 +1,2 @@
- context line
--old line 1
- context line
-@@ -8,3 +7,3 @@
- context line
--old line 2
-+new line 1
- context line
-@@ -15,3 +14,4 @@
- context line
--old line 3
-+new line 2
-+new line 3
- context line
-`,
- Fragments: []*TextFragment{
- {
- OldPosition: 1,
- OldLines: 3,
- NewPosition: 1,
- NewLines: 2,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 1\n"},
- {OpContext, "context line\n"},
- },
- LinesDeleted: 1,
- LeadingContext: 1,
- TrailingContext: 1,
- },
- {
- OldPosition: 8,
- OldLines: 3,
- NewPosition: 7,
- NewLines: 3,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 2\n"},
- {OpAdd, "new line 1\n"},
- {OpContext, "context line\n"},
- },
- LinesDeleted: 1,
- LinesAdded: 1,
- LeadingContext: 1,
- TrailingContext: 1,
- },
- {
- OldPosition: 15,
- OldLines: 3,
- NewPosition: 14,
- NewLines: 4,
- Lines: []Line{
- {OpContext, "context line\n"},
- {OpDelete, "old line 3\n"},
- {OpAdd, "new line 2\n"},
- {OpAdd, "new line 3\n"},
- {OpContext, "context line\n"},
- },
- LinesDeleted: 1,
- LinesAdded: 2,
- LeadingContext: 1,
- TrailingContext: 1,
- },
- },
- },
- "badNewFile": {
- Input: `@@ -1 +1,2 @@
--old line 1
-+new line 1
-+new line 2
-`,
- File: File{
- IsNew: true,
- },
- Err: true,
- },
- "badDeletedFile": {
- Input: `@@ -1,2 +1 @@
--old line 1
- context line
-`,
- File: File{
- IsDelete: true,
- },
- Err: true,
- },
- }
-
- for name, test := range tests {
- t.Run(name, func(t *testing.T) {
- p := newTestParser(test.Input, true)
-
- file := test.File
- n, err := p.ParseTextFragments(&file)
- if test.Err {
- if err == nil || err == io.EOF {
- t.Fatalf("expected error parsing text fragments, but got %v", err)
- }
- return
- }
- if err != nil {
- t.Fatalf("error parsing text fragments: %v", err)
- }
-
- if len(test.Fragments) != n {
- t.Fatalf("incorrect number of added fragments: expected %d, actual %d", len(test.Fragments), n)
- }
-
- for i, frag := range test.Fragments {
- if !reflect.DeepEqual(frag, file.TextFragments[i]) {
- t.Errorf("incorrect fragment at position %d\nexpected: %+v\nactual: %+v", i, frag, file.TextFragments[i])
- }
- }
- })
- }
-}
diff --git a/pkg/links/links.go b/pkg/links/links.go
index 1bed63e..0795dfc 100644
--- a/pkg/links/links.go
+++ b/pkg/links/links.go
@@ -8,7 +8,7 @@ import (
"golang.org/x/net/html"
- "github.com/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
)
type Set map[string]struct{}
diff --git a/pkg/links/links_test.go b/pkg/links/links_test.go
deleted file mode 100644
index 4d33c3f..0000000
--- a/pkg/links/links_test.go
+++ /dev/null
@@ -1,228 +0,0 @@
-package links
-
-import (
- "strings"
- "testing"
-
- "github.com/antonmedv/gitmal/pkg/git"
-)
-
-func buildTestSets(blobs []git.Blob) (Set, Set) {
- dirs := BuildDirSet(blobs)
- files := BuildFileSet(blobs)
- return dirs, files
-}
-
-func TestResolve_Links(t *testing.T) {
- blobs := []git.Blob{
- {Path: "README.md"},
- {Path: "docs/intro.md"},
- {Path: "docs/getting-started.md"},
- {Path: "docs/faq.md"},
- {Path: "docs/tutorial/step1.md"},
- }
-
- dirs, files := buildTestSets(blobs)
-
- currentPath := "docs/intro.md"
- rootHref := "../../"
- ref := "master"
-
- tests := []struct {
- name string
- content string
- wantContain []string
- notContain []string
- }{
- {
- name: "relative link to existing .md file gets .html appended (per current transformHref)",
- content: `<a href="getting-started.md">Getting started</a>`,
- wantContain: []string{
- `href="../../blob/master/docs/getting-started.md.html"`,
- },
- notContain: []string{
- `href="../../blob/master/docs/getting-started.md"`,
- },
- },
- {
- name: "relative link without extension to existing .md file gets .html appended",
- content: `<a href="faq">FAQ</a>`,
- wantContain: []string{
- `href="../../blob/master/docs/faq.md.html"`,
- },
- notContain: []string{
- `href="faq">`,
- },
- },
- {
- name: "relative link to directory without trailing slash goes to /index.html",
- content: `<a href="tutorial">Tutorial</a>`,
- wantContain: []string{
- `href="../../blob/master/docs/tutorial/index.html"`,
- },
- notContain: []string{
- `href="tutorial">`,
- },
- },
- {
- name: "relative link to directory with trailing slash goes to /index.html",
- content: `<a href="tutorial/">Tutorial</a>`,
- wantContain: []string{
- `href="../../blob/master/docs/tutorial/index.html"`,
- },
- notContain: []string{
- `href="tutorial/">`,
- },
- },
- {
- name: "absolute http URL unchanged",
- content: `<a href="https://example.org">External</a>`,
- wantContain: []string{
- `href="https://example.org"`,
- },
- },
- {
- name: "root-relative link to repo file is resolved",
- content: `<a href="/README.md">FAQ</a>`,
- wantContain: []string{
- `href="../../blob/master/README.md.html"`,
- },
- },
- {
- name: "fragment-only href unchanged",
- content: `<a href="#section1">Jump</a>`,
- wantContain: []string{
- `href="#section1"`,
- },
- },
- {
- name: "mailto href unchanged",
- content: `<a href="mailto:test@example.com">Mail</a>`,
- wantContain: []string{
- `href="mailto:test@example.com"`,
- },
- },
- {
- name: "unknown relative path left untouched",
- content: `<a href="unknown.md">Unknown</a>`,
- wantContain: []string{
- `href="unknown.md"`,
- },
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := Resolve(tt.content, currentPath, rootHref, ref, dirs, files)
-
- for _, want := range tt.wantContain {
- if !strings.Contains(got, want) {
- t.Errorf("expected output to contain %q, got:\n%s", want, got)
- }
- }
- for _, notWant := range tt.notContain {
- if strings.Contains(got, notWant) {
- t.Errorf("expected output NOT to contain %q, got:\n%s", notWant, got)
- }
- }
- })
- }
-}
-
-func TestResolve_Images(t *testing.T) {
- // For image behavior we only care about currentPath/rootHref/ref, not dirs/files.
- blobs := []git.Blob{
- {Path: "foo/bar/readme.md"},
- }
- dirs, files := buildTestSets(blobs)
-
- rootHref := "../../"
- ref := "master"
-
- t.Run("relative image src rewritten to raw URL with ref", func(t *testing.T) {
- // current blob: foo/bar/readme.md
- // img src: ../images/pic.png
- // repoPath: foo/images/pic.png
- // final: rootHref + "/raw/master/foo/images/pic.png"
- content := `<p><img src="../images/pic.png" alt="Pic"></p>`
-
- got := Resolve(content, "foo/bar/readme.md", rootHref, ref, dirs, files)
-
- expected := `src="../../raw/master/foo/images/pic.png"`
- if !strings.Contains(got, expected) {
- t.Fatalf("expected output to contain %q, got:\n%s", expected, got)
- }
- })
-
- t.Run("relative image src with ./ prefix", func(t *testing.T) {
- content := `<p><img src="./img/logo.png"></p>`
-
- got := Resolve(content, "foo/readme.md", rootHref, ref, dirs, files)
-
- // repoPath: "foo/img/logo.png"
- expected := `src="../../raw/master/foo/img/logo.png"`
- if !strings.Contains(got, expected) {
- t.Fatalf("expected output to contain %q, got:\n%s", expected, got)
- }
- })
-
- t.Run("absolute image src unchanged, root-relative resolved from repo root", func(t *testing.T) {
- content := `
-<p>
- <img src="https://cdn.example.com/img.png">
- <img src="/static/logo.png">
-</p>`
-
- got := Resolve(content, "docs/intro.md", rootHref, ref, dirs, files)
-
- if !strings.Contains(got, `src="https://cdn.example.com/img.png"`) {
- t.Errorf("expected absolute src to be unchanged, got:\n%s", got)
- }
- // root-relative should now point to raw/ref/... from repo root
- if !strings.Contains(got, `src="../../raw/master/static/logo.png"`) {
- t.Errorf("expected root-relative src to be resolved to raw URL, got:\n%s", got)
- }
- })
-
- t.Run("image with query and fragment preserves them", func(t *testing.T) {
- content := `<img src="../images/pic.png?size=large#anchor">`
-
- got := Resolve(content, "foo/bar/readme.md", rootHref, ref, dirs, files)
-
- if !strings.Contains(got, `src="../../raw/master/foo/images/pic.png?size=large#anchor"`) {
- t.Errorf("expected src to be rewritten and keep query+fragment, got:\n%s", got)
- }
- })
-}
-
-func TestBuildDirSet(t *testing.T) {
- blobs := []git.Blob{
- {Path: "a/b/c.md"},
- {Path: "a/d/e.md"},
- {Path: "x.md"},
- }
-
- dirs := BuildDirSet(blobs)
-
- wantDirs := []string{"a", "a/b", "a/d"}
- for _, d := range wantDirs {
- if _, ok := dirs[d]; !ok {
- t.Errorf("expected dirs to contain %q", d)
- }
- }
-}
-
-func TestBuildFileSet(t *testing.T) {
- blobs := []git.Blob{
- {Path: "docs/intro.md"},
- {Path: "README.md"},
- }
-
- files := BuildFileSet(blobs)
-
- for _, p := range []string{"docs/intro.md", "README.md"} {
- if _, ok := files[p]; !ok {
- t.Errorf("expected files to contain %q", p)
- }
- }
-}
diff --git a/pkg/templates/blob.gohtml b/pkg/templates/blob.gohtml
index 458a855..b98e2b3 100644
--- a/pkg/templates/blob.gohtml
+++ b/pkg/templates/blob.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.BlobParams */ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.BlobParams */ -}}
{{ define "head" }}
<style>
{{ .CSS }}
diff --git a/pkg/templates/branches.gohtml b/pkg/templates/branches.gohtml
index 9ffc091..743461d 100644
--- a/pkg/templates/branches.gohtml
+++ b/pkg/templates/branches.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.BranchesParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.BranchesParams*/ -}}
{{ define "head" }}
<style>
.branches {
diff --git a/pkg/templates/commit.gohtml b/pkg/templates/commit.gohtml
index d5c6b37..3176f97 100644
--- a/pkg/templates/commit.gohtml
+++ b/pkg/templates/commit.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.CommitParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.CommitParams*/ -}}
{{ define "head" }}
<style>
h1 code {
diff --git a/pkg/templates/commits_list.gohtml b/pkg/templates/commits_list.gohtml
index 21d3ab2..76dd43c 100644
--- a/pkg/templates/commits_list.gohtml
+++ b/pkg/templates/commits_list.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.CommitsListParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.CommitsListParams*/ -}}
{{ define "head" }}
<style>
.commits {
diff --git a/pkg/templates/file_tree.gohtml b/pkg/templates/file_tree.gohtml
index f096ecb..21fc07c 100644
--- a/pkg/templates/file_tree.gohtml
+++ b/pkg/templates/file_tree.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype:github.com/antonmedv/gitmal/pkg/templates.FileTreeParams*/ -}}
+{{- /*gotype:mokhan.ca/antonmedv/gitmal/pkg/templates.FileTreeParams*/ -}}
{{ define "file_tree" }}
{{ range .Nodes }}
{{ if .IsDir }}
diff --git a/pkg/templates/header.gohtml b/pkg/templates/header.gohtml
index e326c43..4b5af05 100644
--- a/pkg/templates/header.gohtml
+++ b/pkg/templates/header.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.HeaderParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.HeaderParams*/ -}}
{{ define "header" }}
<div class="header-container">
<header>
diff --git a/pkg/templates/layout.gohtml b/pkg/templates/layout.gohtml
index cefc24d..9438396 100644
--- a/pkg/templates/layout.gohtml
+++ b/pkg/templates/layout.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.LayoutParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.LayoutParams*/ -}}
<!DOCTYPE html>
<html lang="en">
<head>
@@ -313,7 +313,6 @@
</div>
</main>
<footer>
- Generated by <a href="https://github.com/antonmedv/gitmal">Gitmal</a>
</footer>
</body>
</html>
diff --git a/pkg/templates/list.gohtml b/pkg/templates/list.gohtml
index 9955260..9780504 100644
--- a/pkg/templates/list.gohtml
+++ b/pkg/templates/list.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.ListParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.ListParams*/ -}}
{{ define "head" }}
<style>
.files {
diff --git a/pkg/templates/markdown.gohtml b/pkg/templates/markdown.gohtml
index 782e993..7827950 100644
--- a/pkg/templates/markdown.gohtml
+++ b/pkg/templates/markdown.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.MarkdownParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.MarkdownParams*/ -}}
{{ define "head" }}
<style>
[id] {
diff --git a/pkg/templates/preview.gohtml b/pkg/templates/preview.gohtml
index 0f9b78c..bc6f898 100644
--- a/pkg/templates/preview.gohtml
+++ b/pkg/templates/preview.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.PreviewParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.PreviewParams*/ -}}
<!DOCTYPE html>
<html lang="en">
<head>
diff --git a/pkg/templates/tags.gohtml b/pkg/templates/tags.gohtml
index 32f8e0b..97b77b0 100644
--- a/pkg/templates/tags.gohtml
+++ b/pkg/templates/tags.gohtml
@@ -1,4 +1,4 @@
-{{- /*gotype: github.com/antonmedv/gitmal/pkg/templates.TagsParams*/ -}}
+{{- /*gotype: mokhan.ca/antonmedv/gitmal/pkg/templates.TagsParams*/ -}}
{{ define "head" }}
<style>
.tags {
diff --git a/pkg/templates/templates.go b/pkg/templates/templates.go
index 91d4884..593f0a3 100644
--- a/pkg/templates/templates.go
+++ b/pkg/templates/templates.go
@@ -7,7 +7,7 @@ import (
"path/filepath"
"time"
- "github.com/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
)
var funcs = FuncMap{
diff --git a/post_process.go b/post_process.go
index 392fa74..895d933 100644
--- a/post_process.go
+++ b/post_process.go
@@ -16,7 +16,7 @@ import (
"github.com/tdewolff/minify/v2/html"
"github.com/tdewolff/minify/v2/svg"
- "github.com/antonmedv/gitmal/pkg/progress_bar"
+ "mokhan.ca/antonmedv/gitmal/pkg/progress_bar"
)
func postProcessHTML(root string, doMinify bool, doGzip bool) error {
diff --git a/readme.go b/readme.go
index a70146c..ecdb500 100644
--- a/readme.go
+++ b/readme.go
@@ -5,8 +5,8 @@ import (
"html/template"
"strings"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/links"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/links"
)
func readme(files []git.Blob, dirsSet, filesSet links.Set, params Params, rootHref string) template.HTML {
diff --git a/tags.go b/tags.go
index eb3bdf0..fc8ebba 100644
--- a/tags.go
+++ b/tags.go
@@ -5,8 +5,8 @@ import (
"os"
"path/filepath"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
func generateTags(entries []git.Tag, params Params) error {
diff --git a/themes.go b/themes.go
index e2a8d17..ef9dc1c 100644
--- a/themes.go
+++ b/themes.go
@@ -11,7 +11,7 @@ import (
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
var themeStyles = map[string]string{
diff --git a/utils.go b/utils.go
index 2deacc6..0b096c6 100644
--- a/utils.go
+++ b/utils.go
@@ -6,8 +6,8 @@ import (
"path/filepath"
"strings"
- "github.com/antonmedv/gitmal/pkg/git"
- "github.com/antonmedv/gitmal/pkg/templates"
+ "mokhan.ca/antonmedv/gitmal/pkg/git"
+ "mokhan.ca/antonmedv/gitmal/pkg/templates"
)
const dot = "ยท"