Skip to content

Commit d159043

Browse files
committed
Update HACKING.md
1 parent c1e0a61 commit d159043

2 files changed

Lines changed: 95 additions & 3 deletions

File tree

HACKING.md

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
# Hacking guidelines
22

3-
## Developer dependencies
3+
<!-- toc -->
4+
5+
- [Instructions](#instructions)
6+
* [Developer dependencies](#developer-dependencies)
7+
* [Makefile targets](#makefile-targets)
8+
- [Internals](#internals)
9+
* [Object tree](#object-tree)
10+
* [Failure reporting](#failure-reporting)
11+
- [Code style](#code-style)
12+
* [Comment formatting](#comment-formatting)
13+
14+
<!-- tocstop -->
15+
16+
## Instructions
17+
18+
### Developer dependencies
419

520
To develop httpexpect, you need:
621

@@ -10,7 +25,7 @@ To develop httpexpect, you need:
1025

1126
`go install golang.org/x/tools/cmd/stringer@latest`
1227

13-
## Makefile targets
28+
### Makefile targets
1429

1530
Re-generate, build, lint, and test everything:
1631

@@ -48,7 +63,81 @@ Run go mod tidy:
4863
make tidy
4964
```
5065

51-
## Comment formatting
66+
Generate TOC in HACKING.md:
67+
68+
```
69+
make toc
70+
```
71+
72+
## Internals
73+
74+
### Object tree
75+
76+
The typical user workflow looks like this:
77+
78+
* create `Expect` instance (root object) using `httpexpect.Default` or `httpexpect.WithConfig`
79+
* use `Expect` methods to create `Request` instance (HTTP request builder)
80+
* use `Request` methods to configure HTTP request (e.g. `WithHeader`, `WithText`)
81+
* use `Request.Expect()` method to send HTTP request and receive HTTP response; the method returns `Response` instance (HTTP response matcher)
82+
* use `Response` methods to make assertions on HTTP response
83+
* use `Response` methods to create child matcher objects for HTTP response payload (e.g. `Response.Headers()` or `Response.Body()`)
84+
* use methods of matcher objects to make assertions on payload, or to create nested child matcher objects
85+
86+
All objects described above are linked into a tree using `chain` struct:
87+
88+
* every object has `chain` field
89+
* when a child object is created (e.g. `Expect` creates `Request`, `Request` creates `Response`, and so on), the child object clones `chain` of its parent and stores it inside its `chain` field
90+
* when an object performs an assertion (e.g. user calls `IsEqual`), it creates a temporary clone of its `chain` and uses it to report failure or success
91+
92+
`chain` maintains context needed to report succeeded or failed assertions:
93+
94+
* `AssertionContext` defines *where* the assertion happens: path to the assertion in object tree, pointer to current request and response, etc.
95+
* `AssertionHandler` defines *what* to do in response to success or failure
96+
* `AssertionSeverity` defines *how* to treat failures, either as fatal or non-fatal
97+
98+
These fields are inherited by child `chain` when it is cloned.
99+
100+
In addition, `chain` maintains a reference to its parent and flags indicating whether a failure happened on the `chain` or any of its children.
101+
102+
When success or failure is reported, the following happens:
103+
104+
* `chain` invokes `AssertionHandler` and passes `AssertionContext` and `AssertionFailure` to it
105+
* in case of failure, `chain` raises a flag on itself, indicating failure
106+
* in case of failure, `chain` raises a flag on its parents and garndparents (up to the tree root), indicating that their children have failures (this feature is rarely used)
107+
108+
These failure flags are then used to ignore all subsequent assertions on a failed branch of the object tree. For example, if you run this code:
109+
110+
```go
111+
e.GET("/test").Expect().Status(http.StatusOK).Body().IsObject()
112+
```
113+
114+
and if `Status()` assertion failed, then this branch of the tree will be marked as failed, and calls to `Body()` and `IsObject()` will be just ignored. This is achieved by inheriting failure flag when cloning `chain`, and checking this flag in every assertion.
115+
116+
### Failure reporting
117+
118+
`AssertionHandler` is an interface that is used to handle every succeeded or failed assertion (like `IsEqual`).
119+
120+
It can be implemented by user if the user needs very precise control on assertion handling. In most cases, however, user does not need it, and just uses `DefaultAssertionHandler` implementation, which does the following:
121+
122+
* pass `AssertionContext` and `AssertionFailure` to `Formatter`, to get formatted message
123+
* when reporting failed assertion, pass formatted message to `Reporter`
124+
* when reporting succeeded assertion, pass formatted message to `Logger`
125+
126+
`Formatter`, `Reporter`, and `Logger` are also interfaces also can be implemented by user. Again, in most cases user can use default implemention for them:
127+
128+
* `DefaultFormatter` for `Formatter`
129+
* `testing.T`, `FatalReporter`, `AssertReporter`, or `RequireReporter` for `Reporter`
130+
* `testing.T` for `Logger`
131+
132+
In most cases, all the user needs to do is to select which reporter to use: `testing.T` or `FatalReporter` for non-fatal and fatal failure reports using standard `testing` package, and `AssertReporter` or `RequireReporter` for non-fatal and fatal failure reports using `testify` package (which adds nice backtrace and indentation).
133+
134+
For everything else, we will automatically employ default implementations (`DefaultFormatter`, `DefaultAssertionHandler`).
135+
136+
Note that `Formatter`, `Reporter`, and `Logger` are used only by `DefaultAssertionHandler`. If the user provides custom `AssertionHandler`, that implementation is free to ignore these three interfaces and can do whatever it wants.
137+
138+
## Code style
139+
140+
### Comment formatting
52141

53142
Exported functions should have documentation comments, formatted as follows:
54143

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,6 @@ ifneq ($(shell which mdspell),)
4040
mdspell -a README.md
4141
sort .spelling -o .spelling
4242
endif
43+
44+
toc:
45+
markdown-toc --maxdepth 3 -i HACKING.md

0 commit comments

Comments
 (0)