@@ -227,18 +227,54 @@ func TestStringLibrary(t *testing.T) {
227
227
expectEsimatedCost : checker.CostEstimate {Min : 3 , Max : 3 },
228
228
expectRuntimeCost : 3 ,
229
229
},
230
+ {
231
+ name : "lowerAsciiEquals" ,
232
+ expr : "'ABCDEFGHIJ abcdefghij'.lowerAscii() == 'abcdefghij ABCDEFGHIJ'.lowerAscii()" ,
233
+ expectEsimatedCost : checker.CostEstimate {Min : 7 , Max : 9 },
234
+ expectRuntimeCost : 9 ,
235
+ },
230
236
{
231
237
name : "upperAscii" ,
232
238
expr : "'ABCDEFGHIJ abcdefghij'.upperAscii()" ,
233
239
expectEsimatedCost : checker.CostEstimate {Min : 3 , Max : 3 },
234
240
expectRuntimeCost : 3 ,
235
241
},
242
+ {
243
+ name : "upperAsciiEquals" ,
244
+ expr : "'ABCDEFGHIJ abcdefghij'.upperAscii() == 'abcdefghij ABCDEFGHIJ'.upperAscii()" ,
245
+ expectEsimatedCost : checker.CostEstimate {Min : 7 , Max : 9 },
246
+ expectRuntimeCost : 9 ,
247
+ },
248
+ {
249
+ name : "quote" ,
250
+ expr : "strings.quote('ABCDEFGHIJ abcdefghij')" ,
251
+ expectEsimatedCost : checker.CostEstimate {Min : 3 , Max : 3 },
252
+ expectRuntimeCost : 3 ,
253
+ },
254
+ {
255
+ name : "quoteEquals" ,
256
+ expr : "strings.quote('ABCDEFGHIJ abcdefghij') == strings.quote('ABCDEFGHIJ abcdefghij')" ,
257
+ expectEsimatedCost : checker.CostEstimate {Min : 7 , Max : 11 },
258
+ expectRuntimeCost : 9 ,
259
+ },
236
260
{
237
261
name : "replace" ,
238
262
expr : "'abc 123 def 123'.replace('123', '456')" ,
239
263
expectEsimatedCost : checker.CostEstimate {Min : 3 , Max : 3 },
240
264
expectRuntimeCost : 3 ,
241
265
},
266
+ {
267
+ name : "replace between all chars" ,
268
+ expr : "'abc 123 def 123'.replace('', 'x')" ,
269
+ expectEsimatedCost : checker.CostEstimate {Min : 3 , Max : 3 },
270
+ expectRuntimeCost : 3 ,
271
+ },
272
+ {
273
+ name : "replace with empty" ,
274
+ expr : "'abc 123 def 123'.replace('123', '')" ,
275
+ expectEsimatedCost : checker.CostEstimate {Min : 3 , Max : 3 },
276
+ expectRuntimeCost : 3 ,
277
+ },
242
278
{
243
279
name : "replace with limit" ,
244
280
expr : "'abc 123 def 123'.replace('123', '456', 1)" ,
@@ -413,6 +449,107 @@ func testCost(t *testing.T, expr string, expectEsimatedCost checker.CostEstimate
413
449
}
414
450
}
415
451
452
+ func TestSize (t * testing.T ) {
453
+ exactSize := func (size int ) checker.SizeEstimate {
454
+ return checker.SizeEstimate {Min : uint64 (size ), Max : uint64 (size )}
455
+ }
456
+ exactSizes := func (sizes ... int ) []checker.SizeEstimate {
457
+ results := make ([]checker.SizeEstimate , len (sizes ))
458
+ for i , size := range sizes {
459
+ results [i ] = exactSize (size )
460
+ }
461
+ return results
462
+ }
463
+ cases := []struct {
464
+ name string
465
+ function string
466
+ overload string
467
+ targetSize checker.SizeEstimate
468
+ argSizes []checker.SizeEstimate
469
+ expectSize checker.SizeEstimate
470
+ }{
471
+ {
472
+ name : "replace empty with char" ,
473
+ function : "replace" ,
474
+ targetSize : exactSize (3 ), // e.g. abc
475
+ argSizes : exactSizes (0 , 1 ), // e.g. replace "" with "_"
476
+ expectSize : exactSize (7 ), // e.g. _a_b_c_
477
+ },
478
+ {
479
+ name : "maybe replace char with empty" ,
480
+ function : "replace" ,
481
+ targetSize : exactSize (3 ),
482
+ argSizes : exactSizes (1 , 0 ),
483
+ expectSize : checker.SizeEstimate {Min : 0 , Max : 3 },
484
+ },
485
+ {
486
+ name : "maybe replace repeated" ,
487
+ function : "replace" ,
488
+ targetSize : exactSize (4 ),
489
+ argSizes : exactSizes (2 , 4 ),
490
+ expectSize : checker.SizeEstimate {Min : 4 , Max : 8 },
491
+ },
492
+ {
493
+ name : "maybe replace empty" ,
494
+ function : "replace" ,
495
+ targetSize : exactSize (4 ),
496
+ argSizes : []checker.SizeEstimate {{Min : 0 , Max : 1 }, {Min : 0 , Max : 2 }},
497
+ expectSize : checker.SizeEstimate {Min : 0 , Max : 14 }, // len(__a__a__a__a__) == 14
498
+ },
499
+ {
500
+ name : "replace non-empty size range, maybe larger" ,
501
+ function : "replace" ,
502
+ targetSize : exactSize (4 ),
503
+ argSizes : []checker.SizeEstimate {{Min : 1 , Max : 1 }, {Min : 1 , Max : 2 }},
504
+ expectSize : checker.SizeEstimate {Min : 4 , Max : 8 },
505
+ },
506
+ {
507
+ name : "replace non-empty size range, maybe smaller" ,
508
+ function : "replace" ,
509
+ targetSize : exactSize (4 ),
510
+ argSizes : []checker.SizeEstimate {{Min : 1 , Max : 2 }, {Min : 1 , Max : 1 }},
511
+ expectSize : checker.SizeEstimate {Min : 2 , Max : 4 },
512
+ },
513
+ }
514
+ est := & CostEstimator {SizeEstimator : & testCostEstimator {}}
515
+ for _ , tc := range cases {
516
+ t .Run (tc .name , func (t * testing.T ) {
517
+ var targetNode checker.AstNode = testSizeNode {size : tc .targetSize }
518
+ argNodes := make ([]checker.AstNode , len (tc .argSizes ))
519
+ for i , arg := range tc .argSizes {
520
+ argNodes [i ] = testSizeNode {size : arg }
521
+ }
522
+ result := est .EstimateCallCost (tc .function , tc .overload , & targetNode , argNodes )
523
+ if result .ResultSize == nil {
524
+ t .Fatalf ("Expected ResultSize but got none" )
525
+ }
526
+ if * result .ResultSize != tc .expectSize {
527
+ t .Fatalf ("Expected %+v but got %+v" , tc .expectSize , * result .ResultSize )
528
+ }
529
+ })
530
+ }
531
+ }
532
+
533
+ type testSizeNode struct {
534
+ size checker.SizeEstimate
535
+ }
536
+
537
+ func (t testSizeNode ) Path () []string {
538
+ return nil // not needed
539
+ }
540
+
541
+ func (t testSizeNode ) Type () * expr.Type {
542
+ return nil // not needed
543
+ }
544
+
545
+ func (t testSizeNode ) Expr () * expr.Expr {
546
+ return nil // not needed
547
+ }
548
+
549
+ func (t testSizeNode ) ComputedSize () * checker.SizeEstimate {
550
+ return & t .size
551
+ }
552
+
416
553
type testCostEstimator struct {
417
554
}
418
555
0 commit comments