mirror of
https://github.com/jimeh/undent.git
synced 2026-02-19 11:56:39 +00:00
feat(undent): add initial implementation of String, Stringf, and Bytes
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/*.tidy-check
|
||||||
|
/bin/*
|
||||||
|
/coverage.out
|
||||||
|
/output.txt
|
||||||
78
.golangci.yml
Normal file
78
.golangci.yml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
linters-settings:
|
||||||
|
funlen:
|
||||||
|
lines: 100
|
||||||
|
statements: 150
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 20
|
||||||
|
golint:
|
||||||
|
min-confidence: 0
|
||||||
|
govet:
|
||||||
|
check-shadowing: true
|
||||||
|
enable-all: true
|
||||||
|
lll:
|
||||||
|
line-length: 80
|
||||||
|
tab-width: 4
|
||||||
|
maligned:
|
||||||
|
suggest-new: true
|
||||||
|
misspell:
|
||||||
|
locale: US
|
||||||
|
|
||||||
|
linters:
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- bodyclose
|
||||||
|
- deadcode
|
||||||
|
- depguard
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- funlen
|
||||||
|
- gochecknoinits
|
||||||
|
- goconst
|
||||||
|
- gocritic
|
||||||
|
- gocyclo
|
||||||
|
- goerr113
|
||||||
|
- goimports
|
||||||
|
- golint
|
||||||
|
- goprintffuncname
|
||||||
|
- gosec
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- lll
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- nlreturn
|
||||||
|
- noctx
|
||||||
|
- nolintlint
|
||||||
|
- scopelint
|
||||||
|
- sqlclosecheck
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unused
|
||||||
|
- varcheck
|
||||||
|
- whitespace
|
||||||
|
|
||||||
|
issues:
|
||||||
|
include:
|
||||||
|
# - EXC0002 # disable excluding of issues about comments from golint
|
||||||
|
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
|
||||||
|
- source: "^//go:generate "
|
||||||
|
linters:
|
||||||
|
- lll
|
||||||
|
- source: "`json:"
|
||||||
|
linters:
|
||||||
|
- lll
|
||||||
|
|
||||||
|
run:
|
||||||
|
timeout: 2m
|
||||||
|
allow-parallel-runners: true
|
||||||
|
modules-download-mode: readonly
|
||||||
20
LICENSE
Normal file
20
LICENSE
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2020 Jim Myhrberg
|
||||||
|
|
||||||
|
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.
|
||||||
165
Makefile
Normal file
165
Makefile
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
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
|
||||||
|
gobin: $(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)
|
||||||
|
|
||||||
|
.PHONY: $(1)
|
||||||
|
$(1): $(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.31))
|
||||||
|
|
||||||
|
.PHONY: tools
|
||||||
|
tools: $(TOOLS)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Development
|
||||||
|
#
|
||||||
|
|
||||||
|
TEST ?= $$(go list ./... | grep -v 'vendor')
|
||||||
|
BENCH ?= .
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(TOOLS)
|
||||||
|
rm -f ./coverage.out ./go.mod.tidy-check ./go.sum.tidy-check
|
||||||
|
|
||||||
|
.PHONY: clean-golden
|
||||||
|
clean-golden:
|
||||||
|
rm -f $(shell find * -path '*/testdata/*' -name "*.golden" \
|
||||||
|
-exec echo "'{}'" \;)
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
go test $(V) -count=1 -race $(TESTARGS) $(TEST)
|
||||||
|
|
||||||
|
.PHONY: test-update-golden
|
||||||
|
test-update-golden:
|
||||||
|
@$(MAKE) test UPDATE_GOLDEN=1
|
||||||
|
|
||||||
|
.PHONY: regen-golden
|
||||||
|
regen-golden: clean-golden test-update-golden
|
||||||
|
|
||||||
|
.PHONY: test-deps
|
||||||
|
test-deps:
|
||||||
|
go test all
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: golangci-lint
|
||||||
|
GOGC=off golangci-lint $(V) run
|
||||||
|
|
||||||
|
.PHONY: format
|
||||||
|
format: gofumports
|
||||||
|
gofumports -w .
|
||||||
|
|
||||||
|
.SILENT: bench
|
||||||
|
.PHONY: bench
|
||||||
|
bench:
|
||||||
|
go test $(V) -count=1 -bench=$(BENCH) $(TESTARGS) $(TEST)
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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:
|
||||||
|
$(info Downloading dependencies)
|
||||||
|
go mod download
|
||||||
|
|
||||||
|
.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
|
||||||
|
@godoc -http=127.0.0.1:6060
|
||||||
19
README.md
19
README.md
@@ -1 +1,20 @@
|
|||||||
# undent
|
# undent
|
||||||
|
|
||||||
|
|
||||||
|
Go package which removes leading indentation/white-space from multi-line strings
|
||||||
|
and byte slices.
|
||||||
|
|
||||||
|
```go
|
||||||
|
s := undent.String(`
|
||||||
|
{
|
||||||
|
"hello": "world"
|
||||||
|
}`,
|
||||||
|
)
|
||||||
|
fmt.Println(s)
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"hello": "world"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
5
go.mod
Normal file
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module github.com/jimeh/undent
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.6.1
|
||||||
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.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
|
github.com/stretchr/testify v1.6.1/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=
|
||||||
73
undent.go
Normal file
73
undent.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// Package undent removes leading indentation/white-space from strings and byte
|
||||||
|
// slices.
|
||||||
|
package undent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var matcher = regexp.MustCompile(`(?m)^([ \t]*)(?:\S)`)
|
||||||
|
|
||||||
|
// Bytes removes leading indentation/white-space from given byte slice.
|
||||||
|
func Bytes(b []byte) []byte {
|
||||||
|
matches := matcher.FindAll(b, -1)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
index := 0
|
||||||
|
length := len(matches[0])
|
||||||
|
|
||||||
|
for i, s := range matches[1:] {
|
||||||
|
l := len(s)
|
||||||
|
if l < length {
|
||||||
|
index = i + 1
|
||||||
|
length = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if length <= 1 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
indent := matches[index][0 : length-1]
|
||||||
|
|
||||||
|
return regexp.MustCompile(
|
||||||
|
`(?m)^`+regexp.QuoteMeta(string(indent)),
|
||||||
|
).ReplaceAllLiteral(b, []byte{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// String removes leading indentation/white-space from given string.
|
||||||
|
func String(s string) string {
|
||||||
|
matches := matcher.FindAllString(s, -1)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
index := 0
|
||||||
|
length := len(matches[0])
|
||||||
|
|
||||||
|
for i, s := range matches[1:] {
|
||||||
|
l := len(s)
|
||||||
|
if l < length {
|
||||||
|
index = i + 1
|
||||||
|
length = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if length <= 1 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
indent := matches[index][0 : length-1]
|
||||||
|
|
||||||
|
return regexp.MustCompile(
|
||||||
|
`(?m)^`+regexp.QuoteMeta(indent),
|
||||||
|
).ReplaceAllLiteralString(s, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stringf removes leading indentation/white-space from given format string
|
||||||
|
// before passing format and all additional arguments to fmt.Sprintf, returning
|
||||||
|
// the result.
|
||||||
|
func Stringf(format string, a ...interface{}) string {
|
||||||
|
return fmt.Sprintf(String(format), a...)
|
||||||
|
}
|
||||||
51
undent_example_test.go
Normal file
51
undent_example_test.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package undent_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jimeh/undent"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleBytes() {
|
||||||
|
b := undent.Bytes([]byte(`
|
||||||
|
{
|
||||||
|
"hello": "world"
|
||||||
|
}`,
|
||||||
|
))
|
||||||
|
|
||||||
|
fmt.Println(string(b))
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "hello": "world"
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleString() {
|
||||||
|
s := undent.String(`
|
||||||
|
{
|
||||||
|
"hello": "world"
|
||||||
|
}`,
|
||||||
|
)
|
||||||
|
fmt.Println(s)
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "hello": "world"
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleStringf() {
|
||||||
|
s := undent.Stringf(`
|
||||||
|
{
|
||||||
|
"hello": "%s"
|
||||||
|
}`,
|
||||||
|
"world",
|
||||||
|
)
|
||||||
|
fmt.Println(s)
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "hello": "world"
|
||||||
|
// }
|
||||||
|
}
|
||||||
386
undent_test.go
Normal file
386
undent_test.go
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
package undent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var stringTestCases = []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
s: "",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single-line",
|
||||||
|
s: "hello world",
|
||||||
|
want: "hello world",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single-line indented",
|
||||||
|
s: " hello world",
|
||||||
|
want: "hello world",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line space indented",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line tab indented",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line tab indented with tabs and spaces after indent",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line space indented with blank lines",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
|
||||||
|
"bar"
|
||||||
|
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
|
||||||
|
"bar"
|
||||||
|
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line tab indented with blank lines",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
|
||||||
|
"bar"
|
||||||
|
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
|
||||||
|
"bar"
|
||||||
|
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line space indented with random indentation",
|
||||||
|
s: `
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
foo
|
||||||
|
bar`,
|
||||||
|
want: `
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
foo
|
||||||
|
bar`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line tab indented with random indentation",
|
||||||
|
s: `
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
foo
|
||||||
|
bar`,
|
||||||
|
want: `
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
foo
|
||||||
|
bar`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var stringfTestCases = []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
a []interface{}
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
s: "",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single-line",
|
||||||
|
s: "hello %s, %d",
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: "hello world, 42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single-line indented",
|
||||||
|
s: " hello %s, %d",
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: "hello world, 42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "%s",
|
||||||
|
"foo": [
|
||||||
|
%d
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
42
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line space indented",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "%s",
|
||||||
|
"foo": [
|
||||||
|
%d
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
42
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line tab indented",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "%s",
|
||||||
|
"foo": [
|
||||||
|
%d
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
42
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line tab indented with tabs and spaces after indent",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "%s",
|
||||||
|
"foo": [
|
||||||
|
%d
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
42
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line space indented with blank lines",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "%s",
|
||||||
|
"foo": [
|
||||||
|
|
||||||
|
%d
|
||||||
|
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
|
||||||
|
42
|
||||||
|
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line tab indented with blank lines",
|
||||||
|
s: `
|
||||||
|
{
|
||||||
|
"hello": "%s",
|
||||||
|
"foo": [
|
||||||
|
|
||||||
|
%d
|
||||||
|
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: `
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"foo": [
|
||||||
|
|
||||||
|
42
|
||||||
|
|
||||||
|
]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line space indented with random indentation",
|
||||||
|
s: `
|
||||||
|
hello
|
||||||
|
%s
|
||||||
|
foo
|
||||||
|
%d`,
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: `
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
foo
|
||||||
|
42`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi-line tab indented with random indentation",
|
||||||
|
s: `
|
||||||
|
hello
|
||||||
|
%s
|
||||||
|
foo
|
||||||
|
%d`,
|
||||||
|
a: []interface{}{"world", 42},
|
||||||
|
want: `
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
foo
|
||||||
|
42`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBytes(t *testing.T) {
|
||||||
|
for _, tt := range stringTestCases {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := Bytes([]byte(tt.s))
|
||||||
|
|
||||||
|
assert.Equal(t, []byte(tt.want), got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestString(t *testing.T) {
|
||||||
|
for _, tt := range stringTestCases {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := String(tt.s)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringf(t *testing.T) {
|
||||||
|
for _, tt := range stringfTestCases {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := Stringf(tt.s, tt.a...)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkBytes(b *testing.B) {
|
||||||
|
for _, tt := range stringTestCases {
|
||||||
|
b.Run(tt.name, func(b *testing.B) {
|
||||||
|
input := []byte(tt.s)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Bytes(input)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkString(b *testing.B) {
|
||||||
|
for _, tt := range stringTestCases {
|
||||||
|
b.Run(tt.name, func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
String(tt.s)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user