mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-12 02:06:37 +08:00
autoresearch iter 8: render synthesized notification content in stable order
bodyContent's fallback ranged over the body map, and Go randomizes map iteration, so the same notification rendered its fields in a different order on every send. Observed failing before the fix: the second call already reordered the output. Iterate sorted keys instead.
This commit is contained in:
@@ -6,6 +6,8 @@ package push
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -87,13 +89,15 @@ func bodyTitle(body map[string]any) string {
|
|||||||
|
|
||||||
// bodyContent returns the notification body, rendering every entry with format
|
// bodyContent returns the notification body, rendering every entry with format
|
||||||
// (a "%s … %v" pair) and joining them with sep when no content field is given.
|
// (a "%s … %v" pair) and joining them with sep when no content field is given.
|
||||||
|
// Entries render in sorted key order so identical bodies always produce
|
||||||
|
// identical text.
|
||||||
func bodyContent(body map[string]any, format, sep string) string {
|
func bodyContent(body map[string]any, format, sep string) string {
|
||||||
if c, ok := body["content"].(string); ok && c != "" {
|
if c, ok := body["content"].(string); ok && c != "" {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
parts := make([]string, 0, len(body))
|
parts := make([]string, 0, len(body))
|
||||||
for k, v := range body {
|
for _, k := range slices.Sorted(maps.Keys(body)) {
|
||||||
parts = append(parts, fmt.Sprintf(format, k, v))
|
parts = append(parts, fmt.Sprintf(format, k, body[k]))
|
||||||
}
|
}
|
||||||
return strings.Join(parts, sep)
|
return strings.Join(parts, sep)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,3 +73,24 @@ func TestParseTemplate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Synthesized content must render in a stable order, otherwise two identical
|
||||||
|
// notifications produce different text on every send.
|
||||||
|
func TestBodyContentFallbackIsDeterministic(t *testing.T) {
|
||||||
|
body := map[string]any{
|
||||||
|
"zebra": 1,
|
||||||
|
"alpha": 2,
|
||||||
|
"mike": 3,
|
||||||
|
"charlie": 4,
|
||||||
|
"yankee": 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
first := bodyContent(body, "%s=%v", ",")
|
||||||
|
for i := 1; i <= 50; i++ {
|
||||||
|
if got := bodyContent(body, "%s=%v", ","); got != first {
|
||||||
|
t.Fatalf("bodyContent order changed on call %d: %q != %q", i, got, first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, "alpha=2,charlie=4,mike=3,yankee=5,zebra=1", first)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user