Repository: segmentio/terraform-docs
Pull request #188 (2020-02-01 19:39:44)

Add TestSettings for cleaner required Settings in tests
### Prerequisites

Put an `x` into the box(es) that apply:

- [ ] This pull request fixes a bug.
- [ ] This pull request adds a feature.
- [x] This pull request enhances existing functionality.
- [ ] This pull request introduces breaking change.

For more information, see the [Contributing Guide](https://github.com/segmentio/terraform-docs/tree/master/CONTRIBUTING.md).

### Description

This PR adds a new struct `TestSettings` which is being used in test functions, and it replaces all the duplicate repetitive definitions of `print.Settings` into predefined builder functions.

For example:

```go
// we can use
settings := testutil.Settings().WithSections().With(&print.Settings{
	SortByName: true,
}).Build()


// instead of
settings := &print.Settings{
	SortByName:    true,
	EscapePipe:    true,
	ShowHeader:    true,
	ShowProviders: true,
	ShowInputs:    true,
	ShowOutputs:   true,
}
```

### Issues Resolved

List any existing issues this pull request resolves.

### Checklist

Put an `x` into all boxes that apply:

- [ ] I have read the [Contributing Guidelines](https://github.com/segmentio/terraform-docs/tree/master/CONTRIBUTING.md).

#### Tests

- [ ] I have added tests to cover my changes.
- [x] All tests pass when I run `make test`.

#### Documentation

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.

#### Code Style

- [ ] My code follows the code style of this project.



Patch:
diff --git a/Makefile b/Makefile
index c7205f4..7716a2e 100644
--- a/Makefile
+++ b/Makefile
@@ -33,11 +33,11 @@ GOBUILD     ?= CGO_ENABLED=0 $(GOCMD) build $(MODVENDOR) -ldflags $(GOLDFLAGS)
 GORUN       ?= GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOCMD) run $(MODVENDOR)
 
 # Binary versions
-GITCHGLOG_VERSION := 0.8.0
-GOLANGCI_VERSION  := v1.18.0
+GITCHGLOG_VERSION := 0.9.1
+GOLANGCI_VERSION  := v1.23.1
 
 .PHONY: all
-all: clean deps lint test build
+all: clean verify checkfmt lint test build
 
 #########################
 ## Development targets ##
diff --git a/go.mod b/go.mod
index 00b2a79..54c0504 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.13
 
 require (
 	github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7
+	github.com/imdario/mergo v0.3.8
 	github.com/spf13/cobra v0.0.5
 	github.com/stretchr/testify v1.4.0
 	mvdan.cc/xurls/v2 v2.1.0
diff --git a/go.sum b/go.sum
index b42c553..d07a7c3 100644
--- a/go.sum
+++ b/go.sum
@@ -27,6 +27,8 @@ github.com/hashicorp/hcl/v2 v2.0.0 h1:efQznTz+ydmQXq3BOnRa3AXzvCeTq1P4dKj/z5GLlY
 github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90=
 github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 h1:Pc5TCv9mbxFN6UVX0LH6CpQrdTM5YjbVI2w15237Pjk=
 github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A=
+github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -91,6 +93,5 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-mvdan.cc/xurls v1.1.0 h1:kj0j2lonKseISJCiq1Tfk+iTv65dDGCl0rTbanXJGGc=
 mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA=
 mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E=
diff --git a/vendor/github.com/imdario/mergo/.gitignore b/vendor/github.com/imdario/mergo/.gitignore
new file mode 100644
index 0000000..529c341
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/.gitignore
@@ -0,0 +1,33 @@
+#### joe made this: http://goel.io/joe
+
+#### go ####
+# Binaries for programs and plugins
+*.exe
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
+.glide/
+
+#### vim ####
+# Swap
+[._]*.s[a-v][a-z]
+[._]*.sw[a-p]
+[._]s[a-v][a-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+
+# Temporary
+.netrwhist
+*~
+# Auto-generated tag files
+tags
diff --git a/vendor/github.com/imdario/mergo/.travis.yml b/vendor/github.com/imdario/mergo/.travis.yml
new file mode 100644
index 0000000..dad2972
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+install:
+  - go get -t
+  - go get golang.org/x/tools/cmd/cover
+  - go get github.com/mattn/goveralls
+script:
+  - go test -race -v ./...
+after_script:
+  - $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN
diff --git a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..469b449
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/vendor/github.com/imdario/mergo/LICENSE b/vendor/github.com/imdario/mergo/LICENSE
new file mode 100644
index 0000000..6866802
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2013 Dario Castañé. All rights reserved.
+Copyright (c) 2012 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md
new file mode 100644
index 0000000..02fc81e
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/README.md
@@ -0,0 +1,238 @@
+# Mergo
+
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
+
+Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
+
+## Status
+
+It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
+
+[![GoDoc][3]][4]
+[![GoCard][5]][6]
+[![Build Status][1]][2]
+[![Coverage Status][7]][8]
+[![Sourcegraph][9]][10]
+[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield)
+
+[1]: https://travis-ci.org/imdario/mergo.png
+[2]: https://travis-ci.org/imdario/mergo
+[3]: https://godoc.org/github.com/imdario/mergo?status.svg
+[4]: https://godoc.org/github.com/imdario/mergo
+[5]: https://goreportcard.com/badge/imdario/mergo
+[6]: https://goreportcard.com/report/github.com/imdario/mergo
+[7]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
+[8]: https://coveralls.io/github/imdario/mergo?branch=master
+[9]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
+[10]: https://sourcegraph.com/github.com/imdario/mergo?badge
+
+### Latest release
+
+[Release v0.3.7](https://github.com/imdario/mergo/releases/tag/v0.3.7).
+
+### Important note
+
+Please keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code.
+
+If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0).
+
+### Donations
+
+If Mergo is useful to you, consider buying me a coffee, a beer or making a monthly donation so I can keep building great free software. :heart_eyes:
+
+<a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
+[![Beerpay](https://beerpay.io/imdario/mergo/badge.svg)](https://beerpay.io/imdario/mergo)
+[![Beerpay](https://beerpay.io/imdario/mergo/make-wish.svg)](https://beerpay.io/imdario/mergo)
+<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
+
+### Mergo in the wild
+
+- [moby/moby](https://github.com/moby/moby)
+- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
+- [vmware/dispatch](https://github.com/vmware/dispatch)
+- [Shopify/themekit](https://github.com/Shopify/themekit)
+- [imdario/zas](https://github.com/imdario/zas)
+- [matcornic/hermes](https://github.com/matcornic/hermes)
+- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go)
+- [kataras/iris](https://github.com/kataras/iris)
+- [michaelsauter/crane](https://github.com/michaelsauter/crane)
+- [go-task/task](https://github.com/go-task/task)
+- [sensu/uchiwa](https://github.com/sensu/uchiwa)
+- [ory/hydra](https://github.com/ory/hydra)
+- [sisatech/vcli](https://github.com/sisatech/vcli)
+- [dairycart/dairycart](https://github.com/dairycart/dairycart)
+- [projectcalico/felix](https://github.com/projectcalico/felix)
+- [resin-os/balena](https://github.com/resin-os/balena)
+- [go-kivik/kivik](https://github.com/go-kivik/kivik)
+- [Telefonica/govice](https://github.com/Telefonica/govice)
+- [supergiant/supergiant](supergiant/supergiant)
+- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce)
+- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
+- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel)
+- [EagerIO/Stout](https://github.com/EagerIO/Stout)
+- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
+- [russross/canvasassignments](https://github.com/russross/canvasassignments)
+- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
+- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
+- [divshot/gitling](https://github.com/divshot/gitling)
+- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
+- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
+- [elwinar/rambler](https://github.com/elwinar/rambler)
+- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
+- [jfbus/impressionist](https://github.com/jfbus/impressionist)
+- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
+- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
+- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
+- [thoas/picfit](https://github.com/thoas/picfit)
+- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
+- [jnuthong/item_search](https://github.com/jnuthong/item_search)
+- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
+
+## Installation
+
+    go get github.com/imdario/mergo
+
+    // use in your .go code
+    import (
+        "github.com/imdario/mergo"
+    )
+
+## Usage
+
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are not considered zero values](https://golang.org/ref/spec#The_zero_value) either. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+
+```go
+if err := mergo.Merge(&dst, src); err != nil {
+    // ...
+}
+```
+
+Also, you can merge overwriting values using the transformer `WithOverride`.
+
+```go
+if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
+    // ...
+}
+```
+
+Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
+
+```go
+if err := mergo.Map(&dst, srcMap); err != nil {
+    // ...
+}
+```
+
+Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values.
+
+More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo).
+
+### Nice example
+
+```go
+package main
+
+import (
+	"fmt"
+	"github.com/imdario/mergo"
+)
+
+type Foo struct {
+	A string
+	B int64
+}
+
+func main() {
+	src := Foo{
+		A: "one",
+		B: 2,
+	}
+	dest := Foo{
+		A: "two",
+	}
+	mergo.Merge(&dest, src)
+	fmt.Println(dest)
+	// Will print
+	// {two 2}
+}
+```
+
+Note: if test are failing due missing package, please execute:
+
+    go get gopkg.in/yaml.v2
+
+### Transformers
+
+Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`?
+
+```go
+package main
+
+import (
+	"fmt"
+	"github.com/imdario/mergo"
+        "reflect"
+        "time"
+)
+
+type timeTransfomer struct {
+}
+
+func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+	if typ == reflect.TypeOf(time.Time{}) {
+		return func(dst, src reflect.Value) error {
+			if dst.CanSet() {
+				isZero := dst.MethodByName("IsZero")
+				result := isZero.Call([]reflect.Value{})
+				if result[0].Bool() {
+					dst.Set(src)
+				}
+			}
+			return nil
+		}
+	}
+	return nil
+}
+
+type Snapshot struct {
+	Time time.Time
+	// ...
+}
+
+func main() {
+	src := Snapshot{time.Now()}
+	dest := Snapshot{}
+	mergo.Merge(&dest, src, mergo.WithTransformers(timeTransfomer{}))
+	fmt.Println(dest)
+	// Will print
+	// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
+}
+```
+
+
+## Contact me
+
+If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
+
+## About
+
+Written by [Dario Castañé](http://dario.im).
+
+## Top Contributors
+
+[![0](https://sourcerer.io/fame/imdario/imdario/mergo/images/0)](https://sourcerer.io/fame/imdario/imdario/mergo/links/0)
+[![1](https://sourcerer.io/fame/imdario/imdario/mergo/images/1)](https://sourcerer.io/fame/imdario/imdario/mergo/links/1)
+[![2](https://sourcerer.io/fame/imdario/imdario/mergo/images/2)](https://sourcerer.io/fame/imdario/imdario/mergo/links/2)
+[![3](https://sourcerer.io/fame/imdario/imdario/mergo/images/3)](https://sourcerer.io/fame/imdario/imdario/mergo/links/3)
+[![4](https://sourcerer.io/fame/imdario/imdario/mergo/images/4)](https://sourcerer.io/fame/imdario/imdario/mergo/links/4)
+[![5](https://sourcerer.io/fame/imdario/imdario/mergo/images/5)](https://sourcerer.io/fame/imdario/imdario/mergo/links/5)
+[![6](https://sourcerer.io/fame/imdario/imdario/mergo/images/6)](https://sourcerer.io/fame/imdario/imdario/mergo/links/6)
+[![7](https://sourcerer.io/fame/imdario/imdario/mergo/images/7)](https://sourcerer.io/fame/imdario/imdario/mergo/links/7)
+
+
+## License
+
+[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
+
+
+[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_large)
diff --git a/vendor/github.com/imdario/mergo/doc.go b/vendor/github.com/imdario/mergo/doc.go
new file mode 100644
index 0000000..6e9aa7b
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/doc.go
@@ -0,0 +1,44 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package mergo merges same-type structs and maps by setting default values in zero-value fields.
+
+Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+Usage
+
+From my own work-in-progress project:
+
+	type networkConfig struct {
+		Protocol string
+		Address string
+		ServerType string `json: "server_type"`
+		Port uint16
+	}
+
+	type FssnConfig struct {
+		Network networkConfig
+	}
+
+	var fssnDefault = FssnConfig {
+		networkConfig {
+			"tcp",
+			"127.0.0.1",
+			"http",
+			31560,
+		},
+	}
+
+	// Inside a function [...]
+
+	if err := mergo.Merge(&config, fssnDefault); err != nil {
+		log.Fatal(err)
+	}
+
+	// More code [...]
+
+*/
+package mergo
diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/github.com/imdario/mergo/map.go
new file mode 100644
index 0000000..3f5afa8
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/map.go
@@ -0,0 +1,175 @@
+// Copyright 2014 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+	"fmt"
+	"reflect"
+	"unicode"
+	"unicode/utf8"
+)
+
+func changeInitialCase(s string, mapper func(rune) rune) string {
+	if s == "" {
+		return s
+	}
+	r, n := utf8.DecodeRuneInString(s)
+	return string(mapper(r)) + s[n:]
+}
+
+func isExported(field reflect.StructField) bool {
+	r, _ := utf8.DecodeRuneInString(field.Name)
+	return r >= 'A' && r <= 'Z'
+}
+
+// Traverses recursively both values, assigning src's fields values to dst.
+// The map argument tracks comparisons that have already been seen, which allows
+// short circuiting on recursive types.
+func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
+	overwrite := config.Overwrite
+	if dst.CanAddr() {
+		addr := dst.UnsafeAddr()
+		h := 17 * addr
+		seen := visited[h]
+		typ := dst.Type()
+		for p := seen; p != nil; p = p.next {
+			if p.ptr == addr && p.typ == typ {
+				return nil
+			}
+		}
+		// Remember, remember...
+		visited[h] = &visit{addr, typ, seen}
+	}
+	zeroValue := reflect.Value{}
+	switch dst.Kind() {
+	case reflect.Map:
+		dstMap := dst.Interface().(map[string]interface{})
+		for i, n := 0, src.NumField(); i < n; i++ {
+			srcType := src.Type()
+			field := srcType.Field(i)
+			if !isExported(field) {
+				continue
+			}
+			fieldName := field.Name
+			fieldName = changeInitialCase(fieldName, unicode.ToLower)
+			if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
+				dstMap[fieldName] = src.Field(i).Interface()
+			}
+		}
+	case reflect.Ptr:
+		if dst.IsNil() {
+			v := reflect.New(dst.Type().Elem())
+			dst.Set(v)
+		}
+		dst = dst.Elem()
+		fallthrough
+	case reflect.Struct:
+		srcMap := src.Interface().(map[string]interface{})
+		for key := range srcMap {
+			config.overwriteWithEmptyValue = true
+			srcValue := srcMap[key]
+			fieldName := changeInitialCase(key, unicode.ToUpper)
+			dstElement := dst.FieldByName(fieldName)
+			if dstElement == zeroValue {
+				// We discard it because the field doesn't exist.
+				continue
+			}
+			srcElement := reflect.ValueOf(srcValue)
+			dstKind := dstElement.Kind()
+			srcKind := srcElement.Kind()
+			if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
+				srcElement = srcElement.Elem()
+				srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
+			} else if dstKind == reflect.Ptr {
+				// Can this work? I guess it can't.
+				if srcKind != reflect.Ptr && srcElement.CanAddr() {
+					srcPtr := srcElement.Addr()
+					srcElement = reflect.ValueOf(srcPtr)
+					srcKind = reflect.Ptr
+				}
+			}
+
+			if !srcElement.IsValid() {
+				continue
+			}
+			if srcKind == dstKind {
+				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+					return
+				}
+			} else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
+				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+					return
+				}
+			} else if srcKind == reflect.Map {
+				if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
+					return
+				}
+			} else {
+				return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
+			}
+		}
+	}
+	return
+}
+
+// Map sets fields' values in dst from src.
+// src can be a map with string keys or a struct. dst must be the opposite:
+// if src is a map, dst must be a valid pointer to struct. If src is a struct,
+// dst must be map[string]interface{}.
+// It won't merge unexported (private) fields and will do recursively
+// any exported field.
+// If dst is a map, keys will be src fields' names in lower camel case.
+// Missing key in src that doesn't match a field in dst will be skipped. This
+// doesn't apply if dst is a map.
+// This is separated method from Merge because it is cleaner and it keeps sane
+// semantics: merging equal types, mapping different (restricted) types.
+func Map(dst, src interface{}, opts ...func(*Config)) error {
+	return _map(dst, src, opts...)
+}
+
+// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
+// non-empty src attribute values.
+// Deprecated: Use Map(…) with WithOverride
+func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
+	return _map(dst, src, append(opts, WithOverride)...)
+}
+
+func _map(dst, src interface{}, opts ...func(*Config)) error {
+	var (
+		vDst, vSrc reflect.Value
+		err        error
+	)
+	config := &Config{}
+
+	for _, opt := range opts {
+		opt(config)
+	}
+
+	if vDst, vSrc, err = resolveValues(dst, src); err != nil {
+		return err
+	}
+	// To be friction-less, we redirect equal-type arguments
+	// to deepMerge. Only because arguments can be anything.
+	if vSrc.Kind() == vDst.Kind() {
+		return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+	}
+	switch vSrc.Kind() {
+	case reflect.Struct:
+		if vDst.Kind() != reflect.Map {
+			return ErrExpectedMapAsDestination
+		}
+	case reflect.Map:
+		if vDst.Kind() != reflect.Struct {
+			return ErrExpectedStructAsDestination
+		}
+	default:
+		return ErrNotSupported
+	}
+	return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+}
diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/github.com/imdario/mergo/merge.go
new file mode 100644
index 0000000..3fb6c64
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/merge.go
@@ -0,0 +1,283 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+	"fmt"
+	"reflect"
+)
+
+func hasExportedField(dst reflect.Value) (exported bool) {
+	for i, n := 0, dst.NumField(); i < n; i++ {
+		field := dst.Type().Field(i)
+		if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
+			exported = exported || hasExportedField(dst.Field(i))
+		} else {
+			exported = exported || len(field.PkgPath) == 0
+		}
+	}
+	return
+}
+
+type Config struct {
+	Overwrite                    bool
+	AppendSlice                  bool
+	TypeCheck                    bool
+	Transformers                 Transformers
+	overwriteWithEmptyValue      bool
+	overwriteSliceWithEmptyValue bool
+}
+
+type Transformers interface {
+	Transformer(reflect.Type) func(dst, src reflect.Value) error
+}
+
+// Traverses recursively both values, assigning src's fields values to dst.
+// The map argument tracks comparisons that have already been seen, which allows
+// short circuiting on recursive types.
+func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
+	overwrite := config.Overwrite
+	typeCheck := config.TypeCheck
+	overwriteWithEmptySrc := config.overwriteWithEmptyValue
+	overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
+	config.overwriteWithEmptyValue = false
+
+	if !src.IsValid() {
+		return
+	}
+	if dst.CanAddr() {
+		addr := dst.UnsafeAddr()
+		h := 17 * addr
+		seen := visited[h]
+		typ := dst.Type()
+		for p := seen; p != nil; p = p.next {
+			if p.ptr == addr && p.typ == typ {
+				return nil
+			}
+		}
+		// Remember, remember...
+		visited[h] = &visit{addr, typ, seen}
+	}
+
+	if config.Transformers != nil && !isEmptyValue(dst) {
+		if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
+			err = fn(dst, src)
+			return
+		}
+	}
+
+	switch dst.Kind() {
+	case reflect.Struct:
+		if hasExportedField(dst) {
+			for i, n := 0, dst.NumField(); i < n; i++ {
+				if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
+					return
+				}
+			}
+		} else {
+			if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
+				dst.Set(src)
+			}
+		}
+	case reflect.Map:
+		if dst.IsNil() && !src.IsNil() {
+			dst.Set(reflect.MakeMap(dst.Type()))
+		}
+		for _, key := range src.MapKeys() {
+			srcElement := src.MapIndex(key)
+			if !srcElement.IsValid() {
+				continue
+			}
+			dstElement := dst.MapIndex(key)
+			switch srcElement.Kind() {
+			case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
+				if srcElement.IsNil() {
+					continue
+				}
+				fallthrough
+			default:
+				if !srcElement.CanInterface() {
+					continue
+				}
+				switch reflect.TypeOf(srcElement.Interface()).Kind() {
+				case reflect.Struct:
+					fallthrough
+				case reflect.Ptr:
+					fallthrough
+				case reflect.Map:
+					srcMapElm := srcElement
+					dstMapElm := dstElement
+					if srcMapElm.CanInterface() {
+						srcMapElm = reflect.ValueOf(srcMapElm.Interface())
+						if dstMapElm.IsValid() {
+							dstMapElm = reflect.ValueOf(dstMapElm.Interface())
+						}
+					}
+					if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
+						return
+					}
+				case reflect.Slice:
+					srcSlice := reflect.ValueOf(srcElement.Interface())
+
+					var dstSlice reflect.Value
+					if !dstElement.IsValid() || dstElement.IsNil() {
+						dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
+					} else {
+						dstSlice = reflect.ValueOf(dstElement.Interface())
+					}
+
+					if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
+						if typeCheck && srcSlice.Type() != dstSlice.Type() {
+							return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+						}
+						dstSlice = srcSlice
+					} else if config.AppendSlice {
+						if srcSlice.Type() != dstSlice.Type() {
+							return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+						}
+						dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
+					}
+					dst.SetMapIndex(key, dstSlice)
+				}
+			}
+			if dstElement.IsValid() && !isEmptyValue(dstElement) && (reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map || reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice) {
+				continue
+			}
+
+			if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement)) {
+				if dst.IsNil() {
+					dst.Set(reflect.MakeMap(dst.Type()))
+				}
+				dst.SetMapIndex(key, srcElement)
+			}
+		}
+	case reflect.Slice:
+		if !dst.CanSet() {
+			break
+		}
+		if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
+			dst.Set(src)
+		} else if config.AppendSlice {
+			if src.Type() != dst.Type() {
+				return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
+			}
+			dst.Set(reflect.AppendSlice(dst, src))
+		}
+	case reflect.Ptr:
+		fallthrough
+	case reflect.Interface:
+		if src.IsNil() {
+			break
+		}
+
+		if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
+			if dst.IsNil() || overwrite {
+				if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
+					dst.Set(src)
+				}
+			}
+			break
+		}
+
+		if src.Kind() != reflect.Interface {
+			if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
+				if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
+					dst.Set(src)
+				}
+			} else if src.Kind() == reflect.Ptr {
+				if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+					return
+				}
+			} else if dst.Elem().Type() == src.Type() {
+				if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
+					return
+				}
+			} else {
+				return ErrDifferentArgumentsTypes
+			}
+			break
+		}
+		if dst.IsNil() || overwrite {
+			if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
+				dst.Set(src)
+			}
+		} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+			return
+		}
+	default:
+		if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) {
+			dst.Set(src)
+		}
+	}
+
+	return
+}
+
+// Merge will fill any empty for value type attributes on the dst struct using corresponding
+// src attributes if they themselves are not empty. dst and src must be valid same-type structs
+// and dst must be a pointer to struct.
+// It won't merge unexported (private) fields and will do recursively any exported field.
+func Merge(dst, src interface{}, opts ...func(*Config)) error {
+	return merge(dst, src, opts...)
+}
+
+// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
+// non-empty src attribute values.
+// Deprecated: use Merge(…) with WithOverride
+func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
+	return merge(dst, src, append(opts, WithOverride)...)
+}
+
+// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
+func WithTransformers(transformers Transformers) func(*Config) {
+	return func(config *Config) {
+		config.Transformers = transformers
+	}
+}
+
+// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
+func WithOverride(config *Config) {
+	config.Overwrite = true
+}
+
+// WithOverride will make merge override empty dst slice with empty src slice.
+func WithOverrideEmptySlice(config *Config) {
+	config.overwriteSliceWithEmptyValue = true
+}
+
+// WithAppendSlice will make merge append slices instead of overwriting it.
+func WithAppendSlice(config *Config) {
+	config.AppendSlice = true
+}
+
+// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
+func WithTypeCheck(config *Config) {
+	config.TypeCheck = true
+}
+
+func merge(dst, src interface{}, opts ...func(*Config)) error {
+	var (
+		vDst, vSrc reflect.Value
+		err        error
+	)
+
+	config := &Config{}
+
+	for _, opt := range opts {
+		opt(config)
+	}
+
+	if vDst, vSrc, err = resolveValues(dst, src); err != nil {
+		return err
+	}
+	if vDst.Type() != vSrc.Type() {
+		return ErrDifferentArgumentsTypes
+	}
+	return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+}
diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/github.com/imdario/mergo/mergo.go
new file mode 100644
index 0000000..a82fea2
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/mergo.go
@@ -0,0 +1,97 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+	"errors"
+	"reflect"
+)
+
+// Errors reported by Mergo when it finds invalid arguments.
+var (
+	ErrNilArguments                = errors.New("src and dst must not be nil")
+	ErrDifferentArgumentsTypes     = errors.New("src and dst must be of same type")
+	ErrNotSupported                = errors.New("only structs and maps are supported")
+	ErrExpectedMapAsDestination    = errors.New("dst was expected to be a map")
+	ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
+)
+
+// During deepMerge, must keep track of checks that are
+// in progress.  The comparison algorithm assumes that all
+// checks in progress are true when it reencounters them.
+// Visited are stored in a map indexed by 17 * a1 + a2;
+type visit struct {
+	ptr  uintptr
+	typ  reflect.Type
+	next *visit
+}
+
+// From src/pkg/encoding/json/encode.go.
+func isEmptyValue(v reflect.Value) bool {
+	switch v.Kind() {
+	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+		return v.Len() == 0
+	case reflect.Bool:
+		return !v.Bool()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+	case reflect.Float32, reflect.Float64:
+		return v.Float() == 0
+	case reflect.Interface, reflect.Ptr:
+		if v.IsNil() {
+			return true
+		}
+		return isEmptyValue(v.Elem())
+	case reflect.Func:
+		return v.IsNil()
+	case reflect.Invalid:
+		return true
+	}
+	return false
+}
+
+func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
+	if dst == nil || src == nil {
+		err = ErrNilArguments
+		return
+	}
+	vDst = reflect.ValueOf(dst).Elem()
+	if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
+		err = ErrNotSupported
+		return
+	}
+	vSrc = reflect.ValueOf(src)
+	// We check if vSrc is a pointer to dereference it.
+	if vSrc.Kind() == reflect.Ptr {
+		vSrc = vSrc.Elem()
+	}
+	return
+}
+
+// Traverses recursively both values, assigning src's fields values to dst.
+// The map argument tracks comparisons that have already been seen, which allows
+// short circuiting on recursive types.
+func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
+	if dst.CanAddr() {
+		addr := dst.UnsafeAddr()
+		h := 17 * addr
+		seen := visited[h]
+		typ := dst.Type()
+		for p := seen; p != nil; p = p.next {
+			if p.ptr == addr && p.typ == typ {
+				return nil
+			}
+		}
+		// Remember, remember...
+		visited[h] = &visit{addr, typ, seen}
+	}
+	return // TODO refactor
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 9a2a469..c3f5d43 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -29,6 +29,8 @@ github.com/hashicorp/hcl/v2/hclwrite
 github.com/hashicorp/hcl/v2/json
 # github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7
 github.com/hashicorp/terraform-config-inspect/tfconfig
+# github.com/imdario/mergo v0.3.8
+github.com/imdario/mergo
 # github.com/inconshreveable/mousetrap v1.0.0
 github.com/inconshreveable/mousetrap
 # github.com/mitchellh/go-wordwrap v1.0.0


Test patch:
diff --git a/internal/pkg/print/json/json_test.go b/internal/pkg/print/json/json_test.go
index 217bc07..da8b822 100644
--- a/internal/pkg/print/json/json_test.go
+++ b/internal/pkg/print/json/json_test.go
@@ -10,13 +10,7 @@ import (
 
 func TestJson(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-	}
+	settings := testutil.Settings().WithSections().Build()
 
 	module, expected, err := testutil.GetExpected("json")
 	assert.Nil(err)
@@ -29,14 +23,9 @@ func TestJson(t *testing.T) {
 
 func TestJsonSortByName(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		SortByName:    true,
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-	}
+	settings := testutil.Settings().WithSections().With(&print.Settings{
+		SortByName: true,
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-SortByName")
 	assert.Nil(err)
@@ -49,15 +38,10 @@ func TestJsonSortByName(t *testing.T) {
 
 func TestJsonSortByRequired(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		SortByName:     true,
 		SortByRequired: true,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-SortByRequired")
 	assert.Nil(err)
@@ -70,13 +54,12 @@ func TestJsonSortByRequired(t *testing.T) {
 
 func TestJsonNoHeader(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: true,
 		ShowInputs:    true,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-NoHeader")
 	assert.Nil(err)
@@ -89,13 +72,12 @@ func TestJsonNoHeader(t *testing.T) {
 
 func TestJsonNoProviders(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: false,
 		ShowInputs:    true,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-NoProviders")
 	assert.Nil(err)
@@ -108,13 +90,12 @@ func TestJsonNoProviders(t *testing.T) {
 
 func TestJsonNoInputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: true,
 		ShowInputs:    false,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-NoInputs")
 	assert.Nil(err)
@@ -127,13 +108,12 @@ func TestJsonNoInputs(t *testing.T) {
 
 func TestJsonNoOutputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: true,
 		ShowInputs:    true,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-NoOutputs")
 	assert.Nil(err)
@@ -146,13 +126,12 @@ func TestJsonNoOutputs(t *testing.T) {
 
 func TestJsonOnlyHeader(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: false,
 		ShowInputs:    false,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-OnlyHeader")
 	assert.Nil(err)
@@ -165,13 +144,12 @@ func TestJsonOnlyHeader(t *testing.T) {
 
 func TestJsonOnlyProviders(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: true,
 		ShowInputs:    false,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-OnlyProviders")
 	assert.Nil(err)
@@ -184,13 +162,12 @@ func TestJsonOnlyProviders(t *testing.T) {
 
 func TestJsonOnlyInputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: false,
 		ShowInputs:    true,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-OnlyInputs")
 	assert.Nil(err)
@@ -203,13 +180,12 @@ func TestJsonOnlyInputs(t *testing.T) {
 
 func TestJsonOnlyOutputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: false,
 		ShowInputs:    false,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-OnlyOutputs")
 	assert.Nil(err)
@@ -222,14 +198,9 @@ func TestJsonOnlyOutputs(t *testing.T) {
 
 func TestJsonEscapeCharacters(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		EscapeCharacters: true,
-		EscapePipe:       true,
-		ShowHeader:       true,
-		ShowProviders:    true,
-		ShowInputs:       true,
-		ShowOutputs:      true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("json-EscapeCharacters")
 	assert.Nil(err)
diff --git a/internal/pkg/print/markdown/document/document_test.go b/internal/pkg/print/markdown/document/document_test.go
index 3f6e1d0..ee0d741 100644
--- a/internal/pkg/print/markdown/document/document_test.go
+++ b/internal/pkg/print/markdown/document/document_test.go
@@ -10,13 +10,7 @@ import (
 
 func TestDocument(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-	}
+	settings := testutil.Settings().WithSections().Build()
 
 	module, expected, err := testutil.GetExpected("document")
 	assert.Nil(err)
@@ -29,14 +23,9 @@ func TestDocument(t *testing.T) {
 
 func TestDocumentWithRequired(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowRequired:  true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-	}
+	settings := testutil.Settings().WithSections().With(&print.Settings{
+		ShowRequired: true,
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-WithRequired")
 	assert.Nil(err)
@@ -49,14 +38,9 @@ func TestDocumentWithRequired(t *testing.T) {
 
 func TestDocumentSortByName(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		SortByName:    true,
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-	}
+	settings := testutil.Settings().WithSections().With(&print.Settings{
+		SortByName: true,
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-SortByName")
 	assert.Nil(err)
@@ -69,15 +53,10 @@ func TestDocumentSortByName(t *testing.T) {
 
 func TestDocumentSortByRequired(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		SortByName:     true,
 		SortByRequired: true,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-SortByRequired")
 	assert.Nil(err)
@@ -90,13 +69,12 @@ func TestDocumentSortByRequired(t *testing.T) {
 
 func TestDocumentNoHeader(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: true,
 		ShowInputs:    true,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-NoHeader")
 	assert.Nil(err)
@@ -109,13 +87,12 @@ func TestDocumentNoHeader(t *testing.T) {
 
 func TestDocumentNoProviders(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: false,
 		ShowInputs:    true,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-NoProviders")
 	assert.Nil(err)
@@ -128,13 +105,12 @@ func TestDocumentNoProviders(t *testing.T) {
 
 func TestDocumentNoInputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: true,
 		ShowInputs:    false,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-NoInputs")
 	assert.Nil(err)
@@ -147,13 +123,12 @@ func TestDocumentNoInputs(t *testing.T) {
 
 func TestDocumentNoOutputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: true,
 		ShowInputs:    true,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-NoOutputs")
 	assert.Nil(err)
@@ -166,13 +141,12 @@ func TestDocumentNoOutputs(t *testing.T) {
 
 func TestDocumentOnlyHeader(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: false,
 		ShowInputs:    false,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-OnlyHeader")
 	assert.Nil(err)
@@ -185,13 +159,12 @@ func TestDocumentOnlyHeader(t *testing.T) {
 
 func TestDocumentOnlyProviders(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: true,
 		ShowInputs:    false,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-OnlyProviders")
 	assert.Nil(err)
@@ -204,13 +177,12 @@ func TestDocumentOnlyProviders(t *testing.T) {
 
 func TestDocumentOnlyInputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: false,
 		ShowInputs:    true,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-OnlyInputs")
 	assert.Nil(err)
@@ -223,13 +195,12 @@ func TestDocumentOnlyInputs(t *testing.T) {
 
 func TestDocumentOnlyOutputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: false,
 		ShowInputs:    false,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-OnlyOutputs")
 	assert.Nil(err)
@@ -242,14 +213,9 @@ func TestDocumentOnlyOutputs(t *testing.T) {
 
 func TestDocumentEscapeCharacters(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		EscapeCharacters: true,
-		EscapePipe:       true,
-		ShowHeader:       true,
-		ShowProviders:    true,
-		ShowInputs:       true,
-		ShowOutputs:      true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-EscapeCharacters")
 	assert.Nil(err)
@@ -262,14 +228,9 @@ func TestDocumentEscapeCharacters(t *testing.T) {
 
 func TestDocumentIndentationBellowAllowed(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		MarkdownIndent: 0,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-IndentationBellowAllowed")
 	assert.Nil(err)
@@ -282,14 +243,9 @@ func TestDocumentIndentationBellowAllowed(t *testing.T) {
 
 func TestDocumentIndentationAboveAllowed(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		MarkdownIndent: 10,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-IndentationAboveAllowed")
 	assert.Nil(err)
@@ -302,14 +258,9 @@ func TestDocumentIndentationAboveAllowed(t *testing.T) {
 
 func TestDocumentIndentationOfFour(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		MarkdownIndent: 4,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("document-IndentationOfFour")
 	assert.Nil(err)
diff --git a/internal/pkg/print/markdown/table/table_test.go b/internal/pkg/print/markdown/table/table_test.go
index 963d9d6..818628f 100644
--- a/internal/pkg/print/markdown/table/table_test.go
+++ b/internal/pkg/print/markdown/table/table_test.go
@@ -10,13 +10,7 @@ import (
 
 func TestTable(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-	}
+	settings := testutil.Settings().WithSections().Build()
 
 	module, expected, err := testutil.GetExpected("table")
 	assert.Nil(err)
@@ -29,14 +23,9 @@ func TestTable(t *testing.T) {
 
 func TestTableWithRequired(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		ShowRequired:  true,
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-	}
+	settings := testutil.Settings().WithSections().With(&print.Settings{
+		ShowRequired: true,
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-WithRequired")
 	assert.Nil(err)
@@ -49,14 +38,9 @@ func TestTableWithRequired(t *testing.T) {
 
 func TestTableSortByName(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		SortByName:    true,
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-	}
+	settings := testutil.Settings().WithSections().With(&print.Settings{
+		SortByName: true,
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-SortByName")
 	assert.Nil(err)
@@ -69,15 +53,10 @@ func TestTableSortByName(t *testing.T) {
 
 func TestTableSortByRequired(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		SortByName:     true,
 		SortByRequired: true,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-SortByRequired")
 	assert.Nil(err)
@@ -90,13 +69,12 @@ func TestTableSortByRequired(t *testing.T) {
 
 func TestTableNoHeader(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: true,
 		ShowInputs:    true,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-NoHeader")
 	assert.Nil(err)
@@ -109,13 +87,12 @@ func TestTableNoHeader(t *testing.T) {
 
 func TestTableNoProviders(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: false,
 		ShowInputs:    true,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-NoProviders")
 	assert.Nil(err)
@@ -128,13 +105,12 @@ func TestTableNoProviders(t *testing.T) {
 
 func TestTableNoInputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: true,
 		ShowInputs:    false,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-NoInputs")
 	assert.Nil(err)
@@ -147,13 +123,12 @@ func TestTableNoInputs(t *testing.T) {
 
 func TestTableNoOutputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: true,
 		ShowInputs:    true,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-NoOutputs")
 	assert.Nil(err)
@@ -166,13 +141,12 @@ func TestTableNoOutputs(t *testing.T) {
 
 func TestTableOnlyHeader(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: false,
 		ShowInputs:    false,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-OnlyHeader")
 	assert.Nil(err)
@@ -185,13 +159,12 @@ func TestTableOnlyHeader(t *testing.T) {
 
 func TestTableOnlyProviders(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: true,
 		ShowInputs:    false,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-OnlyProviders")
 	assert.Nil(err)
@@ -204,13 +177,12 @@ func TestTableOnlyProviders(t *testing.T) {
 
 func TestTableOnlyInputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: false,
 		ShowInputs:    true,
 		ShowOutputs:   false,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-OnlyInputs")
 	assert.Nil(err)
@@ -223,13 +195,12 @@ func TestTableOnlyInputs(t *testing.T) {
 
 func TestTableOnlyOutputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: false,
 		ShowInputs:    false,
 		ShowOutputs:   true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-OnlyOutputs")
 	assert.Nil(err)
@@ -242,14 +213,9 @@ func TestTableOnlyOutputs(t *testing.T) {
 
 func TestTableEscapeCharacters(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		EscapeCharacters: true,
-		EscapePipe:       true,
-		ShowHeader:       true,
-		ShowProviders:    true,
-		ShowInputs:       true,
-		ShowOutputs:      true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-EscapeCharacters")
 	assert.Nil(err)
@@ -262,14 +228,9 @@ func TestTableEscapeCharacters(t *testing.T) {
 
 func TestTableIndentationBellowAllowed(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		MarkdownIndent: 0,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-IndentationBellowAllowed")
 	assert.Nil(err)
@@ -282,14 +243,9 @@ func TestTableIndentationBellowAllowed(t *testing.T) {
 
 func TestTableIndentationAboveAllowed(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		MarkdownIndent: 10,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-IndentationAboveAllowed")
 	assert.Nil(err)
@@ -302,14 +258,9 @@ func TestTableIndentationAboveAllowed(t *testing.T) {
 
 func TestTableIndentationOfFour(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().With(&print.Settings{
 		MarkdownIndent: 4,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("table-IndentationOfFour")
 	assert.Nil(err)
diff --git a/internal/pkg/print/pretty/pretty_test.go b/internal/pkg/print/pretty/pretty_test.go
index 7ff5873..998ccb1 100644
--- a/internal/pkg/print/pretty/pretty_test.go
+++ b/internal/pkg/print/pretty/pretty_test.go
@@ -10,14 +10,7 @@ import (
 
 func TestPretty(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-		ShowColor:     true,
-	}
+	settings := testutil.Settings().WithSections().WithColor().Build()
 
 	module, expected, err := testutil.GetExpected("pretty")
 	assert.Nil(err)
@@ -30,15 +23,9 @@ func TestPretty(t *testing.T) {
 
 func TestPrettySortByName(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		SortByName:    true,
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-		ShowColor:     true,
-	}
+	settings := testutil.Settings().WithSections().WithColor().With(&print.Settings{
+		SortByName: true,
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-SortByName")
 	assert.Nil(err)
@@ -51,16 +38,10 @@ func TestPrettySortByName(t *testing.T) {
 
 func TestPrettySortByRequired(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
+	settings := testutil.Settings().WithSections().WithColor().With(&print.Settings{
 		SortByName:     true,
 		SortByRequired: true,
-		EscapePipe:     true,
-		ShowHeader:     true,
-		ShowProviders:  true,
-		ShowInputs:     true,
-		ShowOutputs:    true,
-		ShowColor:      true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-SortByRequired")
 	assert.Nil(err)
@@ -73,14 +54,12 @@ func TestPrettySortByRequired(t *testing.T) {
 
 func TestPrettyNoHeader(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().WithColor().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: true,
 		ShowInputs:    true,
 		ShowOutputs:   true,
-		ShowColor:     true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-NoHeader")
 	assert.Nil(err)
@@ -93,14 +72,12 @@ func TestPrettyNoHeader(t *testing.T) {
 
 func TestPrettyNoProviders(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().WithColor().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: false,
 		ShowInputs:    true,
 		ShowOutputs:   true,
-		ShowColor:     true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-NoProviders")
 	assert.Nil(err)
@@ -113,14 +90,12 @@ func TestPrettyNoProviders(t *testing.T) {
 
 func TestPrettyNoInputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().WithColor().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: true,
 		ShowInputs:    false,
 		ShowOutputs:   true,
-		ShowColor:     true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-NoInputs")
 	assert.Nil(err)
@@ -133,14 +108,12 @@ func TestPrettyNoInputs(t *testing.T) {
 
 func TestPrettyNoOutputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().WithColor().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: true,
 		ShowInputs:    true,
 		ShowOutputs:   false,
-		ShowColor:     true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-NoOutputs")
 	assert.Nil(err)
@@ -153,14 +126,12 @@ func TestPrettyNoOutputs(t *testing.T) {
 
 func TestPrettyOnlyHeader(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().WithColor().With(&print.Settings{
 		ShowHeader:    true,
 		ShowProviders: false,
 		ShowInputs:    false,
 		ShowOutputs:   false,
-		ShowColor:     true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-OnlyHeader")
 	assert.Nil(err)
@@ -173,14 +144,12 @@ func TestPrettyOnlyHeader(t *testing.T) {
 
 func TestPrettyOnlyProviders(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().WithColor().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: true,
 		ShowInputs:    false,
 		ShowOutputs:   false,
-		ShowColor:     true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-OnlyProviders")
 	assert.Nil(err)
@@ -193,14 +162,12 @@ func TestPrettyOnlyProviders(t *testing.T) {
 
 func TestPrettyOnlyInputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().WithColor().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: false,
 		ShowInputs:    true,
 		ShowOutputs:   false,
-		ShowColor:     true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-OnlyInputs")
 	assert.Nil(err)
@@ -213,14 +180,12 @@ func TestPrettyOnlyInputs(t *testing.T) {
 
 func TestPrettyOnlyOutputs(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
+	settings := testutil.Settings().WithColor().With(&print.Settings{
 		ShowHeader:    false,
 		ShowProviders: false,
 		ShowInputs:    false,
 		ShowOutputs:   true,
-		ShowColor:     true,
-	}
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-OnlyOutputs")
 	assert.Nil(err)
@@ -233,14 +198,9 @@ func TestPrettyOnlyOutputs(t *testing.T) {
 
 func TestPrettyNoColor(t *testing.T) {
 	assert := assert.New(t)
-	settings := &print.Settings{
-		EscapePipe:    true,
-		ShowHeader:    true,
-		ShowProviders: true,
-		ShowInputs:    true,
-		ShowOutputs:   true,
-		ShowColor:     false,
-	}
+	settings := testutil.Settings().WithSections().With(&print.Settings{
+		ShowColor: false,
+	}).Build()
 
 	module, expected, err := testutil.GetExpected("pretty-NoColor")
 	assert.Nil(err)
diff --git a/internal/pkg/testutil/settings.go b/internal/pkg/testutil/settings.go
new file mode 100644
index 0000000..1838cf1
--- /dev/null
+++ b/internal/pkg/testutil/settings.go
@@ -0,0 +1,59 @@
+package testutil
+
+import (
+	"github.com/imdario/mergo"
+	"github.com/segmentio/terraform-docs/internal/pkg/print"
+)
+
+// TestSettings respresents the Settings instance for tests
+type TestSettings struct {
+	full *print.Settings
+}
+
+// Settings returns TestSettings instance with predefined set of print.Settings
+func Settings() *TestSettings {
+	shared := &print.Settings{
+		EscapePipe: true,
+	}
+	return &TestSettings{
+		full: shared,
+	}
+}
+
+// With appends provided 'override' print.Settings to TestSettings
+func (s *TestSettings) With(override *print.Settings) *TestSettings {
+	if err := mergo.Merge(override, s.full); err == nil {
+		s.full = override
+	}
+	return s
+}
+
+// WithColor appends predefined 'ShowColor: true' to TestSettings
+func (s *TestSettings) WithColor() *TestSettings {
+	color := &print.Settings{
+		ShowColor: true,
+	}
+	if err := mergo.Merge(color, s.full); err == nil {
+		s.full = color
+	}
+	return s
+}
+
+// WithSections appends predefined show all sections ShowHeader, ShowProviders, ShowInputs, ShowOutputs to TestSettings
+func (s *TestSettings) WithSections() *TestSettings {
+	sections := &print.Settings{
+		ShowHeader:    true,
+		ShowProviders: true,
+		ShowInputs:    true,
+		ShowOutputs:   true,
+	}
+	if err := mergo.Merge(sections, s.full); err == nil {
+		s.full = sections
+	}
+	return s
+}
+
+// Build builds and returns print.Settings based on the provided overrides in TestSettings
+func (s *TestSettings) Build() *print.Settings {
+	return s.full
+}