@@ -263,6 +263,18 @@ func TestStringLibrary(t *testing.T) {
263
263
expectEsimatedCost : checker.CostEstimate {Min : 3 , Max : 3 },
264
264
expectRuntimeCost : 3 ,
265
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
+ },
266
278
{
267
279
name : "replace with limit" ,
268
280
expr : "'abc 123 def 123'.replace('123', '456', 1)" ,
@@ -437,6 +449,107 @@ func testCost(t *testing.T, expr string, expectEsimatedCost checker.CostEstimate
437
449
}
438
450
}
439
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
+
440
553
type testCostEstimator struct {
441
554
}
442
555
0 commit comments