Skip to content

Commit

Permalink
Merge pull request #904 from nyaruka/truncate_by_rune
Browse files Browse the repository at this point in the history
🈹 Fix anywhere we truncate strings to do it by rune
  • Loading branch information
rowanseymour authored Apr 21, 2020
2 parents 5372f5d + 7a5b960 commit 9db1cf5
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 14 deletions.
1 change: 1 addition & 0 deletions excellent/types/text_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func TestXText(t *testing.T) {
assert.Equal(t, types.NewXText("abc"), types.NewXText("abcdef").Slice(0, 3))
assert.Equal(t, types.NewXText("cd"), types.NewXText("abcdef").Slice(2, 4))
assert.Equal(t, types.NewXText("😁😁"), types.NewXText("😁😁😁😁").Slice(2, 4))
assert.Equal(t, types.NewXText("界"), types.NewXText("世界").Slice(1, 2))

assert.Equal(t, types.NewXText("abc"), types.NewXText("abcd").Slice(-1, 3))
assert.Equal(t, types.NewXText("bcd"), types.NewXText("abcd").Slice(1, 4))
Expand Down
2 changes: 1 addition & 1 deletion flows/actions/modifiers/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func testModifierType(t *testing.T, sessionAssets flows.SessionAssets, typeName

// apply the modifier
eventLog := test.NewEventLog()
modifier.Apply(envs.NewBuilder().Build(), sessionAssets, contact, eventLog.Log)
modifier.Apply(envs.NewBuilder().WithMaxValueLength(256).Build(), sessionAssets, contact, eventLog.Log)

// clone test case and populate with actual values
actual := tc
Expand Down
15 changes: 10 additions & 5 deletions flows/actions/modifiers/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/nyaruka/goflow/assets"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/excellent/types"
"github.com/nyaruka/goflow/flows"
"github.com/nyaruka/goflow/flows/events"
"github.com/nyaruka/goflow/utils"
Expand Down Expand Up @@ -40,13 +41,17 @@ func (m *FieldModifier) Apply(env envs.Environment, assets flows.SessionAssets,
oldValue := contact.Fields().Get(m.field)

if !m.value.Equals(oldValue) {
// truncate text value if necessary
if m.value != nil && m.value.Text.Length() > env.MaxValueLength() {
m.value.Text = m.value.Text.Slice(0, env.MaxValueLength())
var value *flows.Value

// copy and truncate text value if necessary
if m.value != nil {
v := *m.value
value = &v
value.Text = types.NewXText(utils.Truncate(value.Text.Native(), env.MaxValueLength()))
}

contact.Fields().Set(m.field, m.value)
log(events.NewContactFieldChanged(m.field, m.value))
contact.Fields().Set(m.field, value)
log(events.NewContactFieldChanged(m.field, value))
m.reevaluateGroups(env, assets, contact, false, log)
}
}
Expand Down
8 changes: 3 additions & 5 deletions flows/actions/modifiers/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,10 @@ func NewName(name string) *NameModifier {
func (m *NameModifier) Apply(env envs.Environment, assets flows.SessionAssets, contact *flows.Contact, log flows.EventCallback) {
if contact.Name() != m.Name {
// truncate value if necessary
if len(m.Name) > env.MaxValueLength() {
m.Name = m.Name[0:env.MaxValueLength()]
}
name := utils.Truncate(m.Name, env.MaxValueLength())

contact.SetName(m.Name)
log(events.NewContactNameChanged(m.Name))
contact.SetName(name)
log(events.NewContactNameChanged(name))
m.reevaluateGroups(env, assets, contact, false, log)
}
}
Expand Down
46 changes: 46 additions & 0 deletions flows/actions/modifiers/testdata/field.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,51 @@
"value": null
}
]
},
{
"description": "truncates text value if necessary",
"contact_before": {
"uuid": "5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f",
"name": "Bob",
"fields": {
"gender": {
"text": "M"
}
},
"created_on": "2018-06-20T11:40:30.123456789Z"
},
"modifier": {
"type": "field",
"field": {
"key": "gender",
"name": "Gender"
},
"value": {
"text": "創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息"
}
},
"contact_after": {
"uuid": "5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f",
"name": "Bob",
"created_on": "2018-06-20T11:40:30.123456789Z",
"fields": {
"gender": {
"text": "創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程"
}
}
},
"events": [
{
"type": "contact_field_changed",
"created_on": "2018-10-18T14:20:30.000123456Z",
"field": {
"key": "gender",
"name": "Gender"
},
"value": {
"text": "創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程"
}
}
]
}
]
24 changes: 24 additions & 0 deletions flows/actions/modifiers/testdata/name.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,29 @@
]
}
]
},
{
"description": "truncates name if necessary",
"contact_before": {
"uuid": "5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f",
"name": "Bob",
"created_on": "2018-06-20T11:40:30.123456789Z"
},
"modifier": {
"type": "name",
"name": "創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息"
},
"contact_after": {
"uuid": "5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f",
"name": "創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程",
"created_on": "2018-06-20T11:40:30.123456789Z"
},
"events": [
{
"type": "contact_name_changed",
"created_on": "2018-10-18T14:20:30.000123456Z",
"name": "創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程以發送消息創建流程"
}
]
}
]
4 changes: 1 addition & 3 deletions flows/runs/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@ func (r *flowRun) Events() []flows.Event { return r.events }
func (r *flowRun) Results() flows.Results { return r.results }
func (r *flowRun) SaveResult(result *flows.Result) {
// truncate value if necessary
if len(result.Value) > r.Environment().MaxValueLength() {
result.Value = result.Value[0:r.Environment().MaxValueLength()]
}
result.Value = utils.Truncate(result.Value, r.Environment().MaxValueLength())

r.results.Save(result)
r.modifiedOn = dates.Now()
Expand Down
40 changes: 40 additions & 0 deletions flows/runs/run_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package runs_test

import (
"strings"
"testing"
"time"

Expand Down Expand Up @@ -262,3 +263,42 @@ func TestMissingRelatedRunContext(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, types.NewXErrorf("null doesn't support lookups"), val)
}

func TestSaveResult(t *testing.T) {
sa, err := test.CreateSessionAssets([]byte(sessionAssets), "")
require.NoError(t, err)

trigger, err := triggers.ReadTrigger(sa, []byte(sessionTrigger), assets.IgnoreMissing)
require.NoError(t, err)

eng := test.NewEngine()
session, _, err := eng.NewSession(sa, trigger)
require.NoError(t, err)

run := session.Runs()[0]

dates.SetNowSource(dates.NewFixedNowSource(time.Date(2020, 4, 20, 12, 39, 30, 123456789, time.UTC)))
defer dates.SetNowSource(dates.DefaultNowSource)

// no results means empty object with default of empty string
test.AssertXEqual(t, types.NewXObject(map[string]types.XValue{"__default__": types.XTextEmpty}), flows.Context(session.Environment(), run.Results()))

run.SaveResult(flows.NewResult("Response 1", "red", "Red", "Rojo", "6d35528e-cae3-4e30-b842-8fe6ed7d5c02", "I like red", nil, dates.Now()))

// name is snaked
assert.Equal(t, "red", run.Results().Get("response_1").Value)
assert.Equal(t, "Red", run.Results().Get("response_1").Category)
assert.Equal(t, time.Date(2020, 4, 20, 12, 39, 30, 123456789, time.UTC), run.ModifiedOn())

run.SaveResult(flows.NewResult("Response 1", "blue", "Blue", "Azul", "6d35528e-cae3-4e30-b842-8fe6ed7d5c02", "I like blue", nil, dates.Now()))

// result is overwritten
assert.Equal(t, "blue", run.Results().Get("response_1").Value)
assert.Equal(t, "Blue", run.Results().Get("response_1").Category)
assert.Equal(t, time.Date(2020, 4, 20, 12, 39, 30, 123456789, time.UTC), run.ModifiedOn())

// long values should truncated
run.SaveResult(flows.NewResult("Response 1", strings.Repeat("創", 700), "Blue", "Azul", "6d35528e-cae3-4e30-b842-8fe6ed7d5c02", "I like blue", nil, dates.Now()))

assert.Equal(t, strings.Repeat("創", 640), run.Results().Get("response_1").Value)
}

0 comments on commit 9db1cf5

Please sign in to comment.