Showing preview only (273K chars total). Download the full file or copy to clipboard to get everything.
Repository: ozontech/cute
Branch: master
Commit: 9f4583b9e8d9
Files: 72
Total size: 255.0 KB
Directory structure:
gitextract_fkbtdg57/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── main.yml
├── .gitignore
├── .golangci.yaml
├── LICENSE
├── Makefile
├── README.MD
├── allure.go
├── assert.go
├── assert_broken.go
├── assert_broken_test.go
├── assert_optional.go
├── assert_optional_test.go
├── assert_require.go
├── assert_require_test.go
├── assert_trace.go
├── asserts/
│ ├── headers/
│ │ ├── headers.go
│ │ └── headers_test.go
│ └── json/
│ ├── json.go
│ ├── json_test.go
│ └── util.go
├── builder.go
├── builder_allure.go
├── builder_asserts.go
├── builder_middleware.go
├── builder_option.go
├── builder_request.go
├── builder_retry.go
├── builder_table.go
├── builder_table_test.go
├── builder_test.go
├── cute.go
├── errors/
│ ├── broken.go
│ ├── error.go
│ ├── optional.go
│ ├── require.go
│ └── trace.go
├── examples/
│ ├── custom_asserts.go
│ ├── inside_step_test.go
│ ├── masked_data_test.go
│ ├── parallel_test.go
│ ├── single_test.go
│ ├── suite/
│ │ ├── common.go
│ │ ├── main_test.go
│ │ ├── one_step.go
│ │ ├── one_step_errors.go
│ │ ├── resources/
│ │ │ └── example_valid_request.json
│ │ ├── simple.go
│ │ └── two_steps.go
│ ├── table_test/
│ │ └── table_test.go
│ ├── two_step_test.go
│ └── upload_file_test.go
├── go.mod
├── go.sum
├── init.go
├── interface.go
├── internal/
│ └── utils/
│ ├── body.go
│ └── json.go
├── json_marshaler.go
├── jsonschema.go
├── jsonschema_test.go
├── logger.go
├── provider.go
├── request.go
├── request_test.go
├── result.go
├── result_test.go
├── roundtripper.go
├── step.go
├── test.go
└── test_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report \
about: Create a report to help us improve \
title: ' ' \
labels: ' ' \
assignees: ' '
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Used func: '...'
2. What you actually wanted to do: '...'
3. What has been expected: '...'
4. What you got actual: '....'
5. Error Log (if any): '...'
6. Allure-Report screenshot (if any): '...'
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request \
about: Suggest an idea for this project \
title: '' \
labels: '' \
assignees: ''
---
**Is your feature request related to a problem? Please describe.** \
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like** \
A clear and concise description of what you want to happen.
**Describe alternatives you've considered** \
A clear and concise description of any alternative solutions or features you've considered.
**Additional context** \
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build_and_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.21
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
golangci-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run golangci-lint
# You may pin to the exact commit or the version.
# uses: golangci/golangci-lint-action@5c56cd6c9dc07901af25baab6f2b0d9f3b7c3018
uses: golangci/golangci-lint-action@v2.5.2
# for settings see https://github.com/golangci/golangci-lint-action
with:
only-new-issues: true
# golangci-lint command line arguments
args: --timeout=5m0s
examples:
name: examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run examples
run: make examples
- name: Archive code coverage results
uses: actions/upload-artifact@v4
with:
name: allure-results
path: ./examples/allure-results
================================================
FILE: .gitignore
================================================
.idea/
testdata/
allure-results/
bin/
vendor/
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
================================================
FILE: .golangci.yaml
================================================
run:
timeout: 10m
issues-exit-code: 1
tests: true
skip-dirs:
- bin
- vendor
- var
- tmp
skip-files:
- \.pb\.go$
- \.pb\.goclay\.go$
output:
format: colored-line-number
print-issued-lines: true
print-linter-name: true
linters-settings:
govet:
check-shadowing: true
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
linters:
disable-all: true
enable:
- errcheck
- goconst
- goimports
- gosec
- govet
- ineffassign
- megacheck
- revive
- typecheck
- unused # will be used insted of varcheck + deadcode + structcheck. More info https://github.com/golangci/golangci-lint/issues/1841
- prealloc
- wsl
issues:
exclude-use-default: false
exclude:
# _ instead of err checks
- G104
# for "public interface + private struct implementation" cases only!
- exported func .* returns unexported type .*, which can be annoying to use
# can be removed in the development phase
# - (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form)
# not for the active development - can be removed in the stable phase
- should have a package comment
- don't use an underscore in package name
# EXC0001 errcheck: Almost all programs ignore errors on these functions and in most cases it's ok
- Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
- should check returned error before deferring
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
export GO111MODULE=on
export GOSUMDB=off
LOCAL_BIN:=$(CURDIR)/bin
##################### GOLANG-CI RELATED CHECKS #####################
# Check global GOLANGCI-LINT
GOLANGCI_BIN:=$(LOCAL_BIN)/golangci-lint
GOLANGCI_TAG:=1.54.2
# Check local bin version
ifneq ($(wildcard $(GOLANGCI_BIN)),)
GOLANGCI_BIN_VERSION:=$(shell $(GOLANGCI_BIN) --version)
ifneq ($(GOLANGCI_BIN_VERSION),)
GOLANGCI_BIN_VERSION_SHORT:=$(shell echo "$(GOLANGCI_BIN_VERSION)" | sed -E 's/.* version (.*) built from .* on .*/\1/g')
else
GOLANGCI_BIN_VERSION_SHORT:=0
endif
ifneq "$(GOLANGCI_TAG)" "$(word 1, $(sort $(GOLANGCI_TAG) $(GOLANGCI_BIN_VERSION_SHORT)))"
GOLANGCI_BIN:=
endif
endif
# Check global bin version
ifneq (, $(shell which golangci-lint))
GOLANGCI_VERSION:=$(shell golangci-lint --version 2> /dev/null )
ifneq ($(GOLANGCI_VERSION),)
GOLANGCI_VERSION_SHORT:=$(shell echo "$(GOLANGCI_VERSION)"|sed -E 's/.* version (.*) built from .* on .*/\1/g')
else
GOLANGCI_VERSION_SHORT:=0
endif
ifeq "$(GOLANGCI_TAG)" "$(word 1, $(sort $(GOLANGCI_TAG) $(GOLANGCI_VERSION_SHORT)))"
GOLANGCI_BIN:=$(shell which golangci-lint)
endif
endif
##################### GOLANG-CI RELATED CHECKS #####################
.PHONY: install
install:
go mod tidy && go mod download
# run full lint like in pipeline
.PHONY: lint
lint: install-lint
$(GOLANGCI_BIN) run --config=.golangci.yaml ./... --new-from-rev=origin/master --build-tags=examples,allure_go,provider
.PHONY: install-lint
install-lint:
ifeq ($(wildcard $(GOLANGCI_BIN)),)
$(info #Downloading golangci-lint v$(GOLANGCI_TAG))
tmp=$$(mktemp -d) && cd $$tmp && pwd && go mod init temp && go get -d github.com/golangci/golangci-lint/cmd/golangci-lint@v$(GOLANGCI_TAG) && \
go build -ldflags "-X 'main.version=$(GOLANGCI_TAG)' -X 'main.commit=test' -X 'main.date=test'" -o $(LOCAL_BIN)/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint && \
rm -rf $$tmp
GOLANGCI_BIN:=$(LOCAL_BIN)/golangci-lint
endif
.PHONY: cover
cover:
go test -v -coverprofile=coverage.out ./... && go tool cover -html=coverage.out
.PHONY: example
example:
go test ./... -tags example
.PHONY: test
test:
go test ./...
================================================
FILE: README.MD
================================================
<p align="center">
<img src=".images/cute.png" alt="cute"/>
</p>
# CUTE — create your tests easily
HTTP and REST API testing for Go using Allure reports.
## Features
- Expressive and intuitive syntax.
- Built-in JSON support.
- Custom asserts.
- One step to BDD.
- Allure reports.
---
## Head of contents
- [Features](#features)
- [Workflow](#workflow)
- [Installation](#installation)
- [Requirements](#requirements)
- [Demo](#demo)
- [Test examples](#test-examples)
- [Single test](#single-step-test)
- [Multi-step test](#multi-step-test)
- [Suite tests](#suite)
- [Table tests](#table-tests)
- [Asserts](#asserts)
- [Ready-made asserts](#ready-made-asserts)
- [JSON asserts](#json-asserts)
- [Headers asserts](#headers-asserts)
- [JSON schema](#json-schema-validations)
- [Custom asserts](#custom-asserts)
- [Base](#base)
- [T](#t)
- [Errors](#assert-errors)
- [Global Environment Keys](#global-environment-keys)
## Workflow
1. Create a request and write assets.
2. Run tests.
3. Check Allure reports.
## Installation
```bash
go get -u github.com/ozontech/cute
```
## Requirements
- Go 1.17+
## Demo
Run example.
```bash
make example
```
To view detailed test reports, install Allure framework. It's optional.
[Learn more about Allure reports](https://github.com/allure-framework)
```bash
brew install allure
```
Run Allure.
```bash
allure serve ./examples/allure-results
```
## Test examples
See [**Examples**](examples) directory for featured examples.
### <h3><a href="examples/single_test.go">Single-step test</a></h3>
Allows implementing single-request tests. See full example in the [**Examples**](examples) directory.
To view an Allure report, use `testing.T` or `provider.T` from [allure-go](https://github.com/ozontech/allure-go/tree/master?tab=readme-ov-file).
```go
import (
"context"
"net/http"
"path"
"testing"
"time"
"github.com/ozontech/cute"
"github.com/ozontech/cute/asserts/json"
)
func TestExample(t *testing.T) {
cute.NewTestBuilder().
Title("Title").
Description("some_description").
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusOK).
AssertBody(
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
).
ExecuteTest(context.Background(), t)
}
```
<details>
<summary>Allure report</summary>

</details>
### <h3><a href="examples/two_step_test.go">Multi-step test</a></h3>
Allows implementing several requests within one test.
```go
import (
"context"
"fmt"
"net/http"
"testing"
"github.com/ozontech/cute"
)
func Test_TwoSteps(t *testing.T) {
responseCode := 0
// First step
cute.NewTestBuilder().
Title("Test with two requests and parse body.").
Tag("two_steps").
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
).
ExpectStatus(http.StatusOK).
NextTest().
// Execute after first step and parse response code
AfterTestExecute(func(response *http.Response, errors []error) error {
responseCode = response.StatusCode
return nil
}).
// Second step
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/2/comments"),
cute.WithMethod(http.MethodDelete),
).
ExecuteTest(context.Background(), t)
fmt.Println("Response code from first request", responseCode)
}
```
See full in the [**Examples**](examples/two_step_test.go) directory.
<details>
<summary>Allure report</summary>

</details>
### <h3><a href="examples/suite">Suite</a></h3>
Suite provides a structure for describing tests by organizing them into test suites. It's helpful if you have a large number of different tests and find it difficult to browse through them without using additional layer nesting levels of test calls.
[Learn more about suite with Allure reports](https://github.com/ozontech/allure-go#suite)
1. Declare a structure with `suite.Suite` and `*cute.HTTPTestMaker`.
```go
import (
"github.com/ozontech/cute"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
)
type ExampleSuite struct {
suite.Suite
host *url.URL
testMaker *cute.HTTPTestMaker
}
func (i *ExampleSuite) BeforeAll(t provider.T) {
// Prepare http test builder
i.testMaker = cute.NewHTTPTestMaker()
// Preparing host
host, err := url.Parse("https://jsonplaceholder.typicode.com/")
if err != nil {
t.Fatalf("could not parse url, error %w", err)
}
i.host = host
}
```
2. Declare a test.
```go
import (
"github.com/ozontech/allure-go/pkg/framework/suite"
)
func TestExampleTest(t *testing.T) {
suite.RunSuite(t, new(ExampleSuite))
}
```
3. Describe tests.
```go
import (
"github.com/ozontech/cute"
"github.com/ozontech/cute/asserts/headers"
"github.com/ozontech/cute/asserts/json"
)
func (i *ExampleSuite) TestExample_OneStep(t provider.T) {
var (
testBuilder = i.testMaker.NewTestBuilder()
)
u, _ := url.Parse(i.host.String())
u.Path = path.Join(u.Path, "/posts/1/comments")
testBuilder.
Title("TestExample_OneStep").
Tags("one_step", "some_local_tag", "json").
Create().
StepName("Example GET json request").
RequestBuilder(
cute.WithHeaders(map[string][]string{
"some_header": []string{"something"},
"some_array_header": []string{"1", "2", "3", "some_thing"},
}),
cute.WithURL(u),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectJSONSchemaFile("file://./resources/example_valid_request.json").
ExpectStatus(http.StatusOK).
AssertBody(
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
json.NotPresent("$[1].some_not_present"),
json.GreaterThan("$", 3),
json.Length("$", 5),
json.LessThan("$", 100),
json.NotEqual("$[3].name", "kekekekeke"),
).
OptionalAssertBody(
json.GreaterThan("$", 3),
json.Length("$", 5),
json.LessThan("$", 100),
).
AssertHeaders(
headers.Present("Content-Type"),
).
ExecuteTest(context.Background(), t)
}
```
See full example in the [**Examples**](examples/suite) directory.
<details>
<summary>Allure report</summary>

</details>
## <h2><a href="examples/table_test/table_test.go">Table tests</a></h2>
You can create a table test in 2 ways. They'll have the same Allure reports.
### Builder table tests
```go
import (
"context"
"fmt"
"net/http"
"testing"
"github.com/ozontech/cute"
)
func Test_Table_Array(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_1",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodPost),
},
},
Expect: &cute.Expect{
Code: 200,
},
},
{
Name: "test_2",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 200,
AssertBody: []cute.AssertBody{
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
func(body []byte) error {
return errors.NewAssertError("example error", "example message", nil, nil)
},
},
},
},
}
cute.NewTestBuilder().
Title("Example table test").
Tag("table_test").
Description("Execute array tests").
CreateTableTest().
PutTests(tests...).
ExecuteTest(context.Background(), t)
}
```
### Array tests
```go
func Test_Execute_Array(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_1",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodPost),
},
},
Expect: &cute.Expect{
Code: 200,
},
},
{
Name: "test_2",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 200,
AssertBody: []cute.AssertBody{
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
func(body []byte) error {
return errors.NewAssertError("example error", "example message", nil, nil)
},
},
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
```
See full example in the [**Examples**](examples/table_test/table_test.go) directory.
<details>
<summary>Allure report</summary>
Common report for all table tests:

Main report:

</details>
<h2><a href="asserts">Asserts</a></h2>
You can create your own asserts or use ready-made from the package asserts.
### Ready-made asserts
#### <h4><a href="asserts/json">JSON asserts</a></h4>
- `Equal` is a function to assert that a JSONPath expression matches the given value.
- `NotEqual` is a function to check that a JSONPath expression value isn't equal to the given value.
- `Length` is a function to assert that value is the expected length.
- `GreaterThan` is a function to assert that value is greater than the given length.
- `GreaterOrEqualThan` is a function to assert that value is greater or equal to the given length.
- `LessThan` is a function to assert that value is less than the given length.
- `LessOrEqualThan` is a function to assert that value is less or equal to the given length.
- `Present` is a function to assert that value is present. Value can be 0 or null.
- `NotEmpty` is a function to assert that value is present and not empty. Value can't be 0 or null.
- `NotPresent` is a function to assert that value isn't present.
- `Diff` is a function to compare two JSONs.
- `Contains` is a function to assert that a JSONPath expression extracts a value in an array.
- `EqualJSON` is a function to check that a JSON path expression value is equal to given JSON.
- `NotEqualJSON` is a function to check that a JSONPath expression value isn't equal to given JSON.
- `GetValueFromJSON` is a function for getting a value from a JSON.
[Learn more about expressions](https://goessner.net/articles/JsonPath/)
[Learn more about asserts implementation](https://github.com/ozontech/cute/blob/master/asserts/json/json.go)
#### <h4><a href="asserts/headers">Headers asserts</a></h4>
- `Present` is a function to assert that header is present.
- `NotPresent` is a function to assert that header isn't present.
[Learn more about asserts implementation](asserts/headers/headers.go)
#### <h4><a href="jsonschema.go">JSON schema validations</a></h4>
You can validate a JSON schema in 3 ways. Choose a way depending on JSON schema location.
- `ExpectJSONSchemaString(string)` is a function for validating a JSON schema from a string.
- `ExpectJSONSchemaByte([]byte)` is a function for validating a JSON schema from an array of bytes.
- `ExpectJSONSchemaFile(string)` is a function for validating a JSON schema from a file or remote resource.
<details>
<summary>Allure report</summary>

</details>
### <h3><a href="assert.go">Custom asserts</a></h3>
You can implement [3 type of asserts](assert.go):
#### Base
Types for creating custom assertions.
```go
type AssertBody func(body []byte) error
type AssertHeaders func(headers http.Header) error
type AssertResponse func(response *http.Response) error
```
Example:
```go
func customAssertBody() cute.AssertBody {
return func(bytes []byte) error {
if len(bytes) == 0 {
return errors.New("response body is empty")
}
return nil
}
}
```
#### T
Used for creating custom asserts via [Allure Actions](https://github.com/ozontech/allure-go#suite) and [testing.TB](https://pkg.go.dev/testing#TB).
You can:
- log information to Allure,
- log error on Allure yourself,
- return an error.
```go
type AssertBodyT func(t cute.T, body []byte) error
type AssertHeadersT func(t cute.T, headers http.Header) error
type AssertResponseT func(t cute.T, response *http.Response) error
```
Example with T:
```go
func customAssertBodyT() cute.AssertBodyT {
return func(t cute.T, bytes []byte) error {
require.GreaterOrEqual(t, len(bytes), 100)
return nil
}
}
```
Example with creating steps:
```go
func customAssertBodySuite() cute.AssertBodyT {
return func(t cute.T, bytes []byte) error {
step := allure.NewSimpleStep("Custom assert step")
defer func() {
t.Step(step)
}()
if len(bytes) == 0 {
step.Status = allure.Failed
step.Attachment(allure.NewAttachment("Error", allure.Text, []byte("response body is empty")))
return nil
}
return nil
}
}
```
<details>
<summary>Allure report</summary>

</details>
#### <h4><a href="errors/error.go">Assert errors</a></h4>
You can use `errors.NewAssertError` method from [errors](errors/error.go) package.
Example:
```go
import (
"github.com/ozontech/cute"
"github.com/ozontech/cute/errors"
)
func customAssertBodyWithCustomError() cute.AssertBody {
return func(bytes []byte) error {
if len(bytes) == 0 {
return errors.NewAssertError("customAssertBodyWithCustomError", "body must be not empty", "len is 0", "len more 0")
}
return nil
}
}
```
To create a pretty-error in your custom assert, implement it with [interfaces](errors/error.go):
- Name.
```go
type WithNameError interface {
GetName() string
SetName(string)
}
```
- Parameters for Allure step.
```go
type WithFields interface {
GetFields() map[string]interface{}
PutFields(map[string]interface{})
}
```
<details>
<summary>Allure report</summary>

</details>
#### Optional assert
If assert returns an optional error, step fails but the test is successful.
You can use `errors.NewOptionalError(error)` method from [errors](errors/error.go) package.
```go
import (
"github.com/ozontech/cute"
"github.com/ozontech/cute/errors"
)
func customAssertBodyWithCustomError() cute.AssertBody {
return func(bytes []byte) error {
if len(bytes) == 0 {
return errors.NewOptionalError("body is empty")
}
return nil
}
}
```
To create optional error, implement error with interface:
```go
type OptionalError interface {
IsOptional() bool
SetOptional(bool)
}
```
<details>
<summary>Allure report</summary>

</details>
## <h2><a href="https://github.com/ozontech/allure-go?tab=readme-ov-file#wrench-configure-your-environment">Global Environment Keys</a></h2>
| Key | Meaning | Default |
|---|---------------------------------------------------------------|-------------------------|
|`ALLURE_OUTPUT_PATH`| Path to output allure results. | `.` (Folder with tests) |
|`ALLURE_OUTPUT_FOLDER`| Name of result folder. | `/allure-results` |
|`ALLURE_ISSUE_PATTERN`| Url pattepn to issue. Must contain `%s`. | |
|`ALLURE_TESTCASE_PATTERN`| URL pattern to TestCase. Must contain `%s`. | |
|`ALLURE_LAUNCH_TAGS`| Default tags for all tests. Tags must be separated by commas. | |
================================================
FILE: allure.go
================================================
package cute
func (qt *cute) setAllureInformation(t allureProvider) {
// Log main vars to allureProvider
qt.setLabelsAllure(t)
qt.setInfoAllure(t)
qt.setLinksAllure(t)
}
func (qt *cute) setLinksAllure(t linksAllureProvider) {
if qt.allureLinks.issue != "" {
t.SetIssue(qt.allureLinks.issue)
}
if qt.allureLinks.testCase != "" {
t.SetTestCase(qt.allureLinks.testCase)
}
if qt.allureLinks.link != nil {
t.Link(qt.allureLinks.link)
}
if qt.allureLinks.tmsLink != "" {
t.TmsLink(qt.allureLinks.tmsLink)
}
if len(qt.allureLinks.tmsLinks) > 0 {
t.TmsLinks(qt.allureLinks.tmsLinks...)
}
}
func (qt *cute) setLabelsAllure(t labelsAllureProvider) {
if qt.allureLabels.id != "" {
t.ID(qt.allureLabels.id)
}
if qt.allureLabels.suiteLabel != "" {
t.AddSuiteLabel(qt.allureLabels.suiteLabel)
}
if qt.allureLabels.subSuite != "" {
t.AddSubSuite(qt.allureLabels.subSuite)
}
if qt.allureLabels.parentSuite != "" {
t.AddParentSuite(qt.allureLabels.parentSuite)
}
if qt.allureLabels.story != "" {
t.Story(qt.allureLabels.story)
}
if qt.allureLabels.tag != "" {
t.Tag(qt.allureLabels.tag)
}
if qt.allureLabels.allureID != "" {
t.AllureID(qt.allureLabels.allureID)
}
if qt.allureLabels.severity != "" {
t.Severity(qt.allureLabels.severity)
}
if qt.allureLabels.owner != "" {
t.Owner(qt.allureLabels.owner)
}
if qt.allureLabels.lead != "" {
t.Lead(qt.allureLabels.lead)
}
if qt.allureLabels.label != nil {
t.Label(qt.allureLabels.label)
}
if len(qt.allureLabels.labels) != 0 {
t.Labels(qt.allureLabels.labels...)
}
if qt.allureLabels.feature != "" {
t.Feature(qt.allureLabels.feature)
}
if qt.allureLabels.epic != "" {
t.Epic(qt.allureLabels.epic)
}
if len(qt.allureLabels.tags) != 0 {
t.Tags(qt.allureLabels.tags...)
}
if qt.allureLabels.layer != "" {
t.Layer(qt.allureLabels.layer)
}
}
func (qt *cute) setInfoAllure(t infoAllureProvider) {
if qt.allureInfo.title != "" {
t.Title(qt.allureInfo.title)
}
if qt.allureInfo.description != "" {
t.Description(qt.allureInfo.description)
}
if qt.allureInfo.stage != "" {
t.Stage(qt.allureInfo.stage)
}
}
================================================
FILE: assert.go
================================================
package cute
import (
"net/http"
)
// This is type of asserts, for create some assert with using custom logic.
// AssertBody is type for create custom assertions for body
// Example asserts:
// - json.LengthGreaterThan
// - json.LengthGreaterOrEqualThan
// - json.LengthLessThan
// - json.LengthLessOrEqualThan
// - json.Present
// - json.NotEmpty
// - json.NotPresent
type AssertBody func(body []byte) error
// AssertHeaders is type for create custom assertions for headers
// Example asserts:
// - headers.Present
// - headers.NotPresent
type AssertHeaders func(headers http.Header) error
// AssertResponse is type for create custom assertions for response
type AssertResponse func(response *http.Response) error
// This is type for create custom assertions with using allure and testing.allureProvider
// AssertBodyT is type for create custom assertions for body with TB
// Check example in AssertBody
// TB is testing.T and it can be used for require ore assert from testify or another packages
type AssertBodyT func(t T, body []byte) error
// AssertHeadersT is type for create custom assertions for headers with TB
// Check example in AssertHeaders
// TB is testing.T and it can be used for require ore assert from testify or another packages
type AssertHeadersT func(t T, headers http.Header) error
// AssertResponseT is type for create custom assertions for response with TB
// Check example in AssertResponse
// TB is testing.T and it can be used for require ore assert from testify or another packages
type AssertResponseT func(t T, response *http.Response) error
func (it *Test) assertHeaders(t internalT, headers http.Header) []error {
var (
asserts = it.Expect.AssertHeaders
assertT = it.Expect.AssertHeadersT
)
if len(asserts) == 0 && len(assertT) == 0 {
return nil
}
return it.executeWithStep(t, "Assert headers", func(t T) []error {
errs := make([]error, 0)
// Execute assert only response
for _, f := range asserts {
err := f(headers)
if err != nil {
errs = append(errs, err)
}
}
// Execute assert for response with TB
for _, f := range assertT {
err := f(t, headers)
if err != nil {
errs = append(errs, err)
}
}
return errs
})
}
func (it *Test) assertResponse(t internalT, resp *http.Response) []error {
var (
asserts = it.Expect.AssertResponse
assertT = it.Expect.AssertResponseT
)
if len(asserts) == 0 && len(assertT) == 0 {
return nil
}
return it.executeWithStep(t, "Assert response", func(t T) []error {
errs := make([]error, 0)
// Execute assert only response
for _, f := range asserts {
err := f(resp)
if err != nil {
errs = append(errs, err)
}
}
// Execute assert for response with TB
for _, f := range assertT {
err := f(t, resp)
if err != nil {
errs = append(errs, err)
}
}
return errs
})
}
func (it *Test) assertBody(t internalT, body []byte) []error {
var (
asserts = it.Expect.AssertBody
assertT = it.Expect.AssertBodyT
)
if len(asserts) == 0 && len(assertT) == 0 {
return nil
}
return it.executeWithStep(t, "Assert body", func(t T) []error {
errs := make([]error, 0)
// Execute assert only response
for _, f := range asserts {
err := f(body)
if err != nil {
errs = append(errs, err)
}
}
// Execute assert for response with TB
for _, f := range assertT {
err := f(t, body)
if err != nil {
errs = append(errs, err)
}
}
return errs
})
}
================================================
FILE: assert_broken.go
================================================
package cute
import (
"net/http"
"github.com/ozontech/cute/errors"
)
func brokenAssertHeaders(assert AssertHeaders) AssertHeaders {
return func(headers http.Header) error {
err := assert(headers)
return wrapBrokenError(err)
}
}
func brokenAssertBody(assert AssertBody) AssertBody {
return func(body []byte) error {
err := assert(body)
return wrapBrokenError(err)
}
}
func brokenAssertResponse(assert AssertResponse) AssertResponse {
return func(resp *http.Response) error {
err := assert(resp)
return wrapBrokenError(err)
}
}
func brokenAssertHeadersT(assert AssertHeadersT) AssertHeadersT {
return func(t T, headers http.Header) error {
err := assert(t, headers)
return wrapBrokenError(err)
}
}
func brokenAssertBodyT(assert AssertBodyT) AssertBodyT {
return func(t T, body []byte) error {
err := assert(t, body)
return wrapBrokenError(err)
}
}
func brokenAssertResponseT(assert AssertResponseT) AssertResponseT {
return func(t T, resp *http.Response) error {
err := assert(t, resp)
return wrapBrokenError(err)
}
}
func wrapBrokenError(err error) error {
if err == nil {
return nil
}
if tErr, ok := err.(errors.BrokenError); ok {
tErr.SetBroken(true)
return tErr.(error)
}
return errors.WrapBrokenError(err)
}
================================================
FILE: assert_broken_test.go
================================================
package cute
import (
"errors"
"net/http"
"testing"
cuteErrors "github.com/ozontech/cute/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestBrokenAssertResponse(t *testing.T) {
v := &http.Response{}
f := func(_ *http.Response) error {
return errors.New("test error")
}
err := brokenAssertResponse(f)(v)
if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) {
require.True(t, BrokenError.IsBroken())
}
}
func TestBrokenAssertResponseT(t *testing.T) {
v := &http.Response{}
f := func(T, *http.Response) error {
return errors.New("test error")
}
err := brokenAssertResponseT(f)(nil, v)
if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) {
require.True(t, BrokenError.IsBroken())
}
}
func TestBrokenAssertHeaders(t *testing.T) {
h := http.Header{}
f := func(_ http.Header) error {
return errors.New("test error")
}
err := brokenAssertHeaders(f)(h)
if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) {
require.True(t, BrokenError.IsBroken())
}
}
func TestBrokenAssertHeadersT(t *testing.T) {
h := http.Header{}
f := func(T, http.Header) error {
return errors.New("test error")
}
err := brokenAssertHeadersT(f)(nil, h)
if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) {
require.True(t, BrokenError.IsBroken())
}
}
func TestBrokenAssertBody(t *testing.T) {
v := []byte{}
f := func(_ []byte) error {
return errors.New("test error")
}
err := brokenAssertBody(f)(v)
if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) {
require.True(t, BrokenError.IsBroken())
}
}
func TestBrokenAssertBodyT(t *testing.T) {
v := []byte{}
f := func(T, []byte) error {
return errors.New("test error")
}
err := brokenAssertBodyT(f)(nil, v)
if BrokenError, ok := err.(cuteErrors.BrokenError); assert.True(t, ok) {
require.True(t, BrokenError.IsBroken())
}
}
func TestWrapBrokenError(t *testing.T) {
err := errors.New("test error")
optError := wrapBrokenError(err)
if BrokenError, ok := optError.(cuteErrors.BrokenError); assert.True(t, ok) {
require.True(t, BrokenError.IsBroken())
}
}
================================================
FILE: assert_optional.go
================================================
package cute
import (
"net/http"
"github.com/ozontech/cute/errors"
)
func optionalAssertHeaders(assert AssertHeaders) AssertHeaders {
return func(headers http.Header) error {
err := assert(headers)
return wrapOptionalError(err)
}
}
func optionalAssertBody(assert AssertBody) AssertBody {
return func(body []byte) error {
err := assert(body)
return wrapOptionalError(err)
}
}
func optionalAssertResponse(assert AssertResponse) AssertResponse {
return func(resp *http.Response) error {
err := assert(resp)
return wrapOptionalError(err)
}
}
func optionalAssertHeadersT(assert AssertHeadersT) AssertHeadersT {
return func(t T, headers http.Header) error {
err := assert(t, headers)
return wrapOptionalError(err)
}
}
func optionalAssertBodyT(assert AssertBodyT) AssertBodyT {
return func(t T, body []byte) error {
err := assert(t, body)
return wrapOptionalError(err)
}
}
func optionalAssertResponseT(assert AssertResponseT) AssertResponseT {
return func(t T, resp *http.Response) error {
err := assert(t, resp)
return wrapOptionalError(err)
}
}
func wrapOptionalError(err error) error {
if err == nil {
return nil
}
if tErr, ok := err.(errors.OptionalError); ok {
tErr.SetOptional(true)
return tErr.(error)
}
return errors.WrapOptionalError(err)
}
================================================
FILE: assert_optional_test.go
================================================
package cute
import (
"errors"
"net/http"
"testing"
cuteErrors "github.com/ozontech/cute/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOptionalAssertResponse(t *testing.T) {
v := &http.Response{}
f := func(*http.Response) error {
return errors.New("test error")
}
err := optionalAssertResponse(f)(v)
if optionalError, ok := err.(cuteErrors.OptionalError); assert.True(t, ok) {
require.True(t, optionalError.IsOptional())
}
}
func TestOptionalAssertResponseT(t *testing.T) {
v := &http.Response{}
f := func(T, *http.Response) error {
return errors.New("test error")
}
err := optionalAssertResponseT(f)(nil, v)
if optionalError, ok := err.(cuteErrors.OptionalError); assert.True(t, ok) {
require.True(t, optionalError.IsOptional())
}
}
func TestOptionalAssertHeaders(t *testing.T) {
h := http.Header{}
f := func(http.Header) error {
return errors.New("test error")
}
err := optionalAssertHeaders(f)(h)
if optionalError, ok := err.(cuteErrors.OptionalError); assert.True(t, ok) {
require.True(t, optionalError.IsOptional())
}
}
func TestOptionalAssertHeadersT(t *testing.T) {
h := http.Header{}
f := func(T, http.Header) error {
return errors.New("test error")
}
err := optionalAssertHeadersT(f)(nil, h)
if optionalError, ok := err.(cuteErrors.OptionalError); assert.True(t, ok) {
require.True(t, optionalError.IsOptional())
}
}
func TestOptionalAssertBody(t *testing.T) {
v := []byte{}
f := func([]byte) error {
return errors.New("test error")
}
err := optionalAssertBody(f)(v)
if optionalError, ok := err.(cuteErrors.OptionalError); assert.True(t, ok) {
require.True(t, optionalError.IsOptional())
}
}
func TestOptionalAssertBodyT(t *testing.T) {
v := []byte{}
f := func(T, []byte) error {
return errors.New("test error")
}
err := optionalAssertBodyT(f)(nil, v)
if optionalError, ok := err.(cuteErrors.OptionalError); assert.True(t, ok) {
require.True(t, optionalError.IsOptional())
}
}
func TestWrapOptionalError(t *testing.T) {
err := errors.New("test error")
optError := wrapOptionalError(err)
if optionalError, ok := optError.(cuteErrors.OptionalError); assert.True(t, ok) {
require.True(t, optionalError.IsOptional())
}
}
================================================
FILE: assert_require.go
================================================
package cute
import (
"net/http"
"github.com/ozontech/cute/errors"
)
func requireAssertHeaders(assert AssertHeaders) AssertHeaders {
return func(headers http.Header) error {
err := assert(headers)
return wrapRequireError(err)
}
}
func requireAssertBody(assert AssertBody) AssertBody {
return func(body []byte) error {
err := assert(body)
return wrapRequireError(err)
}
}
func requireAssertResponse(assert AssertResponse) AssertResponse {
return func(resp *http.Response) error {
err := assert(resp)
return wrapRequireError(err)
}
}
func requireAssertHeadersT(assert AssertHeadersT) AssertHeadersT {
return func(t T, headers http.Header) error {
err := assert(t, headers)
return wrapRequireError(err)
}
}
func requireAssertBodyT(assert AssertBodyT) AssertBodyT {
return func(t T, body []byte) error {
err := assert(t, body)
return wrapRequireError(err)
}
}
func requireAssertResponseT(assert AssertResponseT) AssertResponseT {
return func(t T, resp *http.Response) error {
err := assert(t, resp)
return wrapRequireError(err)
}
}
func wrapRequireError(err error) error {
if err == nil {
return nil
}
if tErr, ok := err.(errors.RequireError); ok {
tErr.SetRequire(true)
return tErr.(error)
}
return errors.WrapRequireError(err)
}
================================================
FILE: assert_require_test.go
================================================
package cute
import (
"errors"
"net/http"
"testing"
cuteErrors "github.com/ozontech/cute/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRequireAssertResponse(t *testing.T) {
v := &http.Response{}
f := func(_ *http.Response) error {
return errors.New("test error")
}
err := requireAssertResponse(f)(v)
if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) {
require.True(t, RequireError.IsRequire())
}
}
func TestRequireAssertResponseT(t *testing.T) {
v := &http.Response{}
f := func(T, *http.Response) error {
return errors.New("test error")
}
err := requireAssertResponseT(f)(nil, v)
if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) {
require.True(t, RequireError.IsRequire())
}
}
func TestRequireAssertHeaders(t *testing.T) {
h := http.Header{}
f := func(http.Header) error {
return errors.New("test error")
}
err := requireAssertHeaders(f)(h)
if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) {
require.True(t, RequireError.IsRequire())
}
}
func TestRequireAssertHeadersT(t *testing.T) {
h := http.Header{}
f := func(T, http.Header) error {
return errors.New("test error")
}
err := requireAssertHeadersT(f)(nil, h)
if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) {
require.True(t, RequireError.IsRequire())
}
}
func TestRequireAssertBody(t *testing.T) {
v := []byte{}
f := func([]byte) error {
return errors.New("test error")
}
err := requireAssertBody(f)(v)
if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) {
require.True(t, RequireError.IsRequire())
}
}
func TestRequireAssertBodyT(t *testing.T) {
v := []byte{}
f := func(T, []byte) error {
return errors.New("test error")
}
err := requireAssertBodyT(f)(nil, v)
if RequireError, ok := err.(cuteErrors.RequireError); assert.True(t, ok) {
require.True(t, RequireError.IsRequire())
}
}
func TestWrapRequireError(t *testing.T) {
err := errors.New("test error")
optError := wrapRequireError(err)
if RequireError, ok := optError.(cuteErrors.RequireError); assert.True(t, ok) {
require.True(t, RequireError.IsRequire())
}
}
================================================
FILE: assert_trace.go
================================================
package cute
import (
"fmt"
"net/http"
"runtime"
"github.com/ozontech/cute/errors"
)
// assertHeadersWithTrace is a function to add trace inside assert headers error
func assertHeadersWithTrace(assert AssertHeaders, trace string) AssertHeaders {
return func(headers http.Header) error {
err := assert(headers)
return wrapWithTrace(err, trace)
}
}
// assertBodyWithTrace is a function to add trace inside assert body error
func assertBodyWithTrace(assert AssertBody, trace string) AssertBody {
return func(body []byte) error {
err := assert(body)
return wrapWithTrace(err, trace)
}
}
// assertResponseWithTrace is a function to add trace inside assert response error
func assertResponseWithTrace(assert AssertResponse, trace string) AssertResponse {
return func(resp *http.Response) error {
err := assert(resp)
return wrapWithTrace(err, trace)
}
}
// assertHeadersTWithTrace is a function to add trace inside assert headers error
func assertHeadersTWithTrace(assert AssertHeadersT, trace string) AssertHeadersT {
return func(t T, headers http.Header) error {
err := assert(t, headers)
return wrapWithTrace(err, trace)
}
}
// assertBodyTWithTrace is a function to add trace inside assert body error
func assertBodyTWithTrace(assert AssertBodyT, trace string) AssertBodyT {
return func(t T, body []byte) error {
err := assert(t, body)
return wrapWithTrace(err, trace)
}
}
// assertResponseTWithTrace is a function to add trace inside assert response error
func assertResponseTWithTrace(assert AssertResponseT, trace string) AssertResponseT {
return func(t T, resp *http.Response) error {
err := assert(t, resp)
return wrapWithTrace(err, trace)
}
}
// wrapWithTrace is a function to add trace inside error
func wrapWithTrace(err error, trace string) error {
if err == nil {
return nil
}
if tErr, ok := err.(errors.WithTrace); ok {
tErr.SetTrace(trace)
return tErr.(error)
}
return errors.WrapErrorWithTrace(err, trace)
}
func getTrace() string {
pcs := make([]uintptr, 10)
depth := runtime.Callers(3, pcs)
if depth == 0 {
fmt.Println("Couldn't get the stack information")
return ""
}
callers := runtime.CallersFrames(pcs[:depth])
caller, _ := callers.Next()
return fmt.Sprintf("%s:%d", caller.File, caller.Line)
}
================================================
FILE: asserts/headers/headers.go
================================================
package headers
import (
"fmt"
"net/http"
"github.com/ozontech/cute"
"github.com/ozontech/cute/errors"
)
// Present is a function to asserts that header is present
func Present(key string) cute.AssertHeaders {
return func(headers http.Header) error {
if v := headers.Get(key); v == "" {
return errors.NewAssertError("Present", fmt.Sprintf("header %s is not present", key), nil, nil)
}
return nil
}
}
// NotPresent is a function to asserts that header is not present
func NotPresent(key string) cute.AssertHeaders {
return func(headers http.Header) error {
if v := headers.Values(key); len(v) > 0 {
return errors.NewAssertError("NotPresent", fmt.Sprintf("header %s is present", key), nil, nil)
}
return nil
}
}
================================================
FILE: asserts/headers/headers_test.go
================================================
package headers
import (
"net/http"
"testing"
"github.com/stretchr/testify/require"
)
func TestPresent(t *testing.T) {
headers := http.Header{
"Content-Type": []string{"application/json"},
}
err := Present("Content-Type")(headers)
require.NoError(t, err)
}
func TestPresentError(t *testing.T) {
headers := http.Header{
"Content-Type": []string{},
}
err := Present("not-present")(headers)
require.Error(t, err)
}
func TestNotPresent(t *testing.T) {
headers := http.Header{
"Content-Type": []string{"", "application/json"},
}
err := NotPresent("Content-Type")(headers)
require.Error(t, err)
}
func TestNotPresentError(t *testing.T) {
headers := http.Header{
"Content-Type": []string{},
}
err := NotPresent("not-present")(headers)
require.NoError(t, err)
}
================================================
FILE: asserts/json/json.go
================================================
package json
import (
"fmt"
jd "github.com/josephburnett/jd/lib"
"github.com/ohler55/ojg/jp"
"github.com/ohler55/ojg/oj"
"github.com/ozontech/cute"
cuteErrors "github.com/ozontech/cute/errors"
)
// Diff is a function to compare two jsons
func Diff(original string) cute.AssertBody {
return func(body []byte) error {
originalJSON, err := jd.ReadJsonString(original)
if err != nil {
return fmt.Errorf("could not parse original json in Diff error: '%s'", err)
}
bodyJSON, err := jd.ReadJsonString(string(body))
if err != nil {
return fmt.Errorf("could not parse body json in Diff error: '%s'", err)
}
diff := originalJSON.Diff(bodyJSON).Render()
if diff != "" {
cErr := cuteErrors.NewEmptyAssertError("JSON Diff", "JSON is not the same")
cErr.PutAttachment(&cuteErrors.Attachment{
Name: "JSON diff",
MimeType: "text/plain",
Content: []byte(diff),
})
return cErr
}
return nil
}
}
// Contains is a function to assert that a jsonpath expression extracts a value in an array
// About expression - https://goessner.net/articles/JsonPath/
func Contains(expression string, expect interface{}) cute.AssertBody {
return func(body []byte) error {
return contains(body, expression, expect)
}
}
// Equal is a function to assert that a jsonpath expression matches the given value
// About expression - https://goessner.net/articles/JsonPath/
func Equal(expression string, expect interface{}) cute.AssertBody {
return func(body []byte) error {
return equal(body, expression, expect)
}
}
// NotEqual is a function to check json path expression value is not equal to given value
// About expression - https://goessner.net/articles/JsonPath/
func NotEqual(expression string, expect interface{}) cute.AssertBody {
return func(body []byte) error {
return notEqual(body, expression, expect)
}
}
// EqualJSON is a function to check json path expression value is equal to given json
// About expression - https://goessner.net/articles/JsonPath/
func EqualJSON(expression string, expect []byte) cute.AssertBody {
return func(body []byte) error {
return equalJSON(body, expression, expect)
}
}
// NotEqualJSON is a function to check json path expression value is not equal to given json
// About expression - https://goessner.net/articles/JsonPath/
func NotEqualJSON(expression string, expect []byte) cute.AssertBody {
return func(body []byte) error {
return notEqualJSON(body, expression, expect)
}
}
// Length is a function to asserts that value is the expected length
// About expression - https://goessner.net/articles/JsonPath/
func Length(expression string, expectLength int) cute.AssertBody {
return func(body []byte) error {
return length(body, expression, expectLength)
}
}
// LengthGreaterThan is a function to asserts that value is greater than the given length
// About expression - https://goessner.net/articles/JsonPath/
func LengthGreaterThan(expression string, minimumLength int) cute.AssertBody {
return func(body []byte) error {
return greaterThan(body, expression, minimumLength)
}
}
// LengthGreaterOrEqualThan is a function to asserts that value is greater or equal than the given length
// About expression - https://goessner.net/articles/JsonPath/
func LengthGreaterOrEqualThan(expression string, minimumLength int) cute.AssertBody {
return func(body []byte) error {
return greaterOrEqualThan(body, expression, minimumLength)
}
}
// LengthLessThan is a function to asserts that value is less than the given length
// About expression - https://goessner.net/articles/JsonPath/
func LengthLessThan(expression string, maximumLength int) cute.AssertBody {
return func(body []byte) error {
return lessThan(body, expression, maximumLength)
}
}
// LengthLessOrEqualThan is a function to asserts that value is less or equal than the given length
// About expression - https://goessner.net/articles/JsonPath/
func LengthLessOrEqualThan(expression string, maximumLength int) cute.AssertBody {
return func(body []byte) error {
return lessOrEqualThan(body, expression, maximumLength)
}
}
// Present is a function to asserts that value is present
// value can be nil or 0
// About expression - https://goessner.net/articles/JsonPath/
func Present(expression string) cute.AssertBody {
return func(body []byte) error {
return present(body, expression)
}
}
// NotEmpty is a function to asserts that value is present
// value can't be nil or 0
// About expression - https://goessner.net/articles/JsonPath/
func NotEmpty(expression string) cute.AssertBody {
return func(body []byte) error {
return notEmpty(body, expression)
}
}
// NotPresent is a function to asserts that value is not present
// About expression - https://goessner.net/articles/JsonPath/
func NotPresent(expression string) cute.AssertBody {
return func(body []byte) error {
return notPresent(body, expression)
}
}
// GetValueFromJSON is function for get value from json
func GetValueFromJSON(js []byte, expression string) ([]interface{}, error) {
obj, err := oj.Parse(js)
if err != nil {
return nil, fmt.Errorf("could not parse json in GetValueFromJSON error: '%s'", err)
}
jsonPath, err := jp.ParseString(expression)
if err != nil {
return nil, fmt.Errorf("could not parse path in GetValueFromJSON error: '%s'", err)
}
res := jsonPath.Get(obj)
if len(res) == 0 {
return nil, fmt.Errorf("could not find element by path %v in JSON", expression)
}
return res, nil
}
================================================
FILE: asserts/json/json_test.go
================================================
package json
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type jsonTest struct {
caseName string
data string
expression string
expect interface{}
IsNilErr bool
}
func TestDiff(t *testing.T) {
testCases := []struct {
name string
originalJSON string
bodyJSON string
expectedError string
}{
{
name: "SameJSON",
originalJSON: `{"key1": "value1", "key2": "value2"}`,
bodyJSON: `{"key1": "value1", "key2": "value2"}`,
expectedError: "", // No error expected, JSONs are the same
},
{
name: "DifferentValueJSON",
originalJSON: `{"key1": "value1", "key2": "value2"}`,
bodyJSON: `{"key1": "value1", "key2": "value3"}`,
expectedError: "JSON is not the same",
},
{
name: "MissingKeyJSON",
originalJSON: `{"key1": "value1", "key2": "value2"}`,
bodyJSON: `{"key1": "value1"}`,
expectedError: "JSON is not the same",
},
{
name: "ExtraKeyJSON",
originalJSON: `{"key1": "value1"}`,
bodyJSON: `{"key1": "value1", "key2": "value2"}`,
expectedError: "JSON is not the same",
},
{
name: "EmptyJSON",
originalJSON: `{}`,
bodyJSON: `{}`,
expectedError: "", // No error expected, empty JSONs are the same
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
// Call the Diff function with the test input
err := Diff(testCase.originalJSON)([]byte(testCase.bodyJSON))
// Check if the error message matches the expected result
if testCase.expectedError == "" {
assert.NoError(t, err) // No error expected
} else {
assert.Error(t, err) // Error expected
assert.Contains(t, err.Error(), testCase.expectedError)
}
})
}
}
func TestNotPresent(t *testing.T) {
tests := []jsonTest{
{
caseName: "correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
},
{
caseName: "not present check",
data: `{"o":["a", "b", "c"]}`,
expression: "$.b",
IsNilErr: true,
},
{
caseName: "not present check ",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o[0]",
},
{
caseName: "correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o[0]['1']",
},
}
for _, test := range tests {
err := NotPresent(test.expression)([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestPresent(t *testing.T) {
tests := []jsonTest{
{
caseName: "correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
IsNilErr: true,
},
{
caseName: "not present check",
data: `{"o":["a", "b", "c"]}`,
expression: "$.b",
},
{
caseName: "correct present check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o[0]",
IsNilErr: true,
},
{
caseName: "correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o[0]['1']",
IsNilErr: true,
},
{
caseName: "check not correct path",
data: `{"o":["a", "b", "c"]}`,
expression: "$.not_correct",
},
{
caseName: "empty integer",
data: `{"o":0}`,
expression: "$.o",
IsNilErr: true,
},
{
caseName: "empty object",
data: `{"o":null}`,
expression: "$.o",
IsNilErr: true,
},
{
caseName: "empty string",
data: `{"o":null, "b":""}`,
expression: "$.b",
IsNilErr: true,
},
}
for _, test := range tests {
err := Present(test.expression)([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestNotEmpty(t *testing.T) {
tests := []jsonTest{
{
caseName: "correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
IsNilErr: true,
},
{
caseName: "not present check",
data: `{"o":["a", "b", "c"]}`,
expression: "$.b",
},
{
caseName: "correct present check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o[0]",
IsNilErr: true,
},
{
caseName: "correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o[0]['1']",
IsNilErr: true,
},
{
caseName: "check not correct path",
data: `{"o":["a", "b", "c"]}`,
expression: "$.not_correct",
},
{
caseName: "empty integer",
data: `{"o":0}`,
expression: "$.o",
},
{
caseName: "empty object",
data: `{"o":null}`,
expression: "$.o",
},
{
caseName: "empty string",
data: `{"o":null, "b":""}`,
expression: "$.b",
},
}
for _, test := range tests {
err := NotEmpty(test.expression)([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestLength(t *testing.T) {
tests := []jsonTest{
{
caseName: "correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 3,
IsNilErr: true,
},
{
caseName: "not correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 4,
},
{
caseName: "correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 6,
IsNilErr: true,
},
{
caseName: "not correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 99,
},
{
caseName: "check not contain value",
data: `{"o":"123456"}`,
expression: "$.a",
expect: 1,
},
{
caseName: "correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 3,
IsNilErr: true,
},
}
for _, test := range tests {
err := Length(test.expression, test.expect.(int))([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestLengthGreaterThan(t *testing.T) {
tests := []jsonTest{
{
caseName: "correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 2,
IsNilErr: true,
},
{
caseName: "not correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 4,
},
{
caseName: "not correct check array when equal",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 3,
},
{
caseName: "correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 4,
IsNilErr: true,
},
{
caseName: "not correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 99,
},
{
caseName: "correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 1,
IsNilErr: true,
},
{
caseName: "check not correct path",
data: `{"o":["a", "b", "c"]}`,
expression: "$.not_correct",
expect: 0,
},
}
for _, test := range tests {
err := LengthGreaterThan(test.expression, test.expect.(int))([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestLengthGreaterOrEqualThan(t *testing.T) {
tests := []jsonTest{
{
caseName: "correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 2,
IsNilErr: true,
},
{
caseName: "correct check array when equal",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 3,
IsNilErr: true,
},
{
caseName: "not correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 4,
},
{
caseName: "correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 4,
IsNilErr: true,
},
{
caseName: "correct check string when equal",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 6,
IsNilErr: true,
},
{
caseName: "not correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 99,
},
{
caseName: "correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 1,
IsNilErr: true,
},
{
caseName: "correct check map when equal",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 3,
IsNilErr: true,
},
{
caseName: "not correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 5,
},
{
caseName: "check not correct path",
data: `{"o":["a", "b", "c"]}`,
expression: "$.not_correct",
expect: 0,
},
}
for _, test := range tests {
err := LengthGreaterOrEqualThan(test.expression, test.expect.(int))([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestLengthLessThan(t *testing.T) {
tests := []jsonTest{
{
caseName: "correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 4,
IsNilErr: true,
},
{
caseName: "not correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 3,
},
{
caseName: "correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 7,
IsNilErr: true,
},
{
caseName: "not correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 6,
},
{
caseName: "correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 4,
IsNilErr: true,
},
{
caseName: "not correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 3,
},
{
caseName: "check not correct path",
data: `{"o":["a", "b", "c"]}`,
expression: "$.not_correct",
expect: 0,
},
}
for _, test := range tests {
err := LengthLessThan(test.expression, test.expect.(int))([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestLengthLessOrEqualThan(t *testing.T) {
tests := []jsonTest{
{
caseName: "correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 4,
IsNilErr: true,
},
{
caseName: "correct check array when equal",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 3,
IsNilErr: true,
},
{
caseName: "not correct check array",
data: `{"o":["a", "b", "c"]}`,
expression: "$.o",
expect: 2,
},
{
caseName: "correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 7,
IsNilErr: true,
},
{
caseName: "correct check string when equal",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 6,
IsNilErr: true,
},
{
caseName: "not correct check string",
data: `{"o":"123456"}`,
expression: "$.o",
expect: 5,
},
{
caseName: "correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 4,
IsNilErr: true,
},
{
caseName: "correct check map when equal",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 3,
IsNilErr: true,
},
{
caseName: "not correct check map",
data: `{"o":[{"1":"a"}, {"2":"b"}, {"3":"c"}]}`,
expression: "$.o",
expect: 2,
},
{
caseName: "check not correct path",
data: `{"o":["a", "b", "c"]}`,
expression: "$.not_correct",
expect: 0,
},
}
for _, test := range tests {
err := LengthLessOrEqualThan(test.expression, test.expect.(int))([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestEqual(t *testing.T) {
tests := []jsonTest{
{
caseName: "valid json",
data: `{"first": 777, "second": [{"key_1": "some_key", "value": "some_value"}]}`,
expression: "$.second[0].value",
expect: "some_value",
IsNilErr: true,
},
{
caseName: "not valid json",
data: "{not_valid_json}",
},
{
caseName: "3rd party key",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.l",
expect: nil,
},
{
caseName: "not array",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.b[bs]",
},
{
caseName: "valid array",
data: `{"arr": ["one","two"]}`,
expression: "$.arr",
expect: []string{"one", "two"},
IsNilErr: true,
},
{
caseName: "check equal map",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.b",
expect: map[string]interface{}{"bs": "sb"},
IsNilErr: true,
},
{
caseName: "check equal string",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.a",
expect: "as",
IsNilErr: true,
},
{
caseName: "check equal not correct string",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.a",
expect: []byte("not_correct"),
},
{
caseName: "check 186135434",
data: `{"a":186135434, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: 186135434,
IsNilErr: true,
},
{
caseName: "check float",
data: `{"a":1.0000001, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: 1.0000001,
IsNilErr: true,
},
{
caseName: "check float 2",
data: `{"a":999.0000001, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: 999.0000001,
IsNilErr: true,
},
}
for _, test := range tests {
err := Equal(test.expression, test.expect)([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestNotEqual(t *testing.T) {
tests := []jsonTest{
{
caseName: "valid json",
data: `{"first": 777, "second": [{"key_1": "some_key", "value": "some_value"}]}`,
expression: "$.second[0].value",
expect: "some_value",
IsNilErr: false,
},
{
caseName: "not valid json",
data: "{not_valid_json}",
},
{
caseName: "3rd party key",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.l",
expect: nil,
},
{
caseName: "not array",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.b[bs]",
expect: "sb",
},
{
caseName: "check equal map",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.b",
expect: map[string]interface{}{"bs": "sb"},
IsNilErr: false,
},
{
caseName: "check equal string",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.a",
expect: "as",
IsNilErr: false,
},
}
for _, test := range tests {
err := NotEqual(test.expression, test.expect)([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestEqualJSON(t *testing.T) {
tests := []jsonTest{
{
caseName: "valid json",
data: `{"first": 777, "second": [{"key_1": "some_key", "value": "some_value"}]}`,
expression: "$.second[0].value",
expect: `"some_value"`,
IsNilErr: true,
},
{
caseName: "not valid json",
data: "{not_valid_json}",
},
{
caseName: "3rd party key",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.l",
},
{
caseName: "not array",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.b[bs]",
},
{
caseName: "valid array",
data: `{"arr": ["one","two"]}`,
expression: "$.arr",
expect: `["one", "two"]`,
IsNilErr: true,
},
{
caseName: "check equal map",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.b",
expect: `{"bs": "sb"}`,
IsNilErr: true,
},
{
caseName: "check equal string",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.a",
expect: `"as"`,
IsNilErr: true,
},
{
caseName: "check equal not correct string",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.a",
expect: `"not_correct"`,
},
{
caseName: "check deep equal",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$",
expect: `{ "b": {"bs": "sb"}, "a":"as" }`,
IsNilErr: true,
},
{
caseName: "check deep equal not correct",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$",
expect: `{ "b": {"sb": "bs"}, "a":"as" }`,
},
{
caseName: "check 186135434",
data: `{"a":186135434, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: "186135434",
IsNilErr: true,
},
{
caseName: "check float",
data: `{"a":1.0000001, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: "1.0000001",
IsNilErr: true,
},
{
caseName: "check float 2",
data: `{"a":999.0000001, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: "999.0000001",
IsNilErr: true,
},
}
for _, test := range tests {
exp, _ := test.expect.(string)
err := EqualJSON(test.expression, []byte(exp))([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestNotEqualJSON(t *testing.T) {
tests := []jsonTest{
{
caseName: "valid json",
data: `{"first": 777, "second": [{"key_1": "some_key", "value": "some_value"}]}`,
expression: "$.second[0].value",
expect: `"some_value"`,
},
{
caseName: "not valid json",
data: "{not_valid_json}",
},
{
caseName: "3rd party key",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.l",
},
{
caseName: "not array",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.b[bs]",
},
{
caseName: "valid array",
data: `{"arr": ["one","two"]}`,
expression: "$.arr",
expect: `["one", "two"]`,
},
{
caseName: "check equal map",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.b",
expect: `{"bs": "sb"}`,
},
{
caseName: "check equal string",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.a",
expect: `"as"`,
},
{
caseName: "check equal not correct string",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$.a",
expect: `"not_correct"`,
IsNilErr: true,
},
{
caseName: "check deep equal",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$",
expect: `{ "b": {"bs": "sb"}, "a":"as" }`,
},
{
caseName: "check deep equal not correct",
data: `{"a":"as", "b":{"bs":"sb"}}`,
expression: "$",
expect: `{ "b": {"sb": "bs"}, "a":"as" }`,
IsNilErr: true,
},
{
caseName: "check 186135434",
data: `{"a":186135434, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: "186135434",
},
{
caseName: "check float",
data: `{"a":1.0000001, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: "1.0000001",
},
{
caseName: "check float 2",
data: `{"a":999.0000001, "b":{"bs":"sb"}}`,
expression: "$.a",
expect: "999.0000001",
},
}
for _, test := range tests {
exp, _ := test.expect.(string)
err := NotEqualJSON(test.expression, []byte(exp))([]byte(test.data))
if test.IsNilErr {
require.NoError(t, err, "failed test %v", test.caseName)
} else {
require.Error(t, err, "failed test %v", test.caseName)
}
}
}
func TestGetValueFromJSON(t *testing.T) {
testCases := []struct {
name string
inputJSON string
expression string
expectedValue []interface{}
expectedError string
}{
{
name: "ValidExpressionObject",
inputJSON: `{"key1": "value1", "key2": {"key3": "value3"}}`,
expression: "key2.key3",
expectedValue: []interface{}{"value3"},
expectedError: "", // No error expected
},
{
name: "ValidExpressionArray",
inputJSON: `{"key1": "value1", "key2": [1, 2, 3]}`,
expression: "key2[1]",
expectedValue: []interface{}{int64(2)},
expectedError: "", // No error expected
},
{
name: "ValidExpressionMap",
inputJSON: `{"key1": "value1", "key2": {"subkey1": "subvalue1"}}`,
expression: "key2",
expectedValue: []interface{}{map[string]interface{}{"subkey1": "subvalue1"}},
expectedError: "", // No error expected
},
{
name: "InvalidJSON",
inputJSON: `invalid json`,
expression: "key1",
expectedValue: nil,
expectedError: "could not parse json",
},
{
name: "InvalidExpression",
inputJSON: `{"key1": "value1"}`,
expression: "key2",
expectedValue: nil,
expectedError: "could not find element by path key2 in JSON",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
// Call the GetValueFromJSON function with the test input
value, err := GetValueFromJSON([]byte(testCase.inputJSON), testCase.expression)
// Check if the error message matches the expected result
if testCase.expectedError == "" {
assert.NoError(t, err) // No error expected
} else {
assert.Error(t, err) // Error expected
assert.Contains(t, err.Error(), testCase.expectedError)
}
// Check if the returned value is an array and matches the expected result
assert.IsType(t, []interface{}{}, value)
assert.Equal(t, testCase.expectedValue, value)
})
}
}
================================================
FILE: asserts/json/util.go
================================================
package json
import (
"bytes"
"fmt"
"reflect"
"strings"
"github.com/ohler55/ojg/oj"
"github.com/ozontech/cute/errors"
)
// Contains is a function to assert that a jsonpath expression extracts a value in an array
// Given the response is {"first": 777, "second": [{"key_1": "some_key", "value": "some_value"}]}, we can assert on the result like so `$.second[? @.key_1=="some_key"].value`, "some_value"
// About expression - https://goessner.net/articles/JsonPath/
func contains(data []byte, expression string, expect interface{}) error {
values, err := GetValueFromJSON(data, expression)
if err != nil {
return err
}
for _, value := range values {
ok, found := insideArray(value, expect)
if !ok {
return errors.NewAssertError("Contains", fmt.Sprintf("on path %v. %v could not be applied builtin len()", expression, expect), nil, nil)
}
if !found {
return errors.NewAssertError("Contains", fmt.Sprintf("on path %v. expect %v, but actual %v", expression, expect, value), value, expect)
}
}
return nil
}
func equalAbstract(data []byte, expression string, expect interface{}, name string) error {
values, err := GetValueFromJSON(data, expression)
if err != nil {
return err
}
for _, value := range values {
if !objectsAreEqual(value, expect) {
return errors.NewAssertError(name, fmt.Sprintf("on path %v. expect %v, but actual %v", expression, expect, value), value, expect)
}
}
return nil
}
func notEqualAbstract(data []byte, expression string, expect interface{}, name string) error {
values, err := GetValueFromJSON(data, expression)
if err != nil {
return err
}
for _, value := range values {
if objectsAreEqual(value, expect) {
return errors.NewAssertError(name, fmt.Sprintf("on path %v. expect %v, but actual %v", expression, expect, value), value, expect)
}
}
return nil
}
// Equal is a function to assert that a jsonpath expression matches the given value
// About expression - https://goessner.net/articles/JsonPath/
func equal(data []byte, expression string, expect interface{}) error {
return equalAbstract(data, expression, expect, "Equal")
}
// NotEqual is a function to check json path expression value is not equal to given value
// About expression - https://goessner.net/articles/JsonPath/
func notEqual(data []byte, expression string, expect interface{}) error {
return notEqualAbstract(data, expression, expect, "NotEqual")
}
// EqualJSON is a function to check json path expression value is equal to given json
// About expression - https://goessner.net/articles/JsonPath/
func equalJSON(data []byte, expression string, expect []byte) error {
obj, err := oj.Parse(expect)
if err != nil {
return fmt.Errorf("could not parse json in EqualJSON error: '%s'", err)
}
return equalAbstract(data, expression, obj, "EqualJSON")
}
// NotEqualJSON is a function to check json path expression value is not equal to given json
// About expression - https://goessner.net/articles/JsonPath/
func notEqualJSON(data []byte, expression string, expect []byte) error {
obj, err := oj.Parse(expect)
if err != nil {
return fmt.Errorf("could not parse json in NotEqualJSON error: '%s'", err)
}
return notEqualAbstract(data, expression, obj, "NotEqualJSON")
}
// Length is a function to asserts that value is the expected length
// About expression - https://goessner.net/articles/JsonPath/
func length(data []byte, expression string, expectLength int) error {
values, err := GetValueFromJSON(data, expression)
if err != nil {
return err
}
for _, value := range values {
v := reflect.ValueOf(value)
if v.Len() != expectLength {
return errors.NewAssertError("Length", fmt.Sprintf("on path %v. expect lenght %v, but actual %v", expression, expectLength, v.Len()), v.Len(), expectLength)
}
}
return nil
}
// GreaterThan is a function to asserts that value is greater than the given length
// About expression - https://goessner.net/articles/JsonPath/
func greaterThan(data []byte, expression string, minimumLength int) error {
values, err := GetValueFromJSON(data, expression)
if err != nil {
return err
}
for _, value := range values {
v := reflect.ValueOf(value)
if v.Len() <= minimumLength {
return errors.NewAssertError("GreaterThan", fmt.Sprintf("on path %v. %v is greater than %v", expression, v.Len(), minimumLength), v.Len(), minimumLength)
}
}
return nil
}
// GreaterOrEqualThan is a function to asserts that value is greater or equal than the given length
// About expression - https://goessner.net/articles/JsonPath/
func greaterOrEqualThan(data []byte, expression string, minimumLength int) error {
values, err := GetValueFromJSON(data, expression)
if err != nil {
return err
}
for _, value := range values {
v := reflect.ValueOf(value)
if v.Len() < minimumLength {
return errors.NewAssertError("GreaterOrEqualThan", fmt.Sprintf("on path %v. %v is greater or equal than %v", expression, v.Len(), minimumLength), v.Len(), minimumLength)
}
}
return nil
}
// LessThan is a function to asserts that value is less than the given length
// About expression - https://goessner.net/articles/JsonPath/
func lessThan(data []byte, expression string, maximumLength int) error {
values, err := GetValueFromJSON(data, expression)
if err != nil {
return err
}
for _, value := range values {
v := reflect.ValueOf(value)
if v.Len() >= maximumLength {
return errors.NewAssertError("LessThan", fmt.Sprintf("on path %v. %v is less than %v", expression, v.Len(), maximumLength), v.Len(), maximumLength)
}
}
return nil
}
// LessOrEqualThan is a function to asserts that value is less or equal than the given length
// About expression - https://goessner.net/articles/JsonPath/
func lessOrEqualThan(data []byte, expression string, maximumLength int) error {
values, err := GetValueFromJSON(data, expression)
if err != nil {
return err
}
for _, value := range values {
v := reflect.ValueOf(value)
if v.Len() > maximumLength {
return errors.NewAssertError("LessThan", fmt.Sprintf("on path %v. %v is less or equal than %v", expression, v.Len(), maximumLength), v.Len(), maximumLength)
}
}
return nil
}
// notEmpty is a function to asserts that value is not empty (!= 0, != null)
// About expression - https://goessner.net/articles/JsonPath/
func notEmpty(data []byte, expression string) error {
values, _ := GetValueFromJSON(data, expression)
if len(values) == 0 {
return errors.NewAssertError("NotEmpty", fmt.Sprintf("on path %v. value is not present", expression), nil, nil)
}
for _, value := range values {
if isEmpty(value) {
return errors.NewAssertError("NotEmpty", fmt.Sprintf("on path %v. value is not present", expression), nil, nil)
}
}
return nil
}
// Present is a function to asserts that value is present
// value can be 0 or null
// About expression - https://goessner.net/articles/JsonPath/
func present(data []byte, expression string) error {
values, err := GetValueFromJSON(data, expression)
if err != nil || len(values) == 0 {
return errors.NewAssertError("Present", fmt.Sprintf("on path %v. value not present", expression), nil, nil)
}
return nil
}
// NotPresent is a function to asserts that value is not present
// About expression - https://goessner.net/articles/JsonPath/
func notPresent(data []byte, expression string) error {
values, _ := GetValueFromJSON(data, expression)
for _, value := range values {
if !isEmpty(value) {
return errors.NewAssertError("NotPresent", fmt.Sprintf("on path %v. value present", expression), nil, nil)
}
}
return nil
}
func objectsAreEqual(expect, actual interface{}) bool {
if reflect.DeepEqual(expect, actual) {
return true
}
if expect == nil || actual == nil {
return expect == actual
}
if fmt.Sprintf("%v", expect) == fmt.Sprintf("%v", actual) {
return true
}
exp, ok := expect.([]byte)
if !ok {
return reflect.DeepEqual(expect, actual)
}
act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
}
func isEmpty(object interface{}) bool {
if object == nil {
return true
}
objValue := reflect.ValueOf(object)
switch objValue.Kind() {
case reflect.Ptr:
if objValue.IsNil() {
return true
}
deref := objValue.Elem().Interface()
return isEmpty(deref)
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
return objValue.Len() == 0
default:
zero := reflect.Zero(objValue.Type())
return reflect.DeepEqual(object, zero.Interface())
}
}
func insideArray(list interface{}, element interface{}) (ok, found bool) {
var (
listValue = reflect.ValueOf(list)
elementValue = reflect.ValueOf(element)
)
defer func() {
if err := recover(); err != nil {
ok = false
found = false
}
}()
if reflect.TypeOf(list).Kind() == reflect.String {
return true, strings.Contains(listValue.String(), elementValue.String())
}
if reflect.TypeOf(list).Kind() == reflect.Map {
mapKeys := listValue.MapKeys()
for i := 0; i < len(mapKeys); i++ {
if objectsAreEqual(mapKeys[i].Interface(), element) {
return true, true
}
}
return true, false
}
for i := 0; i < listValue.Len(); i++ {
if objectsAreEqual(listValue.Index(i).Interface(), element) {
return true, true
}
}
return true, false
}
================================================
FILE: builder.go
================================================
package cute
import (
"net/http"
"time"
)
const defaultHTTPTimeout = 30
var (
errorAssertIsNil = "assert must be not nil"
)
// HTTPTestMaker is a creator tests
type HTTPTestMaker struct {
httpClient *http.Client
middleware *Middleware
jsonMarshaler JSONMarshaler
}
// NewHTTPTestMaker is function for set options for all cute.
// For example, you can set timeout for all requests or set custom http client
// Options:
// - WithCustomHTTPTimeout - set timeout for all requests
// - WithHTTPClient - set custom http client
// - WithCustomHTTPRoundTripper - set custom http round tripper
// - WithJSONMarshaler - set custom json marshaler
// - WithMiddlewareAfter - set function which will run AFTER test execution
// - WithMiddlewareAfterT - set function which will run AFTER test execution with TB
// - WithMiddlewareBefore - set function which will run BEFORE test execution
// - WithMiddlewareBeforeT - set function which will run BEFORE test execution with TB
func NewHTTPTestMaker(opts ...Option) *HTTPTestMaker {
var (
o = &options{
middleware: new(Middleware),
}
timeout = defaultHTTPTimeout * time.Second
roundTripper = http.DefaultTransport
jsMarshaler JSONMarshaler = &jsonMarshaler{}
)
for _, opt := range opts {
opt(o)
}
if o.httpTimeout != 0 {
timeout = o.httpTimeout
}
if o.httpRoundTripper != nil { //nolint
roundTripper = o.httpRoundTripper
}
httpClient := &http.Client{
Transport: roundTripper,
Timeout: timeout,
}
if o.httpClient != nil {
httpClient = o.httpClient
}
if o.jsonMarshaler != nil {
jsMarshaler = o.jsonMarshaler
}
m := &HTTPTestMaker{
httpClient: httpClient,
jsonMarshaler: jsMarshaler,
middleware: o.middleware,
}
return m
}
// NewTestBuilder is a function for initialization foundation for cute
func (m *HTTPTestMaker) NewTestBuilder() AllureBuilder {
tests := createDefaultTests(m)
return &cute{
baseProps: m,
countTests: 0,
tests: tests,
allureInfo: new(allureInformation),
allureLinks: new(allureLinks),
allureLabels: new(allureLabels),
parallel: false,
}
}
func createDefaultTests(m *HTTPTestMaker) []*Test {
tests := make([]*Test, 1)
tests[0] = createDefaultTest(m)
return tests
}
func createDefaultTest(m *HTTPTestMaker) *Test {
return &Test{
httpClient: m.httpClient,
jsonMarshaler: m.jsonMarshaler,
Middleware: createMiddlewareFromTemplate(m.middleware),
AllureStep: new(AllureStep),
Request: &Request{
Retry: new(RequestRetryPolitic),
},
Expect: &Expect{JSONSchema: new(ExpectJSONSchema)},
}
}
func createMiddlewareFromTemplate(m *Middleware) *Middleware {
after := make([]AfterExecute, 0, len(m.After))
after = append(after, m.After...)
afterT := make([]AfterExecuteT, 0, len(m.AfterT))
afterT = append(afterT, m.AfterT...)
before := make([]BeforeExecute, 0, len(m.Before))
before = append(before, m.Before...)
beforeT := make([]BeforeExecuteT, 0, len(m.BeforeT))
beforeT = append(beforeT, m.BeforeT...)
middleware := &Middleware{
After: after,
AfterT: afterT,
Before: before,
BeforeT: beforeT,
}
return middleware
}
func (qt *cute) Create() MiddlewareRequest {
return qt
}
func (qt *cute) CreateStep(name string) MiddlewareRequest {
qt.tests[qt.countTests].AllureStep.Name = name
return qt
}
func (qt *cute) CreateRequest() RequestHTTPBuilder {
return qt
}
================================================
FILE: builder_allure.go
================================================
package cute
import (
"fmt"
"github.com/ozontech/allure-go/pkg/allure"
)
func (qt *cute) Parallel() AllureBuilder {
qt.parallel = true
return qt
}
func (qt *cute) Title(title string) AllureBuilder {
qt.allureInfo.title = title
return qt
}
func (qt *cute) Epic(epic string) AllureBuilder {
qt.allureLabels.epic = epic
return qt
}
func (qt *cute) Titlef(format string, args ...interface{}) AllureBuilder {
qt.allureInfo.title = fmt.Sprintf(format, args...)
return qt
}
func (qt *cute) Descriptionf(format string, args ...interface{}) AllureBuilder {
qt.allureInfo.description = fmt.Sprintf(format, args...)
return qt
}
func (qt *cute) Stage(stage string) AllureBuilder {
qt.allureInfo.stage = stage
return qt
}
func (qt *cute) Stagef(format string, args ...interface{}) AllureBuilder {
qt.allureInfo.stage = fmt.Sprintf(format, args...)
return qt
}
func (qt *cute) Layer(value string) AllureBuilder {
qt.allureLabels.layer = value
return qt
}
func (qt *cute) TmsLink(tmsLink string) AllureBuilder {
qt.allureLinks.tmsLink = tmsLink
return qt
}
func (qt *cute) TmsLinks(tmsLinks ...string) AllureBuilder {
qt.allureLinks.tmsLinks = append(qt.allureLinks.tmsLinks, tmsLinks...)
return qt
}
func (qt *cute) SetIssue(issue string) AllureBuilder {
qt.allureLinks.issue = issue
return qt
}
func (qt *cute) SetTestCase(testCase string) AllureBuilder {
qt.allureLinks.testCase = testCase
return qt
}
func (qt *cute) Link(link *allure.Link) AllureBuilder {
qt.allureLinks.link = link
return qt
}
func (qt *cute) ID(value string) AllureBuilder {
qt.allureLabels.id = value
return qt
}
func (qt *cute) AllureID(value string) AllureBuilder {
qt.allureLabels.allureID = value
return qt
}
func (qt *cute) AddSuiteLabel(value string) AllureBuilder {
qt.allureLabels.suiteLabel = value
return qt
}
func (qt *cute) AddSubSuite(value string) AllureBuilder {
qt.allureLabels.subSuite = value
return qt
}
func (qt *cute) AddParentSuite(value string) AllureBuilder {
qt.allureLabels.parentSuite = value
return qt
}
func (qt *cute) Story(value string) AllureBuilder {
qt.allureLabels.story = value
return qt
}
func (qt *cute) Tag(value string) AllureBuilder {
qt.allureLabels.tag = value
return qt
}
func (qt *cute) Severity(value allure.SeverityType) AllureBuilder {
qt.allureLabels.severity = value
return qt
}
func (qt *cute) Owner(value string) AllureBuilder {
qt.allureLabels.owner = value
return qt
}
func (qt *cute) Lead(value string) AllureBuilder {
qt.allureLabels.lead = value
return qt
}
func (qt *cute) Label(label *allure.Label) AllureBuilder {
qt.allureLabels.label = label
return qt
}
func (qt *cute) Labels(labels ...*allure.Label) AllureBuilder {
qt.allureLabels.labels = labels
return qt
}
func (qt *cute) Description(description string) AllureBuilder {
qt.allureInfo.description = description
return qt
}
func (qt *cute) Tags(tags ...string) AllureBuilder {
qt.allureLabels.tags = tags
return qt
}
func (qt *cute) Feature(feature string) AllureBuilder {
qt.allureLabels.feature = feature
return qt
}
================================================
FILE: builder_asserts.go
================================================
package cute
import "time"
func (qt *cute) AssertBody(asserts ...AssertBody) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assertBodyWithTrace(assert, trace))
}
return qt
}
func (qt *cute) OptionalAssertBody(asserts ...AssertBody) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assertBodyWithTrace(optionalAssertBody(assert), trace))
}
return qt
}
func (qt *cute) BrokenAssertBody(asserts ...AssertBody) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assertBodyWithTrace(brokenAssertBody(assert), trace))
}
return qt
}
func (qt *cute) RequireBody(asserts ...AssertBody) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assertBodyWithTrace(requireAssertBody(assert), trace))
}
return qt
}
func (qt *cute) AssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assertHeadersWithTrace(assert, trace))
}
return qt
}
func (qt *cute) OptionalAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assertHeadersWithTrace(optionalAssertHeaders(assert), trace))
}
return qt
}
func (qt *cute) RequireHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assertHeadersWithTrace(requireAssertHeaders(assert), trace))
}
return qt
}
func (qt *cute) BrokenAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assertHeadersWithTrace(brokenAssertHeaders(assert), trace))
}
return qt
}
func (qt *cute) AssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assertResponseWithTrace(assert, trace))
}
return qt
}
func (qt *cute) OptionalAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assertResponseWithTrace(optionalAssertResponse(assert), trace))
}
return qt
}
func (qt *cute) RequireResponse(asserts ...AssertResponse) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assertResponseWithTrace(requireAssertResponse(assert), trace))
}
return qt
}
func (qt *cute) BrokenAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assertResponseWithTrace(brokenAssertResponse(assert), trace))
}
return qt
}
func (qt *cute) AssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assertBodyTWithTrace(assert, trace))
}
return qt
}
func (qt *cute) OptionalAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assertBodyTWithTrace(optionalAssertBodyT(assert), trace))
}
return qt
}
func (qt *cute) BrokenAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assertBodyTWithTrace(brokenAssertBodyT(assert), trace))
}
return qt
}
func (qt *cute) RequireBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assertBodyTWithTrace(requireAssertBodyT(assert), trace))
}
return qt
}
func (qt *cute) AssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, assertHeadersTWithTrace(assert, trace))
}
return qt
}
func (qt *cute) OptionalAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, assertHeadersTWithTrace(optionalAssertHeadersT(assert), trace))
}
return qt
}
func (qt *cute) RequireHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, assertHeadersTWithTrace(requireAssertHeadersT(assert), trace))
}
return qt
}
func (qt *cute) BrokenAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, assertHeadersTWithTrace(brokenAssertHeadersT(assert), trace))
}
return qt
}
func (qt *cute) AssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, assertResponseTWithTrace(assert, trace))
}
return qt
}
func (qt *cute) OptionalAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, assertResponseTWithTrace(optionalAssertResponseT(assert), trace))
}
return qt
}
func (qt *cute) BrokenAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, assertResponseTWithTrace(brokenAssertResponseT(assert), trace))
}
return qt
}
func (qt *cute) RequireResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder {
trace := getTrace()
for _, assert := range asserts {
if assert == nil {
panic(errorAssertIsNil)
}
qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, assertResponseTWithTrace(requireAssertResponseT(assert), trace))
}
return qt
}
func (qt *cute) ExpectExecuteTimeout(t time.Duration) ExpectHTTPBuilder {
qt.tests[qt.countTests].Expect.ExecuteTime = t
return qt
}
func (qt *cute) ExpectStatus(code int) ExpectHTTPBuilder {
qt.tests[qt.countTests].Expect.Code = code
return qt
}
func (qt *cute) ExpectJSONSchemaString(schema string) ExpectHTTPBuilder {
qt.tests[qt.countTests].Expect.JSONSchema.String = schema
return qt
}
func (qt *cute) ExpectJSONSchemaByte(schema []byte) ExpectHTTPBuilder {
qt.tests[qt.countTests].Expect.JSONSchema.Byte = schema
return qt
}
func (qt *cute) ExpectJSONSchemaFile(filePath string) ExpectHTTPBuilder {
qt.tests[qt.countTests].Expect.JSONSchema.File = filePath
return qt
}
================================================
FILE: builder_middleware.go
================================================
package cute
func (qt *cute) StepName(name string) MiddlewareRequest {
qt.tests[qt.countTests].AllureStep.Name = name
return qt
}
func (qt *cute) BeforeExecute(fs ...BeforeExecute) MiddlewareRequest {
qt.tests[qt.countTests].Middleware.Before = append(qt.tests[qt.countTests].Middleware.Before, fs...)
return qt
}
func (qt *cute) BeforeExecuteT(fs ...BeforeExecuteT) MiddlewareRequest {
qt.tests[qt.countTests].Middleware.BeforeT = append(qt.tests[qt.countTests].Middleware.BeforeT, fs...)
return qt
}
func (qt *cute) After(fs ...AfterExecute) ExpectHTTPBuilder {
qt.tests[qt.countTests].Middleware.After = append(qt.tests[qt.countTests].Middleware.After, fs...)
return qt
}
func (qt *cute) AfterT(fs ...AfterExecuteT) ExpectHTTPBuilder {
qt.tests[qt.countTests].Middleware.AfterT = append(qt.tests[qt.countTests].Middleware.AfterT, fs...)
return qt
}
func (qt *cute) AfterExecute(fs ...AfterExecute) MiddlewareRequest {
qt.tests[qt.countTests].Middleware.After = append(qt.tests[qt.countTests].Middleware.After, fs...)
return qt
}
func (qt *cute) AfterExecuteT(fs ...AfterExecuteT) MiddlewareRequest {
qt.tests[qt.countTests].Middleware.AfterT = append(qt.tests[qt.countTests].Middleware.AfterT, fs...)
return qt
}
func (qt *cute) AfterTestExecute(fs ...AfterExecute) NextTestBuilder {
previousTest := 0
if qt.countTests != 0 {
previousTest = qt.countTests - 1
}
qt.tests[previousTest].Middleware.After = append(qt.tests[previousTest].Middleware.After, fs...)
return qt
}
func (qt *cute) AfterTestExecuteT(fs ...AfterExecuteT) NextTestBuilder {
previousTest := 0
if qt.countTests != 0 {
previousTest = qt.countTests - 1
}
qt.tests[previousTest].Middleware.AfterT = append(qt.tests[previousTest].Middleware.AfterT, fs...)
return qt
}
================================================
FILE: builder_option.go
================================================
package cute
import (
"net/http"
"time"
)
type options struct {
httpClient *http.Client
httpTimeout time.Duration
httpRoundTripper http.RoundTripper
jsonMarshaler JSONMarshaler
middleware *Middleware
}
// Option ...
type Option func(*options)
// WithHTTPClient is a function for set custom http client
func WithHTTPClient(client *http.Client) Option {
return func(o *options) {
o.httpClient = client
}
}
// WithJSONMarshaler is a function for set custom json marshaler
func WithJSONMarshaler(m JSONMarshaler) Option {
return func(o *options) {
o.jsonMarshaler = m
}
}
// WithCustomHTTPTimeout is a function for set custom http client timeout
func WithCustomHTTPTimeout(t time.Duration) Option {
return func(o *options) {
o.httpTimeout = t
}
}
// WithCustomHTTPRoundTripper is a function for set custom http round tripper
func WithCustomHTTPRoundTripper(r http.RoundTripper) Option {
return func(o *options) {
o.httpRoundTripper = r
}
}
// WithMiddlewareAfter is function for set function which will run AFTER test execution
func WithMiddlewareAfter(after ...AfterExecute) Option {
return func(o *options) {
o.middleware.After = append(o.middleware.After, after...)
}
}
// WithMiddlewareAfterT is function for set function which will run AFTER test execution
func WithMiddlewareAfterT(after ...AfterExecuteT) Option {
return func(o *options) {
o.middleware.AfterT = append(o.middleware.AfterT, after...)
}
}
// WithMiddlewareBefore is function for set function which will run BEFORE test execution
func WithMiddlewareBefore(before ...BeforeExecute) Option {
return func(o *options) {
o.middleware.Before = append(o.middleware.Before, before...)
}
}
// WithMiddlewareBeforeT is function for set function which will run BEFORE test execution
func WithMiddlewareBeforeT(beforeT ...BeforeExecuteT) Option {
return func(o *options) {
o.middleware.BeforeT = append(o.middleware.BeforeT, beforeT...)
}
}
================================================
FILE: builder_request.go
================================================
package cute
import (
"net/http"
"time"
)
// RequestRepeat is a function for set options in request
// if response.Code != Expect.Code, than request will repeat Count counts with Delay delay.
// Default delay is 1 second.
// Deprecated: use RequestRetry instead
func (qt *cute) RequestRepeat(count int) RequestHTTPBuilder {
qt.tests[qt.countTests].Request.Retry.Count = count
return qt
}
// RequestRepeatDelay set delay for request repeat.
// if response.Code != Expect.Code, than request will repeat Count counts with Delay delay.
// Default delay is 1 second.
// Deprecated: use RequestRetryDelay instead
func (qt *cute) RequestRepeatDelay(delay time.Duration) RequestHTTPBuilder {
qt.tests[qt.countTests].Request.Retry.Delay = delay
return qt
}
// RequestRepeatPolitic set politic for request repeat.
// if response.Code != Expect.Code, than request will repeat Count counts with Delay delay.
// if Optional is true and request is failed, than test step allure will be skipped, and t.Fail() will not execute.
// If Broken is true and request is failed, than test step allure will be broken, and t.Fail() will not execute.
// Deprecated: use RequestRetryPolitic instead
func (qt *cute) RequestRepeatPolitic(politic *RequestRepeatPolitic) RequestHTTPBuilder {
if politic == nil {
panic("politic is nil in RequestRetryPolitic")
}
qt.tests[qt.countTests].Request.Retry = &RequestRetryPolitic{
Count: politic.Count,
Delay: politic.Delay,
Optional: politic.Optional,
Broken: politic.Broken,
}
return qt
}
// RequestRepeatOptional set option politic for request repeat.
// if Optional is true and request is failed, than test step allure will be skipped, and t.Fail() will not execute.
// Deprecated: use RequestRetryOptional instead
func (qt *cute) RequestRepeatOptional(option bool) RequestHTTPBuilder {
qt.tests[qt.countTests].Request.Retry.Optional = option
return qt
}
// RequestRepeatBroken set broken politic for request repeat.
// If Broken is true and request is failed, than test step allure will be broken, and t.Fail() will not execute.
// Deprecated: use RequestRetryBroken instead
func (qt *cute) RequestRepeatBroken(broken bool) RequestHTTPBuilder {
qt.tests[qt.countTests].Request.Retry.Broken = broken
return qt
}
// RequestRetry is a function for set options in request
// if response.Code != Expect.Code, than request will repeat Count counts with Delay delay.
// Default delay is 1 second.
func (qt *cute) RequestRetry(count int) RequestHTTPBuilder {
qt.tests[qt.countTests].Request.Retry.Count = count
return qt
}
// RequestRetryDelay set delay for request repeat.
// if response.Code != Expect.Code, than request will repeat Count counts with Delay delay.
// Default delay is 1 second.
func (qt *cute) RequestRetryDelay(delay time.Duration) RequestHTTPBuilder {
qt.tests[qt.countTests].Request.Retry.Delay = delay
return qt
}
// RequestRetryPolitic set politic for request repeat.
// if response.Code != Expect.Code, than request will repeat Count counts with Delay delay.
// if Optional is true and request is failed, than test step allure will be skipped, and t.Fail() will not execute.
// If Broken is true and request is failed, than test step allure will be broken, and t.Fail() will not execute.
func (qt *cute) RequestRetryPolitic(politic *RequestRetryPolitic) RequestHTTPBuilder {
if politic == nil {
panic("politic is nil in RequestRetryPolitic")
}
qt.tests[qt.countTests].Request.Retry = politic
return qt
}
// RequestRetryOptional set option politic for request repeat.
// if Optional is true and request is failed, than test step allure will be skipped, and t.Fail() will not execute.
func (qt *cute) RequestRetryOptional(option bool) RequestHTTPBuilder {
qt.tests[qt.countTests].Request.Retry.Optional = option
return qt
}
// RequestRetryBroken set broken politic for request repeat.
// If Broken is true and request is failed, than test step allure will be broken, and t.Fail() will not execute.
func (qt *cute) RequestRetryBroken(broken bool) RequestHTTPBuilder {
qt.tests[qt.countTests].Request.Retry.Broken = broken
return qt
}
// RequestSanitizerHook assigns the provided RequestSanitizerHook to the test,
// allowing URL sanitization before logging or reporting.
func (qt *cute) RequestSanitizerHook(hook RequestSanitizerHook) RequestHTTPBuilder {
qt.tests[qt.countTests].RequestSanitizer = hook
return qt
}
// ResponseSanitizerHook assigns the provided ResponseSanitizerHook to the test,
// allowing URL sanitization before logging or reporting.
func (qt *cute) ResponseSanitizerHook(hook ResponseSanitizerHook) RequestHTTPBuilder {
qt.tests[qt.countTests].ResponseSanitizer = hook
return qt
}
func (qt *cute) Request(r *http.Request) ExpectHTTPBuilder {
qt.tests[qt.countTests].Request.Base = r
return qt
}
func (qt *cute) RequestBuilder(r ...RequestBuilder) ExpectHTTPBuilder {
qt.tests[qt.countTests].Request.Builders = append(qt.tests[qt.countTests].Request.Builders, r...)
return qt
}
================================================
FILE: builder_retry.go
================================================
package cute
import "time"
// Retry is a function for configure test repeat
// if response.Code != Expect.Code or any of asserts are failed/broken than test will repeat counts with delay.
// Default delay is 1 second.
func (qt *cute) Retry(count int) MiddlewareRequest {
if count < 1 {
panic("count must be greater than 0")
}
qt.tests[qt.countTests].Retry.MaxAttempts = count
return qt
}
// RetryDelay set delay for test repeat.
// if response.Code != Expect.Code or any of asserts are failed/broken than test will repeat counts with delay.
// Default delay is 1 second.
func (qt *cute) RetryDelay(delay time.Duration) MiddlewareRequest {
if delay < 0 {
panic("delay must be greater than or equal to 0")
}
qt.tests[qt.countTests].Retry.Delay = delay
return qt
}
================================================
FILE: builder_table.go
================================================
package cute
import "net/http"
func (qt *cute) CreateTableTest() MiddlewareTable {
qt.isTableTest = true
return qt
}
func (qt *cute) PutNewTest(name string, r *http.Request, expect *Expect) TableTest {
// Validate, that first step is empty
if qt.countTests == 0 {
if qt.tests[0].Request.Base == nil &&
len(qt.tests[0].Request.Builders) == 0 {
qt.tests[0].Expect = expect
qt.tests[0].Name = name
qt.tests[0].Request.Base = r
return qt
}
}
newTest := createDefaultTest(qt.baseProps)
newTest.Expect = expect
newTest.Name = name
newTest.Request.Base = r
qt.tests = append(qt.tests, newTest)
qt.countTests++ // async?
return qt
}
func (qt *cute) PutTests(tests ...*Test) TableTest {
for _, test := range tests {
// Fill common fields
qt.fillBaseProps(test)
// Validate, that first step is empty
if qt.countTests == 0 {
if qt.tests[0].Request.Base == nil &&
len(qt.tests[0].Request.Builders) == 0 {
qt.tests[0] = test
continue
}
}
qt.tests = append(qt.tests, test)
qt.countTests++
}
return qt
}
func (qt *cute) fillBaseProps(t *Test) {
if qt.baseProps == nil {
return
}
if qt.baseProps.httpClient != nil {
t.httpClient = qt.baseProps.httpClient
}
if qt.baseProps.jsonMarshaler != nil {
t.jsonMarshaler = qt.baseProps.jsonMarshaler
}
if t.Middleware == nil {
t.Middleware = createMiddlewareFromTemplate(qt.baseProps.middleware)
} else {
t.Middleware.After = append(t.Middleware.After, qt.baseProps.middleware.After...)
t.Middleware.AfterT = append(t.Middleware.AfterT, qt.baseProps.middleware.AfterT...)
t.Middleware.Before = append(t.Middleware.Before, qt.baseProps.middleware.Before...)
t.Middleware.BeforeT = append(t.Middleware.BeforeT, qt.baseProps.middleware.BeforeT...)
}
}
func (qt *cute) NextTest() NextTestBuilder {
qt.countTests++ // async?
qt.tests = append(qt.tests, createDefaultTest(qt.baseProps))
return qt
}
================================================
FILE: builder_table_test.go
================================================
package cute
import (
"net/http"
"testing"
"github.com/stretchr/testify/require"
)
func TestFillBaseProps_WhenBasePropsIsNil(t *testing.T) {
testObj := &Test{}
cuteObj := &cute{}
cuteObj.fillBaseProps(testObj)
require.Nil(t, testObj.httpClient)
require.Nil(t, testObj.jsonMarshaler)
require.Nil(t, testObj.Middleware)
}
func TestFillBaseProps_WhenBasePropsIsNotNil(t *testing.T) {
testObj := &Test{}
cuteObj := &cute{}
qtBaseProps := &HTTPTestMaker{
httpClient: &http.Client{},
jsonMarshaler: &jsonMarshaler{},
middleware: &Middleware{
After: []AfterExecute{
func(*http.Response, []error) error {
return nil
},
func(*http.Response, []error) error {
return nil
},
},
AfterT: []AfterExecuteT{func(T, *http.Response, []error) error { return nil }},
Before: []BeforeExecute{
func(*http.Request) error {
return nil
},
func(*http.Request) error {
return nil
},
},
BeforeT: []BeforeExecuteT{
func(T, *http.Request) error { return nil },
func(T, *http.Request) error {
return nil
},
},
},
}
cuteObj.baseProps = qtBaseProps
cuteObj.fillBaseProps(testObj)
require.Equal(t, qtBaseProps.httpClient, testObj.httpClient)
require.Equal(t, qtBaseProps.jsonMarshaler, testObj.jsonMarshaler)
require.Len(t, testObj.Middleware.After, len(qtBaseProps.middleware.After))
require.Len(t, testObj.Middleware.AfterT, len(qtBaseProps.middleware.AfterT))
require.Len(t, testObj.Middleware.Before, len(qtBaseProps.middleware.Before))
require.Len(t, testObj.Middleware.BeforeT, len(qtBaseProps.middleware.BeforeT))
}
func TestFillBaseProps_WhenBasePropsIsNotNil_After(t *testing.T) {
testObj := &Test{
Middleware: &Middleware{
After: []AfterExecute{
func(*http.Response, []error) error {
return nil
},
},
},
}
cuteObj := &cute{}
qtBaseProps := &HTTPTestMaker{
httpClient: &http.Client{},
jsonMarshaler: &jsonMarshaler{},
middleware: &Middleware{
After: []AfterExecute{
func(*http.Response, []error) error {
return nil
},
func(*http.Response, []error) error {
return nil
},
},
BeforeT: []BeforeExecuteT{
func(T, *http.Request) error { return nil },
func(T, *http.Request) error {
return nil
},
},
},
}
cuteObj.baseProps = qtBaseProps
cuteObj.fillBaseProps(testObj)
require.Equal(t, qtBaseProps.httpClient, testObj.httpClient)
require.Equal(t, qtBaseProps.jsonMarshaler, testObj.jsonMarshaler)
require.Len(t, testObj.Middleware.After, len(qtBaseProps.middleware.After)+1)
require.Len(t, testObj.Middleware.AfterT, len(qtBaseProps.middleware.AfterT))
require.Len(t, testObj.Middleware.Before, len(qtBaseProps.middleware.Before))
require.Len(t, testObj.Middleware.BeforeT, len(qtBaseProps.middleware.BeforeT))
}
func TestFillBaseProps_WhenBasePropsIsNotNil_Middleware(t *testing.T) {
testObj := &Test{
Middleware: &Middleware{
After: []AfterExecute{
func(*http.Response, []error) error {
return nil
},
func(*http.Response, []error) error {
return nil
},
},
AfterT: []AfterExecuteT{
func(T, *http.Response, []error) error {
return nil
},
func(T, *http.Response, []error) error {
return nil
},
func(T, *http.Response, []error) error {
return nil
},
},
Before: []BeforeExecute{
func(*http.Request) error {
return nil
},
func(*http.Request) error {
return nil
},
func(*http.Request) error {
return nil
},
func(*http.Request) error {
return nil
},
},
BeforeT: []BeforeExecuteT{
func(T, *http.Request) error {
return nil
},
},
},
}
cuteObj := &cute{}
qtBaseProps := &HTTPTestMaker{
httpClient: &http.Client{},
jsonMarshaler: &jsonMarshaler{},
middleware: &Middleware{
After: []AfterExecute{
func(*http.Response, []error) error {
return nil
},
func(*http.Response, []error) error {
return nil
},
},
AfterT: []AfterExecuteT{func(T, *http.Response, []error) error { return nil }},
Before: []BeforeExecute{
func(*http.Request) error {
return nil
},
func(*http.Request) error {
return nil
},
},
BeforeT: []BeforeExecuteT{
func(T, *http.Request) error { return nil },
func(T, *http.Request) error {
return nil
},
},
},
}
cuteObj.baseProps = qtBaseProps
cuteObj.fillBaseProps(testObj)
require.Equal(t, qtBaseProps.httpClient, testObj.httpClient)
require.Equal(t, qtBaseProps.jsonMarshaler, testObj.jsonMarshaler)
require.Len(t, testObj.Middleware.After, len(qtBaseProps.middleware.After)+2)
require.Len(t, testObj.Middleware.AfterT, len(qtBaseProps.middleware.AfterT)+3)
require.Len(t, testObj.Middleware.Before, len(qtBaseProps.middleware.Before)+4)
require.Len(t, testObj.Middleware.BeforeT, len(qtBaseProps.middleware.BeforeT)+1)
}
================================================
FILE: builder_test.go
================================================
package cute
import (
"net/http"
"testing"
"time"
"github.com/ozontech/allure-go/pkg/allure"
"github.com/stretchr/testify/require"
)
func TestBuilderAfterTest(t *testing.T) {
var (
maker = NewHTTPTestMaker()
)
ht := maker.NewTestBuilder().
Create().
RequestBuilder().
NextTest().
AfterTestExecute(
func(response *http.Response, errors []error) error {
return nil
},
func(response *http.Response, errors []error) error {
return nil
}).
AfterTestExecuteT(
func(t T, response *http.Response, errors []error) error {
return nil
},
func(t T, response *http.Response, errors []error) error {
return nil
},
func(t T, response *http.Response, errors []error) error {
return nil
},
)
res := ht.(*cute)
require.Len(t, res.tests[0].Middleware.After, 2)
require.Len(t, res.tests[0].Middleware.AfterT, 3)
}
func TestBuilderAfterTestTwoStep(t *testing.T) {
var (
maker = NewHTTPTestMaker(
WithMiddlewareBefore(
func(request *http.Request) error {
return nil
},
func(request *http.Request) error {
return nil
},
),
WithMiddlewareBeforeT(
func(t T, request *http.Request) error {
return nil
},
),
WithMiddlewareAfter(
func(response *http.Response, errors []error) error {
return nil
},
),
WithMiddlewareAfterT(
func(t T, response *http.Response, errors []error) error {
return nil
},
func(t T, response *http.Response, errors []error) error {
return nil
},
func(t T, response *http.Response, errors []error) error {
return nil
},
),
)
)
ht :=
maker.NewTestBuilder().
Create().
RequestBuilder().
NextTest().
AfterTestExecute(
func(response *http.Response, errors []error) error {
return nil
},
func(response *http.Response, errors []error) error {
return nil
}).
AfterTestExecuteT(
func(t T, response *http.Response, errors []error) error {
return nil
},
func(t T, response *http.Response, errors []error) error {
return nil
},
func(t T, response *http.Response, errors []error) error {
return nil
},
).
Create().
AfterExecute(
func(response *http.Response, errors []error) error {
return nil
},
).
AfterExecuteT(
func(t T, response *http.Response, errors []error) error {
return nil
}).
RequestBuilder().
NextTest().
AfterTestExecute(
func(response *http.Response, errors []error) error {
return nil
},
)
res := ht.(*cute)
require.Len(t, res.tests[0].Middleware.After, 2+1)
require.Len(t, res.tests[0].Middleware.Before, 2)
require.Len(t, res.tests[0].Middleware.BeforeT, 1)
require.Len(t, res.tests[0].Middleware.AfterT, 3+3)
require.Len(t, res.tests[1].Middleware.After, 2+1)
require.Len(t, res.tests[1].Middleware.AfterT, 1+3)
require.Len(t, res.tests[1].Middleware.Before, 2)
require.Len(t, res.tests[1].Middleware.BeforeT, 1)
}
func TestNewTestBuilder(t *testing.T) {
var (
maker = NewHTTPTestMaker()
ht = maker.NewTestBuilder().(*cute)
)
require.NotNil(t, ht.tests)
require.Len(t, ht.tests, 1)
require.NotNil(t, ht.tests[0].Request)
require.NotNil(t, ht.tests[0].Middleware)
require.NotNil(t, ht.tests[0].AllureStep)
require.NotNil(t, ht.allureInfo)
require.NotNil(t, ht.baseProps.httpClient)
}
func TestHTTPTestMaker(t *testing.T) {
var (
maker = NewHTTPTestMaker()
ht = maker.NewTestBuilder()
title = "title"
epic = "epic"
desc = "desc"
feature = "feature"
tags = []string{"tag_1", "tag_2"}
stepName = "stepname"
req, _ = http.NewRequest(http.MethodGet, "https://site.go", nil)
executeTime = time.Duration(10)
status = 400
schemaStg = "some_json_schema"
schemaBt = []byte("some_json_schema")
schemaFile = "file_path"
id = "ID"
addSuiteLabel = "AddSuiteLabel"
addSubSuite = "AddSubSuite"
addParentSuite = "AddParentSuite"
story = "Story"
tag = "Tag"
allureID = "AllureID"
owner = "Owner"
lead = "Lead"
label = &allure.Label{Name: "kek", Value: "lol"}
setIssue = "SetIssue"
setTestCase = "SetTestCase"
repeatCount = 10
repeatDelay = time.Duration(10)
link = &allure.Link{
Name: "link",
Type: "type",
URL: "http://go.go",
}
labels = []*allure.Label{
{
Name: "label_1",
Value: "value_1",
},
{
Name: "label_2",
Value: "value_2",
},
}
assertHeaders = []AssertHeaders{
func(headers http.Header) error {
return nil
},
}
assertHeadersT = []AssertHeadersT{
func(t T, headers http.Header) error {
return nil
},
func(t T, headers http.Header) error {
return nil
},
}
assertBody = []AssertBody{
func(body []byte) error {
return nil
},
}
assertBodyT = []AssertBodyT{
func(t T, body []byte) error {
return nil
},
func(t T, body []byte) error {
return nil
},
}
assertResponse = []AssertResponse{
func(resp *http.Response) error {
return nil
},
}
assertResponseT = []AssertResponseT{
func(t T, resp *http.Response) error {
return nil
},
func(t T, resp *http.Response) error {
return nil
},
}
after = []AfterExecute{
func(response *http.Response, errors []error) error {
return nil
},
func(response *http.Response, errors []error) error {
return nil
},
}
afterT = []AfterExecuteT{
func(t T, response *http.Response, errors []error) error {
return nil
},
func(t T, response *http.Response, errors []error) error {
return nil
},
}
)
ht.
Title(title).
Tags(tags...).
Epic(epic).
Feature(feature).
ID(id).
AddSuiteLabel(addSuiteLabel).
AddSubSuite(addSubSuite).
AddParentSuite(addParentSuite).
Story(story).
Tag(tag).
Severity(allure.CRITICAL).
AllureID(allureID).
Owner(owner).
Lead(lead).
Label(label).
Labels(labels...).
SetIssue(setIssue).
SetTestCase(setTestCase).
Link(link).
Description(desc).
CreateStep(stepName).
RequestRetry(repeatCount).
RequestRetryDelay(repeatDelay).
Request(req).
ExpectExecuteTimeout(executeTime).
ExpectStatus(status).
ExpectJSONSchemaByte(schemaBt).
ExpectJSONSchemaString(schemaStg).
ExpectJSONSchemaFile(schemaFile).
AssertHeaders(assertHeaders...).
AssertHeadersT(assertHeadersT...).
AssertBody(assertBody...).
AssertBodyT(assertBodyT...).
AssertResponse(assertResponse...).
AssertResponseT(assertResponseT...).
After(after...).
AfterT(afterT...)
resHt := ht.(*cute)
resTest := resHt.tests[0]
require.Equal(t, title, resHt.allureInfo.title)
require.Equal(t, tags, resHt.allureLabels.tags)
require.Equal(t, desc, resHt.allureInfo.description)
require.Equal(t, feature, resHt.allureLabels.feature)
require.Equal(t, epic, resHt.allureLabels.epic)
require.Equal(t, stepName, resTest.AllureStep.Name)
require.Equal(t, req, resTest.Request.Base)
require.Equal(t, executeTime, resTest.Expect.ExecuteTime)
require.Equal(t, status, resTest.Expect.Code)
require.Equal(t, schemaBt, resTest.Expect.JSONSchema.Byte)
require.Equal(t, schemaStg, resTest.Expect.JSONSchema.String)
require.Equal(t, schemaFile, resTest.Expect.JSONSchema.File)
require.Equal(t, id, resHt.allureLabels.id)
require.Equal(t, addSuiteLabel, resHt.allureLabels.suiteLabel)
require.Equal(t, addSubSuite, resHt.allureLabels.subSuite)
require.Equal(t, addParentSuite, resHt.allureLabels.parentSuite)
require.Equal(t, story, resHt.allureLabels.story)
require.Equal(t, tag, resHt.allureLabels.tag)
require.Equal(t, owner, resHt.allureLabels.owner)
require.Equal(t, lead, resHt.allureLabels.lead)
require.Equal(t, label, resHt.allureLabels.label)
require.Equal(t, allureID, resHt.allureLabels.allureID)
require.Equal(t, setIssue, resHt.allureLinks.issue)
require.Equal(t, setTestCase, resHt.allureLinks.testCase)
require.Equal(t, link, resHt.allureLinks.link)
require.Equal(t, repeatCount, resTest.Request.Retry.Count)
require.Equal(t, repeatDelay, resTest.Request.Retry.Delay)
require.Equal(t, len(assertHeaders), len(resTest.Expect.AssertHeaders))
require.Equal(t, len(assertHeadersT), len(resTest.Expect.AssertHeadersT))
require.Equal(t, len(assertBody), len(resTest.Expect.AssertBody))
require.Equal(t, len(assertBodyT), len(resTest.Expect.AssertBodyT))
require.Equal(t, len(assertResponse), len(resTest.Expect.AssertResponse))
require.Equal(t, len(assertResponseT), len(resTest.Expect.AssertResponseT))
require.Equal(t, len(after), len(resTest.Middleware.After))
require.Equal(t, len(afterT), len(resTest.Middleware.AfterT))
}
func TestCreateDefaultTest(t *testing.T) {
resTest := createDefaultTest(&HTTPTestMaker{httpClient: http.DefaultClient, middleware: new(Middleware)})
require.Equal(t, &Test{
httpClient: http.DefaultClient,
Name: "",
AllureStep: new(AllureStep),
Middleware: &Middleware{
After: make([]AfterExecute, 0),
AfterT: make([]AfterExecuteT, 0),
Before: make([]BeforeExecute, 0),
BeforeT: make([]BeforeExecuteT, 0),
},
Request: &Request{
Retry: new(RequestRetryPolitic),
},
Expect: &Expect{
JSONSchema: new(ExpectJSONSchema),
},
}, resTest)
}
func TestCreateTableTest(t *testing.T) {
c := &cute{}
c.CreateTableTest()
require.True(t, c.isTableTest)
}
func TestPutNewTest(t *testing.T) {
tests := make([]*Test, 1)
tests[0] = createDefaultTest(&HTTPTestMaker{httpClient: http.DefaultClient, middleware: new(Middleware)})
var (
c = &cute{tests: tests, baseProps: &HTTPTestMaker{
middleware: &Middleware{},
}}
reqOne, _ = http.NewRequest("GET", "URL_1", nil)
expectOne = &Expect{Code: 200}
reqSecond, _ = http.NewRequest("POST", "URL_1", nil)
expectSecond = &Expect{Code: 400}
)
c.PutNewTest("name_1", reqOne, expectOne)
c.PutNewTest("name_2", reqSecond, expectSecond)
require.Equal(t, c.tests[0].Name, "name_1")
require.Equal(t, c.tests[0].Expect, expectOne)
require.Equal(t, c.tests[0].Request.Base, reqOne)
require.Equal(t, c.tests[1].Name, "name_2")
require.Equal(t, c.tests[1].Expect, expectSecond)
require.Equal(t, c.tests[1].Request.Base, reqSecond)
}
func TestPutTests(t *testing.T) {
var (
tests = createDefaultTests(&HTTPTestMaker{httpClient: http.DefaultClient, middleware: new(Middleware)})
c = &cute{tests: tests}
reqOne, _ = http.NewRequest("GET", "URL_1", nil)
expectOne = &Expect{Code: 200}
reqSecond, _ = http.NewRequest("POST", "URL_1", nil)
expectSecond = &Expect{Code: 400}
)
tests = append(tests,
&Test{
Name: "name_1",
Request: &Request{
Base: reqOne,
},
Expect: expectOne,
},
&Test{
Name: "name_2",
Request: &Request{
Base: reqSecond,
},
Expect: expectSecond,
},
)
c.PutTests(tests...)
require.Equal(t, c.tests[0].Name, "name_1")
require.Equal(t, c.tests[0].Expect, expectOne)
require.Equal(t, c.tests[0].Request.Base, reqOne)
require.Equal(t, c.tests[1].Name, "name_2")
require.Equal(t, c.tests[1].Expect, expectSecond)
require.Equal(t, c.tests[1].Request.Base, reqSecond)
}
func TestCreateHTTPTestMakerWithHttpClient(t *testing.T) {
cli := &http.Client{
Transport: nil,
CheckRedirect: nil,
Jar: nil,
Timeout: 100,
}
maker := NewHTTPTestMaker(WithHTTPClient(cli))
require.Equal(t, cli, maker.httpClient)
require.Equal(t, time.Duration(100), maker.httpClient.Timeout)
}
type rt struct {
}
func (r *rt) RoundTrip(*http.Request) (*http.Response, error) {
return nil, nil
}
func TestCreateHTTPMakerOps(t *testing.T) {
timeout := time.Second * 100
roundTripper := &rt{}
maker := NewHTTPTestMaker(
WithCustomHTTPTimeout(timeout),
WithCustomHTTPRoundTripper(roundTripper),
)
require.Equal(t, timeout, maker.httpClient.Timeout)
require.Equal(t, roundTripper, maker.httpClient.Transport)
}
================================================
FILE: cute.go
================================================
package cute
import (
"context"
"strings"
"testing"
"github.com/ozontech/allure-go/pkg/allure"
"github.com/ozontech/allure-go/pkg/framework/core/allure_manager/manager"
"github.com/ozontech/allure-go/pkg/framework/core/common"
"github.com/ozontech/allure-go/pkg/framework/provider"
)
type cute struct {
baseProps *HTTPTestMaker
parallel bool
allureInfo *allureInformation
allureLinks *allureLinks
allureLabels *allureLabels
countTests int // Общее количество тестов.
isTableTest bool
tests []*Test
}
type allureInformation struct {
title string
description string
stage string
}
type allureLabels struct {
id string
feature string
epic string
tag string
tags []string
suiteLabel string
subSuite string
parentSuite string
story string
severity allure.SeverityType
owner string
lead string
label *allure.Label
labels []*allure.Label
allureID string
layer string
}
type allureLinks struct {
issue string
testCase string
link *allure.Link
tmsLink string
tmsLinks []string
}
func (qt *cute) ExecuteTest(ctx context.Context, t tProvider) []ResultsHTTPBuilder {
var internalT allureProvider
if t == nil {
panic("could not start test without testing.T")
}
stepCtx, isStepCtx := t.(provider.StepCtx)
if isStepCtx {
return qt.executeTestsInsideStep(ctx, stepCtx)
}
tOriginal, ok := t.(*testing.T)
if ok {
newT := createAllureT(tOriginal)
if !qt.isTableTest {
defer newT.FinishTest() //nolint
}
internalT = newT
}
allureT, ok := t.(provider.T)
if ok {
internalT = allureT
}
if qt.parallel {
internalT.Parallel()
}
return qt.executeTests(ctx, internalT)
}
func createAllureT(t *testing.T) *common.Common {
var (
newT = common.NewT(t)
callers = strings.Split(t.Name(), "/")
providerCfg = manager.NewProviderConfig().
WithFullName(t.Name()).
WithPackageName("package").
WithSuiteName(t.Name()).
WithRunner(callers[0])
newProvider = manager.NewProvider(providerCfg)
)
newProvider.NewTest(t.Name(), "package")
newT.SetProvider(newProvider)
newT.Provider.TestContext()
return newT
}
// executeTests is method for run tests
// It's could be table tests or usual tests
func (qt *cute) executeTests(ctx context.Context, allureProvider allureProvider) []ResultsHTTPBuilder {
var (
res = make([]ResultsHTTPBuilder, 0)
)
// Cycle for change number of Test
for i := 0; i <= qt.countTests; i++ {
currentTest := qt.tests[i]
// Execute by new T for table tests
if qt.isTableTest {
tableTestName := currentTest.Name
allureProvider.Run(tableTestName, func(inT provider.T) {
// Set current test name
inT.Title(tableTestName)
res = append(res, qt.executeInsideAllure(ctx, inT, currentTest))
})
} else {
currentTest.Name = allureProvider.Name()
// set labels
qt.setAllureInformation(allureProvider)
res = append(res, qt.executeInsideAllure(ctx, allureProvider, currentTest))
}
}
return res
}
// executeInsideAllure is method for run test inside allure
// It's could be table tests or usual tests
func (qt *cute) executeInsideAllure(ctx context.Context, allureProvider allureProvider, currentTest *Test) ResultsHTTPBuilder {
resT := currentTest.executeInsideAllure(ctx, allureProvider)
// Remove from base struct all asserts
currentTest.clearFields()
return resT
}
// executeTestsInsideStep is method for run group of tests inside provider.StepCtx
func (qt *cute) executeTestsInsideStep(ctx context.Context, stepCtx provider.StepCtx) []ResultsHTTPBuilder {
var (
res = make([]ResultsHTTPBuilder, 0)
)
// Cycle for change number of Test
for i := 0; i <= qt.countTests; i++ {
currentTest := qt.tests[i]
result := currentTest.executeInsideStep(ctx, stepCtx)
// Remove from base struct all asserts
currentTest.clearFields()
res = append(res, result)
}
return res
}
================================================
FILE: errors/broken.go
================================================
package errors
// BrokenError is an interface for set errors like Broken errors.
// If the function returns an error, which implements this interface, the allure step will has a broken status
type BrokenError interface {
IsBroken() bool
SetBroken(bool)
Error() string
}
// NewBrokenError returns error with a Broken tag for Allure
func NewBrokenError(err string) error {
return &CuteError{
Broken: true,
Message: err,
}
}
// WrapBrokenError returns error with a Broken tag for Allure
func WrapBrokenError(err error) error {
return &CuteError{
Broken: true,
Err: err,
}
}
================================================
FILE: errors/error.go
================================================
package errors
import "fmt"
const (
// ActualField is a key for actual value in error fields
ActualField = "Actual"
// ExpectedField is a key for expected value in error fields
ExpectedField = "Expected"
)
// AssertError is a common interface for all errors in the package
type AssertError interface {
error
WithNameError
WithFields
WithAttachments
WithTrace
}
// WithNameError is interface for creates allure step.
// If function returns error, which implement this interface, allure step will create automatically
type WithNameError interface {
GetName() string
SetName(string)
}
// WithFields is interface for put parameters in allure step.
// If function returns error, which implement this interface, parameters will add to allure step
type WithFields interface {
GetFields() map[string]interface{}
PutFields(map[string]interface{})
}
// WithTrace is interface for put trace in logs
type WithTrace interface {
GetTrace() string
SetTrace(string)
}
// Attachment represents an attachment to Allure with properties like name, MIME type, and content.
type Attachment struct {
Name string // Name of the attachment.
MimeType string // MIME type of the attachment.
Content []byte // Content of the attachment.
}
// WithAttachments is an interface that defines methods for managing attachments.
type WithAttachments interface {
GetAttachments() []*Attachment
PutAttachment(a *Attachment)
}
// CuteError is a struct for error with additional fields for allure and logs
type CuteError struct {
// Optional is a flag to determine if the error is optional
// If the error is optional, it will not fail the test
Optional bool
// Require is a flag to determine if the error is required
// If the error is required, it will fail the test
Require bool
// Broken is a flag to determine if the error is broken
// If the error is broken, it will fail the test and mark the test as broken in allure
Broken bool
// Name is a name of the error
Name string
// Message is a message of the error
Message string
// Err is a wrapped error
Err error
// Trace is a trace of the error
// It could be a file path, function name, or any other information
Trace string
// Fields is a map of additional fields for the error
// It could be actual and expected values, parameters, or any other information
// ActualField and ExpectedField fields will be logged
Fields map[string]interface{}
// Attachments is a slice of attachments for the error
Attachments []*Attachment
}
// NewCuteError is the function, which creates cute error with "Name" and "Message" for allure
func NewCuteError(name string, err error) *CuteError {
return &CuteError{
Name: name,
Err: err,
}
}
// NewAssertError is the function, which creates error with "Actual" and "Expected" for allure
func NewAssertError(name string, message string, actual interface{}, expected interface{}) error {
return &CuteError{
Name: name,
Message: message,
Fields: map[string]interface{}{
ActualField: actual,
ExpectedField: expected,
},
}
}
// NewAssertErrorWithMessage is the function, which creates error with "Name" and "Message" for allure
// Deprecated: use NewEmptyAssertError instead
func NewAssertErrorWithMessage(name string, message string) error {
return NewEmptyAssertError(name, message)
}
// NewEmptyAssertError is the function, which creates error with "Name" and "Message" for allure
// Returns AssertError with empty fields
// You can use PutFields and PutAttachment to add additional information
// You can use SetOptional, SetRequire, SetBroken to change error behavior
func NewEmptyAssertError(name string, message string) AssertError {
return &CuteError{
Name: name,
Message: message,
Fields: map[string]interface{}{},
}
}
// Unwrap is a method to get wrapped error
// It is used for errors.Is and errors.As functions
func (a *CuteError) Unwrap() error {
return a.Err
}
// Error is a method to get error message
// It is used for fmt.Errorf and fmt.Println functions
func (a *CuteError) Error() string {
if a.Trace == "" {
return a.Message
}
errText := a.Message
if a.Err != nil {
errText = a.Err.Error()
}
return fmt.Sprintf("%s\nCalled from: %s", errText, a.Trace)
}
// GetName is a method to get error name
// It is used for allure step name
func (a *CuteError) GetName() string {
return a.Name
}
// SetName is a method to set error name
// It is used for allure step name
func (a *CuteError) SetName(name string) {
a.Name = name
}
// GetFields ...
func (a *CuteError) GetFields() map[string]interface{} {
return a.Fields
}
// PutFields ...
func (a *CuteError) PutFields(fields map[string]interface{}) {
for k, v := range fields {
a.Fields[k] = v
}
}
// GetAttachments ...
func (a *CuteError) GetAttachments() []*Attachment {
return a.Attachments
}
// PutAttachment ...
func (a *CuteError) PutAttachment(attachment *Attachment) {
a.Attachments = append(a.Attachments, attachment)
}
// IsOptional ...
func (a *CuteError) IsOptional() bool {
return a.Optional
}
// SetOptional ...
func (a *CuteError) SetOptional(opt bool) {
a.Optional = opt
}
// IsRequire ...
func (a *CuteError) IsRequire() bool {
return a.Require
}
// SetRequire ...
func (a *CuteError) SetRequire(b bool) {
a.Require = b
}
// IsBroken ...
func (a *CuteError) IsBroken() bool {
return a.Broken
}
// SetBroken ...
func (a *CuteError) SetBroken(b bool) {
a.Broken = b
}
// GetTrace ...
func (a *CuteError) GetTrace() string {
return a.Trace
}
// SetTrace ...
func (a *CuteError) SetTrace(trace string) {
a.Trace = trace
}
================================================
FILE: errors/optional.go
================================================
package errors
// OptionalError is an interface for set errors like Optional errors.
// If the function returns an error, which implements this interface, the allure step will has to skip status
type OptionalError interface {
IsOptional() bool
SetOptional(bool)
}
// NewOptionalError returns error with an Optional tag for Allure
func NewOptionalError(err string) error {
return &CuteError{
Optional: true,
Message: err,
}
}
// WrapOptionalError returns error with an Optional tag for Allure
func WrapOptionalError(err error) error {
return &CuteError{
Optional: true,
Err: err,
}
}
================================================
FILE: errors/require.go
================================================
package errors
// RequireError is an interface for set errors like require error.
// If the function returns an error, which implements this interface, the allure step will has failed status
type RequireError interface {
IsRequire() bool
SetRequire(bool)
}
type requireError struct {
err error
require bool
}
// NewRequireError returns error with flag for execute t.FailNow() and finish test after this error
func NewRequireError(err string) error {
return &CuteError{
Require: true,
Message: err,
}
}
// WrapRequireError returns error with flag for execute t.FailNow() and finish test after this error
func WrapRequireError(err error) error {
return &CuteError{
Require: true,
Err: err,
}
}
================================================
FILE: errors/trace.go
================================================
package errors
// NewErrorWithTrace is a function for create error with trace
func NewErrorWithTrace(err, trace string) error {
return &CuteError{
Trace: trace,
Message: err,
}
}
// WrapErrorWithTrace is a function for wrap error with trace
func WrapErrorWithTrace(err error, trace string) error {
return &CuteError{
Trace: trace,
Err: err,
}
}
================================================
FILE: examples/custom_asserts.go
================================================
package examples
import (
"errors"
"net/http"
"github.com/ozontech/allure-go/pkg/allure"
"github.com/ozontech/cute"
cuteErrors "github.com/ozontech/cute/errors"
"github.com/stretchr/testify/require"
)
func CustomAssertBodyWithCustomError() cute.AssertBody {
return func(bytes []byte) error {
if len(bytes) == 0 {
return cuteErrors.NewAssertError("customAssertBodyWithCustomError", "body must be not empty", "len is 0", "len more 0")
}
return nil
}
}
func CustomAssertBody() cute.AssertBody {
return func(bytes []byte) error {
if len(bytes) == 0 {
return errors.New("response body is empty")
}
return nil
}
}
func CustomAssertBodyT() cute.AssertBodyT {
return func(t cute.T, bytes []byte) error {
t.WithNewParameters("example_parameter", "example")
require.GreaterOrEqual(t, len(bytes), 100)
return nil
}
}
func CustomAssertBodyWithAllureStep() cute.AssertBodyT {
return func(t cute.T, bytes []byte) error {
step := allure.NewSimpleStep("Custom assert step")
defer func() {
t.Step(step)
}()
if len(bytes) == 0 {
step.Status = allure.Failed
step.WithAttachments(allure.NewAttachment("Error", allure.Text, []byte("response body is empty")))
return nil
}
return nil
}
}
func CustomAssertHeaders() cute.AssertHeaders {
return func(headers http.Header) error {
if len(headers) == 0 {
return errors.New("response without headers")
}
return nil
}
}
func CustomAssertResponse() cute.AssertResponse {
return func(resp *http.Response) error {
if resp.ContentLength == 0 {
return errors.New("content length is zero")
}
return nil
}
}
================================================
FILE: examples/inside_step_test.go
================================================
//go:build example
// +build example
package examples
import (
"context"
"net/http"
"net/url"
"testing"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
"github.com/ozontech/cute"
)
func TestInsideStep(t *testing.T) {
runner.Run(t, "Single test with allure-go Runner", func(t provider.T) {
t.WithNewStep("First step", func(sCtx provider.StepCtx) {
sCtx.NewStep("Inside first step")
})
t.WithNewStep("Step name", func(sCtx provider.StepCtx) {
u, _ := url.Parse("https://jsonplaceholder.typicode.com/posts/1/comments")
cute.NewTestBuilder().
Title("Super simple test").
Tags("simple", "suite", "some_local_tag", "json").
Parallel().
Create().
RequestBuilder(
cute.WithHeaders(map[string][]string{
"some_header": []string{"something"},
}),
cute.WithURL(u),
cute.WithMethod(http.MethodPost),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusCreated).
ExecuteTest(context.Background(), sCtx)
})
})
}
================================================
FILE: examples/masked_data_test.go
================================================
//go:build example
// +build example
package examples
import (
"context"
"net/http"
"net/url"
"testing"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
"github.com/ozontech/cute"
)
func TestSanitizer(t *testing.T) {
runner.Run(t, "Single test with request and response sanitizer", func(t provider.T) {
t.WithNewStep("First step", func(sCtx provider.StepCtx) {
sCtx.NewStep("Inside first step")
})
t.WithNewStep("Step name", func(sCtx provider.StepCtx) {
u, _ := url.Parse("https://jsonplaceholder.typicode.com/posts/1/comments?example=11")
query := u.Query()
query.Set("name", "Vasya")
u.RawQuery = query.Encode()
cute.NewTestBuilder().
Title("Super simple test").
Tags("simple", "suite", "some_local_tag", "json").
Parallel().
Create().
RequestSanitizerHook(func(req *http.Request) {
req.URL.Path = "/path/masked"
values := req.URL.Query()
values.Set("example", "masked")
req.URL.RawQuery = values.Encode()
req.Header["some_header"] = []string{"masked"}
}).
ResponseSanitizerHook(func(resp *http.Response) {
resp.Header["some_header"] = []string{"masked"}
resp.Header["Content-Type"] = []string{"masked"}
}).
RequestBuilder(
cute.WithHeaders(map[string][]string{
"some_header": []string{"something"},
}),
cute.WithURL(u),
cute.WithMethod(http.MethodPost),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusCreated).
ExecuteTest(context.Background(), sCtx)
})
})
}
================================================
FILE: examples/parallel_test.go
================================================
//go:build example
// +build example
package examples
import (
"context"
"net/http"
"testing"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/cute"
)
func Test_Async_1(t *testing.T) {
cute.NewTestBuilder().
Title("Title async test 1").
Tags("parallel_test").
Parallel().
Create().
BeforeExecuteT(
func(t cute.T, r *http.Request) error {
t.WithNewStep("insideBefore", func(stepCtx provider.StepCtx) {
time.Sleep(time.Second)
now := time.Now()
stepCtx.Logf("Test 1. Start time %v", now)
stepCtx.WithNewParameters("Test 1. Time", now)
})
return nil
},
).
AfterExecuteT(
func(t cute.T, resp *http.Response, errs []error) error {
t.WithNewStep("insideAfter", func(stepCtx provider.StepCtx) {
now := time.Now()
stepCtx.Logf("Test 1. Stop time %v", now)
stepCtx.WithNewParameters("Test 1. Stop time", now)
})
return nil
}).
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
).
ExecuteTest(context.Background(), t)
}
func Test_Async_2(t *testing.T) {
cute.NewTestBuilder().
Title("Title async test 2").
Tags("parallel_test").
Parallel().
Create().
BeforeExecuteT(
func(t cute.T, r *http.Request) error {
t.WithNewStep("insideBefore", func(stepCtx provider.StepCtx) {
now := time.Now()
stepCtx.Logf("Test 2. Start time %v", now)
stepCtx.WithNewParameters("Test 2. Start time", now)
time.Sleep(2 * time.Second)
})
return nil
},
).
AfterExecuteT(
func(t cute.T, resp *http.Response, errs []error) error {
t.WithNewStep("insideAfter", func(stepCtx provider.StepCtx) {
now := time.Now()
stepCtx.Logf("test 2. Stop time %v", now)
stepCtx.WithNewParameters("Test 2. Stop time", now)
})
return nil
}).
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
).
ExpectStatus(200).
ExecuteTest(context.Background(), t)
}
================================================
FILE: examples/single_test.go
================================================
//go:build example
// +build example
package examples
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"path"
"testing"
"time"
"github.com/ozontech/allure-go/pkg/allure"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
cuteErrors "github.com/ozontech/cute/errors"
"github.com/ozontech/cute"
"github.com/ozontech/cute/asserts/json"
)
func Test_Single_1(t *testing.T) {
cute.NewTestBuilder().
Title("Single test with default T").
Tag("single_test").
Description("some_description").
Parallel().
Create().
RequestRetry(3).
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMarshalBody(struct {
Name string `json:"name"`
}{
Name: "Vasya Pupkin",
}),
cute.WithQueryKV("socks", "42"),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusOK).
AssertBody(json.Diff("{\"aaa\":\"bb\"}")).
AssertBody(
json.Present("$[1].name"),
json.Present("$[0].passport"), // Example fail
json.Equal("$[0].email", "Eliseo@gardner.biz"),
CustomAssertBody(),
).
AssertBodyT(func(t cute.T, body []byte) error {
t.Step(allure.NewSimpleStep("inside Assert body. 1 ", allure.NewParameters("key", "value")...))
return nil
}).
After(
func(response *http.Response, errors []error) error {
b, err := io.ReadAll(response.Body)
if err != nil {
return err
}
email, err := json.GetValueFromJSON(b, "$[0].email")
if err != nil {
return err
}
fmt.Println("Email from test", email)
return nil
},
).
ExecuteTest(context.Background(), t)
}
func Test_Single_Broken(t *testing.T) {
cute.NewTestBuilder().
Title("Test_Single_Broken").
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
).
BrokenAssertBodyT(func(t cute.T, body []byte) error {
return errors.New("example broken error")
}).
ExpectStatus(http.StatusOK).
NextTest().
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
).
AssertBody(func(body []byte) error {
return errors.New("it's NOT must be run")
},
).
ExecuteTest(context.Background(), t)
t.Skip()
}
func Test_Single_RepeatPolitic_Optional_Success_Test(t *testing.T) {
cute.NewTestBuilder().
Title("Test_Single_RepeatPolitic_Optional_Success_Test").
Create().
RequestRetry(2).
RequestRetryOptional(true).
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
).
BrokenAssertBodyT(func(t cute.T, body []byte) error {
return errors.New("example broken error")
}).
ExpectStatus(http.StatusCreated).
ExecuteTest(context.Background(), t)
t.Logf("You should see it")
}
func Test_Single_RepeatPolitic_Broken_Failed_Test(t *testing.T) {
cute.NewTestBuilder().
Title("Test_Single_RepeatPolitic_Broken_Failed_Test").
Create().
RequestRetry(2).
RequestRetryOptional(false).
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
).
BrokenAssertBodyT(func(t cute.T, body []byte) error {
return errors.New("example broken error")
}).
ExpectStatus(http.StatusCreated).
ExecuteTest(context.Background(), t)
t.Logf("You should see it")
}
func Test_Single_Broken_2(t *testing.T) {
cute.NewTestBuilder().
Title("Test_Single_Broken_2").
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
).
AssertBodyT(func(t cute.T, body []byte) error {
err := errors.New("example broken error")
return cuteErrors.WrapBrokenError(err)
}).
ExpectStatus(http.StatusOK).
NextTest().
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
).
AssertBody(func(body []byte) error {
return errors.New("it's NOT must be run")
},
).
ExecuteTest(context.Background(), t)
}
func Test_Single_2_AllureRunner(t *testing.T) {
runner.Run(t, "Single test with allure-go Runner", func(t provider.T) {
var (
testMaker = cute.NewHTTPTestMaker()
testBuilder = testMaker.NewTestBuilder()
)
u, _ := url.Parse("https://jsonplaceholder.typicode.com/")
u.Path = path.Join(u.Path, "/posts/1/comments")
testBuilder.
Title("Single test with allure.T and repeat errors").
Tag("single_test").
Description("some_description").
Create().
RequestRetryDelay(3*time.Second). // delay before new try
RequestRetry(3). // count attempts
RequestBuilder(
cute.WithURL(u),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusBadGateway).
AssertBody(
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
).
OptionalAssertBody(
json.Present("$[0].photo"), // Example optional fail
).
ExecuteTest(context.Background(), t)
})
}
================================================
FILE: examples/suite/common.go
================================================
package suite
import (
"net/url"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/suite"
"github.com/stretchr/testify/require"
"github.com/ozontech/cute"
)
type ExampleSuite struct {
suite.Suite
host *url.URL
testMaker *cute.HTTPTestMaker
}
func (i *ExampleSuite) BeforeAll(t provider.T) {
// Prepare http test builder
i.testMaker = cute.NewHTTPTestMaker()
// Preparing host
host, err := url.Parse("https://jsonplaceholder.typicode.com/")
require.NoError(t, err)
i.host = host
}
func (i *ExampleSuite) BeforeEach(t provider.T) {
t.Feature("ExampleSuite")
t.Tags("some_global_tag")
}
================================================
FILE: examples/suite/main_test.go
================================================
//go:build example
// +build example
package suite
import (
"os"
"testing"
"github.com/ozontech/allure-go/pkg/framework/suite"
)
func TestExampleSuite(t *testing.T) {
os.Setenv("ALLURE_OUTPUT_PATH", "../") // custom, read Readme.md for more info
suite.RunSuite(t, new(ExampleSuite))
}
================================================
FILE: examples/suite/one_step.go
================================================
package suite
import (
"context"
"net/http"
"net/url"
"path"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/cute"
"github.com/ozontech/cute/asserts/headers"
"github.com/ozontech/cute/asserts/json"
"github.com/ozontech/cute/examples"
)
/*
Example testing HTTP GET and validate body.
Validate:
1) Execute time
2) Status code
3) Validate body by json schema
4) Validate fields in json
Response:
[
{
"postId": 1,
"id": 1,
"name": "id labore ex et quam laborum",
"email": "Eliseo@gardner.biz",
"body": "laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium"
},
{
"postId": 1,
"id": 2,
"name": "quo vero reiciendis velit similique earum",
"email": "Jayne_Kuhic@sydney.com",
"body": "est natus enim nihil est dolore omnis voluptatem numquam\net omnis occaecati quod ullam at\nvoluptatem error expedita pariatur\nnihil sint nostrum voluptatem reiciendis et"
},
{
"postId": 1,
"id": 3,
"name": "odio adipisci rerum aut animi",
"email": "Nikita@garfield.biz",
"body": "quia molestiae reprehenderit quasi aspernatur\naut expedita occaecati aliquam eveniet laudantium\nomnis quibusdam delectus saepe quia accusamus maiores nam est\ncum et ducimus et vero voluptates excepturi deleniti ratione"
},
{
"postId": 1,
"id": 4,
"name": "alias odio sit",
"email": "Lew@alysha.tv",
"body": "non et atque\noccaecati deserunt quas accusantium unde odit nobis qui voluptatem\nquia voluptas consequuntur itaque dolor\net qui rerum deleniti ut occaecati"
},
{
"postId": 1,
"id": 5,
"name": "vero eaque aliquid doloribus et culpa",
"email": "Hayden@althea.biz",
"body": "harum non quasi et ratione\ntempore iure ex voluptates in ratione\nharum architecto fugit inventore cupiditate\nvoluptates magni quo et"
}
]
*/
func (i *ExampleSuite) Test_OneStep(t provider.T) {
var (
testBuilder = i.testMaker.NewTestBuilder()
)
u, _ := url.Parse(i.host.String())
u.Path = path.Join(u.Path, "/posts/1/comments")
testBuilder.
Title("Test with one step").
Tags("one_stp", "some_local_tag", "suite", "json").
Feature("some_feature").
Epic("some_epic").
Description("some_description").
Parallel().
CreateStep("Example GET json request").
AfterExecuteT(func(t cute.T, resp *http.Response, errs []error) error {
if len(errs) != 0 {
return nil
}
/*
Implement some logic
*/
return nil
},
// After failed test
func(t cute.T, resp *http.Response, errs []error) error {
if len(errs) == 0 {
return nil
}
/*
Implement some logic
*/
return nil
},
).
RequestBuilder(
cute.WithHeaders(map[string][]string{
"some_header": []string{"something"},
"some_array_header": []string{"1", "2", "3", "some_thing"},
}),
cute.WithURL(u),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectJSONSchemaFile("file://./resources/example_valid_request.json").
ExpectStatus(http.StatusOK).
AssertBody(
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
json.NotPresent("$[1].some_not_present"),
json.LengthGreaterThan("$", 3),
json.Length("$", 5),
json.LengthLessThan("$", 100),
json.NotEqual("$[3].name", "kekekekeke"),
// Custom assert body
examples.CustomAssertBody(),
).
AssertBodyT(
// Custom assert body with testing.tb
examples.CustomAssertBodyT(),
func(t cute.T, body []byte) error {
/*
Implement here logic with TB
*/
time.Sleep(5 * time.Second)
return nil
},
).
AssertHeaders(
headers.Present("Content-Type"),
// Custom assert headers
examples.CustomAssertHeaders(),
).
AssertResponse(
examples.CustomAssertResponse(),
).
ExecuteTest(context.Background(), t)
}
================================================
FILE: examples/suite/one_step_errors.go
================================================
package suite
import (
"context"
"errors"
"net/http"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/cute"
"github.com/ozontech/cute/asserts/headers"
"github.com/ozontech/cute/asserts/json"
cuteErrors "github.com/ozontech/cute/errors"
"github.com/ozontech/cute/examples"
)
func (i *ExampleSuite) Test_OneStep_Errors(t provider.T) {
var (
testBuilder = i.testMaker.NewTestBuilder()
)
testBuilder.
Title("Test with errors").
Tags("one_step", "some_local_tag", "suite", "json").
Parallel().
CreateStep("Example GET json request").
RequestBuilder(
cute.WithHeaders(map[string][]string{
"some_header": []string{"something"},
"some_array_header": []string{"1", "2", "3", "some_thing"},
}),
cute.WithURI(i.host.String()+"/posts/1/comments"),
cute.WithMethod(http.MethodGet),
cute.WithMarshalBody(
map[string]interface{}{
"key": "value",
"more_key": map[string]interface{}{
"some_value": "sss",
},
},
),
).
ExpectExecuteTimeout(10*time.Second).
ExpectJSONSchemaFile("file://./resources/example_valid_request.json").
AssertBody(
json.Equal("$[0].email", "something"),
json.Present("$[1].not_present"),
json.LengthGreaterThan("$", 99999),
json.Length("$", 0),
// Custom assert body
examples.CustomAssertBody(),
examples.CustomAssertBodyWithCustomError(),
).
AssertHeaders(
headers.Present("Content-Type"),
// Custom assert headers
examples.CustomAssertHeaders(),
).
AssertResponse(
examples.CustomAssertResponse(),
).
AssertHeadersT(
func(t cute.T, headers http.Header) error {
// Example pretty print error
return cuteErrors.NewAssertError("custom_assert", "example custom assert", "empty", "not empty") //
},
).
// Example optional
OptionalAssertBody( // example optional assert
func(body []byte) error {
return errors.New("some optional error from OptionalAssert")
},
).
AssertBody(
func(body []byte) error {
return cuteErrors.NewOptionalError("some optional error from creator") // example optional error
},
).
ExecuteTest(context.Background(), t)
}
================================================
FILE: examples/suite/resources/example_valid_request.json
================================================
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "array",
"items": [
{
"type": "object",
"properties": {
"postId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"body": {
"type": "string"
}
},
"required": [
"postId",
"id",
"name",
"email",
"body"
]
},
{
"type": "object",
"properties": {
"postId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"body": {
"type": "string"
}
},
"required": [
"postId",
"id",
"name",
"email",
"body"
]
},
{
"type": "object",
"properties": {
"postId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"body": {
"type": "string"
}
},
"required": [
"postId",
"id",
"name",
"email",
"body"
]
},
{
"type": "object",
"properties": {
"postId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"body": {
"type": "string"
}
},
"required": [
"postId",
"id",
"name",
"email",
"body"
]
},
{
"type": "object",
"properties": {
"postId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"body": {
"type": "string"
}
},
"required": [
"postId",
"id",
"name",
"email",
"body"
]
}
]
}
================================================
FILE: examples/suite/simple.go
================================================
package suite
import (
"context"
"net/http"
"net/url"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/cute"
)
/*
Example simple request
Validate:
1) Execute time
2) Status code
*/
func (i *ExampleSuite) Test_Simple(t provider.T) {
var (
testMaker = cute.NewHTTPTestMaker()
testBuilder = testMaker.NewTestBuilder()
)
u, _ := url.Parse("https://jsonplaceholder.typicode.com/posts/1/comments")
testBuilder.
Title("Super simple test").
Tags("simple", "suite", "some_local_tag", "json").
Parallel().
Create().
RequestBuilder(
cute.WithHeaders(map[string][]string{
"some_header": []string{"something"},
}),
cute.WithURL(u),
cute.WithMethod(http.MethodPost),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusCreated).
ExecuteTest(context.Background(), t)
}
================================================
FILE: examples/suite/two_steps.go
================================================
package suite
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path"
"strings"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/cute"
"github.com/ozontech/cute/examples"
)
/*
Example testing HTTP POST, validate body and make second request.
Validate:
1) Execute time
2) Status code
*/
func (i *ExampleSuite) Test_TwoSteps(t provider.T) {
var (
testBuilder = i.testMaker.NewTestBuilder()
// Request body
r = `
{
"result": {
"author": "Yours Truly",
"date": "15.11.1993",
"slides": [
{
"title": "Beer",
"type": "drink"
},
{
"title": "Apple",
"type": "fruit"
},
{
"title": "Orange",
"type": "fruit"
}
],
"Info": {
"shop": "BigShopPlus",
"address": "address"
},
"title": "Sample Show"
}
}
`
)
u, _ := url.Parse(i.host.String())
u.Path = path.Join(u.Path, "/posts/1/comments")
req, _ := http.NewRequest(http.MethodPost, u.String(), ioutil.NopCloser(strings.NewReader(r)))
req.Header = map[string][]string{
"some_auth_token": []string{fmt.Sprint(11111)},
}
testBuilder.
Title("Test in suite with two steps").
Tags("suite", "some_tag").
Parallel().
CreateStep("Creat entry /posts/1").
// CreateWithStep first step
Request(req).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusCreated).
AssertBody(
// Custom assert body
examples.CustomAssertBody(),
).
NextTest().
CreateStep("Delete entry").
// CreateWithStep second step for delete
RequestBuilder(
cute.WithURL(u),
cute.WithMethod(http.MethodDelete),
cute.WithHeaders(map[string][]string{
"some_auth_token": []string{fmt.Sprint(11111)},
}),
).
ExecuteTest(context.Background(), t)
}
================================================
FILE: examples/table_test/table_test.go
================================================
//go:build example
// +build example
package table_test
import (
"context"
"fmt"
"net/http"
"net/url"
"os"
"strconv"
"testing"
"time"
"github.com/ozontech/cute"
"github.com/ozontech/cute/asserts/json"
"github.com/ozontech/cute/errors"
)
func init() {
os.Setenv("ALLURE_OUTPUT_PATH", "../") // custom, read Readme.md for more info
}
func Test_Table(t *testing.T) {
u, _ := url.Parse("https://jsonplaceholder.typicode.com/posts/1/comments")
req, _ := http.NewRequest(http.MethodPost, u.String(), nil)
req.Header = map[string][]string{
"some_auth_token": []string{fmt.Sprint(11111)},
}
cute.NewTestBuilder().
Title("Example put tests in table test").
Tag("table_test").
CreateTableTest().
PutNewTest(
"Execute validation 1",
req,
&cute.Expect{
Code: 201,
}).
PutNewTest(
"Execute validation 2",
req,
&cute.Expect{
AssertBody: []cute.AssertBody{
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
},
},
).
ExecuteTest(context.Background(), t)
}
func Test_Table_Array(t *testing.T) {
tests := []*cute.Test{
{
Name: "Create something",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodPost),
},
},
Expect: &cute.Expect{
Code: 200,
},
},
{
Name: "Delete something",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 200,
AssertBody: []cute.AssertBody{
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
func(body []byte) error {
return errors.NewAssertError("example error", "example message", nil, nil)
},
},
},
},
}
cute.NewTestBuilder().
Title("Example table test").
Tag("table_test").
Description("Execute array tests").
CreateTableTest().
PutTests(tests...).
ExecuteTest(context.Background(), t)
}
func Test_One_Execute(t *testing.T) {
test := &cute.Test{
Name: "test_1",
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
},
},
Expect: nil,
}
test.Execute(context.Background(), t)
}
func Test_Array_Retry_OptionalFirstTries(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_1",
Retry: &cute.Retry{
MaxAttempts: 10,
Delay: 1 * time.Second,
},
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/Random/201,202"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 201,
},
},
{
Name: "test_2",
Retry: &cute.Retry{
MaxAttempts: 10,
Delay: 1 * time.Second,
},
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/Random/403,404"),
cute.WithMethod(http.MethodGet),
cute.WithMarshalBody([]byte("{\"test\":\"abc\"}")),
},
},
Expect: &cute.Expect{
Code: 404,
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
func Test_Array_Retry_OptionalFirstTries_UltimatelyFailing(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_1",
Retry: &cute.Retry{
MaxAttempts: 4,
Delay: 1 * time.Second,
},
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/Random/202,200"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 201,
},
},
{
Name: "test_2",
Retry: &cute.Retry{
MaxAttempts: 3,
Delay: 1 * time.Second,
},
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/Random/403,401"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 404,
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
func Test_Array_TimeoutRetry(t *testing.T) {
var executeTimeout = 3000
tests := []*cute.Test{
{
Retry: &cute.Retry{
MaxAttempts: 2,
},
Name: "test_timeout",
Middleware: &cute.Middleware{
Before: []cute.BeforeExecute{
cute.BeforeExecute(func(request *http.Request) error {
query := request.URL.Query()
query.Set("sleep", strconv.Itoa(executeTimeout))
request.URL.RawQuery = query.Encode()
executeTimeout = executeTimeout - 1000
return nil
}),
},
},
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/202?sleep=3000"),
cute.WithBody([]byte("{\"test\":\"abc\"}")),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 202,
ExecuteTime: 3 * time.Second,
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
func Test_Array(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_1",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodPost),
},
},
Expect: &cute.Expect{
Code: 201,
},
},
{
Name: "test_2",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 200,
AssertBody: []cute.AssertBody{
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
func(body []byte) error {
return errors.NewAssertError("example error", "example message", nil, nil)
},
},
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
func Test_Array_All_Parallel(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_201",
Parallel: true,
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/201"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 201,
},
},
{
Name: "test_200_delay_5s",
Parallel: true,
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/200?sleep=5000"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 200,
},
},
{
Name: "test_202_delay_3s",
Parallel: true,
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/202?sleep=3000"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 202,
},
},
{
Name: "test_203",
Parallel: true,
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/203"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 203,
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
func Test_Array_Some_Parallel(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_parallel_1",
Parallel: true,
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/201?sleep=1000"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 201,
},
},
{
Name: "test_parallel_2",
Parallel: true,
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/202?sleep=1000"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 202,
},
},
{
Name: "test_1_sequential",
Parallel: false,
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodPost),
},
},
Expect: &cute.Expect{
Code: 201,
},
},
{
Name: "test_2_sequential",
Parallel: false,
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 200,
AssertBody: []cute.AssertBody{
json.Equal("$[0].email", "Eliseo@gardner.biz"),
json.Present("$[1].name"),
},
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
func Test_Array_Retry(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_1",
Parallel: true,
Retry: &cute.Retry{
MaxAttempts: 10,
Delay: 1,
},
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/Random/201,202"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 201,
},
},
{
Name: "test_2",
Parallel: true,
Retry: &cute.Retry{
MaxAttempts: 10,
Delay: 1,
},
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/Random/403,404"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 404,
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
func Test_Array_Timeout(t *testing.T) {
tests := []*cute.Test{
{
Name: "test_timeout",
Middleware: nil,
Request: &cute.Request{
Builders: []cute.RequestBuilder{
cute.WithURI("https://httpstat.us/202?sleep=3000"),
cute.WithMethod(http.MethodGet),
},
},
Expect: &cute.Expect{
Code: 202,
ExecuteTime: 2 * time.Second,
},
},
}
for _, test := range tests {
test.Execute(context.Background(), t)
}
}
================================================
FILE: examples/two_step_test.go
================================================
//go:build example
// +build example
package examples
import (
"context"
"errors"
"fmt"
"net/http"
"testing"
"time"
"github.com/ozontech/allure-go/pkg/framework/provider"
"github.com/ozontech/allure-go/pkg/framework/runner"
"github.com/ozontech/cute"
)
func Test_TwoSteps_1(t *testing.T) {
cute.NewTestBuilder().
Title("Test with two requests.").
Tags("two_steps").
Parallel().
CreateStep("Create entry /posts/1").
// CreateWithStep first step
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusCreated).
NextTest().
CreateStep("Delete entry").
// CreateWithStep second step for delete
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodDelete),
cute.WithHeaders(map[string][]string{
"some_auth_token": []string{fmt.Sprint(11111)},
}),
).
ExecuteTest(context.Background(), t)
}
func Test_TwoSteps_2_AllureRunner(t *testing.T) {
runner.Run(t, "Test with two steps", func(t provider.T) {
testBuilder := cute.NewHTTPTestMaker().NewTestBuilder()
testBuilder.
Title("Test with two requests executed by allure-go").
Tag("two_steps").
Description("some_description").
CreateStep("Request 1").
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
).
ExpectStatus(http.StatusOK).
ExecuteTest(context.Background(), t)
testBuilder.
CreateStep("Request 2").
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/2/comments"),
cute.WithMethod(http.MethodGet),
).
ExpectExecuteTimeout(10*time.Second).
ExpectStatus(http.StatusOK).
ExecuteTest(context.Background(), t)
})
}
func Test_TwoSteps_3(t *testing.T) {
responseCode := 0
// First step.
cute.NewTestBuilder().
Title("Test with two requests and parse body.").
Tag("two_steps").
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/1/comments"),
cute.WithMethod(http.MethodGet),
).
ExpectStatus(http.StatusOK).
RequireBody(func(body []byte) error {
return errors.New("example")
}).
NextTest().
AfterTestExecute(func(response *http.Response, errors []error) error { // Execute after first step
responseCode = response.StatusCode
fmt.Println("Hello from after test execute")
fmt.Println("Response code", responseCode)
return nil
}).
// Second step. This test isn't run, because previous test has failed require validation
Create().
RequestBuilder(
cute.WithURI("https://jsonplaceholder.typicode.com/posts/2/comments"),
cute.WithMethod(http.MethodDelete),
).
ExecuteTest(context.Background(), t)
fmt.Println("Response code from first request", responseCode)
}
================================================
FILE: examples/upload_file_test.go
================================================
//go:build example_upload_file
// +build example_upload_file
package examples
import (
"context"
"net/http"
"testing"
"github.com/ozontech/cute"
)
func TestUploadFile(t *testing.T) {
cute.NewTestBuilder().
Title("Upload file").
Create().
RequestBuilder(
cute.WithURI("http://localhost:7000/v1/banner"),
cute.WithMethod("POST"),
cute.WithFormKV("body", []byte("{\"name\": \"Vasya\"}")), // Fill the form with the body
cute.WithFileFormKV("image", &cute.File{ // Fill the form with the file
Path: "/vasya/thebestmypicture.png",
}),
).
ExpectStatus(http.StatusOK).
ExecuteTest(context.Background(), t)
}
================================================
FILE: go.mod
================================================
module github.com/ozontech/cute
go 1.21
require (
github.com/josephburnett/jd v1.7.1
github.com/ohler55/ojg v1.21.1
github.com/ozontech/allure-go/pkg/allure v0.6.13
github.com/ozontech/allure-go/pkg/framework v0.6.31
github.com/stretchr/testify v1.8.4
github.com/xeipuuv/gojsonschema v1.2.0
moul.io/http2curl/v2 v2.3.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
================================================
FILE: go.sum
================================================
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/josephburnett/jd v1.7.1 h1:oXBPMS+SNnILTMGj1fWLK9pexpeJUXtbVFfRku/PjBU=
github.com/josephburnett/jd v1.7.1/go.mod h1:R8ZnZnLt2D4rhW4NvBc/USTo6mzyNT6fYNIIWOJA9GY=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/ohler55/ojg v1.21.1 h1:b2RLUaDcy9gvn46dmhTjezu/TDauoR0/kgKTqkwIxto=
github.com/ohler55/ojg v1.21.1/go.mod h1:gQhDVpQLqrmnd2eqGAvJtn+NfKoYJbe/A4Sj3/Vro4o=
github.com/ozontech/allure-go/pkg/allure v0.6.13 h1:vkLSIvOEERHTxe+oq8DXDu/m+kLnVUkrXNN8xTKuKU4=
github.com/ozontech/allure-go/pkg/allure v0.6.13/go.mod h1:4oEG2yq+DGOzJS/ZjPc87C/mx3tAnlYpYonk77Ru/vQ=
github.com/ozontech/allure-go/pkg/framework v0.6.31 h1:u32AqB9/JkzcL5vSl8PSUmMZbsVTmoriDylI3FIYgX4=
github.com/ozontech/allure-go/pkg/framework v0.6.31/go.mod h1:wfqY4e4+w4BoRFDxHp7TNcdWfcCOWJV3BjrUqUughWY=
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1
gitextract_fkbtdg57/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows/ │ └── main.yml ├── .gitignore ├── .golangci.yaml ├── LICENSE ├── Makefile ├── README.MD ├── allure.go ├── assert.go ├── assert_broken.go ├── assert_broken_test.go ├── assert_optional.go ├── assert_optional_test.go ├── assert_require.go ├── assert_require_test.go ├── assert_trace.go ├── asserts/ │ ├── headers/ │ │ ├── headers.go │ │ └── headers_test.go │ └── json/ │ ├── json.go │ ├── json_test.go │ └── util.go ├── builder.go ├── builder_allure.go ├── builder_asserts.go ├── builder_middleware.go ├── builder_option.go ├── builder_request.go ├── builder_retry.go ├── builder_table.go ├── builder_table_test.go ├── builder_test.go ├── cute.go ├── errors/ │ ├── broken.go │ ├── error.go │ ├── optional.go │ ├── require.go │ └── trace.go ├── examples/ │ ├── custom_asserts.go │ ├── inside_step_test.go │ ├── masked_data_test.go │ ├── parallel_test.go │ ├── single_test.go │ ├── suite/ │ │ ├── common.go │ │ ├── main_test.go │ │ ├── one_step.go │ │ ├── one_step_errors.go │ │ ├── resources/ │ │ │ └── example_valid_request.json │ │ ├── simple.go │ │ └── two_steps.go │ ├── table_test/ │ │ └── table_test.go │ ├── two_step_test.go │ └── upload_file_test.go ├── go.mod ├── go.sum ├── init.go ├── interface.go ├── internal/ │ └── utils/ │ ├── body.go │ └── json.go ├── json_marshaler.go ├── jsonschema.go ├── jsonschema_test.go ├── logger.go ├── provider.go ├── request.go ├── request_test.go ├── result.go ├── result_test.go ├── roundtripper.go ├── step.go ├── test.go └── test_test.go
SYMBOL INDEX (470 symbols across 61 files)
FILE: allure.go
method setAllureInformation (line 3) | func (qt *cute) setAllureInformation(t allureProvider) {
method setLinksAllure (line 10) | func (qt *cute) setLinksAllure(t linksAllureProvider) {
method setLabelsAllure (line 32) | func (qt *cute) setLabelsAllure(t labelsAllureProvider) {
method setInfoAllure (line 98) | func (qt *cute) setInfoAllure(t infoAllureProvider) {
FILE: assert.go
type AssertBody (line 18) | type AssertBody
type AssertHeaders (line 24) | type AssertHeaders
type AssertResponse (line 27) | type AssertResponse
type AssertBodyT (line 34) | type AssertBodyT
type AssertHeadersT (line 39) | type AssertHeadersT
type AssertResponseT (line 44) | type AssertResponseT
method assertHeaders (line 46) | func (it *Test) assertHeaders(t internalT, headers http.Header) []error {
method assertResponse (line 78) | func (it *Test) assertResponse(t internalT, resp *http.Response) []error {
method assertBody (line 110) | func (it *Test) assertBody(t internalT, body []byte) []error {
FILE: assert_broken.go
function brokenAssertHeaders (line 9) | func brokenAssertHeaders(assert AssertHeaders) AssertHeaders {
function brokenAssertBody (line 17) | func brokenAssertBody(assert AssertBody) AssertBody {
function brokenAssertResponse (line 25) | func brokenAssertResponse(assert AssertResponse) AssertResponse {
function brokenAssertHeadersT (line 33) | func brokenAssertHeadersT(assert AssertHeadersT) AssertHeadersT {
function brokenAssertBodyT (line 41) | func brokenAssertBodyT(assert AssertBodyT) AssertBodyT {
function brokenAssertResponseT (line 49) | func brokenAssertResponseT(assert AssertResponseT) AssertResponseT {
function wrapBrokenError (line 57) | func wrapBrokenError(err error) error {
FILE: assert_broken_test.go
function TestBrokenAssertResponse (line 13) | func TestBrokenAssertResponse(t *testing.T) {
function TestBrokenAssertResponseT (line 26) | func TestBrokenAssertResponseT(t *testing.T) {
function TestBrokenAssertHeaders (line 39) | func TestBrokenAssertHeaders(t *testing.T) {
function TestBrokenAssertHeadersT (line 52) | func TestBrokenAssertHeadersT(t *testing.T) {
function TestBrokenAssertBody (line 65) | func TestBrokenAssertBody(t *testing.T) {
function TestBrokenAssertBodyT (line 78) | func TestBrokenAssertBodyT(t *testing.T) {
function TestWrapBrokenError (line 91) | func TestWrapBrokenError(t *testing.T) {
FILE: assert_optional.go
function optionalAssertHeaders (line 9) | func optionalAssertHeaders(assert AssertHeaders) AssertHeaders {
function optionalAssertBody (line 17) | func optionalAssertBody(assert AssertBody) AssertBody {
function optionalAssertResponse (line 25) | func optionalAssertResponse(assert AssertResponse) AssertResponse {
function optionalAssertHeadersT (line 33) | func optionalAssertHeadersT(assert AssertHeadersT) AssertHeadersT {
function optionalAssertBodyT (line 41) | func optionalAssertBodyT(assert AssertBodyT) AssertBodyT {
function optionalAssertResponseT (line 49) | func optionalAssertResponseT(assert AssertResponseT) AssertResponseT {
function wrapOptionalError (line 57) | func wrapOptionalError(err error) error {
FILE: assert_optional_test.go
function TestOptionalAssertResponse (line 13) | func TestOptionalAssertResponse(t *testing.T) {
function TestOptionalAssertResponseT (line 26) | func TestOptionalAssertResponseT(t *testing.T) {
function TestOptionalAssertHeaders (line 39) | func TestOptionalAssertHeaders(t *testing.T) {
function TestOptionalAssertHeadersT (line 52) | func TestOptionalAssertHeadersT(t *testing.T) {
function TestOptionalAssertBody (line 65) | func TestOptionalAssertBody(t *testing.T) {
function TestOptionalAssertBodyT (line 78) | func TestOptionalAssertBodyT(t *testing.T) {
function TestWrapOptionalError (line 91) | func TestWrapOptionalError(t *testing.T) {
FILE: assert_require.go
function requireAssertHeaders (line 9) | func requireAssertHeaders(assert AssertHeaders) AssertHeaders {
function requireAssertBody (line 17) | func requireAssertBody(assert AssertBody) AssertBody {
function requireAssertResponse (line 25) | func requireAssertResponse(assert AssertResponse) AssertResponse {
function requireAssertHeadersT (line 33) | func requireAssertHeadersT(assert AssertHeadersT) AssertHeadersT {
function requireAssertBodyT (line 41) | func requireAssertBodyT(assert AssertBodyT) AssertBodyT {
function requireAssertResponseT (line 49) | func requireAssertResponseT(assert AssertResponseT) AssertResponseT {
function wrapRequireError (line 57) | func wrapRequireError(err error) error {
FILE: assert_require_test.go
function TestRequireAssertResponse (line 13) | func TestRequireAssertResponse(t *testing.T) {
function TestRequireAssertResponseT (line 26) | func TestRequireAssertResponseT(t *testing.T) {
function TestRequireAssertHeaders (line 39) | func TestRequireAssertHeaders(t *testing.T) {
function TestRequireAssertHeadersT (line 52) | func TestRequireAssertHeadersT(t *testing.T) {
function TestRequireAssertBody (line 65) | func TestRequireAssertBody(t *testing.T) {
function TestRequireAssertBodyT (line 78) | func TestRequireAssertBodyT(t *testing.T) {
function TestWrapRequireError (line 91) | func TestWrapRequireError(t *testing.T) {
FILE: assert_trace.go
function assertHeadersWithTrace (line 12) | func assertHeadersWithTrace(assert AssertHeaders, trace string) AssertHe...
function assertBodyWithTrace (line 21) | func assertBodyWithTrace(assert AssertBody, trace string) AssertBody {
function assertResponseWithTrace (line 30) | func assertResponseWithTrace(assert AssertResponse, trace string) Assert...
function assertHeadersTWithTrace (line 39) | func assertHeadersTWithTrace(assert AssertHeadersT, trace string) Assert...
function assertBodyTWithTrace (line 48) | func assertBodyTWithTrace(assert AssertBodyT, trace string) AssertBodyT {
function assertResponseTWithTrace (line 57) | func assertResponseTWithTrace(assert AssertResponseT, trace string) Asse...
function wrapWithTrace (line 66) | func wrapWithTrace(err error, trace string) error {
function getTrace (line 80) | func getTrace() string {
FILE: asserts/headers/headers.go
function Present (line 12) | func Present(key string) cute.AssertHeaders {
function NotPresent (line 23) | func NotPresent(key string) cute.AssertHeaders {
FILE: asserts/headers/headers_test.go
function TestPresent (line 10) | func TestPresent(t *testing.T) {
function TestPresentError (line 19) | func TestPresentError(t *testing.T) {
function TestNotPresent (line 28) | func TestNotPresent(t *testing.T) {
function TestNotPresentError (line 37) | func TestNotPresentError(t *testing.T) {
FILE: asserts/json/json.go
function Diff (line 14) | func Diff(original string) cute.AssertBody {
function Contains (line 44) | func Contains(expression string, expect interface{}) cute.AssertBody {
function Equal (line 52) | func Equal(expression string, expect interface{}) cute.AssertBody {
function NotEqual (line 60) | func NotEqual(expression string, expect interface{}) cute.AssertBody {
function EqualJSON (line 68) | func EqualJSON(expression string, expect []byte) cute.AssertBody {
function NotEqualJSON (line 76) | func NotEqualJSON(expression string, expect []byte) cute.AssertBody {
function Length (line 84) | func Length(expression string, expectLength int) cute.AssertBody {
function LengthGreaterThan (line 92) | func LengthGreaterThan(expression string, minimumLength int) cute.Assert...
function LengthGreaterOrEqualThan (line 100) | func LengthGreaterOrEqualThan(expression string, minimumLength int) cute...
function LengthLessThan (line 108) | func LengthLessThan(expression string, maximumLength int) cute.AssertBody {
function LengthLessOrEqualThan (line 116) | func LengthLessOrEqualThan(expression string, maximumLength int) cute.As...
function Present (line 125) | func Present(expression string) cute.AssertBody {
function NotEmpty (line 134) | func NotEmpty(expression string) cute.AssertBody {
function NotPresent (line 142) | func NotPresent(expression string) cute.AssertBody {
function GetValueFromJSON (line 149) | func GetValueFromJSON(js []byte, expression string) ([]interface{}, erro...
FILE: asserts/json/json_test.go
type jsonTest (line 10) | type jsonTest struct
function TestDiff (line 18) | func TestDiff(t *testing.T) {
function TestNotPresent (line 73) | func TestNotPresent(t *testing.T) {
function TestPresent (line 109) | func TestPresent(t *testing.T) {
function TestNotEmpty (line 170) | func TestNotEmpty(t *testing.T) {
function TestLength (line 228) | func TestLength(t *testing.T) {
function TestLengthGreaterThan (line 282) | func TestLengthGreaterThan(t *testing.T) {
function TestLengthGreaterOrEqualThan (line 342) | func TestLengthGreaterOrEqualThan(t *testing.T) {
function TestLengthLessThan (line 423) | func TestLengthLessThan(t *testing.T) {
function TestLengthLessOrEqualThan (line 483) | func TestLengthLessOrEqualThan(t *testing.T) {
function TestEqual (line 564) | func TestEqual(t *testing.T) {
function TestNotEqual (line 649) | func TestNotEqual(t *testing.T) {
function TestEqualJSON (line 701) | func TestEqualJSON(t *testing.T) {
function TestNotEqualJSON (line 799) | func TestNotEqualJSON(t *testing.T) {
function TestGetValueFromJSON (line 891) | func TestGetValueFromJSON(t *testing.T) {
FILE: asserts/json/util.go
function contains (line 16) | func contains(data []byte, expression string, expect interface{}) error {
function equalAbstract (line 36) | func equalAbstract(data []byte, expression string, expect interface{}, n...
function notEqualAbstract (line 51) | func notEqualAbstract(data []byte, expression string, expect interface{}...
function equal (line 68) | func equal(data []byte, expression string, expect interface{}) error {
function notEqual (line 74) | func notEqual(data []byte, expression string, expect interface{}) error {
function equalJSON (line 80) | func equalJSON(data []byte, expression string, expect []byte) error {
function notEqualJSON (line 91) | func notEqualJSON(data []byte, expression string, expect []byte) error {
function length (line 102) | func length(data []byte, expression string, expectLength int) error {
function greaterThan (line 120) | func greaterThan(data []byte, expression string, minimumLength int) error {
function greaterOrEqualThan (line 138) | func greaterOrEqualThan(data []byte, expression string, minimumLength in...
function lessThan (line 156) | func lessThan(data []byte, expression string, maximumLength int) error {
function lessOrEqualThan (line 174) | func lessOrEqualThan(data []byte, expression string, maximumLength int) ...
function notEmpty (line 192) | func notEmpty(data []byte, expression string) error {
function present (line 211) | func present(data []byte, expression string) error {
function notPresent (line 222) | func notPresent(data []byte, expression string) error {
function objectsAreEqual (line 234) | func objectsAreEqual(expect, actual interface{}) bool {
function isEmpty (line 264) | func isEmpty(object interface{}) bool {
function insideArray (line 288) | func insideArray(list interface{}, element interface{}) (ok, found bool) {
FILE: builder.go
constant defaultHTTPTimeout (line 8) | defaultHTTPTimeout = 30
type HTTPTestMaker (line 15) | type HTTPTestMaker struct
method NewTestBuilder (line 78) | func (m *HTTPTestMaker) NewTestBuilder() AllureBuilder {
function NewHTTPTestMaker (line 32) | func NewHTTPTestMaker(opts ...Option) *HTTPTestMaker {
function createDefaultTests (line 92) | func createDefaultTests(m *HTTPTestMaker) []*Test {
function createDefaultTest (line 99) | func createDefaultTest(m *HTTPTestMaker) *Test {
function createMiddlewareFromTemplate (line 112) | func createMiddlewareFromTemplate(m *Middleware) *Middleware {
method Create (line 135) | func (qt *cute) Create() MiddlewareRequest {
method CreateStep (line 139) | func (qt *cute) CreateStep(name string) MiddlewareRequest {
method CreateRequest (line 145) | func (qt *cute) CreateRequest() RequestHTTPBuilder {
FILE: builder_allure.go
method Parallel (line 9) | func (qt *cute) Parallel() AllureBuilder {
method Title (line 15) | func (qt *cute) Title(title string) AllureBuilder {
method Epic (line 21) | func (qt *cute) Epic(epic string) AllureBuilder {
method Titlef (line 27) | func (qt *cute) Titlef(format string, args ...interface{}) AllureBuilder {
method Descriptionf (line 33) | func (qt *cute) Descriptionf(format string, args ...interface{}) AllureB...
method Stage (line 39) | func (qt *cute) Stage(stage string) AllureBuilder {
method Stagef (line 45) | func (qt *cute) Stagef(format string, args ...interface{}) AllureBuilder {
method Layer (line 51) | func (qt *cute) Layer(value string) AllureBuilder {
method TmsLink (line 57) | func (qt *cute) TmsLink(tmsLink string) AllureBuilder {
method TmsLinks (line 63) | func (qt *cute) TmsLinks(tmsLinks ...string) AllureBuilder {
method SetIssue (line 69) | func (qt *cute) SetIssue(issue string) AllureBuilder {
method SetTestCase (line 75) | func (qt *cute) SetTestCase(testCase string) AllureBuilder {
method Link (line 81) | func (qt *cute) Link(link *allure.Link) AllureBuilder {
method ID (line 87) | func (qt *cute) ID(value string) AllureBuilder {
method AllureID (line 93) | func (qt *cute) AllureID(value string) AllureBuilder {
method AddSuiteLabel (line 99) | func (qt *cute) AddSuiteLabel(value string) AllureBuilder {
method AddSubSuite (line 105) | func (qt *cute) AddSubSuite(value string) AllureBuilder {
method AddParentSuite (line 111) | func (qt *cute) AddParentSuite(value string) AllureBuilder {
method Story (line 117) | func (qt *cute) Story(value string) AllureBuilder {
method Tag (line 123) | func (qt *cute) Tag(value string) AllureBuilder {
method Severity (line 129) | func (qt *cute) Severity(value allure.SeverityType) AllureBuilder {
method Owner (line 135) | func (qt *cute) Owner(value string) AllureBuilder {
method Lead (line 141) | func (qt *cute) Lead(value string) AllureBuilder {
method Label (line 147) | func (qt *cute) Label(label *allure.Label) AllureBuilder {
method Labels (line 153) | func (qt *cute) Labels(labels ...*allure.Label) AllureBuilder {
method Description (line 159) | func (qt *cute) Description(description string) AllureBuilder {
method Tags (line 165) | func (qt *cute) Tags(tags ...string) AllureBuilder {
method Feature (line 171) | func (qt *cute) Feature(feature string) AllureBuilder {
FILE: builder_asserts.go
method AssertBody (line 5) | func (qt *cute) AssertBody(asserts ...AssertBody) ExpectHTTPBuilder {
method OptionalAssertBody (line 19) | func (qt *cute) OptionalAssertBody(asserts ...AssertBody) ExpectHTTPBuil...
method BrokenAssertBody (line 33) | func (qt *cute) BrokenAssertBody(asserts ...AssertBody) ExpectHTTPBuilder {
method RequireBody (line 47) | func (qt *cute) RequireBody(asserts ...AssertBody) ExpectHTTPBuilder {
method AssertHeaders (line 61) | func (qt *cute) AssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder {
method OptionalAssertHeaders (line 75) | func (qt *cute) OptionalAssertHeaders(asserts ...AssertHeaders) ExpectHT...
method RequireHeaders (line 89) | func (qt *cute) RequireHeaders(asserts ...AssertHeaders) ExpectHTTPBuild...
method BrokenAssertHeaders (line 103) | func (qt *cute) BrokenAssertHeaders(asserts ...AssertHeaders) ExpectHTTP...
method AssertResponse (line 117) | func (qt *cute) AssertResponse(asserts ...AssertResponse) ExpectHTTPBuil...
method OptionalAssertResponse (line 131) | func (qt *cute) OptionalAssertResponse(asserts ...AssertResponse) Expect...
method RequireResponse (line 145) | func (qt *cute) RequireResponse(asserts ...AssertResponse) ExpectHTTPBui...
method BrokenAssertResponse (line 159) | func (qt *cute) BrokenAssertResponse(asserts ...AssertResponse) ExpectHT...
method AssertBodyT (line 173) | func (qt *cute) AssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder {
method OptionalAssertBodyT (line 187) | func (qt *cute) OptionalAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBu...
method BrokenAssertBodyT (line 201) | func (qt *cute) BrokenAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuil...
method RequireBodyT (line 215) | func (qt *cute) RequireBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder {
method AssertHeadersT (line 229) | func (qt *cute) AssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuil...
method OptionalAssertHeadersT (line 243) | func (qt *cute) OptionalAssertHeadersT(asserts ...AssertHeadersT) Expect...
method RequireHeadersT (line 257) | func (qt *cute) RequireHeadersT(asserts ...AssertHeadersT) ExpectHTTPBui...
method BrokenAssertHeadersT (line 271) | func (qt *cute) BrokenAssertHeadersT(asserts ...AssertHeadersT) ExpectHT...
method AssertResponseT (line 285) | func (qt *cute) AssertResponseT(asserts ...AssertResponseT) ExpectHTTPBu...
method OptionalAssertResponseT (line 299) | func (qt *cute) OptionalAssertResponseT(asserts ...AssertResponseT) Expe...
method BrokenAssertResponseT (line 313) | func (qt *cute) BrokenAssertResponseT(asserts ...AssertResponseT) Expect...
method RequireResponseT (line 327) | func (qt *cute) RequireResponseT(asserts ...AssertResponseT) ExpectHTTPB...
method ExpectExecuteTimeout (line 341) | func (qt *cute) ExpectExecuteTimeout(t time.Duration) ExpectHTTPBuilder {
method ExpectStatus (line 347) | func (qt *cute) ExpectStatus(code int) ExpectHTTPBuilder {
method ExpectJSONSchemaString (line 353) | func (qt *cute) ExpectJSONSchemaString(schema string) ExpectHTTPBuilder {
method ExpectJSONSchemaByte (line 359) | func (qt *cute) ExpectJSONSchemaByte(schema []byte) ExpectHTTPBuilder {
method ExpectJSONSchemaFile (line 365) | func (qt *cute) ExpectJSONSchemaFile(filePath string) ExpectHTTPBuilder {
FILE: builder_middleware.go
method StepName (line 3) | func (qt *cute) StepName(name string) MiddlewareRequest {
method BeforeExecute (line 9) | func (qt *cute) BeforeExecute(fs ...BeforeExecute) MiddlewareRequest {
method BeforeExecuteT (line 15) | func (qt *cute) BeforeExecuteT(fs ...BeforeExecuteT) MiddlewareRequest {
method After (line 21) | func (qt *cute) After(fs ...AfterExecute) ExpectHTTPBuilder {
method AfterT (line 27) | func (qt *cute) AfterT(fs ...AfterExecuteT) ExpectHTTPBuilder {
method AfterExecute (line 33) | func (qt *cute) AfterExecute(fs ...AfterExecute) MiddlewareRequest {
method AfterExecuteT (line 39) | func (qt *cute) AfterExecuteT(fs ...AfterExecuteT) MiddlewareRequest {
method AfterTestExecute (line 45) | func (qt *cute) AfterTestExecute(fs ...AfterExecute) NextTestBuilder {
method AfterTestExecuteT (line 56) | func (qt *cute) AfterTestExecuteT(fs ...AfterExecuteT) NextTestBuilder {
FILE: builder_option.go
type options (line 8) | type options struct
type Option (line 19) | type Option
function WithHTTPClient (line 22) | func WithHTTPClient(client *http.Client) Option {
function WithJSONMarshaler (line 29) | func WithJSONMarshaler(m JSONMarshaler) Option {
function WithCustomHTTPTimeout (line 36) | func WithCustomHTTPTimeout(t time.Duration) Option {
function WithCustomHTTPRoundTripper (line 43) | func WithCustomHTTPRoundTripper(r http.RoundTripper) Option {
function WithMiddlewareAfter (line 50) | func WithMiddlewareAfter(after ...AfterExecute) Option {
function WithMiddlewareAfterT (line 57) | func WithMiddlewareAfterT(after ...AfterExecuteT) Option {
function WithMiddlewareBefore (line 64) | func WithMiddlewareBefore(before ...BeforeExecute) Option {
function WithMiddlewareBeforeT (line 71) | func WithMiddlewareBeforeT(beforeT ...BeforeExecuteT) Option {
FILE: builder_request.go
method RequestRepeat (line 12) | func (qt *cute) RequestRepeat(count int) RequestHTTPBuilder {
method RequestRepeatDelay (line 22) | func (qt *cute) RequestRepeatDelay(delay time.Duration) RequestHTTPBuild...
method RequestRepeatPolitic (line 33) | func (qt *cute) RequestRepeatPolitic(politic *RequestRepeatPolitic) Requ...
method RequestRepeatOptional (line 51) | func (qt *cute) RequestRepeatOptional(option bool) RequestHTTPBuilder {
method RequestRepeatBroken (line 60) | func (qt *cute) RequestRepeatBroken(broken bool) RequestHTTPBuilder {
method RequestRetry (line 69) | func (qt *cute) RequestRetry(count int) RequestHTTPBuilder {
method RequestRetryDelay (line 78) | func (qt *cute) RequestRetryDelay(delay time.Duration) RequestHTTPBuilder {
method RequestRetryPolitic (line 88) | func (qt *cute) RequestRetryPolitic(politic *RequestRetryPolitic) Reques...
method RequestRetryOptional (line 100) | func (qt *cute) RequestRetryOptional(option bool) RequestHTTPBuilder {
method RequestRetryBroken (line 108) | func (qt *cute) RequestRetryBroken(broken bool) RequestHTTPBuilder {
method RequestSanitizerHook (line 116) | func (qt *cute) RequestSanitizerHook(hook RequestSanitizerHook) RequestH...
method ResponseSanitizerHook (line 124) | func (qt *cute) ResponseSanitizerHook(hook ResponseSanitizerHook) Reques...
method Request (line 130) | func (qt *cute) Request(r *http.Request) ExpectHTTPBuilder {
method RequestBuilder (line 136) | func (qt *cute) RequestBuilder(r ...RequestBuilder) ExpectHTTPBuilder {
FILE: builder_retry.go
method Retry (line 8) | func (qt *cute) Retry(count int) MiddlewareRequest {
method RetryDelay (line 21) | func (qt *cute) RetryDelay(delay time.Duration) MiddlewareRequest {
FILE: builder_table.go
method CreateTableTest (line 5) | func (qt *cute) CreateTableTest() MiddlewareTable {
method PutNewTest (line 11) | func (qt *cute) PutNewTest(name string, r *http.Request, expect *Expect)...
method PutTests (line 34) | func (qt *cute) PutTests(tests ...*Test) TableTest {
method fillBaseProps (line 56) | func (qt *cute) fillBaseProps(t *Test) {
method NextTest (line 79) | func (qt *cute) NextTest() NextTestBuilder {
FILE: builder_table_test.go
function TestFillBaseProps_WhenBasePropsIsNil (line 10) | func TestFillBaseProps_WhenBasePropsIsNil(t *testing.T) {
function TestFillBaseProps_WhenBasePropsIsNotNil (line 21) | func TestFillBaseProps_WhenBasePropsIsNotNil(t *testing.T) {
function TestFillBaseProps_WhenBasePropsIsNotNil_After (line 66) | func TestFillBaseProps_WhenBasePropsIsNotNil_After(t *testing.T) {
function TestFillBaseProps_WhenBasePropsIsNotNil_Middleware (line 110) | func TestFillBaseProps_WhenBasePropsIsNotNil_Middleware(t *testing.T) {
FILE: builder_test.go
function TestBuilderAfterTest (line 12) | func TestBuilderAfterTest(t *testing.T) {
function TestBuilderAfterTestTwoStep (line 48) | func TestBuilderAfterTestTwoStep(t *testing.T) {
function TestNewTestBuilder (line 142) | func TestNewTestBuilder(t *testing.T) {
function TestHTTPTestMaker (line 157) | func TestHTTPTestMaker(t *testing.T) {
function TestCreateDefaultTest (line 349) | func TestCreateDefaultTest(t *testing.T) {
function TestCreateTableTest (line 371) | func TestCreateTableTest(t *testing.T) {
function TestPutNewTest (line 378) | func TestPutNewTest(t *testing.T) {
function TestPutTests (line 404) | func TestPutTests(t *testing.T) {
function TestCreateHTTPTestMakerWithHttpClient (line 442) | func TestCreateHTTPTestMakerWithHttpClient(t *testing.T) {
type rt (line 456) | type rt struct
method RoundTrip (line 459) | func (r *rt) RoundTrip(*http.Request) (*http.Response, error) {
function TestCreateHTTPMakerOps (line 463) | func TestCreateHTTPMakerOps(t *testing.T) {
FILE: cute.go
type cute (line 14) | type cute struct
method ExecuteTest (line 62) | func (qt *cute) ExecuteTest(ctx context.Context, t tProvider) []Result...
method executeTests (line 118) | func (qt *cute) executeTests(ctx context.Context, allureProvider allur...
method executeInsideAllure (line 152) | func (qt *cute) executeInsideAllure(ctx context.Context, allureProvide...
method executeTestsInsideStep (line 162) | func (qt *cute) executeTestsInsideStep(ctx context.Context, stepCtx pr...
type allureInformation (line 29) | type allureInformation struct
type allureLabels (line 35) | type allureLabels struct
type allureLinks (line 54) | type allureLinks struct
function createAllureT (line 96) | func createAllureT(t *testing.T) *common.Common {
FILE: errors/broken.go
type BrokenError (line 5) | type BrokenError interface
function NewBrokenError (line 12) | func NewBrokenError(err string) error {
function WrapBrokenError (line 20) | func WrapBrokenError(err error) error {
FILE: errors/error.go
constant ActualField (line 7) | ActualField = "Actual"
constant ExpectedField (line 9) | ExpectedField = "Expected"
type AssertError (line 13) | type AssertError interface
type WithNameError (line 23) | type WithNameError interface
type WithFields (line 30) | type WithFields interface
type WithTrace (line 36) | type WithTrace interface
type Attachment (line 42) | type Attachment struct
type WithAttachments (line 49) | type WithAttachments interface
type CuteError (line 55) | type CuteError struct
method Unwrap (line 125) | func (a *CuteError) Unwrap() error {
method Error (line 131) | func (a *CuteError) Error() string {
method GetName (line 147) | func (a *CuteError) GetName() string {
method SetName (line 153) | func (a *CuteError) SetName(name string) {
method GetFields (line 158) | func (a *CuteError) GetFields() map[string]interface{} {
method PutFields (line 163) | func (a *CuteError) PutFields(fields map[string]interface{}) {
method GetAttachments (line 170) | func (a *CuteError) GetAttachments() []*Attachment {
method PutAttachment (line 175) | func (a *CuteError) PutAttachment(attachment *Attachment) {
method IsOptional (line 180) | func (a *CuteError) IsOptional() bool {
method SetOptional (line 185) | func (a *CuteError) SetOptional(opt bool) {
method IsRequire (line 190) | func (a *CuteError) IsRequire() bool {
method SetRequire (line 195) | func (a *CuteError) SetRequire(b bool) {
method IsBroken (line 200) | func (a *CuteError) IsBroken() bool {
method SetBroken (line 205) | func (a *CuteError) SetBroken(b bool) {
method GetTrace (line 210) | func (a *CuteError) GetTrace() string {
method SetTrace (line 215) | func (a *CuteError) SetTrace(trace string) {
function NewCuteError (line 86) | func NewCuteError(name string, err error) *CuteError {
function NewAssertError (line 94) | func NewAssertError(name string, message string, actual interface{}, exp...
function NewAssertErrorWithMessage (line 107) | func NewAssertErrorWithMessage(name string, message string) error {
function NewEmptyAssertError (line 115) | func NewEmptyAssertError(name string, message string) AssertError {
FILE: errors/optional.go
type OptionalError (line 5) | type OptionalError interface
function NewOptionalError (line 11) | func NewOptionalError(err string) error {
function WrapOptionalError (line 19) | func WrapOptionalError(err error) error {
FILE: errors/require.go
type RequireError (line 5) | type RequireError interface
type requireError (line 10) | type requireError struct
function NewRequireError (line 16) | func NewRequireError(err string) error {
function WrapRequireError (line 24) | func WrapRequireError(err error) error {
FILE: errors/trace.go
function NewErrorWithTrace (line 4) | func NewErrorWithTrace(err, trace string) error {
function WrapErrorWithTrace (line 12) | func WrapErrorWithTrace(err error, trace string) error {
FILE: examples/custom_asserts.go
function CustomAssertBodyWithCustomError (line 13) | func CustomAssertBodyWithCustomError() cute.AssertBody {
function CustomAssertBody (line 23) | func CustomAssertBody() cute.AssertBody {
function CustomAssertBodyT (line 33) | func CustomAssertBodyT() cute.AssertBodyT {
function CustomAssertBodyWithAllureStep (line 41) | func CustomAssertBodyWithAllureStep() cute.AssertBodyT {
function CustomAssertHeaders (line 60) | func CustomAssertHeaders() cute.AssertHeaders {
function CustomAssertResponse (line 70) | func CustomAssertResponse() cute.AssertResponse {
FILE: examples/inside_step_test.go
function TestInsideStep (line 19) | func TestInsideStep(t *testing.T) {
FILE: examples/masked_data_test.go
function TestSanitizer (line 19) | func TestSanitizer(t *testing.T) {
FILE: examples/parallel_test.go
function Test_Async_1 (line 16) | func Test_Async_1(t *testing.T) {
function Test_Async_2 (line 51) | func Test_Async_2(t *testing.T) {
FILE: examples/single_test.go
function Test_Single_1 (line 26) | func Test_Single_1(t *testing.T) {
function Test_Single_Broken (line 78) | func Test_Single_Broken(t *testing.T) {
function Test_Single_RepeatPolitic_Optional_Success_Test (line 103) | func Test_Single_RepeatPolitic_Optional_Success_Test(t *testing.T) {
function Test_Single_RepeatPolitic_Broken_Failed_Test (line 121) | func Test_Single_RepeatPolitic_Broken_Failed_Test(t *testing.T) {
function Test_Single_Broken_2 (line 139) | func Test_Single_Broken_2(t *testing.T) {
function Test_Single_2_AllureRunner (line 163) | func Test_Single_2_AllureRunner(t *testing.T) {
FILE: examples/suite/common.go
type ExampleSuite (line 13) | type ExampleSuite struct
method BeforeAll (line 20) | func (i *ExampleSuite) BeforeAll(t provider.T) {
method BeforeEach (line 31) | func (i *ExampleSuite) BeforeEach(t provider.T) {
FILE: examples/suite/main_test.go
function TestExampleSuite (line 13) | func TestExampleSuite(t *testing.T) {
FILE: examples/suite/one_step.go
method Test_OneStep (line 66) | func (i *ExampleSuite) Test_OneStep(t provider.T) {
FILE: examples/suite/one_step_errors.go
method Test_OneStep_Errors (line 17) | func (i *ExampleSuite) Test_OneStep_Errors(t provider.T) {
FILE: examples/suite/simple.go
method Test_Simple (line 21) | func (i *ExampleSuite) Test_Simple(t provider.T) {
FILE: examples/suite/two_steps.go
method Test_TwoSteps (line 27) | func (i *ExampleSuite) Test_TwoSteps(t provider.T) {
FILE: examples/table_test/table_test.go
function init (line 21) | func init() {
function Test_Table (line 25) | func Test_Table(t *testing.T) {
function Test_Table_Array (line 55) | func Test_Table_Array(t *testing.T) {
function Test_One_Execute (line 101) | func Test_One_Execute(t *testing.T) {
function Test_Array_Retry_OptionalFirstTries (line 116) | func Test_Array_Retry_OptionalFirstTries(t *testing.T) {
function Test_Array_Retry_OptionalFirstTries_UltimatelyFailing (line 161) | func Test_Array_Retry_OptionalFirstTries_UltimatelyFailing(t *testing.T) {
function Test_Array_TimeoutRetry (line 205) | func Test_Array_TimeoutRetry(t *testing.T) {
function Test_Array (line 244) | func Test_Array(t *testing.T) {
function Test_Array_All_Parallel (line 286) | func Test_Array_All_Parallel(t *testing.T) {
function Test_Array_Some_Parallel (line 351) | func Test_Array_Some_Parallel(t *testing.T) {
function Test_Array_Retry (line 420) | func Test_Array_Retry(t *testing.T) {
function Test_Array_Timeout (line 465) | func Test_Array_Timeout(t *testing.T) {
FILE: examples/two_step_test.go
function Test_TwoSteps_1 (line 19) | func Test_TwoSteps_1(t *testing.T) {
function Test_TwoSteps_2_AllureRunner (line 48) | func Test_TwoSteps_2_AllureRunner(t *testing.T) {
function Test_TwoSteps_3 (line 76) | func Test_TwoSteps_3(t *testing.T) {
FILE: examples/upload_file_test.go
function TestUploadFile (line 14) | func TestUploadFile(t *testing.T) {
FILE: init.go
function init (line 5) | func init() {
function NewTestBuilder (line 11) | func NewTestBuilder() AllureBuilder {
FILE: interface.go
type AllureBuilder (line 12) | type AllureBuilder interface
type AllureInfoBuilder (line 25) | type AllureInfoBuilder interface
type AllureLinksBuilder (line 37) | type AllureLinksBuilder interface
type AllureLabelsBuilder (line 46) | type AllureLabelsBuilder interface
type CreateBuilder (line 68) | type CreateBuilder interface
type MiddlewareTable (line 80) | type MiddlewareTable interface
type MiddlewareRequest (line 88) | type MiddlewareRequest interface
type RetryPolitic (line 97) | type RetryPolitic interface
type BeforeTest (line 112) | type BeforeTest interface
type After (line 123) | type After interface
type AfterTest (line 134) | type AfterTest interface
type AfterTestExecute (line 145) | type AfterTestExecute interface
type TableTest (line 153) | type TableTest interface
type RequestHTTPBuilder (line 162) | type RequestHTTPBuilder interface
type RequestParams (line 187) | type RequestParams interface
type ExpectHTTPBuilder (line 238) | type ExpectHTTPBuilder interface
type ControlTest (line 342) | type ControlTest interface
type NextTestBuilder (line 350) | type NextTestBuilder interface
type ResultsHTTPBuilder (line 357) | type ResultsHTTPBuilder interface
type BeforeExecute (line 370) | type BeforeExecute
type BeforeExecuteT (line 373) | type BeforeExecuteT
type AfterExecute (line 376) | type AfterExecute
type AfterExecuteT (line 379) | type AfterExecuteT
FILE: internal/utils/body.go
function GetBody (line 10) | func GetBody(body io.ReadCloser) ([]byte, error) {
function DrainBody (line 25) | func DrainBody(body io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
FILE: internal/utils/json.go
function ToJSON (line 9) | func ToJSON(v interface{}) (string, error) {
function PrettyJSON (line 16) | func PrettyJSON(b []byte) ([]byte, error) {
FILE: json_marshaler.go
type JSONMarshaler (line 6) | type JSONMarshaler interface
type jsonMarshaler (line 11) | type jsonMarshaler struct
method Marshal (line 14) | func (j jsonMarshaler) Marshal(v any) ([]byte, error) {
method Unmarshal (line 18) | func (j jsonMarshaler) Unmarshal(data []byte, v any) error {
FILE: jsonschema.go
method validateJSONSchema (line 12) | func (it *Test) validateJSONSchema(t internalT, body []byte) []error {
function checkJSONSchema (line 33) | func checkJSONSchema(expect gojsonschema.JSONLoader, data []byte) []error {
function createJSONSchemaError (line 53) | func createJSONSchemaError(err gojsonschema.ResultError) error {
FILE: jsonschema_test.go
function TestValidateJSONSchemaEmptySchema (line 10) | func TestValidateJSONSchemaEmptySchema(t *testing.T) {
function TestValidateJSONSchemaFromString (line 21) | func TestValidateJSONSchemaFromString(t *testing.T) {
function TestValidateJSONSchemaFromStringWithError (line 62) | func TestValidateJSONSchemaFromStringWithError(t *testing.T) {
function TestValidateJSONSchemaFromByteWithTwoError (line 112) | func TestValidateJSONSchemaFromByteWithTwoError(t *testing.T) {
FILE: logger.go
type tlogger (line 7) | type tlogger interface
method Info (line 14) | func (it *Test) Info(t tlogger, format string, args ...interface{}) {
method Error (line 19) | func (it *Test) Error(t tlogger, format string, args ...interface{}) {
method Debug (line 24) | func (it *Test) Debug(t tlogger, format string, args ...interface{}) {
method logf (line 28) | func (it *Test) logf(t tlogger, level, format string, args ...interface{...
method errorf (line 42) | func (it *Test) errorf(t tlogger, level, format string, args ...interfac...
FILE: provider.go
type T (line 9) | type T interface
type allureProvider (line 17) | type allureProvider interface
type internalT (line 29) | type internalT interface
type tProvider (line 39) | type tProvider interface
type logProvider (line 52) | type logProvider interface
type stepProvider (line 57) | type stepProvider interface
type attachmentProvider (line 62) | type attachmentProvider interface
type parametersProvider (line 67) | type parametersProvider interface
type infoAllureProvider (line 72) | type infoAllureProvider interface
type labelsAllureProvider (line 83) | type labelsAllureProvider interface
type linksAllureProvider (line 102) | type linksAllureProvider interface
FILE: request.go
type RequestBuilder (line 8) | type RequestBuilder
type File (line 13) | type File struct
type requestOptions (line 19) | type requestOptions struct
function newRequestOptions (line 32) | func newRequestOptions() *requestOptions {
function WithMethod (line 42) | func WithMethod(method string) func(o *requestOptions) {
function WithURL (line 49) | func WithURL(url *url.URL) func(o *requestOptions) {
function WithURI (line 56) | func WithURI(uri string) func(o *requestOptions) {
function WithHeaders (line 63) | func WithHeaders(headers map[string][]string) func(o *requestOptions) {
function WithHeadersKV (line 72) | func WithHeadersKV(name string, value string) func(o *requestOptions) {
function WithQueryKV (line 79) | func WithQueryKV(name string, value string) func(o *requestOptions) {
function WithQuery (line 86) | func WithQuery(queries map[string][]string) func(o *requestOptions) {
function WithBody (line 95) | func WithBody(body []byte) func(o *requestOptions) {
function WithMarshalBody (line 102) | func WithMarshalBody(body interface{}) func(o *requestOptions) {
function WithFileFormKV (line 109) | func WithFileFormKV(name string, file *File) func(o *requestOptions) {
function WithFileForm (line 116) | func WithFileForm(fileForms map[string]*File) func(o *requestOptions) {
function WithFormKV (line 125) | func WithFormKV(name string, body []byte) func(o *requestOptions) {
function WithForm (line 132) | func WithForm(forms map[string][]byte) func(o *requestOptions) {
FILE: request_test.go
function TestRequest (line 11) | func TestRequest(t *testing.T) {
FILE: result.go
type ResultState (line 8) | type ResultState
constant ResultStateSuccess (line 12) | ResultStateSuccess ResultState = iota
constant ResultStateBroken (line 13) | ResultStateBroken
constant ResultStateFail (line 14) | ResultStateFail
constant resultStateFailNow (line 17) | resultStateFailNow
type testResults (line 20) | type testResults struct
method GetHTTPResponse (line 36) | func (r *testResults) GetHTTPResponse() *http.Response {
method GetErrors (line 40) | func (r *testResults) GetErrors() []error {
method GetName (line 44) | func (r *testResults) GetName() string {
method GetResultState (line 48) | func (r *testResults) GetResultState() ResultState {
function newTestResult (line 27) | func newTestResult(name string, resp *http.Response, state ResultState, ...
FILE: result_test.go
function TestResult (line 11) | func TestResult(t *testing.T) {
FILE: roundtripper.go
method makeRequest (line 19) | func (it *Test) makeRequest(t internalT, req *http.Request) (*http.Respo...
method doRequest (line 69) | func (it *Test) doRequest(t T, baseReq *http.Request) (*http.Response, e...
method validateResponseCode (line 134) | func (it *Test) validateResponseCode(resp *http.Response) error {
method addInformationRequest (line 146) | func (it *Test) addInformationRequest(t T, req *http.Request) error {
function copyRequest (line 204) | func copyRequest(ctx context.Context, req *http.Request) (*http.Request,...
method addInformationResponse (line 219) | func (it *Test) addInformationResponse(t T, response *http.Response) err...
method createTitle (line 279) | func (it *Test) createTitle(try, countRepeat int, req *http.Request) str...
FILE: step.go
method executeWithStep (line 11) | func (it *Test) executeWithStep(t internalT, stepName string, execute fu...
function processStepErrors (line 28) | func processStepErrors(stepCtx provider.StepCtx, errs []error) {
FILE: test.go
constant defaultExecuteTestTime (line 23) | defaultExecuteTestTime = 10 * time.Second
constant defaultDelayRepeat (line 24) | defaultDelayRepeat = 1 * time.Second
type RequestSanitizerHook (line 34) | type RequestSanitizerHook
type ResponseSanitizerHook (line 38) | type ResponseSanitizerHook
type Test (line 43) | type Test struct
method Execute (line 140) | func (it *Test) Execute(ctx context.Context, t tProvider) ResultsHTTPB...
method clearFields (line 176) | func (it *Test) clearFields() {
method initEmptyFields (line 185) | func (it *Test) initEmptyFields() {
method executeInsideStep (line 232) | func (it *Test) executeInsideStep(ctx context.Context, t internalT) Re...
method executeInsideAllure (line 242) | func (it *Test) executeInsideAllure(ctx context.Context, allureProvide...
method startRepeatableTest (line 259) | func (it *Test) startRepeatableTest(ctx context.Context, t internalT) ...
method startTestInsideStep (line 304) | func (it *Test) startTestInsideStep(ctx context.Context, t internalT) ...
method processTestErrors (line 327) | func (it *Test) processTestErrors(t internalT, errs []error) ResultSta...
method startTest (line 391) | func (it *Test) startTest(ctx context.Context, t internalT) (*http.Res...
method afterTest (line 441) | func (it *Test) afterTest(t internalT, resp *http.Response, errs []err...
method beforeTest (line 465) | func (it *Test) beforeTest(t internalT, req *http.Request) []error {
method createRequest (line 490) | func (it *Test) createRequest(ctx context.Context) (*http.Request, err...
method buildRequest (line 516) | func (it *Test) buildRequest(ctx context.Context) (*http.Request, erro...
method validateRequest (line 654) | func (it *Test) validateRequest(req *http.Request) error {
method validateResponse (line 666) | func (it *Test) validateResponse(t internalT, resp *http.Response) []e...
type Retry (line 68) | type Retry struct
type Request (line 76) | type Request struct
type RequestRetryPolitic (line 87) | type RequestRetryPolitic struct
type RequestRepeatPolitic (line 96) | type RequestRepeatPolitic struct
type Middleware (line 104) | type Middleware struct
type AllureStep (line 112) | type AllureStep struct
type Expect (line 117) | type Expect struct
type ExpectJSONSchema (line 133) | type ExpectJSONSchema struct
function createFormFile (line 606) | func createFormFile(mp *multipart.Writer, fieldName string, file *File) ...
function createFormField (line 640) | func createFormField(mp *multipart.Writer, fieldName string, body []byte...
FILE: test_test.go
function TestCreateRequest (line 20) | func TestCreateRequest(t *testing.T) {
function TestCreateRequestBuilder (line 35) | func TestCreateRequestBuilder(t *testing.T) {
function TestCreateRequestBuilder_MarshalBody (line 66) | func TestCreateRequestBuilder_MarshalBody(t *testing.T) {
function TestValidateRequestEmptyUrl (line 93) | func TestValidateRequestEmptyUrl(t *testing.T) {
function TestValidateRequestEmptyMethod (line 99) | func TestValidateRequestEmptyMethod(t *testing.T) {
function TestValidateResponseEmpty (line 108) | func TestValidateResponseEmpty(t *testing.T) {
function TestValidateResponseCode (line 119) | func TestValidateResponseCode(t *testing.T) {
function TestValidateResponseWithErrors (line 129) | func TestValidateResponseWithErrors(t *testing.T) {
type mockRoundTripper (line 170) | type mockRoundTripper struct
method RoundTrip (line 172) | func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Respons...
function TestSanitizeURLHook (line 180) | func TestSanitizeURLHook(t *testing.T) {
function TestSanitizeURL_LastRequestURL (line 219) | func TestSanitizeURL_LastRequestURL(t *testing.T) {
function sanitizeKeyParam (line 243) | func sanitizeKeyParam(mask string) RequestSanitizerHook {
function TestSanitizeURL_RealRequest (line 251) | func TestSanitizeURL_RealRequest(t *testing.T) {
Condensed preview — 72 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (290K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 672,
"preview": "---\nname: Bug report \\\nabout: Create a report to help us improve \\\ntitle: ' ' \\\nlabels: ' ' \\\nassignees: ' ' \n\n---\n\n**De"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 610,
"preview": "---\nname: Feature request \\\nabout: Suggest an idea for this project \\\ntitle: '' \\\nlabels: '' \\\nassignees: ''\n\n---\n\n**Is "
},
{
"path": ".github/workflows/main.yml",
"chars": 1236,
"preview": "name: CI\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n build_and_test:\n run"
},
{
"path": ".gitignore",
"chars": 239,
"preview": ".idea/\ntestdata/\nallure-results/\nbin/\nvendor/\n\n# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Te"
},
{
"path": ".golangci.yaml",
"chars": 1586,
"preview": "run:\n timeout: 10m\n issues-exit-code: 1\n tests: true\n skip-dirs:\n - bin\n - vendor\n - var\n - tmp\n skip-f"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 2139,
"preview": "export GO111MODULE=on\nexport GOSUMDB=off\nLOCAL_BIN:=$(CURDIR)/bin\n\n##################### GOLANG-CI RELATED CHECKS ######"
},
{
"path": "README.MD",
"chars": 17593,
"preview": "<p align=\"center\">\n <img src=\".images/cute.png\" alt=\"cute\"/>\n</p>\n\n# CUTE — create your tests easily\n\nHTTP and REST API"
},
{
"path": "allure.go",
"chars": 2152,
"preview": "package cute\n\nfunc (qt *cute) setAllureInformation(t allureProvider) {\n\t// Log main vars to allureProvider\n\tqt.setLabels"
},
{
"path": "assert.go",
"chars": 3451,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n)\n\n// This is type of asserts, for create some assert with using custom logic.\n\n// As"
},
{
"path": "assert_broken.go",
"chars": 1278,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/ozontech/cute/errors\"\n)\n\nfunc brokenAssertHeaders(assert AssertHeaders)"
},
{
"path": "assert_broken_test.go",
"chars": 2190,
"preview": "package cute\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"testing\"\n\n\tcuteErrors \"github.com/ozontech/cute/errors\"\n\t\"github.com/stre"
},
{
"path": "assert_optional.go",
"chars": 1310,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/ozontech/cute/errors\"\n)\n\nfunc optionalAssertHeaders(assert AssertHeader"
},
{
"path": "assert_optional_test.go",
"chars": 2268,
"preview": "package cute\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"testing\"\n\n\tcuteErrors \"github.com/ozontech/cute/errors\"\n\t\"github.com/stre"
},
{
"path": "assert_require.go",
"chars": 1294,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/ozontech/cute/errors\"\n)\n\nfunc requireAssertHeaders(assert AssertHeaders"
},
{
"path": "assert_require_test.go",
"chars": 2228,
"preview": "package cute\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"testing\"\n\n\tcuteErrors \"github.com/ozontech/cute/errors\"\n\t\"github.com/stre"
},
{
"path": "assert_trace.go",
"chars": 2294,
"preview": "package cute\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"runtime\"\n\n\t\"github.com/ozontech/cute/errors\"\n)\n\n// assertHeadersWithTrace is"
},
{
"path": "asserts/headers/headers.go",
"chars": 742,
"preview": "package headers\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/ozontech/cute\"\n\t\"github.com/ozontech/cute/errors\"\n)\n\n// Prese"
},
{
"path": "asserts/headers/headers_test.go",
"chars": 791,
"preview": "package headers\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestPresent(t *testing."
},
{
"path": "asserts/json/json.go",
"chars": 5466,
"preview": "package json\n\nimport (\n\t\"fmt\"\n\n\tjd \"github.com/josephburnett/jd/lib\"\n\t\"github.com/ohler55/ojg/jp\"\n\t\"github.com/ohler55/o"
},
{
"path": "asserts/json/json_test.go",
"chars": 22387,
"preview": "package json\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype "
},
{
"path": "asserts/json/util.go",
"chars": 9336,
"preview": "package json\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/ohler55/ojg/oj\"\n\t\"github.com/ozontech/cute/er"
},
{
"path": "builder.go",
"chars": 3427,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\nconst defaultHTTPTimeout = 30\n\nvar (\n\terrorAssertIsNil = \"assert must be n"
},
{
"path": "builder_allure.go",
"chars": 3111,
"preview": "package cute\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n)\n\nfunc (qt *cute) Parallel() AllureBuilder {"
},
{
"path": "builder_asserts.go",
"chars": 9442,
"preview": "package cute\n\nimport \"time\"\n\nfunc (qt *cute) AssertBody(asserts ...AssertBody) ExpectHTTPBuilder {\n\ttrace := getTrace()\n"
},
{
"path": "builder_middleware.go",
"chars": 1782,
"preview": "package cute\n\nfunc (qt *cute) StepName(name string) MiddlewareRequest {\n\tqt.tests[qt.countTests].AllureStep.Name = name\n"
},
{
"path": "builder_option.go",
"chars": 1959,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\ntype options struct {\n\thttpClient *http.Client\n\thttpTimeout tim"
},
{
"path": "builder_request.go",
"chars": 5014,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\n// RequestRepeat is a function for set options in request\n// if response.C"
},
{
"path": "builder_retry.go",
"chars": 781,
"preview": "package cute\n\nimport \"time\"\n\n// Retry is a function for configure test repeat\n// if response.Code != Expect.Code or any "
},
{
"path": "builder_table.go",
"chars": 1931,
"preview": "package cute\n\nimport \"net/http\"\n\nfunc (qt *cute) CreateTableTest() MiddlewareTable {\n\tqt.isTableTest = true\n\n\treturn qt\n"
},
{
"path": "builder_table_test.go",
"chars": 4902,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFillBaseProps_WhenBase"
},
{
"path": "builder_test.go",
"chars": 12008,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n\t\"github.com/stretchr"
},
{
"path": "cute.go",
"chars": 3964,
"preview": "package cute\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n\t\"github.com/ozonte"
},
{
"path": "errors/broken.go",
"chars": 593,
"preview": "package errors\n\n// BrokenError is an interface for set errors like Broken errors.\n// If the function returns an error, w"
},
{
"path": "errors/error.go",
"chars": 5591,
"preview": "package errors\n\nimport \"fmt\"\n\nconst (\n\t// ActualField is a key for actual value in error fields\n\tActualField = \"Actual\"\n"
},
{
"path": "errors/optional.go",
"chars": 606,
"preview": "package errors\n\n// OptionalError is an interface for set errors like Optional errors.\n// If the function returns an erro"
},
{
"path": "errors/require.go",
"chars": 720,
"preview": "package errors\n\n// RequireError is an interface for set errors like require error.\n// If the function returns an error, "
},
{
"path": "errors/trace.go",
"chars": 363,
"preview": "package errors\n\n// NewErrorWithTrace is a function for create error with trace\nfunc NewErrorWithTrace(err, trace string)"
},
{
"path": "examples/custom_asserts.go",
"chars": 1622,
"preview": "package examples\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n\t\"github.com/ozontech/cute"
},
{
"path": "examples/inside_step_test.go",
"chars": 1075,
"preview": "//go:build example\n// +build example\n\npackage examples\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t"
},
{
"path": "examples/masked_data_test.go",
"chars": 1608,
"preview": "//go:build example\n// +build example\n\npackage examples\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t"
},
{
"path": "examples/parallel_test.go",
"chars": 2085,
"preview": "//go:build example\n// +build example\n\npackage examples\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com"
},
{
"path": "examples/single_test.go",
"chars": 5004,
"preview": "//go:build example\n// +build example\n\npackage examples\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url"
},
{
"path": "examples/suite/common.go",
"chars": 659,
"preview": "package suite\n\nimport (\n\t\"net/url\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider\"\n\t\"github.com/ozontech/allure"
},
{
"path": "examples/suite/main_test.go",
"chars": 294,
"preview": "//go:build example\n// +build example\n\npackage suite\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/ozontech/allure-go/pkg/fram"
},
{
"path": "examples/suite/one_step.go",
"chars": 3921,
"preview": "package suite\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"time\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework"
},
{
"path": "examples/suite/one_step_errors.go",
"chars": 2171,
"preview": "package suite\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provider"
},
{
"path": "examples/suite/resources/example_valid_request.json",
"chars": 2384,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n \"type\": \"array\",\n \"items\": [\n {\n \"type\": \"object\",\n"
},
{
"path": "examples/suite/simple.go",
"chars": 864,
"preview": "package suite\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/ozontech/allure-go/pkg/framework/provide"
},
{
"path": "examples/suite/two_steps.go",
"chars": 1942,
"preview": "package suite\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/o"
},
{
"path": "examples/table_test/table_test.go",
"chars": 10343,
"preview": "//go:build example\n// +build example\n\npackage table_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"strc"
},
{
"path": "examples/two_step_test.go",
"chars": 2916,
"preview": "//go:build example\n// +build example\n\npackage examples\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\t\"ti"
},
{
"path": "examples/upload_file_test.go",
"chars": 641,
"preview": "//go:build example_upload_file\n// +build example_upload_file\n\npackage examples\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"testin"
},
{
"path": "go.mod",
"chars": 961,
"preview": "module github.com/ozontech/cute\n\ngo 1.21\n\nrequire (\n\tgithub.com/josephburnett/jd v1.7.1\n\tgithub.com/ohler55/ojg v1.21.1\n"
},
{
"path": "go.sum",
"chars": 8276,
"preview": "github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go"
},
{
"path": "init.go",
"chars": 297,
"preview": "package cute\n\nvar commonBuilder *HTTPTestMaker\n\nfunc init() {\n\tcommonBuilder = NewHTTPTestMaker()\n}\n\n// NewTestBuilder i"
},
{
"path": "interface.go",
"chars": 16495,
"preview": "package cute\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n)\n\n// AllureBuilder i"
},
{
"path": "internal/utils/body.go",
"chars": 761,
"preview": "package utils\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net/http\"\n)\n\n// GetBody get body from IO\nfunc GetBody(body io.ReadCloser) ([]by"
},
{
"path": "internal/utils/json.go",
"chars": 479,
"preview": "package utils\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n)\n\n// ToJSON returns string Json representation of any object that can"
},
{
"path": "json_marshaler.go",
"chars": 432,
"preview": "package cute\n\nimport \"encoding/json\"\n\n// JSONMarshaler is marshaler which use for marshal/unmarshal JSON to/from struct\n"
},
{
"path": "jsonschema.go",
"chars": 2018,
"preview": "package cute\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ozontech/cute/errors\"\n\t\"github.com/xeipuuv/gojsonschema\"\n)\n\n// Validate is a"
},
{
"path": "jsonschema_test.go",
"chars": 3364,
"preview": "package cute\n\nimport (\n\t\"testing\"\n\n\tcuteErrors \"github.com/ozontech/cute/errors\"\n\t\"github.com/stretchr/testify/require\"\n"
},
{
"path": "logger.go",
"chars": 1521,
"preview": "package cute\n\nimport (\n\t\"fmt\"\n)\n\ntype tlogger interface {\n\tName() string\n\tLogf(format string, args ...any)\n\tErrorf(forma"
},
{
"path": "provider.go",
"chars": 2239,
"preview": "package cute\n\nimport (\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n\t\"github.com/ozontech/allure-go/pkg/framework/provide"
},
{
"path": "request.go",
"chars": 3477,
"preview": "package cute\n\nimport (\n\t\"net/url\"\n)\n\n// RequestBuilder is a function for set options in request\ntype RequestBuilder func"
},
{
"path": "request_test.go",
"chars": 991,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRequest(t *"
},
{
"path": "result.go",
"chars": 942,
"preview": "package cute\n\nimport (\n\t\"net/http\"\n)\n\n// ResultState is state of test\ntype ResultState int\n\n// ResultState is state of t"
},
{
"path": "result_test.go",
"chars": 661,
"preview": "package cute\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestResult(t *te"
},
{
"path": "roundtripper.go",
"chars": 7338,
"preview": "package cute\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/ozontech/allure-go"
},
{
"path": "step.go",
"chars": 2031,
"preview": "package cute\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ozontech/allure-go/pkg/allure\"\n\t\"github.com/ozontech/allure-go/pkg/framework"
},
{
"path": "test.go",
"chars": 16631,
"preview": "package cute\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"testi"
},
{
"path": "test_test.go",
"chars": 5824,
"preview": "package cute\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"strings\"\n\t\"test"
}
]
About this extraction
This page contains the full source code of the ozontech/cute GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 72 files (255.0 KB), approximately 73.4k tokens, and a symbol index with 470 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.