mirror of
https://github.com/romdo/go-conventionalcommit.git
synced 2026-02-18 23:56:41 +00:00
Merge pull request #1 from romdo/add-rawmessage
feat(parser): implement RawMessage
This commit is contained in:
145
.github/workflows/ci.yml
vendored
Normal file
145
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
name: CI
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
version: v1.41
|
||||
env:
|
||||
VERBOSE: "true"
|
||||
|
||||
tidy:
|
||||
name: Tidy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
- name: Check if mods are tidy
|
||||
run: make check-tidy
|
||||
|
||||
benchmark:
|
||||
name: Benchmarks
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref != 'refs/heads/main'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
- name: Run benchmarks
|
||||
run: make bench | tee output.raw
|
||||
- name: Fix benchmark names
|
||||
run: >-
|
||||
perl -pe 's/^(Benchmark.+?)\/(\S+)(-\d+)(\s+)/\1__\2\4/' output.raw |
|
||||
tr '-' '_' | tee output.txt
|
||||
- name: Announce benchmark result
|
||||
uses: rhysd/github-action-benchmark@v1
|
||||
with:
|
||||
tool: "go"
|
||||
output-file-path: output.txt
|
||||
fail-on-alert: true
|
||||
comment-on-alert: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
auto-push: false
|
||||
|
||||
cov:
|
||||
name: Coverage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
- name: Publish coverage
|
||||
uses: paambaati/codeclimate-action@v2.7.4
|
||||
env:
|
||||
VERBOSE: "true"
|
||||
GOMAXPROCS: 4
|
||||
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
|
||||
with:
|
||||
coverageCommand: make cov
|
||||
prefix: github.com/${{ github.repository }}
|
||||
coverageLocations: |
|
||||
${{ github.workspace }}/coverage.out:gocov
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go_version:
|
||||
- "1.15"
|
||||
- "1.16"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.terraform_version }}
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
- name: Run tests
|
||||
run: make test
|
||||
env:
|
||||
VERBOSE: "true"
|
||||
|
||||
benchmark-store:
|
||||
name: Store benchmarks
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
- name: Run benchmarks
|
||||
run: make bench | tee output.raw
|
||||
- name: Fix benchmark names
|
||||
run: >-
|
||||
perl -pe 's/^(Benchmark.+?)\/(\S+)(-\d+)(\s+)/\1__\2\4/' output.raw |
|
||||
tr '-' '_' | tee output.txt
|
||||
- name: Store benchmark result
|
||||
uses: rhysd/github-action-benchmark@v1
|
||||
with:
|
||||
tool: "go"
|
||||
output-file-path: output.txt
|
||||
github-token: ${{ secrets.ROMDOBOT_TOKEN }}
|
||||
comment-on-alert: true
|
||||
auto-push: true
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/*.tidy-check
|
||||
/bin/*
|
||||
/coverage.out
|
||||
/output.txt
|
||||
93
.golangci.yml
Normal file
93
.golangci.yml
Normal file
@@ -0,0 +1,93 @@
|
||||
linters-settings:
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 150
|
||||
goconst:
|
||||
min-occurrences: 5
|
||||
gocyclo:
|
||||
min-complexity: 20
|
||||
golint:
|
||||
min-confidence: 0
|
||||
govet:
|
||||
check-shadowing: true
|
||||
enable-all: true
|
||||
disable:
|
||||
- fieldalignment
|
||||
lll:
|
||||
line-length: 80
|
||||
tab-width: 4
|
||||
maligned:
|
||||
suggest-new: true
|
||||
misspell:
|
||||
locale: US
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
- dupl
|
||||
- durationcheck
|
||||
- errcheck
|
||||
- errorlint
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- funlen
|
||||
- gochecknoinits
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- godot
|
||||
- gofumpt
|
||||
- goimports
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
- nilerr
|
||||
- noctx
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- predeclared
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- tparallel
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- wastedassign
|
||||
- whitespace
|
||||
|
||||
issues:
|
||||
exclude:
|
||||
- Using the variable on range scope `tt` in function literal
|
||||
- Using the variable on range scope `tc` in function literal
|
||||
exclude-rules:
|
||||
- path: "_test\\.go"
|
||||
linters:
|
||||
- funlen
|
||||
- dupl
|
||||
- goconst
|
||||
- source: "^//go:generate "
|
||||
linters:
|
||||
- lll
|
||||
- source: "`json:"
|
||||
linters:
|
||||
- lll
|
||||
|
||||
run:
|
||||
timeout: 2m
|
||||
allow-parallel-runners: true
|
||||
modules-download-mode: readonly
|
||||
192
Makefile
Normal file
192
Makefile
Normal file
@@ -0,0 +1,192 @@
|
||||
GOMODNAME := $(shell grep 'module' go.mod | sed -e 's/^module //')
|
||||
SOURCES := $(shell find . -name "*.go" -or -name "go.mod" -or -name "go.sum" \
|
||||
-or -name "Makefile")
|
||||
|
||||
# Verbose output
|
||||
ifdef VERBOSE
|
||||
V = -v
|
||||
endif
|
||||
|
||||
#
|
||||
# Environment
|
||||
#
|
||||
|
||||
BINDIR := bin
|
||||
TOOLDIR := $(BINDIR)/tools
|
||||
|
||||
# Global environment variables for all targets
|
||||
SHELL ?= /bin/bash
|
||||
SHELL := env \
|
||||
GO111MODULE=on \
|
||||
GOBIN=$(CURDIR)/$(TOOLDIR) \
|
||||
CGO_ENABLED=1 \
|
||||
PATH='$(CURDIR)/$(BINDIR):$(CURDIR)/$(TOOLDIR):$(PATH)' \
|
||||
$(SHELL)
|
||||
|
||||
#
|
||||
# Defaults
|
||||
#
|
||||
|
||||
# Default target
|
||||
.DEFAULT_GOAL := test
|
||||
|
||||
#
|
||||
# Tools
|
||||
#
|
||||
|
||||
TOOLS += $(TOOLDIR)/gobin
|
||||
$(TOOLDIR)/gobin:
|
||||
GO111MODULE=off go get -u github.com/myitcv/gobin
|
||||
|
||||
# external tool
|
||||
define tool # 1: binary-name, 2: go-import-path
|
||||
TOOLS += $(TOOLDIR)/$(1)
|
||||
|
||||
$(TOOLDIR)/$(1): $(TOOLDIR)/gobin Makefile
|
||||
gobin $(V) "$(2)"
|
||||
endef
|
||||
|
||||
$(eval $(call tool,godoc,golang.org/x/tools/cmd/godoc))
|
||||
$(eval $(call tool,gofumports,mvdan.cc/gofumpt/gofumports))
|
||||
$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.41))
|
||||
$(eval $(call tool,gomod,github.com/Helcaraxan/gomod))
|
||||
|
||||
.PHONY: tools
|
||||
tools: $(TOOLS)
|
||||
|
||||
#
|
||||
# Development
|
||||
#
|
||||
|
||||
BENCH ?= .
|
||||
TESTARGS ?=
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(TOOLS)
|
||||
rm -f ./coverage.out ./go.mod.tidy-check ./go.sum.tidy-check
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test $(V) -count=1 -race $(TESTARGS) ./...
|
||||
|
||||
.PHONY: test-deps
|
||||
test-deps:
|
||||
go test all
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(TOOLDIR)/golangci-lint
|
||||
golangci-lint $(V) run
|
||||
|
||||
.PHONY: format
|
||||
format: $(TOOLDIR)/gofumports
|
||||
gofumports -w .
|
||||
|
||||
.SILENT: bench
|
||||
.PHONY: bench
|
||||
bench:
|
||||
go test $(V) -count=1 -bench=$(BENCH) $(TESTARGS) ./...
|
||||
|
||||
#
|
||||
# Code Generation
|
||||
#
|
||||
|
||||
.PHONY: generate
|
||||
generate:
|
||||
go generate ./...
|
||||
|
||||
.PHONY: check-generate
|
||||
check-generate:
|
||||
$(eval CHKDIR := $(shell mktemp -d))
|
||||
cp -av . "$(CHKDIR)"
|
||||
make -C "$(CHKDIR)/" generate
|
||||
( diff -rN . "$(CHKDIR)" && rm -rf "$(CHKDIR)" ) || \
|
||||
( rm -rf "$(CHKDIR)" && exit 1 )
|
||||
|
||||
#
|
||||
# Coverage
|
||||
#
|
||||
|
||||
.PHONY: cov
|
||||
cov: coverage.out
|
||||
|
||||
.PHONY: cov-html
|
||||
cov-html: coverage.out
|
||||
go tool cover -html=./coverage.out
|
||||
|
||||
.PHONY: cov-func
|
||||
cov-func: coverage.out
|
||||
go tool cover -func=./coverage.out
|
||||
|
||||
coverage.out: $(SOURCES)
|
||||
go test $(V) -covermode=count -coverprofile=./coverage.out ./...
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
go mod download
|
||||
|
||||
.PHONY: deps-update
|
||||
deps-update:
|
||||
go get -u -t ./...
|
||||
|
||||
.PHONY: deps-analyze
|
||||
deps-analyze: $(TOOLDIR)/gomod
|
||||
gomod analyze
|
||||
|
||||
.PHONY: tidy
|
||||
tidy:
|
||||
go mod tidy $(V)
|
||||
|
||||
.PHONY: verify
|
||||
verify:
|
||||
go mod verify
|
||||
|
||||
.SILENT: check-tidy
|
||||
.PHONY: check-tidy
|
||||
check-tidy:
|
||||
cp go.mod go.mod.tidy-check
|
||||
cp go.sum go.sum.tidy-check
|
||||
go mod tidy
|
||||
( \
|
||||
diff go.mod go.mod.tidy-check && \
|
||||
diff go.sum go.sum.tidy-check && \
|
||||
rm -f go.mod go.sum && \
|
||||
mv go.mod.tidy-check go.mod && \
|
||||
mv go.sum.tidy-check go.sum \
|
||||
) || ( \
|
||||
rm -f go.mod go.sum && \
|
||||
mv go.mod.tidy-check go.mod && \
|
||||
mv go.sum.tidy-check go.sum; \
|
||||
exit 1 \
|
||||
)
|
||||
|
||||
#
|
||||
# Documentation
|
||||
#
|
||||
|
||||
# Serve docs
|
||||
.PHONY: docs
|
||||
docs: godoc
|
||||
$(info serviing docs on http://127.0.0.1:6060/pkg/$(GOMODNAME)/)
|
||||
@godoc -http=127.0.0.1:6060
|
||||
|
||||
#
|
||||
# Release
|
||||
#
|
||||
|
||||
.PHONY: new-version
|
||||
new-version: check-npx
|
||||
npx standard-version
|
||||
|
||||
.PHONY: next-version
|
||||
next-version: check-npx
|
||||
npx standard-version --dry-run
|
||||
|
||||
.PHONY: check-npx
|
||||
check-npx:
|
||||
$(if $(shell which npx),,\
|
||||
$(error No npx found in PATH, please install NodeJS))
|
||||
5
go.mod
Normal file
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module github.com/romdo/go-conventionalcommit
|
||||
|
||||
go 1.15
|
||||
|
||||
require github.com/stretchr/testify v1.7.0
|
||||
11
go.sum
Normal file
11
go.sum
Normal file
@@ -0,0 +1,11 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
102
line.go
Normal file
102
line.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package conventionalcommit
|
||||
|
||||
const (
|
||||
lf = 10 // linefeed ("\n") character
|
||||
cr = 13 // carriage return ("\r") character
|
||||
)
|
||||
|
||||
// Line represents a single line of text defined as; A continuous sequence of
|
||||
// bytes which do not contain a \r (carriage return) or \n (line-feed) byte.
|
||||
type Line struct {
|
||||
// Line number within commit message, starting a 1 rather than 0, as
|
||||
// text viewed in a text editor starts on line 1, not line 0.
|
||||
Number int
|
||||
|
||||
// Content is the raw bytes that make up the text content in the line.
|
||||
Content []byte
|
||||
|
||||
// Break is the linebreak type used at the end of the line. It will be one
|
||||
// of "\n", "\r\n", "\r", or empty if it is the very last line.
|
||||
Break []byte
|
||||
}
|
||||
|
||||
// Lines is a slice of *Line types with some helper methods attached.
|
||||
type Lines []*Line
|
||||
|
||||
// NewLines breaks the given byte slice down into a slice of Line structs,
|
||||
// allowing easier inspection and manipulation of content on a line-by-line
|
||||
// basis.
|
||||
func NewLines(content []byte) Lines {
|
||||
r := Lines{}
|
||||
|
||||
if len(content) == 0 {
|
||||
return r
|
||||
}
|
||||
|
||||
// List of start/end offsets for each line break.
|
||||
var breaks [][]int
|
||||
|
||||
// Locate each line break within content.
|
||||
for i := 0; i < len(content); i++ {
|
||||
if content[i] == lf {
|
||||
breaks = append(breaks, []int{i, i + 1})
|
||||
} else if content[i] == cr {
|
||||
b := []int{i, i + 1}
|
||||
if i+1 < len(content) && content[i+1] == lf {
|
||||
b[1]++
|
||||
i++
|
||||
}
|
||||
breaks = append(breaks, b)
|
||||
}
|
||||
}
|
||||
|
||||
// Return a single line if there are no line breaks.
|
||||
if len(breaks) == 0 {
|
||||
return Lines{{Number: 1, Content: content, Break: []byte{}}}
|
||||
}
|
||||
|
||||
// Extract each line based on linebreak offsets.
|
||||
offset := 0
|
||||
for n, loc := range breaks {
|
||||
r = append(r, &Line{
|
||||
Number: n + 1,
|
||||
Content: content[offset:loc[0]],
|
||||
Break: content[loc[0]:loc[1]],
|
||||
})
|
||||
offset = loc[1]
|
||||
}
|
||||
|
||||
// Extract final line
|
||||
r = append(r, &Line{
|
||||
Number: len(breaks) + 1,
|
||||
Content: content[offset:],
|
||||
Break: []byte{},
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Bytes combines all Lines into a single byte slice, retaining the original
|
||||
// line break types for each line.
|
||||
func (s Lines) Bytes() []byte {
|
||||
// Pre-calculate capacity of result byte slice.
|
||||
size := 0
|
||||
for _, l := range s {
|
||||
size = size + len(l.Content) + len(l.Break)
|
||||
}
|
||||
|
||||
b := make([]byte, 0, size)
|
||||
|
||||
for _, l := range s {
|
||||
b = append(b, l.Content...)
|
||||
b = append(b, l.Break...)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Bytes combines all Lines into a single string, retaining the original line
|
||||
// break types for each line.
|
||||
func (s Lines) String() string {
|
||||
return string(s.Bytes())
|
||||
}
|
||||
594
line_test.go
Normal file
594
line_test.go
Normal file
@@ -0,0 +1,594 @@
|
||||
package conventionalcommit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewLines(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
content []byte
|
||||
want Lines
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
content: nil,
|
||||
want: Lines{},
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
content: []byte{},
|
||||
want: Lines{},
|
||||
},
|
||||
{
|
||||
name: "single line without trailing linebreak",
|
||||
content: []byte("hello world"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single line with trailing LF",
|
||||
content: []byte("hello world\n"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single line with trailing CRLF",
|
||||
content: []byte("hello world\r\n"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single line with trailing CR",
|
||||
content: []byte("hello world\r"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines separated by LF",
|
||||
content: []byte("hello world\nfoo\nbar"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("bar"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines separated by LF with trailing LF",
|
||||
content: []byte("hello world\nfoo\nbar\n"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("bar"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines separated by CRLF",
|
||||
content: []byte("hello world\r\nfoo\r\nbar"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("bar"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines separated by CRLF with trailing CRLF",
|
||||
content: []byte("hello world\r\nfoo\r\nbar\r\n"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("bar"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines separated by CR",
|
||||
content: []byte("hello world\rfoo\rbar"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("bar"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines separated by CR with trailing CR",
|
||||
content: []byte("hello world\rfoo\rbar\r"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("bar"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines separated by mixed break types",
|
||||
content: []byte("hello\nworld\r\nfoo\rbar"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("world"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("foo"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte("bar"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines separated by mixed break types with " +
|
||||
"trailing LF",
|
||||
content: []byte("hello\nworld\r\nfoo\rbar\n"),
|
||||
want: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("world"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("foo"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte("bar"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := NewLines(tt.content)
|
||||
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var linesBytesTestCases = []struct {
|
||||
name string
|
||||
lines Lines
|
||||
want []byte
|
||||
}{
|
||||
{
|
||||
name: "single line",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
},
|
||||
},
|
||||
want: []byte("hello world"),
|
||||
},
|
||||
{
|
||||
name: "single line with trailing LF",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []byte("hello world\n"),
|
||||
},
|
||||
{
|
||||
name: "single line with trailing CRLF",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []byte("hello world\r\n"),
|
||||
},
|
||||
{
|
||||
name: "single line with trailing CR",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []byte("hello world\r"),
|
||||
},
|
||||
{
|
||||
name: "multi-line separated by LF",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("Aliquam feugiat tellus ut neque."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte("Sed bibendum."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Content: []byte("Nullam libero mauris, consequat."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 6,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 7,
|
||||
Content: []byte("Integer placerat tristique nisl."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 8,
|
||||
Content: []byte("Etiam vel neque nec dui bibendum."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 9,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 10,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 11,
|
||||
Content: []byte("Nullam libero mauris, dictum id, arcu."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 12,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []byte(
|
||||
"Aliquam feugiat tellus ut neque.\n" +
|
||||
"Sed bibendum.\n" +
|
||||
"Nullam libero mauris, consequat.\n" +
|
||||
"\n" +
|
||||
"Integer placerat tristique nisl.\n" +
|
||||
"Etiam vel neque nec dui bibendum.\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"Nullam libero mauris, dictum id, arcu.\n",
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "multi-line separated by CRLF",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("Aliquam feugiat tellus ut neque."),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte("Sed bibendum."),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Content: []byte("Nullam libero mauris, consequat."),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 6,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 7,
|
||||
Content: []byte("Integer placerat tristique nisl."),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 8,
|
||||
Content: []byte("Etiam vel neque nec dui bibendum."),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 9,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 10,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 11,
|
||||
Content: []byte("Nullam libero mauris, dictum id, arcu."),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 12,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []byte(
|
||||
"Aliquam feugiat tellus ut neque.\r\n" +
|
||||
"Sed bibendum.\r\n" +
|
||||
"Nullam libero mauris, consequat.\r\n" +
|
||||
"\r\n" +
|
||||
"Integer placerat tristique nisl.\r\n" +
|
||||
"Etiam vel neque nec dui bibendum.\r\n" +
|
||||
"\r\n" +
|
||||
"\r\n" +
|
||||
"Nullam libero mauris, dictum id, arcu.\r\n",
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "multi-line separated by CR",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("Aliquam feugiat tellus ut neque."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte("Sed bibendum."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Content: []byte("Nullam libero mauris, consequat."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 6,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 7,
|
||||
Content: []byte("Integer placerat tristique nisl."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 8,
|
||||
Content: []byte("Etiam vel neque nec dui bibendum."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 9,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 10,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 11,
|
||||
Content: []byte("Nullam libero mauris, dictum id, arcu."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 12,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []byte(
|
||||
"Aliquam feugiat tellus ut neque.\r" +
|
||||
"Sed bibendum.\r" +
|
||||
"Nullam libero mauris, consequat.\r" +
|
||||
"\r" +
|
||||
"Integer placerat tristique nisl.\r" +
|
||||
"Etiam vel neque nec dui bibendum.\r" +
|
||||
"\r" +
|
||||
"\r" +
|
||||
"Nullam libero mauris, dictum id, arcu.\r",
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
func TestLines_Bytes(t *testing.T) {
|
||||
for _, tt := range linesBytesTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.lines.Bytes()
|
||||
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLines_Bytes(b *testing.B) {
|
||||
for _, tt := range linesBytesTestCases {
|
||||
b.Run(tt.name, func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = tt.lines.Bytes()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLines_String(t *testing.T) {
|
||||
for _, tt := range linesBytesTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.lines.String()
|
||||
|
||||
assert.Equal(t, string(tt.want), got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLines_String(b *testing.B) {
|
||||
for _, tt := range linesBytesTestCases {
|
||||
b.Run(tt.name, func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = tt.lines.String()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
30
paragraph.go
Normal file
30
paragraph.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package conventionalcommit
|
||||
|
||||
import "bytes"
|
||||
|
||||
// Paragraph represents a textual paragraph defined as; A continuous sequence of
|
||||
// textual lines which are not empty or and do not consist of only whitespace.
|
||||
type Paragraph struct {
|
||||
// Lines is a list of lines which collectively form a paragraph.
|
||||
Lines Lines
|
||||
}
|
||||
|
||||
func NewParagraphs(lines Lines) []*Paragraph {
|
||||
r := []*Paragraph{}
|
||||
|
||||
paragraph := &Paragraph{Lines: Lines{}}
|
||||
for _, line := range lines {
|
||||
if len(bytes.TrimSpace(line.Content)) > 0 {
|
||||
paragraph.Lines = append(paragraph.Lines, line)
|
||||
} else if len(paragraph.Lines) > 0 {
|
||||
r = append(r, paragraph)
|
||||
paragraph = &Paragraph{Lines: Lines{}}
|
||||
}
|
||||
}
|
||||
|
||||
if len(paragraph.Lines) > 0 {
|
||||
r = append(r, paragraph)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
338
paragraph_test.go
Normal file
338
paragraph_test.go
Normal file
@@ -0,0 +1,338 @@
|
||||
package conventionalcommit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewParagraphs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
lines Lines
|
||||
want []*Paragraph
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
lines: nil,
|
||||
want: []*Paragraph{},
|
||||
},
|
||||
{
|
||||
name: "no lines",
|
||||
lines: Lines{},
|
||||
want: []*Paragraph{},
|
||||
},
|
||||
{
|
||||
name: "single empty line",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte{},
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []*Paragraph{},
|
||||
},
|
||||
{
|
||||
name: "multiple empty lines",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte{},
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte{},
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte{},
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []*Paragraph{},
|
||||
},
|
||||
{
|
||||
name: "single whitespace line",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("\t "),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []*Paragraph{},
|
||||
},
|
||||
{
|
||||
name: "multiple whitespace lines",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte{},
|
||||
Break: []byte("\t "),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte{},
|
||||
Break: []byte("\t "),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("\t "),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []*Paragraph{},
|
||||
},
|
||||
{
|
||||
name: "single line",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo bar"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo bar"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple lines with trailing line break",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo bar"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("hello world"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("foo bar"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple paragraphs with excess blank lines",
|
||||
lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte("\t "),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("Aliquam feugiat tellus ut neque."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte("Sed bibendum."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Content: []byte("Nullam libero mauris, consequat."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 6,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 7,
|
||||
Content: []byte("Integer placerat tristique nisl."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 8,
|
||||
Content: []byte("Etiam vel neque nec dui bibendum."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 9,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 10,
|
||||
Content: []byte(" "),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 11,
|
||||
Content: []byte("\t\t"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 12,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 13,
|
||||
Content: []byte("Donec hendrerit tempor tellus."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 14,
|
||||
Content: []byte("In id erat non orci commodo lobortis."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 15,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 16,
|
||||
Content: []byte(" "),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 17,
|
||||
Content: []byte("\t\t"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 18,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 18,
|
||||
Content: []byte(""),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
want: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("Aliquam feugiat tellus ut neque."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte("Sed bibendum."),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Content: []byte("Nullam libero mauris, consequat."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 7,
|
||||
Content: []byte("Integer placerat tristique nisl."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 8,
|
||||
Content: []byte(
|
||||
"Etiam vel neque nec dui bibendum.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 13,
|
||||
Content: []byte("Donec hendrerit tempor tellus."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 14,
|
||||
Content: []byte(
|
||||
"In id erat non orci commodo lobortis.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := NewParagraphs(tt.lines)
|
||||
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
50
raw_message.go
Normal file
50
raw_message.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package conventionalcommit
|
||||
|
||||
// RawMessage represents a commit message in a more structured form than a
|
||||
// simple string or byte slice. This makes it easier to process a message for
|
||||
// the purposes of extracting detailed information, linting, and formatting.
|
||||
type RawMessage struct {
|
||||
// Lines is a list of all individual lines of text in the commit message,
|
||||
// which also includes the original line number, making it easy to pass a
|
||||
// single Line around while still knowing where in the original commit
|
||||
// message it belongs.
|
||||
Lines Lines
|
||||
|
||||
// Paragraphs is a list of textual paragraphs in the commit message. A
|
||||
// paragraph is defined as any continuous sequence of lines which are not
|
||||
// empty or consist of only whitespace.
|
||||
Paragraphs []*Paragraph
|
||||
}
|
||||
|
||||
// NewRawMessage returns a RawMessage, with the given commit message broken down
|
||||
// into individual lines of text, with sequential non-empty lines grouped into
|
||||
// paragraphs.
|
||||
func NewRawMessage(message []byte) *RawMessage {
|
||||
r := &RawMessage{
|
||||
Lines: Lines{},
|
||||
Paragraphs: []*Paragraph{},
|
||||
}
|
||||
|
||||
if len(message) == 0 {
|
||||
return r
|
||||
}
|
||||
|
||||
r.Lines = NewLines(message)
|
||||
r.Paragraphs = NewParagraphs(r.Lines)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Bytes renders the RawMessage back into a byte slice which is identical to the
|
||||
// original input byte slice given to NewRawMessage. This includes retaining the
|
||||
// original line break types for each line.
|
||||
func (s *RawMessage) Bytes() []byte {
|
||||
return s.Lines.Bytes()
|
||||
}
|
||||
|
||||
// String renders the RawMessage back into a string which is identical to the
|
||||
// original input byte slice given to NewRawMessage. This includes retaining the
|
||||
// original line break types for each line.
|
||||
func (s *RawMessage) String() string {
|
||||
return s.Lines.String()
|
||||
}
|
||||
641
raw_message_test.go
Normal file
641
raw_message_test.go
Normal file
@@ -0,0 +1,641 @@
|
||||
package conventionalcommit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var rawMessageTestCases = []struct {
|
||||
name string
|
||||
bytes []byte
|
||||
rawMessage *RawMessage
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
bytes: nil,
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{},
|
||||
Paragraphs: []*Paragraph{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
bytes: []byte(""),
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{},
|
||||
Paragraphs: []*Paragraph{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single space",
|
||||
bytes: []byte(" "),
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte(" "),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
Paragraphs: []*Paragraph{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "subject only",
|
||||
bytes: []byte("fix: a broken thing"),
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
Paragraphs: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "subject and body",
|
||||
bytes: []byte("fix: a broken thing\n\nIt is now fixed."),
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("It is now fixed."),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
Paragraphs: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("It is now fixed."),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "subject and body with CRLF line breaks",
|
||||
bytes: []byte("fix: a broken thing\r\n\r\nIt is now fixed."),
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("It is now fixed."),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
Paragraphs: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte("\r\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("It is now fixed."),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "subject and body with CR line breaks",
|
||||
bytes: []byte("fix: a broken thing\r\rIt is now fixed."),
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("It is now fixed."),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
Paragraphs: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte("\r"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("It is now fixed."),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "separated by whitespace line",
|
||||
bytes: []byte("fix: a broken thing\n \nIt is now fixed."),
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(" "),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("It is now fixed."),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
Paragraphs: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: a broken thing"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte("It is now fixed."),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "subject and long body",
|
||||
bytes: []byte(`fix: something broken
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec hendrerit
|
||||
tempor tellus. Donec pretium posuere tellus. Proin quam nisl, tincidunt et,
|
||||
mattis eget, convallis nec, purus. Cum sociis natoque penatibus et magnis dis
|
||||
parturient montes, nascetur ridiculous mus. Nulla posuere. Donec vitae dolor.
|
||||
Nullam tristique diam non turpis. Cras placerat accumsan nulla. Nullam rutrum.
|
||||
Nam vestibulum accumsan nisl.
|
||||
|
||||
Nullam eu ante vel est convallis dignissim. Fusce suscipit, wisi nec facilisis
|
||||
facilisis, est dui fermentum leo, quis tempor ligula erat quis odio. Nunc porta
|
||||
vulputate tellus. Nunc rutrum turpis sed pede. Sed bibendum. Aliquam posuere.
|
||||
Nunc aliquet, augue nec adipiscing interdum, lacus tellus malesuada massa, quis
|
||||
varius mi purus non odio. Pellentesque condimentum, magna ut suscipit hendrerit,
|
||||
ipsum augue ornare nulla, non luctus diam neque sit amet urna. Curabitur
|
||||
vulputate vestibulum lorem. Fusce sagittis, libero non molestie mollis, magna
|
||||
orci ultrices dolor, at vulputate neque nulla lacinia eros. Sed id ligula quis
|
||||
est convallis tempor. Curabitur lacinia pulvinar nibh. Nam a sapien.
|
||||
|
||||
Phasellus lacus. Nam euismod tellus id erat.`),
|
||||
rawMessage: &RawMessage{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: something broken"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 2,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte(
|
||||
"Lorem ipsum dolor sit amet, consectetuer " +
|
||||
"adipiscing elit. Donec hendrerit"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte(
|
||||
"tempor tellus. Donec pretium posuere tellus. " +
|
||||
"Proin quam nisl, tincidunt et,"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Content: []byte(
|
||||
"mattis eget, convallis nec, purus. Cum sociis " +
|
||||
"natoque penatibus et magnis dis"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 6,
|
||||
Content: []byte(
|
||||
"parturient montes, nascetur ridiculous mus. " +
|
||||
"Nulla posuere. Donec vitae dolor."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 7,
|
||||
Content: []byte(
|
||||
"Nullam tristique diam non turpis. Cras placerat " +
|
||||
"accumsan nulla. Nullam rutrum."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 8,
|
||||
Content: []byte(
|
||||
"Nam vestibulum accumsan nisl."),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 9,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 10,
|
||||
Content: []byte(
|
||||
"Nullam eu ante vel est convallis dignissim. " +
|
||||
"Fusce suscipit, wisi nec facilisis",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 11,
|
||||
Content: []byte(
|
||||
"facilisis, est dui fermentum leo, quis tempor " +
|
||||
"ligula erat quis odio. Nunc porta",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 12,
|
||||
Content: []byte(
|
||||
"vulputate tellus. Nunc rutrum turpis sed pede. " +
|
||||
"Sed bibendum. Aliquam posuere.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 13,
|
||||
Content: []byte(
|
||||
"Nunc aliquet, augue nec adipiscing interdum, " +
|
||||
"lacus tellus malesuada massa, quis",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 14,
|
||||
Content: []byte(
|
||||
"varius mi purus non odio. Pellentesque " +
|
||||
"condimentum, magna ut suscipit hendrerit,",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 15,
|
||||
Content: []byte(
|
||||
"ipsum augue ornare nulla, non luctus diam neque " +
|
||||
"sit amet urna. Curabitur",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 16,
|
||||
Content: []byte(
|
||||
"vulputate vestibulum lorem. Fusce sagittis, " +
|
||||
"libero non molestie mollis, magna",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 17,
|
||||
Content: []byte(
|
||||
"orci ultrices dolor, at vulputate neque nulla " +
|
||||
"lacinia eros. Sed id ligula quis",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 18,
|
||||
Content: []byte(
|
||||
"est convallis tempor. Curabitur lacinia " +
|
||||
"pulvinar nibh. Nam a sapien.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 19,
|
||||
Content: []byte(""),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 20,
|
||||
Content: []byte(
|
||||
"Phasellus lacus. Nam euismod tellus id erat.",
|
||||
),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
Paragraphs: []*Paragraph{
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 1,
|
||||
Content: []byte("fix: something broken"),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 3,
|
||||
Content: []byte(
|
||||
"Lorem ipsum dolor sit amet, " +
|
||||
"consectetuer adipiscing elit. Donec " +
|
||||
"hendrerit",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 4,
|
||||
Content: []byte(
|
||||
"tempor tellus. Donec pretium posuere " +
|
||||
"tellus. Proin quam nisl, tincidunt " +
|
||||
"et,",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 5,
|
||||
Content: []byte(
|
||||
"mattis eget, convallis nec, purus. Cum " +
|
||||
"sociis natoque penatibus et magnis " +
|
||||
"dis",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 6,
|
||||
Content: []byte(
|
||||
"parturient montes, nascetur ridiculous " +
|
||||
"mus. Nulla posuere. Donec vitae " +
|
||||
"dolor.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 7,
|
||||
Content: []byte(
|
||||
"Nullam tristique diam non turpis. Cras " +
|
||||
"placerat accumsan nulla. Nullam " +
|
||||
"rutrum.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 8,
|
||||
Content: []byte(
|
||||
"Nam vestibulum accumsan nisl.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 10,
|
||||
Content: []byte(
|
||||
"Nullam eu ante vel est convallis " +
|
||||
"dignissim. Fusce suscipit, wisi nec " +
|
||||
"facilisis",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 11,
|
||||
Content: []byte(
|
||||
"facilisis, est dui fermentum leo, quis " +
|
||||
"tempor ligula erat quis odio. Nunc " +
|
||||
"porta",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 12,
|
||||
Content: []byte(
|
||||
"vulputate tellus. Nunc rutrum turpis " +
|
||||
"sed pede. Sed bibendum. Aliquam " +
|
||||
"posuere.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 13,
|
||||
Content: []byte(
|
||||
"Nunc aliquet, augue nec adipiscing " +
|
||||
"interdum, lacus tellus malesuada " +
|
||||
"massa, quis",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 14,
|
||||
Content: []byte(
|
||||
"varius mi purus non odio. Pellentesque " +
|
||||
"condimentum, magna ut suscipit " +
|
||||
"hendrerit,",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 15,
|
||||
Content: []byte(
|
||||
"ipsum augue ornare nulla, non luctus " +
|
||||
"diam neque sit amet urna. Curabitur",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 16,
|
||||
Content: []byte(
|
||||
"vulputate vestibulum lorem. Fusce " +
|
||||
"sagittis, libero non molestie " +
|
||||
"mollis, magna",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 17,
|
||||
Content: []byte(
|
||||
"orci ultrices dolor, at vulputate neque " +
|
||||
"nulla lacinia eros. Sed id ligula " +
|
||||
"quis",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
{
|
||||
Number: 18,
|
||||
Content: []byte(
|
||||
"est convallis tempor. Curabitur lacinia " +
|
||||
"pulvinar nibh. Nam a sapien.",
|
||||
),
|
||||
Break: []byte("\n"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Lines: Lines{
|
||||
{
|
||||
Number: 20,
|
||||
Content: []byte(
|
||||
"Phasellus lacus. Nam euismod tellus id " +
|
||||
"erat.",
|
||||
),
|
||||
Break: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestNewRawMessage(t *testing.T) {
|
||||
for _, tt := range rawMessageTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := NewRawMessage(tt.bytes)
|
||||
|
||||
assert.Equal(t, tt.rawMessage, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewRawMessage(b *testing.B) {
|
||||
for _, tt := range rawMessageTestCases {
|
||||
b.Run(tt.name, func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = NewRawMessage(tt.bytes)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawMessage_Bytes(t *testing.T) {
|
||||
for _, tt := range rawMessageTestCases {
|
||||
if tt.bytes == nil {
|
||||
continue
|
||||
}
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.rawMessage.Bytes()
|
||||
|
||||
assert.Equal(t, tt.bytes, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRawMessage_Bytes(b *testing.B) {
|
||||
for _, tt := range rawMessageTestCases {
|
||||
if tt.bytes == nil {
|
||||
continue
|
||||
}
|
||||
b.Run(tt.name, func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = tt.rawMessage.Bytes()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawMessage_String(t *testing.T) {
|
||||
for _, tt := range rawMessageTestCases {
|
||||
if tt.bytes == nil {
|
||||
continue
|
||||
}
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.rawMessage.String()
|
||||
|
||||
assert.Equal(t, string(tt.bytes), got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRawMessage_String(b *testing.B) {
|
||||
for _, tt := range rawMessageTestCases {
|
||||
if tt.bytes == nil {
|
||||
continue
|
||||
}
|
||||
b.Run(tt.name, func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = tt.rawMessage.String()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user