Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

hardening DefaultContext to make it panic-free #2246

Merged
merged 1 commit into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion default_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import (
var _ Context = &DefaultContext{}
var _ context.Context = &DefaultContext{}

// TODO(sio4): #road-to-v1 - make DefaultContext private
// and only allow it to be generated by App.newContext() or any similar.

// DefaultContext is, as its name implies, a default
// implementation of the Context interface.
type DefaultContext struct {
Expand Down Expand Up @@ -67,16 +70,22 @@ func (d *DefaultContext) Param(key string) string {
// Set a value onto the Context. Any value set onto the Context
// will be automatically available in templates.
func (d *DefaultContext) Set(key string, value interface{}) {
if d.data == nil {
d.data = &sync.Map{}
}
d.data.Store(key, value)
}

// Value that has previously stored on the context.
func (d *DefaultContext) Value(key interface{}) interface{} {
if k, ok := key.(string); ok {
if k, ok := key.(string); ok && d.data != nil {
if v, ok := d.data.Load(k); ok {
return v
}
}
if d.Context == nil {
return nil
}
return d.Context.Value(key)
}

Expand Down Expand Up @@ -235,6 +244,11 @@ func (d *DefaultContext) Redirect(status int, url string, args ...interface{}) e
// Data contains all the values set through Get/Set.
func (d *DefaultContext) Data() map[string]interface{} {
m := map[string]interface{}{}

if d.data == nil {
return m
}

d.data.Range(func(k, v interface{}) bool {
s, ok := k.(string)
if !ok {
Expand Down
81 changes: 80 additions & 1 deletion default_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ func Test_DefaultContext_GetSet(t *testing.T) {
r.Equal("Mark", c.Value("name").(string))
}

func Test_DefaultContext_Set_Unconfigured(t *testing.T) {
r := require.New(t)
c := DefaultContext{}

c.Set("name", "Yonghwan")
r.NotNil(c.Value("name"))
r.Equal("Yonghwan", c.Value("name").(string))
}

func Test_DefaultContext_Value(t *testing.T) {
r := require.New(t)
c := basicContext()
Expand All @@ -151,7 +160,12 @@ func Test_DefaultContext_Value(t *testing.T) {
c.Set("name", "Mark")
r.NotNil(c.Value("name"))
r.Equal("Mark", c.Value("name").(string))
r.Equal("Mark", c.Value("name").(string))
}

func Test_DefaultContext_Value_Unconfigured(t *testing.T) {
r := require.New(t)
c := DefaultContext{}
r.Nil(c.Value("name"))
}

func Test_DefaultContext_Render(t *testing.T) {
Expand Down Expand Up @@ -301,3 +315,68 @@ func Test_DefaultContext_Bind_JSON(t *testing.T) {

r.Equal("Mark", user.FirstName)
}

func Test_DefaultContext_Data(t *testing.T) {
r := require.New(t)
c := basicContext()

r.EqualValues(map[string]interface{}{}, c.Data())
}

func Test_DefaultContext_Data_Unconfigured(t *testing.T) {
r := require.New(t)
c := DefaultContext{}

r.EqualValues(map[string]interface{}{}, c.Data())
}

func Test_DefaultContext_String(t *testing.T) {
r := require.New(t)
c := basicContext()
c.Set("name", "Buffalo")
c.Set("language", "go")

r.EqualValues("language: go\n\nname: Buffalo", c.String())
}

func Test_DefaultContext_String_EmptyData(t *testing.T) {
r := require.New(t)
c := basicContext()
r.EqualValues("", c.String())
}

func Test_DefaultContext_String_EmptyData_Unconfigured(t *testing.T) {
r := require.New(t)
c := DefaultContext{}

r.EqualValues("", c.String())
}

func Test_DefaultContext_MarshalJSON(t *testing.T) {
r := require.New(t)
c := basicContext()
c.Set("name", "Buffalo")
c.Set("language", "go")

jb, err := c.MarshalJSON()
r.NoError(err)
r.EqualValues(`{"language":"go","name":"Buffalo"}`, string(jb))
}

func Test_DefaultContext_MarshalJSON_EmptyData(t *testing.T) {
r := require.New(t)
c := basicContext()

jb, err := c.MarshalJSON()
r.NoError(err)
r.EqualValues(`{}`, string(jb))
}

func Test_DefaultContext_MarshalJSON_EmptyData_Unconfigured(t *testing.T) {
r := require.New(t)
c := DefaultContext{}

jb, err := c.MarshalJSON()
r.NoError(err)
r.EqualValues(`{}`, string(jb))
}