Skip to content

Commit 4fe1b84

Browse files
committed
Add Clone method to Context
This adds the ability to clone Chi contexts so that they may be used outside of the request/response lifecycle. This is useful in scenarios where the context may be held _after_ a request has been served to a user, like asynchronous background tasks, mirror testing, etc.
1 parent de0d16e commit 4fe1b84

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

context.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,22 @@ func (x *Context) Reset() {
9595
x.parentCtx = nil
9696
}
9797

98+
// Clone a routing context so that it may be used outside of the request/response lifecycle.
99+
func (c *Context) Clone() *Context {
100+
clone := *c
101+
102+
clone.URLParams.Keys = append([]string(nil), c.URLParams.Keys...)
103+
clone.URLParams.Values = append([]string(nil), c.URLParams.Values...)
104+
105+
clone.routeParams.Keys = append([]string(nil), c.routeParams.Keys...)
106+
clone.routeParams.Values = append([]string(nil), c.routeParams.Values...)
107+
108+
clone.RoutePatterns = append([]string(nil), c.RoutePatterns...)
109+
clone.methodsAllowed = append([]methodTyp(nil), c.methodsAllowed...)
110+
111+
return &clone
112+
}
113+
98114
// URLParam returns the corresponding URL parameter value from the request
99115
// routing context.
100116
func (x *Context) URLParam(key string) string {

context_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,47 @@ func TestReplaceWildcardsConsecutive(t *testing.T) {
102102
t.Fatalf("unexpected trailing wildcard behavior: %s", p)
103103
}
104104
}
105+
106+
func TestContext_Clone(t *testing.T) {
107+
orig := &Context{
108+
RoutePatterns: []string{"/v1", "/resources/{id}"},
109+
methodsAllowed: []methodTyp{mHEAD, mGET},
110+
URLParams: RouteParams{
111+
Keys: []string{"foo"},
112+
Values: []string{"bar"},
113+
},
114+
routeParams: RouteParams{
115+
Keys: []string{"id"},
116+
Values: []string{"123"},
117+
},
118+
}
119+
120+
clone := orig.Clone()
121+
orig.Reset()
122+
123+
orig.URLParams.Keys = append(orig.URLParams.Keys, "bar")
124+
orig.URLParams.Values = append(orig.URLParams.Values, "baz")
125+
orig.routeParams.Keys = append(orig.routeParams.Keys, "name")
126+
orig.routeParams.Values = append(orig.routeParams.Values, "foxmulder")
127+
orig.RoutePatterns = append(orig.RoutePatterns, "/mutated")
128+
orig.methodsAllowed = append(orig.methodsAllowed, mPOST)
129+
130+
if got := clone.URLParams.Keys[0]; got != "foo" {
131+
t.Fatalf("clone URLParams.Keys was corrupted, want %q got %q", "foo", got)
132+
}
133+
if got := clone.URLParams.Values[0]; got != "bar" {
134+
t.Fatalf("clone URLParams.Values was corrupted, want %q got %q", "bar", got)
135+
}
136+
if got := clone.routeParams.Keys[0]; got != "id" {
137+
t.Fatalf("clone routeParams.Keys was corrupted, want %q got %q", "id", got)
138+
}
139+
if got := clone.routeParams.Values[0]; got != "123" {
140+
t.Fatalf("clone routeParams.Values was corrupted, want %q got %q", "123", got)
141+
}
142+
if got := clone.RoutePatterns[0]; got != "/v1" {
143+
t.Fatalf("clone RoutePatterns[0] was corrupted, want %q got %q", "/v1", got)
144+
}
145+
if got := clone.methodsAllowed[0]; got != mHEAD {
146+
t.Fatalf("clone methodsAllowed[0] was corrupted, want %d got %d", mHEAD, got)
147+
}
148+
}

0 commit comments

Comments
 (0)