@@ -2,6 +2,7 @@ package response
22
33import (
44 "encoding/json"
5+ "fmt"
56 "testing"
67
78 "github.com/stretchr/testify/assert"
@@ -69,6 +70,31 @@ func TestFlatten(t *testing.T) {
6970 "commit.author.date" : "2026-01-01" ,
7071 }, result )
7172 })
73+
74+ t .Run ("silently drops nested maps at maxDepth boundary" , func (t * testing.T ) {
75+ // With defaultMaxDepth=2, depth starts at 1.
76+ // "user" is recursed into at depth=2, but "org" inside it
77+ // is a map at depth=2 where depth < maxDepth is false,
78+ // and the else-if !ok branch also doesn't fire because ok=true.
79+ // Result: "user.org" and its contents are silently lost.
80+ input := map [string ]any {
81+ "title" : "issue" ,
82+ "user" : map [string ]any {
83+ "login" : "alice" ,
84+ "org" : map [string ]any {
85+ "name" : "acme" ,
86+ },
87+ },
88+ }
89+ result := flattenTo (input , defaultMaxDepth )
90+
91+ assert .Equal (t , "issue" , result ["title" ])
92+ assert .Equal (t , "alice" , result ["user.login" ])
93+ // BUG: org data is silently dropped — neither "user.org" nor
94+ // "user.org.name" appear in the result.
95+ assert .Nil (t , result ["user.org" ], "nested map at maxDepth is silently dropped" )
96+ assert .Nil (t , result ["user.org.name" ], "nested map contents at maxDepth are lost" )
97+ })
7298}
7399
74100func TestFilterByFillRate (t * testing.T ) {
@@ -156,6 +182,38 @@ func TestOptimizeList_NilInput(t *testing.T) {
156182 assert .Equal (t , "null" , string (raw ))
157183}
158184
185+ func TestOptimizeList_NilInput_AsRawMessage (t * testing.T ) {
186+ // This mirrors how list_issues embeds OptimizeList output as json.RawMessage.
187+ // When the input slice is nil, OptimizeList returns the bytes "null",
188+ // which produces {"issues":null,...} instead of {"issues":[],...}.
189+ // Consumers expecting an array will break.
190+ optimized , err := OptimizeList [map [string ]any ](nil )
191+ require .NoError (t , err )
192+
193+ wrapper := map [string ]any {
194+ "issues" : json .RawMessage (optimized ),
195+ "totalCount" : 0 ,
196+ }
197+
198+ out , err := json .Marshal (wrapper )
199+ require .NoError (t , err )
200+
201+ // Parse back and check what "issues" became
202+ var parsed map [string ]json.RawMessage
203+ err = json .Unmarshal (out , & parsed )
204+ require .NoError (t , err )
205+
206+ // BUG: "issues" is JSON null, not an empty array
207+ assert .Equal (t , "null" , string (parsed ["issues" ]),
208+ "nil input produces JSON null instead of empty array when embedded as RawMessage" )
209+
210+ // This is what a consumer trying to decode an array would see:
211+ var issues []map [string ]any
212+ err = json .Unmarshal (parsed ["issues" ], & issues )
213+ require .NoError (t , err ) // unmarshal succeeds but...
214+ assert .Nil (t , issues , "decoded slice is nil, not empty — may cause nil-pointer issues in consumers" )
215+ }
216+
159217func TestOptimizeList_SkipsFillRateBelowMinRows (t * testing.T ) {
160218 items := []map [string ]any {
161219 {"title" : "a" , "rare" : "x" },
@@ -172,6 +230,72 @@ func TestOptimizeList_SkipsFillRateBelowMinRows(t *testing.T) {
172230 assert .Equal (t , "x" , result [0 ]["rare" ])
173231}
174232
233+ func TestWhitespaceNormalization_DestroysCodeBlocks (t * testing.T ) {
234+ // PR/issue bodies often contain markdown with code blocks, bullet lists,
235+ // and intentional line breaks. The whitespace normalization strategy
236+ // collapses all of this into a single line.
237+ body := "## Steps to reproduce\n \n " +
238+ "1. Run the following:\n \n " +
239+ "```go\n func main() {\n \t fmt.Println(\" hello\" )\n }\n ```\n \n " +
240+ "2. Observe the error:\n \n " +
241+ "```\n panic: runtime error\n goroutine 1\n ```"
242+
243+ items := []map [string ]any {
244+ {
245+ "title" : "Bug report" ,
246+ "body" : body ,
247+ },
248+ }
249+
250+ raw , err := OptimizeList (items )
251+ require .NoError (t , err )
252+
253+ var result []map [string ]any
254+ err = json .Unmarshal (raw , & result )
255+ require .NoError (t , err )
256+ require .Len (t , result , 1 )
257+
258+ optimized := result [0 ]["body" ].(string )
259+
260+ assert .Equal (t ,
261+ "## Steps to reproduce 1. Run the following: ```go func main() { fmt.Println(\" hello\" ) } ``` 2. Observe the error: ``` panic: runtime error goroutine 1 ```" ,
262+ optimized ,
263+ "code blocks and markdown structure are flattened into unreadable text" ,
264+ )
265+ }
266+
267+ func TestFillRateAfterZeroRemoval_DropsLegitimateValues (t * testing.T ) {
268+ // This simulates list_branches with 10 branches where 1 is protected.
269+ // Pipeline order: optimizeItem (strips protected:false) → filterByFillRate.
270+ // After optimizeItem, "protected" only appears on 1/10 items.
271+ // Fill rate = 1/10 = 0.1, minCount = int(0.1*10) = 1, and 1 > 1 is false.
272+ // So "protected: true" is removed from the one branch that had it.
273+
274+ items := make ([]map [string ]any , 10 )
275+ for i := range items {
276+ items [i ] = map [string ]any {
277+ "name" : fmt .Sprintf ("branch-%d" , i ),
278+ "protected" : false ,
279+ }
280+ }
281+ // One branch is actually protected
282+ items [0 ]["protected" ] = true
283+
284+ raw , err := OptimizeList (items )
285+ require .NoError (t , err )
286+
287+ var result []map [string ]any
288+ err = json .Unmarshal (raw , & result )
289+ require .NoError (t , err )
290+ require .Len (t , result , 10 )
291+
292+ // BUG: The protected branch lost its "protected: true" field.
293+ // optimizeItem stripped "protected: false" from 9 items, then
294+ // filterByFillRate saw "protected" on only 1/10 and removed it.
295+ assert .Nil (t , result [0 ]["protected" ],
296+ "protected:true is lost because zero-value removal deflated the fill rate" )
297+ }
298+
175299func TestPreservedFields (t * testing.T ) {
176300 t .Run ("keeps preserved URL keys, strips non-preserved" , func (t * testing.T ) {
177301 cfg := OptimizeListConfig {
0 commit comments